mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-24 06:50:20 +01:00
commit
86c71f188f
@ -202,8 +202,8 @@ have total samples after those.
|
||||
Certain formats have encrypted data, and need a key to decrypt. vgmstream
|
||||
will try to find the correct key from a list, but it can be provided by
|
||||
a companion file:
|
||||
- .adx: .adxkey (derived 6 byte key, in start/mult/add format)
|
||||
- .ahx: .ahxkey (derived 6 byte key, in start/mult/add format)
|
||||
- .adx: .adxkey (keystring, keycode, or derived 6 byte start/mult/add key)
|
||||
- .ahx: .ahxkey (derived 6 byte start/mult/add key)
|
||||
- .hca: .hcakey (8 byte decryption key, a 64-bit number)
|
||||
- May be followed by 2 byte AWB scramble key for newer HCA
|
||||
- .fsb: .fsbkey (decryption key, in hex)
|
||||
|
@ -147,7 +147,6 @@ codec = (codec string)
|
||||
Changes the behavior of some codecs:
|
||||
```
|
||||
# - NGC_DSP: 0=normal interleave, 1=byte interleave, 2=no interleave
|
||||
# - ATRAC3: 0=autodetect joint stereo, 1=force joint stereo, 2=force normal stereo
|
||||
# - XMA1|XMA2: 0=dual multichannel (2ch xN), 1=single multichannel (1ch xN)
|
||||
# - XBOX: 0=standard (mono or stereo interleave), 1=force mono interleave mode
|
||||
# - PCFX: 0=standard, 1='buggy encoder' mode, 2/3=same as 0/1 but with double volume
|
||||
|
@ -297,6 +297,12 @@ uint32_t ffmpeg_get_channel_layout(ffmpeg_codec_data * data);
|
||||
void ffmpeg_set_channel_remapping(ffmpeg_codec_data * data, int *channels_remap);
|
||||
|
||||
|
||||
/* ffmpeg_decoder_utils.c (helper-things) */
|
||||
ffmpeg_codec_data * init_ffmpeg_atrac3_raw(STREAMFILE *sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay);
|
||||
ffmpeg_codec_data * init_ffmpeg_atrac3_riff(STREAMFILE *sf, off_t offset, int* out_samples);
|
||||
|
||||
|
||||
/* ffmpeg_decoder_custom_opus.c (helper-things) */
|
||||
typedef struct {
|
||||
int channels;
|
||||
int skip;
|
||||
@ -307,7 +313,6 @@ typedef struct {
|
||||
int channel_mapping[8];
|
||||
} opus_config;
|
||||
|
||||
/* ffmpeg_decoder_custom_opus.c (helper-things) */
|
||||
ffmpeg_codec_data * init_ffmpeg_switch_opus_config(STREAMFILE *streamFile, off_t start_offset, size_t data_size, opus_config* cfg);
|
||||
ffmpeg_codec_data * init_ffmpeg_switch_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
ffmpeg_codec_data * init_ffmpeg_ue4_opus(STREAMFILE *streamFile, off_t start_offset, size_t data_size, int channels, int skip, int sample_rate);
|
||||
@ -319,13 +324,11 @@ size_t switch_opus_get_samples(off_t offset, size_t stream_size, STREAMFILE *str
|
||||
size_t switch_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
|
||||
size_t ue4_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
|
||||
size_t ea_opus_get_encoder_delay(off_t offset, STREAMFILE *streamFile);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* coding_utils */
|
||||
int ffmpeg_fmt_chunk_swap_endian(uint8_t * chunk, size_t chunk_size, uint16_t codec);
|
||||
int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay);
|
||||
int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay);
|
||||
int ffmpeg_make_riff_xma1(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int stream_mode);
|
||||
int ffmpeg_make_riff_xma2(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_count, int block_size);
|
||||
@ -367,8 +370,6 @@ void xma_fix_raw_samples(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stre
|
||||
void xma_fix_raw_samples_hb(VGMSTREAM *vgmstream, STREAMFILE *headerFile, STREAMFILE *bodyFile, off_t stream_offset, size_t stream_size, off_t chunk_offset, int fix_num_samples, int fix_loop_samples);
|
||||
void xma_fix_raw_samples_ch(VGMSTREAM *vgmstream, STREAMFILE*streamFile, off_t stream_offset, size_t stream_size, int channel_per_stream, int fix_num_samples, int fix_loop_samples);
|
||||
|
||||
int riff_get_fact_skip_samples(STREAMFILE * streamFile, off_t start_offset);
|
||||
|
||||
size_t atrac3_bytes_to_samples(size_t bytes, int full_block_align);
|
||||
size_t atrac3plus_bytes_to_samples(size_t bytes, int full_block_align);
|
||||
size_t ac3_bytes_to_samples(size_t bytes, int full_block_align, int channels);
|
||||
|
@ -37,45 +37,6 @@ static uint32_t read_bitsBE_b(off_t bit_offset, int num_bits, STREAMFILE *stream
|
||||
/* ******************************************** */
|
||||
/* All helpers copy a RIFF header to buf and returns the number of bytes in buf or -1 when buf is not big enough */
|
||||
|
||||
int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay) {
|
||||
uint16_t codec_ATRAC3 = 0x0270;
|
||||
size_t riff_size = 4+4+ 4 + 0x28 + 0x10 + 4+4;
|
||||
|
||||
if (buf_size < riff_size)
|
||||
return -1;
|
||||
|
||||
memcpy(buf+0x00, "RIFF", 4);
|
||||
put_32bitLE(buf+0x04, (int32_t)(riff_size-4-4 + data_size)); /* riff size */
|
||||
memcpy(buf+0x08, "WAVE", 4);
|
||||
|
||||
memcpy(buf+0x0c, "fmt ", 4);
|
||||
put_32bitLE(buf+0x10, 0x20);/*fmt size*/
|
||||
put_16bitLE(buf+0x14, codec_ATRAC3);
|
||||
put_16bitLE(buf+0x16, channels);
|
||||
put_32bitLE(buf+0x18, sample_rate);
|
||||
put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong) */
|
||||
put_32bitLE(buf+0x20, (int16_t)(block_align)); /* block align */
|
||||
|
||||
put_16bitLE(buf+0x24, 0x0e); /* extra data size */
|
||||
put_16bitLE(buf+0x26, 1); /* unknown, always 1 */
|
||||
put_16bitLE(buf+0x28, 0x0800 * channels); /* unknown (some size? 0x1000=2ch, 0x0800=1ch) */
|
||||
put_16bitLE(buf+0x2a, 0); /* unknown, always 0 */
|
||||
put_16bitLE(buf+0x2c, joint_stereo ? 0x0001 : 0x0000);
|
||||
put_16bitLE(buf+0x2e, joint_stereo ? 0x0001 : 0x0000); /* repeated? */
|
||||
put_16bitLE(buf+0x30, 1); /* unknown, always 1 (frame_factor?) */
|
||||
put_16bitLE(buf+0x32, 0); /* unknown, always 0 */
|
||||
|
||||
memcpy(buf+0x34, "fact", 4);
|
||||
put_32bitLE(buf+0x38, 0x8); /* fact size */
|
||||
put_32bitLE(buf+0x3c, sample_count);
|
||||
put_32bitLE(buf+0x40, encoder_delay);
|
||||
|
||||
memcpy(buf+0x44, "data", 4);
|
||||
put_32bitLE(buf+0x48, data_size); /* data size */
|
||||
|
||||
return riff_size;
|
||||
}
|
||||
|
||||
int ffmpeg_make_riff_atrac3plus(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int encoder_delay) {
|
||||
uint16_t codec_ATRAC3plus = 0xfffe; /* wave format extensible */
|
||||
size_t riff_size = 4+4+ 4 + 0x3c + 0x14 + 4+4;
|
||||
@ -988,24 +949,6 @@ void xma2_parse_xma2_chunk(STREAMFILE *streamFile, off_t chunk_offset, int * out
|
||||
if(out_loop_flag) *out_loop_flag = loop_flag;
|
||||
}
|
||||
|
||||
/* manually read from "fact" chunk */
|
||||
int riff_get_fact_skip_samples(STREAMFILE * streamFile, off_t start_offset) {
|
||||
off_t chunk_offset;
|
||||
size_t chunk_size, fact_skip_samples = 0;
|
||||
if (!find_chunk_le(streamFile, 0x66616374, start_offset + 0x0c, 0, &chunk_offset, &chunk_size)) /* find "fact" */
|
||||
goto fail;
|
||||
if (chunk_size == 0x8) {
|
||||
fact_skip_samples = read_32bitLE(chunk_offset + 0x4, streamFile);
|
||||
}
|
||||
else if (chunk_size == 0xc) {
|
||||
fact_skip_samples = read_32bitLE(chunk_offset + 0x8, streamFile);
|
||||
}
|
||||
|
||||
return fact_skip_samples;
|
||||
fail:
|
||||
return 0; /* meh */
|
||||
}
|
||||
|
||||
/* ******************************************** */
|
||||
/* OTHER STUFF */
|
||||
/* ******************************************** */
|
||||
|
@ -52,6 +52,14 @@ static void remap_audio(sample_t *outbuf, int sample_count, int channels, int ch
|
||||
}
|
||||
}
|
||||
|
||||
static void invert_audio(sample_t *outbuf, int sample_count, int channels) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < sample_count*channels; i++) {
|
||||
outbuf[i] = -outbuf[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* converts codec's samples (can be in any format, ex. Ogg's float32) to PCM16 */
|
||||
static void convert_audio_pcm16(sample_t *outbuf, const uint8_t *inbuf, int fullSampleCount, int bitsPerSample, int floatingPoint) {
|
||||
int s;
|
||||
@ -728,6 +736,8 @@ end:
|
||||
convert_audio_pcm16(outbuf, data->sampleBuffer, samplesReadNow * channels, data->bitsPerSample, data->floatingPoint);
|
||||
if (data->channel_remap_set)
|
||||
remap_audio(outbuf, samplesReadNow, data->channels, data->channel_remap);
|
||||
if (data->invert_audio_set)
|
||||
invert_audio(outbuf, samplesReadNow, data->channels);
|
||||
|
||||
/* clean buffer when requested more samples than possible */
|
||||
if (endOfAudio && samplesReadNow < samples_to_do) {
|
||||
|
189
src/coding/ffmpeg_decoder_utils.c
Normal file
189
src/coding/ffmpeg_decoder_utils.c
Normal file
@ -0,0 +1,189 @@
|
||||
#include "coding.h"
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
|
||||
static int ffmpeg_make_riff_atrac3(uint8_t * buf, size_t buf_size, size_t sample_count, size_t data_size, int channels, int sample_rate, int block_align, int joint_stereo, int encoder_delay) {
|
||||
uint16_t codec_ATRAC3 = 0x0270;
|
||||
size_t riff_size = 4+4+ 4 + 0x28 + 0x10 + 4+4;
|
||||
|
||||
if (buf_size < riff_size)
|
||||
return -1;
|
||||
|
||||
memcpy(buf+0x00, "RIFF", 4);
|
||||
put_32bitLE(buf+0x04, (int32_t)(riff_size-4-4 + data_size)); /* riff size */
|
||||
memcpy(buf+0x08, "WAVE", 4);
|
||||
|
||||
memcpy(buf+0x0c, "fmt ", 4);
|
||||
put_32bitLE(buf+0x10, 0x20);/*fmt size*/
|
||||
put_16bitLE(buf+0x14, codec_ATRAC3);
|
||||
put_16bitLE(buf+0x16, channels);
|
||||
put_32bitLE(buf+0x18, sample_rate);
|
||||
put_32bitLE(buf+0x1c, sample_rate*channels / sizeof(sample)); /* average bytes per second (wrong) */
|
||||
put_32bitLE(buf+0x20, (int16_t)(block_align)); /* block align */
|
||||
|
||||
put_16bitLE(buf+0x24, 0x0e); /* extra data size */
|
||||
put_16bitLE(buf+0x26, 1); /* unknown, always 1 */
|
||||
put_16bitLE(buf+0x28, 0x0800 * channels); /* unknown (some size? 0x1000=2ch, 0x0800=1ch) */
|
||||
put_16bitLE(buf+0x2a, 0); /* unknown, always 0 */
|
||||
put_16bitLE(buf+0x2c, joint_stereo ? 0x0001 : 0x0000);
|
||||
put_16bitLE(buf+0x2e, joint_stereo ? 0x0001 : 0x0000); /* repeated? */
|
||||
put_16bitLE(buf+0x30, 1); /* unknown, always 1 (frame_factor?) */
|
||||
put_16bitLE(buf+0x32, 0); /* unknown, always 0 */
|
||||
|
||||
memcpy(buf+0x34, "fact", 4);
|
||||
put_32bitLE(buf+0x38, 0x8); /* fact size */
|
||||
put_32bitLE(buf+0x3c, sample_count);
|
||||
put_32bitLE(buf+0x40, encoder_delay);
|
||||
|
||||
memcpy(buf+0x44, "data", 4);
|
||||
put_32bitLE(buf+0x48, data_size); /* data size */
|
||||
|
||||
return riff_size;
|
||||
}
|
||||
|
||||
ffmpeg_codec_data * init_ffmpeg_atrac3_raw(STREAMFILE *sf, off_t offset, size_t data_size, int sample_count, int channels, int sample_rate, int block_align, int encoder_delay) {
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[0x100];
|
||||
int bytes;
|
||||
int joint_stereo = (block_align == 0x60*channels) && channels > 1; /* only lowest block size does joint stereo */
|
||||
int is_at3 = 1; /* could detect using block size */
|
||||
|
||||
/* create fake header + init ffmpeg + apply fixes to FFmpeg decoding */
|
||||
bytes = ffmpeg_make_riff_atrac3(buf,sizeof(buf), sample_count, data_size, channels, sample_rate, block_align, joint_stereo, encoder_delay);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(sf, buf,bytes, offset,data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
|
||||
/* unlike with RIFF ATRAC3 we don't set implicit delay, as raw ATRAC3 headers often give loop/samples
|
||||
* in offsets, so calcs are expected to be handled externally (presumably the game would call raw decoding API
|
||||
* and any skips would be handled manually) */
|
||||
|
||||
/* FFmpeg reads this but just in case they fiddle with it in the future */
|
||||
ffmpeg_data->totalSamples = sample_count;
|
||||
|
||||
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
|
||||
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, encoder_delay);
|
||||
|
||||
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
|
||||
if (is_at3) {
|
||||
ffmpeg_data->invert_audio_set = 1;
|
||||
}
|
||||
|
||||
return ffmpeg_data;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* init ATRAC3/plus while adding some fixes */
|
||||
ffmpeg_codec_data * init_ffmpeg_atrac3_riff(STREAMFILE *sf, off_t offset, int* out_samples) {
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
int is_at3 = 0, is_at3p = 0, codec;
|
||||
size_t riff_size;
|
||||
int fact_samples, skip_samples, implicit_skip;
|
||||
off_t fact_offset = 0;
|
||||
size_t fact_size = 0;
|
||||
|
||||
|
||||
/* some simplified checks just in case */
|
||||
if (read_32bitBE(offset + 0x00,sf) != 0x52494646) /* "RIFF" */
|
||||
goto fail;
|
||||
|
||||
riff_size = read_32bitLE(offset + 0x04,sf) + 0x08;
|
||||
codec = (uint16_t)read_16bitLE(offset + 0x14, sf);
|
||||
switch(codec) {
|
||||
case 0x0270: is_at3 = 1; break;
|
||||
case 0xFFFE: is_at3p = 1; break;
|
||||
default: goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* init ffmpeg + apply fixes to FFmpeg decoding (with these fixes should be
|
||||
* sample-accurate vs official tools, except usual +-1 float-to-pcm conversion) */
|
||||
ffmpeg_data = init_ffmpeg_offset(sf, offset, riff_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
|
||||
|
||||
/* well behaved .at3 define "fact" but official tools accept files without it */
|
||||
if (find_chunk_le(sf,0x66616374,offset + 0x0c,0, &fact_offset, &fact_size)) { /* "fact" */
|
||||
if (fact_size == 0x08) { /* early AT3 (mainly PSP games) */
|
||||
fact_samples = read_32bitLE(fact_offset + 0x00, sf);
|
||||
skip_samples = read_32bitLE(fact_offset + 0x04, sf); /* base skip samples */
|
||||
}
|
||||
else if (fact_size == 0x0c) { /* late AT3 (mainly PS3 games and few PSP games) */
|
||||
fact_samples = read_32bitLE(fact_offset + 0x00, sf);
|
||||
/* 0x04: base skip samples, ignored by decoder */
|
||||
skip_samples = read_32bitLE(fact_offset + 0x08, sf); /* skip samples with implicit skip of 184 added */
|
||||
}
|
||||
else {
|
||||
VGM_LOG("ATRAC3: unknown fact size\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fact_samples = 0; /* tools output 0 samples in this case unless loop end is defined */
|
||||
if (is_at3)
|
||||
skip_samples = 1024; /* 1 frame */
|
||||
else if (is_at3p)
|
||||
skip_samples = 2048; /* 1 frame */
|
||||
else
|
||||
skip_samples = 0;
|
||||
}
|
||||
|
||||
/* implicit skip: official tools skip this even with encoder delay forced to 0. Maybe FFmpeg decodes late,
|
||||
* but when forcing tools to decode all frame samples it always ends a bit before last frame, so maybe it's
|
||||
* really an internal skip, since encoder adds extra frames so fact num_samples + encoder delay + implicit skip
|
||||
* never goes past file. Same for all bitrate/channels, not added to loops. */
|
||||
if (is_at3) {
|
||||
implicit_skip = 69;
|
||||
}
|
||||
else if (is_at3p && fact_size == 0x08) {
|
||||
implicit_skip = 184*2;
|
||||
}
|
||||
else if (is_at3p && fact_size == 0x0c) {
|
||||
implicit_skip = 184; /* first 184 is already added to delay vs field at 0x08 */
|
||||
}
|
||||
else if (is_at3p) {
|
||||
implicit_skip = 184; /* default for unknown sizes */
|
||||
}
|
||||
else {
|
||||
implicit_skip = 0;
|
||||
}
|
||||
|
||||
/* FFmpeg reads this but just in case they fiddle with it in the future */
|
||||
ffmpeg_data->totalSamples = fact_samples;
|
||||
|
||||
/* encoder delay: encoder introduces some garbage (not always silent) samples to skip at the beginning (at least 1 frame)
|
||||
* FFmpeg doesn't set this, and even if it ever does it's probably better to force it for the implicit skip. */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, skip_samples + implicit_skip);
|
||||
|
||||
/* invert ATRAC3: waveform is inverted vs official tools (not noticeable but for accuracy) */
|
||||
if (is_at3) {
|
||||
ffmpeg_data->invert_audio_set = 1;
|
||||
}
|
||||
|
||||
/* multichannel fix: LFE channel should be reordered on decode (ATRAC3Plus only, only 1/2/6/8ch exist):
|
||||
* - 6ch: FL FR FC BL BR LFE > FL FR FC LFE BL BR
|
||||
* - 8ch: FL FR FC BL BR SL SR LFE > FL FR FC LFE BL BR SL SR */
|
||||
if (is_at3p && ffmpeg_data->channels == 6) {
|
||||
/* LFE BR BL > LFE BL BR > same */
|
||||
int channel_remap[] = { 0, 1, 2, 5, 5, 5, };
|
||||
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
|
||||
}
|
||||
else if (is_at3p && ffmpeg_data->channels == 8) {
|
||||
/* LFE BR SL SR BL > LFE BL SL SR BR > LFE BL BR SR SL > LFE BL BR SL SR > same */
|
||||
int channel_remap[] = { 0, 1, 2, 7, 7, 7, 7, 7};
|
||||
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
|
||||
}
|
||||
|
||||
|
||||
if (out_samples)
|
||||
*out_samples = fact_samples;
|
||||
|
||||
return ffmpeg_data;
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
@ -29,19 +29,19 @@
|
||||
typedef struct {
|
||||
/* EALayer3 v1 header */
|
||||
uint32_t v1_pcm_flag;
|
||||
uint32_t v1_pcm_decode_discard;
|
||||
uint32_t v1_pcm_number;
|
||||
uint32_t v1_offset_samples;
|
||||
uint32_t v1_pcm_samples;
|
||||
uint32_t v1_pcm_unknown;
|
||||
|
||||
/* EALayer3 v2 header */
|
||||
uint32_t v2_extended_flag;
|
||||
uint32_t v2_stereo_flag;
|
||||
uint32_t v2_unknown; /* unused? */
|
||||
uint32_t v2_reserved;
|
||||
uint32_t v2_frame_size; /* full size including headers and pcm block */
|
||||
uint32_t v2_mode; /* discard mode */
|
||||
uint32_t v2_mode_value; /* samples to use depending on mode */
|
||||
uint32_t v2_pcm_number;
|
||||
uint32_t v2_common_size; /* common header+data size; can be zero */
|
||||
uint32_t v2_offset_mode; /* discard mode */
|
||||
uint32_t v2_offset_samples; /* use depends on mode */
|
||||
uint32_t v2_pcm_samples;
|
||||
uint32_t v2_common_size; /* granule size: common header+data size; can be zero */
|
||||
|
||||
/* EALayer3 common header + side info */
|
||||
uint32_t version_index;
|
||||
@ -275,11 +275,11 @@ static int ealayer3_parse_frame_v1(vgm_bitstream *is, ealayer3_frame_info * eaf,
|
||||
|
||||
/* check PCM block */
|
||||
if (eaf->v1_pcm_flag == 0xEE) {
|
||||
r_bits(is, 16,&eaf->v1_pcm_decode_discard); /* samples to discard of the next decoded (not PCM block) samples */
|
||||
r_bits(is, 16,&eaf->v1_pcm_number); /* number of PCM samples, can be 0 */
|
||||
r_bits(is, 16,&eaf->v1_offset_samples); /* samples to discard of the next decoded (not PCM block) samples */
|
||||
r_bits(is, 16,&eaf->v1_pcm_samples); /* number of PCM samples, can be 0 */
|
||||
|
||||
eaf->pre_size += 2+2; /* 16b+16b */
|
||||
eaf->pcm_size = (2*eaf->v1_pcm_number * channels_per_frame);
|
||||
eaf->pcm_size = (2*eaf->v1_pcm_samples * channels_per_frame);
|
||||
|
||||
if (is_v1b) { /* extra 32b in v1b */
|
||||
r_bits(is, 32,&eaf->v1_pcm_unknown);
|
||||
@ -303,15 +303,15 @@ static int ealayer3_parse_frame_v2(vgm_bitstream *is, ealayer3_frame_info * eaf)
|
||||
/* read EA-frame V2 header */
|
||||
r_bits(is, 1,&eaf->v2_extended_flag);
|
||||
r_bits(is, 1,&eaf->v2_stereo_flag);
|
||||
r_bits(is, 2,&eaf->v2_unknown);
|
||||
r_bits(is, 2,&eaf->v2_reserved);
|
||||
r_bits(is, 12,&eaf->v2_frame_size);
|
||||
|
||||
eaf->pre_size = 2; /* 16b */
|
||||
|
||||
if (eaf->v2_extended_flag) {
|
||||
r_bits(is, 2,&eaf->v2_mode);
|
||||
r_bits(is, 10,&eaf->v2_mode_value);
|
||||
r_bits(is, 10,&eaf->v2_pcm_number);
|
||||
r_bits(is, 2,&eaf->v2_offset_mode);
|
||||
r_bits(is, 10,&eaf->v2_offset_samples);
|
||||
r_bits(is, 10,&eaf->v2_pcm_samples);
|
||||
r_bits(is, 10,&eaf->v2_common_size);
|
||||
|
||||
eaf->pre_size += 4; /* 32b */
|
||||
@ -323,10 +323,10 @@ static int ealayer3_parse_frame_v2(vgm_bitstream *is, ealayer3_frame_info * eaf)
|
||||
if (!ok) goto fail;
|
||||
}
|
||||
VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_common_size == 0, "EA EAL3: v2 empty frame\n"); /* seen in V2S */
|
||||
VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_mode_value > 0, "EA EAL3: v2_mode=%x with value=0x%x\n", eaf->v2_mode, eaf->v2_mode_value);
|
||||
//VGM_ASSERT(eaf->v2_pcm_number > 0, "EA EAL3: v2_pcm_number 0x%x\n", eaf->v2_pcm_number);
|
||||
VGM_ASSERT(eaf->v2_extended_flag && eaf->v2_offset_samples > 0, "EA EAL3: v2_offset_mode=%x with value=0x%x\n", eaf->v2_offset_mode, eaf->v2_offset_samples);
|
||||
//VGM_ASSERT(eaf->v2_pcm_samples > 0, "EA EAL3: v2_pcm_samples 0x%x\n", eaf->v2_pcm_samples);
|
||||
|
||||
eaf->pcm_size = (2*eaf->v2_pcm_number * eaf->channels);
|
||||
eaf->pcm_size = (2*eaf->v2_pcm_samples * eaf->channels);
|
||||
|
||||
eaf->eaframe_size = eaf->pre_size + eaf->common_size + eaf->pcm_size;
|
||||
|
||||
@ -614,43 +614,44 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (eaf->v1_pcm_number && !eaf->pcm_size) {
|
||||
VGM_LOG("MPEG EAL3: pcm size without pcm number\n");
|
||||
goto fail; //todo ??? first block?
|
||||
if (eaf->v1_pcm_samples && !eaf->pcm_size) {
|
||||
VGM_LOG("MPEG EAL3: pcm_size without pcm_samples\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (eaf->v1_pcm_number) {
|
||||
if (eaf->v1_pcm_samples || eaf->v1_offset_samples) {
|
||||
uint8_t* outbuf = ms->output_buffer + bytes_filled;
|
||||
off_t pcm_offset = stream->offset + eaf->pre_size + eaf->common_size;
|
||||
|
||||
VGM_ASSERT(eaf->v1_pcm_decode_discard > 576, "MPEG EAL3: big discard %i at 0x%x\n", eaf->v1_pcm_decode_discard, (uint32_t)stream->offset);
|
||||
VGM_ASSERT(eaf->v1_pcm_number > 0x100, "MPEG EAL3: big samples %i at 0x%x\n", eaf->v1_pcm_number, (uint32_t)stream->offset);
|
||||
VGM_ASSERT(eaf->v1_offset_samples > 576, "MPEG EAL3: big discard %i at 0x%x\n", eaf->v1_offset_samples, (uint32_t)stream->offset);
|
||||
VGM_ASSERT(eaf->v1_pcm_samples > 0x100, "MPEG EAL3: big samples %i at 0x%x\n", eaf->v1_pcm_samples, (uint32_t)stream->offset);
|
||||
VGM_ASSERT(eaf->v1_offset_samples > 0 && eaf->v1_pcm_samples == 0, "EAL3: offset_samples without pcm_samples\n"); /* not seen but could work */
|
||||
|
||||
//;VGM_LOG("EA EAL3 v1: off=%lx, discard=%x, pcm=%i, pcm_o=%lx\n",
|
||||
// stream->offset, eaf->v1_pcm_decode_discard, eaf->v1_pcm_number, pcm_offset);
|
||||
// stream->offset, eaf->v1_offset_samples, eaf->v1_pcm_samples, pcm_offset);
|
||||
|
||||
/* V1 usually discards + copies samples at the same time
|
||||
* V1b PCM block is interleaved/'planar' format (ex. NFS:U PS3) */
|
||||
ealayer3_copy_pcm_block(outbuf, pcm_offset, eaf->v1_pcm_number, channels_per_frame, (data->type == MPEG_EAL31), stream->streamfile);
|
||||
ms->samples_filled += eaf->v1_pcm_number;
|
||||
ealayer3_copy_pcm_block(outbuf, pcm_offset, eaf->v1_pcm_samples, channels_per_frame, (data->type == MPEG_EAL31), stream->streamfile);
|
||||
ms->samples_filled += eaf->v1_pcm_samples;
|
||||
|
||||
/* skip decoded samples as PCM block 'overwrites' them w/ special meanings */
|
||||
{
|
||||
size_t decode_to_discard = eaf->v1_pcm_decode_discard;
|
||||
size_t decode_to_discard = eaf->v1_offset_samples;
|
||||
|
||||
if (data->type == MPEG_EAL31) {
|
||||
//todo should also discard v1_pcm_number, but block layout samples may be exhausted
|
||||
//todo should also discard v1_pcm_samples, but block layout samples may be exhausted
|
||||
// and won't move (maybe new block if offset = new offset detected)
|
||||
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_samples;
|
||||
}
|
||||
else {
|
||||
//todo maybe should be (576 or samples_per_frame - decode_to_discard) but V1b doesn't seem to set discard
|
||||
VGM_ASSERT(decode_to_discard > 0, "EAL3: found offset_samples in V1b\n");
|
||||
/* probably (576 or samples_per_frame - eaf->v1_offset_samples) but V1b seems to always use 0 and ~47 samples */
|
||||
if (decode_to_discard == 0) /* seems ok (ex. comparing NFS:UC PS3 vs PC gets correct waveform this way) */
|
||||
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number; /* musn't discard pcm_number */
|
||||
else if (decode_to_discard == 576) //todo unsure
|
||||
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_number;
|
||||
decode_to_discard = data->samples_per_frame;//+ eaf->v1_pcm_samples; /* musn't discard pcm_number */
|
||||
}
|
||||
|
||||
ms->decode_to_discard += decode_to_discard;
|
||||
}
|
||||
}
|
||||
@ -658,37 +659,56 @@ static int ealayer3_write_pcm_block(VGMSTREAMCHANNEL *stream, mpeg_codec_data *d
|
||||
if (eaf->v2_extended_flag) {
|
||||
uint8_t* outbuf = ms->output_buffer + bytes_filled;
|
||||
off_t pcm_offset = stream->offset + eaf->pre_size + eaf->common_size;
|
||||
size_t usable_samples, decode_to_discard;
|
||||
|
||||
/* V2P usually only copies big PCM, while V2S discards then copies few samples (similar to V1b).
|
||||
* Unlike V1b, both modes seem to use 'packed' PCM block */
|
||||
ealayer3_copy_pcm_block(outbuf, pcm_offset, eaf->v2_pcm_number, channels_per_frame, 1, stream->streamfile);
|
||||
ms->samples_filled += eaf->v2_pcm_number;
|
||||
ealayer3_copy_pcm_block(outbuf, pcm_offset, eaf->v2_pcm_samples, channels_per_frame, 1, stream->streamfile);
|
||||
ms->samples_filled += eaf->v2_pcm_samples;
|
||||
|
||||
//;VGM_LOG("EA EAL3 v2: off=%lx, mode=%x, value=%i, pcm=%i, c-size=%x, pcm_o=%lx\n",
|
||||
// stream->offset, eaf->v2_mode, eaf->v2_mode_value, eaf->v2_pcm_number, eaf->v2_common_size, pcm_offset);
|
||||
// stream->offset, eaf->v2_offset_mode, eaf->v2_offset_samples, eaf->v2_pcm_samples, eaf->v2_common_size, pcm_offset);
|
||||
|
||||
/* modify decoded samples depending on flag (looks correct in V2P loops, ex. NFS:W) */
|
||||
if (eaf->v2_mode == 0x00) {
|
||||
size_t decode_to_discard = eaf->v2_mode_value; /* (usually 0 in V2P, varies in V2S) */
|
||||
decode_to_discard = 576 - decode_to_discard;
|
||||
//todo improve how discarding works since there could exists a subtle-but-unlikely PCM+granule usage
|
||||
//todo test other modes (only seen IGNORE)
|
||||
|
||||
ms->decode_to_discard += decode_to_discard;
|
||||
/* get how many samples we can use in this granule + pcm block (thus how many we can't) */
|
||||
if (eaf->v2_offset_mode == 0x00) { /* IGNORE (looks correct in V2P loops, ex. NFS:W) */
|
||||
/* offset_samples is usually 0 in V2P (no discard), varies in V2S and may be 576 (full discard).
|
||||
* If block has pcm_samples then usable_samples will be at least that value (for all known files),
|
||||
* and is assumed PCM isn't discarded so only discards the decoded granule. */
|
||||
usable_samples = 576 - eaf->v2_offset_samples;
|
||||
if (eaf->common_size == 0)
|
||||
usable_samples = eaf->v2_pcm_samples;
|
||||
|
||||
if (usable_samples == eaf->v2_pcm_samples) {
|
||||
decode_to_discard = 576;
|
||||
}
|
||||
else {
|
||||
VGM_LOG("EAL3: unknown discard\n");
|
||||
decode_to_discard = 0;
|
||||
}
|
||||
}
|
||||
else if (eaf->v2_offset_mode == 0x01) { /* PRESERVE */
|
||||
usable_samples = 576;
|
||||
if (eaf->common_size == 0)
|
||||
usable_samples = eaf->v2_pcm_samples;
|
||||
decode_to_discard = 0; /* all preserved */
|
||||
}
|
||||
else if (eaf->v2_offset_mode == 0x02) { /* MUTE */
|
||||
usable_samples = 576;
|
||||
if (eaf->common_size == 0)
|
||||
usable_samples = eaf->v2_pcm_samples * 2; // why 2?
|
||||
decode_to_discard = 0; /* not discarded but muted */
|
||||
//mute_samples = eaf->v2_offset_samples; //todo must 0 first N decoded samples
|
||||
}
|
||||
else {
|
||||
VGM_LOG("EAL3: unknown mode\n"); /* not defined */
|
||||
usable_samples = 576;
|
||||
decode_to_discard = 0;
|
||||
}
|
||||
|
||||
/* todo supposed skip modes (only seen 0x00):
|
||||
*
|
||||
* AB00CCCC CCCCCCCC if A is set: DDEEEEEE EEEEFFFF FFFFFFGG GGGGGGGG
|
||||
* D = BLOCKOFFSETMODE: IGNORE = 0x0, PRESERVE = 0x1, MUTE = 0x2, MAX = 0x3
|
||||
* E = samples to discard (mode == 0) or skip (mode == 1 or 2) before outputting the uncompressed samples
|
||||
* (when mode == 3 this is ignored)
|
||||
* F = number of uncompressed sample frames (pcm block)
|
||||
* G = MPEG granule size (can be zero)
|
||||
*
|
||||
* if 0: 576 - E if G == 0 then F
|
||||
* if 1: 576 if G == 0 then F
|
||||
* if 2: 576 if G == 0 then F * 2
|
||||
* if 3: 576
|
||||
*/
|
||||
ms->decode_to_discard += decode_to_discard;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
@ -203,13 +203,23 @@ fail:
|
||||
}
|
||||
|
||||
void free_layout_segmented(segmented_layout_data *data) {
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
if (data->segments) {
|
||||
for (i = 0; i < data->segment_count; i++) {
|
||||
int is_repeat = 0;
|
||||
|
||||
/* segments are allowed to be repeated so don't close the same thing twice */
|
||||
for (j = 0; j < i; j++) {
|
||||
if (data->segments[i] == data->segments[j])
|
||||
is_repeat = 1;
|
||||
}
|
||||
if (is_repeat)
|
||||
continue;
|
||||
|
||||
close_vgmstream(data->segments[i]);
|
||||
}
|
||||
free(data->segments);
|
||||
|
@ -1919,7 +1919,7 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\coding\ffmpeg_decoder_utils_ea_schl.c"
|
||||
RelativePath=".\coding\ffmpeg_decoder_utils.c"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
|
@ -144,6 +144,7 @@
|
||||
<ClCompile Include="coding\circus_decoder.c" />
|
||||
<ClCompile Include="coding\coding_utils.c" />
|
||||
<ClCompile Include="coding\ffmpeg_decoder.c" />
|
||||
<ClCompile Include="coding\ffmpeg_decoder_utils.c" />
|
||||
<ClCompile Include="coding\ffmpeg_decoder_custom_opus.c" />
|
||||
<ClCompile Include="coding\lsf_decoder.c" />
|
||||
<ClCompile Include="coding\mp4_aac_decoder.c" />
|
||||
|
@ -1558,6 +1558,9 @@
|
||||
<ClCompile Include="coding\ffmpeg_decoder.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\ffmpeg_decoder_utils.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="coding\ffmpeg_decoder_custom_opus.c">
|
||||
<Filter>coding\Source Files</Filter>
|
||||
</ClCompile>
|
||||
|
@ -256,14 +256,44 @@ static int find_adx_key(STREAMFILE *streamFile, uint8_t type, uint16_t *xor_star
|
||||
|
||||
/* try to find key in external file first */
|
||||
{
|
||||
uint8_t keybuf[6];
|
||||
uint8_t keybuf[0x20+1] = {0}; /* +1 extra null for keystrings */
|
||||
size_t key_size;
|
||||
|
||||
if (read_key_file(keybuf, 6, streamFile) == 6) {
|
||||
*xor_start = get_16bitBE(keybuf+0);
|
||||
*xor_mult = get_16bitBE(keybuf+2);
|
||||
*xor_add = get_16bitBE(keybuf+4);
|
||||
return 1;
|
||||
/* handle type8 keystrings, key9 keycodes and derived keys too */
|
||||
key_size = read_key_file(keybuf,0x20, streamFile);
|
||||
|
||||
if (key_size > 0) {
|
||||
int i, is_ascii = 0;
|
||||
|
||||
/* keystrings should be ASCII, also needed to tell apart 0x06 strings from derived keys */
|
||||
if (type == 8) {
|
||||
is_ascii = 1;
|
||||
for (i = 0; i < key_size; i++) {
|
||||
if (keybuf[i] < 0x20 || keybuf[i] > 0x7f) {
|
||||
is_ascii = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (key_size == 0x06 && !is_ascii) {
|
||||
*xor_start = get_16bitBE(keybuf + 0x00);
|
||||
*xor_mult = get_16bitBE(keybuf + 0x02);
|
||||
*xor_add = get_16bitBE(keybuf + 0x04);
|
||||
return 1;
|
||||
}
|
||||
else if (type == 8 && is_ascii) {
|
||||
const char * keystring = (const char *)keybuf;
|
||||
derive_adx_key8(keystring, xor_start, xor_mult, xor_add);
|
||||
return 1;
|
||||
}
|
||||
else if (type == 9 && key_size == 0x08) {
|
||||
uint64_t keycode = (uint64_t)get_64bitBE(keybuf);
|
||||
derive_adx_key9(keycode, xor_start, xor_mult, xor_add);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* no key set or unknown format, try list */
|
||||
}
|
||||
|
||||
/* setup totals */
|
||||
|
@ -10,187 +10,180 @@ typedef struct {
|
||||
|
||||
/**
|
||||
* List of known keys, cracked from the sound files.
|
||||
* Keystrings (type 8) and keycodes (type 9) from VGAudio / game's executables / 2ch.net.
|
||||
* Keystrings (type 8) and keycodes (type 9) from executables / VGAudio / game's executables / 2ch.net.
|
||||
* Multiple keys may work for a game due to how they are derived.
|
||||
* start/mult/add are optional (0,0,0) if key8/9 are provided, but take priority if given.
|
||||
*/
|
||||
static const adxkey_info adxkey8_list[] = {
|
||||
|
||||
/* Clover Studio (GOD HAND, Okami) */
|
||||
/* GOD HAND (PS2), Okami (PS2) [Clover Studio] */
|
||||
{0x49e1,0x4a57,0x553d, "karaage",0},
|
||||
|
||||
/* Grasshopper Manufacture 0 (Blood+) */
|
||||
{0x5f5d,0x58bd,0x55ed, NULL,0}, // estimated (keystring not in ELF?)
|
||||
/* Blood+ (PS2) [Grasshopper Manufacture] */
|
||||
{0x5f5d,0x58bd,0x55ed, NULL,0}, // keystring not in ELF?
|
||||
|
||||
/* Grasshopper Manufacture 1 (Killer7) */
|
||||
/* Killer7 (PS2) [Grasshopper Manufacture] */
|
||||
{0x50fb,0x5803,0x5701, "GHM",0},
|
||||
|
||||
/* Grasshopper Manufacture 2 (Samurai Champloo) */
|
||||
/* Samurai Champloo (PS2) [Grasshopper Manufacture] */
|
||||
{0x4f3f,0x472f,0x562f, "GHMSC",0},
|
||||
|
||||
/* Moss Ltd (Raiden III) */
|
||||
/* Raiden III (PS2) [Moss] */
|
||||
{0x66f5,0x58bd,0x4459, "(C)2005 MOSS LTD. BMW Z4",0},
|
||||
|
||||
/* Sonic Team 0 (Phantasy Star Universe) */
|
||||
/* Phantasy Star Universe (PC), Phantasy Star Universe: Ambition of the Illuminus (PS2) [Sonic Team] */
|
||||
{0x5deb,0x5f27,0x673f, "3x5k62bg9ptbwy",0},
|
||||
|
||||
/* G.rev 0 (Senko no Ronde) */
|
||||
/* Senko no Ronde [G.rev] */
|
||||
{0x46d3,0x5ced,0x474d, "ranatus",0},
|
||||
|
||||
/* Sonic Team 1 (NiGHTS: Journey of Dreams) */
|
||||
/* NiGHTS: Journey of Dreams (Wii) [Sonic Team] */
|
||||
{0x440b,0x6539,0x5723, "sakakit4649",0},
|
||||
|
||||
/* unknown source */
|
||||
{0x586d,0x5d65,0x63eb, NULL,0}, // from guessadx (unique?)
|
||||
|
||||
/* Navel (Shuffle! On the Stage (PS2)) */
|
||||
/* Shuffle! On the Stage (PS2) [Navel] */
|
||||
{0x4969,0x5deb,0x467f, "SHUF",0},
|
||||
|
||||
/* Success (Aoishiro (PS2)) */
|
||||
/* Aoishiro (PS2) [Success] */
|
||||
{0x4d65,0x5eb7,0x5dfd, "wakasugi",0},
|
||||
|
||||
/* Sonic Team 2 (Sonic and the Black Knight) */
|
||||
/* Sonic and the Black Knight (Wii) [Sonic Team] */
|
||||
{0x55b7,0x6191,0x5a77, "morio",0},
|
||||
|
||||
/* Enterbrain (Amagami) */
|
||||
/* Amagami (PS2) [Enterbrain] */
|
||||
{0x5a17,0x509f,0x5bfd, "mituba",0}, /* also AHX key */
|
||||
|
||||
/* Yamasa (Yamasa Digi Portable: Matsuri no Tatsujin) */
|
||||
{0x4c01,0x549d,0x676f, NULL,0}, // confirmed unique with guessadx
|
||||
/* Yamasa Digi Portable: Matsuri no Tatsujin (PSP) [Yamasa] */
|
||||
{0x4c01,0x549d,0x676f, "7fa0xB9tw3",0},
|
||||
|
||||
/* Kadokawa Shoten (Fragments Blue) */
|
||||
{0x5803,0x4555,0x47bf, NULL,0}, // confirmed unique with guessadx
|
||||
/* Fragments Blue (PS2) [Kadokawa Shoten] */
|
||||
{0x5803,0x4555,0x47bf, "PIETA",0},
|
||||
|
||||
/* Namco (Soulcalibur IV) */
|
||||
{0x59ed,0x4679,0x46c9, NULL,0}, // confirmed unique with guessadx
|
||||
/* Soulcalibur IV (PS3) [Namco] */
|
||||
{0x59ed,0x4679,0x46c9, "SC4Test",0},
|
||||
|
||||
/* G.rev 1 (Senko no Ronde DUO) */
|
||||
/* Senko no Ronde DUO (X360) [G.rev] */
|
||||
{0x6157,0x6809,0x4045, NULL,0}, // from guessadx
|
||||
|
||||
/* ASCII Media Works 0 (Nogizaka Haruka no Himitsu: Cosplay Hajimemashita) */
|
||||
{0x45af,0x5f27,0x52b1, NULL,0}, // 2nd from guessadx, other was {0x45ad,0x5f27,0x10fd}
|
||||
/* Nogizaka Haruka no Himitsu: Cosplay Hajimemashita (PS2) [Vridge] */
|
||||
{0x45af,0x5f27,0x52b1, "SKFHSIA",0},
|
||||
|
||||
/* D3 Publisher 0 (Little Anchor) */
|
||||
/* Little Anchor (PS2) [D3 Publisher] */
|
||||
{0x5f65,0x5b3d,0x5f65, NULL,0}, // confirmed unique with guessadx
|
||||
|
||||
/* Marvelous 0 (Hanayoi Romanesque: Ai to Kanashimi) */
|
||||
/* Hanayoi Romanesque: Ai to Kanashimi (PS2) [Marvelous] */
|
||||
{0x5563,0x5047,0x43ed, NULL,0}, // 2nd from guessadx, other was {0x5562,0x5047,0x1433}
|
||||
|
||||
/* Capcom (Mobile Suit Gundam: Gundam vs. Gundam NEXT PLUS) */
|
||||
/* Mobile Suit Gundam: Gundam vs. Gundam NEXT PLUS (PSP) [Capcom] */
|
||||
{0x4f7b,0x4fdb,0x5cbf, "CS-GGNX+",0},
|
||||
|
||||
/* Developer: Bridge NetShop
|
||||
* Publisher: Kadokawa Shoten (Shoukan Shoujo: Elemental Girl Calling) */
|
||||
{0x4f7b,0x5071,0x4c61, NULL,0}, // confirmed unique with guessadx
|
||||
/* Shoukan Shoujo: Elemental Girl Calling (PS2) [Bridge NetShop] */
|
||||
{0x4f7b,0x5071,0x4c61, "ELEMENGAL",0},
|
||||
|
||||
/* Developer: Net Corporation
|
||||
* Publisher: Tecmo (Rakushou! Pachi-Slot Sengen 6: Rio 2 Cruising Vanadis) */
|
||||
/* Rakushou! Pachi-Slot Sengen 6: Rio 2 Cruising Vanadis (PS2) [Net Corporation] */
|
||||
{0x53e9,0x586d,0x4eaf, NULL,0}, // confirmed unique with guessadx
|
||||
|
||||
/* Developer: Aquaplus
|
||||
* Tears to Tiara Gaiden Avalon no Kagi (PS3) */
|
||||
/* Tears to Tiara Gaiden Avalon no Nazo (PS3) [Aquaplus] */
|
||||
{0x47e1,0x60e9,0x51c1, NULL,0}, // confirmed unique with guessadx
|
||||
|
||||
/* Developer: Broccoli
|
||||
* Neon Genesis Evangelion: Koutetsu no Girlfriend 2nd (PS2) */
|
||||
{0x481d,0x4f25,0x5243, NULL,0}, // confirmed unique with guessadx
|
||||
/* Neon Genesis Evangelion: Koutetsu no Girlfriend 2nd (PS2) [Broccoli] */
|
||||
{0x481d,0x4f25,0x5243, "eva2",0},
|
||||
|
||||
/* Developer: Marvelous
|
||||
* Futakoi Alternative (PS2) */
|
||||
{0x413b,0x543b,0x57d1, NULL,0}, // confirmed unique with guessadx
|
||||
/* Futakoi Alternative (PS2) [Marvelous] */
|
||||
{0x413b,0x543b,0x57d1, "LOVLOV",0},
|
||||
|
||||
/* Developer: Marvelous
|
||||
* Gakuen Utopia - Manabi Straight! KiraKira Happy Festa! (PS2) */
|
||||
/* Gakuen Utopia: Manabi Straight! KiraKira Happy Festa! (PS2) [Marvelous] */
|
||||
{0x440b,0x4327,0x564b, "MANABIST",0},
|
||||
|
||||
/* Developer: Datam Polystar
|
||||
* Soshite Kono Uchuu ni Kirameku Kimi no Shi XXX (PS2) */
|
||||
{0x5f5d,0x552b,0x5507, NULL,0}, // confirmed unique with guessadx
|
||||
/* Soshite Kono Uchuu ni Kirameku Kimi no Shi XXX (PS2) [Datam Polystar] */
|
||||
{0x5f5d,0x552b,0x5507, "DATAM-KK2",0},
|
||||
|
||||
/* Developer: Sega
|
||||
* Sakura Taisen: Atsuki Chishio Ni (PS2) */
|
||||
/* Sakura Taisen: Atsuki Chishio Ni (PS2) [Sega] */
|
||||
{0x645d,0x6011,0x5c29, NULL,0}, // confirmed unique with guessadx
|
||||
|
||||
/* Developer: Sega
|
||||
* Sakura Taisen 3 ~Paris wa Moeteiru ka~ (PS2) */
|
||||
/* Sakura Taisen 3 ~Paris wa Moeteiru ka~ (PS2) [Sega] */
|
||||
{0x62ad,0x4b13,0x5957, NULL,0}, // confirmed unique with guessadx
|
||||
|
||||
/* Developer: Jinx
|
||||
* Sotsugyou 2nd Generation (PS2) */
|
||||
/* Sotsugyou 2nd Generation (PS2) [Jinx] */
|
||||
{0x6305,0x509f,0x4c01, NULL,0}, // First guess from guessadx, other was {0x6307,0x509f,0x2ac5}
|
||||
|
||||
/* La Corda d'Oro (2005)(-)(Koei)[PSP] */
|
||||
{0x55b7,0x67e5,0x5387, NULL,0}, // confirmed unique with guessadx
|
||||
/* La Corda d'Oro (PSP) [Koei] */
|
||||
{0x55b7,0x67e5,0x5387, NULL,0}, // keystring not in ELF?
|
||||
|
||||
/* Nanatsuiro * Drops Pure!! (2007)(Media Works)[PS2] */
|
||||
/* Nanatsuiro * Drops Pure!! (PS2) [Media Works] */
|
||||
{0x6731,0x645d,0x566b, NULL,0}, // confirmed unique with guessadx
|
||||
|
||||
/* Shakugan no Shana (2006)(Vridge)(Media Works)[PS2] */
|
||||
/* Shakugan no Shana (PS2) [Vridge] */
|
||||
{0x5fc5,0x63d9,0x599f, "FUZETSU",0},
|
||||
|
||||
/* Uragiri wa Boku no Namae o Shitteiru (2010)(Kadokawa Shoten)[PS2] */
|
||||
/* Uragiri wa Boku no Namae o Shitteiru (PS2) [Kadokawa Shoten] */
|
||||
{0x4c73,0x4d8d,0x5827, NULL,0}, // confirmed unique with guessadx
|
||||
|
||||
/* StormLover Kai!! (2012)(D3 Publisher)[PSP] */
|
||||
{0x5a11,0x67e5,0x6751, NULL,0}, // confirmed unique with guessadx
|
||||
/* StormLover!! (PSP), StormLover Kai!! (PSP) [Vridge] */
|
||||
{0x5a11,0x67e5,0x6751, "HEXDPFMDKPQW",0}, /* unknown AHX key */
|
||||
|
||||
/* Sora no Otoshimono - DokiDoki Summer Vacation (2010)(Kadokawa Shoten)[PSP] */
|
||||
{0x5e75,0x4a89,0x4c61, NULL,0}, // confirmed unique with guessadx
|
||||
/* Sora no Otoshimono: DokiDoki Summer Vacation (PSP) [Kadokawa Shoten] */
|
||||
{0x5e75,0x4a89,0x4c61, "funen-gomi",0},
|
||||
|
||||
/* Boku wa Koukuu Kanseikan - Airport Hero Naha (2006)(Sonic Powered)(Electronic Arts)[PSP] */
|
||||
{0x64ab,0x5297,0x632f, NULL,0}, // confirmed unique with guessadx
|
||||
/* Boku wa Koukuu Kanseikan: Airport Hero Naha (PSP) [Sonic Powered] */
|
||||
{0x64ab,0x5297,0x632f, "sonic",0},
|
||||
|
||||
/* Lucky Star - Net Idol Meister (2009)(Kadokawa Shoten)[PSP] */
|
||||
{0x4d82,0x5243,0x0685, NULL,0}, // confirmed unique with guessadx
|
||||
/* Lucky Star: Net Idol Meister (PSP) [Vridge, Kadokawa Shoten] */
|
||||
{0x4d81,0x5243,0x58c7, "JJOLIFJLE",0}, /* unknown AHX key */
|
||||
|
||||
/* Ishin Renka: Ryouma Gaiden (2010-11-25)(-)(D3 Publisher)[PSP] */
|
||||
{0x54d1,0x526d,0x5e8b, NULL,0}, // ?
|
||||
/* Ishin Renka: Ryouma Gaiden (PSP) [Vridge] */
|
||||
{0x54d1,0x526d,0x5e8b, "LQAFJOIEJ",0}, /* unknown AHX key */
|
||||
|
||||
/* Lucky Star - Ryouou Gakuen Outousai Portable (2010-12-22)(-)(Kadokawa Shoten)[PSP] */
|
||||
{0x4d06,0x663b,0x7d09, NULL,0}, // ?
|
||||
/* Lucky Star: Ryouou Gakuen Outousai Portable (PSP) [Vridge] */
|
||||
{0x4d05,0x663b,0x6343, "IUNOIRU",0}, /* unknown AHX key */
|
||||
|
||||
/* Marriage Royale - Prism Story (2010-04-28)(-)(ASCII Media Works)[PSP] */
|
||||
{0x40a9,0x46b1,0x62ad, NULL,0}, // ?
|
||||
/* Marriage Royale: Prism Story (PSP) [Vridge] */
|
||||
{0x40a9,0x46b1,0x62ad, "ROYMAR",0}, /* unknown AHX key */
|
||||
|
||||
/* Nogizaka Haruka no Himitsu - Doujinshi Hajime Mashita (2010-10-28)(-)(ASCII Media Works)[PSP] */
|
||||
{0x4601,0x671f,0x0455, NULL,0}, // ?
|
||||
/* Nogizaka Haruka no Himitsu: Doujinshi Hajimemashita (PSP) [Vridge] */
|
||||
{0x4609,0x671f,0x4b65, "CLKMEOUHFLIE",0}, /* unknown AHX key */
|
||||
|
||||
/* Slotter Mania P - Mach Go Go Go III (2011-01-06)(-)(Dorart)[PSP] */
|
||||
{0x41ef,0x463d,0x5507, NULL,0}, // ?
|
||||
/* Slotter Mania P: Mach Go Go Go III (PSP) [Dorart] */
|
||||
{0x41ef,0x463d,0x5507, "SGGK",0},
|
||||
|
||||
/* Nichijou - Uchuujin (2011-07-28)(-)(Kadokawa Shoten)[PSP] */
|
||||
{0x4369,0x486d,0x5461, NULL,0}, // ?
|
||||
/* Nichijou: Uchuujin (PSP) [Vridge] */
|
||||
{0x4369,0x486d,0x5461, "LJLOUHIU787",0}, /* unknown AHX key */
|
||||
|
||||
/* R-15 Portable (2011-10-27)(-)(Kadokawa Shoten)[PSP] */
|
||||
{0x6809,0x5fd5,0x5bb1, NULL,0}, // ?
|
||||
/* R-15 Portable (PSP) [Kadokawa Shoten] */
|
||||
{0x6809,0x5fd5,0x5bb1, "R-15(Heart)Love",0},
|
||||
|
||||
/* Suzumiya Haruhi-chan no Mahjong (2011-07-07)(-)(Kadokawa Shoten)[PSP] */
|
||||
{0x5c33,0x4133,0x4ce7, NULL,0}, // ?
|
||||
/* Suzumiya Haruhi-chan no Mahjong (PSP) [Kadokawa Shoten] */
|
||||
{0x5c33,0x4133,0x4ce7, "bi88a#fas",0},
|
||||
|
||||
/* Storm Lover Natsu Koi!! (2011-08-04)(Vridge)(D3 Publisher)[PSP] */
|
||||
{0x4133,0x5a01,0x5723, NULL,0}, // ?
|
||||
/* StormLover Natsu Koi!! (PSP) [Vridge] */
|
||||
{0x4133,0x5a01,0x5723, "LIKDFJUIDJOQ",0}, /* unknown AHX key */
|
||||
|
||||
/* Shounen Onmyouji: Tsubasa yo Ima, Sora e Kaere [PS2] */
|
||||
/* Shounen Onmyouji: Tsubasa yo Ima, Sora e Kaere (PS2) [Kadokawa Shoten] */
|
||||
{0x55d9,0x46d3,0x5b01, "SONMYOJI",0},
|
||||
|
||||
/* Girls Bravo: Romance 15's [PS2] */
|
||||
/* Girls Bravo: Romance 15's (PS2) [Kadokawa Shoten] */
|
||||
{0x658f,0x4a89,0x5213, "GBRAVO",0},
|
||||
|
||||
/* Kashimashi! Girl Meets Girl - Hajimete no Natsu Monogatari (PS2) */
|
||||
/* Kashimashi! Girl Meets Girl: Hajimete no Natsu Monogatari (PS2) [Vridge] */
|
||||
{0x6109,0x5135,0x673f, "KASHIM",0},
|
||||
|
||||
/* Bakumatsu Renka - Karyuu Kenshiden (PS2) */
|
||||
/* Bakumatsu Renka: Karyuu Kenshiden (PS2) [Vridge] */
|
||||
{0x4919,0x612d,0x4919, "RENRENKA22",0},
|
||||
|
||||
/* Tensei Hakkenshi - Fuumaroku (PS2) */
|
||||
/* Tensei Hakkenshi: Fuumaroku (PS2) [Vridge] */
|
||||
{0x5761,0x6283,0x4531, "HAKKEN",0},
|
||||
|
||||
/* Lucky Star - Ryouou Gakuen Outousai (PS2) */
|
||||
/* Lucky Star: Ryouou Gakuen Outousai (PS2) [Vridge] */
|
||||
{0x481D,0x44F9,0x4E35, "LSTARPS2",0},
|
||||
|
||||
/* Bakumatsu Renka: Shinsengumi (PS2) */
|
||||
/* Bakumatsu Renka: Shinsengumi (PS2) [Vridge] */
|
||||
{0x5381,0x5701,0x665B, "SHINN",0},
|
||||
|
||||
/* Gintama Gin-san to Issho! Boku no Kabukichou Nikki (PS2) [Bandai Namco?] */
|
||||
{0x67CD,0x5CA7,0x655F, "gt25809",0},
|
||||
|
||||
};
|
||||
|
||||
static const adxkey_info adxkey9_list[] = {
|
||||
@ -213,7 +206,7 @@ static const adxkey_info adxkey9_list[] = {
|
||||
/* Fallen Princess (iOS/Android) */
|
||||
{0x5e4b,0x190d,0x76bb, NULL,145552191146490718}, // 02051AF25990FB5E
|
||||
|
||||
/* Yuuki Yuuna wa Yuusha de aru - Hanayui no Kirameki / Yuyuyui (iOS/Android) */
|
||||
/* Yuuki Yuuna wa Yuusha de aru: Hanayui no Kirameki / Yuyuyui (iOS/Android) */
|
||||
{0x3f10,0x3651,0x6d31, NULL,4867249871962584729}, // 438BF1F883653699
|
||||
|
||||
/* Super Robot Wars X-Omega (iOS/Android) voices */
|
||||
|
@ -27,13 +27,13 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||
|
||||
codec = read_32bitLE(0x0c,streamFile);
|
||||
file_size = read_32bitLE(0x10,streamFile);
|
||||
/*file_id = read_32bitLE(0x14,streamFile);*/
|
||||
/* file_id = read_32bitLE(0x14,streamFile); */
|
||||
block_size = read_32bitLE(0x18,streamFile);
|
||||
loop_start = read_32bitLE(0x1c,streamFile);
|
||||
sample_rate = (read_32bitLE(0x20,streamFile) + read_32bitLE(0x24,streamFile)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */
|
||||
start_offset = read_32bitLE(0x28,streamFile);
|
||||
/*0x2c: unk (vol?) */
|
||||
/*0x2d: unk (0x10?) */
|
||||
/* 0x2c: unk (vol?) */
|
||||
/* 0x2d: unk (0x10?) */
|
||||
channel_count = read_8bit(0x2e,streamFile);
|
||||
block_align = (uint8_t)read_8bit(0x2f,streamFile);
|
||||
|
||||
@ -65,31 +65,26 @@ VGMSTREAM * init_vgmstream_bgw(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 3: { /* ATRAC3 (encrypted) */
|
||||
uint8_t buf[0x100];
|
||||
int bytes, joint_stereo, skip_samples;
|
||||
size_t data_size = file_size - start_offset;
|
||||
int encoder_delay, block_align;
|
||||
|
||||
vgmstream->num_samples = block_size; /* atrac3_bytes_to_samples gives the same value */
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */
|
||||
joint_stereo = 0;
|
||||
skip_samples = 0;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_align, joint_stereo, skip_samples);
|
||||
if (bytes <= 0) goto fail;
|
||||
encoder_delay = 1024*2 + 69*2; /* observed value, all files start at +2200 (PS-ADPCM also starts around 50-150 samples in) */
|
||||
block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */
|
||||
vgmstream->num_samples = block_size - encoder_delay; /* atrac3_bytes_to_samples gives block_size */
|
||||
|
||||
temp_streamFile = setup_bgw_atrac3_streamfile(streamFile, start_offset,data_size, 0xC0,channel_count);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0,data_size);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(temp_streamFile, 0x00,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start - encoder_delay;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
break;
|
||||
}
|
||||
@ -132,13 +127,13 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||
|
||||
file_size = read_32bitLE(0x08,streamFile);
|
||||
codec = read_32bitLE(0x0c,streamFile);
|
||||
/*file_id = read_32bitLE(0x10,streamFile);*/
|
||||
/* file_id = read_32bitLE(0x10,streamFile);*/
|
||||
block_size = read_32bitLE(0x14,streamFile);
|
||||
loop_start = read_32bitLE(0x18,streamFile);
|
||||
sample_rate = (read_32bitLE(0x1c,streamFile) + read_32bitLE(0x20,streamFile)) & 0x7FFFFFFF; /* bizarrely obfuscated sample rate */
|
||||
start_offset = read_32bitLE(0x24,streamFile);
|
||||
/*0x2c: unk (0x00?) */
|
||||
/*0x2d: unk (0x00/01?) */
|
||||
/* 0x2c: unk (0x00?) */
|
||||
/* 0x2d: unk (0x00/01?) */
|
||||
channel_count = read_8bit(0x2a,streamFile);
|
||||
/*0x2b: unk (0x01 when PCM, 0x10 when VAG?) */
|
||||
block_align = read_8bit(0x2c,streamFile);
|
||||
@ -184,31 +179,26 @@ VGMSTREAM * init_vgmstream_spw(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 3: { /* ATRAC3 (encrypted) */
|
||||
uint8_t buf[0x100];
|
||||
int bytes, joint_stereo, skip_samples;
|
||||
size_t data_size = file_size - start_offset;
|
||||
int encoder_delay, block_align;
|
||||
|
||||
vgmstream->num_samples = block_size; /* atrac3_bytes_to_samples gives the same value */
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */
|
||||
joint_stereo = 0;
|
||||
skip_samples = 0;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_align, joint_stereo, skip_samples);
|
||||
if (bytes <= 0) goto fail;
|
||||
encoder_delay = 1024*2 + 69*2; /* observed value, all files start at +2200 (PS-ADPCM also starts around 50-150 samples in) */
|
||||
block_align = 0xC0 * vgmstream->channels; /* 0x00 in header */
|
||||
vgmstream->num_samples = block_size - encoder_delay; /* atrac3_bytes_to_samples gives block_size */
|
||||
|
||||
temp_streamFile = setup_bgw_atrac3_streamfile(streamFile, start_offset,data_size, 0xC0,channel_count);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(temp_streamFile, buf,bytes, 0,data_size);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(temp_streamFile, 0x00,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start - encoder_delay;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
}
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
break;
|
||||
}
|
||||
|
@ -9,23 +9,24 @@
|
||||
#define EAAC_VERSION_V0 0x00 /* SNR/SNS */
|
||||
#define EAAC_VERSION_V1 0x01 /* SPS */
|
||||
|
||||
#define EAAC_CODEC_NONE 0x00 /* internal 'codec not set' */
|
||||
#define EAAC_CODEC_RESERVED 0x01 /* not used/reserved? /MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */
|
||||
#define EAAC_CODEC_PCM 0x02
|
||||
#define EAAC_CODEC_NONE 0x00 /* XAS v0? */
|
||||
#define EAAC_CODEC_RESERVED 0x01 /* EALAYER3 V1a? MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */
|
||||
#define EAAC_CODEC_PCM16BE 0x02
|
||||
#define EAAC_CODEC_EAXMA 0x03
|
||||
#define EAAC_CODEC_XAS 0x04
|
||||
#define EAAC_CODEC_XAS1 0x04
|
||||
#define EAAC_CODEC_EALAYER3_V1 0x05
|
||||
#define EAAC_CODEC_EALAYER3_V2_PCM 0x06
|
||||
#define EAAC_CODEC_EALAYER3_V2_SPIKE 0x07
|
||||
#define EAAC_CODEC_DSP 0x08
|
||||
#define EAAC_CODEC_GCADPCM 0x08
|
||||
#define EAAC_CODEC_EASPEEX 0x09
|
||||
#define EAAC_CODEC_EATRAX 0x0a
|
||||
#define EAAC_CODEC_EAMP3 0x0b
|
||||
#define EAAC_CODEC_EAOPUS 0x0c
|
||||
|
||||
#define EAAC_FLAG_NONE 0x00
|
||||
#define EAAC_FLAG_LOOPED 0x02
|
||||
#define EAAC_FLAG_STREAMED 0x04
|
||||
#define EAAC_TYPE_RAM 0x00
|
||||
#define EAAC_TYPE_STREAM 0x01
|
||||
|
||||
#define EAAC_LOOP_SET 0x01
|
||||
|
||||
#define EAAC_BLOCKID0_DATA 0x00
|
||||
#define EAAC_BLOCKID0_END 0x80 /* maybe meant to be a bitflag? */
|
||||
@ -839,7 +840,8 @@ typedef struct {
|
||||
int codec;
|
||||
int channel_config;
|
||||
int sample_rate;
|
||||
int flags;
|
||||
int type;
|
||||
int loop;
|
||||
|
||||
int streamed;
|
||||
int channels;
|
||||
@ -871,34 +873,45 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
/* EA SNR/SPH header */
|
||||
header1 = (uint32_t)read_32bitBE(header_offset + 0x00, streamHead);
|
||||
header2 = (uint32_t)read_32bitBE(header_offset + 0x04, streamHead);
|
||||
eaac.version = (header1 >> 28) & 0x0F; /* 4 bits */
|
||||
eaac.codec = (header1 >> 24) & 0x0F; /* 4 bits */
|
||||
eaac.version = (header1 >> 28) & 0x0F; /* 4 bits */
|
||||
eaac.codec = (header1 >> 24) & 0x0F; /* 4 bits */
|
||||
eaac.channel_config = (header1 >> 18) & 0x3F; /* 6 bits */
|
||||
eaac.sample_rate = (header1 & 0x03FFFF); /* 18 bits (some Dead Space 2 (PC) do use 96000) */
|
||||
eaac.flags = (header2 >> 28) & 0x0F; /* 4 bits *//* TODO: maybe even 3 bits and not 4? */
|
||||
eaac.num_samples = (header2 & 0x0FFFFFFF); /* 28 bits */
|
||||
eaac.sample_rate = (header1 >> 0) & 0x03FFFF; /* 18 bits */
|
||||
eaac.type = (header2 >> 30) & 0x03; /* 2 bits */
|
||||
eaac.loop = (header2 >> 29) & 0x01; /* 1 bits */
|
||||
eaac.num_samples = (header2 >> 0) & 0x1FFFFFFF; /* 29 bits */
|
||||
/* rest is optional, depends on used flags and codec (handled below) */
|
||||
eaac.stream_offset = start_offset;
|
||||
|
||||
/* common channel configs are mono/stereo/quad/5.1/7.1 (from debug strings), while others are quite rare
|
||||
* [Battlefield 4 (X360)-EAXMA: 3/5/7ch, Army of Two: The Devil's Cartel (PS3)-EALayer3v2P: 11ch] */
|
||||
eaac.channels = eaac.channel_config + 1;
|
||||
|
||||
/* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than block flags) */
|
||||
if (eaac.version != EAAC_VERSION_V0 && eaac.version != EAAC_VERSION_V1) {
|
||||
VGM_LOG("EA EAAC: unknown version\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* catch unknown/garbage values just in case */
|
||||
if (eaac.flags != EAAC_FLAG_NONE && !(eaac.flags & (EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED))) {
|
||||
VGM_LOG("EA EAAC: unknown flags 0x%02x\n", eaac.flags);
|
||||
/* accepted max (some Dead Space 2 (PC) do use 96000) */
|
||||
if (eaac.sample_rate > 200000) {
|
||||
VGM_LOG("EA EAAC: unknown sample rate\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* catch unknown values (0x02: "gigasample"? some kind of memory+stream thing?) */
|
||||
if (eaac.type != EAAC_TYPE_RAM && eaac.type != EAAC_TYPE_STREAM) {
|
||||
VGM_LOG("EA EAAC: unknown type 0x%02x\n", eaac.type);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Non-streamed sounds are stored as a single block (may not set block end flags) */
|
||||
eaac.streamed = (eaac.flags & EAAC_FLAG_STREAMED) != 0;
|
||||
eaac.streamed = (eaac.type == EAAC_TYPE_STREAM);
|
||||
|
||||
/* get loops (fairly involved due to the multiple layouts and mutant streamfiles)
|
||||
* full loops aren't too uncommon [Dead Space (PC) stream sfx/ambiance, FIFA 98 (PS3) RAM sfx],
|
||||
* while actual looping is very rare [Need for Speed: World (PC)-EAL3, The Simpsons Game (X360)-EAXMA] */
|
||||
if (eaac.flags & EAAC_FLAG_LOOPED) {
|
||||
if (eaac.loop == EAAC_LOOP_SET) {
|
||||
eaac.loop_flag = 1;
|
||||
eaac.loop_start = read_32bitBE(header_offset+0x08, streamHead);
|
||||
eaac.loop_end = eaac.num_samples;
|
||||
@ -938,28 +951,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
eaac.codec == EAAC_CODEC_EALAYER3_V2_PCM ||
|
||||
eaac.codec == EAAC_CODEC_EALAYER3_V2_SPIKE ||
|
||||
eaac.codec == EAAC_CODEC_EAXMA ||
|
||||
eaac.codec == EAAC_CODEC_XAS)) {
|
||||
eaac.codec == EAAC_CODEC_XAS1)) {
|
||||
VGM_LOG("EA EAAC: unknown actual looping for codec %x\n", eaac.codec);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* common channel configs are mono/stereo/quad/5.1/7.1 (from debug strings) */
|
||||
switch(eaac.channel_config) {
|
||||
case 0x00: eaac.channels = 1; break;
|
||||
case 0x01: eaac.channels = 2; break;
|
||||
case 0x02: eaac.channels = 3; break; /* rare [Battlefield 4 (X360)-EAXMA] */
|
||||
case 0x03: eaac.channels = 4; break;
|
||||
case 0x04: eaac.channels = 5; break; /* rare [Battlefield 4 (X360)-EAXMA] */
|
||||
case 0x05: eaac.channels = 6; break;
|
||||
case 0x06: eaac.channels = 7; break; /* rare [Battlefield 4 (X360)-EAXMA] */
|
||||
case 0x07: eaac.channels = 8; break;
|
||||
case 0x0a: eaac.channels = 11; break; /* rare [Army of Two: The Devil's Cartel (PS3)-EALayer3v2P] */
|
||||
default:
|
||||
/* surely channels = channel_config+1 but fail just in case for now */
|
||||
VGM_LOG("EA EAAC: unknown channel config 0x%02x\n", eaac.channel_config);
|
||||
goto fail;
|
||||
}
|
||||
/* if type is gigasample there seems to be a field with number of "gigasamples in ram",
|
||||
* that goes after loop_start but before streamed/gigasamples' eaac.loop_offset) */
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
@ -975,7 +974,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
/* EA decoder list and known internal FourCCs */
|
||||
switch(eaac.codec) {
|
||||
|
||||
case EAAC_CODEC_PCM: /* "P6B0": PCM16BE [NBA Jam (Wii)] */
|
||||
case EAAC_CODEC_PCM16BE: /* "P6B0": PCM16BE [NBA Jam (Wii)] */
|
||||
vgmstream->coding_type = coding_PCM16_int;
|
||||
vgmstream->codec_endian = 1;
|
||||
vgmstream->layout_type = layout_blocked_ea_sns;
|
||||
@ -1003,7 +1002,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
}
|
||||
#endif
|
||||
|
||||
case EAAC_CODEC_XAS: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */
|
||||
case EAAC_CODEC_XAS1: /* "Xas1": EA-XAS v1 [Dead Space (PC/PS3)] */
|
||||
|
||||
/* special (if hacky) loop handling, see comments */
|
||||
if (eaac.loop_start > 0) {
|
||||
@ -1053,7 +1052,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
}
|
||||
#endif
|
||||
|
||||
case EAAC_CODEC_DSP: /* "Gca0"?: DSP [Need for Speed: Nitro (Wii) sfx] */
|
||||
case EAAC_CODEC_GCADPCM: /* "Gca0": DSP [Need for Speed: Nitro (Wii) sfx] */
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_blocked_ea_sns;
|
||||
/* DSP coefs are read in the blocks */
|
||||
@ -1148,9 +1147,11 @@ fail:
|
||||
}
|
||||
|
||||
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) {
|
||||
switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */
|
||||
case EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED: return 0x10;
|
||||
case EAAC_FLAG_LOOPED: return 0x0C;
|
||||
//const int EAAC_FLAG_LOOPED = 0x02;
|
||||
//const int EAAC_FLAG_STREAMED = 0x04;
|
||||
switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */ //todo improve
|
||||
case 0x02 | 0x04: return 0x10;
|
||||
case 0x02: return 0x0C;
|
||||
default: return 0x08;
|
||||
}
|
||||
}
|
||||
@ -1242,8 +1243,7 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st
|
||||
}
|
||||
#endif
|
||||
|
||||
case EAAC_CODEC_XAS:
|
||||
{
|
||||
case EAAC_CODEC_XAS1: {
|
||||
start_offset = offsets[i];
|
||||
|
||||
data->segments[i]->coding_type = coding_EA_XAS_V1;
|
||||
|
@ -101,6 +101,8 @@ typedef struct {
|
||||
int big_endian;
|
||||
int loop_flag;
|
||||
int codec_config;
|
||||
|
||||
size_t stream_size;
|
||||
} ea_header;
|
||||
|
||||
static VGMSTREAM * parse_schl_block(STREAMFILE *streamFile, off_t offset, int standalone);
|
||||
@ -1167,8 +1169,6 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case EA_CODEC2_ATRAC3PLUS: {
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
/* regular ATRAC3plus chunked in SCxx blocks, including RIFF header [Medal of Honor Heroes 2 (PSP)] */
|
||||
if (!is_bnk) {
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
@ -1177,23 +1177,19 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
ea->stream_size = get_streamfile_size(temp_streamFile);
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(temp_streamFile, start_offset, get_streamfile_size(temp_streamFile));
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(temp_streamFile, start_offset, NULL);
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
}
|
||||
else {
|
||||
size_t riff_size = read_32bitLE(start_offset + 0x04, streamFile) + 0x08;
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, riff_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
/* memory file without blocks */
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, start_offset, NULL);
|
||||
}
|
||||
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamFile, start_offset));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -1203,6 +1199,8 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->stream_size = ea->stream_size;
|
||||
|
||||
/* open files; channel offsets are updated below */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
@ -1635,16 +1633,23 @@ fail:
|
||||
|
||||
static void update_ea_stream_size_and_samples(STREAMFILE* streamFile, off_t start_offset, VGMSTREAM *vgmstream, int standalone) {
|
||||
uint32_t block_id;
|
||||
int32_t num_samples;
|
||||
size_t stream_size, file_size;
|
||||
int multiple_schl;
|
||||
int32_t num_samples = 0;
|
||||
size_t stream_size = 0, file_size;
|
||||
int multiple_schl = 0;
|
||||
|
||||
stream_size = 0, num_samples = 0, multiple_schl = 0;
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
|
||||
/* formats with custom codecs */
|
||||
if (vgmstream->layout_type != layout_blocked_ea_schl) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* manually read totals */
|
||||
block_update(start_offset, vgmstream);
|
||||
while (vgmstream->next_block_offset < file_size) {
|
||||
block_update_ea_schl(vgmstream->next_block_offset, vgmstream);
|
||||
if (vgmstream->current_block_samples < 0)
|
||||
break;
|
||||
|
||||
block_id = read_32bitBE(vgmstream->current_block_offset + 0x00, streamFile);
|
||||
if (block_id == EA_BLOCKID_END) { /* banks should never contain movie "SHxx" */
|
||||
@ -1678,7 +1683,8 @@ static void update_ea_stream_size_and_samples(STREAMFILE* streamFile, off_t star
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->stream_size = stream_size;
|
||||
if (vgmstream->stream_size == 0)
|
||||
vgmstream->stream_size = stream_size;
|
||||
}
|
||||
|
||||
/* find data start offset inside the first SCDl; not very elegant but oh well */
|
||||
|
@ -15,6 +15,7 @@ VGMSTREAM * init_vgmstream_ffmpeg(STREAMFILE *streamFile) {
|
||||
|
||||
VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start, uint64_t size) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
ffmpeg_codec_data *data = NULL;
|
||||
int loop_flag = 0;
|
||||
int32_t loop_start = 0, loop_end = 0, num_samples = 0;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
@ -23,9 +24,13 @@ VGMSTREAM * init_vgmstream_ffmpeg_offset(STREAMFILE *streamFile, uint64_t start,
|
||||
//if (!check_extensions(streamFile, "..."))
|
||||
// goto fail;
|
||||
|
||||
/* don't try to open headers and other mini files */
|
||||
if (get_streamfile_size(streamFile) <= 0x100)
|
||||
goto fail;
|
||||
|
||||
|
||||
/* init ffmpeg */
|
||||
ffmpeg_codec_data *data = init_ffmpeg_offset(streamFile, start, size);
|
||||
data = init_ffmpeg_offset(streamFile, start, size);
|
||||
if (!data) return NULL;
|
||||
|
||||
total_subsongs = data->streamCount;
|
||||
|
@ -313,39 +313,41 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
int32_t bytes;
|
||||
|
||||
if (genh.codec == ATRAC3) {
|
||||
int block_size = genh.interleave;
|
||||
int joint_stereo;
|
||||
switch(genh.codec_mode) {
|
||||
case 0: joint_stereo = vgmstream->channels > 1 && genh.interleave/vgmstream->channels==0x60 ? 1 : 0; break; /* autodetect */
|
||||
case 1: joint_stereo = 1; break; /* force joint stereo */
|
||||
case 2: joint_stereo = 0; break; /* force stereo */
|
||||
default: goto fail;
|
||||
}
|
||||
int block_align, encoder_delay;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 200, vgmstream->num_samples, genh.data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, genh.skip_samples);
|
||||
block_align = genh.interleave;
|
||||
encoder_delay = genh.skip_samples;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_atrac3_raw(streamFile, genh.start_offset,genh.data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
}
|
||||
else if (genh.codec == ATRAC3PLUS) {
|
||||
int block_size = genh.interleave;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3plus(buf, 200, vgmstream->num_samples, genh.data_size, vgmstream->channels, vgmstream->sample_rate, block_size, genh.skip_samples);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, genh.start_offset,genh.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
else if (genh.codec == XMA1) {
|
||||
int xma_stream_mode = genh.codec_mode == 1 ? 1 : 0;
|
||||
|
||||
bytes = ffmpeg_make_riff_xma1(buf, 100, vgmstream->num_samples, genh.data_size, vgmstream->channels, vgmstream->sample_rate, xma_stream_mode);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, genh.start_offset,genh.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
else if (genh.codec == XMA2) {
|
||||
int block_size = genh.interleave ? genh.interleave : 2048;
|
||||
int block_count = genh.data_size / block_size;
|
||||
int block_count, block_size;
|
||||
|
||||
block_size = genh.interleave ? genh.interleave : 2048;
|
||||
block_count = genh.data_size / block_size;
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf, 200, vgmstream->num_samples, genh.data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, genh.start_offset,genh.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, genh.start_offset,genh.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
@ -353,7 +355,7 @@ VGMSTREAM * init_vgmstream_genh(STREAMFILE *streamFile) {
|
||||
|
||||
if (genh.codec == XMA1 || genh.codec == XMA2) {
|
||||
xma_fix_raw_samples(vgmstream, streamFile, genh.start_offset,genh.data_size, 0, 0,0);
|
||||
} else if (genh.skip_samples_mode && genh.skip_samples >= 0) { /* force encoder delay */
|
||||
} else if (genh.skip_samples_mode && genh.skip_samples >= 0 && genh.codec != ATRAC3) { /* force encoder delay */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, genh.skip_samples);
|
||||
}
|
||||
|
||||
|
@ -6,10 +6,10 @@
|
||||
VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
int loop_flag, channel_count;
|
||||
int loop_flag, channel_count, sample_rate, num_samples, loop_start, loop_end;
|
||||
off_t start_offset, chunk_offset, first_offset;
|
||||
size_t datasize;
|
||||
int codec_id;
|
||||
size_t data_size;
|
||||
int codec;
|
||||
|
||||
|
||||
/* checks */
|
||||
@ -19,16 +19,43 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "gsp");
|
||||
if (!streamHeader) goto fail;
|
||||
|
||||
/* check header */
|
||||
if (read_32bitBE(0x00,streamHeader) != 0x47534E44) /* "GSND" */
|
||||
goto fail;
|
||||
/* 0x04: version?, 0x08: 1?, 0x0c: 0?, */
|
||||
first_offset = read_32bitBE(0x10,streamHeader); /* usually 0x14*/
|
||||
/* 0x04: version? */
|
||||
/* 0x08: 1? */
|
||||
/* 0x0c: 0? */
|
||||
first_offset = read_32bitBE(0x10,streamHeader); /* usually 0x14 */
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x48454144,first_offset,1, &chunk_offset,NULL)) /* "HEAD" */
|
||||
goto fail;
|
||||
/* 0x00: header size */
|
||||
/* 0x04: num_chunks */
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x44415441,first_offset,1, &chunk_offset,NULL)) /* "DATA" */
|
||||
goto fail;
|
||||
data_size = read_32bitBE(chunk_offset + 0x00,streamHeader);
|
||||
codec = read_32bitBE(chunk_offset + 0x04,streamHeader);
|
||||
sample_rate = read_32bitBE(chunk_offset + 0x08,streamHeader);
|
||||
/* 0x0c: always 16? */
|
||||
channel_count = read_16bitBE(chunk_offset + 0x0e,streamHeader);
|
||||
/* 0x10: always 0? */
|
||||
num_samples = read_32bitBE(chunk_offset + 0x14,streamHeader);
|
||||
/* 0x18: always 0? */
|
||||
/* 0x1c: unk (varies with codec_id) */
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x42534943,first_offset,1, &chunk_offset,NULL)) /* "BSIC" */
|
||||
goto fail;
|
||||
/* 0x00/0x04: probably volume/pan/etc floats (1.0) */
|
||||
/* 0x08: null? */
|
||||
loop_flag = read_8bit(chunk_offset+0x0c,streamHeader);
|
||||
loop_start = read_32bitBE(chunk_offset+0x10,streamHeader);
|
||||
loop_end = read_32bitBE(chunk_offset+0x14,streamHeader);
|
||||
|
||||
//if (!find_chunk_be(streamHeader, 0x4E414D45,first_offset,1, &chunk_offset,NULL)) /* "NAME" */
|
||||
// goto fail;
|
||||
/* 0x00: name_size */
|
||||
/* 0x04+: name (same as filename) */
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x44415441,first_offset,1, &chunk_offset,NULL)) goto fail; /*"DATA"*/
|
||||
channel_count = read_16bitBE(chunk_offset+0x0e,streamHeader);
|
||||
if (!find_chunk_be(streamHeader, 0x42534943,first_offset,1, &chunk_offset,NULL)) goto fail; /*"BSIC"*/
|
||||
loop_flag = read_8bit(chunk_offset+0x0c,streamHeader);
|
||||
|
||||
start_offset = 0x00;
|
||||
|
||||
@ -39,27 +66,12 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
|
||||
vgmstream->meta_type = meta_GSP_GSB;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x48454144,first_offset,1, &chunk_offset,NULL)) goto fail; /*"HEAD"*/
|
||||
/* 0x00: header_size, 0x04: num_chunks */
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x44415441,first_offset,1, &chunk_offset,NULL)) goto fail; /*"DATA"*/
|
||||
/* 0x00: filesize, 0x0c: always 10?, 0x10: always 0?, 0x18: always 0? */
|
||||
datasize = read_32bitBE(chunk_offset+0x00,streamHeader);
|
||||
codec_id = read_32bitBE(chunk_offset+0x04,streamHeader);
|
||||
vgmstream->sample_rate = read_32bitBE(chunk_offset+0x08,streamHeader);
|
||||
vgmstream->num_samples = read_32bitBE(chunk_offset+0x14,streamHeader);
|
||||
/* 0x1c: unk (varies with codec_id) */
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x42534943,first_offset,1, &chunk_offset,NULL)) goto fail; /*"BSIC"*/
|
||||
/* 0x00+: probably volume/pan/etc */
|
||||
vgmstream->loop_start_sample = read_32bitBE(chunk_offset+0x10,streamHeader);
|
||||
vgmstream->loop_end_sample = read_32bitBE(chunk_offset+0x14,streamHeader);
|
||||
|
||||
//if (!find_chunk_be(streamHeader, 0x4E414D45,first_offset,1, &chunk_offset,NULL)) goto fail; /*"NAME"*/
|
||||
/* 0x00: name_size, 0x04+: name*/
|
||||
|
||||
switch (codec_id) {
|
||||
switch (codec) {
|
||||
case 0x04: { /* DSP [Super Swing Golf (Wii)] */
|
||||
size_t block_header_size;
|
||||
size_t num_blocks;
|
||||
@ -67,12 +79,13 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_blocked_gsb;
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x47434558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"GCEX"*/
|
||||
if (!find_chunk_be(streamHeader, 0x47434558,first_offset,1, &chunk_offset,NULL)) /* "GCEX" */
|
||||
goto fail;
|
||||
|
||||
//vgmstream->current_block_size = read_32bitBE(chunk_offset+0x00,streamHeader);
|
||||
block_header_size = read_32bitBE(chunk_offset+0x04,streamHeader);
|
||||
num_blocks = read_32bitBE(chunk_offset+0x08,streamHeader);
|
||||
vgmstream->num_samples = (datasize - block_header_size * num_blocks) / 8 / vgmstream->channels * 14;
|
||||
vgmstream->num_samples = (data_size - block_header_size * num_blocks) / 8 / vgmstream->channels * 14;
|
||||
/* 0x0c+: unk */
|
||||
|
||||
dsp_read_coefs_be(vgmstream, streamHeader, chunk_offset+0x18, 0x30);
|
||||
@ -80,30 +93,21 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
}
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x08: { /* ATRAC3 [Quantum Theory (PS3)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[100];
|
||||
int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
block_size = 0x98 * vgmstream->channels;
|
||||
joint_stereo = 0;
|
||||
max_samples = atrac3_bytes_to_samples(datasize, block_size);;
|
||||
encoder_delay = max_samples - vgmstream->num_samples; /* todo guessed */
|
||||
block_align = 0x98 * vgmstream->channels;
|
||||
encoder_delay = 1024 + 69*2; /* observed default, matches XMA (needed as many files start with garbage) */
|
||||
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay;
|
||||
/* fix num_samples as header samples seem to be modified to match altered (49999/48001) sample rates somehow */
|
||||
|
||||
vgmstream->num_samples += encoder_delay;
|
||||
/* make a fake riff so FFmpeg can parse the ATRAC3 */
|
||||
bytes = ffmpeg_make_riff_atrac3(buf,100, vgmstream->num_samples, datasize, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
if (bytes <= 0)
|
||||
goto fail;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->loop_start_sample = (vgmstream->loop_start_sample / ffmpeg_data->blockAlign) * ffmpeg_data->frameSize;
|
||||
vgmstream->loop_end_sample = (vgmstream->loop_end_sample / ffmpeg_data->blockAlign) * ffmpeg_data->frameSize;
|
||||
|
||||
/* set offset samples (offset 0 jumps to sample 0 > pre-applied delay, and offset end loops after sample end > adjusted delay) */
|
||||
vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_align); //- encoder_delay
|
||||
vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_align) - encoder_delay;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -112,17 +116,19 @@ VGMSTREAM * init_vgmstream_gsp_gsb(STREAMFILE *streamFile) {
|
||||
uint8_t buf[200];
|
||||
int32_t bytes;
|
||||
|
||||
if (!find_chunk_be(streamHeader, 0x584D4558,first_offset,1, &chunk_offset,NULL)) goto fail; /*"XMEX"*/
|
||||
/* 0x00: fmt0x166 header (BE), 0x34: seek table */
|
||||
if (!find_chunk_be(streamHeader, 0x584D4558,first_offset,1, &chunk_offset,NULL)) /* "XMEX" */
|
||||
goto fail;
|
||||
/* 0x00: fmt0x166 header (BE) */
|
||||
/* 0x34: seek table */
|
||||
|
||||
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, datasize, streamHeader, 1);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,datasize);
|
||||
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,200, chunk_offset,0x34, data_size, streamHeader, 1);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
xma_fix_raw_samples(vgmstream, streamFile, start_offset,datasize, 0, 0,0); /* samples are ok */
|
||||
xma_fix_raw_samples(vgmstream, streamFile, start_offset,data_size, 0, 0,0); /* samples are ok */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -99,38 +99,27 @@ VGMSTREAM * init_vgmstream_msf(STREAMFILE *streamFile) {
|
||||
case 0x04: /* ATRAC3 low (66 kbps, frame size 96, Joint Stereo) [Silent Hill HD (PS3)] */
|
||||
case 0x05: /* ATRAC3 mid (105 kbps, frame size 152) [Atelier Rorona (PS3)] */
|
||||
case 0x06: { /* ATRAC3 high (132 kbps, frame size 192) [Tekken Tag Tournament HD (PS3)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[100];
|
||||
int32_t bytes, block_size, encoder_delay, joint_stereo;
|
||||
|
||||
block_size = (codec==4 ? 0x60 : (codec==5 ? 0x98 : 0xC0)) * vgmstream->channels;
|
||||
joint_stereo = (codec==4); /* interleaved joint stereo (ch must be even) */
|
||||
int block_align, encoder_delay;
|
||||
|
||||
/* MSF skip samples: from tests with MSEnc and real files (ex. TTT2 eddy.msf v43, v01 demos) seems like 1162 is consistent.
|
||||
* Atelier Rorona bt_normal01 needs it to properly skip the beginning garbage but usually doesn't matter.
|
||||
* (note that encoder may add a fade-in with looping/resampling enabled but should be skipped) */
|
||||
encoder_delay = 1162;
|
||||
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_size) - encoder_delay;
|
||||
encoder_delay = 1024 + 69*2;
|
||||
block_align = (codec==4 ? 0x60 : (codec==5 ? 0x98 : 0xC0)) * vgmstream->channels;
|
||||
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay;
|
||||
if (vgmstream->sample_rate == 0xFFFFFFFF) /* some MSFv1 (Digi World SP) */
|
||||
vgmstream->sample_rate = 44100; /* voice tracks seems to use 44khz, not sure about other tracks */
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
|
||||
/* manually set skip_samples if FFmpeg didn't do it */
|
||||
if (ffmpeg_data->skipSamples <= 0) {
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, encoder_delay);
|
||||
}
|
||||
|
||||
/* MSF loop/sample values are offsets so trickier to adjust the skip_samples but this seems correct */
|
||||
/* MSF loop/sample values are offsets so trickier to adjust but this seems correct */
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_size) /* - encoder_delay*/;
|
||||
vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_size) - encoder_delay;
|
||||
/* set offset samples (offset 0 jumps to sample 0 > pre-applied delay, and offset end loops after sample end > adjusted delay) */
|
||||
vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_align); //- encoder_delay
|
||||
vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_align) - encoder_delay;
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -9,17 +9,19 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||
off_t start_offset, chunk_offset, name_offset = 0;
|
||||
size_t stream_size, chunk_size;
|
||||
int loop_flag = 0, channel_count, is_separate = 0, type, sample_rate;
|
||||
int32_t loop_start, loop_end;
|
||||
int32_t num_samples, loop_start;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
/* check extensions */
|
||||
/* .xws: header and data, .xwh+xwb: header + data (.bin+dat are also found in Wild Arms 4/5) */
|
||||
if (!check_extensions(streamFile,"xws,xwb")) goto fail;
|
||||
/* checks */
|
||||
/* .xws: header and data
|
||||
* .xwh+xwb: header + data (.bin+dat are also found in Wild Arms 4/5) */
|
||||
if (!check_extensions(streamFile,"xws,xwb"))
|
||||
goto fail;
|
||||
is_separate = check_extensions(streamFile,"xwb");
|
||||
|
||||
/* xwh+xwb: use xwh as header; otherwise use the current file */
|
||||
if (is_separate) {
|
||||
/* extra check to avoid hijacking Microsoft's XWB */
|
||||
/* extra check to reject Microsoft's XWB faster */
|
||||
if ((read_32bitBE(0x00,streamFile) == 0x57424E44) || /* "WBND" (LE) */
|
||||
(read_32bitBE(0x00,streamFile) == 0x444E4257)) /* "DNBW" (BE) */
|
||||
goto fail;
|
||||
@ -62,7 +64,7 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||
channel_count = read_8bit(header_offset+0x09, streamHeader);
|
||||
sample_rate = (uint16_t)read_16bitLE(header_offset+0x0a,streamHeader);
|
||||
stream_offset = read_32bitLE(header_offset+0x10,streamHeader);
|
||||
loop_end = read_32bitLE(header_offset+0x14,streamHeader);
|
||||
num_samples = read_32bitLE(header_offset+0x14,streamHeader);
|
||||
loop_start = read_32bitLE(header_offset+0x18,streamHeader);
|
||||
loop_flag = (loop_start != 0xFFFFFFFF);
|
||||
|
||||
@ -84,7 +86,7 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
if (target_subsong == total_subsongs) {
|
||||
next_stream_offset = data_offset + get_streamfile_size(is_separate ? streamFile : streamHeader);
|
||||
next_stream_offset = get_streamfile_size(is_separate ? streamFile : streamHeader) - data_offset;
|
||||
} else {
|
||||
off_t next_header_offset = chunk_offset + 0x4 + 0x1c * (target_subsong);
|
||||
next_stream_offset = read_32bitLE(next_header_offset+0x10,streamHeader);
|
||||
@ -120,41 +122,36 @@ VGMSTREAM * init_vgmstream_ps2_rxws(STREAMFILE *streamFile) {
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(loop_end, channel_count);
|
||||
vgmstream->num_samples = ps_bytes_to_samples(num_samples, channel_count);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channel_count);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channel_count);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
case 0x01: /* PCM */
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = channel_count==1 ? layout_none : layout_interleave;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x2;
|
||||
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(loop_end, channel_count, 16);
|
||||
vgmstream->num_samples = pcm_bytes_to_samples(num_samples, channel_count, 16);
|
||||
vgmstream->loop_start_sample = pcm_bytes_to_samples(loop_start, channel_count, 16);
|
||||
vgmstream->loop_end_sample = pcm_bytes_to_samples(loop_end, channel_count, 16);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x02: { /* ATRAC3 */
|
||||
uint8_t buf[0x100];
|
||||
int32_t bytes, block_size, encoder_delay, joint_stereo;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
block_size = 0xc0 * channel_count;
|
||||
joint_stereo = 0;
|
||||
encoder_delay = 0x0;
|
||||
block_align = 0xc0 * channel_count;
|
||||
encoder_delay = 1024 + 69*2; /* observed default */
|
||||
vgmstream->num_samples = num_samples - encoder_delay;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, stream_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
if (bytes <= 0) goto fail;
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,stream_size);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,stream_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = loop_end;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@ VGMSTREAM * init_vgmstream_va3(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count;
|
||||
uint32_t data_size, loop_start, loop_end;
|
||||
uint32_t data_size;
|
||||
|
||||
/* check extension, case insensitive */
|
||||
if (!check_extensions(streamFile, "va3"))
|
||||
@ -29,41 +29,23 @@ VGMSTREAM * init_vgmstream_va3(STREAMFILE *streamFile) {
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
|
||||
|
||||
vgmstream->meta_type = meta_VA3;
|
||||
vgmstream->sample_rate = read_32bitLE(0x14, streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x08, streamFile);
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->meta_type = meta_VA3;
|
||||
loop_start = 0;
|
||||
loop_end = 0;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[200];
|
||||
int32_t bytes, samples_size = 1024, block_size, encoder_delay, joint_stereo;
|
||||
block_size = 0xC0 * vgmstream->channels;
|
||||
//max_samples = (data_size / block_size) * samples_size;
|
||||
encoder_delay = 0x0;
|
||||
joint_stereo = 0;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
/* make a fake riff so FFmpeg can parse the ATRAC3 */
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 200, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
if (bytes <= 0) goto fail;
|
||||
block_align = 0xC0 * vgmstream->channels;
|
||||
encoder_delay = 0; //todo
|
||||
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf, bytes, start_offset, data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
//vgmstream->num_samples = max_samples;
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (loop_start / block_size) * samples_size;
|
||||
vgmstream->loop_end_sample = (loop_end / block_size) * samples_size;
|
||||
}
|
||||
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
|
@ -56,54 +56,86 @@ VGMSTREAM * init_vgmstream_ps2_vas_container(STREAMFILE *streamFile) {
|
||||
off_t subfile_offset = 0;
|
||||
size_t subfile_size = 0;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int has_table;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "vas"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) != 0xAB8A5A00) /* fixed value */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x04, streamFile)*0x800 + 0x800 != get_streamfile_size(streamFile)) /* just in case */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00, streamFile) == 0xAB8A5A00) { /* fixed value */
|
||||
|
||||
/* offset table, 0x98 has table size */
|
||||
has_table = read_32bitLE(0x94, streamFile);
|
||||
/* just in case */
|
||||
if (read_32bitLE(0x04, streamFile)*0x800 + 0x800 != get_streamfile_size(streamFile))
|
||||
goto fail;
|
||||
|
||||
total_subsongs = read_32bitLE(0x08, streamFile); /* also at 0x10 */
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
total_subsongs = read_32bitLE(0x08, streamFile); /* also at 0x10 */
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
/* check offset table flag, 0x98 has table size */
|
||||
if (read_32bitLE(0x94, streamFile)) {
|
||||
off_t header_offset = 0x800 + 0x10*(target_subsong-1);
|
||||
|
||||
/* some values are repeats found in the file sub-header */
|
||||
subfile_offset = read_32bitLE(header_offset + 0x00,streamFile) * 0x800;
|
||||
subfile_size = read_32bitLE(header_offset + 0x08,streamFile) + 0x800;
|
||||
}
|
||||
else {
|
||||
/* a bunch of files */
|
||||
off_t offset = 0x800;
|
||||
int i;
|
||||
|
||||
if (has_table) {
|
||||
off_t header_offset = 0x800 + 0x10*(target_subsong-1);
|
||||
for (i = 0; i < total_subsongs; i++) {
|
||||
size_t size = read_32bitLE(offset, streamFile) + 0x800;
|
||||
|
||||
/* some values are repeats found in the file sub-header */
|
||||
subfile_offset = read_32bitLE(header_offset + 0x00,streamFile) * 0x800;
|
||||
subfile_size = read_32bitLE(header_offset + 0x08,streamFile) + 0x800;
|
||||
if (i + 1 == target_subsong) {
|
||||
subfile_offset = offset;
|
||||
subfile_size = size;
|
||||
break;
|
||||
}
|
||||
|
||||
offset += size;
|
||||
}
|
||||
if (i == total_subsongs)
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* a bunch of files */
|
||||
off_t offset = 0x800;
|
||||
int i;
|
||||
/* some .vas are just files pasted together, better extracted externally but whatevs */
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
off_t offset = 0;
|
||||
|
||||
for (i = 0; i < total_subsongs; i++) {
|
||||
size_t size = read_32bitLE(offset, streamFile) + 0x800;
|
||||
/* must have multiple .vas */
|
||||
if (read_32bitLE(0x00,streamFile) + 0x800 >= file_size)
|
||||
goto fail;
|
||||
|
||||
if (i + 1 == target_subsong) {
|
||||
subfile_offset = offset;
|
||||
subfile_size = size;
|
||||
break;
|
||||
total_subsongs = 0;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
while (offset < file_size) {
|
||||
size_t size = read_32bitLE(offset,streamFile) + 0x800;
|
||||
|
||||
/* some files can be null, ignore */
|
||||
if (size > 0x800) {
|
||||
total_subsongs++;
|
||||
|
||||
if (total_subsongs == target_subsong) {
|
||||
subfile_offset = offset;
|
||||
subfile_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
offset += size;
|
||||
}
|
||||
if (i == total_subsongs)
|
||||
|
||||
/* should end exactly at file_size */
|
||||
if (offset > file_size)
|
||||
goto fail;
|
||||
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
}
|
||||
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, NULL);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
|
193
src/meta/psf.c
193
src/meta/psf.c
@ -132,13 +132,19 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* PSF segmented - Pivotal games multiple segments (external in some PC/Xbox or inside bigfiles) [The Great Escape, Conflict series] */
|
||||
VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
segmented_layout_data *data = NULL;
|
||||
int i, segment_count, loop_flag = 0, loop_start = 0, loop_end = 0;
|
||||
off_t offset;
|
||||
int i,j, sequence_count = 0, loop_flag = 0, loop_start = 0, loop_end = 0;
|
||||
int sequence[512] = {0};
|
||||
off_t offsets[512] = {0};
|
||||
int total_subsongs = 0, target_subsong = streamFile->stream_index;
|
||||
char stream_name[STREAM_NAME_SIZE] = {0};
|
||||
size_t stream_size = 0;
|
||||
|
||||
|
||||
/* checks */
|
||||
@ -151,43 +157,168 @@ VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE *streamFile) {
|
||||
read_32bitBE(0x00,streamFile) != 0x50534631) /* "PSF\31" [Conflict: Desert Storm 2 (Xbox/GC/PS2), Conflict: Global Terror (Xbox)] */
|
||||
goto fail;
|
||||
|
||||
segment_count = read_32bitLE(0x04, streamFile);
|
||||
loop_flag = 0;
|
||||
|
||||
offset = 0x08;
|
||||
offset += 0x0c; /* first segment points to itself? */
|
||||
segment_count--;
|
||||
/* transition table info:
|
||||
* 0x00: offset
|
||||
* 0x04: 0x02*4 next segment points (one per track)
|
||||
* (xN segments)
|
||||
*
|
||||
* There are 4 possible tracks, like: normal, tension, action, high action. Segment 0 has tracks'
|
||||
* entry segments (where 1=first, right after segment 0), and each segment has a link point to next
|
||||
* (or starting) segment of any of other tracks. Thus, follow point 1/2/3/4 to playtrack 1/2/3/4
|
||||
* (points also loop back). It's designed to go smoothly between any tracks (1>3, 4>1, etc),
|
||||
* so sometimes "step" segments (that aren't normally played) are used.
|
||||
* If a track doesn't exist it may keep repeating silent segments, but still defines points.
|
||||
*
|
||||
* ex. sequence could go like this:
|
||||
* (read segment 0 track1 entry): 1
|
||||
* - track0: 1>2>3>4>5>6>7>8>1>2>3, then to track2 goes 3>15>9
|
||||
* - track1: 9>10>11>12>13>14>9>10, then to track4 goes 10>33
|
||||
* - track2: 33>34>35>36>30>31>32>33, then to track1 goes 33>3
|
||||
* - track3: 3>4>5>6... (etc)
|
||||
*
|
||||
* Well make a sequence based on target subsong:
|
||||
* - 1: tracks mixed with transitions, looping back to track1 (only first is used in .sch so we want all)
|
||||
* - 2~5: track1~4 looping back to themselves
|
||||
* - 6+: single segment (where 6=first segment) to allow free mixes
|
||||
*/
|
||||
{
|
||||
int track[4][255] = {0};
|
||||
int count[4] = {0};
|
||||
int current_track, current_point, next_point, repeat_point;
|
||||
int transition_count = read_32bitLE(0x04, streamFile);
|
||||
|
||||
/* build segments */
|
||||
data = init_layout_segmented(segment_count);
|
||||
if (!data) goto fail;
|
||||
total_subsongs = 1 + 4 + (transition_count - 1);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
off_t psf_offset;
|
||||
size_t psf_size;
|
||||
|
||||
/* mini table */
|
||||
psf_offset = read_32bitLE(offset + 0x00, streamFile);
|
||||
psf_size = get_streamfile_size(streamFile) - psf_offset; /* not ok but meh */
|
||||
/* 0x04-0c: 0x02*4 transition segments (possibly to 4 song variations) */
|
||||
if (target_subsong == 1) {
|
||||
current_track = 0; /* start from first track, will move to others automatically */
|
||||
|
||||
/* use last section transition as loop */
|
||||
if (i + 1 == segment_count) {
|
||||
loop_flag = 1;
|
||||
loop_start = read_16bitLE(offset + 0x0a, streamFile) - 1; /* also ignore first segment */
|
||||
loop_end = i;
|
||||
snprintf(stream_name,sizeof(stream_name), "full");
|
||||
}
|
||||
else if (target_subsong <= 1+4) {
|
||||
current_track = (target_subsong-1) - 1; /* where 0 = first track */
|
||||
|
||||
snprintf(stream_name,sizeof(stream_name), "track%i", (current_track+1));
|
||||
}
|
||||
else {
|
||||
int segment = target_subsong - 1 - 4; /* where 1 = first segment */
|
||||
|
||||
sequence[0] = segment;
|
||||
sequence_count = 1;
|
||||
current_track = -1;
|
||||
|
||||
/* show transitions to help with ordering */
|
||||
track[0][0] = read_16bitLE(0x08 + 0x0c*segment + 0x04, streamFile);
|
||||
track[1][0] = read_16bitLE(0x08 + 0x0c*segment + 0x06, streamFile);
|
||||
track[2][0] = read_16bitLE(0x08 + 0x0c*segment + 0x08, streamFile);
|
||||
track[3][0] = read_16bitLE(0x08 + 0x0c*segment + 0x0a, streamFile);
|
||||
snprintf(stream_name,sizeof(stream_name), "segment%03i to %03i/%03i/%03i/%03i", segment,track[0][0],track[1][0],track[2][0],track[3][0]);
|
||||
}
|
||||
|
||||
/* multiple segment can point to the same PSF offset (for repeated song sections) */
|
||||
//todo reuse repeated VGMSTREAMs to improve memory and bitrate calcs a bit
|
||||
/* find target sequence */
|
||||
current_point = 0; /* segment 0 has track entry points */
|
||||
while (sequence_count < 512 && current_track >= 0) {
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, psf_offset, psf_size, "psf");
|
||||
if (!temp_streamFile) goto fail;
|
||||
next_point = read_16bitLE(0x08 + 0x0c*current_point + 0x04 + 0x02*current_track, streamFile);
|
||||
|
||||
data->segments[i] = init_vgmstream_psf_single(temp_streamFile);
|
||||
if (!data->segments[i]) goto fail;
|
||||
/* find if next point repeats in our current track */
|
||||
repeat_point = -1;
|
||||
for (i = 0; i < count[current_track]; i++) {
|
||||
|
||||
offset += 0x0c;
|
||||
if (track[current_track][i] == next_point) {
|
||||
repeat_point = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* set loops and end sequence */
|
||||
if (repeat_point >= 0) {
|
||||
if (target_subsong == 1) {
|
||||
/* move to next track and change transition to next track too */
|
||||
current_track++;
|
||||
|
||||
/* to loop properly we set loop end in track3 and loop start in track0
|
||||
* when track3 ends and move to track0 could have a transition segment
|
||||
* before actually looping track0, so we do this in 2 steps */
|
||||
|
||||
if (loop_flag) { /* 2nd time repeat is found = loop start in track0 */
|
||||
loop_start = repeat_point;
|
||||
break; /* sequence fully done */
|
||||
}
|
||||
|
||||
if (current_track > 3) { /* 1st time repeat is found = loop end in track3 */
|
||||
current_track = 0;
|
||||
loop_flag = 1;
|
||||
}
|
||||
|
||||
next_point = read_16bitLE(0x08 + 0x0c*current_point + 0x04 + 0x02*current_track, streamFile);
|
||||
|
||||
if (loop_flag) {
|
||||
loop_end = sequence_count; /* this points to the next_point that will be added below */
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* end track N */
|
||||
loop_flag = 1;
|
||||
loop_start = repeat_point;
|
||||
loop_end = sequence_count - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* separate track info to find repeated points (since some transitions are common for all tracks) */
|
||||
track[current_track][count[current_track]] = next_point;
|
||||
count[current_track]++;
|
||||
|
||||
sequence[sequence_count] = next_point;
|
||||
sequence_count++;
|
||||
|
||||
current_point = next_point;
|
||||
}
|
||||
|
||||
if (sequence_count >= 512 || count[current_track] >= 512)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
/* build segments */
|
||||
data = init_layout_segmented(sequence_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
for (i = 0; i < sequence_count; i++) {
|
||||
off_t psf_offset;
|
||||
size_t psf_size;
|
||||
int old_psf = -1;
|
||||
|
||||
psf_offset = read_32bitLE(0x08 + sequence[i]*0x0c + 0x00, streamFile);
|
||||
psf_size = get_streamfile_size(streamFile) - psf_offset; /* not ok but meh */
|
||||
|
||||
/* find repeated sections (sequences often repeat PSFs) */
|
||||
offsets[i] = psf_offset;
|
||||
for (j = 0; j < i; j++) {
|
||||
if (offsets[j] == psf_offset) {
|
||||
old_psf = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* reuse repeated VGMSTREAMs to improve memory and bitrate calcs a bit */
|
||||
if (old_psf >= 0) {
|
||||
data->segments[i] = data->segments[old_psf];
|
||||
}
|
||||
else {
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, psf_offset, psf_size, "psf");
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
data->segments[i] = init_vgmstream_psf_single(temp_streamFile);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
stream_size += data->segments[i]->stream_size; /* only non-repeats */
|
||||
}
|
||||
}
|
||||
|
||||
/* setup VGMSTREAMs */
|
||||
@ -196,6 +327,10 @@ VGMSTREAM * init_vgmstream_psf_segmented(STREAMFILE *streamFile) {
|
||||
vgmstream = allocate_segmented_vgmstream(data,loop_flag, loop_start, loop_end);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
strcpy(vgmstream->stream_name, stream_name);
|
||||
|
||||
return vgmstream;
|
||||
fail:
|
||||
if (!vgmstream) free_layout_segmented(data);
|
||||
|
@ -94,6 +94,7 @@ typedef struct {
|
||||
int interleave;
|
||||
|
||||
int is_at3;
|
||||
int is_at3p;
|
||||
int is_at9;
|
||||
} riff_fmt_chunk;
|
||||
|
||||
@ -122,10 +123,15 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
fmt->channel_layout = read_32bit(current_chunk+0x1c,streamFile);
|
||||
/* 0x10 guid at 0x20 */
|
||||
|
||||
/* happens in .at3/at9, may be a bug in their encoder b/c MS's defs set mono as FC */
|
||||
/* happens in various .at3/at9, may be a bug in their encoder b/c MS's defs set mono as FC */
|
||||
if (fmt->channel_count == 1 && fmt->channel_layout == speaker_FL) { /* other channels are fine */
|
||||
fmt->channel_layout = speaker_FC;
|
||||
}
|
||||
|
||||
/* happens in few at3p, may be a bug in older tools as other games have ok flags [Ridge Racer 7 (PS3)] */
|
||||
if (fmt->channel_count == 6 && fmt->channel_layout == 0x013f) {
|
||||
fmt->channel_layout = 0x3f;
|
||||
}
|
||||
}
|
||||
|
||||
switch (fmt->codec) {
|
||||
@ -242,11 +248,11 @@ static int read_fmt(int big_endian, STREAMFILE * streamFile, off_t current_chunk
|
||||
bztmp = (bztmp >> 8) | (bztmp << 8);
|
||||
fmt->coding_type = coding_AT3plus;
|
||||
fmt->block_size = (bztmp & 0x3FF) * 8 + 8; /* should match fmt->block_size */
|
||||
fmt->is_at3 = 1;
|
||||
fmt->is_at3p = 1;
|
||||
break;
|
||||
#elif defined(VGM_USE_FFMPEG)
|
||||
fmt->coding_type = coding_FFmpeg;
|
||||
fmt->is_at3 = 1;
|
||||
fmt->is_at3p = 1;
|
||||
break;
|
||||
#else
|
||||
goto fail;
|
||||
@ -442,13 +448,22 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
case 0x66616374: /* "fact" */
|
||||
if (chunk_size == 0x04) { /* standard, usually found with ADPCM */
|
||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
} else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, streamFile) == 0x4C794E20) { /* "LyN " */
|
||||
}
|
||||
else if (chunk_size == 0x10 && read_32bitBE(current_chunk+0x08+0x04, streamFile) == 0x4C794E20) { /* "LyN " */
|
||||
goto fail; /* parsed elsewhere */
|
||||
} else if ((fmt.is_at3 || fmt.is_at9) && chunk_size == 0x08) {
|
||||
}
|
||||
else if ((fmt.is_at3 || fmt.is_at3p) && chunk_size == 0x08) { /* early AT3 (mainly PSP games) */
|
||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
fact_sample_skip = read_32bitLE(current_chunk+0x0c, streamFile);
|
||||
} else if ((fmt.is_at3 || fmt.is_at9) && chunk_size == 0x0c) {
|
||||
fact_sample_skip = read_32bitLE(current_chunk+0x0c, streamFile); /* base skip samples */
|
||||
}
|
||||
else if ((fmt.is_at3 || fmt.is_at3p) && chunk_size == 0x0c) { /* late AT3 (mainly PS3 games and few PSP games) */
|
||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
/* 0x0c: base skip samples, ignored by decoder */
|
||||
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile); /* skip samples with extra 184 */
|
||||
}
|
||||
else if (fmt.is_at9 && chunk_size == 0x0c) {
|
||||
fact_sample_count = read_32bitLE(current_chunk+0x08, streamFile);
|
||||
/* 0x0c: base skip samples (same as next field) */
|
||||
fact_sample_skip = read_32bitLE(current_chunk+0x10, streamFile);
|
||||
}
|
||||
break;
|
||||
@ -600,40 +615,22 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case coding_FFmpeg: {
|
||||
ffmpeg_codec_data *ffmpeg_data = init_ffmpeg_offset(streamFile, 0x00, streamFile->get_size(streamFile));
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
if (!fmt.is_at3 && !fmt.is_at3p) goto fail;
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact_sample_count */
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, 0x00, NULL);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
|
||||
if (fmt.is_at3) {
|
||||
/* the encoder introduces some garbage (not always silent) samples to skip before the stream */
|
||||
/* manually set skip_samples if FFmpeg didn't do it */
|
||||
if (ffmpeg_data->skipSamples <= 0) {
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, fact_sample_skip);
|
||||
}
|
||||
vgmstream->num_samples = fact_sample_count;
|
||||
if (loop_flag) {
|
||||
/* adjust RIFF loop/sample absolute values (with skip samples) */
|
||||
loop_start_smpl -= fact_sample_skip;
|
||||
loop_end_smpl -= fact_sample_skip;
|
||||
|
||||
/* LFE channel should be reordered on decode, but FFmpeg doesn't do it automatically:
|
||||
* - 6ch: FL FR FC BL BR LFE > FL FR FC LFE BL BR
|
||||
* - 8ch: FL FR FC BL BR SL SR LFE > FL FR FC LFE BL BR SL SR
|
||||
* (ATRAC3Plus only, 5/7ch can't be encoded) */
|
||||
if (ffmpeg_data->channels == 6) {
|
||||
/* LFE BR BL > LFE BL BR > same */
|
||||
int channel_remap[] = { 0, 1, 2, 5, 5, 5, };
|
||||
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
|
||||
}
|
||||
else if (ffmpeg_data->channels == 8) {
|
||||
/* LFE BR SL SR BL > LFE BL SL SR BR > LFE BL BR SR SL > LFE BL BR SL SR > same */
|
||||
int channel_remap[] = { 0, 1, 2, 7, 7, 7, 7, 7};
|
||||
ffmpeg_set_channel_remapping(ffmpeg_data, channel_remap);
|
||||
}
|
||||
|
||||
/* RIFF loop/sample values are absolute (with skip samples), adjust */
|
||||
if (loop_flag) {
|
||||
loop_start_smpl -= (int32_t)ffmpeg_data->skipSamples;
|
||||
loop_end_smpl -= (int32_t)ffmpeg_data->skipSamples;
|
||||
}
|
||||
/* happens with official tools when "fact" is not found */
|
||||
if (vgmstream->num_samples == 0)
|
||||
vgmstream->num_samples = loop_end_smpl;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -753,7 +750,7 @@ VGMSTREAM * init_vgmstream_riff(STREAMFILE *streamFile) {
|
||||
|
||||
vgmstream->coding_type = coding_MSADPCM_int;
|
||||
|
||||
/* only works with half-interleave as frame_size and interleave are merged ATM*/
|
||||
/* only works with half-interleave as frame_size and interleave are merged ATM */
|
||||
for (ch = 0; ch < vgmstream->channels; ch++) {
|
||||
vgmstream->ch[ch].channel_start_offset =
|
||||
vgmstream->ch[ch].offset = start_offset + half_interleave*ch;
|
||||
|
@ -158,19 +158,14 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
case 0x4154332B: { /* "AT3+" [Crash of the Titans (PSP)] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
int fact_samples = 0;
|
||||
|
||||
/* full RIFF header at start_offset */
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, start_offset, &fact_samples);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamFile, start_offset));
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
|
||||
vgmstream->num_samples = fact_samples;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -125,18 +125,13 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x04: { /* ATRAC3plus [Kurohyo 1/2 (PSP), BraveStory (PSP)] */
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
/* internally has a RIFF header; but the SGXD header / sample rate has priority over it (may not match) */
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, stream_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, start_offset, NULL);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamFile, start_offset));
|
||||
/* SGXD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
|
||||
/* SGXD's sample rate has priority over RIFF's sample rate (may not match) */
|
||||
/* loop/sample values are relative (without skip) vs RIFF (with skip), matching "smpl" otherwise */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -48,17 +48,13 @@ VGMSTREAM * init_vgmstream_smp(STREAMFILE *streamFile) {
|
||||
switch(codec) {
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x01: {
|
||||
uint8_t buf[0x100];
|
||||
int bytes, block_size, joint_stereo, skip_samples;
|
||||
|
||||
int block_align, encoder_delay;
|
||||
if (bps != 16) goto fail;
|
||||
|
||||
block_size = 0x98 * vgmstream->channels;
|
||||
joint_stereo = 0;
|
||||
skip_samples = 0; /* unknown */
|
||||
block_align = 0x98 * vgmstream->channels;
|
||||
encoder_delay = 0; /* 1024 looks ok, but num_samples needs to be adjusted too */
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf,sizeof(buf), vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, skip_samples);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
@ -300,7 +300,7 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
vgmstream->num_samples = read_32bitBE(start_offset+0x00,streamFile);
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end+1;
|
||||
vgmstream->loop_end_sample = loop_end + 1;
|
||||
}
|
||||
|
||||
for (i = 1; i < channel_count; i++) {
|
||||
@ -349,29 +349,24 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
vgmstream->loop_end_sample = loop_end; //todo +1?
|
||||
|
||||
xma_fix_raw_samples(vgmstream, streamFile, start_offset,stream_size, 0, 0,0); /* samples are ok, loops? */
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x0E: { /* ATRAC3/ATRAC3plus [Lord of Arcana (PSP), Final Fantasy Type-0] */
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
int fact_samples = 0;
|
||||
|
||||
/* full RIFF header at start_offset/extradata_offset (same) */
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamFile, start_offset, &fact_samples);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = ffmpeg_data->totalSamples; /* fact samples */
|
||||
vgmstream->num_samples = fact_samples;
|
||||
vgmstream->loop_start_sample = loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
|
||||
if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamFile, start_offset));
|
||||
/* SCD loop/sample values are relative (without skip samples) vs RIFF (with skip samples), no need to adjust */
|
||||
vgmstream->loop_end_sample = loop_end + 1;
|
||||
/* loop/sample values are relative (without skip) vs RIFF (with skip), matching "smpl" otherwise */
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -391,8 +386,12 @@ VGMSTREAM * init_vgmstream_sqex_scd(STREAMFILE *streamFile) {
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = read_32bit(extradata_offset+0x10,streamFile); /* loop values above are also weird and ignored */
|
||||
vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_start
|
||||
vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, streamFile) - (loop_flag ? cfg.encoder_delay : 0); //loop_end
|
||||
vgmstream->loop_start_sample = read_32bit(extradata_offset+0x20, streamFile);
|
||||
vgmstream->loop_end_sample = read_32bit(extradata_offset+0x24, streamFile) + 1;
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample -= cfg.encoder_delay;
|
||||
vgmstream->loop_end_sample -= cfg.encoder_delay;
|
||||
}
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -176,30 +176,20 @@ VGMSTREAM * init_vgmstream_ta_aac_ps3(STREAMFILE *streamFile) {
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
{
|
||||
ffmpeg_codec_data *ffmpeg_data = NULL;
|
||||
uint8_t buf[100];
|
||||
int32_t bytes, samples_size = 1024, block_size, encoder_delay, joint_stereo, max_samples;
|
||||
block_size = (codec_id == 4 ? 0x60 : (codec_id == 5 ? 0x98 : 0xC0)) * vgmstream->channels;
|
||||
max_samples = (data_size / block_size) * samples_size;
|
||||
encoder_delay = 0x0;
|
||||
joint_stereo = 0;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
/* make a fake riff so FFmpeg can parse the ATRAC3 */
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
if (bytes <= 0) goto fail;
|
||||
block_align = (codec_id == 4 ? 0x60 : (codec_id == 5 ? 0x98 : 0xC0)) * vgmstream->channels;
|
||||
encoder_delay = 1024 + 69; /* approximate, gets good loops */
|
||||
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf, bytes, start_offset, data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->num_samples = max_samples;
|
||||
|
||||
if (loop_flag) {
|
||||
vgmstream->loop_start_sample = (loop_start / block_size) * samples_size;
|
||||
vgmstream->loop_end_sample = (loop_end / block_size) * samples_size;
|
||||
}
|
||||
|
||||
/* set offset samples (offset 0 jumps to sample 0 > pre-applied delay, and offset end loops after sample end > adjusted delay) */
|
||||
vgmstream->loop_start_sample = atrac3_bytes_to_samples(loop_start, block_align); // - encoder_delay
|
||||
vgmstream->loop_end_sample = atrac3_bytes_to_samples(loop_end, block_align) - encoder_delay;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -432,26 +432,27 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
int32_t bytes;
|
||||
|
||||
if (txth.codec == ATRAC3) {
|
||||
int block_size = txth.interleave;
|
||||
int joint_stereo;
|
||||
switch(txth.codec_mode) {
|
||||
case 0: joint_stereo = vgmstream->channels > 1 && txth.interleave/vgmstream->channels==0x60 ? 1 : 0; break; /* autodetect */
|
||||
case 1: joint_stereo = 1; break; /* force joint stereo */
|
||||
case 2: joint_stereo = 0; break; /* force stereo */
|
||||
default: goto fail;
|
||||
}
|
||||
int block_align, encoder_delay;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 200, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, txth.skip_samples);
|
||||
block_align = txth.interleave;
|
||||
encoder_delay = txth.skip_samples;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_atrac3_raw(txth.streamBody, txth.start_offset,txth.data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
}
|
||||
else if (txth.codec == ATRAC3PLUS) {
|
||||
int block_size = txth.interleave;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3plus(buf, 200, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, block_size, txth.skip_samples);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(txth.streamBody, buf,bytes, txth.start_offset,txth.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
else if (txth.codec == XMA1) {
|
||||
int xma_stream_mode = txth.codec_mode == 1 ? 1 : 0;
|
||||
|
||||
bytes = ffmpeg_make_riff_xma1(buf, 100, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, xma_stream_mode);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(txth.streamBody, buf,bytes, txth.start_offset,txth.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
else if (txth.codec == XMA2) {
|
||||
int block_count, block_size;
|
||||
@ -460,13 +461,12 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
block_count = txth.data_size / block_size;
|
||||
|
||||
bytes = ffmpeg_make_riff_xma2(buf, 200, vgmstream->num_samples, txth.data_size, vgmstream->channels, vgmstream->sample_rate, block_count, block_size);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(txth.streamBody, buf,bytes, txth.start_offset,txth.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ffmpeg_data = init_ffmpeg_header_offset(txth.streamBody, buf,bytes, txth.start_offset,txth.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
}
|
||||
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
@ -474,7 +474,7 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE *streamFile) {
|
||||
|
||||
if (txth.codec == XMA1 || txth.codec == XMA2) {
|
||||
xma_fix_raw_samples(vgmstream, txth.streamBody, txth.start_offset,txth.data_size, 0, 0,0);
|
||||
} else if (txth.skip_samples_set) { /* force encoder delay */
|
||||
} else if (txth.skip_samples_set && txth.codec != ATRAC3) { /* force encoder delay */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, txth.skip_samples);
|
||||
}
|
||||
|
||||
|
@ -360,15 +360,12 @@ static VGMSTREAM * init_vgmstream_ubi_bao_base(ubi_bao_header * bao, STREAMFILE
|
||||
|
||||
case RAW_AT3_105:
|
||||
case RAW_AT3: {
|
||||
uint8_t buf[0x100];
|
||||
int32_t bytes, block_size, encoder_delay, joint_stereo;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
block_size = (bao->codec == RAW_AT3_105 ? 0x98 : 0xc0) * vgmstream->channels;
|
||||
joint_stereo = 0;
|
||||
block_align = (bao->codec == RAW_AT3_105 ? 0x98 : 0xc0) * vgmstream->channels;
|
||||
encoder_delay = 0; /* num_samples is full bytes-to-samples (unlike FMT_AT3) and comparing X360 vs PS3 games seems ok */
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, vgmstream->num_samples, vgmstream->stream_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamData, buf, bytes, start_offset, bao->stream_size);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamData, start_offset,vgmstream->stream_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -376,16 +373,10 @@ static VGMSTREAM * init_vgmstream_ubi_bao_base(ubi_bao_header * bao, STREAMFILE
|
||||
}
|
||||
|
||||
case FMT_AT3: {
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamData, start_offset, bao->stream_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamData, start_offset, NULL);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamData, start_offset));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -566,38 +566,28 @@ static VGMSTREAM * init_vgmstream_ubi_sb_base(ubi_sb_header *sb, STREAMFILE *str
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case FMT_AT3: {
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
/* skip weird value (3, 4) in Brothers in Arms: D-Day (PSP) */
|
||||
/* skip weird value (3 or 4) in Brothers in Arms: D-Day (PSP) */
|
||||
if (read_32bitBE(start_offset+0x04,streamData) == 0x52494646) {
|
||||
VGM_LOG("UBI SB: skipping unknown value 0x%x before RIFF\n", read_32bitBE(start_offset+0x00,streamData));
|
||||
start_offset += 0x04;
|
||||
sb->stream_size -= 0x04;
|
||||
}
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamData, start_offset, sb->stream_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_riff(streamData, start_offset, NULL);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
if (ffmpeg_data->skipSamples <= 0) /* in case FFmpeg didn't get them */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, riff_get_fact_skip_samples(streamData, start_offset));
|
||||
break;
|
||||
}
|
||||
|
||||
case RAW_AT3: {
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
uint8_t buf[0x100];
|
||||
int32_t bytes, block_size, encoder_delay, joint_stereo;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
block_size = 0x98 * sb->channels;
|
||||
joint_stereo = 0;
|
||||
encoder_delay = 0x00; /* TODO: this is may be incorrect */
|
||||
block_align = 0x98 * sb->channels;
|
||||
encoder_delay = 0; /* TODO: this is may be incorrect */
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf, 0x100, sb->num_samples, sb->stream_size, sb->channels, sb->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamData, buf, bytes, start_offset, sb->stream_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamData, start_offset,sb->stream_size, sb->num_samples,sb->channels,sb->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
@ -66,34 +66,28 @@ VGMSTREAM * init_vgmstream_vawx(STREAMFILE *streamFile) {
|
||||
vgmstream->loop_start_sample = read_32bitBE(0x44,streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitBE(0x48,streamFile);
|
||||
|
||||
//todo fix loops/samples vs ATRAC3
|
||||
/* may be only applying end_skip to num_samples? */
|
||||
xma_fix_raw_samples(vgmstream, streamFile, start_offset,data_size, 0, 0,0);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7: { /* ATRAC3 */
|
||||
uint8_t buf[0x100];
|
||||
int32_t bytes, block_size, encoder_delay, joint_stereo, max_samples;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
data_size = read_32bitBE(0x54,streamFile);
|
||||
block_size = 0x98 * vgmstream->channels;
|
||||
joint_stereo = 0;
|
||||
max_samples = atrac3_bytes_to_samples(data_size, block_size);
|
||||
encoder_delay = 0x0; //max_samples - vgmstream->num_samples; /* todo not correct */
|
||||
vgmstream->num_samples = max_samples; /* use calc samples since loop points are too, breaks looping in some files otherwise */
|
||||
block_align = 0x98 * vgmstream->channels;
|
||||
encoder_delay = 1024 + 69*2; /* observed default, matches XMA (needed as many files start with garbage) */
|
||||
vgmstream->num_samples = atrac3_bytes_to_samples(data_size, block_align) - encoder_delay; /* original samples break looping in some files otherwise */
|
||||
|
||||
/* make a fake riff so FFmpeg can parse the ATRAC3 */
|
||||
bytes = ffmpeg_make_riff_atrac3(buf,0x100, vgmstream->num_samples, data_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, encoder_delay);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, start_offset,data_size);
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, start_offset,data_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->loop_start_sample = atrac3_bytes_to_samples(read_32bitBE(0x44,streamFile), block_size);
|
||||
vgmstream->loop_end_sample = atrac3_bytes_to_samples(read_32bitBE(0x48,streamFile), block_size);
|
||||
//vgmstream->loop_start_sample -= encoder_delay;
|
||||
//vgmstream->loop_end_sample -= encoder_delay;
|
||||
|
||||
/* set offset samples (offset 0 jumps to sample 0 > pre-applied delay, and offset end loops after sample end > adjusted delay) */
|
||||
vgmstream->loop_start_sample = atrac3_bytes_to_samples(read_32bitBE(0x44,streamFile), block_align); //- encoder_delay
|
||||
vgmstream->loop_end_sample = atrac3_bytes_to_samples(read_32bitBE(0x48,streamFile), block_align) - encoder_delay;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -528,16 +528,14 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
case ATRAC3: { /* Techland PS3 extension [Sniper Ghost Warrior (PS3)] */
|
||||
uint8_t buf[0x100];
|
||||
int bytes;
|
||||
int block_align, encoder_delay;
|
||||
|
||||
int block_size = xwb.block_align * vgmstream->channels;
|
||||
int joint_stereo = xwb.block_align == 0x60; /* untested, ATRAC3 default */
|
||||
int skip_samples = 0; /* unknown */
|
||||
block_align = xwb.block_align * vgmstream->channels;
|
||||
encoder_delay = 1024; /* assumed */
|
||||
vgmstream->num_samples -= encoder_delay;
|
||||
|
||||
bytes = ffmpeg_make_riff_atrac3(buf,0x100, vgmstream->num_samples, xwb.stream_size, vgmstream->channels, vgmstream->sample_rate, block_size, joint_stereo, skip_samples);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, xwb.stream_offset,xwb.stream_size);
|
||||
if ( !vgmstream->codec_data ) goto fail;
|
||||
vgmstream->codec_data = init_ffmpeg_atrac3_raw(streamFile, xwb.stream_offset,xwb.stream_size, vgmstream->num_samples,vgmstream->channels,vgmstream->sample_rate, block_align, encoder_delay);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
|
@ -1193,11 +1193,13 @@ typedef struct {
|
||||
int64_t skipSamples; // number of start samples that will be skipped (encoder delay), for looping adjustments
|
||||
int streamCount; // number of FFmpeg audio streams
|
||||
|
||||
/*** internal state ***/
|
||||
// config
|
||||
int channel_remap_set;
|
||||
int channel_remap[32]; /* map of channel > new position */
|
||||
int invert_audio_set;
|
||||
|
||||
/*** internal state ***/
|
||||
// Intermediate byte buffer
|
||||
// intermediate byte buffer
|
||||
uint8_t *sampleBuffer;
|
||||
// max samples we can held (can be less or more than frameSize)
|
||||
size_t sampleBufferBlock;
|
||||
|
Loading…
Reference in New Issue
Block a user