Updated VGMStream to r1050-2930-g9a1b37d2
parent
f5c7c4d49a
commit
bf95a58c02
|
@ -498,6 +498,7 @@
|
|||
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 */; };
|
||||
837CEB072348809400E62A4A /* seb.c in Sources */ = {isa = PBXBuildFile; fileRef = 837CEB062348809400E62A4A /* seb.c */; };
|
||||
8385D4E6245174C700FF8E67 /* diva.c in Sources */ = {isa = PBXBuildFile; fileRef = 8385D4E2245174C600FF8E67 /* diva.c */; };
|
||||
838BDB641D3AF08C0022CA6F /* libavcodec.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB611D3AF08C0022CA6F /* libavcodec.a */; };
|
||||
838BDB651D3AF08C0022CA6F /* libavformat.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB621D3AF08C0022CA6F /* libavformat.a */; };
|
||||
838BDB661D3AF08C0022CA6F /* libavutil.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 838BDB631D3AF08C0022CA6F /* libavutil.a */; };
|
||||
|
@ -1201,6 +1202,7 @@
|
|||
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>"; };
|
||||
837CEB062348809400E62A4A /* seb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = seb.c; sourceTree = "<group>"; };
|
||||
8385D4E2245174C600FF8E67 /* diva.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = diva.c; sourceTree = "<group>"; };
|
||||
838BDB611D3AF08C0022CA6F /* libavcodec.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavcodec.a; path = ../../ThirdParty/ffmpeg/lib/libavcodec.a; sourceTree = "<group>"; };
|
||||
838BDB621D3AF08C0022CA6F /* libavformat.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavformat.a; path = ../../ThirdParty/ffmpeg/lib/libavformat.a; sourceTree = "<group>"; };
|
||||
838BDB631D3AF08C0022CA6F /* libavutil.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libavutil.a; path = ../../ThirdParty/ffmpeg/lib/libavutil.a; sourceTree = "<group>"; };
|
||||
|
@ -1664,6 +1666,7 @@
|
|||
8373341E23F60CDB00DE14DC /* deblock_streamfile.h */,
|
||||
8349A8EE1FE6257C00E26435 /* dec.c */,
|
||||
834FE0CD215C79E8000A5D3D /* derf.c */,
|
||||
8385D4E2245174C600FF8E67 /* diva.c */,
|
||||
836F6E4318BDC2180095E648 /* dmsg_segh.c */,
|
||||
8351F32C2212B57000A606E4 /* dsf.c */,
|
||||
83299FCF1E7660C7003A3242 /* dsp_adx.c */,
|
||||
|
@ -2663,6 +2666,7 @@
|
|||
8306B0B220984552000302D4 /* blocked_mxch.c in Sources */,
|
||||
837CEAFA23487F2C00E62A4A /* xa_04sw.c in Sources */,
|
||||
836F6F8618BDC2190095E648 /* excitebots.c in Sources */,
|
||||
8385D4E6245174C700FF8E67 /* diva.c in Sources */,
|
||||
836F6FF418BDC2190095E648 /* rws.c in Sources */,
|
||||
834FE100215C79ED000A5D3D /* svg.c in Sources */,
|
||||
836F6F2518BDC2190095E648 /* g721_decoder.c in Sources */,
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
* read num_bits (up to 25) from a bit offset.
|
||||
* 25 since we read a 32 bit int, and need to adjust up to 7 bits from the byte-rounded fseek (32-7=25)
|
||||
*/
|
||||
static uint32_t read_bitsBE_b(off_t bit_offset, int num_bits, STREAMFILE *streamFile) {
|
||||
static uint32_t read_bitsBE_b(int64_t bit_offset, int num_bits, STREAMFILE *streamFile) {
|
||||
uint32_t num, mask;
|
||||
if (num_bits > 25) return -1; //???
|
||||
|
||||
|
@ -400,7 +400,7 @@ fail:
|
|||
/* XMA PARSING */
|
||||
/* ******************************************** */
|
||||
|
||||
static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, off_t offset_b, int bits_frame_size, size_t *first_frame_b, size_t *packet_skip_count, size_t *header_size_b) {
|
||||
static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, int64_t offset_b, int bits_frame_size, size_t *first_frame_b, size_t *packet_skip_count, size_t *header_size_b) {
|
||||
if (xma_version == 1) { /* XMA1 */
|
||||
//packet_sequence = read_bitsBE_b(offset_b+0, 4, streamFile); /* numbered from 0 to N */
|
||||
//unknown = read_bitsBE_b(offset_b+4, 2, streamFile); /* packet_metadata? (always 2) */
|
||||
|
@ -431,11 +431,11 @@ static void ms_audio_parse_header(STREAMFILE *streamFile, int xma_version, off_t
|
|||
/* full packet skip, no new frames start in this packet (prev frames can end here)
|
||||
* standardized to some value */
|
||||
if (*packet_skip_count == 0x7FF) { /* XMA1, 11b */
|
||||
VGM_LOG("MS_SAMPLES: XMA1 full packet_skip at 0x%x\n", (uint32_t)offset_b/8);
|
||||
VGM_LOG("MS_SAMPLES: XMA1 full packet_skip\n");// at %"PRIx64"\n", offset_b/8);
|
||||
*packet_skip_count = 0x800;
|
||||
}
|
||||
else if (*packet_skip_count == 0xFF) { /* XMA2, 8b*/
|
||||
VGM_LOG("MS_SAMPLES: XMA2 full packet_skip at 0x%x\n", (uint32_t)offset_b/8);
|
||||
VGM_LOG("MS_SAMPLES: XMA2 full packet_skip\n");// at %"PRIx64"\n", offset_b/8);
|
||||
*packet_skip_count = 0x800;
|
||||
}
|
||||
|
||||
|
@ -458,7 +458,7 @@ static void ms_audio_get_samples(ms_sample_data * msd, STREAMFILE *streamFile, i
|
|||
int frames = 0, samples = 0, loop_start_frame = 0, loop_end_frame = 0;
|
||||
|
||||
size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b;
|
||||
off_t offset_b, packet_offset_b, frame_offset_b;
|
||||
int64_t offset_b, packet_offset_b, frame_offset_b;
|
||||
|
||||
size_t packet_size = bytes_per_packet;
|
||||
size_t packet_size_b = packet_size * 8;
|
||||
|
@ -535,11 +535,11 @@ static void ms_audio_get_skips(STREAMFILE *streamFile, int xma_version, off_t da
|
|||
int start_skip = 0, end_skip = 0;
|
||||
|
||||
size_t first_frame_b, packet_skip_count, header_size_b, frame_size_b;
|
||||
off_t offset_b, packet_offset_b, frame_offset_b;
|
||||
int64_t offset_b, packet_offset_b, frame_offset_b;
|
||||
|
||||
size_t packet_size = bytes_per_packet;
|
||||
size_t packet_size_b = packet_size * 8;
|
||||
off_t offset = data_offset;
|
||||
int64_t offset = data_offset;
|
||||
|
||||
/* read packet */
|
||||
{
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <math.h>
|
||||
#include "coding.h"
|
||||
|
||||
/* Relic Codec decoder, a fairly simple mono-interleave DCT-based codec.
|
||||
|
@ -291,11 +292,16 @@ static uint32_t read_ubits(uint8_t bits, uint32_t offset, uint8_t *buf) {
|
|||
}
|
||||
static int read_sbits(uint8_t bits, uint32_t offset, uint8_t *buf) {
|
||||
uint32_t val = read_ubits(bits, offset, buf);
|
||||
int outval;
|
||||
if (val >> (bits - 1) == 1) { /* upper bit = sign */
|
||||
uint32_t mask = (1 << (bits - 1)) - 1;
|
||||
return -(val & mask);
|
||||
outval = (int)(val & mask);
|
||||
outval = -outval;
|
||||
}
|
||||
return val;
|
||||
else {
|
||||
outval = (int)val;
|
||||
}
|
||||
return outval;
|
||||
}
|
||||
|
||||
static void init_dequantization(float* scales) {
|
||||
|
@ -338,7 +344,7 @@ static void unpack_frame(uint8_t *buf, int buf_size, float *freq1, float *freq2,
|
|||
if (cb_bits > 0 && ev_bits > 0) {
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_CRITICAL_BAND_COUNT - 1; i++) {
|
||||
if (bit_offset >= 8*buf_size)
|
||||
if (bit_offset >= 8u*buf_size)
|
||||
break;
|
||||
|
||||
move = read_ubits(cb_bits, bit_offset, buf);
|
||||
|
@ -360,7 +366,7 @@ static void unpack_frame(uint8_t *buf, int buf_size, float *freq1, float *freq2,
|
|||
/* read first part */
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_MAX_FREQ; i++) {
|
||||
if (bit_offset >= 8*buf_size)
|
||||
if (bit_offset >= 8u*buf_size)
|
||||
break;
|
||||
|
||||
move = read_ubits(ei_bits, bit_offset, buf);
|
||||
|
@ -384,7 +390,7 @@ static void unpack_frame(uint8_t *buf, int buf_size, float *freq1, float *freq2,
|
|||
else {
|
||||
pos = 0;
|
||||
for (i = 0; i < RELIC_MAX_FREQ; i++) {
|
||||
if (bit_offset >= 8*buf_size)
|
||||
if (bit_offset >= 8u*buf_size)
|
||||
break;
|
||||
|
||||
move = read_ubits(ei_bits, bit_offset, buf);
|
||||
|
@ -436,7 +442,7 @@ static void copy_samples(relic_codec_data* data, sample_t* outbuf, int32_t sampl
|
|||
for (ch = 0; ch < ichs; ch++) {
|
||||
for (s = 0; s < samples; s++) {
|
||||
double d64_sample = data->wave_cur[ch][skip + s];
|
||||
int pcm_sample = clamp16(d64_sample);
|
||||
int pcm_sample = clamp16((int32_t)d64_sample);
|
||||
|
||||
/* f32 in PCM 32767.0 .. -32768.0 format, original code
|
||||
* does some custom double-to-int rint() though */
|
||||
|
@ -453,12 +459,12 @@ static relic_codec_data* init_codec(int channels, int bitrate, int codec_rate) {
|
|||
|
||||
if (channels > RELIC_MAX_CHANNELS)
|
||||
goto fail;
|
||||
|
||||
|
||||
data = calloc(1, sizeof(relic_codec_data));
|
||||
if (!data) goto fail;
|
||||
|
||||
|
||||
data->channels = channels;
|
||||
|
||||
|
||||
/* dequantized freq1+2 size (separate from DCT) */
|
||||
if (codec_rate < 22050) /* probably 11025 only */
|
||||
data->freq_size = RELIC_SIZE_LOW;
|
||||
|
@ -471,7 +477,7 @@ static relic_codec_data* init_codec(int channels, int bitrate, int codec_rate) {
|
|||
data->wave_size = RELIC_SIZE_HIGH;
|
||||
data->dct_mode = RELIC_SIZE_HIGH;
|
||||
data->samples_mode = RELIC_SIZE_HIGH;
|
||||
|
||||
|
||||
init_dct(data->dct, RELIC_SIZE_HIGH);
|
||||
init_window(data->window, RELIC_SIZE_HIGH);
|
||||
init_dequantization(data->scales);
|
||||
|
|
|
@ -145,6 +145,7 @@ static const char* extension_list[] = {
|
|||
"ddsp",
|
||||
"de2",
|
||||
"dec",
|
||||
"diva",
|
||||
"dmsg",
|
||||
"ds2", //txth/reserved [Star Wars Bounty Hunter (GC)]
|
||||
"dsf",
|
||||
|
@ -1285,6 +1286,7 @@ static const meta_info meta_info_list[] = {
|
|||
{meta_KWB, "Koei Tecmo WaveBank header"},
|
||||
{meta_LRMD, "Sony LRMD header"},
|
||||
{meta_WWISE_FX, "Audiokinetic Wwise FX header"},
|
||||
{meta_DIVA, "DIVA header"},
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -261,11 +261,11 @@ static int find_adx_key(STREAMFILE *sf, uint8_t type, uint16_t *xor_start, uint1
|
|||
|
||||
/* try to find key in external file first */
|
||||
{
|
||||
uint8_t keybuf[0x20+1] = {0}; /* +1 extra null for keystrings */
|
||||
uint8_t keybuf[0x40+1] = {0}; /* known max ~0x30, +1 extra null for keystrings */
|
||||
size_t key_size;
|
||||
|
||||
/* handle type8 keystrings, key9 keycodes and derived keys too */
|
||||
key_size = read_key_file(keybuf,0x20, sf);
|
||||
key_size = read_key_file(keybuf, sizeof(keybuf), sf);
|
||||
|
||||
if (key_size > 0) {
|
||||
int i, is_ascii = 0;
|
||||
|
|
|
@ -193,6 +193,9 @@ static const adxkey_info adxkey8_list[] = {
|
|||
/* Katekyoo Hitman Reborn! Let's Ansatsu! Nerawareta 10-daime! (PS2) */
|
||||
{0x5381,0x52E5,0x53E9, "REBHITMAN",0},
|
||||
|
||||
/* 428: Fuusasareta Shibuya de (PS3) */
|
||||
{0x52ff,0x649f,0x448f, "hj1kviaqqdzUacryoacwmscfvwtlfkVbbbqpqmzqnbile2euljywazejgyxxvqlf",0},
|
||||
|
||||
};
|
||||
|
||||
static const adxkey_info adxkey9_list[] = {
|
||||
|
@ -234,8 +237,8 @@ static const adxkey_info adxkey9_list[] = {
|
|||
/* Detective Conan Runner / Case Closed Runner (Android) */
|
||||
{0x0613,0x0e3d,0x6dff, NULL,1175268187653273344}, // 104f643098e3f700
|
||||
|
||||
/* Persona 5 Royal (PS4)*/
|
||||
{0x0000,0x1c85,0x1043, NULL,29902882}, // guessed with VGAudio
|
||||
/* Persona 5 Royal (PS4) */
|
||||
{0x0000,0x1c85,0x7043, NULL,29915170}, // 0000000001C87822
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset, didx_offset, data_offset, offset;
|
||||
size_t subfile_size, didx_size;
|
||||
uint32_t subfile_id;
|
||||
int big_endian;
|
||||
off_t subfile_offset, base_offset = 0;
|
||||
size_t subfile_size;
|
||||
uint32_t subfile_id, header_id;
|
||||
int big_endian, version, is_dummy = 0;
|
||||
uint32_t (*read_u32)(off_t,STREAMFILE*);
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
@ -17,47 +17,116 @@ VGMSTREAM* init_vgmstream_bkhd(STREAMFILE* sf) {
|
|||
/* checks */
|
||||
if (!check_extensions(sf,"bnk"))
|
||||
goto fail;
|
||||
if (read_u32be(0x00, sf) != 0x424B4844) /* "BKHD" */
|
||||
|
||||
if (read_u32be(0x00, sf) == 0x414B424B) /* "AKBK" [Shadowrun (X360)] */
|
||||
base_offset = 0x0c;
|
||||
if (read_u32be(base_offset + 0x00, sf) != 0x424B4844) /* "BKHD" */
|
||||
goto fail;
|
||||
big_endian = guess_endianness32bit(0x04, sf);
|
||||
big_endian = guess_endianness32bit(base_offset + 0x04, sf);
|
||||
read_u32 = big_endian ? read_u32be : read_u32le;
|
||||
|
||||
|
||||
/* Wwise banks have event/track/sequence/etc info in the HIRC chunk, as well
|
||||
* as other chunks, and may have a DIDX index to memory .wem in DATA.
|
||||
* as other chunks, and may have a DATA/DIDX index to memory .wem in DATA.
|
||||
* We support the internal .wem mainly for quick tests, as the HIRC is
|
||||
* complex and better handled with TXTP (some info from Nicknine's script) */
|
||||
* complex and better handled with TXTP (some info from Nicknine's script).
|
||||
* unlike RIFF, first chunk follows chunk rules */
|
||||
|
||||
/* unlike RIFF first chunk follows chunk rules */
|
||||
if (!find_chunk(sf, 0x44494458, 0x00,0, &didx_offset, &didx_size, big_endian, 0)) /* "DIDX" */
|
||||
goto fail;
|
||||
if (!find_chunk(sf, 0x44415441, 0x00,0, &data_offset, NULL, big_endian, 0)) /* "DATA" */
|
||||
goto fail;
|
||||
version = read_u32(base_offset + 0x08, sf);
|
||||
if (version == 0 || version == 1) { /* early games */
|
||||
version = read_u32(base_offset + 0x10, sf);
|
||||
}
|
||||
|
||||
total_subsongs = didx_size / 0x0c;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
if (version <= 26) {
|
||||
off_t data_offset, data_start, offset;
|
||||
if (!find_chunk(sf, 0x44415441, base_offset, 0, &data_offset, NULL, big_endian, 0)) /* "DATA" */
|
||||
goto fail;
|
||||
|
||||
offset = didx_offset + (target_subsong - 1) * 0x0c;
|
||||
subfile_id = read_u32(offset + 0x00, sf);
|
||||
subfile_offset = read_u32(offset + 0x04, sf) + data_offset;
|
||||
subfile_size = read_u32(offset + 0x08, sf);
|
||||
/* index:
|
||||
* 00: entries
|
||||
* 04: null
|
||||
* 08: entries size
|
||||
* 0c: padding size after entries
|
||||
* 10: data size
|
||||
* 14: size?
|
||||
* 18: data start
|
||||
* 1c: data size
|
||||
* per entry:
|
||||
* 00: always -1
|
||||
* 04: always 0
|
||||
* 08: index number or -1
|
||||
* 0c: 5 or -1?
|
||||
* 0c: 5 or -1?
|
||||
* 0c: 5 or -1?
|
||||
* 10: stream offset (from data start) or -1 if none
|
||||
* 14: stream size or 0 if none
|
||||
*/
|
||||
|
||||
//;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size);
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "wem");
|
||||
if (!temp_sf) goto fail;
|
||||
total_subsongs = read_u32(data_offset + 0x00, sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
subfile_id = read_u32(0x00, temp_sf);
|
||||
if (subfile_id == 0x52494646 || subfile_id == 0x52494658) { /* "RIFF" / "RIFX" */
|
||||
vgmstream = init_vgmstream_wwise(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
data_start = read_u32(data_offset + 0x18, sf);
|
||||
offset = data_offset + 0x20 + (target_subsong - 1) * 0x18;
|
||||
|
||||
subfile_id = read_u32(offset + 0x08, sf);
|
||||
subfile_offset = read_u32(offset + 0x10, sf) + data_offset + 0x20 + data_start;
|
||||
subfile_size = read_u32(offset + 0x14, sf);
|
||||
}
|
||||
else {
|
||||
vgmstream = init_vgmstream_bkhd_fx(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
off_t didx_offset, data_offset, offset;
|
||||
size_t didx_size;
|
||||
if (!find_chunk(sf, 0x44494458, 0x00,0, &didx_offset, &didx_size, big_endian, 0)) /* "DIDX" */
|
||||
goto fail;
|
||||
if (!find_chunk(sf, 0x44415441, 0x00,0, &data_offset, NULL, big_endian, 0)) /* "DATA" */
|
||||
goto fail;
|
||||
|
||||
total_subsongs = didx_size / 0x0c;
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
|
||||
offset = didx_offset + (target_subsong - 1) * 0x0c;
|
||||
subfile_id = read_u32(offset + 0x00, sf);
|
||||
subfile_offset = read_u32(offset + 0x04, sf) + data_offset;
|
||||
subfile_size = read_u32(offset + 0x08, sf);
|
||||
}
|
||||
|
||||
/* some indexes don't have that, but for now leave a dummy song for easier HIRC mapping */
|
||||
if (subfile_offset <= 0 || subfile_size <= 0) {
|
||||
//;VGM_LOG("BKHD: dummy entry");
|
||||
temp_sf = setup_subfile_streamfile(sf, 0x00, 0x10, "raw");
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
//todo make some better silent entry
|
||||
vgmstream = init_vgmstream_raw_pcm(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
is_dummy = 1;
|
||||
}
|
||||
else {
|
||||
//;VGM_LOG("BKHD: %lx, %x\n", subfile_offset, subfile_size);
|
||||
/* could pass .wem but few files need memory .wem detection */
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, NULL);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
header_id = read_u32be(0x00, temp_sf);
|
||||
if (header_id == 0x52494646 || header_id == 0x52494658) { /* "RIFF" / "RIFX" */
|
||||
vgmstream = init_vgmstream_wwise(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
else {
|
||||
vgmstream = init_vgmstream_bkhd_fx(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u", subfile_id);
|
||||
|
||||
if (is_dummy)
|
||||
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%s", "dummy");
|
||||
else if (subfile_id != 0xFFFFFFFF)
|
||||
snprintf(vgmstream->stream_name, STREAM_NAME_SIZE, "%u", subfile_id);
|
||||
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
@ -69,7 +138,7 @@ fail:
|
|||
}
|
||||
|
||||
|
||||
/* BKHD mini format, probably from a generator plugin [Borderlands 2 (X360)] */
|
||||
/* BKHD mini format, probably from a FX generator plugin [Borderlands 2 (X360)] */
|
||||
VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
off_t start_offset, data_size;
|
||||
|
@ -93,8 +162,7 @@ VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf) {
|
|||
/* 0x14/18: some float? */
|
||||
entries = read_u32(0x1c, sf);
|
||||
/* 0x20 data size / 0x10 */
|
||||
if (read_u8(0x24, sf) != 4) /* bps */
|
||||
goto fail;
|
||||
/* 0x24 usually 4, sometimes higher values? */
|
||||
/* 0x30: unknown table of 16b that goes up and down */
|
||||
|
||||
start_offset = 0x30 + align_size_to_block(entries * 0x02, 0x10);
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
/* DIVA - Hatsune Miku: Project DIVA Arcade */
|
||||
VGMSTREAM * init_vgmstream_diva(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
off_t start_offset;
|
||||
int channel_count;
|
||||
int loop_end;
|
||||
int loop_flag;
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "diva"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) != 0x44495641) /* "DIVA" */
|
||||
goto fail;
|
||||
|
||||
start_offset = 0x40;
|
||||
channel_count = read_8bit(0x1C, streamFile);
|
||||
loop_end = read_32bitLE(0x18, streamFile);
|
||||
|
||||
loop_flag = (loop_end != 0);
|
||||
|
||||
/* build the VGMSTREAM */
|
||||
vgmstream = allocate_vgmstream(channel_count, loop_flag);
|
||||
if (!vgmstream) goto fail;
|
||||
|
||||
vgmstream->sample_rate = read_32bitLE(0x0C, streamFile);
|
||||
vgmstream->num_samples = read_32bitLE(0x10, streamFile);
|
||||
vgmstream->loop_start_sample = read_32bitLE(0x14, streamFile);
|
||||
vgmstream->loop_end_sample = loop_end;
|
||||
vgmstream->meta_type = meta_DIVA;
|
||||
vgmstream->layout_type = layout_none;
|
||||
vgmstream->coding_type = coding_DVI_IMA;
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream, streamFile, start_offset))
|
||||
goto fail;
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -454,6 +454,12 @@ static int parse_genh(STREAMFILE * streamFile, genh_header * genh) {
|
|||
genh->num_samples = genh->num_samples > 0 ? genh->num_samples : genh->loop_end_sample;
|
||||
genh->loop_flag = genh->loop_start_sample != -1;
|
||||
|
||||
/* fix for buggy GENHs that used to work before interleaved XBOX-IMA was added
|
||||
* (could do check for other cases, but maybe it's better to give bad sound on nonsense values) */
|
||||
if (genh->codec == XBOX && genh->interleave < 0x24) { /* found as 0x2 */
|
||||
genh->interleave = 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
#ifdef HCA_BRUTEFORCE
|
||||
static void bruteforce_hca_key(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* out_keycode, uint16_t subkey);
|
||||
#endif
|
||||
static void find_hca_key(hca_codec_data * hca_data, unsigned long long * out_keycode, uint16_t subkey);
|
||||
static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey);
|
||||
|
||||
|
||||
/* CRI HCA - streamed audio from CRI ADX2/Atom middleware */
|
||||
|
@ -17,7 +17,6 @@ VGMSTREAM * init_vgmstream_hca(STREAMFILE *streamFile) {
|
|||
VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
hca_codec_data * hca_data = NULL;
|
||||
unsigned long long keycode = 0;
|
||||
|
||||
|
||||
/* checks */
|
||||
|
@ -32,6 +31,7 @@ VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) {
|
|||
|
||||
/* find decryption key in external file or preloaded list */
|
||||
if (hca_data->info.encryptionEnabled) {
|
||||
uint64_t keycode = 0;
|
||||
uint8_t keybuf[0x08+0x02];
|
||||
size_t keysize;
|
||||
|
||||
|
@ -56,7 +56,7 @@ VGMSTREAM * init_vgmstream_hca_subkey(STREAMFILE *streamFile, uint16_t subkey) {
|
|||
find_hca_key(hca_data, &keycode, subkey);
|
||||
}
|
||||
|
||||
clHCA_SetKey(hca_data->handle, keycode); //maybe should be done through hca_decoder.c?
|
||||
clHCA_SetKey(hca_data->handle, (unsigned long long)keycode); //maybe should be done through hca_decoder.c?
|
||||
}
|
||||
|
||||
|
||||
|
@ -139,25 +139,25 @@ static inline void test_key(hca_codec_data * hca_data, uint64_t key, uint16_t su
|
|||
}
|
||||
|
||||
/* try to find the decryption key from a list. */
|
||||
static void find_hca_key(hca_codec_data* hca_data, unsigned long long* out_keycode, uint16_t subkey) {
|
||||
static void find_hca_key(hca_codec_data* hca_data, uint64_t* p_keycode, uint16_t subkey) {
|
||||
const size_t keys_length = sizeof(hcakey_list) / sizeof(hcakey_info);
|
||||
int best_score = -1;
|
||||
int i,j;
|
||||
|
||||
*out_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */
|
||||
*p_keycode = 0xCC55463930DBE1AB; /* defaults to PSO2 key, most common */
|
||||
|
||||
for (i = 0; i < keys_length; i++) {
|
||||
uint64_t key = hcakey_list[i].key;
|
||||
size_t subkeys_size = hcakey_list[i].subkeys_size;
|
||||
const uint16_t *subkeys = hcakey_list[i].subkeys;
|
||||
|
||||
test_key(hca_data, key, subkey, &best_score, out_keycode);
|
||||
test_key(hca_data, key, subkey, &best_score, p_keycode);
|
||||
if (best_score == 1)
|
||||
goto done;
|
||||
|
||||
if (subkeys_size > 0 && subkey == 0) {
|
||||
for (j = 0; j < subkeys_size; j++) {
|
||||
test_key(hca_data, key, subkeys[j], &best_score, out_keycode);
|
||||
test_key(hca_data, key, subkeys[j], &best_score, p_keycode);
|
||||
if (best_score == 1)
|
||||
goto done;
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ static void find_hca_key(hca_codec_data* hca_data, unsigned long long* out_keyco
|
|||
|
||||
done:
|
||||
VGM_ASSERT(best_score > 1, "HCA: best key=%08x%08x (score=%i)\n",
|
||||
(uint32_t)((*out_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*out_keycode & 0xFFFFFFFF), best_score);
|
||||
(uint32_t)((*p_keycode >> 32) & 0xFFFFFFFF), (uint32_t)(*p_keycode & 0xFFFFFFFF), best_score);
|
||||
VGM_ASSERT(best_score < 0, "HCA: key not found\n");
|
||||
}
|
||||
|
||||
|
|
|
@ -893,4 +893,6 @@ VGMSTREAM* init_vgmstream_bkhd_fx(STREAMFILE* sf);
|
|||
|
||||
VGMSTREAM* init_vgmstream_encrypted(STREAMFILE* sf);
|
||||
|
||||
VGMSTREAM* init_vgmstream_diva(STREAMFILE* sf);
|
||||
|
||||
#endif /*_META_H*/
|
||||
|
|
|
@ -1,56 +1,56 @@
|
|||
#include "meta.h"
|
||||
#include "../coding/coding.h"
|
||||
|
||||
typedef enum { IDSP, OPUS, } nus3audio_codec;
|
||||
typedef enum { IDSP, OPUS, RIFF, } nus3audio_codec;
|
||||
|
||||
/* .nus3audio - Namco's newest newest audio container [Super Smash Bros. Ultimate (Switch)] */
|
||||
VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) {
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
STREAMFILE *temp_streamFile = NULL;
|
||||
VGMSTREAM* init_vgmstream_nus3audio(STREAMFILE* sf) {
|
||||
VGMSTREAM* vgmstream = NULL;
|
||||
STREAMFILE* temp_sf = NULL;
|
||||
off_t subfile_offset = 0, name_offset = 0;
|
||||
size_t subfile_size = 0;
|
||||
nus3audio_codec codec;
|
||||
const char* fake_ext = NULL;
|
||||
int total_subsongs, target_subsong = streamFile->stream_index;
|
||||
int total_subsongs, target_subsong = sf->stream_index;
|
||||
|
||||
|
||||
/* checks */
|
||||
if (!check_extensions(streamFile, "nus3audio"))
|
||||
if (!check_extensions(sf, "nus3audio"))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x00,streamFile) != 0x4E555333) /* "NUS3" */
|
||||
if (read_u32be(0x00,sf) != 0x4E555333) /* "NUS3" */
|
||||
goto fail;
|
||||
if (read_32bitLE(0x04,streamFile) + 0x08 != get_streamfile_size(streamFile))
|
||||
if (read_u32le(0x04,sf) + 0x08 != get_streamfile_size(sf))
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,streamFile) != 0x41554449) /* "AUDI" */
|
||||
if (read_u32be(0x08,sf) != 0x41554449) /* "AUDI" */
|
||||
goto fail;
|
||||
|
||||
|
||||
/* parse existing chunks */
|
||||
{
|
||||
off_t offset = 0x0c;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
size_t file_size = get_streamfile_size(sf);
|
||||
uint32_t codec_id = 0;
|
||||
|
||||
total_subsongs = 0;
|
||||
|
||||
while (offset < file_size) {
|
||||
uint32_t chunk_id = (uint32_t)read_32bitBE(offset+0x00, streamFile);
|
||||
size_t chunk_size = (size_t)read_32bitLE(offset+0x04, streamFile);
|
||||
uint32_t chunk_id = read_u32be(offset+0x00, sf);
|
||||
size_t chunk_size = read_u32le(offset+0x04, sf);
|
||||
|
||||
switch(chunk_id) {
|
||||
case 0x494E4458: /* "INDX": audio index */
|
||||
total_subsongs = read_32bitLE(offset+0x08 + 0x00,streamFile);
|
||||
total_subsongs = read_u32le(offset+0x08 + 0x00,sf);
|
||||
if (target_subsong == 0) target_subsong = 1;
|
||||
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
|
||||
break;
|
||||
|
||||
case 0x4E4D4F46: /* "NMOF": name offsets (absolute, inside TNNM) */
|
||||
name_offset = read_32bitLE(offset+0x08 + 0x04*(target_subsong-1),streamFile);
|
||||
name_offset = read_u32le(offset+0x08 + 0x04*(target_subsong-1),sf);
|
||||
break;
|
||||
|
||||
case 0x41444F46: /* "ADOF": audio offsets (absolute, inside PACK) */
|
||||
subfile_offset = read_32bitLE(offset+0x08 + 0x08*(target_subsong-1) + 0x00,streamFile);
|
||||
subfile_size = read_32bitLE(offset+0x08 + 0x08*(target_subsong-1) + 0x04,streamFile);
|
||||
subfile_offset = read_u32le(offset+0x08 + 0x08*(target_subsong-1) + 0x00,sf);
|
||||
subfile_size = read_u32le(offset+0x08 + 0x08*(target_subsong-1) + 0x04,sf);
|
||||
break;
|
||||
|
||||
case 0x544E4944: /* "TNID": tone ids? */
|
||||
|
@ -69,7 +69,7 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
codec_id = read_32bitBE(subfile_offset, streamFile);
|
||||
codec_id = read_u32be(subfile_offset, sf);
|
||||
switch(codec_id) {
|
||||
case 0x49445350: /* "IDSP" */
|
||||
codec = IDSP;
|
||||
|
@ -79,6 +79,10 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) {
|
|||
codec = OPUS;
|
||||
fake_ext = "opus";
|
||||
break;
|
||||
case 0x52494646: /* "RIFF" [Gundam Versus (PS4)] */
|
||||
codec = RIFF;
|
||||
fake_ext = "wav";
|
||||
break;
|
||||
default:
|
||||
VGM_LOG("NUS3AUDIO: unknown codec %x\n", codec_id);
|
||||
goto fail;
|
||||
|
@ -86,17 +90,21 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
|
||||
temp_streamFile = setup_subfile_streamfile(streamFile, subfile_offset,subfile_size, fake_ext);
|
||||
if (!temp_streamFile) goto fail;
|
||||
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, fake_ext);
|
||||
if (!temp_sf) goto fail;
|
||||
|
||||
/* init the VGMSTREAM */
|
||||
switch(codec) {
|
||||
case IDSP:
|
||||
vgmstream = init_vgmstream_idsp_namco(temp_streamFile);
|
||||
vgmstream = init_vgmstream_idsp_namco(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
case OPUS:
|
||||
vgmstream = init_vgmstream_opus_nus3(temp_streamFile);
|
||||
vgmstream = init_vgmstream_opus_nus3(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
case RIFF:
|
||||
vgmstream = init_vgmstream_riff(temp_sf);
|
||||
if (!vgmstream) goto fail;
|
||||
break;
|
||||
default:
|
||||
|
@ -105,13 +113,13 @@ VGMSTREAM * init_vgmstream_nus3audio(STREAMFILE *streamFile) {
|
|||
|
||||
vgmstream->num_streams = total_subsongs;
|
||||
if (name_offset) /* null-terminated */
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,streamFile);
|
||||
read_string(vgmstream->stream_name,STREAM_NAME_SIZE, name_offset,sf);
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
close_streamfile(temp_sf);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(temp_streamFile);
|
||||
close_streamfile(temp_sf);
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ VGMSTREAM * init_vgmstream_rsd(STREAMFILE *streamFile) {
|
|||
|
||||
loop_flag = 0;
|
||||
|
||||
codec = read_32bitBE(0x04,streamFile);
|
||||
codec = (uint32_t)read_32bitBE(0x04,streamFile);
|
||||
channel_count = read_32bitLE(0x08, streamFile);
|
||||
/* 0x0c: always 16? */
|
||||
sample_rate = read_32bitLE(0x10, streamFile);
|
||||
|
|
|
@ -38,29 +38,34 @@ typedef struct {
|
|||
int32_t loop_end_sample;
|
||||
} wwise_header;
|
||||
|
||||
static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset);
|
||||
|
||||
|
||||
/* Wwise - Audiokinetic Wwise (Wave Works Interactive Sound Engine) middleware */
|
||||
VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
||||
VGMSTREAM * init_vgmstream_wwise(STREAMFILE* sf) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
wwise_header ww = {0};
|
||||
off_t start_offset, first_offset = 0xc;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
|
||||
/* basic checks */
|
||||
/* .wem (Wwise Encoded Media) is "newer Wwise", used after the 2011.2 SDK (~july)
|
||||
* .wav (ex. Shadowrun X360) and .ogg (ex. KOF XII X360), .xma (ex. Tron Evolution X360) are used in older Wwise */
|
||||
if (!check_extensions(streamFile,"wem,wav,lwav,ogg,logg,xma")) goto fail;
|
||||
|
||||
if ((read_32bitBE(0x00,streamFile) != 0x52494646) && /* "RIFF" (LE) */
|
||||
(read_32bitBE(0x00,streamFile) != 0x52494658)) /* "RIFX" (BE) */
|
||||
goto fail;
|
||||
if ((read_32bitBE(0x08,streamFile) != 0x57415645) && /* "WAVE" */
|
||||
(read_32bitBE(0x08,streamFile) != 0x58574D41)) /* "XWMA" */
|
||||
/* checks */
|
||||
/* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011)
|
||||
* .wav: older ADPCM files [Punch Out!! (Wii)]
|
||||
* .xma: older XMA files [Too Human (X360), Tron Evolution (X360)]
|
||||
* .ogg: older Vorbis files [The King of Fighters XII (X360)]
|
||||
* .bnk: Wwise banks for memory .wem detection */
|
||||
if (!check_extensions(sf,"wem,wav,lwav,ogg,logg,xma,bnk"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00,sf) != 0x52494646 && /* "RIFF" (LE) */
|
||||
read_32bitBE(0x00,sf) != 0x52494658) /* "RIFX" (BE) */
|
||||
goto fail;
|
||||
if (read_32bitBE(0x08,sf) != 0x57415645 && /* "WAVE" */
|
||||
read_32bitBE(0x08,sf) != 0x58574D41) /* "XWMA" */
|
||||
goto fail;
|
||||
|
||||
ww.big_endian = read_32bitBE(0x00,streamFile) == 0x52494658;/* RIFX */
|
||||
ww.big_endian = read_32bitBE(0x00,sf) == 0x52494658; /* RIFX */
|
||||
if (ww.big_endian) { /* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
|
@ -69,7 +74,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
ww.file_size = streamFile->get_size(streamFile);
|
||||
ww.file_size = sf->get_size(sf);
|
||||
|
||||
#if 0
|
||||
/* Wwise's RIFF size is often wonky, seemingly depending on codec:
|
||||
|
@ -80,8 +85,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
* - some RIFX have LE size
|
||||
* (later we'll validate "data" which fortunately is correct)
|
||||
*/
|
||||
if (read_32bit(0x04,streamFile)+0x04+0x04 != ww.file_size) {
|
||||
VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", read_32bit(0x04,streamFile)+0x04+0x04, ww.file_size);
|
||||
if (read_32bit(0x04,sf)+0x04+0x04 != ww.file_size) {
|
||||
VGM_LOG("WWISE: bad riff size (real=0x%x vs riff=0x%x)\n", read_32bit(0x04,sf)+0x04+0x04, ww.file_size);
|
||||
goto fail;
|
||||
}
|
||||
#endif
|
||||
|
@ -91,44 +96,50 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
off_t fact_offset;
|
||||
size_t fact_size;
|
||||
|
||||
if (find_chunk(streamFile, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
|
||||
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, streamFile) == 0x4C794E20) /* "LyN " */
|
||||
if (find_chunk(sf, 0x66616374,first_offset,0, &fact_offset,&fact_size, 0, 0)) { /* "fact" */
|
||||
if (fact_size == 0x10 && read_32bitBE(fact_offset+0x04, sf) == 0x4C794E20) /* "LyN " */
|
||||
goto fail; /* parsed elsewhere */
|
||||
/* Wwise doesn't use "fact", though */
|
||||
}
|
||||
/* Wwise doesn't use "fact", though */
|
||||
}
|
||||
|
||||
|
||||
/* parse format (roughly spec-compliant but some massaging is needed) */
|
||||
{
|
||||
off_t loop_offset;
|
||||
size_t loop_size;
|
||||
|
||||
/* find basic chunks */
|
||||
if (!find_chunk(streamFile, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) goto fail; /*"fmt "*/
|
||||
if (!find_chunk(streamFile, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) goto fail; /*"data"*/
|
||||
|
||||
/* base fmt */
|
||||
if (ww.fmt_size < 0x12) goto fail;
|
||||
ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,streamFile);
|
||||
|
||||
if (ww.format == 0x0165) { /* pseudo-XMA2WAVEFORMAT (always "fmt"+"XMA2", unlike .xma that may only have "XMA2") */
|
||||
if (!find_chunk(streamFile, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0))
|
||||
goto fail;
|
||||
xma2_parse_xma2_chunk(streamFile, ww.chunk_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample);
|
||||
if (read_32bitBE(0x0c, sf) == 0x584D4132) { /* "XMA2" with no "fmt" [Too Human (X360)] */
|
||||
ww.format = 0x0165; /* signal for below */
|
||||
}
|
||||
else { /* pseudo-WAVEFORMATEX */
|
||||
ww.channels = read_16bit(ww.fmt_offset+0x02,streamFile);
|
||||
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,streamFile);
|
||||
ww.average_bps = read_32bit(ww.fmt_offset+0x08,streamFile);/* bytes per sec */
|
||||
ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,streamFile);
|
||||
ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,streamFile);
|
||||
else {
|
||||
if (!find_chunk(sf, 0x666d7420,first_offset,0, &ww.fmt_offset,&ww.fmt_size, ww.big_endian, 0)) /* "fmt " */
|
||||
goto fail;
|
||||
if (ww.fmt_size < 0x12)
|
||||
goto fail;
|
||||
ww.format = (uint16_t)read_16bit(ww.fmt_offset+0x00,sf);
|
||||
}
|
||||
|
||||
|
||||
if (ww.format == 0x0165) {
|
||||
/* pseudo-XMA2WAVEFORMAT ("fmt"+"XMA2" or just "XMA2) */
|
||||
if (!find_chunk(sf, 0x584D4132,first_offset,0, &ww.chunk_offset,NULL, ww.big_endian, 0)) /* "XMA2" */
|
||||
goto fail;
|
||||
xma2_parse_xma2_chunk(sf, ww.chunk_offset,&ww.channels,&ww.sample_rate, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample);
|
||||
}
|
||||
else {
|
||||
/* pseudo-WAVEFORMATEX */
|
||||
ww.channels = read_16bit(ww.fmt_offset+0x02,sf);
|
||||
ww.sample_rate = read_32bit(ww.fmt_offset+0x04,sf);
|
||||
ww.average_bps = read_32bit(ww.fmt_offset+0x08,sf);/* bytes per sec */
|
||||
ww.block_align = (uint16_t)read_16bit(ww.fmt_offset+0x0c,sf);
|
||||
ww.bits_per_sample = (uint16_t)read_16bit(ww.fmt_offset+0x0e,sf);
|
||||
if (ww.fmt_size > 0x10 && ww.format != 0x0165 && ww.format != 0x0166) /* ignore XMAWAVEFORMAT */
|
||||
ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,streamFile);
|
||||
ww.extra_size = (uint16_t)read_16bit(ww.fmt_offset+0x10,sf);
|
||||
if (ww.extra_size >= 0x06) { /* always present (actual RIFFs only have it in WAVEFORMATEXTENSIBLE) */
|
||||
/* mostly WAVEFORMATEXTENSIBLE's bitmask (see AkSpeakerConfig.h) */
|
||||
ww.channel_layout = read_32bit(ww.fmt_offset+0x14,streamFile);
|
||||
/* latest games have a pseudo-format instead to handle more cases:
|
||||
ww.channel_layout = read_32bit(ww.fmt_offset+0x14,sf);
|
||||
/* later games (+2018?) have a pseudo-format instead to handle more cases:
|
||||
* - 8b: uNumChannels
|
||||
* - 4b: eConfigType (0=none, 1=standard, 2=ambisonic)
|
||||
* - 19b: uChannelMask */
|
||||
|
@ -138,40 +149,42 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
}
|
||||
}
|
||||
|
||||
/* find loop info */
|
||||
if (ww.format == 0x0166) { /* XMA2WAVEFORMATEX */
|
||||
/* find loop info ("XMA2" chunks already read them) */
|
||||
if (ww.format == 0x0166) { /* XMA2WAVEFORMATEX in fmt */
|
||||
ww.chunk_offset = ww.fmt_offset;
|
||||
xma2_parse_fmt_chunk_extra(streamFile, ww.chunk_offset, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample, ww.big_endian);
|
||||
xma2_parse_fmt_chunk_extra(sf, ww.chunk_offset, &ww.loop_flag, &ww.num_samples, &ww.loop_start_sample, &ww.loop_end_sample, ww.big_endian);
|
||||
}
|
||||
else if (find_chunk(streamFile, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"smpl", common */
|
||||
else if (find_chunk(sf, 0x736D706C,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /* "smpl", common */
|
||||
if (loop_size >= 0x34
|
||||
&& read_32bit(loop_offset+0x1c, streamFile)==1 /*loop count*/
|
||||
&& read_32bit(loop_offset+0x24+4, streamFile)==0) {
|
||||
&& read_32bit(loop_offset+0x1c, sf)==1 /* loop count */
|
||||
&& read_32bit(loop_offset+0x24+4, sf)==0) {
|
||||
ww.loop_flag = 1;
|
||||
ww.loop_start_sample = read_32bit(loop_offset+0x24+0x8, streamFile);
|
||||
ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc,streamFile);
|
||||
//todo fix repeat looping
|
||||
ww.loop_start_sample = read_32bit(loop_offset+0x24+0x8, sf);
|
||||
ww.loop_end_sample = read_32bit(loop_offset+0x24+0xc, sf) + 1; /* like standard RIFF */
|
||||
}
|
||||
}
|
||||
//else if (find_chunk(streamFile, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
|
||||
//else if (find_chunk(sf, 0x4C495354,first_offset,0, &loop_offset,&loop_size, ww.big_endian, 0)) { /*"LIST", common */
|
||||
// /* usually contains "cue"s with sample positions for events (ex. Platinum Games) but no real looping info */
|
||||
//}
|
||||
|
||||
/* other Wwise specific: */
|
||||
//"JUNK": optional padding for aligment (0-size JUNK exists too)
|
||||
//"akd ": seem to store extra info for Wwise editor (wave peaks/loudness/HDR envelope?)
|
||||
/* other Wwise specific chunks:
|
||||
* "JUNK": optional padding for aligment (0-size JUNK exists too)
|
||||
* "akd ": seem to store extra info for Wwise editor (wave peaks/loudness/HDR envelope?)
|
||||
*/
|
||||
|
||||
if (!find_chunk(sf, 0x64617461,first_offset,0, &ww.data_offset,&ww.data_size, ww.big_endian, 0)) /* "data" */
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* format to codec */
|
||||
switch(ww.format) {
|
||||
case 0x0001: ww.codec = PCM; break; /* older Wwise */
|
||||
case 0x0002: ww.codec = IMA; break; /* newer Wwise (conflicts with MSADPCM, probably means "platform's ADPCM") */
|
||||
//case 0x0011: ww.codec = IMA; break; /* older Wwise (used?) */
|
||||
case 0x0069: ww.codec = IMA; break; /* older Wwise (Spiderman Web of Shadows X360, LotR Conquest PC) */
|
||||
case 0x0069: ww.codec = IMA; break; /* older Wwise [Spiderman Web of Shadows (X360), LotR Conquest (PC)] */
|
||||
case 0x0161: ww.codec = XWMA; break; /* WMAv2 */
|
||||
case 0x0162: ww.codec = XWMA; break; /* WMAPro */
|
||||
case 0x0165: ww.codec = XMA2; break; /* always with the "XMA2" chunk, Wwise doesn't use XMA1 */
|
||||
case 0x0166: ww.codec = XMA2; break;
|
||||
case 0x0165: ww.codec = XMA2; break; /* XMA2-chunk XMA (Wwise doesn't use XMA1) */
|
||||
case 0x0166: ww.codec = XMA2; break; /* fmt-chunk XMA */
|
||||
case 0xAAC0: ww.codec = AAC; break;
|
||||
case 0xFFF0: ww.codec = DSP; break;
|
||||
case 0xFFFB: ww.codec = HEVAG; break;
|
||||
|
@ -180,9 +193,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
case 0xFFFF: ww.codec = VORBIS; break;
|
||||
case 0x3039: ww.codec = OPUSNX; break; /* later renamed from "OPUS" */
|
||||
case 0x3040: ww.codec = OPUS; break;
|
||||
#if 0
|
||||
case 0x8311: ww.codec = PTADPCM; break;
|
||||
#endif
|
||||
case 0x8311: ww.codec = PTADPCM; break; /* newer, rare [Genshin Impact (PC)] */
|
||||
default:
|
||||
goto fail;
|
||||
}
|
||||
|
@ -192,7 +203,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
if (ww.extra_size == 0x0c + ww.channels * 0x2e) {
|
||||
/* newer Wwise DSP with coefs [Epic Mickey 2 (Wii), Batman Arkham Origins Blackgate (3DS)] */
|
||||
ww.codec = DSP;
|
||||
} else if (ww.extra_size == 0x0a && find_chunk(streamFile, 0x57696948, first_offset,0, NULL,NULL, ww.big_endian, 0)) { /* WiiH */
|
||||
} else if (ww.extra_size == 0x0a && find_chunk(sf, 0x57696948, first_offset,0, NULL,NULL, ww.big_endian, 0)) { /* WiiH */
|
||||
/* few older Wwise DSP with num_samples in extra_size [Tony Hawk: Shred (Wii)] */
|
||||
ww.codec = DSP;
|
||||
} else if (ww.block_align == 0x104 * ww.channels) {
|
||||
|
@ -201,19 +212,20 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
|
||||
/* Some Wwise files (ex. Oddworld PSV, Bayonetta 2 WiiU, often in BGM.bnk) are truncated mirrors of another file.
|
||||
* They come in RAM banks, prefetch to play the beginning while the rest of the real stream loads.
|
||||
* We'll add basic support to avoid complaints of this or that .wem not playing */
|
||||
/* Some Wwise .bnk (RAM) files have truncated, prefetch mirrors of another file, that
|
||||
* play while the rest of the real stream loads. We'll add basic support to avoid
|
||||
* complaints of this or that .wem not playing */
|
||||
if (ww.data_offset + ww.data_size > ww.file_size) {
|
||||
//VGM_LOG("WWISE: truncated data size (prefetch): (real=0x%x > riff=0x%x)\n", ww.data_size, ww.file_size);
|
||||
|
||||
/* catch wrong rips as truncated tracks' file_size should be much smaller than data_size */
|
||||
if (ww.data_offset + ww.data_size - ww.file_size < 0x5000) {
|
||||
/* catch wrong rips as truncated tracks' file_size should be much smaller than data_size,
|
||||
* but it's possible to pre-fetch small files too [Punch Out!! (Wii)] */
|
||||
if (ww.data_offset + ww.data_size - ww.file_size < 0x5000 && ww.file_size > 0x10000) {
|
||||
VGM_LOG("WWISE: wrong expected data_size\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ww.codec == PCM || ww.codec == IMA || ww.codec == VORBIS || ww.codec == XMA2 || ww.codec == OPUSNX || ww.codec == OPUS) {
|
||||
if (ww.codec == PCM || ww.codec == IMA || ww.codec == DSP || ww.codec == VORBIS || ww.codec == XMA2 || ww.codec == OPUSNX || ww.codec == OPUS) {
|
||||
ww.truncated = 1; /* only seen those, probably all exist */
|
||||
} else {
|
||||
VGM_LOG("WWISE: wrong size, maybe truncated\n");
|
||||
|
@ -264,7 +276,6 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
vgmstream->interleave_block_size = ww.block_align / ww.channels;
|
||||
vgmstream->codec_endian = ww.big_endian;
|
||||
|
||||
/* enough to get real samples */
|
||||
if (ww.truncated) {
|
||||
ww.data_size = ww.file_size - ww.data_offset;
|
||||
}
|
||||
|
@ -286,12 +297,12 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail; /* always 0 for Worbis */
|
||||
|
||||
/* autodetect format (fields are mostly common, see the end of the file) */
|
||||
if (find_chunk(streamFile, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /*"vorb"*/
|
||||
if (find_chunk(sf, 0x766F7262,first_offset,0, &vorb_offset,&vorb_size, ww.big_endian, 0)) { /* "vorb" */
|
||||
/* older Wwise (~<2012) */
|
||||
|
||||
switch(vorb_size) {
|
||||
case 0x2C: /* earliest (~2009), [UFC Undisputed 2009 (PS3), some EVE Online Apocrypha (PC)?] */
|
||||
case 0x28: /* early (~2009) [The Lord of the Rings: Conquest (PC)] */
|
||||
case 0x2C: /* earliest (~2009) [The Lord of the Rings: Conquest (PC)] */
|
||||
case 0x28: /* early (~2009) [UFC Undisputed 2009 (PS3), some EVE Online Apocrypha (PC)] */
|
||||
data_offsets = 0x18;
|
||||
block_offsets = 0; /* no need, full headers are present */
|
||||
cfg.header_type = WWV_TYPE_8;
|
||||
|
@ -299,8 +310,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
cfg.setup_type = WWV_HEADER_TRIAD;
|
||||
break;
|
||||
|
||||
case 0x34: /* common (2010~2011) */
|
||||
case 0x32: /* very rare (mid 2011) [Saints Row the 3rd (PC)] */
|
||||
case 0x34: /* common (2010~2011) [The King of Fighters XII (PS3), Assassin's Creed II (X360)] */
|
||||
case 0x32: /* rare (mid 2011) [Saints Row the 3rd (PC)] */
|
||||
data_offsets = 0x18;
|
||||
block_offsets = 0x30;
|
||||
cfg.header_type = WWV_TYPE_6;
|
||||
|
@ -321,12 +332,12 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->num_samples = read_32bit(vorb_offset + 0x00, streamFile);
|
||||
setup_offset = read_32bit(vorb_offset + data_offsets + 0x00, streamFile); /* within data (0 = no seek table) */
|
||||
audio_offset = read_32bit(vorb_offset + data_offsets + 0x04, streamFile); /* within data */
|
||||
vgmstream->num_samples = read_32bit(vorb_offset + 0x00, sf);
|
||||
setup_offset = read_32bit(vorb_offset + data_offsets + 0x00, sf); /* within data (0 = no seek table) */
|
||||
audio_offset = read_32bit(vorb_offset + data_offsets + 0x04, sf); /* within data */
|
||||
if (block_offsets) {
|
||||
cfg.blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, streamFile); /* small */
|
||||
cfg.blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, streamFile); /* big */
|
||||
cfg.blocksize_1_exp = read_8bit(vorb_offset + block_offsets + 0x00, sf); /* small */
|
||||
cfg.blocksize_0_exp = read_8bit(vorb_offset + block_offsets + 0x01, sf); /* big */
|
||||
}
|
||||
ww.data_size -= audio_offset;
|
||||
|
||||
|
@ -343,8 +354,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
* - trimmed inline: ~2010, ex. Army of Two: 40 days (X360) some multiplayer files
|
||||
* - external: ~2010, ex. Assassin's Creed Brotherhood (X360), Dead Nation (X360) */
|
||||
if (vorb_size == 0x34) {
|
||||
size_t setup_size = (uint16_t)read_16bit(start_offset + setup_offset, streamFile);
|
||||
uint32_t id = (uint32_t)read_32bitBE(start_offset + setup_offset + 0x06, streamFile);
|
||||
size_t setup_size = (uint16_t)read_16bit(start_offset + setup_offset, sf);
|
||||
uint32_t id = (uint32_t)read_32bitBE(start_offset + setup_offset + 0x06, sf);
|
||||
|
||||
/* if the setup after header starts with "(data)BCV" it's an inline codebook) */
|
||||
if ((id & 0x00FFFFFF) == 0x00424356) { /* 0"BCV" */
|
||||
|
@ -356,13 +367,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
}
|
||||
}
|
||||
|
||||
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
}
|
||||
else {
|
||||
/* newer Wwise (>2012) */
|
||||
off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */
|
||||
int is_wem = check_extensions(streamFile,"wem");
|
||||
int is_wem = check_extensions(sf,"wem");
|
||||
|
||||
switch(ww.extra_size) {
|
||||
case 0x30:
|
||||
|
@ -377,18 +388,16 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
|
||||
break;
|
||||
|
||||
//case 0x2a: /* Rocksmith 2011 (X360)? */
|
||||
//non mod packets? TYPE_06? (possibly detectable by checking setup's granule, should be 0)
|
||||
default:
|
||||
VGM_LOG("WWISE: unknown extra size 0x%x\n", vorb_size);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
vgmstream->num_samples = read_32bit(extra_offset + 0x00, streamFile);
|
||||
setup_offset = read_32bit(extra_offset + data_offsets + 0x00, streamFile); /* within data */
|
||||
audio_offset = read_32bit(extra_offset + data_offsets + 0x04, streamFile); /* within data */
|
||||
cfg.blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, streamFile); /* small */
|
||||
cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, streamFile); /* big */
|
||||
vgmstream->num_samples = read_32bit(extra_offset + 0x00, sf);
|
||||
setup_offset = read_32bit(extra_offset + data_offsets + 0x00, sf); /* within data */
|
||||
audio_offset = read_32bit(extra_offset + data_offsets + 0x04, sf); /* within data */
|
||||
cfg.blocksize_1_exp = read_8bit(extra_offset + block_offsets + 0x00, sf); /* small */
|
||||
cfg.blocksize_0_exp = read_8bit(extra_offset + block_offsets + 0x01, sf); /* big */
|
||||
ww.data_size -= audio_offset;
|
||||
|
||||
/* detect normal packets */
|
||||
|
@ -399,11 +408,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
}
|
||||
|
||||
/* try with the selected codebooks */
|
||||
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||
if (!vgmstream->codec_data) {
|
||||
/* codebooks failed: try again with the other type */
|
||||
cfg.setup_type = is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS;
|
||||
vgmstream->codec_data = init_vorbis_custom(streamFile, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
}
|
||||
}
|
||||
|
@ -436,12 +445,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
vgmstream->interleave_block_size = 0x08; /* ww.block_align = 0x8 in older Wwise, samples per block in newer Wwise */
|
||||
|
||||
/* find coef position */
|
||||
if (find_chunk(streamFile, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH", older Wwise */
|
||||
if (find_chunk(sf, 0x57696948,first_offset,0, &wiih_offset,&wiih_size, ww.big_endian, 0)) { /*"WiiH", older Wwise */
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels);
|
||||
if (wiih_size != 0x2e * ww.channels) goto fail;
|
||||
|
||||
if (is_dsp_full_interleave(sf, &ww, wiih_offset))
|
||||
vgmstream->interleave_block_size = ww.data_size / 2;
|
||||
}
|
||||
else if (ww.extra_size == 0x0c + ww.channels * 0x2e) { /* newer Wwise */
|
||||
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, streamFile);
|
||||
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, sf);
|
||||
wiih_offset = ww.fmt_offset + 0x1c;
|
||||
wiih_size = 0x2e * ww.channels;
|
||||
}
|
||||
|
@ -449,6 +461,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
if (ww.truncated) {
|
||||
ww.data_size = ww.file_size - ww.data_offset;
|
||||
vgmstream->num_samples = dsp_bytes_to_samples(ww.data_size, ww.channels);
|
||||
}
|
||||
|
||||
/* for some reason all(?) DSP .wem do full loops (even mono/jingles/etc) but
|
||||
* several tracks do loop like this, so disable it for short-ish tracks */
|
||||
if (ww.loop_flag && vgmstream->loop_start_sample == 0 &&
|
||||
|
@ -456,14 +473,8 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
vgmstream->loop_flag = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* get coefs and default history */
|
||||
dsp_read_coefs(vgmstream,streamFile,wiih_offset, 0x2e, ww.big_endian);
|
||||
for (i=0; i < ww.channels; i++) {
|
||||
vgmstream->ch[i].adpcm_history1_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x24,streamFile);
|
||||
vgmstream->ch[i].adpcm_history2_16 = read_16bitBE(wiih_offset + i * 0x2e + 0x26,streamFile);
|
||||
}
|
||||
dsp_read_coefs(vgmstream,sf,wiih_offset + 0x00, 0x2e, ww.big_endian);
|
||||
dsp_read_hist (vgmstream,sf,wiih_offset + 0x24, 0x2e, ww.big_endian);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -479,13 +490,13 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
//if (ww.fmt_size != ...) goto fail; /* XMA1 0x20, XMA2old: 0x34, XMA2new: 0x40, XMA2 Guitar Hero Live/padded: 0x64, etc */
|
||||
if (!ww.big_endian) goto fail; /* must be Wwise (real XMA are LE and parsed elsewhere) */
|
||||
|
||||
if (find_chunk(streamFile, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */
|
||||
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, streamFile);
|
||||
if (find_chunk(sf, 0x584D4132,first_offset,0, &xma2_offset,&xma2_size, ww.big_endian, 0)) { /*"XMA2"*/ /* older Wwise */
|
||||
bytes = ffmpeg_make_riff_xma2_from_xma2_chunk(buf,0x100, xma2_offset, xma2_size, ww.data_size, sf);
|
||||
} else { /* newer Wwise */
|
||||
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, streamFile, ww.big_endian);
|
||||
bytes = ffmpeg_make_riff_xma_from_fmt_chunk(buf,0x100, ww.fmt_offset, ww.fmt_size, ww.data_size, sf, ww.big_endian);
|
||||
}
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
|
||||
vgmstream->codec_data = init_ffmpeg_header_offset(sf, buf,bytes, ww.data_offset,ww.data_size);
|
||||
if ( !vgmstream->codec_data ) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
@ -493,11 +504,11 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
vgmstream->num_samples = ww.num_samples; /* set while parsing XMAWAVEFORMATs */
|
||||
|
||||
/* Wwise loops are always pre-adjusted (old or new) and only num_samples is off */
|
||||
xma_fix_raw_samples(vgmstream, streamFile, ww.data_offset,ww.data_size, ww.chunk_offset, 1,0);
|
||||
xma_fix_raw_samples(vgmstream, sf, ww.data_offset,ww.data_size, ww.chunk_offset, 1,0);
|
||||
|
||||
/* "XMAc": rare Wwise extension, XMA2 physical loop regions (loop_start_b, loop_end_b, loop_subframe_data)
|
||||
* Can appear even in the file doesn't loop, maybe it's meant to be the playable physical region */
|
||||
//VGM_ASSERT(find_chunk(streamFile, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n");
|
||||
//VGM_ASSERT(find_chunk(sf, 0x584D4163,first_offset,0, NULL,NULL, ww.big_endian, 0), "WWISE: XMAc chunk found\n");
|
||||
/* other chunks: "seek", regular XMA2 seek table */
|
||||
|
||||
/* XMA is VBR so this is very approximate percent, meh */
|
||||
|
@ -518,7 +529,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
if (!ww.big_endian) goto fail; /* must be from Wwise X360 (PC LE XWMA is parsed elsewhere) */
|
||||
|
||||
bytes = ffmpeg_make_riff_xwma(buf,0x100, ww.format, ww.data_size, vgmstream->channels, vgmstream->sample_rate, ww.average_bps, ww.block_align);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(streamFile, buf,bytes, ww.data_offset,ww.data_size);
|
||||
ffmpeg_data = init_ffmpeg_header_offset(sf, buf,bytes, ww.data_offset,ww.data_size);
|
||||
if ( !ffmpeg_data ) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
|
@ -534,9 +545,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
msd.data_size = ww.data_size;
|
||||
|
||||
if (ww.format == 0x0162)
|
||||
wmapro_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x00E0);
|
||||
wmapro_get_samples(&msd, sf, ww.block_align, ww.sample_rate,0x00E0);
|
||||
else
|
||||
wma_get_samples(&msd, streamFile, ww.block_align, ww.sample_rate,0x001F);
|
||||
wma_get_samples(&msd, sf, ww.block_align, ww.sample_rate,0x001F);
|
||||
|
||||
vgmstream->num_samples = msd.num_samples;
|
||||
if (!vgmstream->num_samples)
|
||||
|
@ -555,7 +566,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
|
||||
/* extra: size 0x12, unknown values */
|
||||
|
||||
ffmpeg_data = init_ffmpeg_offset(streamFile, ww.data_offset,ww.data_size);
|
||||
ffmpeg_data = init_ffmpeg_offset(sf, ww.data_offset,ww.data_size);
|
||||
if (!ffmpeg_data) goto fail;
|
||||
vgmstream->codec_data = ffmpeg_data;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
|
@ -572,9 +583,9 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
if (ww.fmt_size == 0x28) {
|
||||
size_t seek_size;
|
||||
|
||||
vgmstream->num_samples += read_32bit(ww.fmt_offset + 0x18, streamFile);
|
||||
vgmstream->num_samples += read_32bit(ww.fmt_offset + 0x18, sf);
|
||||
/* 0x1c: null? 0x20: data_size without seek_size */
|
||||
seek_size = read_32bit(ww.fmt_offset + 0x24, streamFile);
|
||||
seek_size = read_32bit(ww.fmt_offset + 0x24, sf);
|
||||
|
||||
start_offset += seek_size;
|
||||
ww.data_size -= seek_size;
|
||||
|
@ -583,7 +594,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
goto fail;
|
||||
}
|
||||
|
||||
skip = switch_opus_get_encoder_delay(start_offset, streamFile); /* should be 120 */
|
||||
skip = switch_opus_get_encoder_delay(start_offset, sf); /* should be 120 */
|
||||
|
||||
/* OPUS is VBR so this is very approximate percent, meh */
|
||||
if (ww.truncated) {
|
||||
|
@ -592,7 +603,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
ww.data_size = ww.file_size - start_offset;
|
||||
}
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_switch_opus(streamFile, start_offset,ww.data_size, vgmstream->channels, skip, vgmstream->sample_rate);
|
||||
vgmstream->codec_data = init_ffmpeg_switch_opus(sf, start_offset,ww.data_size, vgmstream->channels, skip, vgmstream->sample_rate);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
@ -603,7 +614,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
if (ww.block_align != 0 || ww.bits_per_sample != 0) goto fail;
|
||||
|
||||
/* extra: size 0x12 */
|
||||
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, streamFile);
|
||||
vgmstream->num_samples = read_32bit(ww.fmt_offset + 0x18, sf);
|
||||
/* 0x1c: stream size without OggS? */
|
||||
/* 0x20: full samples (without encoder delay) */
|
||||
|
||||
|
@ -614,7 +625,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
ww.data_size = ww.file_size - start_offset;
|
||||
}
|
||||
|
||||
vgmstream->codec_data = init_ffmpeg_offset(streamFile, ww.data_offset,ww.data_size);
|
||||
vgmstream->codec_data = init_ffmpeg_offset(sf, ww.data_offset,ww.data_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
@ -648,15 +659,15 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
if (ww.extra_size != 0x12) goto fail;
|
||||
|
||||
cfg.channels = vgmstream->channels;
|
||||
cfg.config_data = read_32bitBE(ww.fmt_offset+0x18,streamFile);
|
||||
cfg.encoder_delay = read_32bit(ww.fmt_offset+0x20,streamFile);
|
||||
cfg.config_data = read_32bitBE(ww.fmt_offset+0x18,sf);
|
||||
cfg.encoder_delay = read_32bit(ww.fmt_offset+0x20,sf);
|
||||
|
||||
vgmstream->codec_data = init_atrac9(&cfg);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
vgmstream->coding_type = coding_ATRAC9;
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
vgmstream->num_samples = read_32bit(ww.fmt_offset+0x1c,streamFile);
|
||||
vgmstream->num_samples = read_32bit(ww.fmt_offset+0x1c,sf);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
@ -678,7 +689,7 @@ VGMSTREAM * init_vgmstream_wwise(STREAMFILE *streamFile) {
|
|||
|
||||
|
||||
|
||||
if ( !vgmstream_open_stream(vgmstream,streamFile,start_offset) )
|
||||
if ( !vgmstream_open_stream(vgmstream,sf,start_offset) )
|
||||
goto fail;
|
||||
return vgmstream;
|
||||
|
||||
|
@ -687,6 +698,35 @@ fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset) {
|
||||
/* older (only?) Wwise use full interleave for memory (in .bnk) files, but
|
||||
* detection from the .wem side is problematic [Punch Out!! (Wii)]
|
||||
* - truncated point to streams = normal
|
||||
* - .bnk would be memory banks = full
|
||||
* - otherwise small-ish sizes, stereo, with initial predictors for the
|
||||
* second channel matching half size = full
|
||||
* some files aren't detectable like this though, when predictors are 0
|
||||
* (but since memory wem aren't that used this shouldn't be too common) */
|
||||
|
||||
if (ww->truncated)
|
||||
return 0;
|
||||
|
||||
if (check_extensions(sf,"bnk"))
|
||||
return 1;
|
||||
|
||||
if (ww->channels == 2 && ww->data_size <= 0x30000) {
|
||||
uint16_t head_ps2 = read_u16be(coef_offset + 1 * 0x2e + 0x22, sf); /* ch2's initial predictor */
|
||||
uint16_t init_ps2 = read_u8(ww->data_offset + 0x08, sf); /* at normal interleave */
|
||||
uint16_t half_ps2 = read_u8(ww->data_offset + ww->data_size / 2, sf); /* at full interleave */
|
||||
//;VGM_LOG("WWISE: DSP head2=%x, init2=%x, half2=%x\n", head_ps2, init_ps2, half_ps2);
|
||||
if (head_ps2 != init_ps2 && head_ps2 == half_ps2) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* VORBIS FORMAT RESEARCH */
|
||||
|
|
|
@ -195,16 +195,10 @@ VGMSTREAM * init_vgmstream_zsnd(STREAMFILE *streamFile) {
|
|||
name_offset = 0;
|
||||
name_size = 0;
|
||||
|
||||
//TODO: possibly pitch: sample_rate = round10(pitch * 44100 / 4096);
|
||||
switch(sample_rate) {
|
||||
case 0x0800: sample_rate = 22050; break;
|
||||
case 0x0687: sample_rate = 18000; break;
|
||||
case 0x05ce: sample_rate = 16000; break;
|
||||
case 0x0400: sample_rate = 11025; break;
|
||||
default:
|
||||
VGM_LOG("ZSND: unknown sample_rate %x at %x\n", sample_rate, (uint32_t)header2_offset);
|
||||
goto fail;
|
||||
}
|
||||
/* pitch value, with 0x1000=44100 (voices vary quite a bit, ex. X-Men Legends 2) */
|
||||
sample_rate = round10(sample_rate * 44100.0 / 4096.0);
|
||||
/* there may be some rounding for lower values, ex 0x45A = 11993.99 ~= 12000, though not all:
|
||||
* 0x1000 = 44100, 0x0800 = 22050, 0x0687 ~= 18000, 0x05ce ~= 16000, 0x045a ~= 12000, 0x0400 = 11025 */
|
||||
break;
|
||||
|
||||
case 0x47435542: /* "GCUB" (also for Wii) */
|
||||
|
|
|
@ -77,7 +77,8 @@ static size_t read_stdio(STDIO_STREAMFILE *streamfile, uint8_t *dst, off_t offse
|
|||
/* Workaround a bug that appears when compiling with MSVC (later versions).
|
||||
* This bug is deterministic and seemingly appears randomly after seeking.
|
||||
* It results in fread returning data from the wrong area of the file.
|
||||
* HPS is one format that is almost always affected by this. */
|
||||
* HPS is one format that is almost always affected by this.
|
||||
* May be related/same as open_stdio's bug when using dup() */
|
||||
fseek(streamfile->infile, ftell(streamfile->infile), SEEK_SET);
|
||||
#endif
|
||||
|
||||
|
@ -132,7 +133,12 @@ static STREAMFILE* open_stdio(STDIO_STREAMFILE *streamfile, const char * const f
|
|||
if (!filename)
|
||||
return NULL;
|
||||
|
||||
#if !defined (__ANDROID__)
|
||||
#if !defined (__ANDROID__) && !defined (_MSC_VER)
|
||||
/* when enabling this for MSVC it'll seemingly work, but there are issues possibly related to underlying
|
||||
* IO buffers when using dup(), noticeable by re-opening the same streamfile with small buffer sizes
|
||||
* (reads garbage). fseek bug in line 81 may be related/same thing and may be removed.
|
||||
* this reportedly this causes issues in Android too */
|
||||
|
||||
/* if same name, duplicate the file descriptor we already have open */
|
||||
if (streamfile->infile && !strcmp(streamfile->name,filename)) {
|
||||
int new_fd;
|
||||
|
|
|
@ -492,6 +492,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
|||
init_vgmstream_lrmd,
|
||||
init_vgmstream_bkhd,
|
||||
init_vgmstream_bkhd_fx,
|
||||
init_vgmstream_diva,
|
||||
|
||||
/* lowest priority metas (should go after all metas, and TXTH should go before raw formats) */
|
||||
init_vgmstream_txth, /* proper parsers should supersede TXTH, once added */
|
||||
|
|
|
@ -735,6 +735,7 @@ typedef enum {
|
|||
meta_KWB,
|
||||
meta_LRMD,
|
||||
meta_WWISE_FX,
|
||||
meta_DIVA,
|
||||
} meta_t;
|
||||
|
||||
/* standard WAVEFORMATEXTENSIBLE speaker positions */
|
||||
|
|
Loading…
Reference in New Issue