Merge pull request #121 from bnnm/awc-rws-misc

AWC, RWS, misc
This commit is contained in:
Christopher Snowhill 2017-08-28 15:09:26 -07:00 committed by GitHub
commit cdaa10ed87
33 changed files with 742 additions and 139 deletions

View File

@ -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);

View File

@ -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.

View File

@ -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 */

View File

@ -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) {

View File

@ -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;

View File

@ -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:

View 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

View File

@ -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;
} }
} }

View File

@ -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;

View File

@ -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 */

View File

@ -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);
} }

View File

@ -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"},

View File

@ -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
View 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
View 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;
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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"
> >

View File

@ -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" />

View File

@ -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
View 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;
}

View File

@ -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;
} }

View File

@ -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;
} }
} }

View File

@ -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*/

View File

@ -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)
{ {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -1,58 +1,53 @@
#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);
stream_data_size = stream_frame_count*0x10;
/* Only seen files up to 5 channels, but just if (stream_sample_rate == 0)
to be sure we will look up to 8 chanels */
switch (channel_flag) {
case 0x00800000:
channel_count = 1;
break; break;
case 0x00810000:
channel_count = 2; if (!sample_rate || !channel_size) {
sample_rate = stream_sample_rate;
channel_size = stream_data_size;
}
/* some streams end 1 frame early */
if (channel_size - 0x10 == stream_data_size) {
channel_size -= 0x10;
}
/* Guitar Hero II sometimes uses half sample rate for last stream */
if (sample_rate != stream_sample_rate) {
VGM_LOG("VGS: ignoring stream %i\n", i);
//total_streams++; // todo handle substreams
break; break;
case 0x00820000: }
channel_count = 3;
break; channel_count++;
case 0x00830000:
channel_count = 4;
break;
case 0x00840000:
channel_count = 5;
break;
case 0x00850000:
channel_count = 6;
break;
case 0x00860000:
channel_count = 7;
break;
case 0x00870000:
channel_count = 8;
break;
default:
goto fail;
} }
@ -60,41 +55,22 @@ VGMSTREAM * init_vgmstream_vgs(STREAMFILE *streamFile) {
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;
} }

View File

@ -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];

View File

@ -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);

View File

@ -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++) {

View File

@ -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