misc cleanup

This commit is contained in:
bnnm 2021-09-19 23:54:38 +02:00
parent cbaf17bfe0
commit 82fc05c3dc
8 changed files with 188 additions and 151 deletions

View File

@ -87,7 +87,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
VGMSTREAM* (*init_vgmstream_subkey)(STREAMFILE* sf, uint16_t subkey) = NULL;
const char* extension = NULL;
if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX) */
if (read_u16be(subfile_offset, sf) == 0x8000) { /* (type 0=ADX, also 3?) */
init_vgmstream_subkey = init_vgmstream_adx_subkey; /* Okami HD (PS4) */
extension = "adx";
}
@ -99,7 +99,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
init_vgmstream = init_vgmstream_vag; /* Ukiyo no Roushi (Vita) */
extension = "vag";
}
else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9) */
else if (is_id32be(subfile_offset,sf, "RIFF")) { /* (type 8=ATRAC3, 11=ATRAC9, also 18=ATRAC9?) */
init_vgmstream = init_vgmstream_riff; /* Ukiyo no Roushi (Vita) */
extension = "wav";
subfile_size = read_u32le(subfile_offset + 0x04,sf) + 0x08; /* padded size, use RIFF's */
@ -111,7 +111,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
else if (read_u32be(subfile_offset + 0x08,sf) >= 8000 && read_u32be(subfile_offset + 0x08,sf) <= 48000 &&
read_u16be(subfile_offset + 0x0e,sf) == 0 &&
read_u32be(subfile_offset + 0x18,sf) == 2 &&
read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP), probably should call some check function */
read_u32be(subfile_offset + 0x50,sf) == 0) { /* (type 13=DSP, also 4=Wii?, 5=NDS?), probably should call some check function */
init_vgmstream = init_vgmstream_ngc_dsp_std; /* Sonic: Lost World (WiiU) */
extension = "dsp";
}
@ -125,7 +125,7 @@ VGMSTREAM* init_vgmstream_awb_memory(STREAMFILE* sf, STREAMFILE* sf_acb) {
extension = "m4a";
}
#endif
else {
else { /* 12=XMA? */
vgm_logi("AWB: unknown codec (report)\n");
goto fail;
}

View File

@ -2,34 +2,31 @@
#include "../coding/coding.h"
/* FWAV - Nintendo streams */
VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
off_t info_offset, data_offset;
int channel_count, loop_flag, codec;
int channels, loop_flag, codec, sample_rate;
int big_endian;
size_t interleave = 0;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
int nsmbu_flag = 0;
/* checks */
if (!is_id32be(0x00, sf, "FWAV"))
goto fail;
/* .bfwavnsmbu: fake extension to detect New Super Mario Bros U files with weird sample rate */
if (!check_extensions(streamFile, "bfwav,fwav,bfwavnsmbu"))
if (!check_extensions(sf, "bfwav,fwav,bfwavnsmbu"))
goto fail;
nsmbu_flag = check_extensions(streamFile, "bfwavnsmbu");
/* FWAV header */
if (read_32bitBE(0x00, streamFile) != 0x46574156) /* "FWAV" */
goto fail;
/* 0x06(2): header size (0x40), 0x08: version (0x00010200), 0x0c: file size 0x10(2): sections (2) */
if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFEFF) { /* BE BOM check */
/* BOM check */
if (read_u16be(0x04, sf) == 0xFEFF) {
read_32bit = read_32bitBE;
read_16bit = read_16bitBE;
big_endian = 1;
} else if ((uint16_t)read_16bitBE(0x04, streamFile) == 0xFFFE) { /* LE BOM check */
} else if (read_u16be(0x04, sf) == 0xFFFE) {
read_32bit = read_32bitLE;
read_16bit = read_16bitLE;
big_endian = 0;
@ -37,60 +34,74 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
goto fail;
}
info_offset = read_32bit(0x18, streamFile); /* 0x14(2): info mark (0x7000), 0x1c: info size */
data_offset = read_32bit(0x24, streamFile); /* 0x20(2): data mark (0x7001), 0x28: data size */
/* FWAV header */
/* 0x06(2): header size (0x40) */
/* 0x08: version (0x00010200) */
/* 0x0c: file size */
/* 0x10(2): sections (2) */
/* 0x14(2): info mark (0x7000) */
info_offset = read_32bit(0x18, sf);
/* 0x1c: info size */
/* 0x20(2): data mark (0x7001) */
data_offset = read_32bit(0x24, sf);
/* 0x28: data size */
/* INFO section */
if (read_32bitBE(info_offset, streamFile) != 0x494E464F) /* "INFO" */
if (!is_id32be(info_offset, sf, "INFO"))
goto fail;
codec = read_8bit(info_offset + 0x08, streamFile);
loop_flag = read_8bit(info_offset + 0x09, streamFile);
channel_count = read_32bit(info_offset + 0x1C, streamFile);
codec = read_u8(info_offset + 0x08, sf);
loop_flag = read_u8(info_offset + 0x09, sf);
sample_rate = read_32bit(info_offset + 0x0C, sf);
channels = read_32bit(info_offset + 0x1C, sf);
//TODO remove
if (check_extensions(sf, "bfwavnsmbu"))
sample_rate = 16000;
/* parse channel table */
{
off_t channel1_info, data_start;
int i;
channel1_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*0+0x04, streamFile);
data_start = read_32bit(channel1_info+0x04, streamFile); /* within "DATA" after 0x08 */
channel1_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*0+0x04, sf);
data_start = read_32bit(channel1_info+0x04, sf); /* within "DATA" after 0x08 */
/* channels use absolute offsets but should be ok as interleave */
interleave = 0;
if (channel_count > 1) {
off_t channel2_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*1+0x04, streamFile);
interleave = read_32bit(channel2_info+0x04, streamFile) - data_start;
if (channels > 1) {
off_t channel2_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*1+0x04, sf);
interleave = read_32bit(channel2_info+0x04, sf) - data_start;
}
start_offset = data_offset + 0x08 + data_start;
/* validate all channels just in case of multichannel with non-constant interleave */
for (i = 0; i < channel_count; i++) {
for (i = 0; i < channels; i++) {
/* channel table, 0x00: flag (0x7100), 0x04: channel info offset */
off_t channel_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*i+0x04, streamFile);
off_t channel_info = info_offset + 0x1c + read_32bit(info_offset+0x20+0x08*i+0x04, sf);
/* channel info, 0x00(2): flag (0x1f00), 0x04: offset, 0x08(2): ADPCM flag (0x0300), 0x0c: ADPCM offset */
if ((uint16_t)read_16bit(channel_info+0x00, streamFile) != 0x1F00)
if ((uint16_t)read_16bit(channel_info+0x00, sf) != 0x1F00)
goto fail;
if (read_32bit(channel_info+0x04, streamFile) != data_start + interleave*i)
if (read_32bit(channel_info+0x04, sf) != data_start + interleave*i)
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_32bit(info_offset + 0x0C, streamFile);
if (nsmbu_flag)
vgmstream->sample_rate = 16000;
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = read_32bit(info_offset + 0x14, streamFile);
vgmstream->loop_start_sample = read_32bit(info_offset + 0x10, streamFile);
vgmstream->num_samples = read_32bit(info_offset + 0x14, sf);
vgmstream->loop_start_sample = read_32bit(info_offset + 0x10, sf);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_FWAV;
vgmstream->layout_type = (channel_count == 1) ? layout_none : layout_interleave;
vgmstream->layout_type = (channels == 1) ? layout_none : layout_interleave;
vgmstream->interleave_block_size = interleave;
switch (codec) {
@ -110,9 +121,9 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
for (i = 0; i < vgmstream->channels; i++) {
for (c = 0; c < 16; c++) {
coef_header = info_offset + 0x1C + read_32bit(info_offset + 0x24 + (i*0x08), streamFile);
coef_offset = read_32bit(coef_header + 0x0c, streamFile) + coef_header;
vgmstream->ch[i].adpcm_coef[c] = read_16bit(coef_offset + c*2, streamFile);
coef_header = info_offset + 0x1C + read_32bit(info_offset + 0x24 + (i*0x08), sf);
coef_offset = read_32bit(coef_header + 0x0c, sf) + coef_header;
vgmstream->ch[i].adpcm_coef[c] = read_16bit(coef_offset + c*2, sf);
}
}
}
@ -123,7 +134,7 @@ VGMSTREAM * init_vgmstream_bfwav(STREAMFILE *streamFile) {
}
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream,sf,start_offset))
goto fail;
return vgmstream;

