Updated VGMStream to r1745-79-g449bb5e0

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
main
Christopher Snowhill 2022-07-23 18:36:45 -07:00
parent 5c3b876c04
commit df17e1c788
25 changed files with 513 additions and 345 deletions

View File

@ -551,7 +551,7 @@
837CEB0223487F2C00E62A4A /* raw_int.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEAED23487F2C00E62A4A /* raw_int.c */; };
837CEB0323487F2C00E62A4A /* xavs_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 837CEAEE23487F2C00E62A4A /* xavs_streamfile.h */; };
837CEB0423487F2C00E62A4A /* jstm.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEAEF23487F2C00E62A4A /* jstm.c */; };
837CEB0523487F2C00E62A4A /* sqex_sead_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */; };
837CEB0523487F2C00E62A4A /* sqex_streamfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 837CEAF023487F2C00E62A4A /* sqex_streamfile.h */; };
837CEB072348809400E62A4A /* seb.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEB062348809400E62A4A /* seb.c */; };
8383A62C281203C60062E49E /* s3v.c in Sources */ = {isa = PBXBuildFile; fileRef = 8383A62B281203C50062E49E /* s3v.c */; };
83852B0B2680247900378854 /* rxws.c in Sources */ = {isa = PBXBuildFile; fileRef = 83852B092680247900378854 /* rxws.c */; };
@ -1376,7 +1376,7 @@
837CEAED23487F2C00E62A4A /* raw_int.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = raw_int.c; sourceTree = "<group>"; };
837CEAEE23487F2C00E62A4A /* xavs_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = xavs_streamfile.h; sourceTree = "<group>"; };
837CEAEF23487F2C00E62A4A /* jstm.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = jstm.c; sourceTree = "<group>"; };
837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqex_sead_streamfile.h; sourceTree = "<group>"; };
837CEAF023487F2C00E62A4A /* sqex_streamfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sqex_streamfile.h; sourceTree = "<group>"; };
837CEB062348809400E62A4A /* seb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = seb.c; sourceTree = "<group>"; };
8383A62B281203C50062E49E /* s3v.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = s3v.c; sourceTree = "<group>"; };
83852B092680247900378854 /* rxws.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = rxws.c; sourceTree = "<group>"; };
@ -2297,7 +2297,7 @@
836F6EF318BDC2190095E648 /* spt_spd.c */,
834FE0D6215C79E9000A5D3D /* sqex_scd_sscf.c */,
836F6EF418BDC2190095E648 /* sqex_scd.c */,
837CEAF023487F2C00E62A4A /* sqex_sead_streamfile.h */,
837CEAF023487F2C00E62A4A /* sqex_streamfile.h */,
83A21F84201D8981000F04B9 /* sqex_sead.c */,
8339B322280FDF250076F74B /* sspf.c */,
8317C24826982CC1007DD0B8 /* sspr.c */,
@ -2571,7 +2571,7 @@
83A8BAE625667AA8000F5F3F /* ps2_enth_streamfile.h in Headers */,
83256CE428666C620036D9C0 /* abi_align.h in Headers */,
8306B0D820984590000302D4 /* ea_eaac_streamfile.h in Headers */,
837CEB0523487F2C00E62A4A /* sqex_sead_streamfile.h in Headers */,
837CEB0523487F2C00E62A4A /* sqex_streamfile.h in Headers */,
83031ED9243C510500C3F3E0 /* ubi_lyn_streamfile.h in Headers */,
8373341D23F60C7B00DE14DC /* g7221_decoder_lib.h in Headers */,
8306B0E820984590000302D4 /* opus_interleave_streamfile.h in Headers */,

View File

