This commit is contained in:
bnnm 2021-06-24 22:32:44 +02:00
parent 15bad97db5
commit 8c92b600fd
8 changed files with 213 additions and 217 deletions

View File

@ -1151,7 +1151,7 @@ static const meta_info meta_info_list[] = {
{meta_PS3_PAST, "SNDP header"},
{meta_SGXD, "Sony SGXD header"},
{meta_WII_RAS, "RAS header"},
{meta_PS2_SPM, "SPM header"},
{meta_SPM, "Square SPM header"},
{meta_X360_TRA, "Terminal Reality .TRA raw header"},
{meta_PS2_VGS, "Princess Soft VGS header"},
{meta_PS2_IAB, "Runtime .IAB header"},

View File

@ -1,48 +1,51 @@
#include "meta.h"
#include "../coding/coding.h"
/* AHV - from Amuze games [Headhunter (PS2)] */
VGMSTREAM * init_vgmstream_ahv(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size, channel_size, interleave;
int loop_flag, channel_count;
/* checks (.ahv: from names in bigfile) */
if ( !check_extensions(streamFile,"ahv") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x41485600) /* "AHV\0" */
goto fail;
start_offset = 0x800;
data_size = get_streamfile_size(streamFile) - start_offset;
interleave = read_32bitLE(0x10,streamFile);
channel_count = (interleave != 0) ? 2 : 1;
channel_size = read_32bitLE(0x08,streamFile);
loop_flag = 0;
/* VAGp header after 0x14 */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_AHV;
vgmstream->sample_rate = read_32bitLE(0x0c,streamFile);
vgmstream->num_samples = ps_bytes_to_samples(channel_size,1);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (interleave)
vgmstream->interleave_last_block_size = (data_size % (interleave*channel_count)) / channel_count;
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../coding/coding.h"
/* AHV - from Amuze games [Headhunter (PS2)] */
VGMSTREAM* init_vgmstream_ahv(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
size_t data_size, channel_size, interleave, sample_rate;
int loop_flag, channels;
/* checks */
/* .ahv: from names in bigfile */
if (!check_extensions(sf,"ahv"))
goto fail;
if (!is_id32be(0x00,sf, "AHV\0"))
goto fail;
start_offset = 0x800;
data_size = get_streamfile_size(sf) - start_offset;
channel_size = read_u32le(0x08,sf);
sample_rate = read_32bitLE(0x0c,sf);
interleave = read_u32le(0x10,sf);
channels = (interleave != 0) ? 2 : 1;
loop_flag = 0;
/* VAGp header after 0x14 */
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_AHV;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ps_bytes_to_samples(channel_size, 1);
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
if (interleave)
vgmstream->interleave_last_block_size = (data_size % (interleave*channels)) / channels;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -510,7 +510,7 @@ VGMSTREAM * init_vgmstream_sgxd(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_wii_ras(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_ps2_spm(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_spm(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_x360_tra(STREAMFILE* streamFile);

View File

@ -8,33 +8,37 @@
static VGMSTREAM* init_vgmstream_opus(STREAMFILE* sf, meta_t meta_type, off_t offset, int32_t num_samples, int32_t loop_start, int32_t loop_end) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag = 0, channel_count;
off_t data_offset, samples_offset, multichannel_offset = 0;
int loop_flag = 0, channels, sample_rate;
off_t data_offset, context_offset, multistream_offset = 0;
size_t data_size, skip = 0;
/* header chunk */
if (read_u32le(offset + 0x00,sf) != 0x80000001)
if (read_u32le(offset + 0x00,sf) != 0x80000001) /* 'basic info' chunk */
goto fail;
/* 0x04: chunk size */
/* 0x04: chunk size (should be 0x24) */
/* 0x08: null */
channel_count = read_u8(offset + 0x09, sf);
/* 0x0a: packet size if CBR, 0 if VBR */
/* 0x08: version (0) */
channels = read_u8(offset + 0x09, sf);
/* 0x0a: frame size if CBR, 0 if VBR */
sample_rate = read_u32le(offset + 0x0c,sf);
data_offset = read_u32le(offset + 0x10, sf);
/* 0x14: null/reserved? */
samples_offset = read_u32le(offset + 0x18, sf);
skip = read_u16le(offset + 0x1c, sf);
/* 0x1e: ? (seen in Lego Movie 2 (Switch)) */
/* 0x14: 'frame data offset' (seek table? not seen) */
context_offset = read_u32le(offset + 0x18, sf);
skip = read_u16le(offset + 0x1c, sf); /* pre-skip sample count */
/* 0x1e: officially padding (non-zero in Lego Movie 2 (Switch)) */
/* (no offset to multistream chunk, maybe meant to go after seek/context chunks?) */
/* samples chunk, rare [Famicom Detective Club (Switch)] */
if (samples_offset && read_u32le(offset + samples_offset, sf) == 0x80000003) {
/* 0x80000002: 'offset info' chunk (seek table?), not seen */
/* 'context info' chunk, rare [Famicom Detective Club (Switch)] */
if (context_offset && read_u32le(offset + context_offset, sf) == 0x80000003) {
/* maybe should give priority to external info? */
samples_offset += offset;
context_offset += offset;
/* 0x08: null*/
loop_flag = read_u8 (samples_offset + 0x09, sf);
num_samples = read_s32le(samples_offset + 0x0c, sf); /* slightly smaller than manual count */
loop_start = read_s32le(samples_offset + 0x10, sf);
loop_end = read_s32le(samples_offset + 0x14, sf);
loop_flag = read_u8 (context_offset + 0x09, sf);
num_samples = read_s32le(context_offset + 0x0c, sf); /* slightly smaller than manual count */
loop_start = read_s32le(context_offset + 0x10, sf);
loop_end = read_s32le(context_offset + 0x14, sf);
/* rest (~0x38) reserved/alignment? */
/* values seem to take encoder delay into account */
}
@ -43,13 +47,13 @@ static VGMSTREAM* init_vgmstream_opus(STREAMFILE* sf, meta_t meta_type, off_t of
}
/* multichannel chunk, rare [Clannad (Switch)] */
/* 'multistream info' chunk, rare [Clannad (Switch)] */
if (read_u32le(offset + 0x20, sf) == 0x80000005) {
multichannel_offset = offset + 0x20;
multistream_offset = offset + 0x20;
}
/* data chunk */
/* 'data info' chunk */
data_offset += offset;
if (read_u32le(data_offset, sf) != 0x80000004)
goto fail;
@ -60,13 +64,13 @@ static VGMSTREAM* init_vgmstream_opus(STREAMFILE* sf, meta_t meta_type, off_t of
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_type;
vgmstream->sample_rate = read_u32le(offset + 0x0c,sf);
vgmstream->sample_rate = sample_rate;
if (vgmstream->sample_rate == 16000)
vgmstream->sample_rate = 48000; // Grandia HD Collection contains a false sample_rate in header
vgmstream->sample_rate = 48000; // Grandia HD Collection contains a false sample_rate in header
vgmstream->num_samples = num_samples;
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
@ -80,12 +84,12 @@ static VGMSTREAM* init_vgmstream_opus(STREAMFILE* sf, meta_t meta_type, off_t of
cfg.skip = skip;
cfg.sample_rate = vgmstream->sample_rate;
if (multichannel_offset && vgmstream->channels <= 8) {
if (multistream_offset && vgmstream->channels <= 8) {
int i;
cfg.stream_count = read_u8(multichannel_offset + 0x08,sf);
cfg.coupled_count = read_u8(multichannel_offset + 0x09,sf);
cfg.stream_count = read_u8(multistream_offset + 0x08,sf);
cfg.coupled_count = read_u8(multistream_offset + 0x09,sf); /* stereo streams */
for (i = 0; i < vgmstream->channels; i++) {
cfg.channel_mapping[i] = read_u8(multichannel_offset + 0x0a + i,sf);
cfg.channel_mapping[i] = read_u8(multistream_offset + 0x0a + i,sf);
}
}
@ -174,14 +178,14 @@ VGMSTREAM* init_vgmstream_opus_capcom(STREAMFILE* sf) {
VGMSTREAM *vgmstream = NULL;
off_t offset;
int num_samples, loop_start, loop_end;
int channel_count;
int channels;
/* checks */
if ( !check_extensions(sf,"opus,lopus"))
goto fail;
channel_count = read_32bitLE(0x04,sf);
if (channel_count != 1 && channel_count != 2 && channel_count != 6)
channels = read_32bitLE(0x04,sf);
if (channels != 1 && channels != 2 && channels != 6)
goto fail; /* unknown stream layout */
num_samples = read_32bitLE(0x00,sf);
@ -196,17 +200,17 @@ VGMSTREAM* init_vgmstream_opus_capcom(STREAMFILE* sf) {
/* 0x2c: some size? */
/* 0x30+: extra chunks (0x00: 0x7f, 0x04: num_sample), alt loop starts/regions? */
if (channel_count == 6) {
if (channels == 6) {
/* 2ch multistream hacky-hacks in RE:RE, don't try this at home. We'll end up with:
* main vgmstream > N vgmstream layers > substream IO deinterleaver > opus meta > Opus IO transmogrifier (phew) */
layered_layout_data* data = NULL;
int layers = channel_count / 2;
int layers = channels / 2;
int i;
int loop_flag = (loop_end > 0);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->layout_type = layout_layered;

View File

@ -1,65 +1,54 @@
#include "meta.h"
#include "../util.h"
/* SPM (from Lethal Skies Elite Pilot: Team SW) */
VGMSTREAM * init_vgmstream_ps2_spm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
char filename[PATH_LIMIT];
off_t start_offset;
int loop_flag;
int channel_count;
/* check extension, case insensitive */
streamFile->get_name(streamFile,filename,sizeof(filename));
if (strcasecmp("spm",filename_extension(filename))) goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x53504D00) /* "SPM" */
goto fail;
loop_flag = 1;
channel_count = 2;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
/* fill in the vital statistics */
start_offset = 0x800;
vgmstream->channels = channel_count;
vgmstream->sample_rate = 48000;
vgmstream->coding_type = coding_PCM16LE;
vgmstream->num_samples = read_32bitLE(0x4,streamFile)/4;
if (loop_flag) {
vgmstream->loop_start_sample = read_32bitLE(0x8,streamFile);
vgmstream->loop_end_sample = read_32bitLE(0xC,streamFile);
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 2;
vgmstream->meta_type = meta_PS2_SPM;
/* 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"
/* SPM - Seq-PCM stream Square Sounds Co. games [Lethal Skies Elite Pilot: Team SW (PS2)] */
VGMSTREAM* init_vgmstream_spm(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int loop_flag, channels;
size_t data_size;
int32_t loop_start, loop_end;
/* checks */
/* .spm: extension from debug strings */
if (!check_extensions(sf, "spm"))
goto fail;
if (!is_id32be(0x00,sf,"SPM\0"))
goto fail;
data_size = read_u32le(0x04,sf);
loop_start = read_s32le(0x08,sf);
loop_end = read_s32le(0x0c,sf);
/* 0x10: volume? */
/* rest: null */
start_offset = 0x20;
channels = 2;
loop_flag = 1;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_SPM;
vgmstream->sample_rate = 48000;
vgmstream->num_samples = pcm16_bytes_to_samples(data_size - start_offset, channels);
vgmstream->loop_start_sample = loop_start;
vgmstream->loop_end_sample = loop_end;
vgmstream->coding_type = coding_PCM16LE;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x02;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,66 +1,66 @@
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* VS - VagStream from Square games [Final Fantasy X (PS2) voices, Unlimited Saga (PS2) voices, All Star Pro-Wrestling 2/3 (PS2) music] */
VGMSTREAM * init_vgmstream_vs_square(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
int channel_count, loop_flag, pitch, flags;
off_t start_offset;
/* checks */
/* .vs: header id (probably ok like The Bouncer's .vs, very similar) */
if (!check_extensions(streamFile, "vs"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x56530000) /* "VS\0\0" */
goto fail;
flags = read_32bitLE(0x04,streamFile);
/* 0x08: block number */
/* 0x0c: blocks left in the subfile */
pitch = read_32bitLE(0x10,streamFile); /* usually 0x1000 = 48000 */
/* 0x14: volume, usually 0x64 = 100 but may be bigger/smaller (up to 128?) */
/* 0x18: null */
/* 0x1c: null */
/* some Front Mission 4 voices have flag 0x100, no idea */
if (flags != 0x00 && flags != 0x01) {
VGM_LOG("VS: unknown flags %x\n", flags);
}
loop_flag = 0;
channel_count = (flags & 1) ? 2 : 1;
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS_SQUARE;
vgmstream->sample_rate = round10((48000 * pitch) / 4096); /* needed for rare files */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs_square;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(streamFile));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
#include "meta.h"
#include "../layout/layout.h"
#include "../coding/coding.h"
/* VS - VagStream from Square Sounds Co. games [Final Fantasy X (PS2) voices, Unlimited Saga (PS2) voices, All Star Pro-Wrestling 2/3 (PS2) music] */
VGMSTREAM* init_vgmstream_vs_square(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channels, loop_flag, pitch, flags;
off_t start_offset;
/* checks */
/* .vs: extension from debug strings (probably like The Bouncer's .vs, very similar) */
if (!check_extensions(sf, "vs"))
goto fail;
if (!is_id32be(0x00,sf,"VS\0\0"))
goto fail;
flags = read_u32le(0x04,sf);
/* 0x08: block number */
/* 0x0c: blocks left in the subfile */
pitch = read_u32le(0x10,sf); /* usually 0x1000 = 48000 */
/* 0x14: volume, usually 0x64 = 100, up to 128 [Lethal Skies / Sidewinder F (PS2)] */
/* 0x18: null */
/* 0x1c: null */
/* some Front Mission 4 voices have flag 0x100, no idea */
if (flags != 0x00 && flags != 0x01) {
VGM_LOG("VS: unknown flags %x\n", flags);
}
loop_flag = 0;
channels = (flags & 1) ? 2 : 1;
start_offset = 0x00;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_VS_SQUARE;
vgmstream->sample_rate = round10((48000 * pitch) / 4096); /* needed for rare files */
vgmstream->coding_type = coding_PSX;
vgmstream->layout_type = layout_blocked_vs_square;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
/* calc num_samples */
{
vgmstream->next_block_offset = start_offset;
do {
block_update(vgmstream->next_block_offset,vgmstream);
vgmstream->num_samples += ps_bytes_to_samples(vgmstream->current_block_size, 1);
}
while (vgmstream->next_block_offset < get_streamfile_size(sf));
block_update(start_offset, vgmstream);
}
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -265,7 +265,7 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_ps3_past,
init_vgmstream_sgxd,
init_vgmstream_wii_ras,
init_vgmstream_ps2_spm,
init_vgmstream_spm,
init_vgmstream_x360_tra,
init_vgmstream_ps2_iab,
init_vgmstream_vs_str,

View File

@ -564,7 +564,7 @@ typedef enum {
meta_PS3_PAST, /* Bakugan Battle Brawlers (PS3) */
meta_SGXD, /* Sony: Folklore, Genji, Tokyo Jungle (PS3), Brave Story, Kurohyo (PSP) */
meta_WII_RAS, /* Donkey Kong Country Returns (Wii) */
meta_PS2_SPM, /* Lethal Skies Elite Pilot: Team SW */
meta_SPM,
meta_X360_TRA, /* Def Jam Rapstar */
meta_PS2_VGS, /* Princess Soft PS2 games */
meta_PS2_IAB, /* Ueki no Housoku - Taosu ze Robert Juudan!! (PS2) */