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("AUD", aud);
VGMSTREAM_DECLARE_FILE_TYPE("AUS", aus);
VGMSTREAM_DECLARE_FILE_TYPE("AWC", awc);
VGMSTREAM_DECLARE_FILE_TYPE("B1S", b1s);
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,
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 ---
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_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_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 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 */
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_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_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(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);
/* psx_decoder */

View File

@ -212,23 +212,3 @@ void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac
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;
}
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) {
/* 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;

View File

@ -54,7 +54,6 @@ int mpeg_custom_setup_init_default(STREAMFILE *streamFile, off_t start_offset, m
break;
case MPEG_LYN:
case MPEG_AWC:
goto fail; /* not fully implemented */
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)
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_EAL32P:
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;
}
if (!ok)
@ -393,6 +394,7 @@ static void decode_mpeg_custom_stream(VGMSTREAMCHANNEL *stream, mpeg_codec_data
case MPEG_EAL32P:
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_AWC: ok = mpeg_custom_parse_frame_awc(stream, data, num_stream); break;
default: ok = mpeg_custom_parse_frame_default(stream, data); break;
}
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);
/* for EALayer3, that discards decoded samples and writes PCM blocks instead */
if (data->decode_to_discard) {
/* discard for weird features (EALayer3 and PCM blocks, AWC and repeated frames) */
if (ms->decode_to_discard) {
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)
decode_to_discard = samples_filled;
bytes_to_discard = sizeof(sample)*decode_to_discard*data->channels_per_frame;
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;
}
@ -522,10 +524,10 @@ void reset_mpeg(VGMSTREAM *vgmstream) {
mpg123_feedseek(data->streams[i]->m,0,SEEK_SET,&input_offset);
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
}
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);
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
if (vgmstream->loop_ch)
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_used = 0;
data->decode_to_discard = 0;
}
/* 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);
data->streams[i]->samples_filled = 0;
data->streams[i]->samples_used = 0;
data->streams[i]->decode_to_discard = 0;
}
data->samples_to_discard = data->skip_samples; /* initial delay */
data->decode_to_discard = 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_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_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_awc(VGMSTREAMCHANNEL *stream, mpeg_codec_data *data, int num_stream);
#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) {
int i;
int32_t sample_count;
void decode_pcm16_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int big_endian) {
int i, 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) {
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;
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) {
uint32_t sample_int = read_32bit(stream->offset+i*4,stream->streamfile);
float sample_float;
float* sample_float;
int sample_pcm;
memcpy(&sample_float, &sample_int, 4); /* maybe unorthodox but simplest */
sample_pcm = floor(sample_float * 32767.f + .5f);
sample_float = (float*)&sample_int;
sample_pcm = floor((*sample_float) * 32767.f + .5f);
outbuf[sample_count] = clamp16(sample_pcm);
}

View File

