Minor cleanup/comments

This commit is contained in:
bnnm 2019-11-03 22:58:33 +01:00
parent e0eaffbf3f
commit 3208863d75
4 changed files with 465 additions and 508 deletions

View File

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

View File

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

View File

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

View File

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