mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 16:30:54 +01:00
Merge pull request #853 from bnnm/xwb2
- Fix XMA sample counting in big files [Dead Island (X360)] - Tweak .int validations
This commit is contained in:
commit
7e3e15c12b
@ -466,7 +466,9 @@ a perfectly valid *!tags.m3u*:
|
||||
# @ARTIST Various Artists
|
||||
```
|
||||
|
||||
### Non-English filenames and tags
|
||||
### Compatibility and non-English filenames and tags
|
||||
For best compatibility save `!tags.m3u` as *"ANSI"* or *"UTF-8" (with BOM)*.
|
||||
|
||||
Tags and filenames using extended characters (like Japanese) should work, as long
|
||||
as `!tags.m3u` is saved as *"UTF-8 with BOM"* (UTF-8 is a way to define non-English
|
||||
characters, and BOM is a helper "byte-order" mark). Windows' *notepad* creates files
|
||||
|
@ -19,11 +19,11 @@
|
||||
* 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)
|
||||
*/
|
||||
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;
|
||||
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 >> (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 */
|
||||
|
||||
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 */
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
size_t riff_size;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
size_t riff_size = 4+4+ 4 + 0x3c + 4+4;
|
||||
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:
|
||||
* 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;
|
||||
uint8_t chunk[0x100];
|
||||
|
||||
if (buf_size < riff_size || fmt_size > 0x100)
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -258,14 +258,14 @@ fail:
|
||||
|
||||
/* Makes a XMA2 RIFF header for FFmpeg using a "XMA2" chunk (XMA2WAVEFORMAT) as a base.
|
||||
* 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];
|
||||
size_t riff_size;
|
||||
|
||||
riff_size = 4+4+ 4 + 4+4+xma2_size + 4+4;
|
||||
if (buf_size < riff_size || xma2_size > 0x100)
|
||||
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;
|
||||
|
||||
|
||||
@ -286,7 +286,7 @@ fail:
|
||||
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;
|
||||
|
||||
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;
|
||||
/* swap from LE to BE or the other way around, doesn't matter */
|
||||
switch(codec) {
|
||||
@ -403,23 +403,24 @@ fail:
|
||||
/* 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 */
|
||||
//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 = read_bitsBE_b(offset_b+21, 11, streamFile); /* packets to skip for next packet of this stream */
|
||||
//packet_sequence = read_bitsBE_b(offset_b+0, 4, sf); /* numbered from 0 to N */
|
||||
//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, sf); /* offset in bits inside the packet */
|
||||
*packet_skip_count = read_bitsBE_b(offset_b+21, 11, sf); /* packets to skip for next packet of this stream */
|
||||
*header_size_b = 32;
|
||||
} else if (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, 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 */
|
||||
//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, sf); /* offset in bits inside this packet */
|
||||
//packet_metadata = read_bitsBE_b(offset_b+21, 3, sf); /* packet_metadata (always 1) */
|
||||
*packet_skip_count = read_bitsBE_b(offset_b+24, 8, sf); /* 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_sequence = read_bitsBE_b(offset_b+0, 4, sf); /* numbered from 0 to N */
|
||||
//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, sf); /* offset in bits inside the packet */
|
||||
*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 */
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
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;
|
||||
|
||||
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_b = packet_size * 8;
|
||||
off_t offset = msd->data_offset;
|
||||
off_t max_offset = msd->data_offset + msd->data_size;
|
||||
off_t stream_offset_b = msd->data_offset * 8;
|
||||
int64_t offset = msd->data_offset;
|
||||
int64_t max_offset = msd->data_offset + msd->data_size;
|
||||
int64_t stream_offset_b = msd->data_offset * 8;
|
||||
|
||||
/* read packets */
|
||||
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 */
|
||||
|
||||
/* 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) {
|
||||
continue; /* full skip */
|
||||
}
|
||||
@ -496,7 +497,7 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
|
||||
loop_end_frame = frames;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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 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;
|
||||
}
|
||||
}
|
||||
@ -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 */
|
||||
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;
|
||||
|
||||
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 */
|
||||
|
||||
/* 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) {
|
||||
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 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;
|
||||
|
||||
/* 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" */
|
||||
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;
|
||||
if (flag) {
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, sf);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
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) */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, sf);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
/* 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;
|
||||
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);
|
||||
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 */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, sf);
|
||||
frame_offset_b += 1;
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
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 channels_per_stream = 0;
|
||||
|
||||
/* get from stream config (needed to find skips) */
|
||||
if (chunk_offset) {
|
||||
int format = read_16bitLE(chunk_offset,streamFile);
|
||||
int format = read_16bitLE(chunk_offset,sf);
|
||||
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 */
|
||||
channels_per_stream = channels > 1 ? 2 : 1;
|
||||
} else { /* old XMA2 */
|
||||
int version = read_8bit(chunk_offset,streamFile);
|
||||
channels_per_stream = read_8bit(chunk_offset + 0x20 + (version==3 ? 0x00 : 0x08) + 0x4*start_stream + 0x00,streamFile);
|
||||
int version = read_8bit(chunk_offset,sf);
|
||||
channels_per_stream = read_8bit(chunk_offset + 0x20 + (version==3 ? 0x00 : 0x08) + 0x4*start_stream + 0x00,sf);
|
||||
}
|
||||
}
|
||||
else if (channels) {
|
||||
@ -687,17 +688,17 @@ static int xma_get_channels_per_stream(STREAMFILE* streamFile, off_t chunk_offse
|
||||
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 samples_per_frame = 512;
|
||||
const int samples_per_subframe = 128;
|
||||
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 */
|
||||
int bytes_per_packet = block_align;
|
||||
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) */
|
||||
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 */
|
||||
int use_bit_reservoir = 0; /* last packet frame can spill into the next packet */
|
||||
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;
|
||||
while (offset < max_offset) { /* read packets (superframes) */
|
||||
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) */
|
||||
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
|
||||
* that don't count XMA's final subframe/encoder delay/encoder padding, and FFmpeg stuff.
|
||||
* 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 samples_per_frame = 512;
|
||||
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;
|
||||
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");
|
||||
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
|
||||
* as every stream repeats them). Theoretically every packet could contain skips,
|
||||
* 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(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, first_packet, channels_per_stream, bytes_per_packet, samples_per_frame, bits_frame_size, &start_skip, NULL);
|
||||
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_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
|
||||
}
|
||||
|
||||
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) {
|
||||
int channels_per_stream = xma_get_channels_per_stream(headerFile, chunk_offset, vgmstream->channels);
|
||||
xma_fix_raw_samples_ch(vgmstream, bodyFile, stream_offset, stream_size, channels_per_stream, fix_num_samples, 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(sf_head, chunk_offset, vgmstream->channels);
|
||||
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) {
|
||||
int channels_per_stream = xma_get_channels_per_stream(streamFile, chunk_offset, vgmstream->channels);
|
||||
xma_fix_raw_samples_ch(vgmstream, streamFile, stream_offset, stream_size, channels_per_stream, fix_num_samples, 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(sf, chunk_offset, vgmstream->channels);
|
||||
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.
|
||||
* 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;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE;
|
||||
int i, num_streams, total_channels = 0;
|
||||
|
||||
if (read_16bit(chunk_offset+0x00,streamFile) != 0x165)
|
||||
if (read_16bit(chunk_offset+0x00,sf) != 0x165)
|
||||
return;
|
||||
|
||||
num_streams = read_16bit(chunk_offset+0x08,streamFile);
|
||||
if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0xA,streamFile) > 0;
|
||||
num_streams = read_16bit(chunk_offset+0x08,sf);
|
||||
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 */
|
||||
if(sample_rate) *sample_rate = read_32bit(chunk_offset+0x10,streamFile);
|
||||
if(loop_start_b) *loop_start_b = read_32bit(chunk_offset+0x14,streamFile);
|
||||
if(loop_end_b) *loop_end_b = read_32bit(chunk_offset+0x18,streamFile);
|
||||
if(loop_subframe) *loop_subframe = (uint8_t)read_8bit(chunk_offset+0x1C,streamFile);
|
||||
if(sample_rate) *sample_rate = read_32bit(chunk_offset+0x10,sf);
|
||||
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,sf);
|
||||
if(loop_subframe) *loop_subframe = (uint8_t)read_8bit(chunk_offset+0x1C,sf);
|
||||
|
||||
/* channels is the sum of all streams */
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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). */
|
||||
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;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = be ? read_32bitBE : read_32bitLE;
|
||||
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;
|
||||
if (read_16bit(chunk_offset+0x10,streamFile) < 0x22)
|
||||
if (read_16bit(chunk_offset+0x10,sf) < 0x22)
|
||||
return; /* expected extra data size */
|
||||
|
||||
num_samples = read_32bit(chunk_offset+0x18,streamFile);
|
||||
loop_start_sample = read_32bit(chunk_offset+0x28,streamFile);
|
||||
loop_end_sample = loop_start_sample + read_32bit(chunk_offset+0x2C,streamFile);
|
||||
loop_flag = (uint8_t)read_8bit(chunk_offset+0x30,streamFile) != 0;
|
||||
num_samples = read_32bit(chunk_offset+0x18,sf);
|
||||
loop_start_sample = read_32bit(chunk_offset+0x28,sf);
|
||||
loop_end_sample = loop_start_sample + read_32bit(chunk_offset+0x2C,sf);
|
||||
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) */
|
||||
|
||||
/* 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;
|
||||
|
||||
/* 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_end_sample = play_begin_sample + read_32bit(xma->chunk_offset+0x24,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,sf); */
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
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 */
|
||||
int i, xma2_chunk_version, num_streams;
|
||||
int channels, sample_rate, loop_flag, num_samples, loop_start_sample, loop_end_sample;
|
||||
off_t offset;
|
||||
|
||||
xma2_chunk_version = read_8bit(chunk_offset+0x00,streamFile);
|
||||
num_streams = read_8bit(chunk_offset+0x01,streamFile);
|
||||
loop_start_sample = read_32bit(chunk_offset+0x04,streamFile);
|
||||
loop_end_sample = read_32bit(chunk_offset+0x08,streamFile);
|
||||
loop_flag = (uint8_t)read_8bit(chunk_offset+0x03,streamFile) > 0 || loop_end_sample; /* rarely not set, encoder default */
|
||||
sample_rate = read_32bit(chunk_offset+0x0c,streamFile);
|
||||
xma2_chunk_version = read_8bit(chunk_offset+0x00,sf);
|
||||
num_streams = read_8bit(chunk_offset+0x01,sf);
|
||||
loop_start_sample = read_32bit(chunk_offset+0x04,sf);
|
||||
loop_end_sample = read_32bit(chunk_offset+0x08,sf);
|
||||
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,sf);
|
||||
/* may need loop end +1 */
|
||||
|
||||
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 = read_32bitBE(chunk_offset+offset+0x04,streamFile)*/
|
||||
/* pcm_samples = read_32bitBE(chunk_offset+offset+0x04,sf)*/
|
||||
|
||||
offset = xma2_chunk_version == 3 ? 0x20 : 0x28;
|
||||
channels = 0; /* channels is the sum of all streams */
|
||||
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) */
|
||||
@ -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 */
|
||||
int frames = 0;
|
||||
off_t offset = start_offset;
|
||||
off_t max_offset = start_offset + bytes;
|
||||
|
||||
if (!streamFile)
|
||||
if (!sf)
|
||||
return 0;
|
||||
|
||||
if (max_offset > get_streamfile_size(streamFile))
|
||||
max_offset = get_streamfile_size(streamFile);
|
||||
if (max_offset > get_streamfile_size(sf))
|
||||
max_offset = get_streamfile_size(sf);
|
||||
|
||||
/* 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:
|
||||
@ -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 */
|
||||
while (offset < max_offset) {
|
||||
uint16_t frame_sync = read_u16be(offset+0x00, streamFile);
|
||||
uint32_t frame_size = read_u32be(offset+0x02, streamFile);
|
||||
uint16_t frame_sync = read_u16be(offset+0x00, sf);
|
||||
uint32_t frame_size = read_u32be(offset+0x02, sf);
|
||||
|
||||
frame_sync = (frame_sync >> 4) & 0x0FFF; /* 12b */
|
||||
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 */
|
||||
/* ******************************************** */
|
||||
|
||||
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;
|
||||
|
||||
new_sf = open_wrap_streamfile(sf);
|
||||
|
@ -1,44 +1,44 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* raw PCM file assumed by extension [PaRappa The Rapper 2 (PS2)? , Amplitude (PS2)?] */
|
||||
VGMSTREAM * init_vgmstream_raw_int(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int channel_count;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "int,wp2"))
|
||||
goto fail;
|
||||
|
||||
if (check_extensions(streamFile, "int"))
|
||||
channel_count = 2;
|
||||
else
|
||||
channel_count = 4;
|
||||
|
||||
/* ignore .int PS-ADPCM */
|
||||
if (ps_check_format(streamFile, 0x00, 0x10000))
|
||||
goto fail;
|
||||
|
||||
start_offset = 0x00;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RAW_INT;
|
||||
vgmstream->sample_rate = 48000;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), vgmstream->channels, 16);
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x200;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* raw PCM file assumed by extension [PaRappa The Rapper 2 (PS2), Amplitude (PS2), R-Type Final (PS2)] */
|
||||
VGMSTREAM* init_vgmstream_raw_int(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int channel_count;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "int,wp2"))
|
||||
goto fail;
|
||||
|
||||
if (check_extensions(sf, "wp2"))
|
||||
channel_count = 4;
|
||||
else
|
||||
channel_count = 2;
|
||||
|
||||
/* ignore .int PS-ADPCM (some files start with silence so up a bit) */
|
||||
if (ps_check_format(sf, 0x00, 0x100000))
|
||||
goto fail;
|
||||
|
||||
start_offset = 0x00;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, 0);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_RAW_INT;
|
||||
vgmstream->sample_rate = 48000;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(sf), vgmstream->channels, 16);
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x200;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -242,10 +242,6 @@ VGMSTREAM* init_vgmstream_xwb(STREAMFILE* sf) {
|
||||
if (xwb.version <= XACT1_1_MAX) {
|
||||
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 {
|
||||
xwb.entry_flags = (entry_info) & 0xF; /*4b*/
|
||||
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_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) {
|
||||
xwb.num_samples = msd.num_samples;
|
||||
xwb.fix_xma_num_samples = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user