Add Wwise XWMA [Halo 4 X360]; update xma_get_samples to read WMAPRO

Also ffmpeg_make_riff_xwma doesn't actually need num_samples and use
x_bytes_to_samples in Wwise
This commit is contained in:
bnnm 2017-04-07 20:21:55 +02:00
parent 2086426175
commit 3619b14f8e
4 changed files with 178 additions and 78 deletions

View File

@ -181,17 +181,18 @@ int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_co
int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode);
int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size);
int ffmpeg_make_riff_xma_from_fmt(uint8_t * buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE *streamFile, int big_endian);
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t sample_count, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align);
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align);
/* XMA sample parser info (struct to avoid passing so much stuff, separate for reusing) */
/* MS audio format's sample info (struct to avoid passing so much stuff, separate for reusing) */
typedef struct {
int xma_version;
int channels;
int stream_mode;
off_t data_offset;
size_t data_size;
int loop_flag;
/* frame offsets */
int loop_flag;
uint32_t loop_start_b;
uint32_t loop_end_b;
uint32_t loop_start_subframe;
@ -202,8 +203,9 @@ typedef struct {
int32_t skip_samples;
int32_t loop_start_sample;
int32_t loop_end_sample;
} xma_sample_data;
void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile);
} xma_sample_data; /* ms_sample_data */
void xma_get_samples(xma_sample_data * msd, STREAMFILE *streamFile);
void wmapro_get_samples(xma_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags);
#endif

View File