@ -42,6 +42,7 @@ static const char* extension_list[] = {
"at3",
"aud",
"aus",
"awc",
"b1s",
"baf",
@ -395,10 +396,10 @@ typedef struct {
static const coding_info coding_info_list[] = {
{coding_PCM16BE, "Big 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_PCM16BE, "Big Endian 16-bit PCM"},
{coding_PCM16_int, "16-bit PCM with 2 byte interleave"},
{coding_PCM8, "8-bit PCM"},
{coding_PCM8_U, "8-bit unsigned PCM"},
{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_WWISE_IMA, "Audiokinetic Wwise 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_ACM, "InterPlay ACM"},
{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_scd_int, "SCD multistream interleave"},
{layout_ea_sns_blocked, "Electronic Arts SNS blocked"},
{layout_blocked_awc, "blocked (AWC)"},
{layout_blocked_vgs, "blocked (VGS)"},
#ifdef VGM_USE_VORBIS
{layout_ogg_vorbis, "Ogg"},
#endif
@ -716,7 +720,7 @@ static const meta_info meta_info_list[] = {
{meta_MSVP, "MSVP Header"},
{meta_NGC_SSM, "SSM DSP 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_WII_SMP, "SMP DSP 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_BINK, "RAD Game Tools Bink header"},
{meta_EA_SNU, "Electronic Arts SNU header"},
{meta_AWC, "Rockstar AWC header"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -143,6 +143,12 @@ void render_vgmstream_blocked(sample * buffer, int32_t sample_count, VGMSTREAM *
break;
case layout_ea_sns_blocked:
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;
default:
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 {
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);
else
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 block_update_awc(off_t block_offset, VGMSTREAM * vgmstream);
void block_update_vgs(off_t block_offset, VGMSTREAM * vgmstream);
/* other layouts */
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"
>
</File>
<File
RelativePath=".\coding\mpeg_custom_utils_awc.c"
>
</File>
<File
RelativePath=".\coding\mpeg_custom_utils_ealayer3.c"
>
@ -1530,6 +1534,14 @@
RelativePath=".\layout\blocked.c"
>
</File>
<File
RelativePath=".\layout\blocked_awc.c"
>
</File>
<File
RelativePath=".\layout\blocked_vgs.c"
>
</File>
<File
RelativePath=".\layout\caf_blocked.c"
>

View File

@ -427,6 +427,7 @@
<ClCompile Include="coding\mc3_decoder.c" />
<ClCompile Include="coding\mpeg_custom_utils.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_decoder.c" />
<ClCompile Include="coding\msadpcm_decoder.c" />
@ -453,6 +454,8 @@
<ClCompile Include="layout\ast_blocked.c" />
<ClCompile Include="layout\bdsp_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\de2_blocked.c" />
<ClCompile Include="layout\ea_block.c" />

View File

@ -817,6 +817,9 @@
<ClCompile Include="coding\mpeg_custom_utils_ahx.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mpeg_custom_utils_awc.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\mpeg_custom_utils_ealayer3.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
@ -895,6 +898,12 @@
<ClCompile Include="layout\blocked.c">
<Filter>layout\Source Files</Filter>
</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">
<Filter>layout\Source Files</Filter>
</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;
if(ea_header->bCompression==0) {
vgmstream->coding_type = coding_PCM16LE_int;
vgmstream->coding_type = coding_PCM16_int;
if(ea_header->bBits==1)
vgmstream->coding_type = coding_PCM8_int;
}

View File

@ -68,7 +68,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
vgmstream->coding_type = coding_PCM16LE;
if (channel_count == 2)
{
vgmstream->coding_type = coding_PCM16LE_int;
vgmstream->coding_type = coding_PCM16_int;
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_awc(STREAMFILE * streamFile);
#endif /*_META_H*/

View File

@ -53,7 +53,7 @@ VGMSTREAM * init_vgmstream_sab(STREAMFILE *streamFile) {
vgmstream->current_block_offset=8+32*numSounds;
vgmstream->channels = channel_count;
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);
if(loop_flag)
{

View File

@ -63,7 +63,11 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
break;
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)
loop_flag = vag_find_loop_offsets(streamFile, 0x30, &loopStart, &loopEnd);
else
@ -129,7 +133,15 @@ VGMSTREAM * init_vgmstream_ps2_vag(STREAMFILE *streamFile) {
case 'p': // VAGp
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->layout_type=layout_interleave;
vgmstream->meta_type=meta_PS2_VAGs;

View File

@ -160,9 +160,10 @@ VGMSTREAM * init_vgmstream_rws(STREAMFILE *streamFile) {
switch(codec) {
case 0xD01BD217: /* PCM X360 (D01BD217 35874EED B9D9B8E8 6EA9B995) */
/* The Legend of Spyro (X360) */
vgmstream->coding_type = coding_PCM16BE;
//vgmstream->interleave_block_size = block_size / 2; //0x2; //todo 2ch PCM not working correctly (interleaved PCM not ok?)
/* ex. The Legend of Spyro (X360) */
vgmstream->coding_type = coding_PCM16_int;
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);
break;

View File

@ -225,7 +225,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
switch (codec_id) {
case 0x1:
/* PCM */
vgmstream->coding_type = coding_PCM16LE_int;
vgmstream->coding_type = coding_PCM16_int;
vgmstream->layout_type = layout_none;
vgmstream->num_samples = stream_size / 2 / channel_count;

View File

@ -1,100 +1,76 @@
#include "meta.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 * vgmstream = NULL;
char filename[PATH_LIMIT];
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 */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("vgs",filename_extension(filename))) goto fail;
if (!check_extensions(streamFile,"vgs"))
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x56675321) /* "VgS!" */
goto fail;
/* 0x04: version? */
loop_flag = 0;
channel_flag_offset = get_streamfile_size(streamFile)-0x10;
channel_flag = read_32bitBE(channel_flag_offset,streamFile);
/* Only seen files up to 5 channels, but just
to be sure we will look up to 8 chanels */
switch (channel_flag) {
case 0x00800000:
channel_count = 1;
break;
case 0x00810000:
channel_count = 2;
break;
case 0x00820000:
channel_count = 3;
break;
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;
}
/* contains N streams, which can have one less frame, or half frame and sample rate */
for (i = 0; i < 8; i++) {
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;
if (stream_sample_rate == 0)
break;
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;
}
channel_count++;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x80;
vgmstream->channels = channel_count;
vgmstream->sample_rate = read_32bitLE(0x08,streamFile);
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->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(channel_size*channel_count, channel_count);
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x10;
vgmstream->coding_type = coding_PSX_badflags; /* flag = stream/channel number */
vgmstream->layout_type = layout_blocked_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=
vgmstream->ch[i].offset=start_offset+
vgmstream->interleave_block_size*i;
}
}
/* open files; channel offsets are updated below */
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
block_update_vgs(start_offset, vgmstream);
return vgmstream;
/* clean up anything we may have opened */
fail:
if (vgmstream) close_vgmstream(vgmstream);
close_vgmstream(vgmstream);
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;
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) {
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);
}
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_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_rxw,
init_vgmstream_ps2_int,
init_vgmstream_ngc_dsp_stm,
init_vgmstream_ps2_exst,
init_vgmstream_ps2_svag,
init_vgmstream_ps2_mib,
@ -367,6 +368,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_sk_aud,
init_vgmstream_stm,
init_vgmstream_ea_snu,
init_vgmstream_awc,
init_vgmstream_txth, /* should go at the end (lower priority) */
#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_hwas_blocked:
case layout_ea_sns_blocked:
case layout_blocked_awc:
case layout_blocked_vgs:
render_vgmstream_blocked(buffer,sample_count,vgmstream);
break;
case layout_interleave_byte:
@ -968,9 +972,9 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_NGC_DSP:
return 14;
case coding_PCM16LE:
case coding_PCM16LE_int:
case coding_PCM16LE_XOR_int:
case coding_PCM16BE:
case coding_PCM16_int:
case coding_PCM8:
case coding_PCM8_U:
case coding_PCM8_int:
@ -1052,6 +1056,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) {
case coding_WWISE_IMA:
case coding_REF_IMA:
return (vgmstream->interleave_block_size-4*vgmstream->channels)*2/vgmstream->channels;
case coding_AWC_IMA:
return (0x800-4)*2;
case coding_RAD_IMA_mono:
return 32;
case coding_NDS_PROCYON:
@ -1124,9 +1130,9 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_NGC_DSP:
return 8;
case coding_PCM16LE:
case coding_PCM16LE_int:
case coding_PCM16LE_XOR_int:
case coding_PCM16BE:
case coding_PCM16_int:
return 2;
case coding_PCM8:
case coding_PCM8_U:
@ -1155,6 +1161,8 @@ int get_vgmstream_frame_size(VGMSTREAM * vgmstream) {
case coding_WWISE_IMA:
case coding_REF_IMA:
return vgmstream->interleave_block_size;
case coding_AWC_IMA:
return 0x800;
case coding_RAD_IMA_mono:
return 0x14;
case coding_NGC_DTK:
@ -1306,13 +1314,6 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do);
}
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:
for (chan=0;chan<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);
}
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:
for (chan=0;chan<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;
case coding_PCMFLOAT:
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,
samples_to_do);
samples_to_do,
vgmstream->codec_endian);
}
break;
@ -1650,6 +1660,13 @@ void decode_vgmstream(VGMSTREAM * vgmstream, int samples_written, int samples_to
samples_to_do,chan);
}
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:
for (chan=0;chan<vgmstream->channels;chan++) {

View File

@ -74,9 +74,9 @@ enum { STREAM_NAME_SIZE = 255 }; /* reasonable max */
typedef enum {
/* 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_PCM16BE, /* big endian 16-bit PCM */
coding_PCM16_int, /* 16-bit PCM with sample-level interleave */
coding_PCM8, /* 8-bit PCM */
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_WWISE_IMA, /* Audiokinetic Wwise IMA ADPCM */
coding_REF_IMA, /* Reflections IMA ADPCM */
coding_AWC_IMA, /* Rockstar AWC IMA ADPCM */
coding_MSADPCM, /* Microsoft ADPCM */
coding_WS, /* Westwood Studios VBR ADPCM */
@ -236,6 +237,8 @@ typedef enum {
layout_rws_blocked,
layout_hwas_blocked,
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 */
layout_acm, /* libacm layout */
@ -621,6 +624,7 @@ typedef enum {
meta_STM, /* Angel Studios/Rockstar San Diego Games */
meta_BINK, /* RAD Game Tools BINK audio/video */
meta_EA_SNU, /* Electronic Arts SNU (Dead Space) */
meta_AWC, /* Rockstar AWC (GTA5, RDR) */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */
@ -874,7 +878,7 @@ typedef enum {
MPEG_EAL32P, /* EALayer3 v2 "P" (PCM?), custom frames with v2 header */
MPEG_EAL32S, /* EALayer3 v2 "S" (Spike?), custom frames with v2 header */
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;
/* config for the above modes */
@ -884,6 +888,7 @@ typedef struct {
int chunk_size; /* size of a data portion */
int interleave; /* size of stream interleave */
int encryption; /* encryption mode */
int big_endian;
/* for AHX */
int cri_type;
uint16_t cri_key1;
@ -899,6 +904,11 @@ typedef struct {
size_t output_buffer_size;
size_t samples_filled; /* data in the buffer (in samples) */
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;
typedef struct {
@ -924,7 +934,6 @@ typedef struct {
size_t skip_samples; /* base encoder delay */
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;
#endif