mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
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:
parent
2086426175
commit
3619b14f8e
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user