mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-31 04:13:47 +01:00
cleanup: simplify ogg vorbis meta call
This commit is contained in:
parent
bfd1d28745
commit
4ea05e512a
@ -341,12 +341,12 @@ void free_tac(tac_codec_data* data);
|
||||
typedef struct ogg_vorbis_codec_data ogg_vorbis_codec_data;
|
||||
typedef struct { //todo simplify
|
||||
STREAMFILE *streamfile;
|
||||
ogg_int64_t start; /* file offset where the Ogg starts */
|
||||
ogg_int64_t offset; /* virtual offset, from 0 to size */
|
||||
ogg_int64_t size; /* virtual size of the Ogg */
|
||||
int64_t start; /* file offset where the Ogg starts */
|
||||
int64_t offset; /* virtual offset, from 0 to size */
|
||||
int64_t size; /* virtual size of the Ogg */
|
||||
|
||||
/* decryption setup */
|
||||
void (*decryption_callback)(void *ptr, size_t size, size_t nmemb, void *datasource);
|
||||
void (*decryption_callback)(void* ptr, size_t size, size_t nmemb, void* datasource);
|
||||
uint8_t scd_xor;
|
||||
off_t scd_xor_length;
|
||||
uint32_t xor_value;
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "vorbis_custom_decoder.h"
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
#define VORBIS_DEFAULT_BUFFER_SIZE 0x8000 /* should be at least the size of the setup header, ~0x2000 */
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
/* used by vorbis_custom_decoder.c, but scattered in other .c files */
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/codec.h>
|
||||
|
||||
/* custom Vorbis without Ogg layer */
|
||||
struct vorbis_custom_codec_data {
|
||||
|
116
src/meta/akb.c
116
src/meta/akb.c
@ -3,20 +3,20 @@
|
||||
|
||||
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
|
||||
/* AKB (AAC only) - found in SQEX iOS games */
|
||||
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
|
||||
size_t filesize;
|
||||
uint32_t loop_start, loop_end;
|
||||
|
||||
if ((uint32_t)read_32bitBE(0, streamFile) != 0x414b4220) goto fail;
|
||||
if ((uint32_t)read_32bitBE(0, sf) != 0x414b4220) goto fail;
|
||||
|
||||
loop_start = read_32bitLE(0x14, streamFile);
|
||||
loop_end = read_32bitLE(0x18, streamFile);
|
||||
loop_start = read_32bitLE(0x14, sf);
|
||||
loop_end = read_32bitLE(0x18, sf);
|
||||
|
||||
filesize = get_streamfile_size( streamFile );
|
||||
filesize = get_streamfile_size( sf );
|
||||
|
||||
vgmstream = init_vgmstream_mp4_aac_offset( streamFile, 0x20, filesize - 0x20 );
|
||||
vgmstream = init_vgmstream_mp4_aac_offset( sf, 0x20, filesize - 0x20 );
|
||||
if ( !vgmstream ) goto fail;
|
||||
|
||||
if ( loop_start || loop_end ) {
|
||||
@ -34,7 +34,7 @@ fail:
|
||||
|
||||
|
||||
/* AKB - found in SQEX iOS games */
|
||||
VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, extradata_offset = 0;
|
||||
size_t stream_size, header_size, subheader_size = 0, extradata_size = 0;
|
||||
@ -44,28 +44,28 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
|
||||
/* checks */
|
||||
/* .akb.bytes is the usual extension in later games */
|
||||
if ( !check_extensions(streamFile, "akb,bytes") )
|
||||
if ( !check_extensions(sf, "akb,bytes") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x414B4220) /* "AKB " */
|
||||
if (read_32bitBE(0x00,sf) != 0x414B4220) /* "AKB " */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
|
||||
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
|
||||
/* 0x04(1): version */
|
||||
header_size = read_16bitLE(0x06,streamFile);
|
||||
header_size = read_16bitLE(0x06,sf);
|
||||
|
||||
codec = read_8bit(0x0c,streamFile);
|
||||
channel_count = read_8bit(0x0d,streamFile);
|
||||
sample_rate = (uint16_t)read_16bitLE(0x0e,streamFile);
|
||||
num_samples = read_32bitLE(0x10,streamFile);
|
||||
loop_start = read_32bitLE(0x14,streamFile);
|
||||
loop_end = read_32bitLE(0x18,streamFile);
|
||||
codec = read_8bit(0x0c,sf);
|
||||
channel_count = read_8bit(0x0d,sf);
|
||||
sample_rate = (uint16_t)read_16bitLE(0x0e,sf);
|
||||
num_samples = read_32bitLE(0x10,sf);
|
||||
loop_start = read_32bitLE(0x14,sf);
|
||||
loop_end = read_32bitLE(0x18,sf);
|
||||
|
||||
/* possibly more complex, see AKB2 */
|
||||
if (header_size >= 0x44) { /* v2+ */
|
||||
extradata_size = read_16bitLE(0x1c,streamFile);
|
||||
extradata_size = read_16bitLE(0x1c,sf);
|
||||
/* 0x20+: config? (pan, volume) */
|
||||
subheader_size = read_16bitLE(0x28,streamFile);
|
||||
subheader_size = read_16bitLE(0x28,sf);
|
||||
/* 0x24: file_id? */
|
||||
/* 0x2b: encryption bitflag if version > 2? */
|
||||
extradata_offset = header_size + subheader_size;
|
||||
@ -75,7 +75,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
start_offset = header_size;
|
||||
}
|
||||
|
||||
stream_size = get_streamfile_size(streamFile) - start_offset;
|
||||
stream_size = get_streamfile_size(sf) - start_offset;
|
||||
loop_flag = (loop_end > loop_start);
|
||||
|
||||
|
||||
@ -91,14 +91,14 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
case 0x02: { /* MSADPCM [Dragon Quest II (iOS) sfx] */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02,streamFile);
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02,sf);
|
||||
|
||||
/* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead
|
||||
* (base samples may have more than possible and read over file size otherwise, very strange)
|
||||
* loop_end seems to exist even with loop disabled */
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, sf);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
/* extradata + 0x04: Ogg loop start offset */
|
||||
/* oggs have loop info in the comments */
|
||||
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (ogg_vgmstream) {
|
||||
close_vgmstream(vgmstream);
|
||||
return ogg_vgmstream;
|
||||
@ -128,7 +128,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
/* Alt decoding without libvorbis (minor number of beginning samples difference).
|
||||
* Otherwise same output with (inaudible) +-1 lower byte differences due to rounding. */
|
||||
case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */
|
||||
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset,stream_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -145,7 +145,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
#ifdef VGM_USE_FFMPEG
|
||||
case 0x06: { /* M4A with AAC [The World Ends with You (iPad)] */
|
||||
/* init_vgmstream_akb_mp4 above has priority, but this works fine too */
|
||||
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset,stream_size-start_offset);
|
||||
vgmstream->codec_data = init_ffmpeg_offset(sf, start_offset,stream_size-start_offset);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -168,7 +168,7 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
@ -180,22 +180,22 @@ fail:
|
||||
|
||||
|
||||
/* AKB2 - found in later SQEX iOS games */
|
||||
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset, material_offset, extradata_offset;
|
||||
size_t material_size, extradata_size, stream_size;
|
||||
int loop_flag = 0, channel_count, encryption_flag, codec, sample_rate, num_samples, loop_start, loop_end;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
/* check extensions */
|
||||
/* .akb.bytes is the usual extension in later games */
|
||||
if ( !check_extensions(streamFile, "akb,bytes") )
|
||||
if ( !check_extensions(sf, "akb,bytes") )
|
||||
goto fail;
|
||||
|
||||
/* checks */
|
||||
if (read_32bitBE(0x00,streamFile) != 0x414B4232) /* "AKB2" */
|
||||
if (read_32bitBE(0x00,sf) != 0x414B4232) /* "AKB2" */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x08,streamFile) != get_streamfile_size(streamFile))
|
||||
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
/* 0x04: version */
|
||||
|
||||
@ -203,37 +203,37 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
{
|
||||
off_t table_offset;
|
||||
size_t table_size, entry_size;
|
||||
off_t akb_header_size = read_16bitLE(0x06, streamFile);
|
||||
int table_count = read_8bit(0x0c, streamFile);
|
||||
off_t akb_header_size = read_16bitLE(0x06, sf);
|
||||
int table_count = read_8bit(0x0c, sf);
|
||||
|
||||
/* probably each table has its type somewhere, but only seen last table = sound table */
|
||||
if (table_count > 2) /* 2 only seen in some Mobius FF sound banks */
|
||||
goto fail;
|
||||
entry_size = 0x10; /* technically every entry/table has its own size but to simplify... */
|
||||
|
||||
table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, streamFile);
|
||||
table_size = read_16bitLE(table_offset + 0x02, streamFile);
|
||||
table_offset = read_32bitLE(akb_header_size + (table_count-1)*entry_size + 0x04, sf);
|
||||
table_size = read_16bitLE(table_offset + 0x02, sf);
|
||||
|
||||
total_subsongs = read_8bit(table_offset + 0x0f, streamFile); /* can contain 0 entries too */
|
||||
total_subsongs = read_8bit(table_offset + 0x0f, sf); /* can contain 0 entries too */
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, streamFile);
|
||||
material_offset = table_offset + read_32bitLE(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, sf);
|
||||
}
|
||||
|
||||
/** stream header (material) **/
|
||||
/* 0x00: 0? */
|
||||
codec = read_8bit(material_offset+0x01,streamFile);
|
||||
channel_count = read_8bit(material_offset+0x02,streamFile);
|
||||
encryption_flag = read_8bit(material_offset+0x03,streamFile);
|
||||
material_size = read_16bitLE(material_offset+0x04,streamFile);
|
||||
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,streamFile);
|
||||
stream_size = read_32bitLE(material_offset+0x08,streamFile);
|
||||
num_samples = read_32bitLE(material_offset+0x0c,streamFile);
|
||||
codec = read_8bit(material_offset+0x01,sf);
|
||||
channel_count = read_8bit(material_offset+0x02,sf);
|
||||
encryption_flag = read_8bit(material_offset+0x03,sf);
|
||||
material_size = read_16bitLE(material_offset+0x04,sf);
|
||||
sample_rate = (uint16_t)read_16bitLE(material_offset+0x06,sf);
|
||||
stream_size = read_32bitLE(material_offset+0x08,sf);
|
||||
num_samples = read_32bitLE(material_offset+0x0c,sf);
|
||||
|
||||
loop_start = read_32bitLE(material_offset+0x10,streamFile);
|
||||
loop_end = read_32bitLE(material_offset+0x14,streamFile);
|
||||
extradata_size = read_32bitLE(material_offset+0x18,streamFile);
|
||||
loop_start = read_32bitLE(material_offset+0x10,sf);
|
||||
loop_end = read_32bitLE(material_offset+0x14,sf);
|
||||
extradata_size = read_32bitLE(material_offset+0x18,sf);
|
||||
/* rest: ? (empty or 0x3f80) */
|
||||
|
||||
loop_flag = (loop_end > loop_start);
|
||||
@ -269,14 +269,14 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
case 0x02: { /* MSADPCM [The Irregular at Magic High School Lost Zero (Android)] */
|
||||
vgmstream->coding_type = coding_MSADPCM;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02, streamFile);
|
||||
vgmstream->frame_size = read_16bitLE(extradata_offset + 0x02, sf);
|
||||
|
||||
/* adjusted samples; bigger or smaller than base samples, akb lib uses these fields instead
|
||||
* (base samples may have more than possible and read over file size otherwise, very strange)
|
||||
* loop_end seems to exist even with loop disabled */
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, streamFile);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, streamFile);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(extradata_offset + 0x04, sf);
|
||||
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
|
||||
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
|
||||
break;
|
||||
}
|
||||
|
||||
@ -289,7 +289,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
ovmi.total_subsongs = total_subsongs;
|
||||
ovmi.stream_size = stream_size;
|
||||
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (ogg_vgmstream) {
|
||||
ogg_vgmstream->num_streams = vgmstream->num_streams;
|
||||
ogg_vgmstream->stream_size = vgmstream->stream_size;
|
||||
@ -310,7 +310,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
case 0x05: { /* Ogg Vorbis [The World Ends with You (iOS / latest update)] */
|
||||
ffmpeg_codec_data *ffmpeg_data;
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, start_offset,stream_size);
|
||||
ffmpeg_data = init_ffmpeg_offset(sf, start_offset,stream_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
@ -319,8 +319,8 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
|
||||
/* When loop_flag num_samples may be much larger than real num_samples (it's fine when looping is off)
|
||||
* Actual num_samples would be loop_end_sample+1, but more testing is needed */
|
||||
vgmstream->num_samples = read_32bitLE(material_offset+0x0c,streamFile);//num_samples;
|
||||
vgmstream->loop_start_sample = read_32bitLE(material_offset+0x10,streamFile);//loop_start;
|
||||
vgmstream->num_samples = read_32bitLE(material_offset+0x0c,sf);//num_samples;
|
||||
vgmstream->loop_start_sample = read_32bitLE(material_offset+0x10,sf);//loop_start;
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
break;
|
||||
}
|
||||
@ -331,7 +331,7 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* open the file for reading */
|
||||
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
|
||||
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
@ -27,7 +27,7 @@ VGMSTREAM* init_vgmstream_ao(STREAMFILE *sf) {
|
||||
/* AlphaOgg defines up to 16 loop points for some reason */
|
||||
|
||||
start_offset = 0xc8;
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
|
@ -3,49 +3,49 @@
|
||||
|
||||
|
||||
/* HIS - Her Interactive games [Nancy Drew series (PC)] */
|
||||
VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_his(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
int channel_count, loop_flag = 0, bps, sample_rate, num_samples, version;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "his"))
|
||||
if (!check_extensions(sf, "his"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,streamFile) == 0x48657220) { /* "Her Interactive Sound\x1a" */
|
||||
if (read_32bitBE(0x00,sf) == 0x48657220) { /* "Her Interactive Sound\x1a" */
|
||||
/* Nancy Drew: Secrets Can Kill (PC) */
|
||||
version = 0;
|
||||
channel_count = read_16bitLE(0x16,streamFile);
|
||||
sample_rate = read_32bitLE(0x18,streamFile);
|
||||
channel_count = read_16bitLE(0x16,sf);
|
||||
sample_rate = read_32bitLE(0x18,sf);
|
||||
/* 0x1c: bitrate */
|
||||
/* 0x20: block size */
|
||||
bps = read_16bitLE(0x22,streamFile);
|
||||
bps = read_16bitLE(0x22,sf);
|
||||
|
||||
if (read_32bitBE(0x24,streamFile) != 0x64617461) /* "data" */
|
||||
if (read_32bitBE(0x24,sf) != 0x64617461) /* "data" */
|
||||
goto fail;
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,streamFile), channel_count, bps);
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x28,sf), channel_count, bps);
|
||||
|
||||
start_offset = 0x2c;
|
||||
}
|
||||
else if (read_32bitBE(0x00,streamFile) == 0x48495300) { /* HIS\0 */
|
||||
else if (read_32bitBE(0x00,sf) == 0x48495300) { /* HIS\0 */
|
||||
/* most(?) others */
|
||||
version = read_32bitLE(0x04,streamFile);
|
||||
version = read_32bitLE(0x04,sf);
|
||||
/* 0x08: codec */
|
||||
channel_count = read_16bitLE(0x0a,streamFile);
|
||||
sample_rate = read_32bitLE(0x0c,streamFile);
|
||||
channel_count = read_16bitLE(0x0a,sf);
|
||||
sample_rate = read_32bitLE(0x0c,sf);
|
||||
/* 0x10: bitrate */
|
||||
/* 0x14: block size */
|
||||
bps = read_16bitLE(0x16,streamFile);
|
||||
bps = read_16bitLE(0x16,sf);
|
||||
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,streamFile), channel_count, bps); /* true even for Ogg */
|
||||
num_samples = pcm_bytes_to_samples(read_32bitLE(0x18,sf), channel_count, bps); /* true even for Ogg */
|
||||
|
||||
/* later games use "OggS" */
|
||||
if (version == 1)
|
||||
start_offset = 0x1c; /* Nancy Drew: The Final Scene (PC) */
|
||||
else if (version == 2 && read_32bitBE(0x1e,streamFile) == 0x4F676753)
|
||||
else if (version == 2 && read_32bitBE(0x1e,sf) == 0x4F676753)
|
||||
start_offset = 0x1e; /* Nancy Drew: The Haunted Carousel (PC) */
|
||||
else if (version == 2 && read_32bitBE(0x20,streamFile) == 0x4F676753)
|
||||
else if (version == 2 && read_32bitBE(0x20,sf) == 0x4F676753)
|
||||
start_offset = 0x20; /* Nancy Drew: The Silent Spy (PC) */
|
||||
else
|
||||
goto fail;
|
||||
@ -60,7 +60,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
|
||||
ovmi.meta_type = meta_HIS;
|
||||
return init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
return init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
@ -89,7 +89,7 @@ VGMSTREAM * init_vgmstream_his(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
@ -80,7 +80,7 @@ VGMSTREAM* init_vgmstream_ikm_pc(STREAMFILE* sf) {
|
||||
ovmi.loop_flag = ovmi.loop_end > 0;
|
||||
ovmi.stream_size = read_s32le(0x24, sf);
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
|
@ -137,9 +137,11 @@ typedef struct {
|
||||
off_t scd_xor_length;
|
||||
uint32_t xor_value;
|
||||
|
||||
//ov_callbacks *callbacks
|
||||
|
||||
} ogg_vorbis_meta_info_t;
|
||||
|
||||
VGMSTREAM * init_vgmstream_ogg_vorbis_callbacks(STREAMFILE *streamFile, ov_callbacks *callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi);
|
||||
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE *sf, off_t start, const ogg_vorbis_meta_info_t* ovmi);
|
||||
#endif
|
||||
|
||||
VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile);
|
||||
|
@ -10,12 +10,12 @@
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* MOGG - Harmonix Music Systems (Guitar Hero)[Unencrypted Type] */
|
||||
VGMSTREAM * init_vgmstream_mogg(STREAMFILE *streamFile) {
|
||||
VGMSTREAM* init_vgmstream_mogg(STREAMFILE *sf) {
|
||||
#ifdef VGM_USE_VORBIS
|
||||
off_t start_offset;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "mogg"))
|
||||
if (!check_extensions(sf, "mogg"))
|
||||
goto fail;
|
||||
|
||||
{
|
||||
@ -24,8 +24,8 @@ VGMSTREAM * init_vgmstream_mogg(STREAMFILE *streamFile) {
|
||||
|
||||
ovmi.meta_type = meta_MOGG;
|
||||
|
||||
start_offset = read_32bitLE(0x04, streamFile);
|
||||
result = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
start_offset = read_32bitLE(0x04, sf);
|
||||
result = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
|
||||
if (result != NULL) {
|
||||
return result;
|
||||
|
114
src/meta/nwav.c
114
src/meta/nwav.c
@ -1,57 +1,57 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
|
||||
VGMSTREAM * init_vgmstream_nwav(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .nwav: header id (no filenames in bigfiles) */
|
||||
if ( !check_extensions(streamFile,"nwav") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4E574156) /* "NWAV" */
|
||||
goto fail;
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
int channels;
|
||||
|
||||
/* 0x04: version? */
|
||||
/* 0x08: crc? */
|
||||
ovmi.stream_size = read_32bitLE(0x0c, streamFile);
|
||||
ovmi.loop_end = read_32bitLE(0x10, streamFile); /* num_samples, actually */
|
||||
/* 0x14: sample rate */
|
||||
/* 0x18: bps? (16) */
|
||||
channels = read_8bit(0x19, streamFile);
|
||||
start_offset = read_16bitLE(0x1a, streamFile);
|
||||
|
||||
ovmi.loop_flag = read_16bitLE(0x1c, streamFile) != 0; /* loop count? -1 = loops */
|
||||
/* 0x1e: always 2? */
|
||||
/* 0x20: always 1? */
|
||||
ovmi.loop_start = read_32bitLE(0x24, streamFile);
|
||||
/* 0x28: always 1? */
|
||||
/* 0x2a: always 1? */
|
||||
/* 0x2c: always null? */
|
||||
|
||||
ovmi.meta_type = meta_NWAV;
|
||||
|
||||
/* values are in resulting bytes */
|
||||
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
|
||||
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* NWAV - from Chunsoft games [Fuurai no Shiren Gaiden: Onnakenshi Asuka Kenzan! (PC)] */
|
||||
VGMSTREAM * init_vgmstream_nwav(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
|
||||
|
||||
/* checks */
|
||||
/* .nwav: header id (no filenames in bigfiles) */
|
||||
if ( !check_extensions(sf,"nwav") )
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,sf) != 0x4E574156) /* "NWAV" */
|
||||
goto fail;
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
{
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
int channels;
|
||||
|
||||
/* 0x04: version? */
|
||||
/* 0x08: crc? */
|
||||
ovmi.stream_size = read_32bitLE(0x0c, sf);
|
||||
ovmi.loop_end = read_32bitLE(0x10, sf); /* num_samples, actually */
|
||||
/* 0x14: sample rate */
|
||||
/* 0x18: bps? (16) */
|
||||
channels = read_8bit(0x19, sf);
|
||||
start_offset = read_16bitLE(0x1a, sf);
|
||||
|
||||
ovmi.loop_flag = read_16bitLE(0x1c, sf) != 0; /* loop count? -1 = loops */
|
||||
/* 0x1e: always 2? */
|
||||
/* 0x20: always 1? */
|
||||
ovmi.loop_start = read_32bitLE(0x24, sf);
|
||||
/* 0x28: always 1? */
|
||||
/* 0x2a: always 1? */
|
||||
/* 0x2c: always null? */
|
||||
|
||||
ovmi.meta_type = meta_NWAV;
|
||||
|
||||
/* values are in resulting bytes */
|
||||
ovmi.loop_start = ovmi.loop_start / sizeof(int16_t) / channels;
|
||||
ovmi.loop_end = ovmi.loop_end / sizeof(int16_t) / channels;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
#endif
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -286,21 +286,21 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
* 0x0c(2): PCM block size, 0x0e(2): PCM bps, 0x10: null, 0x18: samples (in PCM bytes)
|
||||
* - .isl: looping table (encrypted like the files) */
|
||||
if (isl_name) {
|
||||
STREAMFILE* islFile = NULL;
|
||||
STREAMFILE* sf_isl = NULL;
|
||||
|
||||
islFile = open_streamfile_by_filename(sf, isl_name);
|
||||
sf_isl = open_streamfile_by_filename(sf, isl_name);
|
||||
|
||||
if (!islFile) {
|
||||
if (!sf_isl) {
|
||||
/* try in ../(file) too since that's how the .isl is stored on disc */
|
||||
char isl_path[PATH_LIMIT];
|
||||
snprintf(isl_path, sizeof(isl_path), "../%s", isl_name);
|
||||
islFile = open_streamfile_by_filename(sf, isl_path);
|
||||
sf_isl = open_streamfile_by_filename(sf, isl_path);
|
||||
}
|
||||
|
||||
if (islFile) {
|
||||
if (sf_isl) {
|
||||
STREAMFILE* dec_sf = NULL;
|
||||
|
||||
dec_sf = setup_ogg_vorbis_streamfile(islFile, cfg);
|
||||
dec_sf = setup_ogg_vorbis_streamfile(sf_isl, cfg);
|
||||
if (dec_sf) {
|
||||
off_t loop_offset;
|
||||
char basename[PATH_LIMIT];
|
||||
@ -327,7 +327,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
close_streamfile(dec_sf);
|
||||
}
|
||||
|
||||
close_streamfile(islFile);
|
||||
close_streamfile(sf_isl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -416,7 +416,7 @@ VGMSTREAM* init_vgmstream_ogg_vorbis(STREAMFILE* sf) {
|
||||
ovmi.meta_type = meta_OGG_VORBIS;
|
||||
}
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(temp_sf != NULL ? temp_sf : sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf != NULL ? temp_sf : sf, start_offset, &ovmi);
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
@ -426,7 +426,7 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VGMSTREAM* init_vgmstream_ogg_vorbis_callbacks(STREAMFILE* sf, ov_callbacks* callbacks, off_t start, const ogg_vorbis_meta_info_t *ovmi) {
|
||||
VGMSTREAM* init_vgmstream_ogg_vorbis_config(STREAMFILE* sf, off_t start, const ogg_vorbis_meta_info_t* ovmi) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
ogg_vorbis_codec_data* data = NULL;
|
||||
ogg_vorbis_io io = {0};
|
||||
|
@ -27,7 +27,7 @@ VGMSTREAM* init_vgmstream_ogv_3rdeye(STREAMFILE* sf) {
|
||||
ovmi.meta_type = meta_OGV_3RDEYE;
|
||||
ovmi.stream_size = subfile_size;
|
||||
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, subfile_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
|
||||
}
|
||||
#else
|
||||
goto fail;
|
||||
|
@ -134,7 +134,7 @@ VGMSTREAM* init_vgmstream_rsd(STREAMFILE* sf) {
|
||||
|
||||
ovmi.meta_type = meta_RSD;
|
||||
close_vgmstream(vgmstream);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ VGMSTREAM* init_vgmstream_sqex_scd(STREAMFILE* sf) {
|
||||
}
|
||||
|
||||
/* actual Ogg init */
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, start_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
|
||||
if (ogg_vgmstream && name_offset)
|
||||
read_string(ogg_vgmstream->stream_name, PATH_LIMIT, name_offset, sf);
|
||||
return ogg_vgmstream;
|
||||
|
@ -172,7 +172,7 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
|
||||
/* 0x18: reserved x2 */
|
||||
/* 0x20: seek table */
|
||||
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_callbacks(sf, NULL, subfile_offset, &ovmi);
|
||||
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, subfile_offset, &ovmi);
|
||||
if (ogg_vgmstream) {
|
||||
ogg_vgmstream->num_streams = vgmstream->num_streams;
|
||||
ogg_vgmstream->stream_size = vgmstream->stream_size;
|
||||
|
@ -1,220 +1,220 @@
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
#define MAX_SEGMENTS 4
|
||||
|
||||
/* .WAVE - "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
|
||||
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t segments_offset;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
|
||||
|
||||
segmented_layout_data *data = NULL;
|
||||
int segment_count, loop_start_segment = 0, loop_end_segment = 0;
|
||||
|
||||
int big_endian;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "wave"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,streamFile) != 0x4DF72D4A && /* header id */
|
||||
read_32bitBE(0x00,streamFile) != 0x4DF72D4A)
|
||||
goto fail;
|
||||
if (read_8bit(0x04,streamFile) != 0x01) /* version? */
|
||||
goto fail;
|
||||
|
||||
/* PS3/X360 games */
|
||||
big_endian = read_32bitBE(0x00,streamFile) == 0x4DF72D4A;
|
||||
if (big_endian) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
channel_count = read_8bit(0x05,streamFile);
|
||||
segment_count = read_16bit(0x06,streamFile);
|
||||
if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
|
||||
|
||||
loop_start_segment = read_16bit(0x08, streamFile);
|
||||
loop_end_segment = read_16bit(0x0a, streamFile);
|
||||
segments_offset = read_32bit(0x0c, streamFile);
|
||||
|
||||
sample_rate = read_32bit(0x10, streamFile);
|
||||
num_samples = read_32bit(0x14, streamFile);
|
||||
/* 0x18: unknown (usually 0, maybe some count) */
|
||||
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_segmented(segment_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
/* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
|
||||
* Often first segment is ADPCM and rest Ogg; may only have one segment. */
|
||||
{
|
||||
off_t extradata_offset, table_offset, segment_offset;
|
||||
size_t segment_size;
|
||||
int32_t segment_samples;
|
||||
int codec;
|
||||
int i, ch;
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
codec = read_8bit(segments_offset+0x10*i+0x00, streamFile);
|
||||
/* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
|
||||
if (read_8bit(segments_offset+0x10*i+0x02, streamFile) != 0x01) goto fail; /* unknown */
|
||||
if (read_8bit(segments_offset+0x10*i+0x03, streamFile) != 0x00) goto fail; /* unknown */
|
||||
|
||||
segment_samples = read_32bit(segments_offset+0x10*i+0x04, streamFile);
|
||||
extradata_offset = read_32bit(segments_offset+0x10*i+0x08, streamFile);
|
||||
table_offset = read_32bit(segments_offset+0x10*i+0x0c, streamFile);
|
||||
|
||||
/* create a sub-VGMSTREAM per segment
|
||||
* (we'll reopen this streamFile as needed, so each sub-VGMSTREAM is fully independent) */
|
||||
switch(codec) {
|
||||
case 0x02: { /* "adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_IMA_int;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
|
||||
/* ADPCM setup */
|
||||
data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, streamFile);
|
||||
data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, streamFile);
|
||||
/* 0x03: reserved */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x03: { /* "dsp-adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_NGC_DSP;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],streamFile,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, streamFile);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
}
|
||||
|
||||
/* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
|
||||
dsp_read_hist(data->segments[i], streamFile, extradata_offset+0x02, 0x06, big_endian);
|
||||
dsp_read_coefs(data->segments[i], streamFile, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x04: { /* "vorbis" */
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
|
||||
segment_offset = read_32bit(table_offset, streamFile);
|
||||
segment_size = read_32bitBE(segment_offset, streamFile); /* always BE */
|
||||
|
||||
ovmi.meta_type = meta_WAVE;
|
||||
ovmi.stream_size = segment_size;
|
||||
|
||||
data->segments[i] = init_vgmstream_ogg_vorbis_callbacks(streamFile, NULL, segment_offset+0x04, &ovmi);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
if (data->segments[i]->num_samples != segment_samples) {
|
||||
VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default: /* others: s16be/s16le/mp3 as referenced in the exe? */
|
||||
VGM_LOG("WAVE: unknown codec\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* setup segmented VGMSTREAMs */
|
||||
if (!setup_layout_segmented(data))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse samples */
|
||||
{
|
||||
int32_t sample_count = 0;
|
||||
int i;
|
||||
|
||||
loop_flag = (loop_start_segment > 0);
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
if (loop_flag && loop_start_segment == i) {
|
||||
loop_start_sample = sample_count;
|
||||
}
|
||||
|
||||
sample_count += data->segments[i]->num_samples;
|
||||
|
||||
if (loop_flag && loop_end_segment-1 == i) {
|
||||
loop_end_sample = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_count != num_samples) {
|
||||
VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, 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->meta_type = meta_WAVE_segmented;
|
||||
vgmstream->stream_size = get_streamfile_size(streamFile); /* wrong kbps otherwise */
|
||||
|
||||
/* .wave can mix codecs, usually first segment is a small ADPCM section) */
|
||||
vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
vgmstream->layout_data = data;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
free_layout_segmented(data);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
#include "../layout/layout.h"
|
||||
|
||||
#define MAX_SEGMENTS 4
|
||||
|
||||
/* .WAVE - "EngineBlack" games, segmented [Shantae and the Pirate's Curse (PC/3DS), TMNT: Danger of the Ooze (PS3/3DS)] */
|
||||
VGMSTREAM * init_vgmstream_wave_segmented(STREAMFILE *sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t segments_offset;
|
||||
int loop_flag = 0, channel_count, sample_rate;
|
||||
int32_t num_samples, loop_start_sample = 0, loop_end_sample = 0;
|
||||
|
||||
segmented_layout_data *data = NULL;
|
||||
int segment_count, loop_start_segment = 0, loop_end_segment = 0;
|
||||
|
||||
int big_endian;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(sf, "wave"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitLE(0x00,sf) != 0x4DF72D4A && /* header id */
|
||||
read_32bitBE(0x00,sf) != 0x4DF72D4A)
|
||||
goto fail;
|
||||
if (read_8bit(0x04,sf) != 0x01) /* version? */
|
||||
goto fail;
|
||||
|
||||
/* PS3/X360 games */
|
||||
big_endian = read_32bitBE(0x00,sf) == 0x4DF72D4A;
|
||||
if (big_endian) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
channel_count = read_8bit(0x05,sf);
|
||||
segment_count = read_16bit(0x06,sf);
|
||||
if (segment_count > MAX_SEGMENTS || segment_count <= 0) goto fail;
|
||||
|
||||
loop_start_segment = read_16bit(0x08, sf);
|
||||
loop_end_segment = read_16bit(0x0a, sf);
|
||||
segments_offset = read_32bit(0x0c, sf);
|
||||
|
||||
sample_rate = read_32bit(0x10, sf);
|
||||
num_samples = read_32bit(0x14, sf);
|
||||
/* 0x18: unknown (usually 0, maybe some count) */
|
||||
|
||||
|
||||
/* init layout */
|
||||
data = init_layout_segmented(segment_count);
|
||||
if (!data) goto fail;
|
||||
|
||||
/* parse segments (usually: preload + intro + loop + ending, intro/ending may be skipped)
|
||||
* Often first segment is ADPCM and rest Ogg; may only have one segment. */
|
||||
{
|
||||
off_t extradata_offset, table_offset, segment_offset;
|
||||
size_t segment_size;
|
||||
int32_t segment_samples;
|
||||
int codec;
|
||||
int i, ch;
|
||||
|
||||
/* open each segment subfile */
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
codec = read_8bit(segments_offset+0x10*i+0x00, sf);
|
||||
/* 0x01(1): unknown (flag? usually 0x00/0x01/0x02) */
|
||||
if (read_8bit(segments_offset+0x10*i+0x02, sf) != 0x01) goto fail; /* unknown */
|
||||
if (read_8bit(segments_offset+0x10*i+0x03, sf) != 0x00) goto fail; /* unknown */
|
||||
|
||||
segment_samples = read_32bit(segments_offset+0x10*i+0x04, sf);
|
||||
extradata_offset = read_32bit(segments_offset+0x10*i+0x08, sf);
|
||||
table_offset = read_32bit(segments_offset+0x10*i+0x0c, sf);
|
||||
|
||||
/* create a sub-VGMSTREAM per segment
|
||||
* (we'll reopen this sf as needed, so each sub-VGMSTREAM is fully independent) */
|
||||
switch(codec) {
|
||||
case 0x02: { /* "adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_IMA_int;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],sf,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, sf);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
|
||||
/* ADPCM setup */
|
||||
data->segments[i]->ch[ch].adpcm_history1_32 = read_16bit(extradata_offset+0x04*ch+0x00, sf);
|
||||
data->segments[i]->ch[ch].adpcm_step_index = read_8bit(extradata_offset+0x04*ch+0x02, sf);
|
||||
/* 0x03: reserved */
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 0x03: { /* "dsp-adpcm" */
|
||||
data->segments[i] = allocate_vgmstream(channel_count, 0);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
data->segments[i]->sample_rate = sample_rate;
|
||||
data->segments[i]->meta_type = meta_WAVE;
|
||||
data->segments[i]->coding_type = coding_NGC_DSP;
|
||||
data->segments[i]->layout_type = layout_none;
|
||||
data->segments[i]->num_samples = segment_samples;
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],sf,0x00))
|
||||
goto fail;
|
||||
|
||||
/* bizarrely enough channel data isn't sequential (segment0 ch1+ may go after all other segments) */
|
||||
for (ch = 0; ch < channel_count; ch++) {
|
||||
segment_offset = read_32bit(table_offset + 0x04*ch, sf);
|
||||
data->segments[i]->ch[ch].channel_start_offset =
|
||||
data->segments[i]->ch[ch].offset = segment_offset;
|
||||
}
|
||||
|
||||
/* ADPCM setup: 0x06 initial ps/hist1/hist2 (per channel) + 0x20 coefs (per channel) */
|
||||
dsp_read_hist(data->segments[i], sf, extradata_offset+0x02, 0x06, big_endian);
|
||||
dsp_read_coefs(data->segments[i], sf, extradata_offset+0x06*channel_count+0x00, 0x20, big_endian);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
case 0x04: { /* "vorbis" */
|
||||
ogg_vorbis_meta_info_t ovmi = {0};
|
||||
|
||||
segment_offset = read_32bit(table_offset, sf);
|
||||
segment_size = read_32bitBE(segment_offset, sf); /* always BE */
|
||||
|
||||
ovmi.meta_type = meta_WAVE;
|
||||
ovmi.stream_size = segment_size;
|
||||
|
||||
data->segments[i] = init_vgmstream_ogg_vorbis_config(sf, segment_offset+0x04, &ovmi);
|
||||
if (!data->segments[i]) goto fail;
|
||||
|
||||
if (data->segments[i]->num_samples != segment_samples) {
|
||||
VGM_LOG("WAVE: segment %i samples != num_samples\n", i);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default: /* others: s16be/s16le/mp3 as referenced in the exe? */
|
||||
VGM_LOG("WAVE: unknown codec\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* setup segmented VGMSTREAMs */
|
||||
if (!setup_layout_segmented(data))
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse samples */
|
||||
{
|
||||
int32_t sample_count = 0;
|
||||
int i;
|
||||
|
||||
loop_flag = (loop_start_segment > 0);
|
||||
|
||||
for (i = 0; i < segment_count; i++) {
|
||||
if (loop_flag && loop_start_segment == i) {
|
||||
loop_start_sample = sample_count;
|
||||
}
|
||||
|
||||
sample_count += data->segments[i]->num_samples;
|
||||
|
||||
if (loop_flag && loop_end_segment-1 == i) {
|
||||
loop_end_sample = sample_count;
|
||||
}
|
||||
}
|
||||
|
||||
if (sample_count != num_samples) {
|
||||
VGM_LOG("WAVE: total segments samples %i != num_samples %i\n", sample_count, num_samples);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, 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->meta_type = meta_WAVE_segmented;
|
||||
vgmstream->stream_size = get_streamfile_size(sf); /* wrong kbps otherwise */
|
||||
|
||||
/* .wave can mix codecs, usually first segment is a small ADPCM section) */
|
||||
vgmstream->coding_type = (segment_count == 1 ? data->segments[0]->coding_type : data->segments[1]->coding_type);
|
||||
vgmstream->layout_type = layout_segmented;
|
||||
vgmstream->layout_data = data;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
free_layout_segmented(data);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -31,10 +31,6 @@ enum { VGMSTREAM_MAX_NUM_SAMPLES = 1000000000 }; /* no ~5h vgm hopefully */
|
||||
//#define VGM_USE_SPEEX
|
||||
|
||||
|
||||
#ifdef VGM_USE_VORBIS
|
||||
#include <vorbis/vorbisfile.h>
|
||||
#endif
|
||||
|
||||
#ifdef VGM_USE_MP4V2
|
||||
#define MP4V2_NO_STDINT_DEFS
|
||||
#include <mp4v2/mp4v2.h>
|
||||
|
Loading…
x
Reference in New Issue
Block a user