View File

@ -191,10 +191,21 @@ done:
}
#ifdef HCA_BRUTEFORCE
typedef enum {
HBF_TYPE_64LE_1,
HBF_TYPE_64BE_1,
HBF_TYPE_32LE_1,
HBF_TYPE_32BE_1,
HBF_TYPE_64LE_4,
HBF_TYPE_64BE_4,
HBF_TYPE_32LE_4,
HBF_TYPE_32BE_4,
} HBF_type_t;
/* Bruteforce binary keys in executables and similar files, mainly for some mobile games.
* Kinda slow but acceptable for ~20MB exes, not very optimized. Unity usually has keys
* in plaintext (inside levelX or other base files) instead though. */
static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
static void bruteforce_hca_key_bin_type(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey, HBF_type_t type) {
STREAMFILE* sf_keys = NULL;
uint8_t* buf = NULL;
int best_score = 0xFFFFFF, cur_score;
@ -203,7 +214,7 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns
uint64_t old_key = 0;
VGM_LOG("HCA: test keys.bin\n");
VGM_LOG("HCA: test keys.bin (type %i)\n", type);
*p_keycode = 0;
@ -226,17 +237,18 @@ static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, uns
uint64_t key;
VGM_ASSERT(pos % 0x1000000 == 0, "HCA: pos %x...\n", pos);
/* keys are usually u32le lower, u32le upper (u64le) but other orders may exist */
key = ((uint64_t)get_u32le(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32le(buf + pos + 0x04) << 32);
//key = ((uint64_t)get_u32le(buf + pos + 0x00) << 32) | ((uint64_t)get_u32le(buf + pos + 0x04) << 0);
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | ((uint64_t)get_u32be(buf + pos + 0x04) << 32);
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 32) | ((uint64_t)get_u32be(buf + pos + 0x04) << 0);
//key = ((uint64_t)get_u32le(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */
//key = ((uint64_t)get_u32be(buf + pos + 0x00) << 0 ) | 0; /* upper bytes not set, ex. P5 */
/* observed files have aligned keys, change if needed */
pos += 0x04;
//pos++;
/* keys are usually u64le but other orders may exist */
switch(type) {
case HBF_TYPE_64LE_1: key = get_u64le(buf + pos); pos += 0x01; break;
case HBF_TYPE_64BE_1: key = get_u64be(buf + pos); pos += 0x01; break;
case HBF_TYPE_32LE_1: key = get_u32le(buf + pos); pos += 0x01; break;
case HBF_TYPE_32BE_1: key = get_u32be(buf + pos); pos += 0x01; break;
case HBF_TYPE_64LE_4: key = get_u64le(buf + pos); pos += 0x04; break;
case HBF_TYPE_64BE_4: key = get_u64be(buf + pos); pos += 0x04; break;
case HBF_TYPE_32LE_4: key = get_u32le(buf + pos); pos += 0x04; break;
case HBF_TYPE_32BE_4: key = get_u32be(buf + pos); pos += 0x04; break;
default: key = 0; pos = keys_size; break;
}
if (key == 0 || key == old_key)
continue;
@ -266,6 +278,18 @@ done:
free(buf);
}
static void bruteforce_hca_key_bin(STREAMFILE* sf, hca_codec_data* hca_data, unsigned long long* p_keycode, uint16_t subkey) {
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_4);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_4);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_4);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_4);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64LE_1);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_64BE_1);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32LE_1);
bruteforce_hca_key_bin_type(sf, hca_data, p_keycode, subkey, HBF_TYPE_32BE_1);
}
#include <inttypes.h>
//#include <stdio.h>
@ -303,14 +327,13 @@ static void bruteforce_hca_key_txt(STREAMFILE* sf, hca_codec_data* hca_data, uns
uint64_t key = 0;
bytes_read = read_line(line, sizeof(line), pos, sf_keys, &line_ok);
if (!line_ok) continue; //???
pos += bytes_read;
if (!line_ok) continue; /* line too long */
count = sscanf(line, "%" SCNd64, &key);
if (count != 1) continue;
VGM_ASSERT(pos % 100000 == 0, "HCA: count %i...\n", i);
VGM_ASSERT(pos % 10000 == 0, "HCA: count %i...\n", i);
if (key == 0)
continue;

View File

@ -2,13 +2,6 @@
#include "../coding/coding.h"
static int is_id4(const char* test, off_t offset, STREAMFILE* sf) {
uint8_t buf[4];
if (read_streamfile(buf, offset, sizeof(buf), sf) != sizeof(buf))
return 0;
return memcmp(buf, test, sizeof(buf)) == 0; /* memcmp to allow "AB\0\0" */
}
/* LucasArts iMUSE (Interactive Music Streaming Engine) formats */
VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
@ -19,19 +12,13 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
/* checks */
/* .imx: The Curse of Monkey Island (PC)
* .imc: Grim Fandango (multi)
* .wav: Grim Fandango (multi) RIFF sfx */
if (!check_extensions(sf, "imx,imc,wav,lwav"))
goto fail;
/* base decoder block table */
if (is_id4("COMP", 0x00, sf)) { /* The Curse of Monkey Island (PC), The Dig (PC) */
if (is_id32be(0x00, sf, "COMP")) { /* The Curse of Monkey Island (PC), The Dig (PC) */
int entries = read_u32be(0x04,sf);
head_offset = 0x10 + entries * 0x10 + 0x02; /* base header + table + header size */
}
else if (is_id4("MCMP", 0x00, sf)) { /* Grim Fandango (multi), Star Wars: X-Wing Alliance (PC) */
else if (is_id32be(0x00, sf, "MCMP")) { /* Grim Fandango (multi), Star Wars: X-Wing Alliance (PC) */
int entries = read_u16be(0x04,sf);
head_offset = 0x06 + entries * 0x09; /* base header + table */
head_offset += 0x02 + read_u16be(head_offset, sf); /* + mini text header */
@ -40,17 +27,23 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
goto fail;
}
/* .imx: The Curse of Monkey Island (PC)
* .imc: Grim Fandango (multi)
* .wav: Grim Fandango (multi) RIFF sfx */
if (!check_extensions(sf, "imx,imc,wav,lwav"))
goto fail;
/* "offsets" below seem to count decoded data. Data is divided into variable-sized blocks that usually
* return 0x2000 bytes (starting from and including header). File starts with a block table to make
* this manageable. Most offsets don't seem to match block or data boundaries so not really sure. */
/* main header after table */
if (is_id4("iMUS", head_offset, sf)) { /* COMP/MCMP */
if (is_id32be(head_offset, sf, "iMUS")) { /* COMP/MCMP */
int header_found = 0;
/* 0x04: decompressed size (header size + pcm bytes) */
if (!is_id4("MAP ", head_offset + 0x08, sf))
if (!is_id32be(head_offset + 0x08, sf, "MAP "))
goto fail;
map_size = read_u32be(head_offset + 0x0c, sf);
map_offset = head_offset + 0x10;
@ -105,12 +98,12 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
if (!header_found)
goto fail;
if (!is_id4("DATA", head_offset + 0x10 + map_size + 0x00, sf))
if (!is_id32be(head_offset + 0x10 + map_size + 0x00, sf, "DATA"))
goto fail;
data_bytes = read_u32be(head_offset + 0x10 + map_size + 0x04, sf);
num_samples = data_bytes / channels / sizeof(int16_t);
}
else if (is_id4("RIFF", head_offset, sf)) { /* MCMP voices */
else if (is_id32be(head_offset, sf, "RIFF")) { /* MCMP voices */
/* standard (LE), with fake codec 1 and sizes also in decoded bytes (see above),
* has standard RIFF chunks (may include extra), start offset in MCSC */
@ -124,7 +117,8 @@ VGMSTREAM* init_vgmstream_imuse(STREAMFILE* sf) {
num_samples = data_bytes / channels / sizeof(int16_t);
}
else {
goto fail; /* The Dig (PC) has no header, detect? */
vgm_logi("IMUSE: unsupported format\n");
goto fail; /* The Dig (PC) has no header, detect? (needs a bunch of sub-codecs) */
}
loop_flag = 0;

View File

@ -2,41 +2,43 @@
#include "../util.h"
/* STRM - common Nintendo NDS streaming format */
VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL;
VGMSTREAM* init_vgmstream_nds_strm(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
off_t start_offset;
int channel_count, loop_flag, codec;
int channels, loop_flag, codec, sample_rate;
/* checks */
if (!check_extensions(streamFile, "strm"))
if (!is_id32be(0x00,sf, "STRM"))
goto fail;
if (read_32bitBE(0x00,streamFile) != 0x5354524D) /* "STRM" */
goto fail;
if (read_32bitBE(0x04,streamFile) != 0xFFFE0001 && /* Old Header Check */
(read_32bitBE(0x04,streamFile) != 0xFEFF0001)) /* Some newer games have a new flag */
if (!check_extensions(sf, "strm"))
goto fail;
if (read_32bitBE(0x10,streamFile) != 0x48454144 && /* "HEAD" */
read_32bitLE(0x14,streamFile) != 0x50) /* 0x50-sized head is all I've seen */
/* BOM check? */
if (read_u32be(0x04,sf) != 0xFFFE0001 &&
read_u32be(0x04,sf) != 0xFEFF0001) /* newer games? */
goto fail;
codec = read_8bit(0x18,streamFile);
loop_flag = read_8bit(0x19,streamFile);
channel_count = read_8bit(0x1a,streamFile);
if (channel_count > 2) goto fail;
if (!is_id32be(0x10,sf, "HEAD") &&
read_u32le(0x14,sf) != 0x50)
goto fail;
start_offset = read_32bitLE(0x28,streamFile);
codec = read_u8(0x18,sf);
loop_flag = read_u8(0x19,sf);
sample_rate = read_u16le(0x1c,sf);
channels = read_u8(0x1a,sf);
if (channels > 2) goto fail;
start_offset = read_u32le(0x28,sf);
/* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channel_count,loop_flag);
vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail;
vgmstream->sample_rate = (uint16_t)read_16bitLE(0x1c,streamFile);
vgmstream->num_samples = read_32bitLE(0x24,streamFile);
vgmstream->loop_start_sample = read_32bitLE(0x20,streamFile);
vgmstream->sample_rate = sample_rate;
vgmstream->num_samples = read_32bitLE(0x24,sf);
vgmstream->loop_start_sample = read_32bitLE(0x20,sf);
vgmstream->loop_end_sample = vgmstream->num_samples;
vgmstream->meta_type = meta_STRM;
@ -55,11 +57,11 @@ VGMSTREAM * init_vgmstream_nds_strm(STREAMFILE *streamFile) {
goto fail;
}
vgmstream->layout_type = layout_interleave;
vgmstream->interleave_block_size = read_32bitLE(0x30,streamFile);
vgmstream->interleave_last_block_size = read_32bitLE(0x38,streamFile);
vgmstream->interleave_block_size = read_32bitLE(0x30,sf);
vgmstream->interleave_last_block_size = read_32bitLE(0x38,sf);
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;

View File

@ -1,6 +1,7 @@
#include "meta.h"
#include "../util.h"
#include "../coding/coding.h"
#include "../util/chunks.h"
/* Wwise uses a custom RIFF/RIFX header, non-standard enough that it's parsed it here.
@ -14,6 +15,7 @@ typedef struct {
int big_endian;
size_t file_size;
int truncated;
int is_wem;
/* chunks references */
off_t fmt_offset;
@ -55,7 +57,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww);
static int is_dsp_full_interleave(STREAMFILE* sf, wwise_header* ww, off_t coef_offset);
/* Wwise - Audiokinetic Wwise (Wave Works Interactive Sound Engine) middleware */
/* Wwise - Audiokinetic Wwise (WaveWorks Interactive Sound Engine) middleware */
VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
wwise_header ww = {0};
@ -66,11 +68,16 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
/* checks */
/* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011)
if (!is_id32be(0x00,sf, "RIFF") && /* LE */
!is_id32be(0x00,sf, "RIFX")) /* BE */
goto fail;
/* note that Wwise allows those extensions only, so custom engine exts shouldn't be added
* .wem: newer "Wwise Encoded Media" used after the 2011.2 SDK (~july 2011)
* .wav: older PCM/ADPCM files [Spider-Man: Web of Shadows (PC), 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 */
* .bnk: Wwise banks for memory .wem detection (hack) */
if (!check_extensions(sf,"wem,wav,lwav,ogg,logg,xma,bnk"))
goto fail;
@ -234,7 +241,6 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
else {
/* newer Wwise (>2012) */
off_t extra_offset = ww.fmt_offset + 0x18; /* after flag + channels */
int is_wem = check_extensions(sf,"wem,bnk"); /* use extension as a guide for faster vorbis inits */
switch(ww.extra_size) {
case 0x30:
@ -246,7 +252,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
/* setup not detectable by header, so we'll try both; libvorbis should reject wrong codebooks
* - standard: early (<2012), ex. The King of Fighters XIII (X360)-2011/11, .ogg (cbs are from aoTuV, too)
* - aoTuV603: later (>2012), ex. Sonic & All-Stars Racing Transformed (PC)-2012/11, .wem */
cfg.setup_type = is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
cfg.setup_type = ww.is_wem ? WWV_AOTUV603_CODEBOOKS : WWV_EXTERNAL_CODEBOOKS; /* aoTuV came along .wem */
break;
default:
@ -278,7 +284,7 @@ VGMSTREAM* init_vgmstream_wwise(STREAMFILE* sf) {
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;
cfg.setup_type = ww.is_wem ? WWV_EXTERNAL_CODEBOOKS : WWV_AOTUV603_CODEBOOKS;
vgmstream->codec_data = init_vorbis_custom(sf, start_offset + setup_offset, VORBIS_WWISE, &cfg);
if (!vgmstream->codec_data) goto fail;
}
@ -693,14 +699,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
uint32_t (*read_u32)(off_t,STREAMFILE*) = NULL;
uint16_t (*read_u16)(off_t,STREAMFILE*) = NULL;
if (read_u32be(0x00,sf) != 0x52494646 && /* "RIFF" (LE) */
read_u32be(0x00,sf) != 0x52494658) /* "RIFX" (BE) */
goto fail;
if (read_u32be(0x08,sf) != 0x57415645 && /* "WAVE" */
read_u32be(0x08,sf) != 0x58574D41) /* "XWMA" */
goto fail;
ww->big_endian = read_u32be(0x00,sf) == 0x52494658; /* RIFX */
ww->big_endian = is_id32be(0x00,sf, "RIFX");
if (ww->big_endian) { /* Wwise honors machine's endianness (PC=RIFF, X360=RIFX --unlike XMA) */
read_u32 = read_u32be;
read_u16 = read_u16be;
@ -727,50 +726,56 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
}
#endif
if (!is_id32be(0x08,sf, "WAVE") &&
!is_id32be(0x08,sf, "XWMA"))
goto fail;
/* parse chunks (reads once linearly) */
{
off_t offset = 0x0c;
while (offset < ww->file_size) {
uint32_t type = read_u32be(offset + 0x00,sf);
uint32_t size = read_u32 (offset + 0x04,sf);
offset += 0x08;
chunk_t rc = {0};
switch(type) {
/* chunks are even-aligned and don't need to add padding byte, unlike real RIFFs */
rc.be_size = ww->big_endian;
rc.current = 0x0c;
while (next_chunk(&rc, sf)) {
switch(rc.type) {
case 0x666d7420: /* "fmt " */
ww->fmt_offset = offset;
ww->fmt_size = size;
ww->fmt_offset = rc.offset;
ww->fmt_size = rc.size;
break;
case 0x584D4132: /* "XMA2" */
ww->xma2_offset = offset;
ww->xma2_size = size;
ww->xma2_offset = rc.offset;
ww->xma2_size = rc.size;
break;
case 0x64617461: /* "data" */
ww->data_offset = offset;
ww->data_size = size;
ww->data_offset = rc.offset;
ww->data_size = rc.size;
break;
case 0x766F7262: /* "vorb" */
ww->vorb_offset = offset;
ww->vorb_size = size;
ww->vorb_offset = rc.offset;
ww->vorb_size = rc.size;
break;
case 0x57696948: /* "WiiH" */
ww->wiih_offset = offset;
ww->wiih_size = size;
ww->wiih_offset = rc.offset;
ww->wiih_size = rc.size;
break;
case 0x7365656B: /* "seek" */
ww->seek_offset = offset;
ww->seek_size = size;
ww->seek_offset = rc.offset;
ww->seek_size = rc.size;
break;
case 0x736D706C: /* "smpl" */
ww->smpl_offset = offset;
ww->smpl_size = size;
ww->smpl_offset = rc.offset;
ww->smpl_size = rc.size;
break;
case 0x6D657461: /* "meta" */
ww->meta_offset = offset;
ww->meta_size = size;
ww->meta_offset = rc.offset;
ww->meta_size = rc.size;
break;
case 0x66616374: /* "fact" */
/* Wwise shouldn't use fact, but if somehow some file does uncomment the following: */
/* Wwise never uses fact, but if somehow some file does uncomment the following: */
//if (size == 0x10 && read_u32be(offset + 0x04, sf) == 0x4C794E20) /* "LyN " */
// goto fail; /* ignore LyN RIFF */
goto fail;
@ -783,12 +788,11 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
default:
break;
}
/* chunks are even-aligned and don't need to add padding byte, unlike real RIFFs */
offset += size;
}
}
/* use extension as a guide for certain cases */
ww->is_wem = check_extensions(sf,"wem,bnk");
/* parse format (roughly spec-compliant but some massaging is needed) */
if (ww->xma2_offset) {
@ -806,7 +810,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
ww->channels = read_u16(ww->fmt_offset + 0x02,sf);
ww->sample_rate = read_u32(ww->fmt_offset + 0x04,sf);
ww->avg_bitrate = read_u32(ww->fmt_offset + 0x08,sf);
ww->block_size = read_u16(ww->fmt_offset + 0x0c,sf);
ww->block_size = read_u16(ww->fmt_offset + 0x0c,sf);
ww->bits_per_sample = read_u16(ww->fmt_offset + 0x0e,sf);
if (ww->fmt_size > 0x10 && ww->format != 0x0165 && ww->format != 0x0166) /* ignore XMAWAVEFORMAT */
ww->extra_size = read_u16(ww->fmt_offset + 0x10,sf);
@ -864,7 +868,9 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
case 0x3041: ww->codec = OPUSWW; break; /* "OPUS_WEM", added on Wwise 2019.2.3, replaces OPUS */
case 0x8311: ww->codec = PTADPCM; break; /* added on Wwise 2019.1, replaces IMA */
default:
vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format);
/* some .wav may end up here, only report in .wem cases (newer codecs) */
if (ww->is_wem)
vgm_logi("WWISE: unknown codec 0x%04x (report)\n", ww->format);
goto fail;
}

View File

@ -13,6 +13,7 @@ typedef struct {
int le_type; /* read type as LE instead of more common BE */
int be_size; /* read type as BE instead of more common LE */
int full_size; /* chunk size includes type+size */
int alignment; /* chunks with odd size need to be aligned to even, per RIFF spec */
} chunk_t;
int next_chunk(chunk_t* chunk, STREAMFILE* sf);

View File

@ -22,8 +22,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_adx,
init_vgmstream_brstm,
init_vgmstream_bfwav,
init_vgmstream_bfstm,
init_vgmstream_mca,
init_vgmstream_nds_strm,
init_vgmstream_agsc,
init_vgmstream_ngc_adpdtk,
@ -66,12 +64,6 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
#endif
init_vgmstream_sli_ogg,
init_vgmstream_sfl_ogg,
#if 0
init_vgmstream_mp4_aac,
#endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
init_vgmstream_akb_mp4,
#endif
init_vgmstream_sadb,
init_vgmstream_ps2_bmdx,
init_vgmstream_wsi,
@ -294,6 +286,14 @@ VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_idsp_namco,
init_vgmstream_kt_g1l,
init_vgmstream_kt_wiibgm,
init_vgmstream_bfstm,
init_vgmstream_mca,
#if 0
init_vgmstream_mp4_aac,
#endif
#if defined(VGM_USE_MP4V2) && defined(VGM_USE_FDKAAC)
init_vgmstream_akb_mp4,
#endif
init_vgmstream_ktss,
init_vgmstream_hca,
init_vgmstream_svag_snk,