mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-18 07:44:43 +01:00
Minor cleanup/comments
This commit is contained in:
parent
e0eaffbf3f
commit
3208863d75
@ -1,189 +1,190 @@
|
||||
#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_floats_set = 1;
|
||||
}
|
||||
|
||||
return ffmpeg_data;
|
||||
fail:
|
||||
free_ffmpeg(ffmpeg_data);
|
||||
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_floats_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:
|
||||
free_ffmpeg(ffmpeg_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
#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_floats_set = 1;
|
||||
}
|
||||
|
||||
return ffmpeg_data;
|
||||
fail:
|
||||
free_ffmpeg(ffmpeg_data);
|
||||
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. This is probably "decoder delay"
|
||||
* also seen in codecs like MP3 */
|
||||
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_floats_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:
|
||||
free_ffmpeg(ffmpeg_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -878,7 +878,7 @@ void decode_fsb_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t *
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
|
||||
/* mono XBOX-IMA with header endianness and alt nibble expand (per hcs's decompilation) */
|
||||
/* mono XBOX-IMA with header endianness and alt nibble expand (verified vs AK test demos) */
|
||||
void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) {
|
||||
int i, sample_count = 0, num_frame;
|
||||
int32_t hist1 = stream->adpcm_history1_32;
|
||||
@ -922,17 +922,6 @@ void decode_wwise_ima(VGMSTREAM * vgmstream, VGMSTREAMCHANNEL * stream, sample_t
|
||||
stream->adpcm_history1_32 = hist1;
|
||||
stream->adpcm_step_index = step_index;
|
||||
}
|
||||
/* from hcs's analysis Wwise IMA expands nibbles slightly different, reducing dbs. Just "MUL" expand?
|
||||
<_ZN13CAkADPCMCodec12DecodeSampleEiii>: //From Wwise_v2015.1.6_Build5553_SDK.Linux
|
||||
10: 83 e0 07 and $0x7,%eax ; sample
|
||||
13: 01 c0 add %eax,%eax ; sample*2
|
||||
15: 83 c0 01 add $0x1,%eax ; sample*2+1
|
||||
18: 0f af 45 e4 imul -0x1c(%rbp),%eax ; (sample*2+1)*scale
|
||||
1c: 8d 50 07 lea 0x7(%rax),%edx ; result+7
|
||||
1f: 85 c0 test %eax,%eax ; result negative?
|
||||
21: 0f 48 c2 cmovs %edx,%eax ; adjust if negative to fix rounding for below division
|
||||
24: c1 f8 03 sar $0x3,%eax ; (sample*2+1)*scale/8
|
||||
*/
|
||||
|
||||
/* MS-IMA with possibly the XBOX-IMA model of even number of samples per block (more tests are needed) */
|
||||
void decode_awc_ima(VGMSTREAMCHANNEL * stream, sample_t * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do) {
|
||||
|
@ -1,117 +1,84 @@
|
||||
#include "meta.h"
|
||||
#include "../util.h"
|
||||
|
||||
/* 2PFS (Konami)
|
||||
- Mahoromatic: Moetto - KiraKira Maid-San (PS2) [.2pfs (V1, 2003)]
|
||||
- GANTZ The Game (PS2) [.sap (V2, 2005)]
|
||||
|
||||
There are two versions of the format, though they use different extensions.
|
||||
Implemented both versions here in case there are .2pfs with the V2 header out there.
|
||||
Both loop correctly AFAIK (there is a truncated Mahoromatic rip around, beware).
|
||||
*/
|
||||
VGMSTREAM * init_vgmstream_ps2_2pfs(STREAMFILE *streamFile)
|
||||
{
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
char filename[PATH_LIMIT];
|
||||
|
||||
off_t start_offset = 0x800;
|
||||
int interleave = 0x1000;
|
||||
|
||||
int loop_flag;
|
||||
int channel_count;
|
||||
int version; /* v1=1, v2=2 */
|
||||
|
||||
int loop_start_block; /* block number where the loop starts */
|
||||
int loop_end_block; /* usually the last block */
|
||||
int loop_start_sample_adjust; /* loops start/end a few samples into the start/end block */
|
||||
int loop_end_sample_adjust;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
streamFile->get_name(streamFile,filename,sizeof(filename));
|
||||
if ( strcasecmp("2pfs",filename_extension(filename))
|
||||
&& strcasecmp("sap",filename_extension(filename)) )
|
||||
goto fail;
|
||||
|
||||
/* check header ("2PFS") */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x32504653)
|
||||
goto fail;
|
||||
|
||||
version = read_16bitLE(0x04,streamFile);
|
||||
if ( version!=0x01 && version!=0x02 )
|
||||
goto fail;
|
||||
|
||||
|
||||
channel_count = read_8bit(0x40,streamFile);
|
||||
loop_flag = read_8bit(0x41,streamFile);
|
||||
/* other header values
|
||||
* 0x06 (4): unknown, v1=0x0004 v2=0x0001
|
||||
* 0x08 (32): unique file id
|
||||
* 0x0c (32): base header size (v1=0x50, v2=0x60) + datasize (without the 0x800 full header size)
|
||||
* 0x10-0x30: unknown (v1 differs from v2)
|
||||
* 0x38-0x40: unknown (v1 same as v2)
|
||||
* 0x4c (32) in V2: unknown, some kind of total samples?
|
||||
*/
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
/* fill in the vital statistics */
|
||||
vgmstream->channels = channel_count;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->num_samples = read_32bitLE(0x34,streamFile) * 28 / 16 / channel_count;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
vgmstream->meta_type = meta_PS2_2PFS;
|
||||
|
||||
if ( version==0x01 ) {
|
||||
vgmstream->sample_rate = read_32bitLE(0x44,streamFile);
|
||||
loop_start_sample_adjust = read_16bitLE(0x42,streamFile);
|
||||
loop_start_block = read_32bitLE(0x48,streamFile);
|
||||
loop_end_block = read_32bitLE(0x4c,streamFile);
|
||||
} else {
|
||||
vgmstream->sample_rate = read_32bitLE(0x48,streamFile);
|
||||
loop_start_sample_adjust = read_32bitLE(0x44,streamFile);
|
||||
loop_start_block = read_32bitLE(0x50,streamFile);
|
||||
loop_end_block = read_32bitLE(0x54,streamFile);
|
||||
}
|
||||
loop_end_sample_adjust = interleave; /* loops end after all samples in the end_block AFAIK */
|
||||
|
||||
if ( loop_flag ) {
|
||||
/* block to offset > offset to sample + adjust (number of samples into the block) */
|
||||
vgmstream->loop_start_sample = ((loop_start_block * channel_count * interleave)
|
||||
* 28 / 16 / channel_count)
|
||||
+ (loop_start_sample_adjust * 28 / 16);
|
||||
vgmstream->loop_end_sample = ((loop_end_block * channel_count * interleave)
|
||||
* 28 / 16 / channel_count)
|
||||
+ (loop_end_sample_adjust * 28 / 16);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* open the file for reading */
|
||||
{
|
||||
int i;
|
||||
STREAMFILE * file;
|
||||
file = streamFile->open(streamFile,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
|
||||
if (!file) goto fail;
|
||||
|
||||
for (i=0;i<channel_count;i++)
|
||||
{
|
||||
vgmstream->ch[i].streamfile = file;
|
||||
|
||||
vgmstream->ch[i].channel_start_offset =
|
||||
vgmstream->ch[i].offset =
|
||||
start_offset + (vgmstream->interleave_block_size * i);
|
||||
}
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
/* clean up anything we may have opened */
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* 2PFS - from Konami Games [Mahoromatic: Moetto - KiraKira Maid-San (PS2), GANTZ The Game (PS2)] */
|
||||
VGMSTREAM * init_vgmstream_ps2_2pfs(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channel_count, version, interleave;
|
||||
int loop_start_block, loop_end_block; /* block number */
|
||||
int loop_start_adjust, loop_end_adjust; /* loops start/end a few samples into the start/end block */
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .sap: standard
|
||||
* .2psf: header id? (Mahoromatic) */
|
||||
if (!check_extensions(streamFile, "sap,2psf"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) != 0x32504653) /* "2PFS" */
|
||||
goto fail;
|
||||
|
||||
version = read_16bitLE(0x04,streamFile);
|
||||
if (version != 0x01 && version != 0x02) /* v1: Mahoromatic, v2: Gantz */
|
||||
goto fail;
|
||||
|
||||
|
||||
channel_count = read_8bit(0x40,streamFile);
|
||||
loop_flag = read_8bit(0x41,streamFile);
|
||||
start_offset = 0x800;
|
||||
interleave = 0x1000;
|
||||
|
||||
/* other header values
|
||||
* 0x06: unknown, v1=0x0004 v2=0x0001
|
||||
* 0x08: unique file id
|
||||
* 0x0c: base header size (v1=0x50, v2=0x60) + datasize (without the 0x800 full header size)
|
||||
* 0x10-0x30: unknown (v1 differs from v2)
|
||||
* 0x38-0x40: unknown (v1 same as v2)
|
||||
* 0x4c: unknown, some kind of total samples? (v2 only)
|
||||
*/
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_PS2_2PFS;
|
||||
vgmstream->num_samples = read_32bitLE(0x34,streamFile) * 28 / 16 / channel_count;
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = interleave;
|
||||
|
||||
if (version == 0x01) {
|
||||
vgmstream->sample_rate = read_32bitLE(0x44,streamFile);
|
||||
loop_start_adjust = read_16bitLE(0x42,streamFile);
|
||||
loop_start_block = read_32bitLE(0x48,streamFile);
|
||||
loop_end_block = read_32bitLE(0x4c,streamFile);
|
||||
}
|
||||
else {
|
||||
vgmstream->sample_rate = read_32bitLE(0x48,streamFile);
|
||||
loop_start_adjust = read_32bitLE(0x44,streamFile);
|
||||
loop_start_block = read_32bitLE(0x50,streamFile);
|
||||
loop_end_block = read_32bitLE(0x54,streamFile);
|
||||
}
|
||||
loop_end_adjust = interleave; /* loops end after all samples in the end_block AFAIK */
|
||||
|
||||
if (loop_flag) {
|
||||
/* block to offset > offset to sample + adjust (number of frames into the block) */
|
||||
vgmstream->loop_start_sample =
|
||||
ps_bytes_to_samples(loop_start_block * channel_count * interleave, channel_count)
|
||||
+ ps_bytes_to_samples(loop_start_adjust * channel_count, channel_count);
|
||||
vgmstream->loop_end_sample =
|
||||
ps_bytes_to_samples(loop_end_block * channel_count * interleave, channel_count)
|
||||
+ ps_bytes_to_samples(loop_end_adjust * channel_count, channel_count);
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (vgmstream) close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
380
src/meta/sgxd.c
380
src/meta/sgxd.c
@ -1,190 +1,190 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */
|
||||
VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
off_t start_offset, data_offset, chunk_offset, name_offset = 0;
|
||||
size_t stream_size;
|
||||
|
||||
int is_sgx, is_sgb = 0;
|
||||
int loop_flag, channels, type;
|
||||
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
/* .sgx: header+data (Genji), .sgd: header+data, .sgh/sgd: header/data */
|
||||
if (!check_extensions(streamFile,"sgx,sgd,sgb"))
|
||||
goto fail;
|
||||
is_sgx = check_extensions(streamFile,"sgx");
|
||||
is_sgb = check_extensions(streamFile,"sgb");
|
||||
|
||||
/* SGB+SGH: use SGH as header; otherwise use the current file as header */
|
||||
if (is_sgb) {
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "sgh");
|
||||
if (!streamHeader) goto fail;
|
||||
} else {
|
||||
streamHeader = streamFile;
|
||||
}
|
||||
|
||||
|
||||
/* SGXD base (size 0x10) */
|
||||
if (read_32bitBE(0x00,streamHeader) != 0x53475844) /* "SGXD" */
|
||||
goto fail;
|
||||
/* 0x04 SGX: full header_size; SGD/SGH: unknown header_size (counting from 0x0/0x8/0x10, varies) */
|
||||
/* 0x08 SGX: first chunk offset? (0x10); SGD/SGH: full header_size */
|
||||
/* 0x0c SGX/SGH: full data size with padding; SGD: full data size + 0x80000000 with padding */
|
||||
if (is_sgb) {
|
||||
data_offset = 0x00;
|
||||
} else if ( is_sgx ) {
|
||||
data_offset = read_32bitLE(0x04,streamHeader);
|
||||
} else {
|
||||
data_offset = read_32bitLE(0x08,streamHeader);
|
||||
}
|
||||
|
||||
|
||||
/* typical chunks: WAVE, RGND, NAME (strings for WAVE or RGND), SEQD (related to SFX), WSUR, WMKR, BUSS */
|
||||
/* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */
|
||||
if (is_sgx) { /* position after chunk+size */
|
||||
if (read_32bitBE(0x10,streamHeader) != 0x57415645) goto fail; /* "WAVE" */
|
||||
chunk_offset = 0x18;
|
||||
} else {
|
||||
if (!find_chunk_le(streamHeader, 0x57415645,0x10,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */
|
||||
}
|
||||
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
|
||||
|
||||
/* check multi-streams (usually only SE containers; Puppeteer) */
|
||||
total_subsongs = read_32bitLE(chunk_offset+0x04,streamHeader);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
/* read stream header */
|
||||
{
|
||||
off_t stream_offset;
|
||||
chunk_offset += 0x08 + 0x38 * (target_subsong-1); /* position in target header*/
|
||||
|
||||
/* 0x00 ? (00/01/02) */
|
||||
if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */
|
||||
name_offset = read_32bitLE(chunk_offset+0x04,streamHeader);
|
||||
type = read_8bit(chunk_offset+0x08,streamHeader);
|
||||
channels = read_8bit(chunk_offset+0x09,streamHeader);
|
||||
/* 0x0a null */
|
||||
sample_rate = read_32bitLE(chunk_offset+0x0c,streamHeader);
|
||||
|
||||
/* 0x10 info_type: meaning of the next value
|
||||
* (00=null, 30/40=data size without padding (ADPCM, ATRAC3plus), 80/A0=block size (AC3) */
|
||||
/* 0x14 info_value (see above) */
|
||||
/* 0x18 unknown (ex. 0x0008/0010/3307/CC02/etc)x2 */
|
||||
/* 0x1c null */
|
||||
|
||||
num_samples = read_32bitLE(chunk_offset+0x20,streamHeader);
|
||||
loop_start_sample = read_32bitLE(chunk_offset+0x24,streamHeader);
|
||||
loop_end_sample = read_32bitLE(chunk_offset+0x28,streamHeader);
|
||||
stream_size = read_32bitLE(chunk_offset+0x2c,streamHeader); /* stream size (without padding) / interleave (for type3) */
|
||||
|
||||
if (is_sgx) {
|
||||
stream_offset = 0x0;
|
||||
} else{
|
||||
stream_offset = read_32bitLE(chunk_offset+0x30,streamHeader);
|
||||
}
|
||||
/* 0x34 SGX: unknown; SGD/SGH: stream size (with padding) / interleave */
|
||||
|
||||
loop_flag = loop_start_sample!=0xffffffff && loop_end_sample!=0xffffffff;
|
||||
start_offset = data_offset + stream_offset;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_SGXD;
|
||||
if (name_offset)
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
||||
|
||||
switch (type) {
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x02: /* Ogg Vorbis [Ni no Kuni: Wrath of the White Witch Remastered (PC)] (codec hijack?) */
|
||||
vgmstream->codec_data = init_ogg_vorbis(streamFile, start_offset, stream_size, NULL);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_OGG_VORBIS;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
#endif
|
||||
case 0x03: /* PS-ADPCM [Genji (PS3), Ape Escape Move (PS3)]*/
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (is_sgx || is_sgb) {
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
} else { /* this only seems to happen with SFX */
|
||||
vgmstream->interleave_block_size = stream_size;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x04: { /* ATRAC3plus [Kurohyo 1/2 (PSP), BraveStory (PSP)] */
|
||||
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;
|
||||
|
||||
/* 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
|
||||
case 0x05: /* Short PS-ADPCM [Afrika (PS3)] */
|
||||
vgmstream->coding_type = coding_PSX_cfg;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x4;
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x06: { /* AC3 [Tokyo Jungle (PS3), Afrika (PS3)] */
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, stream_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
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) {
|
||||
/* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples.
|
||||
* Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, 256);
|
||||
}
|
||||
/* SGXD loop/sample values are relative (without skip samples), no need to adjust */
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
if (is_sgb && streamHeader) close_streamfile(streamHeader);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (is_sgb && streamHeader) close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
|
||||
/* SGXD - Sony/SCEI's format (SGB+SGH / SGD / SGX) */
|
||||
VGMSTREAM * init_vgmstream_sgxd(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE * streamHeader = NULL;
|
||||
off_t start_offset, data_offset, chunk_offset, name_offset = 0;
|
||||
size_t stream_size;
|
||||
|
||||
int is_sgx, is_sgb = 0;
|
||||
int loop_flag, channels, type;
|
||||
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
|
||||
|
||||
/* check extension, case insensitive */
|
||||
/* .sgx: header+data (Genji), .sgd: header+data, .sgh/sgd: header/data */
|
||||
if (!check_extensions(streamFile,"sgx,sgd,sgb"))
|
||||
goto fail;
|
||||
is_sgx = check_extensions(streamFile,"sgx");
|
||||
is_sgb = check_extensions(streamFile,"sgb");
|
||||
|
||||
/* SGB+SGH: use SGH as header; otherwise use the current file as header */
|
||||
if (is_sgb) {
|
||||
streamHeader = open_streamfile_by_ext(streamFile, "sgh");
|
||||
if (!streamHeader) goto fail;
|
||||
} else {
|
||||
streamHeader = streamFile;
|
||||
}
|
||||
|
||||
|
||||
/* SGXD base (size 0x10) */
|
||||
if (read_32bitBE(0x00,streamHeader) != 0x53475844) /* "SGXD" */
|
||||
goto fail;
|
||||
/* 0x04 SGX: full header_size; SGD/SGH: unknown header_size (counting from 0x0/0x8/0x10, varies) */
|
||||
/* 0x08 SGX: first chunk offset? (0x10); SGD/SGH: full header_size */
|
||||
/* 0x0c SGX/SGH: full data size with padding; SGD: full data size + 0x80000000 with padding */
|
||||
if (is_sgb) {
|
||||
data_offset = 0x00;
|
||||
} else if ( is_sgx ) {
|
||||
data_offset = read_32bitLE(0x04,streamHeader);
|
||||
} else {
|
||||
data_offset = read_32bitLE(0x08,streamHeader);
|
||||
}
|
||||
|
||||
|
||||
/* typical chunks: WAVE, RGND, NAME (strings for WAVE or RGND), SEQD (related to SFX), WSUR, WMKR, BUSS */
|
||||
/* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */
|
||||
if (is_sgx) { /* position after chunk+size */
|
||||
if (read_32bitBE(0x10,streamHeader) != 0x57415645) goto fail; /* "WAVE" */
|
||||
chunk_offset = 0x18;
|
||||
} else {
|
||||
if (!find_chunk_le(streamHeader, 0x57415645,0x10,0, &chunk_offset,NULL)) goto fail; /* "WAVE" */
|
||||
}
|
||||
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
|
||||
|
||||
/* check multi-streams (usually only SE containers; Puppeteer) */
|
||||
total_subsongs = read_32bitLE(chunk_offset+0x04,streamHeader);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
/* read stream header */
|
||||
{
|
||||
off_t stream_offset;
|
||||
chunk_offset += 0x08 + 0x38 * (target_subsong-1); /* position in target header*/
|
||||
|
||||
/* 0x00 ? (00/01/02) */
|
||||
if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */
|
||||
name_offset = read_32bitLE(chunk_offset+0x04,streamHeader);
|
||||
type = read_8bit(chunk_offset+0x08,streamHeader);
|
||||
channels = read_8bit(chunk_offset+0x09,streamHeader);
|
||||
/* 0x0a null */
|
||||
sample_rate = read_32bitLE(chunk_offset+0x0c,streamHeader);
|
||||
|
||||
/* 0x10 info_type: meaning of the next value
|
||||
* (00=null, 30/40=data size without padding (ADPCM, ATRAC3plus), 80/A0=block size (AC3) */
|
||||
/* 0x14 info_value (see above) */
|
||||
/* 0x18 unknown (ex. 0x0008/0010/3307/CC02/etc)x2 */
|
||||
/* 0x1c null */
|
||||
|
||||
num_samples = read_32bitLE(chunk_offset+0x20,streamHeader);
|
||||
loop_start_sample = read_32bitLE(chunk_offset+0x24,streamHeader);
|
||||
loop_end_sample = read_32bitLE(chunk_offset+0x28,streamHeader);
|
||||
stream_size = read_32bitLE(chunk_offset+0x2c,streamHeader); /* stream size (without padding) / interleave (for type3) */
|
||||
|
||||
if (is_sgx) {
|
||||
stream_offset = 0x0;
|
||||
} else{
|
||||
stream_offset = read_32bitLE(chunk_offset+0x30,streamHeader);
|
||||
}
|
||||
/* 0x34 SGX: unknown; SGD/SGH: stream size (with padding) / interleave */
|
||||
|
||||
loop_flag = loop_start_sample!=0xffffffff && loop_end_sample!=0xffffffff;
|
||||
start_offset = data_offset + stream_offset;
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels,loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
vgmstream->num_samples = num_samples;
|
||||
vgmstream->loop_start_sample = loop_start_sample;
|
||||
vgmstream->loop_end_sample = loop_end_sample;
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
vgmstream->stream_size = stream_size;
|
||||
vgmstream->meta_type = meta_SGXD;
|
||||
if (name_offset)
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamHeader);
|
||||
|
||||
switch (type) {
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x02: /* Ogg Vorbis [Ni no Kuni: Wrath of the White Witch Remastered (PC)] (codec hijack?) */
|
||||
vgmstream->codec_data = init_ogg_vorbis(streamFile, start_offset, stream_size, NULL);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_OGG_VORBIS;
|
||||
vgmstream->layout_type = layout_none;
|
||||
break;
|
||||
#endif
|
||||
case 0x03: /* PS-ADPCM [Genji (PS3), Ape Escape Move (PS3)]*/
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
if (is_sgx || is_sgb) {
|
||||
vgmstream->interleave_block_size = 0x10;
|
||||
} else { /* this only seems to happen with SFX */
|
||||
vgmstream->interleave_block_size = stream_size;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x04: { /* ATRAC3plus [Kurohyo 1/2 (PSP), BraveStory (PSP)] */
|
||||
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;
|
||||
|
||||
/* 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
|
||||
case 0x05: /* Short PS-ADPCM [Afrika (PS3)] */
|
||||
vgmstream->coding_type = coding_PSX_cfg;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x4;
|
||||
|
||||
break;
|
||||
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x06: { /* AC3 [Tokyo Jungle (PS3), Afrika (PS3)] */
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset, stream_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
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) {
|
||||
/* PS3 AC3 consistently has 256 encoder delay samples, and there are ~1000-2000 samples after num_samples.
|
||||
* Skipping them marginally improves full loops in some Tokyo Jungle tracks (ex. a_1.sgd). */
|
||||
ffmpeg_set_skip_samples(ffmpeg_data, 256);
|
||||
}
|
||||
/* SGXD loop/sample values are relative (without skip samples), no need to adjust */
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
goto fail;
|
||||
|
||||
if (is_sgb && streamHeader) close_streamfile(streamHeader);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
if (is_sgb && streamHeader) close_streamfile(streamHeader);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user