@ -409,6 +409,7 @@ typedef struct {
uint32_t setup_id; /* external setup */
int big_endian; /* flag */
uint32_t stream_end; /* optional, to avoid overreading into next subsong or chunk */
/* Wwise Vorbis config */
wwise_setup_t setup_type;

View File

@ -1132,6 +1132,7 @@ struct g7221_handle {
/* control */
int bit_rate;
int frame_size;
int test_errors;
/* AES setup/state */
s14aes_handle* aes;
/* state */
@ -1179,7 +1180,7 @@ int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples
* so we could avoid one extra buffer, but for clarity we'll leave as is */
/* unpack data into MLT spectrum coefs */
res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value, encrypted);
res = unpack_frame(handle->bit_rate, data, handle->frame_size, &mag_shift, handle->mlt_coefs, &handle->random_value, handle->test_errors);
if (res < 0) goto fail;
/* convert coefs to samples using reverse (inverse) MLT */
@ -1254,6 +1255,7 @@ int g7221_set_key(g7221_handle* handle, const uint8_t* key) {
if (key == NULL) {
s14aes_close(handle->aes);
handle->aes = NULL;
handle->test_errors = 1; /* force? */
return 1;
}
@ -1263,6 +1265,8 @@ int g7221_set_key(g7221_handle* handle, const uint8_t* key) {
if (!handle->aes) goto fail;
}
handle->test_errors = 1;
/* Base key is XORed probably against memdumps, as plain key would be part of the final AES key. However
* roundkey is still in memdumps near AES state (~0x1310 from sbox table, that starts with 0x63,0x7c,0x77,0x7b...)
* so it isn't too effective. XORing was originally done inside aes_expand_key during S14/S22 init. */

View File

@ -65,6 +65,9 @@ vorbis_custom_codec_data* init_vorbis_custom(STREAMFILE* sf, off_t start_offset,
/* write output */
config->data_start_offset = data->config.data_start_offset;
if (!data->config.stream_end) {
data->config.stream_end = get_streamfile_size(sf);
}
return data;
@ -78,19 +81,11 @@ fail:
void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t samples_to_do, int channels) {
VGMSTREAMCHANNEL *stream = &vgmstream->ch[0];
vorbis_custom_codec_data* data = vgmstream->codec_data;
size_t stream_size = get_streamfile_size(stream->streamfile);
//data->op.packet = data->buffer;/* implicit from init */
int samples_done = 0;
while (samples_done < samples_to_do) {
/* extra EOF check for edge cases */
if (stream->offset >= stream_size) {
memset(outbuf + samples_done * channels, 0, (samples_to_do - samples_done) * sizeof(sample) * channels);
break;
}
if (data->samples_full) { /* read more samples */
int samples_to_get;
float **pcm;
@ -123,6 +118,12 @@ void decode_vorbis_custom(VGMSTREAM* vgmstream, sample_t* outbuf, int32_t sample
else { /* read more data */
int ok, rc;
/* extra EOF check */
if (stream->offset >= data->config.stream_end) {
/* may need to drain samples? (not a thing in vorbis due to packet types?) */
goto decode_fail;
}
/* not actually needed, but feels nicer */
data->op.granulepos += samples_to_do; /* can be changed next if desired */
data->op.packetno++;

View File

@ -25,6 +25,7 @@ static const char* extension_list[] = {
"2dx9",
"2pfs",
"3do",
"3ds", //txth/reserved [F1 2011 (3DS)]
"4", //for Game.com audio
"8", //txth/reserved [Gungage (PS1)]
"800",
@ -532,6 +533,7 @@ static const char* extension_list[] = {
"sxd",
"sxd2",
"sxd3",
"szd",
"szd1",
"szd3",

View File

@ -259,7 +259,7 @@ static const adxkey_info adxkey9_list[] = {
{0x0000,0x0000,0x0000, NULL,1991062320101111}, // 000712DC5250B6F7
/* Shin Megami Tensei V (Switch) */
{0x000c,0x13b5,0x1fdb, NULL,0}, // guessed with VGAudio (possible key: 613B4FEE / 1631277038)
{0x0000,0x0000,0x0000, NULL,1731948526}, // 00000000673B6FEE
};

View File

@ -1,48 +1,51 @@
#include "meta.h"
#include "../coding/coding.h"
#include "../util.h"
#if 0
#include "adx_keys.h"
#endif
/* AHX - CRI format mainly for voices, contains MPEG-2 Layer 2 audio with lying frame headers */
VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int channel_count = 1, loop_flag = 0, type;
/* AHX - CRI voice format */
VGMSTREAM* init_vgmstream_ahx(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset;
int channels = 1, loop_flag = 0, type;
/* check extension, case insensitive */
if ( !check_extensions(streamFile, "ahx") ) goto fail;
/* checks */
if (read_u16be(0x00,sf) != 0x8000)
goto fail;
/* check first 2 bytes */
if ((uint16_t)read_16bitBE(0,streamFile)!=0x8000) goto fail;
if (!check_extensions(sf, "ahx") )
goto fail;
/* get stream offset, check for CRI signature just before */
start_offset = (uint16_t)read_16bitBE(0x02,streamFile) + 0x04;
if ((uint16_t)read_16bitBE(start_offset-0x06,streamFile)!=0x2863 || /* "(c" */
(uint32_t)read_32bitBE(start_offset-0x04,streamFile)!=0x29435249) /* ")CRI" */
start_offset = read_u16be(0x02,sf) + 0x04;
if (read_u16be(start_offset - 0x06,sf) != 0x2863 || /* "(c" */
read_u32be(start_offset - 0x04,sf) != 0x29435249) /* ")CRI" */
goto fail;
/* check for encoding type (0x10 is AHX for DC with bigger frames, 0x11 is AHX, 0x0N are ADX) */
type = read_8bit(0x04,streamFile);
/* types: 0x10 = AHX for DC with bigger frames, 0x11 = AHX, 0x0N = ADX */
type = read_u8(0x04,sf);
if (type != 0x10 && type != 0x11) goto fail;
/* check for frame size (0 for AHX) */
if (read_8bit(0x05,streamFile) != 0) goto fail;
/* frame size (0 for AHX) */
if (read_u8(0x05,sf) != 0) goto fail;
/* check for bits per sample? (0 for AHX) */
if (read_8bit(0x06,streamFile) != 0) goto fail;
if (read_u8(0x06,sf) != 0) goto fail;
/* check channel count (only mono AHXs can be created by the encoder) */
if (read_8bit(0x07,streamFile) != 1) goto fail;
if (read_u8(0x07,sf) != 1) goto fail;
/* check version signature */
if (read_8bit(0x12,streamFile) != 0x06) goto fail;
if (read_u8(0x12,sf) != 0x06) goto fail;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = read_32bitBE(0x08,streamFile); /* real sample rate */
vgmstream->num_samples = read_32bitBE(0x0c,streamFile); /* doesn't include encoder_delay (handled in decoder) */
vgmstream->sample_rate = read_s32be(0x08,sf); /* real sample rate */
vgmstream->num_samples = read_s32be(0x0c,sf); /* doesn't include encoder_delay (handled in decoder) */
vgmstream->meta_type = meta_AHX;
@ -50,30 +53,51 @@ VGMSTREAM * init_vgmstream_ahx(STREAMFILE *streamFile) {
#ifdef VGM_USE_MPEG
mpeg_custom_config cfg = {0};
cfg.encryption = read_8bit(0x13,streamFile); /* 0x08 = keyword encryption */
cfg.encryption = read_u8(0x13,sf); /* 0x08 = keyword encryption */
cfg.cri_type = type;
if (cfg.encryption) {
uint8_t keybuf[6];
if (read_key_file(keybuf, 6, streamFile) == 6) {
cfg.cri_key1 = get_16bitBE(keybuf+0);
cfg.cri_key2 = get_16bitBE(keybuf+2);
cfg.cri_key3 = get_16bitBE(keybuf+4);
uint8_t keybuf[0x10+1] = {0}; /* approximate max for keystrings, +1 extra null for keystrings */
size_t key_size;
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
if (key_size > 0) {
#if 0
int i, is_ascii;
is_ascii = 1;
for (i = 0; i < key_size; i++) {
if (keybuf[i] < 0x20 || keybuf[i] > 0x7f) {
is_ascii = 0;
break;
}
}
#endif
if (key_size == 0x06 /*&& !is_ascii*/) {
cfg.cri_key1 = get_u16be(keybuf + 0x00);
cfg.cri_key2 = get_u16be(keybuf + 0x02);
cfg.cri_key3 = get_u16be(keybuf + 0x04);
}
#if 0
else if (is_ascii) {
const char* keystring = (const char*)keybuf;
derive_adx_key8(keystring, &cfg.cri_key1, &cfg.cri_key2, &cfg.cri_key3);
VGM_LOG("ok: %x, %x, %x\n", cfg.cri_key1, cfg.cri_key2, cfg.cri_key3 );
}
#endif
}
}
vgmstream->layout_type = layout_none;
vgmstream->codec_data = init_mpeg_custom(streamFile, start_offset, &vgmstream->coding_type, channel_count, MPEG_AHX, &cfg);
vgmstream->codec_data = init_mpeg_custom(sf, start_offset, &vgmstream->coding_type, channels, MPEG_AHX, &cfg);
if (!vgmstream->codec_data) goto fail;
#else
goto fail;
#endif
}
if ( !vgmstream_open_stream(vgmstream, streamFile, start_offset) )
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:

View File

@ -1,5 +1,7 @@
#include "meta.h"
#include "../coding/coding.h"
#include "sqex_streamfile.h"
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
/* AKB (AAC only) - found in SQEX iOS games */
@ -11,8 +13,8 @@ VGMSTREAM * init_vgmstream_akb_mp4(STREAMFILE *sf) {
if ((uint32_t)read_32bitBE(0, sf) != 0x414b4220) goto fail;
loop_start = read_32bitLE(0x14, sf);
loop_end = read_32bitLE(0x18, sf);
loop_start = read_s32le(0x14, sf);
loop_end = read_s32le(0x18, sf);
filesize = get_streamfile_size( sf );
@ -33,40 +35,59 @@ fail:
#endif
/* AKB - found in SQEX iOS games */
VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
/* AKB - found in SQEX 'sdlib' iOS/Android games */
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;
int loop_flag = 0, channel_count, codec, sample_rate;
int loop_flag = 0, channels, codec, sample_rate, version, flags = 0;
int num_samples, loop_start, loop_end;
/* checks */
if ( !check_extensions(sf, "akb") )
goto fail;
if (read_32bitBE(0x00,sf) != 0x414B4220) /* "AKB " */
goto fail;
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
if (!is_id32be(0x00,sf, "AKB "))
goto fail;
/* 0x04(1): version */
header_size = read_16bitLE(0x06,sf);
if (!check_extensions(sf, "akb"))
goto fail;
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);
version = read_u8(0x04,sf); /* 00=TWEWY, 02=DQs, 03=FFAgito */
/* 0x05(1); unused? */
header_size = read_u16le(0x06,sf);
if (read_u32le(0x08,sf) != get_streamfile_size(sf))
goto fail;
/* material info, though can only hold 1 */
codec = read_u8(0x0c,sf);
channels = read_u8(0x0d,sf);
sample_rate = read_u16le(0x0e,sf);
num_samples = read_s32le(0x10,sf);
loop_start = read_s32le(0x14,sf);
loop_end = read_s32le(0x18,sf);
/* possibly more complex, see AKB2 */
if (header_size >= 0x44) { /* v2+ */
extradata_size = read_16bitLE(0x1c,sf);
extradata_size = read_u16le(0x1c,sf);
/* 0x20+: config? (pan, volume) */
subheader_size = read_16bitLE(0x28,sf);
subheader_size = read_u16le(0x28,sf);
/* 0x24: file_id? */
/* 0x2b: encryption bitflag if version > 2? */
/* 0x28: */
/* 0x29: */
/* 0x2a: */
/* flags:
* 1: (v2+) enable random volume
* 2: (v2+) enable random pitch
* 4: (v2+) enable random pan
* 8: (v3+) encryption (for MS-ADPCM / Ogg) [Final Fantasy Agito (Android)-ogg bgm only, other sounds don't use AKB] */
flags = read_u8(0x2B,sf);
/* 0x2c: max random volume */
/* 0x30: min random volume */
/* 0x34: max random pitch */
/* 0x38: min random pitch */
/* 0x3c: max random pan */
/* 0x40: min random pan */
extradata_offset = header_size + subheader_size;
start_offset = extradata_offset + extradata_size;
}
@ -79,30 +100,34 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_AKB;
vgmstream->sample_rate = sample_rate;
switch (codec) {
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,sf);
vgmstream->frame_size = read_u16le(extradata_offset + 0x02,sf);
/* encryption, untested but should be the same as Ogg */
if (version >= 3 && (flags & 8))
goto fail;
/* 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, sf);
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
vgmstream->num_samples = read_s32le(extradata_offset + 0x04, sf);
vgmstream->loop_start_sample = read_s32le(extradata_offset + 0x08, sf);
vgmstream->loop_end_sample = read_s32le(extradata_offset + 0x0c, sf);
break;
}
#ifdef VGM_USE_VORBIS
case 0x05: { /* Ogg Vorbis [Final Fantasy VI (iOS), Dragon Quest II-VI (iOS)] */
STREAMFILE* temp_sf;
VGMSTREAM *ogg_vgmstream = NULL;
ogg_vorbis_meta_info_t ovmi = {0};
@ -111,7 +136,20 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
/* extradata + 0x04: Ogg loop start offset */
/* oggs have loop info in the comments */
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
/* enable encryption */
if (version >= 3 && (flags & 8)) {
VGM_LOG("temp1\n");
temp_sf = setup_sqex_streamfile(sf, start_offset, stream_size, 1, 0x00, 0x00, "ogg");
if (!temp_sf) goto fail;
VGM_LOG("temp2\n");
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(temp_sf, 0x00, &ovmi);
close_streamfile(temp_sf);
}
else {
ogg_vgmstream = init_vgmstream_ogg_vorbis_config(sf, start_offset, &ovmi);
}
if (ogg_vgmstream) {
close_vgmstream(vgmstream);
return ogg_vgmstream;
@ -161,13 +199,13 @@ VGMSTREAM * init_vgmstream_akb(STREAMFILE *sf) {
}
#endif
case 0x01: /* PCM16LE */
case 0x01: /* PCM16LE (from debugging, not seen) */
default:
goto fail;
}
/* open the file for reading */
if ( !vgmstream_open_stream(vgmstream, sf, start_offset) )
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
@ -178,67 +216,69 @@ fail:
}
/* AKB2 - found in later SQEX iOS games */
VGMSTREAM * init_vgmstream_akb2(STREAMFILE *sf) {
VGMSTREAM * vgmstream = NULL;
/* AKB2 - found in later SQEX 'sdlib' iOS/Android games */
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 loop_flag = 0, channel_count, flags, codec, sample_rate, num_samples, loop_start, loop_end;
int total_subsongs, target_subsong = sf->stream_index;
/* check extensions */
if ( !check_extensions(sf, "akb") )
goto fail;
/* checks */
if (read_32bitBE(0x00,sf) != 0x414B4232) /* "AKB2" */
if (!is_id32be(0x00,sf, "AKB2"))
goto fail;
if (read_32bitLE(0x08,sf) != get_streamfile_size(sf))
if (!check_extensions(sf, "akb"))
goto fail;
/* 0x04: version */
if (read_u32le(0x08,sf) != get_streamfile_size(sf))
goto fail;
/* parse tables */
{
off_t table_offset;
size_t table_size, entry_size;
off_t akb_header_size = read_16bitLE(0x06, sf);
int table_count = read_8bit(0x0c, sf);
off_t akb_header_size = read_u16le(0x06, sf);
int table_count = read_u8(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, sf);
table_size = read_16bitLE(table_offset + 0x02, sf);
table_offset = read_u32le(akb_header_size + (table_count-1)*entry_size + 0x04, sf);
table_size = read_u16le(table_offset + 0x02, sf);
total_subsongs = read_8bit(table_offset + 0x0f, sf); /* can contain 0 entries too */
total_subsongs = read_u8(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, sf);
material_offset = table_offset + read_u32le(table_offset + table_size + (target_subsong-1)*entry_size + 0x04, sf);
}
/** stream header (material) **/
/* 0x00: 0? */
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);
codec = read_u8(material_offset+0x01,sf);
channel_count = read_u8(material_offset+0x02,sf);
flags = read_u8(material_offset+0x03,sf);
material_size = read_u16le(material_offset+0x04,sf);
sample_rate = read_u16le(material_offset+0x06,sf);
stream_size = read_u32le(material_offset+0x08,sf);
num_samples = read_s32le(material_offset+0x0c,sf);
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_start = read_s32le(material_offset+0x10,sf);
loop_end = read_s32le(material_offset+0x14,sf);
extradata_size = read_u32le(material_offset+0x18,sf);
/* rest: ? (empty, floats or 0x3f80) */
loop_flag = (loop_end > loop_start);
extradata_offset = material_offset + material_size;
start_offset = material_offset + material_size + extradata_size;
if (encryption_flag & 0x08)
/* encrypted, not seen (see AKB flags) */
if (flags & 0x08)
goto fail;
@ -267,14 +307,14 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *sf) {
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, sf);
vgmstream->frame_size = read_u16le(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, sf);
vgmstream->loop_start_sample = read_32bitLE(extradata_offset + 0x08, sf);
vgmstream->loop_end_sample = read_32bitLE(extradata_offset + 0x0c, sf);
vgmstream->num_samples = read_s32le(extradata_offset + 0x04, sf);
vgmstream->loop_start_sample = read_s32le(extradata_offset + 0x08, sf);
vgmstream->loop_end_sample = read_s32le(extradata_offset + 0x0c, sf);
break;
}
@ -317,8 +357,8 @@ VGMSTREAM * init_vgmstream_akb2(STREAMFILE *sf) {
/* 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,sf);//num_samples;
vgmstream->loop_start_sample = read_32bitLE(material_offset+0x10,sf);//loop_start;
vgmstream->num_samples = read_s32le(material_offset+0x0c,sf);//num_samples;
vgmstream->loop_start_sample = read_s32le(material_offset+0x10,sf);//loop_start;
vgmstream->loop_end_sample = loop_end;
break;
}

View File

@ -1,48 +1,48 @@
#include "meta.h"
#include "../coding/coding.h"
/* APC - from Cryo games [MegaRace 3 (PC)] */
VGMSTREAM * init_vgmstream_apc(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
size_t data_size;
int loop_flag, channel_count;
/* checks */
if ( !check_extensions(streamFile,"apc") )
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x4352594F) /* "CRYO" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x5F415043) /* "_APC" */
goto fail;
//if (read_32bitBE(0x08,streamFile) != 0x312E3230) /* "1.20" */
// goto fail;
/* 0x14/18: L/R hist sample? */
start_offset = 0x20;
data_size = get_streamfile_size(streamFile) - start_offset;
channel_count = read_32bitLE(0x1c,streamFile) == 0 ? 1 : 2;
loop_flag = 0;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_APC;
vgmstream->sample_rate = read_32bitLE(0x10,streamFile);
vgmstream->num_samples = ima_bytes_to_samples(data_size,channel_count);
vgmstream->coding_type = coding_IMA;
vgmstream->layout_type = layout_none;
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"
/* APC - from Cryo games [MegaRace 3 (PC)] */
VGMSTREAM* init_vgmstream_apc(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset, data_size;
int loop_flag, channels, sample_rate;
/* checks */
if (!is_id32be(0x00,sf, "CRYO"))
goto fail;
if (!is_id32be(0x04,sf, "_APC"))
goto fail;
//if (!is_id32be(0x04,sf, "1.20"))
// goto fail;
if (!check_extensions(sf,"apc"))
goto fail;
sample_rate = read_s32le(0x10,sf);
/* 0x14/18: L/R hist sample? */
channels = read_s32le(0x1c,sf) == 0 ? 1 : 2;
loop_flag = 0;
start_offset = 0x20;
data_size = get_streamfile_size(sf) - start_offset;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->meta_type = meta_APC;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = ima_bytes_to_samples(data_size, channels);
vgmstream->coding_type = coding_IMA;
vgmstream->layout_type = layout_none;
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -1,58 +1,63 @@
#include "meta.h"
#include "../coding/coding.h"
/* ASF - Argonaut PC games [Croc 2 (PC), Aladdin: Nasira's Revenge (PC)] */
VGMSTREAM * init_vgmstream_asf(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset;
int loop_flag, channel_count, version;
/* checks */
/* .asf: original
* .lasf: fake for plugins */
if (!check_extensions(streamFile, "asf,lasf"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x41534600) /* "ASF\0" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x02000100)
goto fail;
if (read_32bitLE(0x08,streamFile) != 0x01 &&
read_32bitLE(0x0c,streamFile) != 0x18 &&
read_32bitLE(0x1c,streamFile) != 0x20)
goto fail;
version = read_32bitLE(0x28,streamFile); /* assumed? */
switch(version){
case 0x0d: channel_count = 1; break; /* Aladdin: Nasira's Revenge (PC) */
case 0x0f: channel_count = 2; break; /* Croc 2 (PC), The Emperor's New Groove (PC) */
default: goto fail;
}
loop_flag = 0;
start_offset = 0x2c;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x24, streamFile);
vgmstream->meta_type = meta_ASF;
vgmstream->coding_type = coding_ASF;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x11;
vgmstream->num_samples = (get_streamfile_size(streamFile)-start_offset)/(0x11*channel_count)*32; /* bytes_to_samples */
//vgmstream->num_samples = read_32bitLE(0x18,streamFile) * (0x20<<channel_count); /* something like this? */
read_string(vgmstream->stream_name,0x10, 0x08+1,streamFile);
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"
/* ASF - Argonaut PC games [Croc 2 (PC), Aladdin: Nasira's Revenge (PC)] */
VGMSTREAM* init_vgmstream_asf(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset;
int loop_flag, channels, type, sample_rate;
/* checks */
if (!is_id32be(0x00,sf, "ASF\0"))
goto fail;
/* .asf: original
* .lasf: fake for plugins */
if (!check_extensions(sf, "asf,lasf"))
goto fail;
if (read_u32le(0x04,sf) != 0x00010002) /* v1.002? */
goto fail;
if (read_u32le(0x08,sf) != 0x01 &&
read_u32le(0x0c,sf) != 0x18)
goto fail;
/* 0x10~18: stream name (same as filename) */
/* 0x18: non-full size? */
if (read_u32le(0x1c,sf) != 0x20) /* samples per frame? */
goto fail;
sample_rate = read_u16le(0x24, sf);
type = read_u32le(0x28,sf); /* assumed? */
switch(type){
case 0x0d: channels = 1; break; /* Aladdin: Nasira's Revenge (PC) */
case 0x0f: channels = 2; break; /* Croc 2 (PC), The Emperor's New Groove (PC) */
default: goto fail;
}
loop_flag = 0;
start_offset = 0x2c;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
vgmstream->meta_type = meta_ASF;
vgmstream->coding_type = coding_ASF;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 0x11;
vgmstream->num_samples = (get_streamfile_size(sf) - start_offset) / (0x11 * channels) * 32; /* bytes_to_samples */
//vgmstream->num_samples = read_32bitLE(0x18,sf) * (32 << channels); /* something like this? */
read_string(vgmstream->stream_name,0x10, 0x08+1,sf);
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -206,10 +206,13 @@ VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf) {
/* Not an actual stream but typically convolution reverb models and other FX plugin helpers.
* Useless but to avoid "subsong not playing" complaints. */
if (read_u32(0x00, sf) == 0x0400 &&
/* Wwise Convolution Reverb */
if ((read_u32(0x00, sf) == 0x00000400 || /* common */
read_u32(0x00, sf) == 0x00020400 ) && /* Elden Ring */
read_u32(0x04, sf) == 0x0800) {
sample_rate = read_u32(0x08, sf);
channels = read_u32(0x0c, sf) & 0xFF; /* 0x31 at 0x0d in PC, field is 32b vs X360 */
/* 0x10: some id or small size? (related to entries?) */
/* 0x14/18: some float? */
entries = read_u32(0x1c, sf);

View File

@ -477,6 +477,7 @@ VGMSTREAM* init_vgmstream_fsb5(STREAMFILE* sf) {
cfg.channels = fsb5.channels;
cfg.sample_rate = fsb5.sample_rate;
cfg.setup_id = read_u32le(fsb5.extradata_offset,sf);
cfg.stream_end = fsb5.stream_offset + fsb5.stream_size;
vgmstream->codec_data = init_vorbis_custom(sb, fsb5.stream_offset, VORBIS_FSB, &cfg);
if (!vgmstream->codec_data) goto fail;

View File

@ -988,6 +988,9 @@ static const hcakey_info hcakey_list[] = {
// Sonic Origins
{1991062320220623}, // 000712DC525289CF
// Pachislot Gyakuten Saiban (iOS/Android)
{2220022040477322}, // 0007E319291DBE8A
};
#endif/*_HCA_KEYS_H_*/

View File

@ -39,7 +39,13 @@ VGMSTREAM* init_vgmstream_kwb(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00, sf, "WBD_") &&
!is_id32le(0x00, sf, "WBD_") &&
!is_id32be(0x00, sf, "WHD1"))
goto fail;
/* .wbd+wbh: common [Bladestorm Nightmare (PC)]
* .wbd+whd: uncommon [Nights of Azure 2 (PS4)]
* .wb2+wh2: newer [Nights of Azure 2 (PC)]
* .sed: mixed header+data [Dissidia NT (PC)] */
if (!check_extensions(sf, "wbd,wb2,sed"))
@ -47,18 +53,20 @@ VGMSTREAM* init_vgmstream_kwb(STREAMFILE* sf) {
/* open companion header */
if (check_extensions(sf, "wbd")) {
if (is_id32be(0x00, sf, "WHD1")) { /* .sed */
sf_h = sf;
sf_b = sf;
}
else if (check_extensions(sf, "wbd")) {
sf_h = open_streamfile_by_ext(sf, "wbh");
if (!sf_h)
sf_h = open_streamfile_by_ext(sf, "whd");
sf_b = sf;
}
else if (check_extensions(sf, "wb2")) {
sf_h = open_streamfile_by_ext(sf, "wh2");
sf_b = sf;
}
else if (check_extensions(sf, "sed")) {
sf_h = sf;
sf_b = sf;
}
else {
goto fail;
}
@ -378,14 +386,14 @@ fail:
return 0;
}
static int parse_type_k4hd(kwb_header* kwb, off_t offset, off_t body_offset, STREAMFILE* sf_h) {
static int parse_type_k4hd_pvhd(kwb_header* kwb, off_t offset, off_t body_offset, STREAMFILE* sf_h) {
off_t ppva_offset, header_offset;
int entries, current_subsongs, relative_subsong;
size_t entry_size;
/* a format mimicking PSVita's hd4+bd4 format */
/* 00: K4HD id */
/* 00: K4HD/PVHD id */
/* 04: chunk size */
/* 08: ? */
/* 0c: ? */
@ -565,7 +573,7 @@ static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
if (read_u32be(0x00, sf_h) == 0x57484431) { /* "WHD1" */
if (is_id32be(0x00, sf_h, "WHD1")) {
/* container of fused .wbh+wbd */
/* 0x04: fixed value? */
kwb->big_endian = read_u8(0x08, sf_h) == 0xFF;
@ -617,7 +625,8 @@ static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
break;
case 0x4B344844: /* "K4HD" [Dissidia NT (PS4), (Vita) */
if (!parse_type_k4hd(kwb, head_offset, body_offset, sf_h))
case 0x50564844: /* "PVHD" [Nights of Azure 2 (PS4)] */
if (!parse_type_k4hd_pvhd(kwb, head_offset, body_offset, sf_h))
goto fail;
break;
@ -632,6 +641,7 @@ static int parse_kwb(kwb_header* kwb, STREAMFILE* sf_h, STREAMFILE* sf_b) {
break;
default:
vgm_logi("KWB: unknown type\n");
goto fail;
}

View File

@ -3,48 +3,45 @@
#include "../coding/coding.h"
#include <string.h>
/* .s14 and .sss - headerless siren14 stream (The Idolm@ster DS, Korogashi Puzzle Katamari Damacy DS) */
VGMSTREAM * init_vgmstream_s14_sss(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
static int test_interleave(STREAMFILE* sf, int channels, int interleave);
/* .s14/.sss - headerless siren14 stream [The Idolm@ster (DS), Korogashi Puzzle Katamari Damacy (DS), Taiko no Tatsujin DS 1/2 (DS)] */
VGMSTREAM* init_vgmstream_s14_sss(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset = 0;
int channel_count, loop_flag = 0, interleave;
int channels, loop_flag = 0, interleave;
/* check extension */
if (check_extensions(streamFile,"sss")) {
channel_count = 2;
} else if (check_extensions(streamFile,"s14")) {
channel_count = 1; //todo missing dual _0ch.s14 _1ch.s14, but dual_ext thing doesn't work properly with siren14 decoder
if (check_extensions(sf,"sss")) {
channels = 2;
} else if (check_extensions(sf,"s14")) {
channels = 1; /* may have dual _0ch.s14 + _1ch.s14, needs .txtp */
} else {
goto fail;
}
/* raw siren comes in 3 frame sizes, try to guess the correct one
* (should try to decode and check the error flag but it isn't currently reported) */
/* raw siren comes in 3 frame sizes, try to guess the correct one */
{
char filename[PATH_LIMIT];
streamFile->get_name(streamFile,filename,sizeof(filename));
/* horrid but I ain't losing sleep over it (besides the header is often incrusted in-code as some tracks loop) */
if (strstr(filename,"S037")==filename || strstr(filename,"b06")==filename || /* Korogashi Puzzle Katamari Damacy */
strstr(filename,"_48kbps")!=NULL) /* Taiko no Tatsujin DS 1/2 */
/* horrid but ain't losing sleep over it (besides the header is often incrusted in-code as some tracks loop)
* Katamari, Taiko = 0x78/0x50, idolmaster=0x3c (usually but can be any) */
if (test_interleave(sf, channels, 0x78))
interleave = 0x78;
else if (strstr(filename,"32700")==filename || /* Hottarake no Shima - Kanata to Nijiiro no Kagami */
strstr(filename,"b0")==filename || strstr(filename,"puzzle")==filename || strstr(filename,"M09")==filename || /* Korogashi Puzzle Katamari Damacy */
strstr(filename,"_32kbps")!=NULL) /* Taiko no Tatsujin DS 1/2 */
interleave = 0x50;
else if (test_interleave(sf, channels, 0x50))
interleave = 0x50;
else if (test_interleave(sf, channels, 0x3c))
interleave = 0x3c;
else
interleave = 0x3c; /* The Idolm@ster - Dearly Stars */
goto fail;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels,loop_flag);
if (!vgmstream) goto fail;
vgmstream->num_samples = get_streamfile_size(streamFile) / (interleave * channel_count) * (32000/50);
vgmstream->sample_rate = 32768; /* maybe 32700? */
vgmstream->num_samples = get_streamfile_size(sf) / (interleave * channels) * (32000/50);
vgmstream->sample_rate = 32768;
vgmstream->meta_type = channel_count==1 ? meta_S14 : meta_SSS;
vgmstream->meta_type = channels==1 ? meta_S14 : meta_SSS;
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = interleave;
@ -58,7 +55,7 @@ VGMSTREAM * init_vgmstream_s14_sss(STREAMFILE *streamFile) {
#endif
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
@ -66,3 +63,27 @@ fail:
close_vgmstream(vgmstream);
return NULL;
}
/* pretty gross (should use TXTH), but codec info seems to be in hard-to-locate places/exe
* and varies per file, so for now autodetect possible types. could also check if data_size matches interleave */
static int test_interleave(STREAMFILE* sf, int channels, int interleave) {
#ifdef VGM_USE_G7221
int res;
g7221_codec_data* data = init_g7221(channels, interleave);
if (!data) goto fail;
set_key_g7221(data, NULL); /* force test key */
/* though this is mainly for key testing, with no key can be used to test frames too */
res = test_key_g7221(data, 0x00, sf);
if (res <= 0) goto fail;
free_g7221(data);
return 1;
fail:
free_g7221(data);
return 0;
#else
return 0;
#endif
}

View File

@ -32,7 +32,7 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) {
/* checks */
/* .sgx: header+data (Genji)
* .sgd: header+data (common)
* .sgh+sgd: header+data */
* .sgh+sgd: header+data (streams) */
if (!check_extensions(sf,"sgx,sgd,sgb"))
goto fail;
@ -73,7 +73,32 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) {
}
/* typical chunks: WAVE, RGND, NAME (strings for WAVE or RGND), SEQD (related to SFX), WSUR, WMKR, BUSS */
/* Format per chunk:
* - 0x00: id
* - 0x04: SGX: unknown; SGD/SGH: chunk length
* - 0x08: null
* - 0x0c: entries */
/* typical chunks (with some entry info):
* - WAVE: wave data (see below)
* - RGND: programs info, notably:
* - 0x18: min note range
* - 0x19: max note range
* - 0x1C: root note
* - 0x34: WAVE id
* > sample_rate = wave_sample_rate * (2 ^ (1/12)) ^ (target_note - root_note)
* - NAME: strings for other chunks
* - 0x00: sub-id?
* - 0x02: type? (possibly: 0000=bank, 0x2xxx=SEQD/WAVE, 0x3xxx=WSUR, 0x4xxx=BUSS, 0x6xxx=CONF)
* - 0x04: absolute offset
* - SEQD: related to SFX (sequences?), entries seem to be offsets to name offset + sequence offset
* > sequence format seems to be 1 byte type (0=sfx, 1=music) + midi without header
* (default tick resolution of 960 pulses per quarter note)
* - WSUR: ?
* - WMKR: ?
* - CONF: ? (name offset + config offset)
* - BUSS: bus config?
/* WAVE chunk (size 0x10 + files * 0x38 + optional padding) */
if (is_sgx) { /* position after chunk+size */
if (!is_id32be(0x10,sf_head, "WAVE"))
@ -83,7 +108,6 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) {
if (!find_chunk_le(sf_head, get_id32be("WAVE"),0x10,0, &chunk_offset, NULL))
goto fail;
}
/* 0x04 SGX: unknown; SGD/SGH: chunk length, 0x08 null */
/* check multi-streams (usually only SE containers; Puppeteer) */
total_subsongs = read_s32le(chunk_offset+0x04,sf_head);
@ -95,18 +119,18 @@ VGMSTREAM* init_vgmstream_sgxd(STREAMFILE* sf) {
uint32_t stream_offset;
chunk_offset += 0x08 + 0x38 * (target_subsong-1); /* position in target header*/
/* 0x00 ? (00/01/02) */
/* 0x00: ? (00/01/02) */
if (!is_sgx) /* meaning unknown in .sgx; offset 0 = not a stream (a RGND sample) */
name_offset = read_u32le(chunk_offset+0x04,sf_head);
codec = read_u8(chunk_offset+0x08,sf_head);
channels = read_u8(chunk_offset+0x09,sf_head);
/* 0x0a null */
/* 0x0a: null */
sample_rate = read_s32le(chunk_offset+0x0c,sf_head);
/* 0x10: info_type, meaning of the next value
* (00=null, 30/40=data size without padding (ADPCM, ATRAC3plus), 80/A0=block size (AC3) */
/* 0x14: info_value (see above) */
/* 0x18: unknown (ex. 0x0008/0010/3307/CC02/etc)x2 */
/* 0x18: unknown (ex. 0x0008/0010/3307/CC02/etc, RGND related?) x2 */
/* 0x1c: null */
num_samples = read_s32le(chunk_offset+0x20,sf_head);

View File

@ -6,7 +6,7 @@
VGMSTREAM* init_vgmstream_sndz(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* sf_b = NULL;
uint32_t stream_offset, stream_size, name_offset, head_size, data_size;
uint32_t stream_offset, stream_size, name_offset, data_size;
int channels, loop_flag, sample_rate, codec, streamed;
int32_t num_samples, loop_start, loop_end;
uint32_t at9_config;
@ -16,7 +16,7 @@ VGMSTREAM* init_vgmstream_sndz(STREAMFILE* sf) {
if (!is_id32be(0x00, sf, "SNDZ"))
goto fail;
head_size = read_u32le(0x04, sf);
//head_size = read_u32le(0x04, sf);
data_size = read_u32le(0x08, sf);
/* 0x0c: version? (0x00010001) */
/* 0x10: size size? */
@ -26,8 +26,8 @@ VGMSTREAM* init_vgmstream_sndz(STREAMFILE* sf) {
/* .szd1: header + .szd2 = data
* .szd3: szd1 + szd2 */
if (!check_extensions(sf, "szd1,szd3"))
* .szd/szd3: szd1 + szd2 */
if (!check_extensions(sf, "szd1,szd,szd3"))
goto fail;
/* parse chunk table and WAVS with offset to offset to WAVD */
@ -95,7 +95,6 @@ VGMSTREAM* init_vgmstream_sndz(STREAMFILE* sf) {
loop_flag = loop_end > 0;
}
VGM_LOG("%i, %x, %x, %x\n", streamed, head_size, data_size, get_streamfile_size(sf));
/* szd3 is streamed but has header+data together, with padding between (data_size is the same as file size)*/
if (streamed && get_streamfile_size(sf) < data_size) {
sf_b = open_streamfile_by_ext(sf, "szd2");

View File

@ -1,6 +1,6 @@
#include "meta.h"
#include "../coding/coding.h"
#include "sqex_sead_streamfile.h"
#include "sqex_streamfile.h"
typedef struct {
@ -278,7 +278,7 @@ VGMSTREAM* init_vgmstream_sqex_sead(STREAMFILE* sf) {
/* 0x0e: reserved x2 */
/* 0x10+ HCA header */
temp_sf = setup_sqex_sead_streamfile(sf, subfile_offset, subfile_size, encryption, header_size, key_start);
temp_sf = setup_sqex_streamfile(sf, subfile_offset, subfile_size, encryption, header_size, key_start, "hca");
if (!temp_sf) goto fail;
temp_vgmstream = init_vgmstream_hca(temp_sf);

View File

@ -6,11 +6,11 @@
typedef struct {
size_t start;
size_t key_start;
} sqex_sead_io_data;
} sqex_io_data;
static size_t sqex_sead_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, sqex_sead_io_data* data) {
/* Found in FFXII_TZA.exe (same key in SCD Ogg V3) */
static size_t sqex_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, size_t length, sqex_io_data* data) {
/* Found in FFXII_TZA.exe (same key in SCD Ogg V3), also in AKB's sdlib as "EncKey" */
static const uint8_t key[0x100] = {
0x3A,0x32,0x32,0x32,0x03,0x7E,0x12,0xF7,0xB2,0xE2,0xA2,0x67,0x32,0x32,0x22,0x32, // 00-0F
0x32,0x52,0x16,0x1B,0x3C,0xA1,0x54,0x7B,0x1B,0x97,0xA6,0x93,0x1A,0x4B,0xAA,0xA6, // 10-1F
@ -45,22 +45,22 @@ static size_t sqex_sead_io_read(STREAMFILE *sf, uint8_t *dest, off_t offset, siz
}
/* decrypts subfile if needed */
static STREAMFILE* setup_sqex_sead_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, int encryption, size_t header_size, size_t key_start) {
static STREAMFILE* setup_sqex_streamfile(STREAMFILE* sf, off_t subfile_offset, size_t subfile_size, int encryption, size_t header_size, size_t key_start, const char* ext) {
STREAMFILE* new_sf = NULL;
/* setup sf */
new_sf = open_wrap_streamfile(sf);
new_sf = open_clamp_streamfile_f(new_sf, subfile_offset, subfile_size);
if (encryption) {
sqex_sead_io_data io_data = {0};
sqex_io_data io_data = {0};
io_data.start = header_size;
io_data.key_start = key_start;
new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(sqex_sead_io_data), sqex_sead_io_read, NULL);
new_sf = open_io_streamfile_f(new_sf, &io_data, sizeof(sqex_io_data), sqex_io_read, NULL);
}
new_sf = open_fakename_streamfile_f(new_sf, NULL, "hca");
new_sf = open_fakename_streamfile_f(new_sf, NULL, ext);
return new_sf;
}

View File

@ -5,35 +5,52 @@
/* SWAV - wave files generated by the DS SDK */
VGMSTREAM* init_vgmstream_swav(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
int channel_count, loop_flag;
off_t start_offset;
int codec_number, bits_per_sample;
uint32_t start_offset, data_size, file_size;
int channels, loop_flag, codec, bits_per_sample, sample_rate;
int32_t loop_start, loop_end;
coding_t coding_type;
/* checks */
if (!is_id32be(0x00,sf, "SWAV"))
goto fail;
/* .swav: standard
* .adpcm: Merlin - A Servant of Two Masters (DS) */
if (!check_extensions(sf, "swav,adpcm"))
goto fail;
if (read_u32be(0x00,sf) != 0x53574156) /* "SWAV" */
goto fail;
if (read_u32be(0x10,sf) != 0x44415441) /* "DATA" */
goto fail;
/* 0x04: BOM mark */
/* 0x06: version? (1.00) */
file_size = read_u32le(0x08,sf);
/* 0x0c: always 16? */
/* 0x0e: always 1? */
/* check type details */
codec_number = read_8bit(0x18,sf);
loop_flag = read_8bit(0x19,sf);
if (!is_id32be(0x10,sf, "DATA"))
goto fail;
data_size = read_u32le(0x14,sf);
codec = read_u8(0x18,sf);
loop_flag = read_u8(0x19,sf);
sample_rate = read_u16le(0x1A,sf);
/* 0x1c: related to size? */
loop_start = read_u16le(0x1E,sf);
loop_end = read_s32le(0x20,sf);
channel_count = 1;
if (get_streamfile_size(sf) != read_s32le(0x08,sf)) {
if (get_streamfile_size(sf) != (read_s32le(0x08,sf) - 0x24) * 2 + 0x24)
start_offset = 0x24;
/* strange values found in Face Training (DSi) samples, may be pitch/etc reference info? (samples sounds ok like this) */
if (sample_rate < 0x2000)
sample_rate = 44100;
channels = 1;
if (get_streamfile_size(sf) != file_size) {
if (get_streamfile_size(sf) != (file_size - 0x24) * 2 + 0x24)
goto fail;
channel_count = 2;
channels = 2;
}
switch (codec_number) {
switch (codec) {
case 0:
coding_type = coding_PCM8;
bits_per_sample = 8;
@ -49,18 +66,17 @@ VGMSTREAM* init_vgmstream_swav(STREAMFILE* sf) {
default:
goto fail;
}
start_offset = 0x24;
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->num_samples = (read_s32le(0x14,sf) - 0x14) * 8 / bits_per_sample;
vgmstream->sample_rate = read_u16le(0x1A,sf);
vgmstream->num_samples = (data_size - 0x14) * 8 / bits_per_sample;
vgmstream->sample_rate = sample_rate;
if (loop_flag) {
vgmstream->loop_start_sample = read_u16le(0x1E,sf) * 32 / bits_per_sample;
vgmstream->loop_end_sample = read_s32le(0x20,sf) * 32 / bits_per_sample + vgmstream->loop_start_sample;
vgmstream->loop_start_sample = loop_start * 32 / bits_per_sample;
vgmstream->loop_end_sample = loop_end * 32 / bits_per_sample + vgmstream->loop_start_sample;
}
if (coding_type == coding_IMA_int) {
@ -71,18 +87,18 @@ VGMSTREAM* init_vgmstream_swav(STREAMFILE* sf) {
{
int i;
for (i = 0; i < channel_count; i++) {
for (i = 0; i < channels; i++) {
vgmstream->ch[i].adpcm_history1_32 = read_s16le(start_offset + 0 + 4*i, sf);
vgmstream->ch[i].adpcm_step_index = read_s16le(start_offset + 2 + 4*i, sf);
}
}
start_offset += 4 * channel_count;
start_offset += 4 * channels;
}
vgmstream->coding_type = coding_type;
vgmstream->meta_type = meta_SWAV;
if (channel_count == 2) {
if (channels == 2) {
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = 1;
} else {

View File

@ -52,8 +52,8 @@ VGMSTREAM* init_vgmstream_vag(STREAMFILE* sf) {
/* check variation */
switch(vag_id) {
case 0x56414731: /* "VAG1" [Metal Gear Solid 3 (PS2), Cabela's African Safari (PSP)] */
meta_type = meta_PS2_VAG1; //TODO not always Konami
case 0x56414731: /* "VAG1" [Metal Gear Solid 3 (PS2), Cabela's African Safari (PSP), Shamu's Deep Sea Adventures (PS2)] */
meta_type = meta_PS2_VAG1; //TODO not always Konami (Sand Grain Studios)
start_offset = 0x40; /* 0x30 is extra data in VAG1 */
interleave = 0x10;
loop_flag = 0;

View File

@ -1,71 +1,71 @@
#include "meta.h"
#include "../util/endianness.h"
#include "../coding/coding.h"
/* .WAVE - WayForward "EngineBlack" games [Mighty Switch Force! (3DS), Adventure Time: Hey Ice King! Why'd You Steal Our Garbage?! (3DS)] */
VGMSTREAM * init_vgmstream_wave(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
off_t start_offset, extradata_offset;
int loop_flag = 0, channel_count, sample_rate, codec;
int32_t num_samples, loop_start = 0, loop_end = 0;
size_t interleave;
VGMSTREAM* init_vgmstream_wave(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
uint32_t start_offset, extradata_offset, interleave;
int channels, loop_flag, sample_rate, codec;
int32_t num_samples, loop_start, loop_end;
int big_endian;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
float (*read_f32)(off_t,STREAMFILE*) = NULL;
read_u32_t read_u32;
read_s32_t read_s32;
read_f32_t read_f32;
/* checks */
if (!check_extensions(streamFile, "wave"))
if (!is_id32be(0x00,sf, "VAW3") && /* Happy Feet Two (3DS) */
read_u32le(0x00,sf) != 0xE5B7ECFE && /* common (LE) */
read_u32be(0x00,sf) != 0xE5B7ECFE) /* used? */
goto fail;
/* 0x04: version? common=0, VAW3=2 */
if (read_32bitLE(0x00,streamFile) != 0xE5B7ECFE && /* header id */
read_32bitBE(0x00,streamFile) != 0xE5B7ECFE)
goto fail;
if (read_32bitBE(0x04,streamFile) != 0x00) /* version? */
if (!check_extensions(sf, "wave"))
goto fail;
/* assumed */
big_endian = read_32bitBE(0x00,streamFile) == 0xE5B7ECFE;
big_endian = read_u32be(0x00,sf) == 0xE5B7ECFE;
if (big_endian) {
read_32bit = read_32bitBE;
read_u32 = read_u32be;
read_s32 = read_s32be;
read_f32 = read_f32be;
} else {
read_32bit = read_32bitLE;
read_u32 = read_u32le;
read_s32 = read_s32le;
read_f32 = read_f32le;
}
channel_count = read_8bit(0x05,streamFile);
if (read_32bit(0x08,streamFile) != get_streamfile_size(streamFile))
goto fail;
if (read_8bit(0x0c,streamFile) != 0x00) /* ? */
if (read_u32(0x08,sf) != get_streamfile_size(sf))
goto fail;
sample_rate = (int)read_f32(0x0c, streamFile); /* sample rate in 32b float (WHY?) */
num_samples = read_32bit(0x10, streamFile);
loop_start = read_32bit(0x14, streamFile);
loop_end = read_32bit(0x18, streamFile);
sample_rate = (int)read_f32(0x0c, sf); /* WHY */
num_samples = read_s32(0x10, sf);
loop_start = read_s32(0x14, sf);
loop_end = read_s32(0x18, sf);
codec = read_8bit(0x1c, streamFile);
channel_count = read_8bit(0x1d, streamFile);
if (read_8bit(0x1e, streamFile) != 0x00) goto fail; /* unknown */
if (read_8bit(0x1f, streamFile) != 0x00) goto fail; /* unknown */
codec = read_u8(0x1c, sf);
channels = read_u8(0x1d, sf);
if (read_u8(0x1e, sf) != 0x00) goto fail; /* unknown */
if (read_u8(0x1f, sf) != 0x00) goto fail; /* unknown */
start_offset = read_32bit(0x20, streamFile);
interleave = read_32bit(0x24, streamFile); /* typically half data_size */
extradata_offset = read_32bit(0x28, streamFile); /* OR: extradata size (0x2c) */
start_offset = read_u32(0x20, sf);
interleave = read_u32(0x24, sf); /* typically half data_size */
extradata_offset = read_u32(0x28, sf); /* OR: extradata size (always 0x2c) */
loop_flag = (loop_start > 0);
/* some songs (ex. Adventure Time's m_candykingdom_overworld.wave) do full loops, but there is no way
* to tell them apart from sfx/voices, so we try to detect if it's long enough. */
if(!loop_flag
&& loop_start == 0 && loop_end == num_samples /* full loop */
&& channel_count > 1
&& channels > 1
&& num_samples > 20*sample_rate) { /* in seconds */
loop_flag = 1;
}
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count, loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = sample_rate;
@ -74,6 +74,7 @@ VGMSTREAM * init_vgmstream_wave(STREAMFILE *streamFile) {
vgmstream->loop_end_sample = loop_end;
vgmstream->meta_type = meta_WAVE;
/* not sure if there are other codecs but anyway */
switch(codec) {
case 0x02:
@ -82,14 +83,14 @@ VGMSTREAM * init_vgmstream_wave(STREAMFILE *streamFile) {
vgmstream->interleave_block_size = interleave;
/* ADPCM setup: 0x20 coefs + 0x06 initial ps/hist1/hist2 + 0x06 loop ps/hist1/hist2, per channel */
dsp_read_coefs(vgmstream, streamFile, extradata_offset+0x00, 0x2c, big_endian);
dsp_read_hist(vgmstream, streamFile, extradata_offset+0x22, 0x2c, big_endian);
dsp_read_coefs(vgmstream, sf, extradata_offset+0x00, 0x2c, big_endian);
dsp_read_hist(vgmstream, sf, extradata_offset+0x22, 0x2c, big_endian);
break;
default:
goto fail;
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;

View File

@ -172,6 +172,7 @@ VGMSTREAM* init_vgmstream_wwise_bnk(STREAMFILE* sf, int* p_prefetch) {
cfg.channels = ww.channels;
cfg.sample_rate = ww.sample_rate;
cfg.big_endian = ww.big_endian;
cfg.stream_end = ww.data_offset + ww.data_size;
if (ww.block_size != 0 || ww.bits_per_sample != 0) goto fail; /* always 0 for Worbis */
@ -237,7 +238,7 @@ VGMSTREAM* init_vgmstream_wwise_bnk(STREAMFILE* sf, int* p_prefetch) {
uint32_t setup_id = read_u32be(start_offset + setup_offset + 0x06, sf);
/* if the setup after header starts with "(data)BCV" it's an inline codebook) */
if ((setup_id & 0x00FFFFFF) == 0x00424356) { /* 0"BCV" */
if ((setup_id & 0x00FFFFFF) == get_id32be("\0BCV")) {
cfg.setup_type = WWV_FULL_SETUP;
}
/* if the setup is suspiciously big it's probably trimmed inline codebooks */
@ -582,7 +583,7 @@ VGMSTREAM* init_vgmstream_wwise_bnk(STREAMFILE* sf, int* p_prefetch) {
case mapping_2POINT1_xiph: /* 2ch+1ch, 2 streams */
case mapping_STEREO: cfg.coupled_count = 1; break; /* 2ch, 1 stream */
default: cfg.coupled_count = 0; break; /* 1ch, 1 stream */
//TODO: AK OPUS doesn't seem to handles others mappings, though AK's .h imply they exist (uses 0 coupleds?)
//TODO: AK OPUS doesn't seem to handle others mappings, though AK's .h imply they exist (uses 0 coupleds?)
}
/* total number internal OPUS streams (should be >0) */
@ -650,6 +651,11 @@ VGMSTREAM* init_vgmstream_wwise_bnk(STREAMFILE* sf, int* p_prefetch) {
vgmstream->layout_type = layout_none;
vgmstream->num_samples = read_s32(ww.fmt_offset + 0x1c, sf);
if (ww.prefetch) {
vgmstream->num_samples = atrac9_bytes_to_samples_cfg(ww.file_size - start_offset, cfg.config_data);
}
break;
}
#endif
@ -932,8 +938,8 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
}
if (ww->codec == PCM || ww->codec == IMA || ww->codec == VORBIS || ww->codec == DSP || ww->codec == XMA2 ||
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM || ww->codec == XWMA) {
ww->prefetch = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM || ww->codec == XWMA || ww->codec == ATRAC9) {
ww->prefetch = 1; /* only seen those, probably all exist (missing XWMA, AAC, HEVAG) */
} else {
vgm_logi("WWISE: wrong expected size, maybe prefetch (report)\n");
goto fail;
@ -945,7 +951,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
* From init bank and CAkSound's sources, those may be piped through their plugins. They come in
* .opuspak (no names), have wrong riff/data sizes and only seem used for sfx (other audio is Vorbis). */
if (ww->format == 0xFFFE && ww->prefetch) {
if (read_u32be(ww->data_offset + 0x00, sf) == 0x4F676753) {
if (is_id32be(ww->data_offset + 0x00, sf, "OggS")) {
ww->codec = OPUSCPR;
}
}

View File

@ -21,8 +21,13 @@ int vgmstream_ctx_is_valid(const char* filename, vgmstream_ctx_valid_cfg *cfg) {
extension = filename_extension(filename);
}
/* some metas accept extensionless files */
/* some metas accept extensionless files, but make sure it's not a path */
if (strlen(extension) <= 0) {
int len = strlen(filename);
if (len <= 0)
return 0;
if (filename[len - 1] == '/' || filename[len - 1] == '\\')
return 0;
return !cfg->reject_extensionless;
}

View File

@ -112,6 +112,7 @@
<string>2dx9</string>
<string>2pfs</string>
<string>3do</string>
<string>3ds</string>
<string>4</string>
<string>8</string>
<string>800</string>
@ -585,6 +586,7 @@
<string>sxd</string>
<string>sxd2</string>
<string>sxd3</string>
<string>szd</string>
<string>szd1</string>
<string>szd3</string>
<string>tad</string>