Add Wwise XMA

This commit is contained in:
bnnm 2017-04-08 13:40:23 +02:00
parent 680ff51e64
commit 87bbd007c8

View File

@ -29,9 +29,10 @@ typedef struct {
int bits_per_sample; int bits_per_sample;
size_t extra_size; size_t extra_size;
int32_t num_samples;
int loop_flag; int loop_flag;
uint32_t loop_start_sample; int32_t loop_start_sample;
uint32_t loop_end_sample; int32_t loop_end_sample;
} wwise_header; } wwise_header;
@ -69,7 +70,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.file_size = streamFile->get_size(streamFile); ww.file_size = streamFile->get_size(streamFile);
#if 0 #if 0
/* sometimes uses a RIFF size that doesn't count chunk/sizes, LE value in RIFX, or just wrong...? */ /* sometimes uses a RIFF size that doesn't count chunks/sizes, has LE size in RIFX, or is just wrong...? */
if (4+4+read_32bit(0x04,streamFile) != ww.file_size) { if (4+4+read_32bit(0x04,streamFile) != ww.file_size) {
VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", 4+4+read_32bit(0x04,streamFile), ww.file_size); VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", 4+4+read_32bit(0x04,streamFile), ww.file_size);
goto fail; goto fail;
@ -77,7 +78,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
#endif #endif
/* parse WAVEFORMATEX (roughly spec-compliant but some massaging is needed) */ /* parse format (roughly spec-compliant but some massaging is needed) */
{ {
off_t loop_offset; off_t loop_offset;
size_t loop_size; size_t loop_size;
@ -94,6 +95,12 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* base fmt */ /* base fmt */
if (ww.fmt_size < 0x12) 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,streamFile);
if (ww.format == 0x0165) { /* XMA2WAVEFORMAT (always "fmt"+"XMA2", unlike .xma that may only have "XMA2") */
off_t xma2_offset;
if (!find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,NULL, ww.big_endian, 0)) goto fail;
xma2_parse_xma2_chunk(streamFile, xma2_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample);
} else { /* WAVEFORMATEX */
ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile); ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile);
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,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.average_bps = read_32bit(ww.fmt_offset+0x08,streamFile);/* bytes per sec */
@ -101,14 +108,16 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile); ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile);
if (ww.fmt_size > 0x10 && ww.format != 0x0165 && ww.format != 0x0166) /* ignore XMAWAVEFORMAT */ 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,streamFile);
#if 0
/* channel bitmask, see AkSpeakerConfig.h (ex. 1ch uses FRONT_CENTER 0x4, 2ch FRONT_LEFT 0x1 | FRONT_RIGHT 0x2, etc) */ /* channel bitmask, see AkSpeakerConfig.h (ex. 1ch uses FRONT_CENTER 0x4, 2ch FRONT_LEFT 0x1 | FRONT_RIGHT 0x2, etc) */
if (ww.extra_size >= 6) //if (ww.extra_size >= 6)
ww.channel_config = read_32bit(ww.fmt_offset+0x14,streamFile); // ww.channel_config = read_32bit(ww.fmt_offset+0x14,streamFile);
#endif }
/* find loop info (both used in early and late Wwise and seem to follow the spec) */ /* find loop info */
if (find_chunk(streamFile, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"smpl"*/ if (ww.format == 0x0166) { /* XMA2WAVEFORMATEX */
xma2_parse_fmt_chunk_extra(streamFile, ww.fmt_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 */
if (loop_size >= 0x34 if (loop_size >= 0x34
&& read_32bit(loop_offset+0x1c, streamFile)==1 /*loop count*/ && read_32bit(loop_offset+0x1c, streamFile)==1 /*loop count*/
&& read_32bit(loop_offset+0x24+4, streamFile)==0) { && read_32bit(loop_offset+0x24+4, streamFile)==0) {
@ -117,7 +126,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc,streamFile); ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc,streamFile);
//todo fix repeat looping //todo fix repeat looping
} }
} else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST"*/ }
else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
//todo parse "adtl" (does it ever contain loop info in Wwise?) //todo parse "adtl" (does it ever contain loop info in Wwise?)
} }
@ -293,24 +303,42 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
#ifdef VGM_USE_FFMPEG #ifdef VGM_USE_FFMPEG
case XMA2: { /* X360/XBone */ case XMA2: { /* X360/XBone */
//chunks: uint8_t buf[0x100];
//"XMA2", "seek": same as the official ones int bytes;
//"XMAc": Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data) off_t xma2_offset;
size_t xma2_size;
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (real LE XMA(2)WAVEFORMAT/EX are parsed elsewhere) */ if (!ww.big_endian) goto fail; /* must be Wwise (real XMA are LE and parsed elsewhere) */
VGM_LOG("WWISE: XMA2 found (unsupported)\n"); if (find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */
goto fail; bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, streamFile);
} else { /* newer Wwise */
bytes = ffmpeg_make_riff_xma_from_fmt(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, streamFile, ww.big_endian);
}
if (bytes <= 0) goto fail;
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
if ( !vgmstream->codec_data ) goto fail;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = ww.num_samples; /* set while parsing XMAWAVEFORMATs */
/* "XMAc": rare Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data) */
VGM_ASSERT(find_chunk(streamFile, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n");
/* other chunks: "seek", regular XMA2 seek table */
break;
} }
case XWMA: { /* X360 */ case XWMA: { /* X360 */
ffmpeg_codec_data *ffmpeg_data = NULL; ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[100]; uint8_t buf[0x100];
int bytes; int bytes;
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */ if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */
bytes = ffmpeg_make_riff_xwma(buf, 100, ww.format, ww.data_size, vgmstream->channels, vgmstream->sample_rate, ww.average_bps, ww.block_align); bytes = ffmpeg_make_riff_xwma(buf,0x100, ww.format, ww.data_size, vgmstream->channels, vgmstream->sample_rate, ww.average_bps, ww.block_align);
if (bytes <= 0) goto fail; if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size); ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);