Add Silicon Knights .AUD + SK Vorbis [Eternal Darkness (GC)]

This commit is contained in:
bnnm 2017-07-29 11:46:53 +02:00
parent fcf8a9485c
commit 54ef2b5190
11 changed files with 296 additions and 9 deletions

View File

@ -49,7 +49,7 @@ vorbis_custom_codec_data * init_vorbis_custom_codec_data(STREAMFILE *streamFile,
case VORBIS_FSB: ok = vorbis_custom_setup_init_fsb(streamFile, start_offset, data); break;
case VORBIS_WWISE: ok = vorbis_custom_setup_init_wwise(streamFile, start_offset, data); break;
case VORBIS_OGL: ok = vorbis_custom_setup_init_ogl(streamFile, start_offset, data); break;
//case VORBIS_SK: ok = vorbis_custom_setup_init_sk(streamFile, start_offset, data); break;
case VORBIS_SK: ok = vorbis_custom_setup_init_sk(streamFile, start_offset, data); break;
default: goto fail;
}
if(!ok) goto fail;
@ -130,10 +130,14 @@ void decode_vorbis_custom(VGMSTREAM * vgmstream, sample * outbuf, int32_t sample
case VORBIS_FSB: ok = vorbis_custom_parse_packet_fsb(stream, data); break;
case VORBIS_WWISE: ok = vorbis_custom_parse_packet_wwise(stream, data); break;
case VORBIS_OGL: ok = vorbis_custom_parse_packet_ogl(stream, data); break;
//case VORBIS_SK: ok = vorbis_custom_parse_packet_sk(stream, data); break;
case VORBIS_SK: ok = vorbis_custom_parse_packet_sk(stream, data); break;
default: goto decode_fail;
}
if(!ok) goto decode_fail;
if(!ok) {
VGM_LOG("Vorbis: cannot parse packet @ around %lx\n",stream->offset);
goto decode_fail;
}
/* parse the fake ogg packet into a logical vorbis block */
rc = vorbis_synthesis(&data->vb,&data->op);

View File

