From 310a064fd0cc16bec1c36b132c278d3253eadd3f Mon Sep 17 00:00:00 2001 From: bnnm Date: Sat, 10 Apr 2021 19:44:38 +0200 Subject: [PATCH] Add EXTS .sts_cp3+int_cp3 [Shadow of the Colossus (PS3)] --- src/formats.c | 3 ++- src/meta/exst.c | 66 +++++++++++++++++++++++++++++++++++-------------- src/meta/meta.h | 2 +- src/vgmstream.c | 2 +- src/vgmstream.h | 2 +- 5 files changed, 53 insertions(+), 22 deletions(-) diff --git a/src/formats.c b/src/formats.c index 9e8c970a..d6d58626 100644 --- a/src/formats.c +++ b/src/formats.c @@ -499,6 +499,7 @@ static const char* extension_list[] = { "stream", "strm", "sts", + "sts_cp3", "stx", "svag", "svs", @@ -930,7 +931,7 @@ static const meta_info meta_info_list[] = { {meta_RAW_INT, "PS2 .int raw header"}, {meta_PS2_OMU, "Alter Echo OMU Header"}, {meta_DSP_STM, "Intelligent Systems STM header"}, - {meta_PS2_EXST, "Sony EXST header"}, + {meta_EXST, "Sony EXST header"}, {meta_SVAG_KCET, "Konami SVAG header"}, {meta_PS_HEADERLESS, "Headerless PS-ADPCM raw header"}, {meta_MIB_MIH, "Sony MultiStream MIH+MIB header"}, diff --git a/src/meta/exst.c b/src/meta/exst.c index 5d9a7312..42e00c64 100644 --- a/src/meta/exst.c +++ b/src/meta/exst.c @@ -3,63 +3,93 @@ /* EXST - from Sony games [Shadow of the Colossus (PS2), Gacha Mecha Stadium Saru Battle (PS2)] */ -VGMSTREAM* init_vgmstream_ps2_exst(STREAMFILE* sf) { +VGMSTREAM* init_vgmstream_exst(STREAMFILE* sf) { VGMSTREAM* vgmstream = NULL; STREAMFILE* sf_body = NULL; off_t start_offset; int loop_flag, channels, sample_rate; - size_t block_size, num_blocks, loop_start_block; + int32_t interleave, num_samples, loop_start, loop_end; + size_t data_size; + int is_cp3 = 0; /* checks */ /* .sts+int: standard [Shadow of the Colossus (PS2)] (some fake .sts have manually joined header+body) - * .x: header+body [Ape Escape 3 (PS2)] */ - if (!check_extensions(sf, "sts,x")) + * .x: header+body [Ape Escape 3 (PS2)] + * .sts_cp3+int_cp3: Shadow of the Colossus (PS3) */ + if (!check_extensions(sf, "sts,sts_cp3,x")) goto fail; if (!is_id32be(0x00,sf, "EXST")) goto fail; - sf_body = open_streamfile_by_ext(sf,"int"); + /* also detectable since PS2 .sts uses blocks and PS3 offsets */ + is_cp3 = check_extensions(sf, "sts_cp3"); + + if (is_cp3) + sf_body = open_streamfile_by_ext(sf,"int_cp3"); + else + sf_body = open_streamfile_by_ext(sf,"int"); + if (sf_body) { /* separate header+body (header is 0x78) */ start_offset = 0x00; + data_size = get_streamfile_size(sf_body); } else { - /* joint header+body */ + /* joint header+body (.x and assumed .sts) */ start_offset = 0x78; + data_size = get_streamfile_size(sf); /* Gacharoku 2 has header+data but padded header (ELF has pointers + size to SOUND.PCK, and * treats them as single files, no extension but there are Sg2ExStAdpcm* calls in the ELF) */ - if ((get_streamfile_size(sf) % 0x10) == 0) + if ((data_size % 0x10) == 0) start_offset = 0x80; - if (get_streamfile_size(sf) < start_offset) + if (data_size <= start_offset) goto fail; + + data_size = data_size - start_offset; } - channels = read_u16le(0x06,sf); + channels = read_u16le(0x06,sf); sample_rate = read_u32le(0x08,sf); - loop_flag = read_u32le(0x0C,sf) == 1; - loop_start_block = read_u32le(0x10,sf); - num_blocks = read_u32le(0x14,sf); + loop_flag = read_u32le(0x0C,sf); + loop_start = read_u32le(0x10,sf); + loop_end = read_u32le(0x14,sf); /* 0x18: 0x24 config per channel? (volume+panning+etc?) */ /* rest is padding up to 0x78 */ + if (!is_cp3) { + interleave = 0x400; + loop_flag = (loop_flag == 1); + + num_samples = ps_bytes_to_samples(data_size, channels); /* same or very close to loop end */ + loop_start = ps_bytes_to_samples(loop_start * interleave * channels, channels); /* blocks */ + loop_end = ps_bytes_to_samples(loop_end * interleave * channels, channels); /* blocks */ + } + else { + interleave = 0x10; + loop_flag = !(loop_start == 0 && loop_end == data_size); /* flag always set even for jingles */ + + num_samples = ps_bytes_to_samples(data_size, channels); /* not same as loop end */ + loop_start = ps_bytes_to_samples(loop_start, channels); /* offset */ + loop_end = ps_bytes_to_samples(loop_end, channels); /* offset */ + } + /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channels, loop_flag); if (!vgmstream) goto fail; - vgmstream->meta_type = meta_PS2_EXST; + vgmstream->meta_type = meta_EXST; vgmstream->sample_rate = sample_rate; vgmstream->coding_type = coding_PSX; vgmstream->layout_type = layout_interleave; - vgmstream->interleave_block_size = 0x400; + vgmstream->interleave_block_size = interleave; - block_size = vgmstream->interleave_block_size * vgmstream->channels; - vgmstream->num_samples = ps_bytes_to_samples(num_blocks * block_size, channels); - vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start_block * block_size, channels); - vgmstream->loop_end_sample = vgmstream->num_samples; + vgmstream->num_samples = num_samples; + vgmstream->loop_start_sample = loop_start; + vgmstream->loop_end_sample = loop_end; if (!vgmstream_open_stream(vgmstream, sf_body ? sf_body : sf, start_offset)) goto fail; diff --git a/src/meta/meta.h b/src/meta/meta.h index 049eb55e..aa9d6812 100644 --- a/src/meta/meta.h +++ b/src/meta/meta.h @@ -84,7 +84,7 @@ VGMSTREAM * init_vgmstream_ps2_rxw(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_raw_int(STREAMFILE *streamFile); -VGMSTREAM * init_vgmstream_ps2_exst(STREAMFILE *streamFile); +VGMSTREAM * init_vgmstream_exst(STREAMFILE *streamFile); VGMSTREAM * init_vgmstream_svag_kcet(STREAMFILE *streamFile); diff --git a/src/vgmstream.c b/src/vgmstream.c index 0942da71..501d3256 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -46,7 +46,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { init_vgmstream_ps2_rxws, init_vgmstream_ps2_rxw, init_vgmstream_ngc_dsp_stm, - init_vgmstream_ps2_exst, + init_vgmstream_exst, init_vgmstream_svag_kcet, init_vgmstream_mib_mih, init_vgmstream_ngc_mpdsp, diff --git a/src/vgmstream.h b/src/vgmstream.h index 799bce3d..a8eb0f1d 100644 --- a/src/vgmstream.h +++ b/src/vgmstream.h @@ -361,7 +361,7 @@ typedef enum { meta_NPS, meta_PS2_RXWS, /* Sony games (Genji, Okage Shadow King, Arc The Lad Twilight of Spirits) */ meta_RAW_INT, - meta_PS2_EXST, /* Shadow of Colossus EXST */ + meta_EXST, meta_SVAG_KCET, meta_PS_HEADERLESS, /* headerless PS-ADPCM */ meta_MIB_MIH,