mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
commit
cdaa10ed87
@ -49,6 +49,7 @@ VGMSTREAM_DECLARE_FILE_TYPE("AST", ast);
|
|||||||
VGMSTREAM_DECLARE_FILE_TYPE("ATRAC3plus", at3);
|
VGMSTREAM_DECLARE_FILE_TYPE("ATRAC3plus", at3);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("AUD", aud);
|
VGMSTREAM_DECLARE_FILE_TYPE("AUD", aud);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("AUS", aus);
|
VGMSTREAM_DECLARE_FILE_TYPE("AUS", aus);
|
||||||
|
VGMSTREAM_DECLARE_FILE_TYPE("AWC", awc);
|
||||||
|
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("B1S", b1s);
|
VGMSTREAM_DECLARE_FILE_TYPE("B1S", b1s);
|
||||||
VGMSTREAM_DECLARE_FILE_TYPE("BAF", baf);
|
VGMSTREAM_DECLARE_FILE_TYPE("BAF", baf);
|
||||||
|
@ -63,7 +63,7 @@ supports Winamp plugins you may also use in_vgmstream.dll instead.
|
|||||||
|
|
||||||
Because the XMPlay MP3 decoder incorrectly tries to play some vgmstream exts,
|
Because the XMPlay MP3 decoder incorrectly tries to play some vgmstream exts,
|
||||||
you need to manually fix it by going to options > plugins > input > vgmstream
|
you need to manually fix it by going to options > plugins > input > vgmstream
|
||||||
and in the "priority filetypes" put: ckd,fsb,genh,msf,p3d,rak,scd,xvag
|
and in the "priority filetypes" put: awc,ckd,fsb,genh,msf,p3d,rak,scd,xvag
|
||||||
|
|
||||||
--- foo_input_vgmstream ---
|
--- foo_input_vgmstream ---
|
||||||
Every should be installed automatically by the .fb2k-component bundle.
|
Every should be installed automatically by the .fb2k-component bundle.
|
||||||
|
@ -30,7 +30,8 @@ void decode_ms_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * out
|
|||||||
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
void decode_otns_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||||
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel);
|
||||||
void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
void decode_ref_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel);
|
||||||
|
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
|
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels);
|
||||||
size_t ima_bytes_to_samples(size_t bytes, int channels);
|
size_t ima_bytes_to_samples(size_t bytes, int channels);
|
||||||
|
|
||||||
@ -54,16 +55,16 @@ void decode_ngc_afc(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspaci
|
|||||||
|
|
||||||
/* pcm_decoder */
|
/* pcm_decoder */
|
||||||
void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
void decode_pcm16LE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
void decode_pcm16LE_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
|
||||||
void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
void decode_pcm16LE_XOR_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
void decode_pcm16BE(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
|
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian);
|
||||||
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
void decode_pcm8(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
void decode_pcm8_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
void decode_pcm8_sb_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
void decode_pcm8_unsigned_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
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_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_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do);
|
||||||
void decode_pcmfloat(VGMSTREAM *vgmstream, 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);
|
size_t pcm_bytes_to_samples(size_t bytes, int channels, int bits_per_sample);
|
||||||
|
|
||||||
/* psx_decoder */
|
/* psx_decoder */
|
||||||
|
@ -212,23 +212,3 @@ void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
|
|||||||
stream->offset=0;
|
stream->offset=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* EA MicroTalk 10:1 / 5:1 */
|
|
||||||
/**
|
|
||||||
* Rarely used but can be found in the wild: FIFA 2001 (PS2), FIFA Soccer 2002 (PS2)
|
|
||||||
*
|
|
||||||
* Decoding algorithm is unknown; some info found by analyzing sx.exe output:
|
|
||||||
* - Comes in 10:1 or 5:1 compression varieties (the later's byte layout looks similar but has roughly double frame size)
|
|
||||||
* - Also with "PCM samples" flag before each frame (later version) or without (first version)
|
|
||||||
* - When PCM flag is 0xEE it has 16b ? + 16b num_samples + PCM samples placed right after the frame, but they
|
|
||||||
* are written *before* (presumably so they have something while the frame is decoded), like EALayer3.
|
|
||||||
* - VBR ADPCM, apparently similar to Westwood VBR ADPCM: first byte seems a header with mode+count, but after it may
|
|
||||||
* be 8 bytes(?) of coefs/hist (unlike Westwood's), then data. Samples per frame changes with the mode used.
|
|
||||||
* ex. decoding pure silence (0000) takes 0x2E (10:1) or 0x48 (5:1) into 432 samples (RLE mode)
|
|
||||||
* - Variable frame size but seems to range from 0x20 to 0x80 (in 5:1 at least)
|
|
||||||
* - After a new SCDl block, first byte (in each channel) is a flag but various values have no effect in the output
|
|
||||||
* (01=first block, 00=normal block?) and should be skipped in the block parser.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
//void decode_ea_mt10(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) {
|
|
||||||
|
@ -678,6 +678,43 @@ void decode_ref_ima(VGMSTREAM * vgmstream,VGMSTREAMCHANNEL * stream, sample * ou
|
|||||||
stream->adpcm_step_index = step_index;
|
stream->adpcm_step_index = step_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||||
|
int i, sample_count;
|
||||||
|
|
||||||
|
int32_t hist1 = stream->adpcm_history1_32;
|
||||||
|
int step_index = stream->adpcm_step_index;
|
||||||
|
|
||||||
|
//internal interleave, mono
|
||||||
|
int block_samples = (0x800 - 4) * 2;
|
||||||
|
first_sample = first_sample % block_samples;
|
||||||
|
|
||||||
|
//inverted header
|
||||||
|
if (first_sample == 0) {
|
||||||
|
off_t header_offset = stream->offset;
|
||||||
|
|
||||||
|
step_index = read_16bitLE(header_offset,stream->streamfile);
|
||||||
|
hist1 = read_16bitLE(header_offset+2,stream->streamfile);
|
||||||
|
if (step_index < 0) step_index=0;
|
||||||
|
if (step_index > 88) step_index=88;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||||
|
off_t byte_offset = stream->offset + 4 + i/2;
|
||||||
|
int nibble_shift = (i&1?4:0); //low nibble first
|
||||||
|
|
||||||
|
ms_ima_expand_nibble(stream, byte_offset,nibble_shift, &hist1, &step_index);
|
||||||
|
outbuf[sample_count] = (short)(hist1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//internal interleave: increment offset on complete frame
|
||||||
|
if (i == block_samples) stream->offset += 0x800;
|
||||||
|
|
||||||
|
stream->adpcm_history1_32 = hist1;
|
||||||
|
stream->adpcm_step_index = step_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
|
size_t ms_ima_bytes_to_samples(size_t bytes, int block_align, int channels) {
|
||||||
/* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
/* MS IMA blocks have a 4 byte header per channel; 2 samples per byte (2 nibbles) */
|
||||||
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels;
|
return (bytes / block_align) * (block_align - 4 * channels) * 2 / channels;
|
||||||
|
@ -54,7 +54,6 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MPEG_LYN:
|
case MPEG_LYN:
|
||||||
case MPEG_AWC:
|
|
||||||
goto fail; /* not fully implemented */
|
goto fail; /* not fully implemented */
|
||||||
|
|
||||||
case MPEG_STANDARD:
|
case MPEG_STANDARD:
|
||||||
|
138
src/coding/mpeg_custom_utils_awc.c
Normal file
138
src/coding/mpeg_custom_utils_awc.c
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#include "mpeg_decoder.h"
|
||||||
|
|
||||||
|
#ifdef VGM_USE_MPEG
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AWC music uses blocks (sfx doesn't), the fun part being each channel has different num_samples/frames
|
||||||
|
* per block, so it's unsuitable for the normal "blocked" layout and parsed here instead.
|
||||||
|
* Channel data is separate within the block (first all frames of ch0, then ch1, etc), padded, and sometimes
|
||||||
|
* the last few frames of a channel are repeated in the new block (marked with the "discard samples" field).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, mpeg_codec_data *data) {
|
||||||
|
size_t header_size = 0;
|
||||||
|
int i;
|
||||||
|
int entries = data->config.channels;
|
||||||
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = data->config.big_endian ? read_32bitBE : read_32bitLE;
|
||||||
|
|
||||||
|
for (i = 0; i < entries; i++) {
|
||||||
|
header_size += 0x18;
|
||||||
|
header_size += read_32bit(offset + 0x18*i + 0x04, streamFile) * 0x04; /* entries in the table */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_size % 0x800) /* padded */
|
||||||
|
header_size += 0x800 - (header_size % 0x800);
|
||||||
|
|
||||||
|
return header_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* init config and validate */
|
||||||
|
int mpeg_custom_setup_init_awc(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type) {
|
||||||
|
mpeg_frame_info info;
|
||||||
|
int is_music;
|
||||||
|
|
||||||
|
/* start_offset can point to a block header that always starts with 0 (music) or normal data (sfx) */
|
||||||
|
is_music = read_32bitBE(start_offset, streamFile) == 0x00000000;
|
||||||
|
if (is_music)
|
||||||
|
start_offset += get_block_header_size(streamFile, start_offset, data);
|
||||||
|
|
||||||
|
/* get frame info at offset */
|
||||||
|
if ( !mpeg_get_frame_info(streamFile, start_offset, &info))
|
||||||
|
goto fail;
|
||||||
|
switch(info.layer) {
|
||||||
|
case 1: *coding_type = coding_MPEG_layer1; break;
|
||||||
|
case 2: *coding_type = coding_MPEG_layer2; break;
|
||||||
|
case 3: *coding_type = coding_MPEG_layer3; break;
|
||||||
|
default: goto fail;
|
||||||
|
}
|
||||||
|
data->channels_per_frame = info.channels;
|
||||||
|
data->samples_per_frame = info.frame_samples;
|
||||||
|
|
||||||
|
|
||||||
|
/* extra checks */
|
||||||
|
if (is_music) {
|
||||||
|
if (data->config.chunk_size <= 0)
|
||||||
|
goto fail; /* needs block size */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no big encoder delay added (for sfx they can start in less than ~300 samples) */
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* writes data to the buffer and moves offsets, parsing AWC blocks */
|
||||||
|
int mpeg_custom_parse_frame_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream) {
|
||||||
|
mpeg_custom_stream *ms = data->streams[num_stream];
|
||||||
|
mpeg_frame_info info;
|
||||||
|
size_t current_data_size = 0, data_offset;
|
||||||
|
size_t file_size = get_streamfile_size(stream->streamfile);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
/* blocked layout used for music */
|
||||||
|
if (data->config.chunk_size) {
|
||||||
|
|
||||||
|
/* block ended for this channel, move to next block start */
|
||||||
|
if (ms->current_size_count > 0 && ms->current_size_count == ms->current_size_target) {
|
||||||
|
//mpg123_open_feed(ms->m); //todo reset maybe needed?
|
||||||
|
|
||||||
|
data_offset = stream->offset - stream->channel_start_offset; /* ignoring header */
|
||||||
|
data_offset -= data_offset % data->config.chunk_size; /* start of current block */
|
||||||
|
stream->offset = stream->channel_start_offset + data_offset + data->config.chunk_size;
|
||||||
|
|
||||||
|
ms->current_size_count = 0;
|
||||||
|
ms->current_size_target = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* just in case, shouldn't happen */
|
||||||
|
if (stream->offset >= file_size) {
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* block starts for this channel, point to mpeg data */
|
||||||
|
if (ms->current_size_count == 0) {
|
||||||
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = data->config.big_endian ? read_32bitBE : read_32bitLE;
|
||||||
|
off_t channel_offset = 0;
|
||||||
|
|
||||||
|
/* block has a header with base info per channel and table per channel (see blocked_awc.c) */
|
||||||
|
ms->decode_to_discard = read_32bit(stream->offset + 0x18*num_stream + 0x08, stream->streamfile);
|
||||||
|
ms->current_size_target = read_32bit(stream->offset + 0x18*num_stream + 0x14, stream->streamfile);
|
||||||
|
|
||||||
|
for (i = 0; i < num_stream; i++) { /* num_stream serves as channel */
|
||||||
|
size_t channel_size = read_32bit(stream->offset + 0x18*i + 0x14, stream->streamfile);
|
||||||
|
if (channel_size % 0x10) /* 32b aligned */
|
||||||
|
channel_size += 0x10 - channel_size % 0x10;
|
||||||
|
|
||||||
|
channel_offset += channel_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//VGM_ASSERT(ms->decode_to_discard > 0, "AWC: s%i discard of %x found at chunk %lx\n", num_stream, ms->decode_to_discard, stream->offset);
|
||||||
|
//;VGM_LOG("AWC: s%i off=%lx to %lx\n", num_stream, stream->offset, stream->offset + channel_offset + get_block_header_size(stream->streamfile, stream->offset, data));
|
||||||
|
|
||||||
|
stream->offset += channel_offset + get_block_header_size(stream->streamfile, stream->offset, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* update frame */
|
||||||
|
if ( !mpeg_get_frame_info(stream->streamfile, stream->offset, &info) )
|
||||||
|
goto fail;
|
||||||
|
current_data_size = info.frame_size;
|
||||||
|
|
||||||
|
data->bytes_in_buffer = read_streamfile(data->buffer,stream->offset, current_data_size, stream->streamfile);
|
||||||
|
|
||||||
|
stream->offset += current_data_size;
|
||||||
|
|
||||||
|
ms->current_size_count += current_data_size;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -579,7 +579,7 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
|
|||||||
if (decode_to_discard == 576)
|
if (decode_to_discard == 576)
|
||||||
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number;
|
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number;
|
||||||
|
|
||||||
data->decode_to_discard += decode_to_discard;
|
ms->decode_to_discard += decode_to_discard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,6 +140,7 @@ mpeg_codec_data *init_mpeg_custom_codec_data(STREAMFILE *streamFile, off_t start
|
|||||||
case MPEG_EAL31:
|
case MPEG_EAL31:
|
||||||
case MPEG_EAL32P:
|
case MPEG_EAL32P:
|
||||||
case MPEG_EAL32S: ok = mpeg_custom_setup_init_ealayer3(streamFile, start_offset, data, coding_type); break;
|
case MPEG_EAL32S: ok = mpeg_custom_setup_init_ealayer3(streamFile, start_offset, data, coding_type); break;
|
||||||
|
case MPEG_AWC: ok = mpeg_custom_setup_init_awc(streamFile, start_offset, data, coding_type); break;
|
||||||
default: ok = mpeg_custom_setup_init_default(streamFile, start_offset, data, coding_type); break;
|
default: ok = mpeg_custom_setup_init_default(streamFile, start_offset, data, coding_type); break;
|
||||||
}
|
}
|
||||||
if (!ok)
|
if (!ok)
|
||||||
@ -393,6 +394,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
|
|||||||
case MPEG_EAL32P:
|
case MPEG_EAL32P:
|
||||||
case MPEG_EAL32S: ok = mpeg_custom_parse_frame_ealayer3(stream, data, num_stream); break;
|
case MPEG_EAL32S: ok = mpeg_custom_parse_frame_ealayer3(stream, data, num_stream); break;
|
||||||
case MPEG_AHX: ok = mpeg_custom_parse_frame_ahx(stream, data); break;
|
case MPEG_AHX: ok = mpeg_custom_parse_frame_ahx(stream, data); break;
|
||||||
|
case MPEG_AWC: ok = mpeg_custom_parse_frame_awc(stream, data, num_stream); break;
|
||||||
default: ok = mpeg_custom_parse_frame_default(stream, data); break;
|
default: ok = mpeg_custom_parse_frame_default(stream, data); break;
|
||||||
}
|
}
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@ -440,16 +442,16 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
|
|||||||
}
|
}
|
||||||
samples_filled = (bytes_done / sizeof(sample) / data->channels_per_frame);
|
samples_filled = (bytes_done / sizeof(sample) / data->channels_per_frame);
|
||||||
|
|
||||||
/* for EALayer3, that discards decoded samples and writes PCM blocks instead */
|
/* discard for weird features (EALayer3 and PCM blocks, AWC and repeated frames) */
|
||||||
if (data->decode_to_discard) {
|
if (ms->decode_to_discard) {
|
||||||
size_t bytes_to_discard = 0;
|
size_t bytes_to_discard = 0;
|
||||||
size_t decode_to_discard = data->decode_to_discard;
|
size_t decode_to_discard = ms->decode_to_discard;
|
||||||
if (decode_to_discard > samples_filled)
|
if (decode_to_discard > samples_filled)
|
||||||
decode_to_discard = samples_filled;
|
decode_to_discard = samples_filled;
|
||||||
bytes_to_discard = sizeof(sample)*decode_to_discard*data->channels_per_frame;
|
bytes_to_discard = sizeof(sample)*decode_to_discard*data->channels_per_frame;
|
||||||
|
|
||||||
bytes_done -= bytes_to_discard;
|
bytes_done -= bytes_to_discard;
|
||||||
data->decode_to_discard -= decode_to_discard;
|
ms->decode_to_discard -= decode_to_discard;
|
||||||
ms->samples_used += decode_to_discard;
|
ms->samples_used += decode_to_discard;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -522,10 +524,10 @@ void reset_mpeg(VGMSTREAM *vgmstream) {
|
|||||||
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
|
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
|
||||||
data->streams[i]->samples_filled = 0;
|
data->streams[i]->samples_filled = 0;
|
||||||
data->streams[i]->samples_used = 0;
|
data->streams[i]->samples_used = 0;
|
||||||
|
data->streams[i]->decode_to_discard = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->samples_to_discard = data->skip_samples; /* initial delay */
|
data->samples_to_discard = data->skip_samples; /* initial delay */
|
||||||
data->decode_to_discard = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -546,6 +548,7 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
|
|||||||
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
|
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
|
||||||
data->streams[i]->samples_filled = 0;
|
data->streams[i]->samples_filled = 0;
|
||||||
data->streams[i]->samples_used = 0;
|
data->streams[i]->samples_used = 0;
|
||||||
|
data->streams[i]->decode_to_discard = 0;
|
||||||
|
|
||||||
if (vgmstream->loop_ch)
|
if (vgmstream->loop_ch)
|
||||||
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
|
vgmstream->loop_ch[i].offset = vgmstream->loop_ch[i].channel_start_offset;
|
||||||
@ -558,7 +561,6 @@ void seek_mpeg(VGMSTREAM *vgmstream, int32_t num_sample) {
|
|||||||
|
|
||||||
data->buffer_full = 0;
|
data->buffer_full = 0;
|
||||||
data->buffer_used = 0;
|
data->buffer_used = 0;
|
||||||
data->decode_to_discard = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resets mpg123 decoder and its internals (with mpg123_open_feed as mpg123_feedseek won't work) */
|
/* resets mpg123 decoder and its internals (with mpg123_open_feed as mpg123_feedseek won't work) */
|
||||||
@ -577,10 +579,10 @@ void flush_mpeg(mpeg_codec_data * data) {
|
|||||||
mpg123_open_feed(data->streams[i]->m);
|
mpg123_open_feed(data->streams[i]->m);
|
||||||
data->streams[i]->samples_filled = 0;
|
data->streams[i]->samples_filled = 0;
|
||||||
data->streams[i]->samples_used = 0;
|
data->streams[i]->samples_used = 0;
|
||||||
|
data->streams[i]->decode_to_discard = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
data->samples_to_discard = data->skip_samples; /* initial delay */
|
data->samples_to_discard = data->skip_samples; /* initial delay */
|
||||||
data->decode_to_discard = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data->bytes_in_buffer = 0;
|
data->bytes_in_buffer = 0;
|
||||||
|
@ -19,10 +19,12 @@ int mpeg_get_frame_info(STREAMFILE *streamfile, off_t offset, mpeg_frame_info *
|
|||||||
|
|
||||||
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
||||||
int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
int mpeg_custom_setup_init_ealayer3(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
||||||
|
int mpeg_custom_setup_init_awc(STREAMFILE *streamFile, off_t start_offset, mpeg_codec_data *data, coding_t *coding_type);
|
||||||
|
|
||||||
int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data);
|
int mpeg_custom_parse_frame_default(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data);
|
||||||
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data);
|
int mpeg_custom_parse_frame_ahx(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data);
|
||||||
int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
int mpeg_custom_parse_frame_ealayer3(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
||||||
|
int mpeg_custom_parse_frame_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
|
||||||
|
|
||||||
#endif/* VGM_USE_MPEG */
|
#endif/* VGM_USE_MPEG */
|
||||||
|
|
||||||
|
@ -68,12 +68,12 @@ void decode_pcm8_unsigned(VGMSTREAMCHANNEL * stream, sample * outbuf, int channe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_pcm16LE_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
|
||||||
int i;
|
int i, sample_count;
|
||||||
int32_t sample_count;
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = big_endian ? read_16bitBE : read_16bitLE;
|
||||||
|
|
||||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||||
outbuf[sample_count]=read_16bitLE(stream->offset+i*2*channelspacing,stream->streamfile);
|
outbuf[sample_count]=read_16bit(stream->offset+i*2*channelspacing,stream->streamfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,17 +118,17 @@ void decode_ulaw(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void decode_pcmfloat(VGMSTREAM *vgmstream, 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) {
|
||||||
int i, sample_count;
|
int i, sample_count;
|
||||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||||
|
|
||||||
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
for (i=first_sample,sample_count=0; i<first_sample+samples_to_do; i++,sample_count+=channelspacing) {
|
||||||
uint32_t sample_int = read_32bit(stream->offset+i*4,stream->streamfile);
|
uint32_t sample_int = read_32bit(stream->offset+i*4,stream->streamfile);
|
||||||
float sample_float;
|
float* sample_float;
|
||||||
int sample_pcm;
|
int sample_pcm;
|
||||||
|
|
||||||
memcpy(&sample_float, &sample_int, 4); /* maybe unorthodox but simplest */
|
sample_float = (float*)&sample_int;
|
||||||
sample_pcm = floor(sample_float * 32767.f + .5f);
|
sample_pcm = floor((*sample_float) * 32767.f + .5f);
|
||||||
|
|
||||||
outbuf[sample_count] = clamp16(sample_pcm);
|
outbuf[sample_count] = clamp16(sample_pcm);
|
||||||
}
|
}
|
||||||
|
@ -42,6 +42,7 @@ static const char* extension_list[] = {
|
|||||||
"at3",
|
"at3",
|
||||||
"aud",
|
"aud",
|
||||||
"aus",
|
"aus",
|
||||||
|
"awc",
|
||||||
|
|
||||||
"b1s",
|
"b1s",
|
||||||
"baf",
|
"baf",
|
||||||
@ -395,10 +396,10 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
static const coding_info coding_info_list[] = {
|
static const coding_info coding_info_list[] = {
|
||||||
{coding_PCM16BE, "Big Endian 16-bit PCM"},
|
|
||||||
{coding_PCM16LE, "Little Endian 16-bit PCM"},
|
{coding_PCM16LE, "Little Endian 16-bit PCM"},
|
||||||
{coding_PCM16LE_int, "Little Endian 16-bit PCM with 2 byte interleave"},
|
|
||||||
{coding_PCM16LE_XOR_int, "Little Endian 16-bit PCM with 2 byte interleave and XOR obfuscation"},
|
{coding_PCM16LE_XOR_int, "Little Endian 16-bit PCM with 2 byte interleave and XOR obfuscation"},
|
||||||
|
{coding_PCM16BE, "Big Endian 16-bit PCM"},
|
||||||
|
{coding_PCM16_int, "16-bit PCM with 2 byte interleave"},
|
||||||
{coding_PCM8, "8-bit PCM"},
|
{coding_PCM8, "8-bit PCM"},
|
||||||
{coding_PCM8_U, "8-bit unsigned PCM"},
|
{coding_PCM8_U, "8-bit unsigned PCM"},
|
||||||
{coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave"},
|
{coding_PCM8_U_int, "8-bit unsigned PCM with 1 byte interleave"},
|
||||||
@ -448,6 +449,7 @@ static const coding_info coding_info_list[] = {
|
|||||||
{coding_FSB_IMA, "FSB multichannel 4-bit IMA ADPCM"},
|
{coding_FSB_IMA, "FSB multichannel 4-bit IMA ADPCM"},
|
||||||
{coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"},
|
{coding_WWISE_IMA, "Audiokinetic Wwise 4-bit IMA ADPCM"},
|
||||||
{coding_REF_IMA, "Reflections 4-bit IMA ADPCM"},
|
{coding_REF_IMA, "Reflections 4-bit IMA ADPCM"},
|
||||||
|
{coding_AWC_IMA, "Rockstar AWC 4-bit IMA ADPCM"},
|
||||||
{coding_WS, "Westwood Studios VBR ADPCM"},
|
{coding_WS, "Westwood Studios VBR ADPCM"},
|
||||||
{coding_ACM, "InterPlay ACM"},
|
{coding_ACM, "InterPlay ACM"},
|
||||||
{coding_NWA0, "NWA DPCM Level 0"},
|
{coding_NWA0, "NWA DPCM Level 0"},
|
||||||
@ -532,6 +534,8 @@ static const layout_info layout_info_list[] = {
|
|||||||
{layout_aax, "AAX blocked, 18-byte interleaved"},
|
{layout_aax, "AAX blocked, 18-byte interleaved"},
|
||||||
{layout_scd_int, "SCD multistream interleave"},
|
{layout_scd_int, "SCD multistream interleave"},
|
||||||
{layout_ea_sns_blocked, "Electronic Arts SNS blocked"},
|
{layout_ea_sns_blocked, "Electronic Arts SNS blocked"},
|
||||||
|
{layout_blocked_awc, "blocked (AWC)"},
|
||||||
|
{layout_blocked_vgs, "blocked (VGS)"},
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
{layout_ogg_vorbis, "Ogg"},
|
{layout_ogg_vorbis, "Ogg"},
|
||||||
#endif
|
#endif
|
||||||
@ -716,7 +720,7 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_MSVP, "MSVP Header"},
|
{meta_MSVP, "MSVP Header"},
|
||||||
{meta_NGC_SSM, "SSM DSP Header"},
|
{meta_NGC_SSM, "SSM DSP Header"},
|
||||||
{meta_PS2_JOE, "Disney/Pixar JOE Header"},
|
{meta_PS2_JOE, "Disney/Pixar JOE Header"},
|
||||||
{meta_VGS, "Guitar Hero Encore Rocks the 80's Header"},
|
{meta_VGS, "Guitar Hero VGS Header"},
|
||||||
{meta_DC_DCSW_DCS, "Evil Twin DCS file with helper"},
|
{meta_DC_DCSW_DCS, "Evil Twin DCS file with helper"},
|
||||||
{meta_WII_SMP, "SMP DSP Header"},
|
{meta_WII_SMP, "SMP DSP Header"},
|
||||||
{meta_EMFF_PS2, "Eidos Music File Format Header"},
|
{meta_EMFF_PS2, "Eidos Music File Format Header"},
|
||||||
@ -880,6 +884,7 @@ static const meta_info meta_info_list[] = {
|
|||||||
{meta_STM, "Angel Studios/Rockstar San Diego STMA header"},
|
{meta_STM, "Angel Studios/Rockstar San Diego STMA header"},
|
||||||
{meta_BINK, "RAD Game Tools Bink header"},
|
{meta_BINK, "RAD Game Tools Bink header"},
|
||||||
{meta_EA_SNU, "Electronic Arts SNU header"},
|
{meta_EA_SNU, "Electronic Arts SNU header"},
|
||||||
|
{meta_AWC, "Rockstar AWC header"},
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
{meta_OGG_VORBIS, "Ogg Vorbis"},
|
{meta_OGG_VORBIS, "Ogg Vorbis"},
|
||||||
|
@ -143,6 +143,12 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
|
|||||||
break;
|
break;
|
||||||
case layout_ea_sns_blocked:
|
case layout_ea_sns_blocked:
|
||||||
ea_sns_block_update(vgmstream->next_block_offset,vgmstream);
|
ea_sns_block_update(vgmstream->next_block_offset,vgmstream);
|
||||||
|
break;
|
||||||
|
case layout_blocked_awc:
|
||||||
|
block_update_awc(vgmstream->next_block_offset,vgmstream);
|
||||||
|
break;
|
||||||
|
case layout_blocked_vgs:
|
||||||
|
block_update_vgs(vgmstream->next_block_offset,vgmstream);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
60
src/layout/blocked_awc.c
Normal file
60
src/layout/blocked_awc.c
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include "layout.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
#include "../layout/layout.h"
|
||||||
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, int channels, int big_endian);
|
||||||
|
|
||||||
|
/* AWC music chunks */
|
||||||
|
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
|
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||||
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE;
|
||||||
|
size_t header_size, entries, block_size, block_samples;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* assumed only AWC_IMA enters here, MPEG/XMA2 need special parsing as blocked layout is too limited */
|
||||||
|
|
||||||
|
entries = read_32bit(block_offset + 0x18*0 + 0x04, streamFile); /* assumed same for all channels */
|
||||||
|
block_samples = entries * (0x800-4)*2;
|
||||||
|
block_size = vgmstream->full_block_size;
|
||||||
|
|
||||||
|
vgmstream->current_block_offset = block_offset;
|
||||||
|
vgmstream->next_block_offset = block_offset + block_size;
|
||||||
|
vgmstream->current_block_samples = block_samples;
|
||||||
|
|
||||||
|
/* starts with a header block */
|
||||||
|
/* for each channel
|
||||||
|
* 0x00: start entry within channel (ie. entries * ch)
|
||||||
|
* 0x04: entries
|
||||||
|
* 0x08: samples to discard in the beginning of this block (MPEG only?)
|
||||||
|
* 0x0c: samples in channel (for MPEG/XMA2 can vary between channels)
|
||||||
|
* 0x10: MPEG only: close to number of frames but varies a bit?
|
||||||
|
* 0x14: MPEG only: channel usable data size (not counting padding)
|
||||||
|
* for each channel
|
||||||
|
* 32b * entries = global samples per frame in each block (for MPEG probably per full frame)
|
||||||
|
*/
|
||||||
|
|
||||||
|
header_size = get_block_header_size(streamFile, block_offset, vgmstream->channels, vgmstream->codec_endian);
|
||||||
|
for (i = 0; i < vgmstream->channels; i++) {
|
||||||
|
vgmstream->ch[i].offset = block_offset + header_size + 0x800*entries*i;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, int channels, int big_endian) {
|
||||||
|
size_t header_size = 0;
|
||||||
|
int i;
|
||||||
|
int entries = channels;
|
||||||
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE;
|
||||||
|
|
||||||
|
for (i = 0; i < entries; i++) {
|
||||||
|
header_size += 0x18;
|
||||||
|
header_size += read_32bit(offset + 0x18*i + 0x04, streamFile) * 0x04; /* entries in the table */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header_size % 0x800) /* padded */
|
||||||
|
header_size += 0x800 - (header_size % 0x800);
|
||||||
|
|
||||||
|
return header_size;
|
||||||
|
}
|
32
src/layout/blocked_vgs.c
Normal file
32
src/layout/blocked_vgs.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "layout.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
#include "../layout/layout.h"
|
||||||
|
#include "../vgmstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* VGS multistream frames */
|
||||||
|
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||||
|
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||||
|
size_t file_size = get_streamfile_size(vgmstream->ch[0].streamfile);
|
||||||
|
int i;
|
||||||
|
size_t channel_size = 0x10;
|
||||||
|
|
||||||
|
|
||||||
|
/* set offsets */
|
||||||
|
for (i = 0; i < vgmstream->channels; i++) {
|
||||||
|
vgmstream->ch[i].offset = block_offset + channel_size*i;
|
||||||
|
}
|
||||||
|
|
||||||
|
vgmstream->current_block_size = channel_size;
|
||||||
|
vgmstream->current_block_offset = block_offset;
|
||||||
|
vgmstream->next_block_offset = block_offset + channel_size*vgmstream->channels;
|
||||||
|
|
||||||
|
/* skip unhandled tracks: flag can be 0x0n per track, of 0x8x for last frame */
|
||||||
|
while (vgmstream->next_block_offset < file_size) {
|
||||||
|
if ((read_8bit(vgmstream->next_block_offset + 0x01, streamFile) & 0x0F) == 0x00)
|
||||||
|
break;
|
||||||
|
|
||||||
|
vgmstream->next_block_offset += channel_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -211,7 +211,7 @@ void eacs_block_update(off_t block_offset, VGMSTREAM * vgmstream) {
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
for (i=0;i<vgmstream->channels;i++) {
|
for (i=0;i<vgmstream->channels;i++) {
|
||||||
if(vgmstream->coding_type==coding_PCM16LE_int)
|
if(vgmstream->coding_type==coding_PCM16_int)
|
||||||
vgmstream->ch[i].offset = block_offset+(i*2);
|
vgmstream->ch[i].offset = block_offset+(i*2);
|
||||||
else
|
else
|
||||||
vgmstream->ch[i].offset = block_offset+i;
|
vgmstream->ch[i].offset = block_offset+i;
|
||||||
|
@ -65,6 +65,9 @@ void hwas_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
|||||||
|
|
||||||
void ea_sns_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
void ea_sns_block_update(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
|
void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
/* other layouts */
|
/* other layouts */
|
||||||
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
void render_vgmstream_interleave(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstream);
|
||||||
|
|
||||||
|
@ -1398,6 +1398,10 @@
|
|||||||
RelativePath=".\coding\mpeg_custom_utils_ahx.c"
|
RelativePath=".\coding\mpeg_custom_utils_ahx.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\coding\mpeg_custom_utils_awc.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\coding\mpeg_custom_utils_ealayer3.c"
|
RelativePath=".\coding\mpeg_custom_utils_ealayer3.c"
|
||||||
>
|
>
|
||||||
@ -1530,6 +1534,14 @@
|
|||||||
RelativePath=".\layout\blocked.c"
|
RelativePath=".\layout\blocked.c"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\layout\blocked_awc.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\layout\blocked_vgs.c"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\layout\caf_blocked.c"
|
RelativePath=".\layout\caf_blocked.c"
|
||||||
>
|
>
|
||||||
|
@ -427,6 +427,7 @@
|
|||||||
<ClCompile Include="coding\mc3_decoder.c" />
|
<ClCompile Include="coding\mc3_decoder.c" />
|
||||||
<ClCompile Include="coding\mpeg_custom_utils.c" />
|
<ClCompile Include="coding\mpeg_custom_utils.c" />
|
||||||
<ClCompile Include="coding\mpeg_custom_utils_ahx.c" />
|
<ClCompile Include="coding\mpeg_custom_utils_ahx.c" />
|
||||||
|
<ClCompile Include="coding\mpeg_custom_utils_awc.c" />
|
||||||
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c" />
|
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c" />
|
||||||
<ClCompile Include="coding\mpeg_decoder.c" />
|
<ClCompile Include="coding\mpeg_decoder.c" />
|
||||||
<ClCompile Include="coding\msadpcm_decoder.c" />
|
<ClCompile Include="coding\msadpcm_decoder.c" />
|
||||||
@ -453,6 +454,8 @@
|
|||||||
<ClCompile Include="layout\ast_blocked.c" />
|
<ClCompile Include="layout\ast_blocked.c" />
|
||||||
<ClCompile Include="layout\bdsp_blocked.c" />
|
<ClCompile Include="layout\bdsp_blocked.c" />
|
||||||
<ClCompile Include="layout\blocked.c" />
|
<ClCompile Include="layout\blocked.c" />
|
||||||
|
<ClCompile Include="layout\blocked_awc.c" />
|
||||||
|
<ClCompile Include="layout\blocked_vgs.c" />
|
||||||
<ClCompile Include="layout\caf_blocked.c" />
|
<ClCompile Include="layout\caf_blocked.c" />
|
||||||
<ClCompile Include="layout\de2_blocked.c" />
|
<ClCompile Include="layout\de2_blocked.c" />
|
||||||
<ClCompile Include="layout\ea_block.c" />
|
<ClCompile Include="layout\ea_block.c" />
|
||||||
|
@ -817,6 +817,9 @@
|
|||||||
<ClCompile Include="coding\mpeg_custom_utils_ahx.c">
|
<ClCompile Include="coding\mpeg_custom_utils_ahx.c">
|
||||||
<Filter>coding\Source Files</Filter>
|
<Filter>coding\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="coding\mpeg_custom_utils_awc.c">
|
||||||
|
<Filter>coding\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c">
|
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c">
|
||||||
<Filter>coding\Source Files</Filter>
|
<Filter>coding\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
@ -895,6 +898,12 @@
|
|||||||
<ClCompile Include="layout\blocked.c">
|
<ClCompile Include="layout\blocked.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="layout\blocked_awc.c">
|
||||||
|
<Filter>layout\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="layout\blocked_vgs.c">
|
||||||
|
<Filter>layout\Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
<ClCompile Include="layout\caf_blocked.c">
|
<ClCompile Include="layout\caf_blocked.c">
|
||||||
<Filter>layout\Source Files</Filter>
|
<Filter>layout\Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
276
src/meta/awc.c
Normal file
276
src/meta/awc.c
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
#include "meta.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
#include "../layout/layout.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int big_endian;
|
||||||
|
int is_encrypted;
|
||||||
|
int is_music;
|
||||||
|
|
||||||
|
int total_streams;
|
||||||
|
|
||||||
|
int channel_count;
|
||||||
|
int sample_rate;
|
||||||
|
int codec;
|
||||||
|
int num_samples;
|
||||||
|
|
||||||
|
int block_chunk;
|
||||||
|
|
||||||
|
off_t stream_offset;
|
||||||
|
off_t stream_size;
|
||||||
|
|
||||||
|
} awc_header;
|
||||||
|
|
||||||
|
static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc);
|
||||||
|
|
||||||
|
|
||||||
|
/* AWC - from RAGE (Rockstar Advanced Game Engine) audio (Red Dead Redemption, Max Payne 3, GTA5) */
|
||||||
|
VGMSTREAM * init_vgmstream_awc(STREAMFILE *streamFile) {
|
||||||
|
VGMSTREAM * vgmstream = NULL;
|
||||||
|
awc_header awc;
|
||||||
|
|
||||||
|
/* check extension */
|
||||||
|
if (!check_extensions(streamFile,"awc"))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
/* check header */
|
||||||
|
if (!parse_awc_header(streamFile, &awc))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (awc.is_encrypted)
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
|
||||||
|
/* build the VGMSTREAM */
|
||||||
|
vgmstream = allocate_vgmstream(awc.channel_count, 0);
|
||||||
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
|
vgmstream->sample_rate = awc.sample_rate;
|
||||||
|
vgmstream->num_samples = awc.num_samples;
|
||||||
|
vgmstream->num_streams = awc.total_streams;
|
||||||
|
vgmstream->meta_type = meta_AWC;
|
||||||
|
|
||||||
|
|
||||||
|
switch(awc.codec) {
|
||||||
|
case 0x01: /* PCM (PC/PS3) [sfx, rarely] */
|
||||||
|
if (awc.is_music) goto fail; /* blocked_awc needs to be prepared */
|
||||||
|
vgmstream->coding_type = awc.big_endian ? coding_PCM16BE : coding_PCM16LE;
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->interleave_block_size = 0x02;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x04: /* IMA (PC) */
|
||||||
|
vgmstream->coding_type = coding_AWC_IMA;
|
||||||
|
vgmstream->layout_type = awc.is_music ? layout_blocked_awc : layout_none;
|
||||||
|
vgmstream->full_block_size = awc.block_chunk;
|
||||||
|
vgmstream->codec_endian = awc.big_endian;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#ifdef VGM_USE_MPEG
|
||||||
|
case 0x07: { /* MPEG (PS3) */
|
||||||
|
mpeg_custom_config cfg;
|
||||||
|
memset(&cfg, 0, sizeof(mpeg_custom_config));
|
||||||
|
|
||||||
|
cfg.chunk_size = awc.block_chunk;
|
||||||
|
cfg.big_endian = awc.big_endian;
|
||||||
|
|
||||||
|
vgmstream->codec_data = init_mpeg_custom_codec_data(streamFile, awc.stream_offset, &vgmstream->coding_type, vgmstream->channels, MPEG_AWC, &cfg);
|
||||||
|
if (!vgmstream->codec_data) goto fail;
|
||||||
|
vgmstream->layout_type = layout_none;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
case 0x05: /* XMA2 (X360) */
|
||||||
|
default:
|
||||||
|
VGM_LOG("AWC: unknown codec 0x%02x\n", awc.codec);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* open files; channel offsets are updated below */
|
||||||
|
if (!vgmstream_open_stream(vgmstream,streamFile,awc.stream_offset))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (vgmstream->layout_type == layout_blocked_awc)
|
||||||
|
block_update_awc(awc.stream_offset, vgmstream);
|
||||||
|
|
||||||
|
return vgmstream;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
close_vgmstream(vgmstream);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse Rockstar's AWC header (much info from LibertyV: https://github.com/koolkdev/libertyv).
|
||||||
|
* Made of entries for N streams, each with a number of tags pointing to chunks (header, data, events, etc). */
|
||||||
|
static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) {
|
||||||
|
int64_t (*read_64bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||||
|
int i, ch, entries;
|
||||||
|
uint32_t flags, info_header, tag_count = 0, tags_skip = 0;
|
||||||
|
off_t off;
|
||||||
|
int target_stream = streamFile->stream_index;
|
||||||
|
|
||||||
|
memset(awc,0,sizeof(awc_header));
|
||||||
|
|
||||||
|
|
||||||
|
/* check header */
|
||||||
|
if (read_32bitBE(0x00,streamFile) != 0x41444154 && /* "ADAT" (LE) */
|
||||||
|
read_32bitBE(0x00,streamFile) != 0x54414441) /* "TADA" (BE) */
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
awc->big_endian = read_32bitBE(0x00,streamFile) == 0x54414441;
|
||||||
|
if (awc->big_endian) {
|
||||||
|
read_64bit = read_64bitBE;
|
||||||
|
read_32bit = read_32bitBE;
|
||||||
|
read_16bit = read_16bitBE;
|
||||||
|
} else {
|
||||||
|
read_64bit = read_64bitLE;
|
||||||
|
read_32bit = read_32bitLE;
|
||||||
|
read_16bit = read_16bitLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
flags = read_32bit(0x04,streamFile);
|
||||||
|
entries = read_32bit(0x08,streamFile);
|
||||||
|
//header_size = read_32bit(0x0c,streamFile); /* after to stream id/tags, not including chunks */
|
||||||
|
|
||||||
|
off = 0x10;
|
||||||
|
|
||||||
|
if ((flags & 0xFF00FFFF) != 0xFF000001 || (flags & 0x00F00000)) {
|
||||||
|
VGM_LOG("AWC: unknown flags 0x%08x\n", flags);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & 0x00010000) /* some kind of mini offset table */
|
||||||
|
off += 0x2 * entries;
|
||||||
|
//if (flags % 0x00020000) /* seems to indicate chunks are not ordered (ie. header may go after data) */
|
||||||
|
// ...
|
||||||
|
//if (flags % 0x00040000) /* music/multichannel flag? (GTA5, not seen in RDR) */
|
||||||
|
// awc->is_music = 1;
|
||||||
|
if (flags & 0x00080000) /* encrypted data chunk (most of GTA5 PC) */
|
||||||
|
awc->is_encrypted = 1;
|
||||||
|
|
||||||
|
|
||||||
|
/* Music when the first id is 0 (base/fake entry with info for all channels), sfx pack otherwise.
|
||||||
|
* sfx = N single streams, music = N-1 interleaved mono channels (even for MP3/XMA).
|
||||||
|
* Music seems layered (N-1/2 stereo pairs), maybe set with events? */
|
||||||
|
awc->is_music = (read_32bit(off + 0x00,streamFile) & 0x1FFFFFFF) == 0x00000000;
|
||||||
|
if (awc->is_music) { /* all streams except id 0 is a channel */
|
||||||
|
awc->total_streams = 1;
|
||||||
|
target_stream = 1; /* we only need id 0, though channels may have its own tags/chunks */
|
||||||
|
}
|
||||||
|
else { /* each stream is a single sound */
|
||||||
|
awc->total_streams = entries;
|
||||||
|
if (target_stream == 0) target_stream = 1;
|
||||||
|
if (target_stream < 0 || target_stream > awc->total_streams || awc->total_streams < 1) goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* get stream base info */
|
||||||
|
for (i = 0; i < entries; i++) {
|
||||||
|
info_header = read_32bit(off + 0x04*i, streamFile);
|
||||||
|
tag_count = (info_header >> 29) & 0x7; /* 3b */
|
||||||
|
//id = (info_header >> 0) & 0x1FFFFFFF; /* 29b */
|
||||||
|
if (target_stream-1 == i)
|
||||||
|
break;
|
||||||
|
tags_skip += tag_count; /* tags to skip to reach target's tags, in the next header */
|
||||||
|
}
|
||||||
|
off += 0x04*entries;
|
||||||
|
off += 0x08*tags_skip;
|
||||||
|
|
||||||
|
/* get stream tags */
|
||||||
|
for (i = 0; i < tag_count; i++) {
|
||||||
|
uint64_t tag_header, tag, size, offset;
|
||||||
|
|
||||||
|
tag_header = (uint64_t)read_64bit(off + 0x08*i,streamFile);
|
||||||
|
tag = (tag_header >> 56) & 0xFF; /* 8b */
|
||||||
|
size = (tag_header >> 28) & 0x0FFFFFFF; /* 28b */
|
||||||
|
offset = (tag_header >> 0) & 0x0FFFFFFF; /* 28b */
|
||||||
|
|
||||||
|
/* Tags are apparently part of a hash derived from a word ("data", "format", etc).
|
||||||
|
* If music + 1ch, the header and data chunks can repeat for no reason (sometimes not even pointed). */
|
||||||
|
switch(tag) {
|
||||||
|
case 0x55: /* data */
|
||||||
|
awc->stream_offset = offset;
|
||||||
|
awc->stream_size = size;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x48: /* music header */
|
||||||
|
if (!awc->is_music) {
|
||||||
|
VGM_LOG("AWC: music header found in sfx\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 0x00(32): unknown (some count?) */
|
||||||
|
awc->block_chunk = read_32bit(offset + 0x04,streamFile);
|
||||||
|
awc->channel_count = read_32bit(offset + 0x08,streamFile);
|
||||||
|
|
||||||
|
if (awc->channel_count != entries - 1) { /* not counting id-0 */
|
||||||
|
VGM_LOG("AWC: number of music channels doesn't match entries\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ch = 0; ch < awc->channel_count; ch++) {
|
||||||
|
int num_samples, sample_rate, codec;
|
||||||
|
/* 0x00(32): stream id (not always in the header entries order) */
|
||||||
|
/* 0x08(16): headroom?, 0x0d(8): round size?, 0x0e(16): unknown (zero?) */
|
||||||
|
num_samples = read_32bit(offset + 0x0c + 0x10*ch + 0x04,streamFile);
|
||||||
|
sample_rate = (uint16_t)read_16bit(offset + 0x0c + 0x10*ch + 0x0a,streamFile);
|
||||||
|
codec = read_8bit(offset + 0x0c + 0x10*ch + 0x0c, streamFile);
|
||||||
|
|
||||||
|
/* validate as all channels should repeat this */
|
||||||
|
if ((awc->num_samples && awc->num_samples != num_samples) ||
|
||||||
|
(awc->sample_rate && awc->sample_rate != sample_rate) ||
|
||||||
|
(awc->codec && awc->codec != codec)) {
|
||||||
|
VGM_LOG("AWC: found header diffs between channels\n"); /* can rarely happen in stereo pairs */
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
awc->num_samples = num_samples;
|
||||||
|
awc->sample_rate = sample_rate;
|
||||||
|
awc->codec = codec;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xFA: /* sfx header */
|
||||||
|
if (awc->is_music) {
|
||||||
|
VGM_LOG("AWC: sfx header found in music\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
/* 0x04(32): -1?, 0x0a(16x4): unknown x4, 0x12: null? */
|
||||||
|
awc->num_samples = read_32bit(offset + 0x00,streamFile);
|
||||||
|
awc->sample_rate = (uint16_t)read_16bit(offset + 0x08,streamFile);
|
||||||
|
awc->codec = read_8bit(offset + 0x13, streamFile);
|
||||||
|
awc->channel_count = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0xA3: /* block-to-sample table (32b x number of blocks w/ num_samples at the start of each block) */
|
||||||
|
case 0xBD: /* events (32bx4): type_hash, params_hash, timestamp_ms, flags */
|
||||||
|
default: /* 0x5C=animation/RSC?, 0x68=midi?, 0x36/0x2B/0x5A/0xD9=? */
|
||||||
|
//VGM_LOG("AWC: ignoring unknown tag 0x%02x\n", tag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!awc->stream_offset) {
|
||||||
|
VGM_LOG("AWC: stream offset not found\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If music, data is divided into blocks of block_chunk size with padding.
|
||||||
|
* Each block has a header/seek table and interleaved data for all channels */
|
||||||
|
if (awc->is_music && read_32bit(awc->stream_offset, streamFile) != 0) {
|
||||||
|
VGM_LOG("AWC: music found, but block doesn't start with seek table\n");
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
fail:
|
||||||
|
return 0;
|
||||||
|
}
|
@ -61,7 +61,7 @@ VGMSTREAM * init_vgmstream_eacs(STREAMFILE *streamFile) {
|
|||||||
vgmstream->sample_rate = ea_header->dwSampleRate;
|
vgmstream->sample_rate = ea_header->dwSampleRate;
|
||||||
|
|
||||||
if(ea_header->bCompression==0) {
|
if(ea_header->bCompression==0) {
|
||||||
vgmstream->coding_type = coding_PCM16LE_int;
|
vgmstream->coding_type = coding_PCM16_int;
|
||||||
if(ea_header->bBits==1)
|
if(ea_header->bBits==1)
|
||||||
vgmstream->coding_type = coding_PCM8_int;
|
vgmstream->coding_type = coding_PCM8_int;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
|
|||||||
vgmstream->coding_type = coding_PCM16LE;
|
vgmstream->coding_type = coding_PCM16LE;
|
||||||
if (channel_count == 2)
|
if (channel_count == 2)
|
||||||
{
|
{
|
||||||
vgmstream->coding_type = coding_PCM16LE_int;
|
vgmstream->coding_type = coding_PCM16_int;
|
||||||
vgmstream->interleave_block_size = 2;
|
vgmstream->interleave_block_size = 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -684,4 +684,6 @@ VGMSTREAM * init_vgmstream_stm(STREAMFILE * streamFile);
|
|||||||
|
|
||||||
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile);
|
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile);
|
||||||
|
|
||||||
|
VGMSTREAM * init_vgmstream_awc(STREAMFILE * streamFile);
|
||||||
|
|
||||||
#endif /*_META_H*/
|
#endif /*_META_H*/
|
||||||
|
@ -53,7 +53,7 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
|
|||||||
vgmstream->current_block_offset=8+32*numSounds;
|
vgmstream->current_block_offset=8+32*numSounds;
|
||||||
vgmstream->channels = channel_count;
|
vgmstream->channels = channel_count;
|
||||||
vgmstream->sample_rate = read_32bitLE(0x20,streamFile);
|
vgmstream->sample_rate = read_32bitLE(0x20,streamFile);
|
||||||
vgmstream->coding_type = coding_PCM16LE_int;
|
vgmstream->coding_type = coding_PCM16_int;
|
||||||
vgmstream->num_samples = (int32_t)((get_streamfile_size(streamFile)-vgmstream->current_block_offset)/2/channel_count);
|
vgmstream->num_samples = (int32_t)((get_streamfile_size(streamFile)-vgmstream->current_block_offset)/2/channel_count);
|
||||||
if(loop_flag)
|
if(loop_flag)
|
||||||
{
|
{
|
||||||
|
@ -63,7 +63,11 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
|
|||||||
break;
|
break;
|
||||||
case 'p': /* "VAGp" (extended) [most common, ex Ratchet & Clank] */
|
case 'p': /* "VAGp" (extended) [most common, ex Ratchet & Clank] */
|
||||||
|
|
||||||
if ((version <= 0x00000004) && (datasize < filesize / 2)) { /* two VAGp in the same file */
|
if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */
|
||||||
|
channel_count = 2; /* The Simpsons Wrestling PSX interleave */
|
||||||
|
loop_flag = 0;
|
||||||
|
}
|
||||||
|
else if ((version <= 0x00000004) && (datasize < filesize / 2)) { /* two VAGp in the same file */
|
||||||
if (is_swag)
|
if (is_swag)
|
||||||
loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd);
|
loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd);
|
||||||
else
|
else
|
||||||
@ -129,7 +133,15 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
|
|||||||
case 'p': // VAGp
|
case 'p': // VAGp
|
||||||
interleave=0x10;
|
interleave=0x10;
|
||||||
|
|
||||||
if ((version == 0x00000004) && (datasize < filesize / 2)) {
|
if (read_32bitBE(0x6000,streamFile) == 0x56414770) { /* "VAGp" */
|
||||||
|
interleave = 0x6000; /* The Simpsons Wrestling PSX interleave, includes header */
|
||||||
|
vgmstream->layout_type = layout_interleave;
|
||||||
|
vgmstream->meta_type = meta_PS2_VAGs;
|
||||||
|
|
||||||
|
vgmstream->num_samples = datasize / 16 * 28;
|
||||||
|
start_offset = 0x30;
|
||||||
|
}
|
||||||
|
else if ((version == 0x00000004) && (datasize < filesize / 2)) {
|
||||||
vgmstream->channels=2;
|
vgmstream->channels=2;
|
||||||
vgmstream->layout_type=layout_interleave;
|
vgmstream->layout_type=layout_interleave;
|
||||||
vgmstream->meta_type=meta_PS2_VAGs;
|
vgmstream->meta_type=meta_PS2_VAGs;
|
||||||
|
@ -160,9 +160,10 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
|
|||||||
|
|
||||||
switch(codec) {
|
switch(codec) {
|
||||||
case 0xD01BD217: /* PCM X360 (D01BD217 35874EED B9D9B8E8 6EA9B995) */
|
case 0xD01BD217: /* PCM X360 (D01BD217 35874EED B9D9B8E8 6EA9B995) */
|
||||||
/* The Legend of Spyro (X360) */
|
/* ex. The Legend of Spyro (X360) */
|
||||||
vgmstream->coding_type = coding_PCM16BE;
|
vgmstream->coding_type = coding_PCM16_int;
|
||||||
//vgmstream->interleave_block_size = block_size / 2; //0x2; //todo 2ch PCM not working correctly (interleaved PCM not ok?)
|
vgmstream->codec_endian = 1; /* big */
|
||||||
|
vgmstream->interleave_block_size = 0x02; /* only used to setup channels */
|
||||||
|
|
||||||
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
vgmstream->num_samples = pcm_bytes_to_samples(stream_size, channel_count, 16);
|
||||||
break;
|
break;
|
||||||
|
@ -225,7 +225,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
|||||||
switch (codec_id) {
|
switch (codec_id) {
|
||||||
case 0x1:
|
case 0x1:
|
||||||
/* PCM */
|
/* PCM */
|
||||||
vgmstream->coding_type = coding_PCM16LE_int;
|
vgmstream->coding_type = coding_PCM16_int;
|
||||||
vgmstream->layout_type = layout_none;
|
vgmstream->layout_type = layout_none;
|
||||||
vgmstream->num_samples = stream_size / 2 / channel_count;
|
vgmstream->num_samples = stream_size / 2 / channel_count;
|
||||||
|
|
||||||
|
116
src/meta/vgs.c
116
src/meta/vgs.c
@ -1,100 +1,76 @@
|
|||||||
#include "meta.h"
|
#include "meta.h"
|
||||||
#include "../util.h"
|
#include "../util.h"
|
||||||
|
#include "../coding/coding.h"
|
||||||
|
#include "../layout/layout.h"
|
||||||
|
|
||||||
/* VGS (from Guitar Hero Encore - Rocks the 80s) */
|
/* VGS - from Guitar Hero Encore - Rocks the 80s, Guitar Hero II PS2 */
|
||||||
VGMSTREAM * init_vgmstream_vgs(STREAMFILE *streamFile) {
|
VGMSTREAM * init_vgmstream_vgs(STREAMFILE *streamFile) {
|
||||||
VGMSTREAM * vgmstream = NULL;
|
VGMSTREAM * vgmstream = NULL;
|
||||||
char filename[PATH_LIMIT];
|
|
||||||
off_t start_offset;
|
off_t start_offset;
|
||||||
|
size_t channel_size = 0, stream_data_size, stream_frame_count;
|
||||||
|
int channel_count = 0, loop_flag = 0, sample_rate = 0, stream_sample_rate;
|
||||||
|
int i;
|
||||||
|
|
||||||
int loop_flag;
|
|
||||||
int channel_flag;
|
|
||||||
int channel_flag_offset;
|
|
||||||
int channel_count;
|
|
||||||
|
|
||||||
/* check extension, case insensitive */
|
/* check extension, case insensitive */
|
||||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
if (!check_extensions(streamFile,"vgs"))
|
||||||
if (strcasecmp("vgs",filename_extension(filename))) goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* check header */
|
/* check header */
|
||||||
if (read_32bitBE(0x00,streamFile) != 0x56675321) /* "VgS!" */
|
if (read_32bitBE(0x00,streamFile) != 0x56675321) /* "VgS!" */
|
||||||
goto fail;
|
goto fail;
|
||||||
|
/* 0x04: version? */
|
||||||
|
|
||||||
loop_flag = 0;
|
/* contains N streams, which can have one less frame, or half frame and sample rate */
|
||||||
channel_flag_offset = get_streamfile_size(streamFile)-0x10;
|
for (i = 0; i < 8; i++) {
|
||||||
channel_flag = read_32bitBE(channel_flag_offset,streamFile);
|
stream_sample_rate = read_32bitLE(0x08 + 0x08*i + 0x00,streamFile);
|
||||||
|
stream_frame_count = read_32bitLE(0x08 + 0x08*i + 0x04,streamFile);
|
||||||
/* Only seen files up to 5 channels, but just
|
stream_data_size = stream_frame_count*0x10;
|
||||||
to be sure we will look up to 8 chanels */
|
|
||||||
switch (channel_flag) {
|
if (stream_sample_rate == 0)
|
||||||
case 0x00800000:
|
break;
|
||||||
channel_count = 1;
|
|
||||||
break;
|
if (!sample_rate || !channel_size) {
|
||||||
case 0x00810000:
|
sample_rate = stream_sample_rate;
|
||||||
channel_count = 2;
|
channel_size = stream_data_size;
|
||||||
break;
|
}
|
||||||
case 0x00820000:
|
|
||||||
channel_count = 3;
|
/* some streams end 1 frame early */
|
||||||
break;
|
if (channel_size - 0x10 == stream_data_size) {
|
||||||
case 0x00830000:
|
channel_size -= 0x10;
|
||||||
channel_count = 4;
|
}
|
||||||
break;
|
|
||||||
case 0x00840000:
|
/* Guitar Hero II sometimes uses half sample rate for last stream */
|
||||||
channel_count = 5;
|
if (sample_rate != stream_sample_rate) {
|
||||||
break;
|
VGM_LOG("VGS: ignoring stream %i\n", i);
|
||||||
case 0x00850000:
|
//total_streams++; // todo handle substreams
|
||||||
channel_count = 6;
|
break;
|
||||||
break;
|
}
|
||||||
case 0x00860000:
|
|
||||||
channel_count = 7;
|
channel_count++;
|
||||||
break;
|
}
|
||||||
case 0x00870000:
|
|
||||||
channel_count = 8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* build the VGMSTREAM */
|
/* build the VGMSTREAM */
|
||||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||||
if (!vgmstream) goto fail;
|
if (!vgmstream) goto fail;
|
||||||
|
|
||||||
/* fill in the vital statistics */
|
|
||||||
start_offset = 0x80;
|
start_offset = 0x80;
|
||||||
vgmstream->channels = channel_count;
|
vgmstream->sample_rate = sample_rate;
|
||||||
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
|
vgmstream->num_samples = ps_bytes_to_samples(channel_size*channel_count, channel_count);
|
||||||
vgmstream->coding_type = coding_PSX_badflags;
|
|
||||||
vgmstream->num_samples = (read_32bitLE(0x0C,streamFile)*channel_count*0x10)*28/16/channel_count;
|
|
||||||
if (loop_flag) {
|
|
||||||
vgmstream->loop_start_sample = 0;
|
|
||||||
vgmstream->loop_end_sample = (read_32bitLE(0x0C,streamFile)*channel_count*0x10)*28/16/channel_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
vgmstream->layout_type = layout_interleave;
|
vgmstream->coding_type = coding_PSX_badflags; /* flag = stream/channel number */
|
||||||
vgmstream->interleave_block_size = 0x10;
|
vgmstream->layout_type = layout_blocked_vgs;
|
||||||
vgmstream->meta_type = meta_VGS;
|
vgmstream->meta_type = meta_VGS;
|
||||||
|
|
||||||
/* 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=
|
/* open files; channel offsets are updated below */
|
||||||
vgmstream->ch[i].offset=start_offset+
|
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||||
vgmstream->interleave_block_size*i;
|
goto fail;
|
||||||
|
block_update_vgs(start_offset, vgmstream);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return vgmstream;
|
return vgmstream;
|
||||||
|
|
||||||
/* clean up anything we may have opened */
|
|
||||||
fail:
|
fail:
|
||||||
if (vgmstream) close_vgmstream(vgmstream);
|
close_vgmstream(vgmstream);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -134,6 +134,18 @@ static inline int32_t read_32bitBE(off_t offset, STREAMFILE * streamfile) {
|
|||||||
if (read_streamfile(buf,offset,4,streamfile)!=4) return -1;
|
if (read_streamfile(buf,offset,4,streamfile)!=4) return -1;
|
||||||
return get_32bitBE(buf);
|
return get_32bitBE(buf);
|
||||||
}
|
}
|
||||||
|
static inline int64_t read_64bitLE(off_t offset, STREAMFILE * streamfile) {
|
||||||
|
uint8_t buf[8];
|
||||||
|
|
||||||
|
if (read_streamfile(buf,offset,8,streamfile)!=8) return -1;
|
||||||
|
return get_64bitLE(buf);
|
||||||
|
}
|
||||||
|
static inline int64_t read_64bitBE(off_t offset, STREAMFILE * streamfile) {
|
||||||
|
uint8_t buf[8];
|
||||||
|
|
||||||
|
if (read_streamfile(buf,offset,8,streamfile)!=8) return -1;
|
||||||
|
return get_64bitBE(buf);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) {
|
static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) {
|
||||||
uint8_t buf[1];
|
uint8_t buf[1];
|
||||||
|
@ -25,6 +25,14 @@ static inline int32_t get_32bitLE(uint8_t * p) {
|
|||||||
return (p[0]) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
|
return (p[0]) | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int64_t get_64bitBE(uint8_t * p) {
|
||||||
|
return (uint64_t)(((uint64_t)p[0]<<56) | ((uint64_t)p[1]<<48) | ((uint64_t)p[2]<<40) | ((uint64_t)p[3]<<32) | ((uint64_t)p[4]<<24) | ((uint64_t)p[5]<<16) | ((uint64_t)p[6]<<8) | ((uint64_t)p[7]));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int64_t get_64bitLE(uint8_t * p) {
|
||||||
|
return (uint64_t)(((uint64_t)p[0]) | ((uint64_t)p[1]<<8) | ((uint64_t)p[2]<<16) | ((uint64_t)p[3]<<24) | ((uint64_t)p[4]<<32) | ((uint64_t)p[5]<<40) | ((uint64_t)p[6]<<48) | ((uint64_t)p[7]<<56));
|
||||||
|
}
|
||||||
|
|
||||||
void put_8bit(uint8_t * buf, int8_t i);
|
void put_8bit(uint8_t * buf, int8_t i);
|
||||||
|
|
||||||
void put_16bitLE(uint8_t * buf, int16_t i);
|
void put_16bitLE(uint8_t * buf, int16_t i);
|
||||||
|
@ -47,6 +47,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
|||||||
init_vgmstream_ps2_rxws,
|
init_vgmstream_ps2_rxws,
|
||||||
init_vgmstream_ps2_rxw,
|
init_vgmstream_ps2_rxw,
|
||||||
init_vgmstream_ps2_int,
|
init_vgmstream_ps2_int,
|
||||||
|
init_vgmstream_ngc_dsp_stm,
|
||||||
init_vgmstream_ps2_exst,
|
init_vgmstream_ps2_exst,
|
||||||
init_vgmstream_ps2_svag,
|
init_vgmstream_ps2_svag,
|
||||||
init_vgmstream_ps2_mib,
|
init_vgmstream_ps2_mib,
|
||||||
@ -367,6 +368,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
|
|||||||
init_vgmstream_sk_aud,
|
init_vgmstream_sk_aud,
|
||||||
init_vgmstream_stm,
|
init_vgmstream_stm,
|
||||||
init_vgmstream_ea_snu,
|
init_vgmstream_ea_snu,
|
||||||
|
init_vgmstream_awc,
|
||||||
|
|
||||||
init_vgmstream_txth, /* should go at the end (lower priority) */
|
init_vgmstream_txth, /* should go at the end (lower priority) */
|
||||||
#ifdef VGM_USE_FFMPEG
|
#ifdef VGM_USE_FFMPEG
|
||||||
@ -933,6 +935,8 @@ void render_vgmstream(sample * buffer, int32_t sample_count, VGMSTREAM * vgmstre
|
|||||||
case layout_rws_blocked:
|
case layout_rws_blocked:
|
||||||
case layout_hwas_blocked:
|
case layout_hwas_blocked:
|
||||||
case layout_ea_sns_blocked:
|
case layout_ea_sns_blocked:
|
||||||
|
case layout_blocked_awc:
|
||||||
|
case layout_blocked_vgs:
|
||||||
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
render_vgmstream_blocked(buffer,sample_count,vgmstream);
|
||||||
break;
|
break;
|
||||||
case layout_interleave_byte:
|
case layout_interleave_byte:
|
||||||
@ -968,9 +972,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||||||
case coding_NGC_DSP:
|
case coding_NGC_DSP:
|
||||||
return 14;
|
return 14;
|
||||||
case coding_PCM16LE:
|
case coding_PCM16LE:
|
||||||
case coding_PCM16LE_int:
|
|
||||||
case coding_PCM16LE_XOR_int:
|
case coding_PCM16LE_XOR_int:
|
||||||
case coding_PCM16BE:
|
case coding_PCM16BE:
|
||||||
|
case coding_PCM16_int:
|
||||||
case coding_PCM8:
|
case coding_PCM8:
|
||||||
case coding_PCM8_U:
|
case coding_PCM8_U:
|
||||||
case coding_PCM8_int:
|
case coding_PCM8_int:
|
||||||
@ -1052,6 +1056,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
|
|||||||
case coding_WWISE_IMA:
|
case coding_WWISE_IMA:
|
||||||
case coding_REF_IMA:
|
case coding_REF_IMA:
|
||||||
return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels;
|
return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels;
|
||||||
|
case coding_AWC_IMA:
|
||||||
|
return (0x800-4)*2;
|
||||||
case coding_RAD_IMA_mono:
|
case coding_RAD_IMA_mono:
|
||||||
return 32;
|
return 32;
|
||||||
case coding_NDS_PROCYON:
|
case coding_NDS_PROCYON:
|
||||||
@ -1124,9 +1130,9 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||||||
case coding_NGC_DSP:
|
case coding_NGC_DSP:
|
||||||
return 8;
|
return 8;
|
||||||
case coding_PCM16LE:
|
case coding_PCM16LE:
|
||||||
case coding_PCM16LE_int:
|
|
||||||
case coding_PCM16LE_XOR_int:
|
case coding_PCM16LE_XOR_int:
|
||||||
case coding_PCM16BE:
|
case coding_PCM16BE:
|
||||||
|
case coding_PCM16_int:
|
||||||
return 2;
|
return 2;
|
||||||
case coding_PCM8:
|
case coding_PCM8:
|
||||||
case coding_PCM8_U:
|
case coding_PCM8_U:
|
||||||
@ -1155,6 +1161,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
|
|||||||
case coding_WWISE_IMA:
|
case coding_WWISE_IMA:
|
||||||
case coding_REF_IMA:
|
case coding_REF_IMA:
|
||||||
return vgmstream->interleave_block_size;
|
return vgmstream->interleave_block_size;
|
||||||
|
case coding_AWC_IMA:
|
||||||
|
return 0x800;
|
||||||
case coding_RAD_IMA_mono:
|
case coding_RAD_IMA_mono:
|
||||||
return 0x14;
|
return 0x14;
|
||||||
case coding_NGC_DTK:
|
case coding_NGC_DTK:
|
||||||
@ -1306,13 +1314,6 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||||||
samples_to_do);
|
samples_to_do);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case coding_PCM16LE_int:
|
|
||||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
|
||||||
decode_pcm16LE_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
|
||||||
vgmstream->channels,vgmstream->samples_into_block,
|
|
||||||
samples_to_do);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case coding_PCM16LE_XOR_int:
|
case coding_PCM16LE_XOR_int:
|
||||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
decode_pcm16LE_XOR_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
decode_pcm16LE_XOR_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||||
@ -1327,6 +1328,14 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||||||
samples_to_do);
|
samples_to_do);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case coding_PCM16_int:
|
||||||
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
|
decode_pcm16_int(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||||
|
vgmstream->channels,vgmstream->samples_into_block,
|
||||||
|
samples_to_do,
|
||||||
|
vgmstream->codec_endian);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case coding_PCM8:
|
case coding_PCM8:
|
||||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
decode_pcm8(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
decode_pcm8(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||||
@ -1371,9 +1380,10 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||||||
break;
|
break;
|
||||||
case coding_PCMFLOAT:
|
case coding_PCMFLOAT:
|
||||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
decode_pcmfloat(vgmstream, &vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
decode_pcmfloat(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||||
vgmstream->channels,vgmstream->samples_into_block,
|
vgmstream->channels,vgmstream->samples_into_block,
|
||||||
samples_to_do);
|
samples_to_do,
|
||||||
|
vgmstream->codec_endian);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1650,6 +1660,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
|
|||||||
samples_to_do,chan);
|
samples_to_do,chan);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case coding_AWC_IMA:
|
||||||
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
|
decode_awc_ima(&vgmstream->ch[chan],buffer+samples_written*vgmstream->channels+chan,
|
||||||
|
vgmstream->channels,vgmstream->samples_into_block,
|
||||||
|
samples_to_do);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case coding_WS:
|
case coding_WS:
|
||||||
for (chan=0;chan<vgmstream->channels;chan++) {
|
for (chan=0;chan<vgmstream->channels;chan++) {
|
||||||
|
@ -74,9 +74,9 @@ enum { STREAM_NAME_SIZE = 255 }; /* reasonable max */
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
/* PCM */
|
/* PCM */
|
||||||
coding_PCM16LE, /* little endian 16-bit PCM */
|
coding_PCM16LE, /* little endian 16-bit PCM */
|
||||||
coding_PCM16LE_int, /* little endian 16-bit PCM with sample-level interleave */
|
|
||||||
coding_PCM16LE_XOR_int, /* little endian 16-bit PCM with sample-level xor */
|
coding_PCM16LE_XOR_int, /* little endian 16-bit PCM with sample-level xor */
|
||||||
coding_PCM16BE, /* big endian 16-bit PCM */
|
coding_PCM16BE, /* big endian 16-bit PCM */
|
||||||
|
coding_PCM16_int, /* 16-bit PCM with sample-level interleave */
|
||||||
|
|
||||||
coding_PCM8, /* 8-bit PCM */
|
coding_PCM8, /* 8-bit PCM */
|
||||||
coding_PCM8_int, /* 8-Bit PCM with sample-level interleave */
|
coding_PCM8_int, /* 8-Bit PCM with sample-level interleave */
|
||||||
@ -132,6 +132,7 @@ typedef enum {
|
|||||||
coding_FSB_IMA, /* FMOD's FSB multichannel IMA ADPCM */
|
coding_FSB_IMA, /* FMOD's FSB multichannel IMA ADPCM */
|
||||||
coding_WWISE_IMA, /* Audiokinetic Wwise IMA ADPCM */
|
coding_WWISE_IMA, /* Audiokinetic Wwise IMA ADPCM */
|
||||||
coding_REF_IMA, /* Reflections IMA ADPCM */
|
coding_REF_IMA, /* Reflections IMA ADPCM */
|
||||||
|
coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */
|
||||||
|
|
||||||
coding_MSADPCM, /* Microsoft ADPCM */
|
coding_MSADPCM, /* Microsoft ADPCM */
|
||||||
coding_WS, /* Westwood Studios VBR ADPCM */
|
coding_WS, /* Westwood Studios VBR ADPCM */
|
||||||
@ -236,6 +237,8 @@ typedef enum {
|
|||||||
layout_rws_blocked,
|
layout_rws_blocked,
|
||||||
layout_hwas_blocked,
|
layout_hwas_blocked,
|
||||||
layout_ea_sns_blocked, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */
|
layout_ea_sns_blocked, /* newest Electronic Arts blocks, found in SNS/SNU/SPS/etc formats */
|
||||||
|
layout_blocked_awc, /* Rockstar AWC */
|
||||||
|
layout_blocked_vgs, /* Guitar Hero II */
|
||||||
|
|
||||||
/* otherwise odd */
|
/* otherwise odd */
|
||||||
layout_acm, /* libacm layout */
|
layout_acm, /* libacm layout */
|
||||||
@ -621,6 +624,7 @@ typedef enum {
|
|||||||
meta_STM, /* Angel Studios/Rockstar San Diego Games */
|
meta_STM, /* Angel Studios/Rockstar San Diego Games */
|
||||||
meta_BINK, /* RAD Game Tools BINK audio/video */
|
meta_BINK, /* RAD Game Tools BINK audio/video */
|
||||||
meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */
|
meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */
|
||||||
|
meta_AWC, /* Rockstar AWC (GTA5, RDR) */
|
||||||
|
|
||||||
#ifdef VGM_USE_VORBIS
|
#ifdef VGM_USE_VORBIS
|
||||||
meta_OGG_VORBIS, /* Ogg Vorbis */
|
meta_OGG_VORBIS, /* Ogg Vorbis */
|
||||||
@ -874,7 +878,7 @@ typedef enum {
|
|||||||
MPEG_EAL32P, /* EALayer3 v2 "P" (PCM?), custom frames with v2 header */
|
MPEG_EAL32P, /* EALayer3 v2 "P" (PCM?), custom frames with v2 header */
|
||||||
MPEG_EAL32S, /* EALayer3 v2 "S" (Spike?), custom frames with v2 header */
|
MPEG_EAL32S, /* EALayer3 v2 "S" (Spike?), custom frames with v2 header */
|
||||||
MPEG_LYN, /* N streams of fixed interleave */
|
MPEG_LYN, /* N streams of fixed interleave */
|
||||||
MPEG_AWC /* N streams in absolute offsets (consecutive) */
|
MPEG_AWC /* N streams in block layout (music) or absolute offsets (sfx) */
|
||||||
} mpeg_custom_t;
|
} mpeg_custom_t;
|
||||||
|
|
||||||
/* config for the above modes */
|
/* config for the above modes */
|
||||||
@ -884,6 +888,7 @@ typedef struct {
|
|||||||
int chunk_size; /* size of a data portion */
|
int chunk_size; /* size of a data portion */
|
||||||
int interleave; /* size of stream interleave */
|
int interleave; /* size of stream interleave */
|
||||||
int encryption; /* encryption mode */
|
int encryption; /* encryption mode */
|
||||||
|
int big_endian;
|
||||||
/* for AHX */
|
/* for AHX */
|
||||||
int cri_type;
|
int cri_type;
|
||||||
uint16_t cri_key1;
|
uint16_t cri_key1;
|
||||||
@ -899,6 +904,11 @@ typedef struct {
|
|||||||
size_t output_buffer_size;
|
size_t output_buffer_size;
|
||||||
size_t samples_filled; /* data in the buffer (in samples) */
|
size_t samples_filled; /* data in the buffer (in samples) */
|
||||||
size_t samples_used; /* data extracted from the buffer */
|
size_t samples_used; /* data extracted from the buffer */
|
||||||
|
|
||||||
|
size_t current_size_count; /* data read (if the parser needs to know) */
|
||||||
|
size_t current_size_target; /* max data, until something happens */
|
||||||
|
size_t decode_to_discard; /* discard from this stream only (for EALayer3 or AWC) */
|
||||||
|
|
||||||
} mpeg_custom_stream;
|
} mpeg_custom_stream;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -924,7 +934,6 @@ typedef struct {
|
|||||||
|
|
||||||
size_t skip_samples; /* base encoder delay */
|
size_t skip_samples; /* base encoder delay */
|
||||||
size_t samples_to_discard; /* for custom mpeg looping */
|
size_t samples_to_discard; /* for custom mpeg looping */
|
||||||
size_t decode_to_discard; /* for EALayer3, that discards decoded samples and writes PCM blocks in their place */
|
|
||||||
|
|
||||||
} mpeg_codec_data;
|
} mpeg_codec_data;
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user