Fix XMA sample counting in big files [Dead Island (X360)]

This commit is contained in:
bnnm 2021-05-05 23:42:48 +02:00
parent 2564aa529f
commit c6a2184048
2 changed files with 106 additions and 103 deletions

View File

@ -19,11 +19,11 @@
* read num_bits (up to 25) from a bit offset. * read num_bits (up to 25) from a bit offset.
* 25 since we read a 32 bit int, and need to adjust up to 7 bits from the byte-rounded fseek (32-7=25) * 25 since we read a 32 bit int, and need to adjust up to 7 bits from the byte-rounded fseek (32-7=25)
*/ */
static uint32_t read_bitsBE_b(int64_t bit_offset, int num_bits, STREAMFILE *streamFile) { static uint32_t read_bitsBE_b(int64_t bit_offset, int num_bits, STREAMFILE* sf) {
uint32_t num, mask; uint32_t num, mask;
if (num_bits > 25) return -1; //??? if (num_bits > 25) return -1; //???
num = read_32bitBE(bit_offset / 8, streamFile); /* fseek rounded to 8 */ num = read_32bitBE(bit_offset / 8, sf); /* fseek rounded to 8 */
num = num << (bit_offset % 8); /* offset adjust (up to 7) */ num = num << (bit_offset % 8); /* offset adjust (up to 7) */
num = num >> (32 - num_bits); num = num >> (32 - num_bits);
mask = 0xffffffff >> (32 - num_bits); mask = 0xffffffff >> (32 - num_bits);
@ -37,7 +37,7 @@ static uint32_t read_bitsBE_b(int64_t bit_offset, int num_bits, STREAMFILE *stre
/* ******************************************** */ /* ******************************************** */
/* All helpers copy a RIFF header to buf and returns the number of bytes in buf or -1 when buf is not big enough */ /* All helpers copy a RIFF header to buf and returns the number of bytes in buf or -1 when buf is not big enough */
int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay) { int ffmpeg_make_riff_atrac3plus(uint8_t* buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay) {
uint16_t codec_ATRAC3plus = 0xfffe; /* wave format extensible */ uint16_t codec_ATRAC3plus = 0xfffe; /* wave format extensible */
size_t riff_size = 4+4+ 4 + 0x3c + 0x14 + 4+4; size_t riff_size = 4+4+ 4 + 0x3c + 0x14 + 4+4;
@ -80,7 +80,7 @@ int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_co
return riff_size; return riff_size;
} }
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_xma1(uint8_t* buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode) {
uint16_t codec_XMA1 = 0x0165; uint16_t codec_XMA1 = 0x0165;
size_t riff_size; size_t riff_size;
int streams, i; int streams, i;
@ -164,7 +164,7 @@ int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, s
return riff_size; return riff_size;
} }
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_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) {
uint16_t codec_XMA2 = 0x0166; uint16_t codec_XMA2 = 0x0166;
size_t riff_size = 4+4+ 4 + 0x3c + 4+4; size_t riff_size = 4+4+ 4 + 0x3c + 4+4;
size_t bytecount; size_t bytecount;
@ -225,17 +225,17 @@ int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, s
/* Makes a XMA1/2 RIFF header for FFmpeg using a "fmt " chunk (XMAWAVEFORMAT or XMA2WAVEFORMATEX) as a base: /* Makes a XMA1/2 RIFF header for FFmpeg using a "fmt " chunk (XMAWAVEFORMAT or XMA2WAVEFORMATEX) as a base:
* Useful to preserve the stream layout */ * Useful to preserve the stream layout */
int ffmpeg_make_riff_xma_from_fmt_chunk(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_xma_from_fmt_chunk(uint8_t* buf, size_t buf_size, off_t fmt_offset, size_t fmt_size, size_t data_size, STREAMFILE* sf, int big_endian) {
size_t riff_size = 4+4+ 4 + 4+4+fmt_size + 4+4; size_t riff_size = 4+4+ 4 + 4+4+fmt_size + 4+4;
uint8_t chunk[0x100]; uint8_t chunk[0x100];
if (buf_size < riff_size || fmt_size > 0x100) if (buf_size < riff_size || fmt_size > 0x100)
goto fail; goto fail;
if (read_streamfile(chunk,fmt_offset,fmt_size, streamFile) != fmt_size) if (read_streamfile(chunk,fmt_offset,fmt_size, sf) != fmt_size)
goto fail; goto fail;
if (big_endian) { if (big_endian) {
int codec = read_16bitBE(fmt_offset,streamFile); int codec = read_16bitBE(fmt_offset,sf);
ffmpeg_fmt_chunk_swap_endian(chunk, fmt_size, codec); ffmpeg_fmt_chunk_swap_endian(chunk, fmt_size, codec);
} }
@ -258,14 +258,14 @@ fail:
/* Makes a XMA2 RIFF header for FFmpeg using a "XMA2" chunk (XMA2WAVEFORMAT) as a base. /* Makes a XMA2 RIFF header for FFmpeg using a "XMA2" chunk (XMA2WAVEFORMAT) as a base.
* Useful to preserve the stream layout */ * Useful to preserve the stream layout */
int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t * buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE *streamFile) { int ffmpeg_make_riff_xma2_from_xma2_chunk(uint8_t* buf, size_t buf_size, off_t xma2_offset, size_t xma2_size, size_t data_size, STREAMFILE* sf) {
uint8_t chunk[0x100]; uint8_t chunk[0x100];
size_t riff_size; size_t riff_size;
riff_size = 4+4+ 4 + 4+4+xma2_size + 4+4; riff_size = 4+4+ 4 + 4+4+xma2_size + 4+4;
if (buf_size < riff_size || xma2_size > 0x100) if (buf_size < riff_size || xma2_size > 0x100)
goto fail; goto fail;
if (read_streamfile(chunk,xma2_offset,xma2_size, streamFile) != xma2_size) if (read_streamfile(chunk,xma2_offset,xma2_size, sf) != xma2_size)
goto fail; goto fail;
@ -286,7 +286,7 @@ fail:
return -1; return -1;
} }
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) { 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; size_t riff_size = 4+4+ 4 + 0x1a + 4+4;
if (buf_size < riff_size) if (buf_size < riff_size)
@ -343,7 +343,7 @@ int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data
} }
int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, size_t chunk_size, uint16_t codec) { int ffmpeg_fmt_chunk_swap_endian(uint8_t* chunk, size_t chunk_size, uint16_t codec) {
int i; int i;
/* swap from LE to BE or the other way around, doesn't matter */ /* swap from LE to BE or the other way around, doesn't matter */
switch(codec) { switch(codec) {
@ -403,23 +403,24 @@ fail:
/* XMA PARSING */ /* XMA PARSING */
/* ******************************************** */ /* ******************************************** */
static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, int64_t offset_b, int bits_frame_size, size_t *first_frame_b, size_t *packet_skip_count, size_t *header_size_b) { static void ms_audio_parse_header(STREAMFILE* sf, int xma_version, int64_t offset_b, int bits_frame_size, size_t *first_frame_b, size_t *packet_skip_count, size_t *header_size_b) {
if (xma_version == 1) { /* XMA1 */ if (xma_version == 1) { /* XMA1 */
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */ //packet_sequence = read_bitsBE_b(offset_b+0, 4, sf); /* numbered from 0 to N */
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */ //unknown = read_bitsBE_b(offset_b+4, 2, sf); /* packet_metadata? (always 2) */
*first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */ *first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, sf); /* 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 */ *packet_skip_count = read_bitsBE_b(offset_b+21, 11, sf); /* packets to skip for next packet of this stream */
*header_size_b = 32; *header_size_b = 32;
} else if (xma_version == 2) { /* XMA2 */ } else if (xma_version == 2) { /* XMA2 */
//frame_count = read_bitsBE_b(offset_b+0, 6, streamFile); /* frames that begin in this packet */ //frame_count = read_bitsBE_b(offset_b+0, 6, sf); /* frames that begin in this packet */
*first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside this packet */ *first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, sf); /* offset in bits inside this packet */
//packet_metadata = read_bitsBE_b(offset_b+21, 3, streamFile); /* packet_metadata (always 1) */ //packet_metadata = read_bitsBE_b(offset_b+21, 3, sf); /* packet_metadata (always 1) */
*packet_skip_count = read_bitsBE_b(offset_b+24, 8, streamFile); /* packets to skip for next packet of this stream */ *packet_skip_count = read_bitsBE_b(offset_b+24, 8, sf); /* packets to skip for next packet of this stream */
*header_size_b = 32; *header_size_b = 32;
} else { /* WMAPRO(v3) */ } else { /* WMAPRO(v3) */
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */ //packet_sequence = read_bitsBE_b(offset_b+0, 4, sf); /* numbered from 0 to N */
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */ //unknown = read_bitsBE_b(offset_b+4, 2, sf); /* packet_metadata? (always 2) */
*first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* offset in bits inside the packet */ *first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, sf); /* offset in bits inside the packet */
*packet_skip_count = 0; /* xwma has no need to skip packets since it uses real multichannel audio */ *packet_skip_count = 0; /* xwma has no need to skip packets since it uses real multichannel audio */
*header_size_b = 4+2+bits_frame_size; /* variable-sized header */ *header_size_b = 4+2+bits_frame_size; /* variable-sized header */
} }
@ -457,7 +458,7 @@ static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, int64
* *
* XMA1/XMA2/WMAPRO data only differs in the packet headers. * XMA1/XMA2/WMAPRO data only differs in the packet headers.
*/ */
static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int channels_per_packet, int bytes_per_packet, int samples_per_frame, int samples_per_subframe, int bits_frame_size) { static void ms_audio_get_samples(ms_sample_data* msd, STREAMFILE* sf, int channels_per_packet, 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; int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0;
size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b; size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b;
@ -465,9 +466,9 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
size_t packet_size = bytes_per_packet; size_t packet_size = bytes_per_packet;
size_t packet_size_b = packet_size * 8; size_t packet_size_b = packet_size * 8;
off_t offset = msd->data_offset; int64_t offset = msd->data_offset;
off_t max_offset = msd->data_offset + msd->data_size; int64_t max_offset = msd->data_offset + msd->data_size;
off_t stream_offset_b = msd->data_offset * 8; int64_t stream_offset_b = msd->data_offset * 8;
/* read packets */ /* read packets */
while (offset < max_offset) { while (offset < max_offset) {
@ -475,7 +476,7 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
offset += packet_size; /* global offset in bytes */ offset += packet_size; /* global offset in bytes */
/* packet header */ /* packet header */
ms_audio_parse_header(streamFile, msd->xma_version, offset_b, bits_frame_size, &first_frame_b, &packet_skip_count, &header_size_b); ms_audio_parse_header(sf, msd->xma_version, offset_b, bits_frame_size, &first_frame_b, &packet_skip_count, &header_size_b);
if (packet_skip_count > 0x7FF) { if (packet_skip_count > 0x7FF) {
continue; /* full skip */ continue; /* full skip */
} }
@ -496,7 +497,7 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
loop_end_frame = frames; loop_end_frame = frames;
/* frame header */ /* frame header */
frame_size_b = read_bitsBE_b(frame_offset_b, bits_frame_size, streamFile); frame_size_b = read_bitsBE_b(frame_offset_b, bits_frame_size, sf);
frame_offset_b += bits_frame_size; frame_offset_b += bits_frame_size;
/* stop when packet padding starts (0x00 for XMA1 or 0xFF in XMA2) */ /* stop when packet padding starts (0x00 for XMA1 or 0xFF in XMA2) */
@ -511,7 +512,7 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
/* last bit in frame = more frames flag, end packet to avoid reading garbage in some cases /* last bit in frame = more frames flag, end packet to avoid reading garbage in some cases
* (last frame spilling to other packets also has this flag, though it's ignored here) */ * (last frame spilling to other packets also has this flag, though it's ignored here) */
if (packet_offset_b < packet_size_b && !read_bitsBE_b(offset_b + packet_offset_b - 1, 1, streamFile)) { if (packet_offset_b < packet_size_b && !read_bitsBE_b(offset_b + packet_offset_b - 1, 1, sf)) {
break; break;
} }
} }
@ -534,7 +535,7 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
} }
/* simlar to the above but only gets skips */ /* simlar to the above but only gets skips */
static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t data_offset, int channels_per_packet, int bytes_per_packet, int samples_per_frame, int bits_frame_size, int *out_start_skip, int *out_end_skip) { static void ms_audio_get_skips(STREAMFILE* sf, int xma_version, off_t data_offset, int channels_per_packet, int bytes_per_packet, int samples_per_frame, int bits_frame_size, int *out_start_skip, int *out_end_skip) {
int start_skip = 0, end_skip = 0; int start_skip = 0, end_skip = 0;
size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b; size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b;
@ -550,7 +551,7 @@ static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t da
offset += packet_size; /* global offset in bytes */ offset += packet_size; /* global offset in bytes */
/* packet header */ /* packet header */
ms_audio_parse_header(streamFile, 2, offset_b, bits_frame_size, &first_frame_b, &packet_skip_count, &header_size_b); ms_audio_parse_header(sf, 2, offset_b, bits_frame_size, &first_frame_b, &packet_skip_count, &header_size_b);
if (packet_skip_count > 0x7FF) { if (packet_skip_count > 0x7FF) {
return; /* full skip */ return; /* full skip */
} }
@ -562,7 +563,7 @@ static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t da
frame_offset_b = offset_b + packet_offset_b; /* in bits for aligment stuff */ frame_offset_b = offset_b + packet_offset_b; /* in bits for aligment stuff */
/* frame header */ /* frame header */
frame_size_b = read_bitsBE_b(frame_offset_b, bits_frame_size, streamFile); frame_size_b = read_bitsBE_b(frame_offset_b, bits_frame_size, sf);
frame_offset_b += bits_frame_size; frame_offset_b += bits_frame_size;
/* stop when packet padding starts (0x00 for XMA1 or 0xFF in XMA2) */ /* stop when packet padding starts (0x00 for XMA1 or 0xFF in XMA2) */
@ -580,10 +581,10 @@ static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t da
/* ignore "postproc transform" */ /* ignore "postproc transform" */
if (channels_per_packet > 1) { if (channels_per_packet > 1) {
flag = read_bitsBE_b(frame_offset_b, 1, streamFile); flag = read_bitsBE_b(frame_offset_b, 1, sf);
frame_offset_b += 1; frame_offset_b += 1;
if (flag) { if (flag) {
flag = read_bitsBE_b(frame_offset_b, 1, streamFile); flag = read_bitsBE_b(frame_offset_b, 1, sf);
frame_offset_b += 1; frame_offset_b += 1;
if (flag) { if (flag) {
frame_offset_b += 1 + 4 * channels_per_packet*channels_per_packet; /* 4-something per double channel? */ frame_offset_b += 1 + 4 * channels_per_packet*channels_per_packet; /* 4-something per double channel? */
@ -592,14 +593,14 @@ static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t da
} }
/* get start/end skips to get the proper number of samples (both can be 0) */ /* get start/end skips to get the proper number of samples (both can be 0) */
flag = read_bitsBE_b(frame_offset_b, 1, streamFile); flag = read_bitsBE_b(frame_offset_b, 1, sf);
frame_offset_b += 1; frame_offset_b += 1;
if (flag) { if (flag) {
/* get start skip */ /* get start skip */
flag = read_bitsBE_b(frame_offset_b, 1, streamFile); flag = read_bitsBE_b(frame_offset_b, 1, sf);
frame_offset_b += 1; frame_offset_b += 1;
if (flag) { if (flag) {
int new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile); int new_skip = read_bitsBE_b(frame_offset_b, 10, sf);
//;VGM_LOG("MS_SAMPLES: start_skip %i at 0x%x (bit 0x%x)\n", new_skip, (uint32_t)frame_offset_b/8, (uint32_t)frame_offset_b); //;VGM_LOG("MS_SAMPLES: start_skip %i at 0x%x (bit 0x%x)\n", new_skip, (uint32_t)frame_offset_b/8, (uint32_t)frame_offset_b);
frame_offset_b += 10; frame_offset_b += 10;
@ -611,10 +612,10 @@ static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t da
} }
/* get end skip */ /* get end skip */
flag = read_bitsBE_b(frame_offset_b, 1, streamFile); flag = read_bitsBE_b(frame_offset_b, 1, sf);
frame_offset_b += 1; frame_offset_b += 1;
if (flag) { if (flag) {
int new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile); int new_skip = read_bitsBE_b(frame_offset_b, 10, sf);
//;VGM_LOG("MS_SAMPLES: end_skip %i at 0x%x (bit 0x%x)\n", new_skip, (uint32_t)frame_offset_b/8, (uint32_t)frame_offset_b); //;VGM_LOG("MS_SAMPLES: end_skip %i at 0x%x (bit 0x%x)\n", new_skip, (uint32_t)frame_offset_b/8, (uint32_t)frame_offset_b);
frame_offset_b += 10; frame_offset_b += 10;
@ -661,20 +662,20 @@ static int wma_get_samples_per_frame(int version, int sample_rate, uint32_t deco
return 1 << frame_len_bits; return 1 << frame_len_bits;
} }
static int xma_get_channels_per_stream(STREAMFILE* streamFile, off_t chunk_offset, int channels) { static int xma_get_channels_per_stream(STREAMFILE* sf, off_t chunk_offset, int channels) {
int start_stream = 0; int start_stream = 0;
int channels_per_stream = 0; int channels_per_stream = 0;
/* get from stream config (needed to find skips) */ /* get from stream config (needed to find skips) */
if (chunk_offset) { if (chunk_offset) {
int format = read_16bitLE(chunk_offset,streamFile); int format = read_16bitLE(chunk_offset,sf);
if (format == 0x0165 || format == 0x6501) { /* XMA1 */ if (format == 0x0165 || format == 0x6501) { /* XMA1 */
channels_per_stream = read_8bit(chunk_offset + 0x0C + 0x14*start_stream + 0x11,streamFile); channels_per_stream = read_8bit(chunk_offset + 0x0C + 0x14*start_stream + 0x11,sf);
} else if (format == 0x0166 || format == 0x6601) { /* new XMA2 */ } else if (format == 0x0166 || format == 0x6601) { /* new XMA2 */
channels_per_stream = channels > 1 ? 2 : 1; channels_per_stream = channels > 1 ? 2 : 1;
} else { /* old XMA2 */ } else { /* old XMA2 */
int version = read_8bit(chunk_offset,streamFile); int version = read_8bit(chunk_offset,sf);
channels_per_stream = read_8bit(chunk_offset + 0x20 + (version==3 ? 0x00 : 0x08) + 0x4*start_stream + 0x00,streamFile); channels_per_stream = read_8bit(chunk_offset + 0x20 + (version==3 ? 0x00 : 0x08) + 0x4*start_stream + 0x00,sf);
} }
} }
else if (channels) { else if (channels) {
@ -687,17 +688,17 @@ static int xma_get_channels_per_stream(STREAMFILE* streamFile, off_t chunk_offse
return channels_per_stream; return channels_per_stream;
} }
void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile) { void xma_get_samples(ms_sample_data* msd, STREAMFILE* sf) {
const int bytes_per_packet = 2048; const int bytes_per_packet = 2048;
const int samples_per_frame = 512; const int samples_per_frame = 512;
const int samples_per_subframe = 128; const int samples_per_subframe = 128;
const int bits_frame_size = 15; const int bits_frame_size = 15;
int channels_per_stream = xma_get_channels_per_stream(streamFile, msd->chunk_offset, msd->channels); int channels_per_stream = xma_get_channels_per_stream(sf, msd->chunk_offset, msd->channels);
ms_audio_get_samples(msd, streamFile, channels_per_stream, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size); ms_audio_get_samples(msd, sf, channels_per_stream, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size);
} }
void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) { void wmapro_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags) {
const int version = 3; /* WMAPRO = WMAv3 */ const int version = 3; /* WMAPRO = WMAv3 */
int bytes_per_packet = block_align; int bytes_per_packet = block_align;
int samples_per_frame = 0; int samples_per_frame = 0;
@ -715,10 +716,10 @@ void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_
samples_per_subframe = 0; /* not needed as WMAPro can't use loop subframes (complex subframe lengths) */ samples_per_subframe = 0; /* not needed as WMAPro can't use loop subframes (complex subframe lengths) */
msd->xma_version = 0; /* signal it's not XMA */ msd->xma_version = 0; /* signal it's not XMA */
ms_audio_get_samples(msd, streamFile, channels_per_stream, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size); ms_audio_get_samples(msd, sf, channels_per_stream, bytes_per_packet, samples_per_frame, samples_per_subframe, bits_frame_size);
} }
void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) { void wma_get_samples(ms_sample_data* msd, STREAMFILE* sf, int block_align, int sample_rate, uint32_t decode_flags) {
const int version = 2; /* WMAv1 rarely used */ const int version = 2; /* WMAv1 rarely used */
int use_bit_reservoir = 0; /* last packet frame can spill into the next packet */ int use_bit_reservoir = 0; /* last packet frame can spill into the next packet */
int samples_per_frame = 0; int samples_per_frame = 0;
@ -741,7 +742,7 @@ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ali
off_t max_offset = msd->data_offset + msd->data_size; off_t max_offset = msd->data_offset + msd->data_size;
while (offset < max_offset) { /* read packets (superframes) */ while (offset < max_offset) { /* read packets (superframes) */
int packet_frames; int packet_frames;
uint8_t header = read_8bit(offset, streamFile); /* upper nibble: index; lower nibble: frames */ uint8_t header = read_8bit(offset, sf); /* upper nibble: index; lower nibble: frames */
/* frames starting in this packet (ie. counts frames that spill due to bit_reservoir) */ /* frames starting in this packet (ie. counts frames that spill due to bit_reservoir) */
packet_frames = (header & 0xf); packet_frames = (header & 0xf);
@ -763,7 +764,7 @@ void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_ali
/* XMA hell for precise looping and gapless support, fixes raw sample values from headers /* XMA hell for precise looping and gapless support, fixes raw sample values from headers
* that don't count XMA's final subframe/encoder delay/encoder padding, and FFmpeg stuff. * that don't count XMA's final subframe/encoder delay/encoder padding, and FFmpeg stuff.
* Configurable since different headers vary for maximum annoyance. */ * Configurable since different headers vary for maximum annoyance. */
void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, int channels_per_stream, int fix_num_samples, int fix_loop_samples) { void xma_fix_raw_samples_ch(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t stream_offset, size_t stream_size, int channels_per_stream, int fix_num_samples, int fix_loop_samples) {
const int bytes_per_packet = 2048; const int bytes_per_packet = 2048;
const int samples_per_frame = 512; const int samples_per_frame = 512;
const int samples_per_subframe = 128; const int samples_per_subframe = 128;
@ -774,7 +775,7 @@ void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t s
off_t last_packet = stream_offset + stream_size - bytes_per_packet; off_t last_packet = stream_offset + stream_size - bytes_per_packet;
int32_t start_skip = 0, end_skip = 0; int32_t start_skip = 0, end_skip = 0;
if (stream_offset + stream_size > get_streamfile_size(streamFile)) { if (stream_offset + stream_size > get_streamfile_size(sf)) {
VGM_LOG("XMA SKIPS: ignoring bad stream offset+size vs real size\n"); VGM_LOG("XMA SKIPS: ignoring bad stream offset+size vs real size\n");
return; return;
} }
@ -782,8 +783,8 @@ void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t s
/* find delay/padding values in the bitstream (should be safe even w/ multistreams /* find delay/padding values in the bitstream (should be safe even w/ multistreams
* as every stream repeats them). Theoretically every packet could contain skips, * as every stream repeats them). Theoretically every packet could contain skips,
* doesn't happen in practice though. */ * doesn't happen in practice though. */
ms_audio_get_skips(streamFile, xma_version, first_packet, channels_per_stream, bytes_per_packet, samples_per_frame, bits_frame_size, &start_skip, NULL); ms_audio_get_skips(sf, xma_version, first_packet, channels_per_stream, bytes_per_packet, samples_per_frame, bits_frame_size, &start_skip, NULL);
ms_audio_get_skips(streamFile, xma_version, last_packet, channels_per_stream, bytes_per_packet, samples_per_frame, bits_frame_size, NULL, &end_skip); ms_audio_get_skips(sf, xma_version, last_packet, channels_per_stream, bytes_per_packet, samples_per_frame, bits_frame_size, NULL, &end_skip);
//;VGM_LOG("XMA SKIPS: apply start=%i, end=%i\n", start_skip, end_skip); //;VGM_LOG("XMA SKIPS: apply start=%i, end=%i\n", start_skip, end_skip);
VGM_ASSERT(start_skip < samples_per_frame, "XMA SKIPS: small start skip\n"); VGM_ASSERT(start_skip < samples_per_frame, "XMA SKIPS: small start skip\n");
@ -835,14 +836,14 @@ void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t s
#endif #endif
} }
void xma_fix_raw_samples_hb(VGMSTREAM *vgmstream, STREAMFILE *headerFile, STREAMFILE *bodyFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) { void xma_fix_raw_samples_hb(VGMSTREAM* vgmstream, STREAMFILE* sf_head, STREAMFILE* sf_body, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) {
int channels_per_stream = xma_get_channels_per_stream(headerFile, chunk_offset, vgmstream->channels); int channels_per_stream = xma_get_channels_per_stream(sf_head, chunk_offset, vgmstream->channels);
xma_fix_raw_samples_ch(vgmstream, bodyFile, stream_offset, stream_size, channels_per_stream, fix_num_samples, fix_loop_samples); xma_fix_raw_samples_ch(vgmstream, sf_body, stream_offset, stream_size, channels_per_stream, fix_num_samples, fix_loop_samples);
} }
void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) { void xma_fix_raw_samples(VGMSTREAM* vgmstream, STREAMFILE* sf, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples) {
int channels_per_stream = xma_get_channels_per_stream(streamFile, chunk_offset, vgmstream->channels); int channels_per_stream = xma_get_channels_per_stream(sf, chunk_offset, vgmstream->channels);
xma_fix_raw_samples_ch(vgmstream, streamFile, stream_offset, stream_size, channels_per_stream, fix_num_samples, fix_loop_samples); xma_fix_raw_samples_ch(vgmstream, sf, stream_offset, stream_size, channels_per_stream, fix_num_samples, fix_loop_samples);
} }
@ -852,46 +853,46 @@ void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stre
/* Read values from a XMA1 RIFF "fmt" chunk (XMAWAVEFORMAT), starting from an offset *after* chunk type+size. /* Read values from a XMA1 RIFF "fmt" chunk (XMAWAVEFORMAT), starting from an offset *after* chunk type+size.
* Useful as custom X360 headers commonly have it lurking inside. */ * Useful as custom X360 headers commonly have it lurking inside. */
void xma1_parse_fmt_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * loop_start_b, int32_t * loop_end_b, int32_t * loop_subframe, int be) { void xma1_parse_fmt_chunk(STREAMFILE* sf, off_t chunk_offset, int * channels, int* sample_rate, int* loop_flag, int32_t * loop_start_b, int32_t * loop_end_b, int32_t * loop_subframe, int be) {
int16_t (*read_16bit)(off_t,STREAMFILE*) = be ? read_16bitBE : read_16bitLE; int16_t (*read_16bit)(off_t,STREAMFILE*) = be ? read_16bitBE : read_16bitLE;
int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE; int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE;
int i, num_streams, total_channels = 0; int i, num_streams, total_channels = 0;
if (read_16bit(chunk_offset+0x00,streamFile) != 0x165) if (read_16bit(chunk_offset+0x00,sf) != 0x165)
return; return;
num_streams = read_16bit(chunk_offset+0x08,streamFile); num_streams = read_16bit(chunk_offset+0x08,sf);
if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0xA,streamFile) > 0; if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0xA,sf) > 0;
/* sample rate and loop bit offsets are defined per stream, but the first is enough */ /* sample rate and loop bit offsets are defined per stream, but the first is enough */
if(sample_rate) *sample_rate = read_32bit(chunk_offset+0x10,streamFile); if(sample_rate) *sample_rate = read_32bit(chunk_offset+0x10,sf);
if(loop_start_b) *loop_start_b = read_32bit(chunk_offset+0x14,streamFile); if(loop_start_b) *loop_start_b = read_32bit(chunk_offset+0x14,sf);
if(loop_end_b) *loop_end_b = read_32bit(chunk_offset+0x18,streamFile); if(loop_end_b) *loop_end_b = read_32bit(chunk_offset+0x18,sf);
if(loop_subframe) *loop_subframe = (uint8_t)read_8bit(chunk_offset+0x1C,streamFile); if(loop_subframe) *loop_subframe = (uint8_t)read_8bit(chunk_offset+0x1C,sf);
/* channels is the sum of all streams */ /* channels is the sum of all streams */
for (i = 0; i < num_streams; i++) { for (i = 0; i < num_streams; i++) {
total_channels += read_8bit(chunk_offset+0x0C+0x14*i+0x11,streamFile); total_channels += read_8bit(chunk_offset+0x0C+0x14*i+0x11,sf);
} }
if(channels) *channels = total_channels; if(channels) *channels = total_channels;
} }
/* Read values from a 'new' XMA2 RIFF "fmt" chunk (XMA2WAVEFORMATEX), starting from an offset *after* chunk type+size. /* Read values from a 'new' XMA2 RIFF "fmt" chunk (XMA2WAVEFORMATEX), starting from an offset *after* chunk type+size.
* Useful as custom X360 headers commonly have it lurking inside. Only parses the extra data (before is a normal WAVEFORMATEX). */ * Useful as custom X360 headers commonly have it lurking inside. Only parses the extra data (before is a normal WAVEFORMATEX). */
void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * out_loop_flag, int32_t * out_num_samples, int32_t * out_loop_start_sample, int32_t * out_loop_end_sample, int be) { void xma2_parse_fmt_chunk_extra(STREAMFILE* sf, off_t chunk_offset, int* out_loop_flag, int32_t* out_num_samples, int32_t* out_loop_start_sample, int32_t* out_loop_end_sample, int be) {
int16_t (*read_16bit)(off_t,STREAMFILE*) = be ? read_16bitBE : read_16bitLE; int16_t (*read_16bit)(off_t,STREAMFILE*) = be ? read_16bitBE : read_16bitLE;
int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE; int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE;
int num_samples, loop_start_sample, loop_end_sample, loop_flag; int num_samples, loop_start_sample, loop_end_sample, loop_flag;
if (read_16bit(chunk_offset+0x00,streamFile) != 0x166) if (read_16bit(chunk_offset+0x00,sf) != 0x166)
return; return;
if (read_16bit(chunk_offset+0x10,streamFile) < 0x22) if (read_16bit(chunk_offset+0x10,sf) < 0x22)
return; /* expected extra data size */ return; /* expected extra data size */
num_samples = read_32bit(chunk_offset+0x18,streamFile); num_samples = read_32bit(chunk_offset+0x18,sf);
loop_start_sample = read_32bit(chunk_offset+0x28,streamFile); loop_start_sample = read_32bit(chunk_offset+0x28,sf);
loop_end_sample = loop_start_sample + read_32bit(chunk_offset+0x2C,streamFile); loop_end_sample = loop_start_sample + read_32bit(chunk_offset+0x2C,sf);
loop_flag = (uint8_t)read_8bit(chunk_offset+0x30,streamFile) != 0; loop_flag = (uint8_t)read_8bit(chunk_offset+0x30,sf) != 0;
/* may need loop end +1, though some header doesn't need it (ex.- Sonic and Sega All Stars Racing .str) */ /* may need loop end +1, though some header doesn't need it (ex.- Sonic and Sega All Stars Racing .str) */
/* flag rarely set, use loop_end as marker */ /* flag rarely set, use loop_end as marker */
@ -912,35 +913,35 @@ void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int
if(out_loop_flag) *out_loop_flag = loop_flag; if(out_loop_flag) *out_loop_flag = loop_flag;
/* play_begin+end = pcm_samples in original sample rate (not usable as file may be resampled) */ /* play_begin+end = pcm_samples in original sample rate (not usable as file may be resampled) */
/* int32_t play_begin_sample = read_32bit(xma->chunk_offset+0x20,streamFile); */ /* int32_t play_begin_sample = read_32bit(xma->chunk_offset+0x20,sf); */
/* int32_t play_end_sample = play_begin_sample + read_32bit(xma->chunk_offset+0x24,streamFile); */ /* int32_t play_end_sample = play_begin_sample + read_32bit(xma->chunk_offset+0x24,sf); */
} }
/* Read values from an 'old' XMA2 RIFF "XMA2" chunk (XMA2WAVEFORMAT), starting from an offset *after* chunk type+size. /* Read values from an 'old' XMA2 RIFF "XMA2" chunk (XMA2WAVEFORMAT), starting from an offset *after* chunk type+size.
* Useful as custom X360 headers commonly have it lurking inside. */ * Useful as custom X360 headers commonly have it lurking inside. */
void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * out_channels, int * out_sample_rate, int * out_loop_flag, int32_t * out_num_samples, int32_t * out_loop_start_sample, int32_t * out_loop_end_sample) { void xma2_parse_xma2_chunk(STREAMFILE* sf, off_t chunk_offset, int* out_channels, int* out_sample_rate, int* out_loop_flag, int32_t* out_num_samples, int32_t* out_loop_start_sample, int32_t* out_loop_end_sample) {
int32_t (*read_32bit)(off_t,STREAMFILE*) = read_32bitBE; /* XMA2WAVEFORMAT is always big endian */ int32_t (*read_32bit)(off_t,STREAMFILE*) = read_32bitBE; /* XMA2WAVEFORMAT is always big endian */
int i, xma2_chunk_version, num_streams; int i, xma2_chunk_version, num_streams;
int channels, sample_rate, loop_flag, num_samples, loop_start_sample, loop_end_sample; int channels, sample_rate, loop_flag, num_samples, loop_start_sample, loop_end_sample;
off_t offset; off_t offset;
xma2_chunk_version = read_8bit(chunk_offset+0x00,streamFile); xma2_chunk_version = read_8bit(chunk_offset+0x00,sf);
num_streams = read_8bit(chunk_offset+0x01,streamFile); num_streams = read_8bit(chunk_offset+0x01,sf);
loop_start_sample = read_32bit(chunk_offset+0x04,streamFile); loop_start_sample = read_32bit(chunk_offset+0x04,sf);
loop_end_sample = read_32bit(chunk_offset+0x08,streamFile); loop_end_sample = read_32bit(chunk_offset+0x08,sf);
loop_flag = (uint8_t)read_8bit(chunk_offset+0x03,streamFile) > 0 || loop_end_sample; /* rarely not set, encoder default */ loop_flag = (uint8_t)read_8bit(chunk_offset+0x03,sf) > 0 || loop_end_sample; /* rarely not set, encoder default */
sample_rate = read_32bit(chunk_offset+0x0c,streamFile); sample_rate = read_32bit(chunk_offset+0x0c,sf);
/* may need loop end +1 */ /* may need loop end +1 */
offset = xma2_chunk_version == 3 ? 0x14 : 0x1C; offset = xma2_chunk_version == 3 ? 0x14 : 0x1C;
num_samples = read_32bit(chunk_offset+offset+0x00,streamFile); num_samples = read_32bit(chunk_offset+offset+0x00,sf);
/* pcm_samples in original sample rate (not usable as file may be resampled) */ /* pcm_samples in original sample rate (not usable as file may be resampled) */
/* pcm_samples = read_32bitBE(chunk_offset+offset+0x04,streamFile)*/ /* pcm_samples = read_32bitBE(chunk_offset+offset+0x04,sf)*/
offset = xma2_chunk_version == 3 ? 0x20 : 0x28; offset = xma2_chunk_version == 3 ? 0x20 : 0x28;
channels = 0; /* channels is the sum of all streams */ channels = 0; /* channels is the sum of all streams */
for (i = 0; i < num_streams; i++) { for (i = 0; i < num_streams; i++) {
channels += read_8bit(chunk_offset+offset+i*0x04,streamFile); channels += read_8bit(chunk_offset+offset+i*0x04,sf);
} }
/* samples are "raw" values, must be fixed externally (see xma_fix_raw_samples) */ /* samples are "raw" values, must be fixed externally (see xma_fix_raw_samples) */
@ -976,17 +977,17 @@ size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels) {
} }
size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes) { size_t aac_get_samples(STREAMFILE* sf, off_t start_offset, size_t bytes) {
const int samples_per_frame = 1024; /* theoretically 960 exists in .MP4 so may need a flag */ const int samples_per_frame = 1024; /* theoretically 960 exists in .MP4 so may need a flag */
int frames = 0; int frames = 0;
off_t offset = start_offset; off_t offset = start_offset;
off_t max_offset = start_offset + bytes; off_t max_offset = start_offset + bytes;
if (!streamFile) if (!sf)
return 0; return 0;
if (max_offset > get_streamfile_size(streamFile)) if (max_offset > get_streamfile_size(sf))
max_offset = get_streamfile_size(streamFile); max_offset = get_streamfile_size(sf);
/* AAC sometimes comes with an "ADIF" header right before data but probably not in games, /* AAC sometimes comes with an "ADIF" header right before data but probably not in games,
* while standard raw frame headers are called "ADTS" and are similar to MPEG's: * while standard raw frame headers are called "ADTS" and are similar to MPEG's:
@ -994,8 +995,8 @@ size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes)
/* AAC uses VBR so must read all frames */ /* AAC uses VBR so must read all frames */
while (offset < max_offset) { while (offset < max_offset) {
uint16_t frame_sync = read_u16be(offset+0x00, streamFile); uint16_t frame_sync = read_u16be(offset+0x00, sf);
uint32_t frame_size = read_u32be(offset+0x02, streamFile); uint32_t frame_size = read_u32be(offset+0x02, sf);
frame_sync = (frame_sync >> 4) & 0x0FFF; /* 12b */ frame_sync = (frame_sync >> 4) & 0x0FFF; /* 12b */
frame_size = (frame_size >> 5) & 0x1FFF; /* 13b */ frame_size = (frame_size >> 5) & 0x1FFF; /* 13b */
@ -1016,7 +1017,7 @@ size_t aac_get_samples(STREAMFILE *streamFile, off_t start_offset, size_t bytes)
/* CUSTOM STREAMFILES */ /* CUSTOM STREAMFILES */
/* ******************************************** */ /* ******************************************** */
STREAMFILE* setup_subfile_streamfile(STREAMFILE *sf, off_t subfile_offset, size_t subfile_size, const char* extension) { STREAMFILE* setup_subfile_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, const char* extension) {
STREAMFILE *new_sf = NULL; STREAMFILE *new_sf = NULL;
new_sf = open_wrap_streamfile(sf); new_sf = open_wrap_streamfile(sf);

View File

@ -242,10 +242,6 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
if (xwb.version <= XACT1_1_MAX) { if (xwb.version <= XACT1_1_MAX) {
xwb.entry_flags = entry_info; xwb.entry_flags = entry_info;
} }
else if (xwb.version == XACT_TECHLAND) { /* Nail'd (X360) */
xwb.entry_flags = 0;
xwb.num_samples = 0;//(entry_info >> 1) & 0x7FFFFFFF; /* seems ok for music banks but not sfx, fixed later */
}
else { else {
xwb.entry_flags = (entry_info) & 0xF; /*4b*/ xwb.entry_flags = (entry_info) & 0xF; /*4b*/
xwb.num_samples = (entry_info >> 4) & 0x0FFFFFFF; /*28b*/ xwb.num_samples = (entry_info >> 4) & 0x0FFFFFFF; /*28b*/
@ -428,7 +424,13 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
xwb.fix_xma_loop_samples = 1; xwb.fix_xma_loop_samples = 1;
xwb.fix_xma_num_samples = 0; xwb.fix_xma_num_samples = 0;
/* for XWB v22 (and below?) this seems normal, also techland [Project Gotham Racing (X360)] */ /* Techland's XMA in tool_version 0x2a (not 0x2c?) seems to use (entry_info >> 1) num_samples
* for music banks, but not sfx [Nail'd (X360)-0x2a, Dead Island (X360)-0x2c] */
if (xwb.version == XACT_TECHLAND) {
xwb.num_samples = 0;
}
/* for XWB v22 (and below?) this seems normal [Project Gotham Racing (X360)] */
if (xwb.num_samples == 0) { if (xwb.num_samples == 0) {
xwb.num_samples = msd.num_samples; xwb.num_samples = msd.num_samples;
xwb.fix_xma_num_samples = 1; xwb.fix_xma_num_samples = 1;