@ -1,13 +1,9 @@
#include "coding.h"
#include "math.h"
#include "../vgmstream.h"
#ifdef VGM_USE_FFMPEG
#define XMA_CHECK_SKIPS 0
#define XMA_BYTES_PER_PACKET 2048
#define XMA_SAMPLES_PER_FRAME 512
#define XMA_SAMPLES_PER_SUBFRAME 128
/* ******************************************** */
/* INTERNAL UTILS */
/* ******************************************** */
@ -287,7 +283,7 @@ fail:
return -1;
}
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t sample_count, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align) {
int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data_size, int channels, int sample_rate, int avg_bps, int block_align) {
size_t riff_size = 4+4+ 4 + 0x1a + 4+4;
if (buf_size < riff_size)
@ -302,11 +298,11 @@ int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t samp
put_16bitLE(buf+0x14, codec);
put_16bitLE(buf+0x16, channels);
put_32bitLE(buf+0x18, sample_rate);
put_32bitLE(buf+0x1c, avg_bps); /* average bits per second, somehow vital for XWMA */
put_32bitLE(buf+0x1c, avg_bps); /* average bytes per second, somehow vital for XWMA */
put_16bitLE(buf+0x20, block_align); /* block align */
put_16bitLE(buf+0x22, 16); /* bits per sample */
put_16bitLE(buf+0x24, 0); /* unk */
/* here goes the "dpds" table, but it's not needed by FFmpeg */
put_16bitLE(buf+0x24, 0); /* extra size */
/* here goes the "dpds" table, but it's optional and not needed by FFmpeg */
memcpy(buf+0x26, "data", 4);
put_32bitLE(buf+0x2a, data_size); /* data size */
@ -374,33 +370,33 @@ fail:
/* ******************************************** */
/* XMA PARSING */
/* ******************************************** */
#define XMA_CHECK_SKIPS 0
/**
* Find total and loop samples by reading XMA frame headers.
* Find total and loop samples of Microsoft audio formats (WMAPRO/XMA1/XMA2) by reading frame headers.
*
* A XMA stream is made of packets, each containing N small frames of X samples.
* Frames are further divided into subframes for looping purposes.
* XMA1 and XMA2 only differ in the packet headers.
* The stream is made of packets, each containing N small frames of X samples. Frames are further divided into subframes.
* XMA1/XMA2/WMAPRO only differ in the packet headers.
*/
void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
static void ms_audio_get_samples(xma_sample_data * msd, STREAMFILE *streamFile, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) {
int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0, skip_packets;
#if XMA_CHECK_SKIPS
int start_skip = 0, end_skip = 0, first_start_skip = 0, last_end_skip = 0;
#endif
uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b;
uint32_t first_frame_b, packet_skip_count = 0, frame_size_b, packet_size_b, header_size_b;
uint64_t offset_b, packet_offset_b, frame_offset_b;
size_t size;
uint32_t packet_size = XMA_BYTES_PER_PACKET;
off_t offset = xma->data_offset;
uint32_t stream_offset_b = xma->data_offset * 8;
uint32_t packet_size = bytes_per_packet;
off_t offset = msd->data_offset;
uint32_t stream_offset_b = msd->data_offset * 8;
size = offset + xma->data_size;
size = offset + msd->data_size;
packet_size_b = packet_size * 8;
/* if we knew the streams mode then we could read just the first one and adjust samples later
* not a big deal but maybe important for skip stuff */
//streams = (xma->stream_mode==0 ? (xma->channels + 1) / 2 : xma->channels)
//streams = (msd->stream_mode==0 ? (msd->channels + 1) / 2 : msd->channels)
skip_packets = 0;
/* read packets */
@ -414,19 +410,28 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
continue;
}
/* XMA1 or XMA2 packet header */
if (xma->xma_version == 1) {
/* packet header */
if (msd->xma_version == 1) { /* XMA1 */
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside the packet */
first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */
packet_skip_count = read_bitsBE_b(offset_b+21, 11, streamFile); /* packets to skip for next packet of this stream */
} else {
header_size_b = 32;
} else if (msd->xma_version == 2) { /* XMA2 */
//frame_count = read_bitsBE_b(offset_b+0, 6, streamFile); /* frames that begin in this packet */
first_frame_b = read_bitsBE_b(offset_b+6, 15, streamFile); /* offset in bits inside this packet */
first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside this packet */
//packet_metadata = read_bitsBE_b(offset_b+21, 3, streamFile); /* packet_metadata (always 1) */
packet_skip_count = read_bitsBE_b(offset_b+24, 8, streamFile); /* packets to skip for next packet of this stream */
header_size_b = 32;
} else { /* WMAPRO(v3) */
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */
first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */
packet_skip_count = 0; /* xwma probably has no need to skip packets since it uses real multichannel ch audio */
header_size_b = 4+2+bits_frame_size; /* variable-size header */
}
/* full packet skip */
if (packet_skip_count == 0x7FF) {
packet_skip_count = 0;
@ -438,22 +443,22 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
VGM_ASSERT(packet_skip_count > 10, "XMA: found big packet skip %i\n", packet_skip_count);//a bit unusual...
//VGM_LOG("packet: off=%x, ff=%i, ps=%i\n", offset, first_frame_b, packet_skip_b);
packet_offset_b = 4*8 + first_frame_b; /* packet offset in bits */
packet_offset_b = header_size_b + first_frame_b; /* packet offset in bits */
/* read packet frames */
while (packet_offset_b < packet_size_b) {
frame_offset_b = offset_b + packet_offset_b; /* in bits for aligment stuff */
//todo not sure if frames or frames+1 (considering skip_samples)
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_start_b)
if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_start_b)
loop_start_frame = frames;
if (xma->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == xma->loop_end_b)
if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_end_b)
loop_end_frame = frames;
/* XMA1/2 frame header */
frame_size_b = read_bitsBE_b(frame_offset_b, 15, streamFile);
frame_offset_b += 15;
/* frame header */
frame_size_b = read_bitsBE_b(frame_offset_b, bits_frame_size, streamFile);
frame_offset_b += bits_frame_size;
if (frame_size_b == 0) /* observed in some files with empty frames/packets */
break;
packet_offset_b += frame_size_b; /* including header */
@ -469,7 +474,7 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
// continue; // todo read packet end bit instead
}
#endif
frame_offset_b += 15;
frame_offset_b += 15; //todo bits_frame_size?
if (frame_size_b == 0x7FFF) { /* end packet frame marker */
break;
@ -481,14 +486,14 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
int flag;
/* ignore "postproc transform" */
if (xma->channels > 1) {
if (msd->channels > 1) {
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
frame_offset_b += 1;
if (flag) {
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
frame_offset_b += 1;
if (flag) {
frame_offset_b += 1 + 4 * xma->channels*xma->channels; /* 4-something per double channel? */
frame_offset_b += 1 + 4 * msd->channels*msd->channels; /* 4-something per double channel? */
}
}
}
@ -508,9 +513,9 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
frame_offset_b += 10;
VGM_ASSERT(start_skip, "XMA: more than one start_skip (%i)\n", new_skip);
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
if (new_skip > samples_per_frame) { /* from xmaencode */
VGM_LOG("XMA: bad start_skip (%i)\n", new_skip);
new_skip = XMA_SAMPLES_PER_FRAME;
new_skip = samples_per_frame;
}
if (frames==0) first_start_skip = new_skip; /* sometimes in the middle */
@ -526,9 +531,9 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
frame_offset_b += 10;
VGM_ASSERT(end_skip, "XMA: more than one end_skip (%i)\n", new_skip);
if (new_skip > XMA_SAMPLES_PER_FRAME) { /* from xmaencode */
if (new_skip > samples_per_frame) { /* from xmaencode */
VGM_LOG("XMA: bad end_skip (%i)\n", new_skip);
new_skip = XMA_SAMPLES_PER_FRAME;
new_skip = samples_per_frame;
}
last_end_skip = new_skip; /* not seen */
@ -540,7 +545,7 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
}
#endif
samples += XMA_SAMPLES_PER_FRAME;
samples += samples_per_frame;
frames++;
}
}
@ -551,20 +556,79 @@ void xma_get_samples(xma_sample_data * xma, STREAMFILE *streamFile) {
samples = samples + 64 - start_skip;
samples = samples + 64 - end_skip;
xma->skip_samples = 64 + 512; //todo not always correct
msd->skip_samples = 64 + samples_per_frame; //todo not always correct
#endif
xma->num_samples = samples;
msd->num_samples = samples;
VGM_LOG("frames=%i\n", frames);
if (xma->loop_flag && loop_end_frame > loop_start_frame) {
xma->loop_start_sample = loop_start_frame * XMA_SAMPLES_PER_FRAME + xma->loop_start_subframe * XMA_SAMPLES_PER_SUBFRAME;
xma->loop_end_sample = loop_end_frame * XMA_SAMPLES_PER_FRAME + xma->loop_end_subframe * XMA_SAMPLES_PER_SUBFRAME;
if (msd->loop_flag && loop_end_frame > loop_start_frame) {
msd->loop_start_sample = loop_start_frame * samples_per_frame + msd->loop_start_subframe * samples_per_subframe;
msd->loop_end_sample = loop_end_frame * samples_per_frame + msd->loop_end_subframe * samples_per_subframe;
#if XMA_CHECK_SKIPS
/* maybe this is needed */
//xma->loop_start_sample -= xma->skip_samples;
//xma->loop_end_sample -= xma->skip_samples;
//msd->loop_start_sample -= msd->skip_samples;
//msd->loop_end_sample -= msd->skip_samples;
#endif
}
}
void xma_get_samples(xma_sample_data * msd, STREAMFILE *streamFile) {
const int bytes_per_packet = 2048;
const int samples_per_frame = 512;
const int samples_per_subframe = 128;
ms_audio_get_samples(msd, streamFile, bytes_per_packet, samples_per_frame, samples_per_subframe, 15);
}
void wmapro_get_samples(xma_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) {
int bytes_per_packet = block_align;
int samples_per_frame = 0;
int samples_per_subframe = 0;
int bits_frame_size = 0;
/* do some WMAPRO setup (code from ffmpeg) */
/* get samples per frame */
{
int version = 3;
int frame_len_bits;
if (sample_rate <= 16000)
frame_len_bits = 9;
else if (sample_rate <= 22050 || (sample_rate <= 32000 && version == 1))
frame_len_bits = 10;
else if (sample_rate <= 48000 || version < 3)
frame_len_bits = 11;
else if (sample_rate <= 96000)
frame_len_bits = 12;
else
frame_len_bits = 13;
if (version == 3) {
int tmp = decode_flags & 0x6;
if (tmp == 0x2)
++frame_len_bits;
else if (tmp == 0x4)
--frame_len_bits;
else if (tmp == 0x6)
frame_len_bits -= 2;
}
samples_per_frame = 1 << frame_len_bits;
}
/* max bits needed to represent this block_align */
bits_frame_size = floor(log(block_align) / log(2)) + 4;
/* not really needed as I've never seen loop subframe data for WMA (probably possible though)
* (FFmpeg has code to get min_samples_per subframe) */
samples_per_subframe = 0;
/* signal it's not XMA */
msd->xma_version = 0;
ms_audio_get_samples(msd, streamFile, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size);
}
#endif

View File

@ -25,11 +25,11 @@ typedef struct {
int channels;
int sample_rate;
int block_align;
int bit_per_sample;
int average_bps;
int bits_per_sample;
size_t extra_size;
int loop_flag;
uint32_t num_samples;
uint32_t loop_start_sample;
uint32_t loop_end_sample;
} wwise_header;
@ -51,7 +51,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if ((read_32bitBE(0x00,streamFile) != 0x52494646) && /* "RIFF" (LE) */
(read_32bitBE(0x00,streamFile) != 0x52494658)) /* "RIFX" (BE) */
goto fail;
if ((read_32bitBE(0x08,streamFile) != 0x57415645)) /* "WAVE" */
if ((read_32bitBE(0x08,streamFile) != 0x57415645) && /* "WAVE" */
(read_32bitBE(0x08,streamFile) != 0x58574D41)) /* "XWMA" */
goto fail;
memset(&ww,0,sizeof(wwise_header));
@ -68,7 +69,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.file_size = streamFile->get_size(streamFile);
#if 0
/* sometimes uses a RIFF size that doesn't count chunk/sizes, or just wrong...? */
/* sometimes uses a RIFF size that doesn't count chunk/sizes, LE value in RIFX, or just wrong...? */
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);
goto fail;
@ -95,13 +96,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,streamFile);
ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile);
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,streamFile);
/* 0x08: average samples per second */
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.bit_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 */
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) */
/* channel bitmask, see AkSpeakerConfig.h (ex. 1ch uses FRONT_CENTER 0x4, 2ch FRONT_LEFT 0x1 | FRONT_RIGHT 0x2, etc) */
if (ww.extra_size >= 6)
ww.channel_config = read_32bit(ww.fmt_offset+0x14,streamFile);
#endif
@ -121,17 +122,19 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
}
/* other Wwise specific: */
//"JUNK": optional padding so that raw data starts in an offset multiple of 0x10 (0-size JUNK exists)
//"JUNK": optional padding so that raw data starts in an offset multiple of 0x10 (0-size JUNK exists too)
//"akd ": unknown (IMA/PCM; "audiokinetic data"?)
}
/* format to codec */
switch(ww.format) {
case 0x0001: ww.codec = PCM; break; /* older Wwise */
case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM) */
case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM, probably means "platform's ADPCM") */
case 0x0011: ww.codec = IMA; break; /* older Wwise */
case 0x0069: ww.codec = IMA; break; /* older Wwise */
case 0x0165: ww.codec = XMA2; break;
case 0x0161: ww.codec = XWMA; break;
case 0x0162: ww.codec = XWMA; break;
case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */
case 0x0166: ww.codec = XMA2; break;
case 0xAAC0: ww.codec = AAC; break;
case 0xFFF0: ww.codec = DSP; break;
@ -154,7 +157,6 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
if (!vgmstream) goto fail;
vgmstream->sample_rate = ww.sample_rate;
vgmstream->num_samples = ww.num_samples;
vgmstream->loop_start_sample = ww.loop_start_sample;
vgmstream->loop_end_sample = ww.loop_end_sample;
vgmstream->meta_type = meta_WWISE_RIFF;
@ -164,25 +166,25 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
switch(ww.codec) {
case PCM: /* common */
/* normally riff.c has priority but it's needed when .wem is used */
if (ww.bit_per_sample != 16) goto fail;
if (ww.bits_per_sample != 16) goto fail;
vgmstream->coding_type = (ww.big_endian ? coding_PCM16BE : coding_PCM16LE);
vgmstream->layout_type = ww.channels > 1 ? layout_interleave : layout_none;
vgmstream->interleave_block_size = 0x02;
vgmstream->num_samples = ww.data_size / ww.channels / (ww.bit_per_sample/8);
vgmstream->num_samples = pcm_bytes_to_samples(ww.data_size, ww.channels, ww.bits_per_sample);
break;
case IMA: /* common */
/* slightly modified MS-IMA.
* Original research by hcs in ima_rejigger (https://github.com/hcs64/vgm_ripping/tree/master/demux/ima_rejigger5) */
#if 0
if (ww.bit_per_sample != 4) goto fail;
if (ww.bits_per_sample != 4) goto fail;
vgmstream->coding_type = coding_WWISE_IMA;
vgmstream->layout_type = layout_none;
vgmstream->interleave_block_size = ww.block_align;
vgmstream->num_samples = (ww.data_size / ww.block_align) * (ww.block_align - 4 * vgmstream->channels) * 2 /vgmstream->channels;
vgmstream->num_samples = (ww.data_size / ww.block_align) * (ww.block_align - 4 * vgmstream->channels) * 2 /vgmstream->channels;//todo ms_ima_bytes_to_samples
break;
#endif
VGM_LOG("WWISE: IMA found (unsupported)\n");
@ -201,7 +203,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
int setup_type = 0; /* 1: triad, 2 = inline codebooks, 3 = external codebooks, 4 = external aoTuV codebooks */
int blocksize_0_pow = 0, blocksize_1_pow = 0;
if (ww.block_align != 0 || ww.bit_per_sample != 0) goto fail;
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
/* autodetect format */
if (find_chunk(streamFile, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /*"vorb"*/
@ -259,7 +261,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
size_t wiih_size;
int i;
if (ww.bit_per_sample != 4) goto fail;
if (ww.bits_per_sample != 4) goto fail;
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_interleave;
@ -267,7 +269,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
/* find coef position */
if (find_chunk(streamFile, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH"*/ /* older Wwise */
vgmstream->num_samples = ww.data_size / ww.channels / 8 * 14;
vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels);
if (wiih_size != 0x2e * ww.channels) goto fail;
}
else if (ww.extra_size == 0x0c + ww.channels * 0x2e) { /* newer Wwise */
@ -295,17 +297,49 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
//"XMA2", "seek": same as the official ones
//"XMAc": Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data)
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (real LE XMA(2)WAVEFORMAT/EX are parsed elsewhere) */
VGM_LOG("WWISE: XMA2 found (unsupported)\n");
goto fail;
}
case XWMA: /* X360 */
VGM_LOG("WWISE: XWMA found (unsupported)\n");
goto fail;
case XWMA: { /* X360 */
ffmpeg_codec_data *ffmpeg_data = NULL;
uint8_t buf[100];
int bytes;
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);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
if ( !ffmpeg_data ) goto fail;
vgmstream->codec_data = ffmpeg_data;
vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none;
/* manually find total samples, why don't they put this in the header is beyond me */
if (ww.format == 0x0162) { /* WMAPRO */
xma_sample_data msd;
memset(&msd,0,sizeof(xma_sample_data));
msd.channels = ww.channels;
msd.data_offset = ww.data_offset;
msd.data_size = ww.data_size;
wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x0000);
vgmstream->num_samples = msd.num_samples;
} else { /* WMAv2 */
vgmstream->num_samples = ffmpeg_data->totalSamples; //todo inaccurate approximation using the avg_bps
}
break;
}
case AAC: { /* iOS/Mac */
ffmpeg_codec_data * ffmpeg_data = NULL;
if (ww.block_align != 0 || ww.bit_per_sample != 0) goto fail;
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
/* extra: size 0x12, unknown values */
@ -322,18 +356,18 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
case HEVAG: /* PSV */
/* changed values, another bizarre Wwise quirk */
//ww.block_align /* unknown (1ch=2, 2ch=4) */
//ww.bit_per_sample; /* probably interleave (0x10) */
//if (ww.bit_per_sample != 4) goto fail;
//ww.bits_per_sample; /* probably interleave (0x10) */
//if (ww.bits_per_sample != 4) goto fail;
if (ww.big_endian) goto fail;
/* extra_data: size 0x06, @0x00: samples per block (28), @0x04: channel config */
/* extra_data: size 0x06, @0x00: samples per block (0x1c), @0x04: channel config */
vgmstream->coding_type = coding_HEVAG;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->num_samples = ww.data_size * 28 / 16 / ww.channels;
vgmstream->num_samples = ps_bytes_to_samples(ww.data_size, ww.channels);
break;
case ATRAC9: /* PSV/PS4 */

View File

@ -380,7 +380,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
block_align = wma_block_align_index[block_index];
wma_codec = xwb.bits_per_sample ? 0x162 : 0x161; /* 0=WMAudio2, 1=WMAudio3 */
bytes = ffmpeg_make_riff_xwma(buf, 100, wma_codec, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
bytes = ffmpeg_make_riff_xwma(buf, 100, wma_codec, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, avg_bps, block_align);
if (bytes <= 0) goto fail;
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);