mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 00:20:47 +01:00
Fix some .vas + unify variations [TMNT 2: Battle Nexus (PC)]
This commit is contained in:
parent
59d3c8fea1
commit
56f21fa810
@ -1,43 +1,165 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
typedef enum { PSX, DSP, IMA, PCM } vas_codec_t;
|
||||
|
||||
/* .VAS - from Konami Computer Enterntainment Osaka games [Jikkyou Powerful Pro Yakyuu 8 (PS2), Jikkyou World Soccer 2000 (PS2)] */
|
||||
/* .VAS - from Konami Computer Enterntainment Osaka games [Jikkyou Powerful Pro Yakyuu 8 (PS2), TMNT 2: Battle Nexus (multi)] */
|
||||
VGMSTREAM* init_vgmstream_vas_kceo(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int loop_flag, channels;
|
||||
int loop_flag, channels, block_size, sample_rate, volume, dummy;
|
||||
uint32_t loop_start, loop_end, data_size;
|
||||
vas_codec_t codec;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "vas"))
|
||||
return NULL;
|
||||
if (read_u32le(0x00,sf) + 0x800 != get_streamfile_size(sf))
|
||||
/* .vas: bigfile extension (internally files just seem to be referred as 'bgm' or 'stream')
|
||||
* .dsp: assumed (GC bigfile is just .bin and has no table) */
|
||||
if (!check_extensions(sf, "vas,dsp"))
|
||||
return NULL;
|
||||
|
||||
if (read_u32le(0x00, sf) == 0x01) { /* PC */
|
||||
channels = read_u32le(0x04, sf);
|
||||
block_size = read_u32le(0x08, sf);
|
||||
sample_rate = read_s32le(0x0c, sf);
|
||||
loop_start = read_u32le(0x10, sf);
|
||||
loop_end = read_u32le(0x14, sf);
|
||||
volume = read_u32le(0x18, sf);
|
||||
loop_flag = read_u32le(0x1c, sf) != 0; // unknown size (low-ish), 0 if no loop
|
||||
// 20: 0x8000 if loop?
|
||||
data_size = read_u32le(0x24, sf);
|
||||
// 28: null?
|
||||
// 2c: null?
|
||||
dummy = read_u32le(0x30, sf);
|
||||
|
||||
if (block_size != channels * 0x02)
|
||||
return NULL;
|
||||
codec = PCM;
|
||||
}
|
||||
else if (read_u32le(0x00, sf) == 0x69) { /* Xbox */
|
||||
channels = read_u32le(0x04, sf);
|
||||
block_size = read_u32le(0x08, sf);
|
||||
sample_rate = read_s32le(0x0c, sf);
|
||||
loop_start = read_u32le(0x10, sf);
|
||||
loop_end = read_u32le(0x14, sf);
|
||||
volume = read_u32le(0x18, sf);
|
||||
loop_flag = read_u32le(0x1c, sf) != 0; // unknown size (low-ish), 0 if no loop
|
||||
// 20: 0x8000 if loop?
|
||||
data_size = read_u32le(0x24, sf);
|
||||
// 28: null or some kind of hash (TMNT3)
|
||||
// 2c: null or codec + channels (TMNT3)
|
||||
dummy = read_u32le(0x30, sf);
|
||||
|
||||
if (block_size != channels * 0x24)
|
||||
return NULL;
|
||||
codec = IMA;
|
||||
}
|
||||
else if (read_u32le(0x00,sf) + 0x800 == get_streamfile_size(sf)) { /* PS2 */
|
||||
data_size = read_u32le(0x00, sf);
|
||||
sample_rate = read_s32le(0x04,sf);
|
||||
volume = read_u32le(0x08, sf);
|
||||
dummy = read_u32le(0x0c, sf);
|
||||
loop_flag = read_u32le(0x10, sf) != 0; // 0/1
|
||||
loop_start = read_u32le(0x14,sf);
|
||||
|
||||
channels = 2;
|
||||
codec = PSX;
|
||||
|
||||
loop_end = data_size;
|
||||
|
||||
if (!ps_check_format(sf, 0x800, 0x1000))
|
||||
return NULL;
|
||||
}
|
||||
else if (read_u32be(0x00,sf) + 0x800 == get_streamfile_size(sf)) { /* GC */
|
||||
data_size = read_u32be(0x00, sf);
|
||||
sample_rate = read_s32be(0x04,sf);
|
||||
volume = read_u32be(0x08, sf);
|
||||
dummy = read_u32be(0x0c, sf);
|
||||
loop_flag = read_u32be(0x10, sf) != 0; // 0/1
|
||||
loop_start = read_u32be(0x14,sf);
|
||||
|
||||
channels = 2;
|
||||
codec = DSP;
|
||||
|
||||
loop_end = data_size;
|
||||
|
||||
// DSP header variation at 0x80 (loop_end seems smaller but not correct?)
|
||||
if (read_u32be(0x8c, sf) != 0x0002) // codec
|
||||
return NULL;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* simple header so do a few extra checks */
|
||||
if (channels != 2) // voices have a slightly different, simpler format
|
||||
return NULL;
|
||||
if (sample_rate > 48000 || sample_rate < 8000)
|
||||
return NULL;
|
||||
if (volume <= 0x00 || volume > 0xFF) /* typically 0x96, some PS2 use ~0xC0 */
|
||||
return NULL;
|
||||
if (dummy != 0)
|
||||
return NULL;
|
||||
|
||||
loop_flag = (read_u32le(0x10,sf) != 0);
|
||||
channels = 2;
|
||||
start_offset = 0x800;
|
||||
|
||||
/* header is too simple so test a bit */
|
||||
if (!ps_check_format(sf, start_offset, 0x1000))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channels, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->meta_type = meta_VAS_KCEO;
|
||||
vgmstream->sample_rate = read_s32le(0x04,sf);
|
||||
vgmstream->sample_rate = sample_rate;
|
||||
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x200;
|
||||
switch (codec) {
|
||||
case PCM:
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x02;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(read_u32le(0x00,sf), channels);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(read_u32le(0x14,sf), channels);
|
||||
vgmstream->loop_end_sample = vgmstream->num_samples;
|
||||
vgmstream->num_samples = pcm16_bytes_to_samples(data_size, vgmstream->channels);
|
||||
vgmstream->loop_start_sample = pcm16_bytes_to_samples(loop_start, vgmstream->channels);
|
||||
vgmstream->loop_end_sample = pcm16_bytes_to_samples(loop_end, vgmstream->channels);
|
||||
break;
|
||||
|
||||
case IMA:
|
||||
vgmstream->coding_type = coding_XBOX_IMA;
|
||||
vgmstream->layout_type = layout_blocked_xvas;
|
||||
|
||||
/* blocks of 0x20000 with padding */
|
||||
data_size -= (data_size / 0x20000) * 0x20;
|
||||
loop_start -= (loop_start / 0x20000) * 0x20;
|
||||
loop_end -= (loop_end / 0x20000) * 0x20;
|
||||
|
||||
vgmstream->num_samples = xbox_ima_bytes_to_samples(data_size, vgmstream->channels);
|
||||
vgmstream->loop_start_sample = xbox_ima_bytes_to_samples(loop_start, vgmstream->channels);
|
||||
vgmstream->loop_end_sample = xbox_ima_bytes_to_samples(loop_end, vgmstream->channels);
|
||||
break;
|
||||
|
||||
case PSX:
|
||||
vgmstream->coding_type = coding_PSX;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x200;
|
||||
|
||||
vgmstream->num_samples = ps_bytes_to_samples(data_size, channels);
|
||||
vgmstream->loop_start_sample = ps_bytes_to_samples(loop_start, channels);
|
||||
vgmstream->loop_end_sample = ps_bytes_to_samples(loop_end, channels);
|
||||
break;
|
||||
|
||||
case DSP:
|
||||
vgmstream->coding_type = coding_NGC_DSP;
|
||||
vgmstream->layout_type = layout_interleave;
|
||||
vgmstream->interleave_block_size = 0x100;
|
||||
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(data_size, channels);
|
||||
vgmstream->loop_start_sample = dsp_bytes_to_samples(loop_start, channels);
|
||||
vgmstream->loop_end_sample = dsp_bytes_to_samples(loop_end, channels);
|
||||
|
||||
dsp_read_coefs_be(vgmstream, sf, 0x90, 0x40);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
|
||||
goto fail;
|
||||
@ -53,8 +175,8 @@ fail:
|
||||
VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset = 0;
|
||||
size_t subfile_size = 0;
|
||||
uint32_t subfile_offset = 0;
|
||||
uint32_t subfile_size = 0;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
@ -62,23 +184,26 @@ VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
|
||||
if (!check_extensions(sf, "vas"))
|
||||
return NULL;
|
||||
|
||||
if (read_u32be(0x00, sf) == 0xAB8A5A00) { /* fixed value */
|
||||
if (read_u32be(0x00, sf) == 0xAB8A5A00) { /* PS2 (fixed value) */
|
||||
|
||||
/* just in case */
|
||||
/* unknown size/id */
|
||||
if (read_u32le(0x04, sf) * 0x800 + 0x800 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
return NULL;
|
||||
|
||||
total_subsongs = read_s32le(0x08, sf); /* also at 0x10 */
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
if (total_subsongs > 0x100) /* arbitrary max */
|
||||
return NULL;
|
||||
|
||||
/* check offset table flag, 0x98 has table size */
|
||||
if (read_32bitLE(0x94, sf)) {
|
||||
if (read_u32le(0x94, sf)) {
|
||||
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,sf) * 0x800;
|
||||
subfile_size = read_32bitLE(header_offset + 0x08,sf) + 0x800;
|
||||
subfile_offset = read_u32le(header_offset + 0x00,sf) * 0x800;
|
||||
subfile_size = read_u32le(header_offset + 0x08,sf) + 0x800;
|
||||
}
|
||||
else {
|
||||
/* a bunch of files */
|
||||
@ -86,7 +211,7 @@ VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < total_subsongs; i++) {
|
||||
size_t size = read_32bitLE(offset, sf) + 0x800;
|
||||
size_t size = read_u32le(offset, sf) + 0x800;
|
||||
|
||||
if (i + 1 == target_subsong) {
|
||||
subfile_offset = offset;
|
||||
@ -97,23 +222,43 @@ VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
|
||||
offset += size;
|
||||
}
|
||||
if (i == total_subsongs)
|
||||
goto fail;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else if (read_u32le(0x00, sf) == 0x800) { /* Xbox/PC (start?) */
|
||||
VGM_STEP();
|
||||
|
||||
total_subsongs = read_s32le(0x04, sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
if (total_subsongs > 0x100) /* arbitrary max */
|
||||
return NULL;
|
||||
if (read_u32le(0x08, sf) != 0x800)
|
||||
return NULL;
|
||||
|
||||
/* table of offset + ? size */
|
||||
uint32_t header_offset = 0x08 + 0x08 * (target_subsong - 1);
|
||||
subfile_offset = read_u32le(header_offset + 0x00,sf);
|
||||
uint32_t next_offset = (target_subsong == total_subsongs) ?
|
||||
get_streamfile_size(sf) :
|
||||
read_u32le(header_offset + 0x08,sf);
|
||||
subfile_size = next_offset - subfile_offset;
|
||||
}
|
||||
else {
|
||||
/* some .vas are just files pasted together, better extracted externally but whatevs */
|
||||
size_t file_size = get_streamfile_size(sf);
|
||||
off_t offset = 0;
|
||||
uint32_t file_size = get_streamfile_size(sf);
|
||||
uint32_t offset = 0;
|
||||
|
||||
/* must have multiple .vas */
|
||||
if (read_32bitLE(0x00,sf) + 0x800 >= file_size)
|
||||
if (read_u32le(0x00,sf) + 0x800 >= file_size)
|
||||
goto fail;
|
||||
|
||||
total_subsongs = 0;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
|
||||
while (offset < file_size) {
|
||||
size_t size = read_32bitLE(offset,sf) + 0x800;
|
||||
uint32_t size = read_u32le(offset,sf) + 0x800;
|
||||
|
||||
/* some files can be null, ignore */
|
||||
if (size > 0x800) {
|
||||
@ -136,7 +281,7 @@ VGMSTREAM* init_vgmstream_vas_kceo_container(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset,subfile_size, NULL);
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_vas_kceo(temp_sf);
|
||||
|
Loading…
Reference in New Issue
Block a user