mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-12 01:30:49 +01:00
misc cleanup
This commit is contained in:
parent
cbaf17bfe0
commit
82fc05c3dc
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
@ -864,6 +868,8 @@ 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:
|
||||
/* 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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user