mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-12-01 01:27:20 +01:00
commit
fcc79e8faa
@ -39,6 +39,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("AIFCL", aifcl);
|
||||
//"aiff", //common
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("AIX", aix);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("AKB", akb);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("AL2", al2);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("AMTS", amts);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("AO", ao);
|
||||
VGMSTREAM_DECLARE_FILE_TYPE("AS4", as4);
|
||||
|
@ -64,6 +64,7 @@ void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channels
|
||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
|
||||
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
|
||||
|
||||
@ -232,12 +233,14 @@ int ffmpeg_make_riff_xwma(uint8_t * buf, size_t buf_size, int codec, size_t data
|
||||
|
||||
/* MS audio format's sample info (struct to avoid passing so much stuff, separate for reusing) */
|
||||
typedef struct {
|
||||
/* input */
|
||||
int xma_version;
|
||||
int channels;
|
||||
int stream_mode;
|
||||
off_t data_offset;
|
||||
size_t data_size;
|
||||
|
||||
int channels; /* for skips */
|
||||
off_t chunk_offset; /* for multistream config */
|
||||
|
||||
/* frame offsets */
|
||||
int loop_flag;
|
||||
uint32_t loop_start_b;
|
||||
@ -256,7 +259,7 @@ void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_
|
||||
void wma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags);
|
||||
|
||||
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 xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample, int be);
|
||||
void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * out_num_samples, int32_t * out_loop_start_sample, int32_t * out_loop_end_sample, int be);
|
||||
void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * channels, int * sample_rate, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample);
|
||||
|
||||
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
|
||||
|
@ -235,7 +235,7 @@ int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, s
|
||||
put_16bitLE(buf+0x14, codec_XMA2);
|
||||
put_16bitLE(buf+0x16, channels);
|
||||
put_32bitLE(buf+0x18, sample_rate);
|
||||
put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong unneeded) */
|
||||
put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong, unneeded) */
|
||||
put_16bitLE(buf+0x20, (int16_t)(channels*sizeof(sample))); /* block align */
|
||||
put_16bitLE(buf+0x22, 16); /* bits per sample */
|
||||
|
||||
@ -424,19 +424,18 @@ fail:
|
||||
/* ******************************************** */
|
||||
/* XMA PARSING */
|
||||
/* ******************************************** */
|
||||
#define XMA_CHECK_SKIPS 0
|
||||
|
||||
/**
|
||||
* Find total and loop samples of Microsoft audio formats (WMAPRO/XMA1/XMA2) by reading frame 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.
|
||||
* XMA1/XMA2 can divided into streams for multichannel (1/2ch ... 1/2ch). From the file start, packet 1..N is owned by
|
||||
* stream 1..N. Then must follow "packet_skip" value to find the stream next packet, as they are arbitrarily interleaved.
|
||||
* XMA1/XMA2/WMAPRO data only differs in the packet headers.
|
||||
*/
|
||||
static void ms_audio_get_samples(ms_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
|
||||
static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int start_packet, 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, start_skip = 0, end_skip = 0;
|
||||
|
||||
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;
|
||||
@ -445,25 +444,15 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
|
||||
off_t offset = msd->data_offset;
|
||||
uint32_t stream_offset_b = msd->data_offset * 8;
|
||||
|
||||
offset += start_packet * packet_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 = (msd->stream_mode==0 ? (msd->channels + 1) / 2 : msd->channels)
|
||||
skip_packets = 0;
|
||||
|
||||
/* read packets */
|
||||
while (offset < size) {
|
||||
offset_b = offset * 8; /* global offset in bits */
|
||||
offset += packet_size; /* global offset in bytes */
|
||||
|
||||
/* skip packets not owned by the first stream, since we only need samples from it */
|
||||
if (skip_packets && packet_skip_count) {
|
||||
packet_skip_count--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* packet header */
|
||||
if (msd->xma_version == 1) { /* XMA1 */
|
||||
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
|
||||
@ -480,149 +469,141 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
|
||||
} 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 */
|
||||
first_frame_b = read_bitsBE_b(offset_b+6, bits_frame_size, streamFile); /* 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 */
|
||||
}
|
||||
|
||||
|
||||
/* full packet skip */
|
||||
if (packet_skip_count == 0x7FF) {
|
||||
/* XMA2 packets with XMA1 RIFF (transmogrified), remove the packet metadata flag */
|
||||
if (msd->xma_version == 1 && (packet_skip_count & 0x700) == 0x100) {
|
||||
//VGM_LOG("MS_SAMPLES: XMA1 transmogrified packet header at 0x%lx\n", (off_t)offset_b/8);
|
||||
packet_skip_count &= ~0x100;
|
||||
}
|
||||
|
||||
/* full packet skip, no new frames start in this packet (prev frames can end here) */
|
||||
if (packet_skip_count == 0x7FF) { /* XMA1, 11b */
|
||||
VGM_LOG("MS_SAMPLES: XMA1 full packet_skip %i at 0x%lx\n", packet_skip_count, (off_t)offset_b/8);
|
||||
packet_skip_count = 0;
|
||||
continue;
|
||||
}
|
||||
if (packet_skip_count > 255) { /* seen in some (converted?) XMA1 */
|
||||
else if (packet_skip_count == 0xFF) { /* XMA2, 8b*/
|
||||
VGM_LOG("MS_SAMPLES: XMA2 full packet_skip %i at 0x%lx\n", packet_skip_count, (off_t)offset_b/8);
|
||||
packet_skip_count = 0;
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
offset += packet_size * (packet_skip_count); /* skip packets not owned by the first stream, since we only need samples from it */
|
||||
|
||||
/* unusual but not impossible, as the encoder can interleave packets in any way */
|
||||
VGM_ASSERT(packet_skip_count > 10, "MS_SAMPLES: found big packet skip %i at 0x%lx\n", packet_skip_count, (off_t)offset_b/8);
|
||||
|
||||
packet_offset_b = header_size_b + first_frame_b;
|
||||
|
||||
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)
|
||||
/* loops, later adjusted with subframe (seems correct vs tests) */
|
||||
if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_start_b)
|
||||
loop_start_frame = frames;
|
||||
if (msd->loop_flag && (offset_b + packet_offset_b) - stream_offset_b == msd->loop_end_b)
|
||||
loop_end_frame = frames;
|
||||
|
||||
|
||||
/* 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 */
|
||||
//;VGM_LOG("MS_SAMPLES: frame_offset=0x%lx (0b%lx), frame_size=0x%x (0b%x)\n", (off_t)frame_offset_b/8,(off_t)frame_offset_b, frame_size_b/8, frame_size_b);
|
||||
|
||||
/* stop when packet padding starts (0x00 for XMA1 or 0xFF in XMA2) */
|
||||
if (frame_size_b == 0 || frame_size_b == (0xffffffff >> (32 - bits_frame_size))) {
|
||||
break;
|
||||
}
|
||||
packet_offset_b += frame_size_b; /* including header */
|
||||
|
||||
#if 0
|
||||
{
|
||||
uint32_t frame_config
|
||||
frame_config = read_bitsBE_b(frame_offset_b, 15, streamFile);
|
||||
|
||||
//VGM_LOG(" frame %04i: off_b=%I64x (~0x%I64x), fs_b=%i (~0x%x), fs=%x\n",frames, frame_offset_b, frame_offset_b/8, frame_size_b,frame_size_b/8, frame_config);
|
||||
|
||||
//if (frame_config != 0x7f00) /* "contains all subframes"? */
|
||||
// continue; // todo read packet end bit instead
|
||||
}
|
||||
#endif
|
||||
frame_offset_b += 15; //todo bits_frame_size?
|
||||
|
||||
if (frame_size_b == 0x7FFF) { /* end packet frame marker */
|
||||
break;
|
||||
}
|
||||
|
||||
#if XMA_CHECK_SKIPS
|
||||
// more header stuff (info from FFmpeg)
|
||||
{
|
||||
/* find skips (info from FFmpeg) */
|
||||
if (channels_per_packet && (msd->xma_version == 1 || msd->xma_version == 2)) {
|
||||
int flag;
|
||||
int tilehdr_size = 15; //todo incorrect but usable for XMA, fix for WMAPro (complex calcs, see ffmpeg decode_tilehdr)
|
||||
|
||||
frame_offset_b += tilehdr_size;
|
||||
|
||||
/* ignore "postproc transform" */
|
||||
if (msd->channels > 1) {
|
||||
if (channels_per_packet > 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 * msd->channels*msd->channels; /* 4-something per double channel? */
|
||||
frame_offset_b += 1 + 4 * channels_per_packet*channels_per_packet; /* 4-something per double channel? */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* get start/end skips to get the proper number of samples */ //todo check if first bit =1 means full 512 skip
|
||||
/* get start/end skips to get the proper number of samples */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
int new_skip;
|
||||
|
||||
/* get start skip */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
VGM_LOG("start_skip at 0x%I64x\n", frame_offset_b);
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
int new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
VGM_LOG("MS_SAMPLES: start_skip %i at 0x%lx (bit 0x%lx)\n", new_skip, (off_t)frame_offset_b/8, (off_t)frame_offset_b);
|
||||
VGM_ASSERT(start_skip, "MS_SAMPLES: more than one start_skip (%i)\n", new_skip); //ignore, happens due to incorrect tilehdr_size
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(start_skip, "XMA: more than one start_skip (%i)\n", new_skip);
|
||||
|
||||
if (new_skip > samples_per_frame) { /* from xmaencode */
|
||||
VGM_LOG("XMA: bad start_skip (%i)\n", new_skip);
|
||||
if (new_skip > samples_per_frame) /* from xmaencode */
|
||||
new_skip = samples_per_frame;
|
||||
}
|
||||
|
||||
if (frames==0) first_start_skip = new_skip; /* sometimes in the middle */
|
||||
start_skip += new_skip;
|
||||
if (start_skip==0)
|
||||
start_skip = new_skip;
|
||||
}
|
||||
|
||||
/* get end skip */
|
||||
flag = read_bitsBE_b(frame_offset_b, 1, streamFile);
|
||||
frame_offset_b += 1;
|
||||
if (flag) {
|
||||
VGM_LOG("end_skip at 0x%I64x\n", frame_offset_b);
|
||||
new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
int new_skip = read_bitsBE_b(frame_offset_b, 10, streamFile);
|
||||
VGM_LOG("MS_SAMPLES: end_skip %i at 0x%lx (bit 0x%lx)\n", new_skip, (off_t)frame_offset_b/8, (off_t)frame_offset_b);
|
||||
VGM_ASSERT(end_skip, "MS_SAMPLES: more than one end_skip (%i)\n", new_skip);//ignore, happens due to incorrect tilehdr_size
|
||||
frame_offset_b += 10;
|
||||
VGM_ASSERT(end_skip, "XMA: more than one end_skip (%i)\n", new_skip);
|
||||
|
||||
if (new_skip > samples_per_frame) { /* from xmaencode */
|
||||
VGM_LOG("XMA: bad end_skip (%i)\n", new_skip);
|
||||
if (new_skip > samples_per_frame) /* from xmaencode */
|
||||
new_skip = samples_per_frame;
|
||||
}
|
||||
|
||||
last_end_skip = new_skip; /* not seen */
|
||||
end_skip += new_skip;
|
||||
end_skip = new_skip;
|
||||
}
|
||||
|
||||
VGM_LOG(" skip: st=%i, ed=%i\n", start_skip, end_skip);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
samples += samples_per_frame;
|
||||
frames++;
|
||||
|
||||
/* 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)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if XMA_CHECK_SKIPS
|
||||
//todo this seems to usually work, but not always
|
||||
/* apply skips (not sure why 64, empty samples generated by the decoder not in the file?) */
|
||||
samples = samples + 64 - start_skip;
|
||||
samples = samples + 64 - end_skip;
|
||||
|
||||
msd->skip_samples = 64 + samples_per_frame; //todo not always correct
|
||||
#endif
|
||||
|
||||
//todo FFmpeg seems to decode 1 subframe late vs xmaencode, and doesn't write 128 init samples, so skips are not useful ATM
|
||||
//samples = samples + 128 - start_skip - end_skip; /* 128 init samples added by xmaencode */
|
||||
msd->num_samples = samples;
|
||||
msd->skip_samples = start_skip;
|
||||
|
||||
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 */
|
||||
//msd->loop_start_sample -= msd->skip_samples;
|
||||
//msd->loop_end_sample -= msd->skip_samples;
|
||||
#endif
|
||||
|
||||
//todo maybe this is needed
|
||||
//msd->loop_start_sample -= start_skip;
|
||||
//msd->loop_end_sample -= start_skip;
|
||||
}
|
||||
}
|
||||
|
||||
@ -658,7 +639,28 @@ void xma_get_samples(ms_sample_data * msd, STREAMFILE *streamFile) {
|
||||
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);
|
||||
int start_stream = 0;
|
||||
int channels_per_stream = 0;
|
||||
|
||||
/* get from stream config (needed to find skips) */
|
||||
if (msd->chunk_offset) {
|
||||
int format = read_16bitLE(msd->chunk_offset,streamFile);
|
||||
if (format == 0x0165 || format == 0x6501) { /* XMA1 */
|
||||
channels_per_stream = read_8bit(msd->chunk_offset + 0x0C + 0x14*start_stream + 0x11,streamFile);
|
||||
} else if (format == 0x0166 || format == 0x6601) { /* new XMA2 */
|
||||
channels_per_stream = msd->channels > 1 ? 2 : 1;
|
||||
} else { /* old XMA2 */
|
||||
int version = read_8bit(msd->chunk_offset,streamFile);
|
||||
channels_per_stream = read_8bit(msd->chunk_offset + 0x20 + (version==3 ? 0x00 : 0x08) + 0x4*start_stream + 0x00,streamFile);
|
||||
}
|
||||
}
|
||||
else if (msd->channels) {
|
||||
channels_per_stream = msd->channels > 1 ? 2 : 1;
|
||||
}
|
||||
if (channels_per_stream > 2)
|
||||
channels_per_stream = 0;
|
||||
|
||||
ms_audio_get_samples(msd, streamFile, start_stream, channels_per_stream, bytes_per_packet, samples_per_frame, samples_per_subframe, 15);
|
||||
}
|
||||
|
||||
void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_align, int sample_rate, uint32_t decode_flags) {
|
||||
@ -667,21 +669,20 @@ void wmapro_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, int block_
|
||||
int samples_per_frame = 0;
|
||||
int samples_per_subframe = 0;
|
||||
int bits_frame_size = 0;
|
||||
int start_packet = 0;
|
||||
int channels_per_stream = msd->channels;
|
||||
|
||||
/* do some WMAPRO setup (code from ffmpeg) */
|
||||
if (!(decode_flags & 0x40)) {
|
||||
VGM_LOG("MS_SAMPLES: no frame length in WMAPro\n");
|
||||
msd->num_samples = 0;
|
||||
return;
|
||||
}
|
||||
samples_per_frame = wma_get_samples_per_frame(version, sample_rate, decode_flags);
|
||||
bits_frame_size = floor(log(block_align) / log(2)) + 4; /* max bits needed to represent this block_align */
|
||||
samples_per_subframe = 0; /* not really needed WMAPro can't use loop subframes (complex subframe lengths) */
|
||||
msd->xma_version = 0; /* signal it's not XMA */
|
||||
|
||||
/* 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);
|
||||
ms_audio_get_samples(msd, streamFile, start_packet, 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) {
|
||||
@ -745,27 +746,46 @@ void xma1_parse_fmt_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * chan
|
||||
|
||||
/* channels is the sum of all streams */
|
||||
for (i = 0; i < num_streams; i++) {
|
||||
total_channels += read_8bit(chunk_offset+0x0C+0x11+i*0x10,streamFile);
|
||||
total_channels += read_8bit(chunk_offset+0x0C+0x14*i+0x11,streamFile);
|
||||
}
|
||||
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 the extra data, the first part is a normal WAVEFORMATEX. */
|
||||
void xma2_parse_fmt_chunk_extra(STREAMFILE *streamFile, off_t chunk_offset, int * loop_flag, int32_t * num_samples, int32_t * loop_start_sample, int32_t * loop_end_sample, int be) {
|
||||
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) {
|
||||
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) return;
|
||||
/* up to extra data is a WAVEFORMATEX */
|
||||
if (read_16bit(chunk_offset+0x10,streamFile) < 0x22) return; /* expected extra data size */
|
||||
|
||||
if(num_samples) *num_samples = read_32bit(chunk_offset+0x18,streamFile);
|
||||
if(loop_start_sample) *loop_start_sample = read_32bit(chunk_offset+0x28,streamFile);
|
||||
if(loop_end_sample) *loop_end_sample = read_32bit(chunk_offset+0x28,streamFile) + read_32bit(chunk_offset+0x2C,streamFile);
|
||||
if(loop_flag) *loop_flag = (uint8_t)read_8bit(chunk_offset+0x30,streamFile) > 0 /* never set in practice */
|
||||
|| read_32bit(chunk_offset+0x2C,streamFile); /*loop_end_sample*/
|
||||
/* play_begin+end = probably pcm_samples (for original sample rate), don't seem to affect anything */
|
||||
num_samples = read_32bit(chunk_offset+0x18,streamFile); /* max samples from all frames */
|
||||
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 isn't used by xmaencode, so final_num_samples = num_samples + setup_samples (128) - start_skip (~512) - end_skip (0..512) */
|
||||
/* loop values seem to be after applying skips, so loop_end wouldn't be higher than final_num_samples */
|
||||
|
||||
/* flag rarely set, use loop_end as marker */
|
||||
if (!loop_flag) {
|
||||
loop_flag = loop_end_sample > 0;
|
||||
|
||||
/* loop_end_sample - 128 + start_skip + end_skip = num_samples, use approx */
|
||||
if (loop_start_sample == 384 && loop_end_sample - 128 + 512 + 512 >= num_samples) {
|
||||
VGM_LOG("XMA2 PARSE: disabling full loop\n");
|
||||
loop_flag = 0; /* some XMA have full loop set without loop flag and shouldn't loop */
|
||||
}
|
||||
}
|
||||
|
||||
if(out_num_samples) *out_num_samples = num_samples;
|
||||
if(out_loop_start_sample) *out_loop_start_sample = loop_start_sample;
|
||||
if(out_loop_end_sample) *out_loop_end_sample = loop_end_sample;
|
||||
if(out_loop_flag) *out_loop_flag = loop_flag;
|
||||
|
||||
/* play_begin+end = pcm_samples in original sample rate (not usable when resampled = looped) */
|
||||
/* 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); */
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int chan
|
||||
}
|
||||
}
|
||||
|
||||
/* decodes u-law (ITU G.711 non-linear PCM) */
|
||||
/* decodes u-law (ITU G.711 non-linear PCM), from g711.c */
|
||||
void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
@ -119,6 +119,40 @@ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
||||
}
|
||||
}
|
||||
|
||||
/* decodes a-law (ITU G.711 non-linear PCM), from g711.c */
|
||||
void decode_alaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
int i;
|
||||
int32_t sample_count;
|
||||
int sign, segment, quantization, sample;
|
||||
|
||||
|
||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||
uint8_t alawbyte = read_8bit(stream->offset+i,stream->streamfile);
|
||||
|
||||
alawbyte ^= 0x55;
|
||||
sign = (alawbyte & 0x80);
|
||||
segment = (alawbyte & 0x70) >> 4; /* exponent */
|
||||
quantization = alawbyte & 0x0F; /* mantissa */
|
||||
|
||||
sample = (quantization << 4);
|
||||
switch (segment) {
|
||||
case 0:
|
||||
sample += 8;
|
||||
break;
|
||||
case 1:
|
||||
sample += 0x108;
|
||||
break;
|
||||
default:
|
||||
sample += 0x108;
|
||||
sample <<= segment - 1;
|
||||
break;
|
||||
}
|
||||
sample = (sign) ? sample : -sample;
|
||||
|
||||
outbuf[sample_count] = sample;
|
||||
}
|
||||
}
|
||||
|
||||
void decode_pcmfloat(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
|
||||
int i, sample_count;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||
|
@ -32,6 +32,7 @@ static const char* extension_list[] = {
|
||||
//"aiff", //common
|
||||
"aix",
|
||||
"akb",
|
||||
"al2",
|
||||
"amts", //fake extension (to be removed)
|
||||
"ao", //txth/reserved [Cloudphobia (PC)]
|
||||
"as4",
|
||||
@ -410,6 +411,7 @@ static const coding_info coding_info_list[] = {
|
||||
{coding_PCM8_int, "8-bit PCM with 1 byte interleave"},
|
||||
{coding_PCM8_SB_int, "8-bit PCM with sign bit, 1 byte interleave"},
|
||||
{coding_ULAW, "8-bit u-Law"},
|
||||
{coding_ALAW, "8-bit a-Law"},
|
||||
{coding_PCMFLOAT, "32-bit float PCM"},
|
||||
{coding_CRI_ADX, "CRI ADX 4-bit ADPCM"},
|
||||
{coding_CRI_ADX_exp, "CRI ADX 4-bit ADPCM with exponential scale"},
|
||||
@ -639,9 +641,9 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_FSB4, "FMOD Sample Bank (FSB4) Header"},
|
||||
{meta_FSB5, "FMOD Sample Bank (FSB5) Header"},
|
||||
{meta_RWX, "RWX Header"},
|
||||
{meta_XWB, "Microsoft XWB Header"},
|
||||
{meta_XWB, "Microsoft XWB header"},
|
||||
{meta_PS2_XA30, "Reflections XA30 PS2 header"},
|
||||
{meta_MUSC, "MUSC Header"},
|
||||
{meta_MUSC, "Krome MUSC header"},
|
||||
{meta_MUSX_V004, "MUSX / Version 004 Header"},
|
||||
{meta_MUSX_V005, "MUSX / Version 005 Header"},
|
||||
{meta_MUSX_V006, "MUSX / Version 006 Header"},
|
||||
@ -890,6 +892,7 @@ static const meta_info meta_info_list[] = {
|
||||
{meta_EA_SNU, "Electronic Arts SNU header"},
|
||||
{meta_AWC, "Rockstar AWC header"},
|
||||
{meta_NSW_OPUS, ".OPUS header"},
|
||||
{meta_PC_AL2, "Illwinter Game Design AL2 raw header"},
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{meta_OGG_VORBIS, "Ogg Vorbis"},
|
||||
|
@ -658,6 +658,10 @@
|
||||
RelativePath=".\meta\pc_adp.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\pc_al2.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\meta\pc_mxst.c"
|
||||
>
|
||||
|
@ -288,6 +288,7 @@
|
||||
<ClCompile Include="meta\ogl.c" />
|
||||
<ClCompile Include="meta\otm.c" />
|
||||
<ClCompile Include="meta\p3d.c" />
|
||||
<ClCompile Include="meta\pc_al2.c" />
|
||||
<ClCompile Include="meta\pc_mxst.c" />
|
||||
<ClCompile Include="meta\pc_smp.c" />
|
||||
<ClCompile Include="meta\pc_sob.c" />
|
||||
|
@ -391,6 +391,9 @@
|
||||
<ClCompile Include="meta\p3d.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\pc_al2.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="meta\pc_mxst.c">
|
||||
<Filter>meta\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -684,4 +684,6 @@ VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_nsw_opus(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE * streamFile);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
@ -1,73 +1,50 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
/* MUSC (near all Spyro games and many other using this) */
|
||||
/* MUSC - from Krome's PS2 games (The Legend of Spyro, Ty the Tasmanian Tiger) */
|
||||
VGMSTREAM * init_vgmstream_musc(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int loop_flag, channel_count;
|
||||
off_t start_offset;
|
||||
size_t data_size;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if (strcasecmp("mus",filename_extension(filename)) &&
|
||||
strcasecmp("musc",filename_extension(filename)))
|
||||
goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x0,streamFile) != 0x4D555343) /* MUSC */
|
||||
goto fail;
|
||||
|
||||
/* check file size */
|
||||
if ((read_32bitLE(0x10,streamFile)+read_32bitLE(0x14,streamFile)) != (get_streamfile_size(streamFile)))
|
||||
goto fail;
|
||||
|
||||
loop_flag = 0;
|
||||
channel_count = 2;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
/* .mus is the real extension, .musc is the header ID */
|
||||
if (!check_extensions(streamFile,"mus,musc"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4D555343) /* "MUSC" */
|
||||
goto fail;
|
||||
|
||||
start_offset = read_32bitLE(0x10,streamFile);
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->sample_rate = (uint16_t) read_16bitLE(0x06,streamFile);
|
||||
|
||||
vgmstream->num_samples = read_32bitLE(0x14,streamFile)/channel_count/16*28;
|
||||
data_size = read_32bitLE(0x14,streamFile);
|
||||
if (start_offset + data_size != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
/* always does full loops unless it ends in silence */
|
||||
loop_flag = read_32bitBE(get_streamfile_size(streamFile) - 0x10,streamFile) != 0x0C000000;
|
||||
channel_count = 2;
|
||||
|
||||
#if 0
|
||||
if (loop_flag)
|
||||
{
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = (read_32bitLE(0x14,streamFile))*28/16/channel_count;
|
||||
}
|
||||
#endif
|
||||
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile)/2;
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x06,streamFile);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channel_count);
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
|
||||
vgmstream->meta_type = meta_MUSC;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = read_32bitLE(0x18,streamFile) / 2;
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
for (i=0;i<channel_count;i++) {
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset=
|
||||
vgmstream->ch[i].offset=start_offset+
|
||||
vgmstream->interleave_block_size*i;
|
||||
}
|
||||
}
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
40
src/meta/pc_al2.c
Normal file
40
src/meta/pc_al2.c
Normal file
@ -0,0 +1,40 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* AL" - headerless a-law, found in Conquest of Elysium 3 (PC) */
|
||||
VGMSTREAM * init_vgmstream_pc_al2(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag = 0, channel_count;
|
||||
|
||||
|
||||
if ( !check_extensions(streamFile,"al2"))
|
||||
goto fail;
|
||||
|
||||
channel_count = 2;
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = 22050;
|
||||
vgmstream->coding_type = coding_ALAW;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x01;
|
||||
vgmstream->meta_type = meta_PC_AL2;
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(get_streamfile_size(streamFile), channel_count, 8);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = 0;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
start_offset = 0;
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
@ -138,8 +138,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM, probably means "platform's ADPCM") */
|
||||
//case 0x0011: ww.codec = IMA; break; /* older Wwise (used?) */
|
||||
case 0x0069: ww.codec = IMA; break; /* older Wwise (Spiderman Web of Shadows X360, LotR Conquest PC) */
|
||||
case 0x0161: ww.codec = XWMA; break;
|
||||
case 0x0162: ww.codec = XWMA; break;
|
||||
case 0x0161: ww.codec = XWMA; break; /* WMAv2 */
|
||||
case 0x0162: ww.codec = XWMA; break; /* WMAPro */
|
||||
case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */
|
||||
case 0x0166: ww.codec = XMA2; break;
|
||||
case 0x3039: ww.codec = OPUS; break;
|
||||
@ -347,7 +347,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
/* Vorbis is VBR so this is very approximate, meh */
|
||||
if (ww.truncated)
|
||||
vgmstream->num_samples = vgmstream->num_samples * (ww.file_size - start_offset) / ww.data_size;
|
||||
VGM_LOG("so=%lx, ds=%x\n", start_offset, ww.data_size);
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -434,6 +434,7 @@ VGM_LOG("so=%lx, ds=%x\n", start_offset, ww.data_size);
|
||||
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 */
|
||||
{
|
||||
ms_sample_data msd;
|
||||
@ -444,11 +445,14 @@ VGM_LOG("so=%lx, ds=%x\n", start_offset, ww.data_size);
|
||||
msd.data_size = ww.data_size;
|
||||
|
||||
if (ww.format == 0x0162)
|
||||
wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x0000);
|
||||
wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x00E0);
|
||||
else
|
||||
wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x0000);
|
||||
wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x001F);
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* ffmpeg_data->totalSamples is approximate from avg-br */
|
||||
vgmstream->num_samples = msd.num_samples;
|
||||
if (!vgmstream->num_samples)
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* very wrong, from avg-br */
|
||||
//num_samples seem to be found in the last "seek" table entry too, as: entry / channels / 2
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -66,13 +66,12 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
|
||||
/* fix samples; for now only XMA1 is fixed, but xmaencode.exe doesn't seem to use XMA2
|
||||
* num_samples in the headers, and the values don't look exact */
|
||||
/* fix samples; for now only XMA1 is fixed, but XMA2 num_samples don't include skip samples and xmaencode.exe doesn't use it */
|
||||
if (is_xma1) {
|
||||
ms_sample_data msd;
|
||||
memset(&msd,0,sizeof(ms_sample_data));
|
||||
|
||||
msd.xma_version = 1;
|
||||
msd.xma_version = is_xma1 ? 1 : 2;
|
||||
msd.channels = channel_count;
|
||||
msd.data_offset = start_offset;
|
||||
msd.data_size = data_size;
|
||||
@ -81,14 +80,14 @@ VGMSTREAM * init_vgmstream_xma(STREAMFILE *streamFile) {
|
||||
msd.loop_end_b = loop_end_b;
|
||||
msd.loop_start_subframe = loop_subframe & 0xF; /* lower 4b: subframe where the loop starts, 0..4 */
|
||||
msd.loop_end_subframe = loop_subframe >> 4; /* upper 4b: subframe where the loop ends, 0..3 */
|
||||
msd.chunk_offset= chunk_offset;
|
||||
|
||||
xma_get_samples(&msd, streamFile);
|
||||
|
||||
num_samples = msd.num_samples;
|
||||
//skip_samples = msd.skip_samples;
|
||||
loop_start_sample = msd.loop_start_sample;
|
||||
loop_end_sample = msd.loop_end_sample;
|
||||
/* XMA2 loop/num_samples don't seem to skip_samples */
|
||||
/* XMA2 loop/num_samples don't seem to use msd.skip_samples */
|
||||
}
|
||||
|
||||
|
||||
@ -146,7 +145,8 @@ fail:
|
||||
#if 0
|
||||
/**
|
||||
* Get real XMA sample rate (from Microsoft docs).
|
||||
* Info only, not for playback as the encoder adjusts sample rate for looping purposes (sample<>data align).
|
||||
* Info only, not for playback as the encoder adjusts sample rate for looping purposes (sample<>data align),
|
||||
* When converting to PCM, xmaencode does use the modified sample rate.
|
||||
*/
|
||||
static int32_t get_xma_sample_rate(int32_t general_rate) {
|
||||
int32_t xma_rate = 48000; /* default XMA */
|
||||
|
@ -370,6 +370,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_ea_snu,
|
||||
init_vgmstream_awc,
|
||||
init_vgmstream_nsw_opus,
|
||||
init_vgmstream_pc_al2,
|
||||
|
||||
init_vgmstream_txth, /* should go at the end (lower priority) */
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
@ -982,6 +983,7 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
||||
case coding_PCM8_SB_int:
|
||||
case coding_PCM8_U_int:
|
||||
case coding_ULAW:
|
||||
case coding_ALAW:
|
||||
case coding_PCMFLOAT:
|
||||
return 1;
|
||||
#ifdef VGM_USE_VORBIS
|
||||
@ -1141,6 +1143,7 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
||||
case coding_PCM8_SB_int:
|
||||
case coding_PCM8_U_int:
|
||||
case coding_ULAW:
|
||||
case coding_ALAW:
|
||||
return 1;
|
||||
case coding_PCMFLOAT:
|
||||
return 4;
|
||||
@ -1379,6 +1382,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_ALAW:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_alaw(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
vgmstream->channels,vgmstream->samples_into_block,
|
||||
samples_to_do);
|
||||
}
|
||||
break;
|
||||
case coding_PCMFLOAT:
|
||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||
decode_pcmfloat(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||
|
@ -86,6 +86,7 @@ typedef enum {
|
||||
coding_PCM8_SB_int, /* 8-bit PCM, sign bit (others are 2's complement) with sample-level interleave */
|
||||
|
||||
coding_ULAW, /* 8-bit u-Law (non-linear PCM) */
|
||||
coding_ALAW, /* 8-bit a-Law (non-linear PCM) */
|
||||
|
||||
coding_PCMFLOAT, /* 32 bit float PCM */
|
||||
|
||||
@ -352,7 +353,7 @@ typedef enum {
|
||||
meta_RWX, /* Air Force Delta Storm (XBOX) */
|
||||
meta_XWB, /* Microsoft XACT framework (Xbox, X360, Windows) */
|
||||
meta_PS2_XA30, /* Driver - Parallel Lines (PS2) */
|
||||
meta_MUSC, /* Spyro Games, possibly more */
|
||||
meta_MUSC, /* Krome PS2 games */
|
||||
meta_MUSX_V004, /* Spyro Games, possibly more */
|
||||
meta_MUSX_V005, /* Spyro Games, possibly more */
|
||||
meta_MUSX_V006, /* Spyro Games, possibly more */
|
||||
@ -627,6 +628,7 @@ typedef enum {
|
||||
meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */
|
||||
meta_AWC, /* Rockstar AWC (GTA5, RDR) */
|
||||
meta_NSW_OPUS, /* Lego City Undercover (Switch) */
|
||||
meta_PC_AL2, /* Conquest of Elysium 3 (PC) */
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
meta_OGG_VORBIS, /* Ogg Vorbis */
|
||||
|
Loading…
Reference in New Issue
Block a user