@ -8,12 +8,12 @@
int vorbis_custom_setup_init_fsb(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_setup_init_wwise(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_setup_init_ogl(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
//int vorbis_custom_setup_init_sk(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_setup_init_sk(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data);
int vorbis_custom_parse_packet_fsb(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
int vorbis_custom_parse_packet_wwise(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
int vorbis_custom_parse_packet_ogl(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
//int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data);
#endif/* VGM_USE_VORBIS */
#endif/*_VORBIS_CUSTOM_DECODER_H_ */

View File

@ -0,0 +1,194 @@
#include "vorbis_custom_decoder.h"
#ifdef VGM_USE_VORBIS
#include <vorbis/codec.h>
/* **************************************************************************** */
/* DEFS */
/* **************************************************************************** */
static int get_page_info(STREAMFILE *streamFile, off_t page_offset, off_t *out_packet_offset, size_t *out_packet_size, int *out_page_packets, int target_packet);
static int build_header(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile, off_t packet_offset, size_t packet_size);
/* **************************************************************************** */
/* EXTERNAL API */
/* **************************************************************************** */
/**
* SK just replaces the id 0x4F676753 ("OggS") by 0x11534B10 (\11"SK"\10), and the word "vorbis" by "SK"
* in init packets (for obfuscation, surely). So essentially we are parsing regular Ogg here.
*
* A simpler way to implement this would be in ogg_vorbis_file with read callbacks (pretend this is proof of concept).
*/
int vorbis_custom_setup_init_sk(STREAMFILE *streamFile, off_t start_offset, vorbis_custom_codec_data *data) {
off_t offset = start_offset;
off_t id_offset = 0, comment_offset = 0, setup_offset = 0;
size_t id_size = 0, comment_size = 0, setup_size = 0;
int page_packets;
/* rebuild header packets, they are standard except the "vorbis" keyword is replaced by "SK" */
/* first page has the id packet */
if (!get_page_info(streamFile, offset, &id_offset, &id_size, &page_packets, 0)) goto fail;
if (page_packets != 1) goto fail;
offset = id_offset + id_size;
/* second page has the comment and setup packets */
if (!get_page_info(streamFile, offset, &comment_offset, &comment_size, &page_packets, 0)) goto fail;
if (page_packets != 2) goto fail;
if (!get_page_info(streamFile, offset, &setup_offset, &setup_size, &page_packets, 1)) goto fail;
if (page_packets != 2) goto fail;
offset = comment_offset + comment_size + setup_size;
/* init with all offsets found */
data->op.bytes = build_header(data->buffer, data->buffer_size, streamFile, id_offset, id_size);
if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse identification header */
data->op.bytes = build_header(data->buffer, data->buffer_size, streamFile, comment_offset, comment_size);
if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) !=0 ) goto fail; /* parse comment header */
data->op.bytes = build_header(data->buffer, data->buffer_size, streamFile, setup_offset, setup_size);
if (!data->op.bytes) goto fail;
if (vorbis_synthesis_headerin(&data->vi, &data->vc, &data->op) != 0) goto fail; /* parse setup header */
/* data starts after triad */
data->config.data_start_offset = offset;
return 1;
fail:
VGM_LOG("SK Vorbis: failed to setup init packets @ around 0x%08lx\n", offset);
return 0;
}
int vorbis_custom_parse_packet_sk(VGMSTREAMCHANNEL *stream, vorbis_custom_codec_data *data) {
off_t packet_offset = 0;
size_t packet_size = 0;
int page_packets;
/* read OggS/SK page and get current packet */
if (!get_page_info(stream->streamfile, stream->offset, &packet_offset, &packet_size, &page_packets, data->current_packet)) goto fail;
data->current_packet++;
/* read raw block */
data->op.bytes = read_streamfile(data->buffer, packet_offset, packet_size, stream->streamfile);
if (data->op.bytes != packet_size) {
VGM_LOG("SK Vorbis: read error, 0x%x packet size vs 0x%lx bytes @ %lx\n", packet_size, data->op.bytes, packet_offset);
goto fail; /* wrong packet? */
}
if (data->current_packet >= page_packets) {
/* processed all packets in page, go to next */
if (!get_page_info(stream->streamfile, stream->offset, &packet_offset, &packet_size, &page_packets, -1)) goto fail;
stream->offset = packet_offset + packet_size;
data->current_packet = 0;
}
return 1;
fail:
VGM_LOG("SK Vorbis: failed to parse packet @ around 0x%08lx\n", stream->offset);
return 0;
}
/* **************************************************************************** */
/* INTERNAL HELPERS */
/* **************************************************************************** */
/**
* Get packet info from an Ogg page, from segment/packet N (-1 = all segments)
*
* Page format:
* 0x00(4): capture pattern ("OggS")
* 0x01(1): stream structure version
* 0x05(1): header type flag
* 0x06(8): absolute granule position
* 0x0e(4): stream serial number
* 0x12(4): page sequence number
* 0x16(4): page checksum
* 0x1a(1): page segments (total bytes in segment table)
* 0x1b(n): segment table (N bytes, 1 packet is sum of sizes until != 0xFF)
* 0x--(n): data
* Reference: https://xiph.org/ogg/doc/framing.html
*/
static int get_page_info(STREAMFILE *streamFile, off_t page_offset, off_t *out_packet_offset, size_t *out_packet_size, int *out_page_packets, int target_packet) {
off_t table_offset, current_packet_offset, target_packet_offset = 0;
size_t total_packets_size = 0, current_packet_size = 0, target_packet_size = 0;
int page_packets = 0;
uint8_t segments;
int i;
if (read_32bitBE(page_offset+0x00, streamFile) != 0x11534B10) /* \11"SK"\10 */
goto fail; /* not a valid page */
/* No point on validating other stuff, but they look legal enough (CRC too it seems) */
segments = (uint8_t)read_8bit(page_offset+0x1a, streamFile);
table_offset = page_offset + 0x1b;
current_packet_offset = page_offset + 0x1b + segments; /* first packet starts after segments */
/* process segments */
for (i = 0; i < segments; i++) {
uint8_t segment_size = (uint8_t)read_8bit(table_offset, streamFile);
total_packets_size += segment_size;
current_packet_size += segment_size;
table_offset += 0x01;
if (segment_size != 0xFF) { /* packet complete */
page_packets++;
if (target_packet+1 == page_packets) {
target_packet_offset = current_packet_offset;
target_packet_size = current_packet_size;
}
/* keep reading to fill page_packets */
current_packet_offset += current_packet_size; /* move to next packet */
current_packet_size = 0;
}
}
/* < 0 is accepted and returns first offset and all packets sizes */
if (target_packet+1 > page_packets) goto fail;
if (target_packet < 0) {
target_packet_offset = page_offset + 0x1b + segments; /* first */
target_packet_size = total_packets_size;
}
if (out_packet_offset) *out_packet_offset = target_packet_offset;
if (out_packet_size) *out_packet_size = target_packet_size;
if (out_page_packets) *out_page_packets = page_packets;
return 1;
fail:
VGM_LOG("SK Vorbis: failed to read page @ 0x%08lx\n", page_offset);
return 0;
}
/* rebuild a "SK" header packet to a "vorbis" one */
static int build_header(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile, off_t packet_offset, size_t packet_size) {
int bytes;
if (0x07+packet_size-0x03 > bufsize) return 0;
put_8bit (buf+0x00, read_8bit(packet_offset,streamFile)); /* packet_type */
memcpy (buf+0x01, "vorbis", 6); /* id */
bytes = read_streamfile(buf+0x07,packet_offset+0x03, packet_size-0x03,streamFile); /* copy rest (all except id+"SK") */
if (packet_size-0x03 != bytes) {
VGM_LOG("SK Vorbis: packet (size 0x%x) not copied correctly (bytes=%x) @ 0x%lx\n", packet_size, bytes, packet_offset);
return 0;
}
return 0x07+packet_size-0x03;
}
#endif

View File

@ -878,6 +878,7 @@ static const meta_info meta_info_list[] = {
{meta_WII_04SW, "Reflections 04SW header"},
{meta_TXTH, "TXTH Generic Header"},
{meta_EA_BNK, "Electronic Arts BNK header"},
{meta_SK_AUD, "Silicon Knights AUD header"},
#ifdef VGM_USE_VORBIS
{meta_OGG_VORBIS, "Ogg Vorbis"},

View File

@ -1458,6 +1458,10 @@
RelativePath=".\coding\vorbis_custom_utils_ogl.c"
>
</File>
<File
RelativePath=".\coding\vorbis_custom_utils_sk.c"
>
</File>
<File
RelativePath=".\coding\vorbis_custom_utils_wwise.c"
>

View File

@ -439,6 +439,7 @@
<ClCompile Include="coding\vorbis_custom_decoder.c" />
<ClCompile Include="coding\vorbis_custom_utils_fsb.c" />
<ClCompile Include="coding\vorbis_custom_utils_ogl.c" />
<ClCompile Include="coding\vorbis_custom_utils_sk.c" />
<ClCompile Include="coding\vorbis_custom_utils_wwise.c" />
<ClCompile Include="coding\ws_decoder.c" />
<ClCompile Include="coding\xa_decoder.c" />

View File

@ -859,6 +859,9 @@
<ClCompile Include="coding\vorbis_custom_utils_ogl.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\vorbis_custom_utils_sk.c">
<Filter>coding\Source Files</Filter>
</ClCompile>
<ClCompile Include="coding\vorbis_custom_utils_wwise.c">
<Filter>coding\Source Files</Filter>
</ClCompile>

View File

@ -684,4 +684,6 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE * streamFile);
VGMSTREAM * init_vgmstream_sk_aud(STREAMFILE * streamFile);
#endif /*_META_H*/

75
src/meta/sk_aud.c Normal file
View File

@ -0,0 +1,75 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
static int get_sk_num_samples(STREAMFILE *streamFile, off_t start_offset);
/* AUD/SK - Silicon Knights obfuscated Ogg (cutscene/voices) [Eternal Darkness (GC)] */
VGMSTREAM * init_vgmstream_sk_aud(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag = 0, channel_count, sample_rate;
/* check extension, case insensitive */
if (!check_extensions(streamFile,"aud"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x11534B10) /* \11"SK"\10 */
goto fail;
/* the format is just mutant Ogg so actually peeking into the Vorbis id packet here */
channel_count = read_8bit (0x23,streamFile);
sample_rate = read_32bitLE(0x24,streamFile);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = get_sk_num_samples(streamFile, 0);
vgmstream->meta_type = meta_SK_AUD;
#ifdef VGM_USE_VORBIS
{
vorbis_custom_config cfg;
memset(&cfg, 0, sizeof(vorbis_custom_config));
vgmstream->layout_type = layout_none;
vgmstream->coding_type = coding_VORBIS_custom;
vgmstream->codec_data = init_vorbis_custom_codec_data(streamFile, 0x00, VORBIS_SK, &cfg);
if (!vgmstream->codec_data) goto fail;
start_offset = cfg.data_start_offset;
}
#else
goto fail;
#endif
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}
/* SK/Ogg doesn't have num_samples info, manually read total samples */
static int get_sk_num_samples(STREAMFILE *streamFile, off_t start_offset) {
uint32_t expected_id = 0x11534B10; /* \11"SK"\10 (would read "OggS" by changing the ID) */
off_t off = get_streamfile_size(streamFile) - 4-1-1-8-4-4-4;
/* simplest way is to find last OggS/SK page from stream end */
while (off >= start_offset) {
uint32_t current_id = read_32bitBE(off, streamFile);
if (current_id == expected_id) { /* last packet starts with 0x0004, if more checks are needed */
return read_32bitLE(off+4+1+1, streamFile); /* get last granule = total samples (64b but whatevs) */
}
off--;
}
return 0;
}

View File

@ -370,6 +370,7 @@ VGMSTREAM * (*init_vgmstream_fcns[])(STREAMFILE *streamFile) = {
init_vgmstream_wii_04sw,
init_vgmstream_ea_bnk,
init_vgmstream_ea_schl_fixed,
init_vgmstream_sk_aud,
init_vgmstream_txth, /* should go at the end (lower priority) */
#ifdef VGM_USE_FFMPEG

View File

@ -492,8 +492,8 @@ typedef enum {
meta_MUS_ACM, /* MUS playlist of InterPlay ACM files */
meta_DE2, /* Falcom (Gurumin) .de2 */
meta_VS, /* Men in Black .vs */
meta_FFXI_BGW, /* FFXI BGW */
meta_FFXI_SPW, /* FFXI SPW */
meta_FFXI_BGW, /* FFXI (PC) BGW */
meta_FFXI_SPW, /* FFXI (PC) SPW */
meta_STS_WII, /* Shikigami No Shiro 3 STS Audio File */
meta_PS2_P2BT, /* Pop'n'Music 7 Audio File */
meta_PS2_GBTS, /* Pop'n'Music 9 Audio File */
@ -621,6 +621,7 @@ typedef enum {
meta_PC_XA30, /* Driver - Parallel Lines (PC) */
meta_WII_04SW, /* Driver - Parallel Lines (Wii) */
meta_TXTH, /* generic text header */
meta_SK_AUD, /* Silicon Knights .AUD (Eternal Darkness GC) */
#ifdef VGM_USE_VORBIS
meta_OGG_VORBIS, /* Ogg Vorbis */
@ -800,11 +801,10 @@ typedef struct {
/* custom Vorbis modes */
typedef enum {
//VORBIS_OGG, /* regular Ogg layer */
VORBIS_FSB, /* simplified/external setup packets, custom packet headers */
VORBIS_WWISE, /* many variations (custom setup, headers and data) */
VORBIS_OGL, /* custom packet headers */
//VORBIS_SK /* "OggS" replaced by "SK" */
VORBIS_SK /* "OggS" replaced by "SK" */
} vorbis_custom_t;
/* config for Wwise Vorbis (3 types for flexibility though not all combinations exist) */
@ -852,6 +852,8 @@ typedef struct {
uint8_t mode_blockflag[64+1]; /* max 6b+1; flags 'n stuff */
int mode_bits; /* bits to store mode_number */
uint8_t prev_blockflag; /* blockflag in the last decoded packet */
/* Ogg-style Vorbis: packet within a page */
int current_packet;
} vorbis_custom_codec_data;
#endif