Merge pull request #1065 from bnnm/brwav-xa-ww

- Improve .bnsf key detection in some cases
- Allow BIK .xmv extension [Emergency Heroes (Wii)]
- Fix some Reflections .xa [Emergency Heroes (Wii)]
- Remove .04sw fake extension (use .xa)
- Fix Wwise XWMA prefetch
- Add .pk/spk variation [Michael Jackson TE (X360)]
- Redo .rwav/rwar and add .brwav
This commit is contained in:
bnnm 2022-01-30 13:40:39 +01:00 committed by GitHub
commit 915531b1a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 419 additions and 350 deletions

View File

@ -107,9 +107,18 @@ class App(object):
subdir = subdir + '/' subdir = subdir + '/'
text = subdir + text text = subdir + text
else: else:
# should be a mini-txtp, but if name isn't "file.ext.txtp" and just "file.txtp",
# probably means proper txtp exists and should't be created (when generating from !tags.m3u)
name = line name = line
text = '' text = ''
basename = os.path.basename(name)
subname, _ = os.path.splitext(basename)
_, subext = os.path.splitext(subname)
if not subext:
print("ignored pre-txtp: %s" % (basename))
continue
outpath = os.path.join(path, name) outpath = os.path.join(path, name)
with open(outpath, 'w') as fo: with open(outpath, 'w') as fo:

View File

@ -116,7 +116,7 @@ int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf) {
/* assumes key was set before this call */ /* assumes key was set before this call */
while (test_frames < S14_KEY_MAX_TEST_FRAMES && current_frame < max_frames) { while (test_frames < S14_KEY_MAX_TEST_FRAMES && current_frame < max_frames) {
int score, ok; int score, res;
size_t bytes; size_t bytes;
uint8_t buf[G7221_MAX_FRAME_SIZE]; uint8_t buf[G7221_MAX_FRAME_SIZE];
@ -127,8 +127,8 @@ int test_key_g7221(g7221_codec_data* data, off_t start, STREAMFILE* sf) {
break; break;
} }
ok = g7221_decode_frame(data->ch[cur_ch].handle, buf, data->ch[cur_ch].buffer); res = g7221_decode_frame(data->ch[cur_ch].handle, buf, data->ch[cur_ch].buffer);
if (!ok) { if (res < 0) {
total_score = -1; total_score = -1;
break; break;
} }

View File

@ -1072,12 +1072,13 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
/* test for errors (in refdec but not Namco's, useful to detect decryption) */ /* test for errors (in refdec but not Namco's, useful to detect decryption) */
if (test_errors) { if (test_errors) {
int max_pad_bytes = 0x7; /* usually 0x04 and rarely ~0x07 */
int bits_left = 8 * expected_frame_size - bitpos; int bits_left = 8 * expected_frame_size - bitpos;
int i, endpos, test_bits; int i, endpos, test_bits;
if (bits_left > 0) { if (bits_left > 0) {
/* frame must be padded with 1s */ /* frame must be padded with 1s after regular data */
endpos = bitpos; endpos = bitpos;
for (i = 0; i < bits_left; i++) { for (i = 0; i < bits_left; i++) {
int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1; int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1;
@ -1087,19 +1088,21 @@ static int unpack_frame(int bit_rate, const uint8_t* data, int frame_size, /*int
return -1; return -1;
} }
/* extra: test we aren't in the middle of padding (happens with bad keys) */ /* extra: test we aren't in the middle of padding (happens with bad keys)
* After reading the whole frame, last bit position should land near last useful
* data, a few bytes into padding, so check there aren't too many padding bits. */
endpos = bitpos; endpos = bitpos;
test_bits = 8 * 0x04; test_bits = 8 * max_pad_bytes;
if (test_bits > bitpos) if (test_bits > bitpos)
test_bits = bitpos; test_bits = bitpos;
for (i = 0; i < test_bits; i++) { for (i = 0; i < test_bits; i++) {
int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1; int bit = (data_u32[endpos >> 5] >> (31 - (endpos & 0x1F))) & 1;
endpos--; endpos--; /* from last position towards valid data */
if (bit != 1) if (bit != 1)
break; break;
} }
/* so many 1s isn't very normal */
if (i == test_bits) if (i == test_bits)
return -8; return -8;
@ -1186,10 +1189,9 @@ int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples
/* Namco also sets number of codes/samples done from unpack_frame/rmlt (ptr arg), /* Namco also sets number of codes/samples done from unpack_frame/rmlt (ptr arg),
* but they seem unused */ * but they seem unused */
return 1;
fail:
//;printf("S14: fail %i\n", res);
return 0; return 0;
fail:
return res;
} }
#if 0 #if 0
@ -1271,7 +1273,7 @@ int g7221_set_key(g7221_handle* handle, const uint8_t* key) {
/* reset new key */ /* reset new key */
s14aes_set_key(handle->aes, temp_key); s14aes_set_key(handle->aes, temp_key);
return 1;
fail:
return 0; return 0;
fail:
return -1;
} }

View File

@ -12,7 +12,7 @@ typedef struct g7221_handle g7221_handle;
/* return a handle for decoding on successful init, NULL on failure */ /* return a handle for decoding on successful init, NULL on failure */
g7221_handle* g7221_init(int bytes_per_frame); g7221_handle* g7221_init(int bytes_per_frame);
/* decode a frame, at code_words, into 16-bit PCM in sample_buffer */ /* decode a frame, at code_words, into 16-bit PCM in sample_buffer. returns <0 on error */
int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples); int g7221_decode_frame(g7221_handle* handle, uint8_t* data, int16_t* out_samples);
#if 0 #if 0
@ -26,7 +26,7 @@ void g7221_reset(g7221_handle* handle);
/* free resources */ /* free resources */
void g7221_free(g7221_handle* handle); void g7221_free(g7221_handle* handle);
/* set new key (ignores key on failure) */ /* set new key (ignores key on failure). returns <0 on error */
int g7221_set_key(g7221_handle* handle, const uint8_t* key); int g7221_set_key(g7221_handle* handle, const uint8_t* key);
#endif #endif

View File

@ -21,7 +21,6 @@
static const char* extension_list[] = { static const char* extension_list[] = {
//"", /* vgmstream can play extensionless files too, but plugins must accept them manually */ //"", /* vgmstream can play extensionless files too, but plugins must accept them manually */
"04sw",
"208", "208",
"2dx9", "2dx9",
"2pfs", "2pfs",
@ -625,6 +624,7 @@ static const char* extension_list[] = {
"xma", "xma",
"xma2", "xma2",
"xmu", "xmu",
"xmv",
"xnb", "xnb",
"xsh", "xsh",
"xsf", "xsf",

View File

@ -3,11 +3,31 @@
#include "../util/endianness.h" #include "../util/endianness.h"
/* FWAV and CWAV are basically identical except always LE */ /* RWAV is a bit simpler, while FWAV and CWAV are basically identical except for endianness.
typedef enum { FWAV, CWAV } bxwav_type_t; * From SDK info, typically .xxxx is the original NintendoWare format (usually a .xml) and .bxxxx is a
* binary/external form (like .rseq=xml then .brseq=binary, or .wav > brwav). */
typedef enum { RWAV, FWAV, CWAV } bxwav_type_t;
static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type); static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type);
/* RWAV - NintendoWare binary Revolution wave (Wii games) */
VGMSTREAM* init_vgmstream_brwav(STREAMFILE* sf) {
/* checks */
if (!is_id32be(0x00, sf, "RWAV"))
goto fail;
/* .brwav: from tools (no games known)
* .rwav: header id */
if (!check_extensions(sf, "brwav,rwav"))
goto fail;
return init_vgmstream_bxwav(sf, RWAV);
fail:
return NULL;
}
/* FWAV - NintendoWare binary caFe wave (WiiU and Switch games) */ /* FWAV - NintendoWare binary caFe wave (WiiU and Switch games) */
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) {
@ -21,7 +41,6 @@ VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf) {
goto fail; goto fail;
return init_vgmstream_bxwav(sf, FWAV); return init_vgmstream_bxwav(sf, FWAV);
fail: fail:
return NULL; return NULL;
} }
@ -43,7 +62,6 @@ VGMSTREAM* init_vgmstream_bcwav(STREAMFILE* sf) {
goto fail; goto fail;
return init_vgmstream_bxwav(sf, CWAV); return init_vgmstream_bxwav(sf, CWAV);
fail: fail:
return NULL; return NULL;
} }
@ -52,7 +70,7 @@ fail:
static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) { static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
uint32_t info_offset, data_offset, chtb_offset; uint32_t info_offset, data_offset, chtb_offset, file_size;
int channels, loop_flag, codec, sample_rate; int channels, loop_flag, codec, sample_rate;
int big_endian; int big_endian;
int32_t num_samples, loop_start; int32_t num_samples, loop_start;
@ -63,7 +81,7 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
read_s16_t read_s16; read_s16_t read_s16;
/* BOM check */ /* BOM check */
if (read_u16be(0x04, sf) == 0xFEFF) { /* WiiU */ if (read_u16be(0x04, sf) == 0xFEFF) { /* Wii, WiiU */
big_endian = 1; big_endian = 1;
read_u32 = read_u32be; read_u32 = read_u32be;
read_s32 = read_s32be; read_s32 = read_s32be;
@ -82,41 +100,95 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
} }
/* header */ /* header */
/* 0x06(2): header size (0x40) */ switch(type) {
/* 0x08: version */ case RWAV:
/* - FWAV: 0x00010200 */ /* 0x06(2): version (usually 0102, 0103=Let's Tap, no diffs) */
/* - CWAV: 0x00000002 (Kirby's Adventure), 0x00000102 (common), 0x00010102 (FE Fates, Hyrule Warriors Legends) */ file_size = read_u32(0x08, sf);
/* 0x0c: file size */ /* 0x0c(2): header size (0x20) */
/* 0x10(2): sections (2) */ /* 0x0e(2): sections (2) */
/* 0x14(2): info mark (0x7000) */ info_offset = read_u32(0x10, sf);
info_offset = read_u32(0x18, sf); /* 0x14: info size */
/* 0x1c: info size */
/* 0x20(2): data mark (0x7001) */ data_offset = read_u32(0x18, sf);
data_offset = read_u32(0x24, sf); /* 0x1c: data size */
/* 0x28: data size */
/* rest: padding */
break;
case FWAV:
case CWAV:
/* 0x06(2): header size (0x40) */
/* 0x08: version */
/* - FWAV: 0x00010200 */
/* - CWAV: 0x00000002 (Kirby's Adventure), 0x00000102 (common), 0x00010102 (FE Fates, Hyrule Warriors Legends) */
file_size = read_u32(0x0c, sf);
/* 0x10(2): sections (2) */
/* 0x14(2): info mark (0x7000) */
info_offset = read_u32(0x18, sf);
/* 0x1c: info size */
/* 0x20(2): data mark (0x7001) */
data_offset = read_u32(0x24, sf);
/* 0x28: data size */
/* rest: padding */
break;
default:
goto fail;
}
if (file_size != get_streamfile_size(sf)) {
vgm_logi("BXWAV: wrong size %x vs %x\n", file_size, (uint32_t)get_streamfile_size(sf));
goto fail;
}
/* INFO section */ /* INFO section */
if (!is_id32be(info_offset + 0x00, sf, "INFO")) if (!is_id32be(info_offset + 0x00, sf, "INFO"))
goto fail; goto fail;
/* 0x04: size */ /* 0x04: size */
codec = read_u8(info_offset + 0x08, sf);
loop_flag = read_u8(info_offset + 0x09, sf); switch(type) {
/* 0x0a: padding */ case RWAV:
sample_rate = read_u32(info_offset + 0x0C, sf); codec = read_u8(info_offset + 0x08, sf);
loop_start = read_s32(info_offset + 0x10, sf); loop_flag = read_u8(info_offset + 0x09, sf);
num_samples = read_s32(info_offset + 0x14, sf); channels = read_u8(info_offset + 0x0a, sf);
/* 0x18: original loop start? (slightly lower) */ /* 0x0b: part of rate? */
chtb_offset = info_offset + 0x1C; sample_rate = read_u16(info_offset + 0x0c, sf);
channels = read_u32(chtb_offset + 0x00, sf); /* 0x0e(2): padding */
loop_start = read_s32(info_offset + 0x10, sf);
num_samples = read_s32(info_offset + 0x14, sf);
chtb_offset = read_u32(info_offset + 0x18, sf) + info_offset + 0x08;
/* 0x1c: channel table size */
loop_start = dsp_nibbles_to_samples(loop_start);
num_samples = dsp_nibbles_to_samples(num_samples);
break;
case FWAV:
case CWAV:
codec = read_u8(info_offset + 0x08, sf);
loop_flag = read_u8(info_offset + 0x09, sf);
/* 0x0a: padding */
sample_rate = read_u32(info_offset + 0x0C, sf);
loop_start = read_s32(info_offset + 0x10, sf);
num_samples = read_s32(info_offset + 0x14, sf);
/* 0x18: original loop start? (slightly lower) */
chtb_offset = info_offset + 0x1C;
channels = read_u32(chtb_offset + 0x00, sf);
break;
default:
goto fail;
}
/* channel table is parsed at the end */ /* channel table is parsed at the end */
/* DATA section */ /* DATA section */
if (!is_id32be(data_offset + 0x00, sf, "DATA")) if (!is_id32be(data_offset + 0x00, sf, "DATA"))
goto fail; goto fail;
/* 0x04: size */
/* build the VGMSTREAM */ /* build the VGMSTREAM */
@ -124,6 +196,7 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
switch(type) { switch(type) {
case RWAV: vgmstream->meta_type = meta_RWAV; break;
case FWAV: vgmstream->meta_type = meta_FWAV; break; case FWAV: vgmstream->meta_type = meta_FWAV; break;
case CWAV: vgmstream->meta_type = meta_CWAV; break; case CWAV: vgmstream->meta_type = meta_CWAV; break;
default: goto fail; default: goto fail;
@ -138,7 +211,7 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
/* only 0x02 is known, other codecs are probably from bxstm that do use them */ /* only 0x02 is known, others can be made with SDK tools */
switch (codec) { switch (codec) {
case 0x00: case 0x00:
vgmstream->coding_type = coding_PCM8; vgmstream->coding_type = coding_PCM8;
@ -171,25 +244,51 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
{ {
int ch, i; int ch, i;
for (ch = 0; ch < channels; ch++) { for (ch = 0; ch < channels; ch++) {
uint32_t chnf_offset, chdt_offset; uint32_t chnf_offset, chdt_offset, coef_offset;
/* channel entry: */ switch(type) {
/* - 0x00: mark (0x7100) */ case RWAV:
/* - 0x02: padding */ /* channel entry: */
/* - 0x04: channel info offset (from channel table offset) */ /* - 0x04: channel info offset (from INFO offset after size) */
chnf_offset = read_u32(chtb_offset + 0x04 + ch * 0x08 + 0x04, sf) + chtb_offset;
/* channel info: */ chnf_offset = read_u32(chtb_offset + ch * 0x04 + 0x00, sf) + info_offset + 0x08;
/* 0x00: mark (0x1F00) */
/* 0x02: padding */
/* 0x04: offset to channel data (from DATA offset after size ) */
/* 0x08: ADPCM mark (0x0300=DSP, 0x0301=IMA, 0x0000=none) */
/* 0x0a: padding */
/* 0x0c: ADPCM offset (from channel info offset), 0xFFFFFFFF otherwise */
/* 0x10: null? */
if (read_u16(chnf_offset + 0x00, sf) != 0x1F00) /* channel info: */
goto fail; /* 0x00: offset to channel data (from DATA offset after size) */
chdt_offset = read_u32(chnf_offset + 0x04, sf) + data_offset + 0x08; /* 0x04: ADPCM offset (from INFO offset after size), 0xFFFFFFFF otherwise? */
/* 0x08: volumes x4? */
/* 0x18: padding */
chdt_offset = read_u32(chnf_offset + 0x00, sf) + data_offset + 0x08;
coef_offset = read_u32(chnf_offset + 0x04, sf) + info_offset + 0x08;
break;
case FWAV:
case CWAV:
/* channel entry: */
/* - 0x00: mark (0x7100) */
/* - 0x02: padding */
/* - 0x04: channel info offset (from channel table offset) */
chnf_offset = read_u32(chtb_offset + 0x04 + ch * 0x08 + 0x04, sf) + chtb_offset;
/* channel info: */
/* 0x00: mark (0x1F00) */
/* 0x02: padding */
/* 0x04: offset to channel data (from DATA offset after size) */
/* 0x08: ADPCM mark (0x0300=DSP, 0x0301=IMA, 0x0000=none) */
/* 0x0a: padding */
/* 0x0c: ADPCM offset (from channel info offset), 0xFFFFFFFF otherwise */
/* 0x10: padding */
if (read_u16(chnf_offset + 0x00, sf) != 0x1F00)
goto fail;
chdt_offset = read_u32(chnf_offset + 0x04, sf) + data_offset + 0x08;
coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset;
break;
default:
goto fail;
}
vgmstream->ch[ch].channel_start_offset = chdt_offset; vgmstream->ch[ch].channel_start_offset = chdt_offset;
vgmstream->ch[ch].offset = chdt_offset; vgmstream->ch[ch].offset = chdt_offset;
@ -197,20 +296,16 @@ static VGMSTREAM* init_vgmstream_bxwav(STREAMFILE* sf, bxwav_type_t type) {
switch(codec) { switch(codec) {
case 0x02: { case 0x02: {
/* standard DSP coef + predictor + hists + loop predictor + loop hists */ /* standard DSP coef + predictor + hists + loop predictor + loop hists */
uint32_t coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset;
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
vgmstream->ch[ch].adpcm_coef[i] = read_s16(coef_offset + 0x00 + i*0x02, sf); vgmstream->ch[ch].adpcm_coef[i] = read_s16(coef_offset + 0x00 + i*0x02, sf);
} }
vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x22, sf); //vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x22, sf);
vgmstream->ch[ch].adpcm_history2_16 = read_s16(coef_offset + 0x24, sf); //vgmstream->ch[ch].adpcm_history2_16 = read_s16(coef_offset + 0x24, sf);
break; break;
} }
case 0x03: { case 0x03: {
/* hist + step */ /* hist + step */
uint32_t coef_offset = read_u32(chnf_offset + 0x0c, sf) + chnf_offset;
vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x00, sf); vgmstream->ch[ch].adpcm_history1_16 = read_s16(coef_offset + 0x00, sf);
vgmstream->ch[ch].adpcm_step_index = read_s16(coef_offset + 0x02, sf); vgmstream->ch[ch].adpcm_step_index = read_s16(coef_offset + 0x02, sf);
break; break;
@ -228,3 +323,73 @@ fail:
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;
} }
/* ************************************************************************* */
/* RWAR - NintendoWare container [BIT.TRIP BEAT (Wii), Dance Dance Revolution Hottest Party 2 (Wii)] */
VGMSTREAM* init_vgmstream_brwar(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL;
STREAMFILE* temp_sf = NULL;
uint32_t tabl_offset, data_offset;
uint32_t subfile_offset, subfile_size;
int total_subsongs, target_subsong = sf->stream_index;
/* checks */
if (!is_id32be(0x00, sf, "RWAR"))
goto fail;
if (!check_extensions(sf,"rwar"))
goto fail;
/* simple container of .rwavs (inside .brsar), rarely used with single siles (DDR) */
/* abridged, see RWAV (same header) */
/* 0x04(2): BOM */
/* 0x06(2): version (usually 0100) */
/* 0x08: file size */
/* 0x0c(2): header size (0x20) */
/* 0x0e(2): sections (2) */
tabl_offset = read_u32be(0x10, sf);
/* 0x14: tabl size */
data_offset = read_u32be(0x18, sf);
/* 0x1c: data size */
/* TABL section */
if (!is_id32be(tabl_offset + 0x00, sf, "TABL"))
goto fail;
/* 0x04: size */
total_subsongs = read_u32be(tabl_offset + 0x08,sf);
if (target_subsong == 0) target_subsong = 1;
if (target_subsong < 0 || target_subsong > total_subsongs || total_subsongs < 1) goto fail;
/* 0x00: always 0x01000000? */
subfile_offset = read_u32be(tabl_offset + 0x0c + (target_subsong-1) * 0x0c + 0x04,sf) + data_offset;
subfile_size = read_u32be(tabl_offset + 0x0c + (target_subsong-1) * 0x0c + 0x08,sf);
/* DATA section */
if (!is_id32be(data_offset + 0x00, sf, "DATA"))
goto fail;
/* 0x04: size */
//VGM_LOG("BRWAR: of=%x, sz=%x\n", subfile_offset, subfile_size);
temp_sf = setup_subfile_streamfile(sf, subfile_offset, subfile_size, "rwav");
if (!temp_sf) goto fail;
vgmstream = init_vgmstream_brwav(temp_sf);
if (!vgmstream) goto fail;
vgmstream->num_streams = total_subsongs;
close_streamfile(temp_sf);
return vgmstream;
fail:
close_streamfile(temp_sf);
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -12,14 +12,15 @@ VGMSTREAM* init_vgmstream_bik(STREAMFILE* sf) {
size_t stream_size; size_t stream_size;
/* checks */ /* checks */
/* .bik/bik2/bk2: standard /* bink1/2 header, followed by version-char (audio is the same) */
* .bika: fake extension for demuxed audio */ if ((read_u32be(0x00,sf) & 0xffffff00) != get_id32be("BIK\0") &&
if (!check_extensions(sf,"bik,bik2,bk2,bika")) (read_u32be(0x00,sf) & 0xffffff00) != get_id32be("KB2\0"))
goto fail; goto fail;
/* check bink1/2 header, followed by version-char (audio is the same) */ /* .bik/bik2/bk2: standard
if ((read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("BIK\0") && * .xmv: Reflections games [Driver: Parallel Lines (Wii), Emergency Heroes (Wii)]
(read_32bitBE(0x00,sf) & 0xffffff00) != get_id32be("KB2\0")) * .bika: fake extension for demuxed audio */
if (!check_extensions(sf,"bik,bik2,bk2,xmv,bika"))
goto fail; goto fail;
/* find target stream info and samples */ /* find target stream info and samples */

View File

@ -234,7 +234,7 @@ static void bruteforce_bnsf_key(STREAMFILE* sf, off_t start, g7221_codec_data* d
} }
} }
//done: done:
VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score); VGM_ASSERT(best_score > 0, "BNSF: best key=%.24s (score=%i)\n", best_key, best_score);
VGM_ASSERT(best_score < 0, "BNSF: key not found\n"); VGM_ASSERT(best_score < 0, "BNSF: key not found\n");

View File

@ -564,8 +564,10 @@ VGMSTREAM * init_vgmstream_bcstm(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_bfstm(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_bfstm(STREAMFILE* streamFile);
VGMSTREAM* init_vgmstream_brwav(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf); VGMSTREAM* init_vgmstream_bfwav(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_bcwav(STREAMFILE* sf); VGMSTREAM* init_vgmstream_bcwav(STREAMFILE* sf);
VGMSTREAM* init_vgmstream_brwar(STREAMFILE* sf);
VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_kt_g1l(STREAMFILE* streamFile);
VGMSTREAM * init_vgmstream_kt_wiibgm(STREAMFILE* streamFile); VGMSTREAM * init_vgmstream_kt_wiibgm(STREAMFILE* streamFile);

View File

@ -1393,10 +1393,8 @@ VGMSTREAM* init_vgmstream_dsp_wiiadpcm(STREAMFILE* sf) {
dspm.header_spacing = dspm.interleave; dspm.header_spacing = dspm.interleave;
dspm.start_offset = dspm.header_offset + 0x60; dspm.start_offset = dspm.header_offset + 0x60;
//
VGM_LOG("%lx, %x\n", dspm.header_offset, dspm.interleave);
VGM_LOG("%x, %x\n", dspm.interleave_first_skip, dspm.interleave_first);
dspm.meta_type = meta_DSP_WIIADPCM; dspm.meta_type = meta_DSP_WIIADPCM;
return init_vgmstream_dsp_common(sf, &dspm); return init_vgmstream_dsp_common(sf, &dspm);
fail: fail:

View File

@ -2,177 +2,64 @@
#include "../coding/coding.h" #include "../coding/coding.h"
#include "../util.h" #include "../util.h"
/* Wii RWAV */
typedef struct {
// in
off_t offset;
STREAMFILE *sf;
int32_t (*read_32bit)(off_t,STREAMFILE*);
// out
int version;
off_t start_offset;
off_t info_chunk;
off_t wave_offset;
} rwav_data_t;
static void read_rwav(rwav_data_t* rd) {
off_t chunk_table_offset;
off_t chunk_table_step;
off_t info_chunk;
off_t data_chunk;
if (!is_id32be(rd->offset, rd->sf, "RWAV"))
return;
/* big endian, version 2 */
if (read_u32be(rd->offset+4,rd->sf) != 0xFEFF0102)
return;
chunk_table_offset = rd->offset + 0x10;
chunk_table_step = 0x08;
info_chunk = rd->offset + rd->read_32bit(chunk_table_offset, rd->sf);
if (!is_id32be(info_chunk, rd->sf, "INFO"))
return;
data_chunk = rd->offset + rd->read_32bit(chunk_table_offset + chunk_table_step, rd->sf);
if (!is_id32be(data_chunk, rd->sf, "DATA"))
return;
rd->start_offset = data_chunk + 0x08;
rd->info_chunk = info_chunk + 0x08;
rd->version = 2;
rd->wave_offset = info_chunk - 0x08; /* pretend to have a WAVE */
return;
}
static void read_rwar(rwav_data_t* rd) {
if (!is_id32be(rd->offset, rd->sf, "RWAR"))
return;
if (read_u32be(rd->offset + 0x04, rd->sf) != 0xFEFF0100) /* version 0 */
return;
rd->offset += 0x60;
read_rwav(rd);
rd->version = 0;
return;
}
/* RWSD is quite similar to BRSTM, but can contain several streams. /* RWSD is quite similar to BRSTM, but can contain several streams.
* Still, some games use it for single streams. We only support the * Still, some games use it for single streams. We only support the single stream form here */
* single stream form here */ //TODO this meta is a hack as WSD is just note info, and data offsets are elsewhere,
// while this assumes whatever data follows RWSD must belong to it; rework for Wii Sports
VGMSTREAM* init_vgmstream_rwsd(STREAMFILE* sf) { VGMSTREAM* init_vgmstream_rwsd(STREAMFILE* sf) {
VGMSTREAM* vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
char filename[PATH_LIMIT];
size_t wave_length; size_t wave_length;
int codec; int codec, channels, loop_flag;
int channels;
int loop_flag;
int rwar = 0;
int rwav = 0;
rwav_data_t rwav_data;
size_t stream_size; size_t stream_size;
off_t start_offset, wave_offset = 0;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
rwav_data.version = -1; if (!is_id32be(0x00, sf, "RWSD"))
rwav_data.start_offset = 0;
rwav_data.info_chunk = -1;
rwav_data.wave_offset = -1;
/* check extension, case insensitive */
sf->get_name(sf,filename,sizeof(filename));
if (check_extensions(sf, "rwsd")) {
;
}
else if (check_extensions(sf, "rwar")) {
rwar = 1;
}
else if (check_extensions(sf, "rwav")) {
rwav = 1;
}
else {
goto fail; goto fail;
}
read_16bit = read_16bitBE;
read_32bit = read_32bitBE;
if (!check_extensions(sf, "rwsd"))
goto fail;
/* check header */ /* check header */
if (rwar || rwav) { switch (read_u32be(0x04, sf)) {
rwav_data.offset = 0; case 0xFEFF0102:
rwav_data.sf = sf; /* ideally we would look through the chunk list for a WAVE chunk,
rwav_data.read_32bit = read_32bit; * but it's always in the same order */
if (rwar) read_rwar(&rwav_data); /* get WAVE offset, check */
if (rwav) read_rwav(&rwav_data); wave_offset = read_32bitBE(0x18,sf);
if (rwav_data.wave_offset < 0) goto fail; if (!is_id32be(wave_offset + 0x00, sf, "WAVE"))
}
else {
if (!is_id32be(0x00, sf, "RWSD"))
goto fail;
switch (read_u32be(0x04, sf)) {
case 0xFEFF0102:
/* ideally we would look through the chunk list for a WAVE chunk,
* but it's always in the same order */
/* get WAVE offset, check */
rwav_data.wave_offset = read_32bit(0x18,sf);
if (!is_id32be(rwav_data.wave_offset + 0x00, sf, "WAVE"))
goto fail;
/* get WAVE size, check */
wave_length = read_32bit(0x1c,sf);
if (read_32bit(rwav_data.wave_offset + 0x04,sf) != wave_length)
goto fail;
/* check wave count */
if (read_32bit(rwav_data.wave_offset + 0x08,sf) != 1)
goto fail; /* only support 1 */
rwav_data.version = 2;
break;
case 0xFEFF0103:
rwav_data.offset = 0xe0;
rwav_data.sf = sf;
rwav_data.read_32bit = read_32bit;
read_rwar(&rwav_data);
if (rwav_data.wave_offset < 0) goto fail;
rwar = 1;
break;
default:
goto fail; goto fail;
}
/* get WAVE size, check */
wave_length = read_32bitBE(0x1c,sf);
if (read_32bitBE(wave_offset + 0x04,sf) != wave_length)
goto fail;
/* check wave count */
if (read_32bitBE(wave_offset + 0x08,sf) != 1)
goto fail; /* only support 1 */
break;
case 0xFEFF0103: /* followed by RWAR, extract that or use .txth subfile */
goto fail;
} }
/* get type details */ /* get type details */
codec = read_u8(rwav_data.wave_offset+0x10,sf); codec = read_u8(wave_offset+0x10,sf);
loop_flag = read_u8(rwav_data.wave_offset+0x11,sf); loop_flag = read_u8(wave_offset+0x11,sf);
channels = read_u8(rwav_data.wave_offset+0x12,sf); channels = read_u8(wave_offset+0x12,sf);
/* build the VGMSTREAM */ /* build the VGMSTREAM */
vgmstream = allocate_vgmstream(channels,loop_flag); vgmstream = allocate_vgmstream(channels, loop_flag);
if (!vgmstream) goto fail; if (!vgmstream) goto fail;
vgmstream->num_samples = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x1c,sf)); vgmstream->num_samples = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x1c,sf));
vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bit(rwav_data.wave_offset+0x18,sf)); vgmstream->loop_start_sample = dsp_nibbles_to_samples(read_32bitBE(wave_offset+0x18,sf));
vgmstream->sample_rate = (uint16_t)read_16bit(rwav_data.wave_offset + 0x14,sf); vgmstream->sample_rate = (uint16_t)read_16bitBE(wave_offset + 0x14,sf);
vgmstream->loop_end_sample = vgmstream->num_samples; vgmstream->loop_end_sample = vgmstream->num_samples;
switch (codec) { switch (codec) {
@ -190,84 +77,48 @@ VGMSTREAM* init_vgmstream_rwsd(STREAMFILE* sf) {
} }
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
vgmstream->meta_type = meta_RWSD;
if (rwar) {
vgmstream->meta_type = meta_RWAR;
}
else if (rwav) {
vgmstream->meta_type = meta_RWAV;
}
else {
vgmstream->meta_type = meta_RWSD;
}
{ {
off_t data_start_offset;
off_t codec_info_offset; off_t codec_info_offset;
int i, j; int i, j;
for (j = 0 ; j < vgmstream->channels; j++) { for (j = 0 ; j < vgmstream->channels; j++) {
if (rwar || rwav) { // dummy for RWSD, must be a proper way to work this out
/* This is pretty nasty, so an explaination is in order. codec_info_offset = wave_offset + 0x6c + j*0x30;
* At 0x10 in the info_chunk is the offset of a table with
* one entry per channel. Each entry in this table is itself
* an offset to a set of information for the channel. The
* first element in the set is the offset into DATA of the channel.
* The second element is the offset of the codec-specific setup for the channel. */
off_t channel_info_offset = rwav_data.info_chunk +
read_32bit(rwav_data.info_chunk +
read_32bit(rwav_data.info_chunk + 0x10,sf) + j*0x04, sf);
data_start_offset = rwav_data.start_offset +
read_32bit(channel_info_offset + 0x00, sf);
codec_info_offset = rwav_data.info_chunk +
read_32bit(channel_info_offset + 0x04, sf);
vgmstream->ch[j].channel_start_offset =
vgmstream->ch[j].offset = data_start_offset;
} else {
// dummy for RWSD, must be a proper way to work this out
codec_info_offset = rwav_data.wave_offset + 0x6c + j*0x30;
}
if (vgmstream->coding_type == coding_NGC_DSP) { if (vgmstream->coding_type == coding_NGC_DSP) {
for (i = 0; i < 16; i++) { for (i = 0; i < 16; i++) {
vgmstream->ch[j].adpcm_coef[i] = read_16bit(codec_info_offset + i*0x2, sf); vgmstream->ch[j].adpcm_coef[i] = read_16bitBE(codec_info_offset + i*0x2, sf);
} }
} }
} }
} }
if (rwar || rwav) {
/* */ /* this is just data size and following data may or may not be from this RWSD */
} start_offset = read_32bitBE(0x08, sf);
else {
if (rwav_data.version == 2)
rwav_data.start_offset = read_32bit(0x08, sf);
}
stream_size = read_32bit(rwav_data.wave_offset + 0x50,sf); stream_size = read_32bitBE(wave_offset + 0x50,sf);
/* open the file for reading by each channel */ /* open the file for reading by each channel */
{ {
int i; int i;
for (i=0;i<channels;i++) { char filename[PATH_LIMIT];
sf->get_name(sf,filename,sizeof(filename));
for (i = 0; i < channels; i++) {
vgmstream->ch[i].streamfile = sf->open(sf,filename,STREAMFILE_DEFAULT_BUFFER_SIZE); vgmstream->ch[i].streamfile = sf->open(sf,filename,STREAMFILE_DEFAULT_BUFFER_SIZE);
if (!vgmstream->ch[i].streamfile) goto fail; if (!vgmstream->ch[i].streamfile) goto fail;
if (!(rwar || rwav)) { vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset =
vgmstream->ch[i].channel_start_offset= start_offset + i*stream_size;
vgmstream->ch[i].offset=
rwav_data.start_offset + i*stream_size;
}
} }
} }
return vgmstream; return vgmstream;
fail: fail:
close_vgmstream(vgmstream); close_vgmstream(vgmstream);
return NULL; return NULL;

View File

@ -1205,12 +1205,9 @@ static int parse_keyval(STREAMFILE* sf_, txth_header* txth, const char* key, cha
else if (is_string(key,"coef_offset")) { else if (is_string(key,"coef_offset")) {
if (!parse_num(txth->sf_head,txth,val, &txth->coef_offset)) goto fail; if (!parse_num(txth->sf_head,txth,val, &txth->coef_offset)) goto fail;
/* special adjustments */ /* special adjustments */
VGM_LOG("coef norm=%x\n",txth->coef_offset );
txth->coef_offset += txth->base_offset; txth->coef_offset += txth->base_offset;
VGM_LOG("coef+base=%x\n",txth->coef_offset );
if (txth->subsong_spacing && !txth->is_offset_absolute) if (txth->subsong_spacing && !txth->is_offset_absolute)
txth->coef_offset += txth->subsong_spacing * (txth->target_subsong - 1); txth->coef_offset += txth->subsong_spacing * (txth->target_subsong - 1);
VGM_LOG("coef+spac=%x\n",txth->coef_offset );
} }
else if (is_string(key,"coef_spacing")) { else if (is_string(key,"coef_spacing")) {
if (!parse_num(txth->sf_head,txth,val, &txth->coef_spacing)) goto fail; if (!parse_num(txth->sf_head,txth,val, &txth->coef_spacing)) goto fail;

View File

@ -3,6 +3,8 @@
#include "../coding/coding.h" #include "../coding/coding.h"
#include "ubi_bao_streamfile.h" #include "ubi_bao_streamfile.h"
#define BAO_MIN_VERSION 0x1B
#define BAO_MAX_VERSION 0x2A
#define BAO_MAX_LAYER_COUNT 16 /* arbitrary max */ #define BAO_MAX_LAYER_COUNT 16 /* arbitrary max */
#define BAO_MAX_CHAIN_COUNT 128 /* POP:TFS goes up to ~100 */ #define BAO_MAX_CHAIN_COUNT 128 /* POP:TFS goes up to ~100 */
@ -145,6 +147,11 @@ VGMSTREAM* init_vgmstream_ubi_bao_pk(STREAMFILE* sf) {
ubi_bao_header bao = { 0 }; ubi_bao_header bao = { 0 };
/* checks */ /* checks */
if (read_u8(0x00, sf) != 0x01)
goto fail;
if (read_u8(0x01, sf) < BAO_MIN_VERSION || read_u8(0x01, sf) > BAO_MAX_VERSION)
goto fail;
if (!check_extensions(sf, "pk,lpk,cpk")) if (!check_extensions(sf, "pk,lpk,cpk"))
goto fail; goto fail;
@ -167,6 +174,11 @@ VGMSTREAM* init_vgmstream_ubi_bao_atomic(STREAMFILE* sf) {
STREAMFILE* streamData = NULL; STREAMFILE* streamData = NULL;
/* checks */ /* checks */
if (read_u8(0x00, sf) != 0x01 && read_u8(0x00, sf) != 0x02) /* 0x01=AC1, 0x02=POP2008 */
goto fail;
if (read_u8(0x01, sf) < BAO_MIN_VERSION || read_u8(0x01, sf) > BAO_MAX_VERSION)
goto fail;
if (!check_extensions(sf, "bao,")) if (!check_extensions(sf, "bao,"))
goto fail; goto fail;
@ -174,13 +186,9 @@ VGMSTREAM* init_vgmstream_ubi_bao_atomic(STREAMFILE* sf) {
* since BAOs reference each other by id and are named by it (though the internal BAO id may * since BAOs reference each other by id and are named by it (though the internal BAO id may
* be other) we can simulate it. Extension is .bao/sbao or extensionaless in some games. */ * be other) we can simulate it. Extension is .bao/sbao or extensionaless in some games. */
/* format: 0x01=AC1, 0x02=POP2008 */
if (read_8bit(0x00, sf) != 0x01 && read_8bit(0x00, sf) != 0x02)
goto fail;
bao.is_atomic = 1; bao.is_atomic = 1;
bao.version = read_32bitBE(0x00, sf) & 0x00FFFFFF; bao.version = read_u32be(0x00, sf) & 0x00FFFFFF;
if (!config_bao_version(&bao, sf)) if (!config_bao_version(&bao, sf))
goto fail; goto fail;
@ -644,7 +652,7 @@ static VGMSTREAM* init_vgmstream_ubi_bao_header(ubi_bao_header* bao, STREAMFILE*
(uint32_t)bao->header_offset, bao->header_id, bao->stream_id, bao->prefetch_id); (uint32_t)bao->header_offset, bao->header_id, bao->stream_id, bao->prefetch_id);
;VGM_LOG("UBI BAO: stream=%x, size=%x, res=%s\n", ;VGM_LOG("UBI BAO: stream=%x, size=%x, res=%s\n",
(uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal")); (uint32_t)bao->stream_offset, bao->stream_size, (bao->is_external ? bao->resource_name : "internal"));
;VGM_LOG("UBI BAO: type=%i, header=%x, extra=%x, prefetch=%x, size=%x\n", ;VGM_LOG("UBI BAO: type=%i, header=%x, extra=%x, pre.of=%x, pre.sz=%x\n",
bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size); bao->header_type, bao->header_size, bao->extra_size, (uint32_t)bao->prefetch_offset, bao->prefetch_size);
@ -703,8 +711,8 @@ static int parse_pk(ubi_bao_header* bao, STREAMFILE* sf) {
if (target_subsong <= 0) target_subsong = 1; if (target_subsong <= 0) target_subsong = 1;
bao->version = read_32bitBE(0x00, sf) & 0x00FFFFFF; bao->version = read_u32be(0x00, sf) & 0x00FFFFFF;
index_size = read_32bitLE(0x04, sf); /* can be 0, not including */ index_size = read_u32le(0x04, sf); /* can be 0, not including */
/* 0x08: resource table offset, always found even if not used */ /* 0x08: resource table offset, always found even if not used */
/* 0x0c: always 0? */ /* 0x0c: always 0? */
/* 0x10: unknown, null if no entries */ /* 0x10: unknown, null if no entries */
@ -1125,11 +1133,12 @@ static int parse_offsets(ubi_bao_header* bao, STREAMFILE* sf) {
read_string(bao->resource_name,255, resources_offset + 0x04+0x04 + name_offset, sf); read_string(bao->resource_name,255, resources_offset + 0x04+0x04 + name_offset, sf);
if (bao->stream_size != resource_size - bao->stream_skip + bao->prefetch_size) { if (bao->stream_size != resource_size - bao->stream_skip + bao->prefetch_size) {
VGM_LOG("UBI BAO: stream vs resource size mismatch at %lx (%x vs %x, %x, %x)\n", offset+0x10*i, bao->stream_size, resource_size, bao->stream_skip, bao->prefetch_size); VGM_LOG("UBI BAO: stream vs resource size mismatch at %lx (res %x vs str=%x, skip=%x, pre=%x)\n", offset+0x10*i, resource_size, bao->stream_size, bao->stream_skip, bao->prefetch_size);
/* rarely resource has more data than stream (sometimes a few bytes, others +0x100000) /* rarely resource has more data than stream (sometimes a few bytes, others +0x100000)
* sometimes short song versions, but not accessed? no samples/sizes/cues/etc in header seem to refer to that [Just Dance (Wii)] */ * sometimes short song versions, but not accessed? no samples/sizes/cues/etc in header seem to refer to that [Just Dance (Wii)]
if (!bao->cfg.audio_ignore_resource_size || bao->prefetch_size) * Michael Jackson the experiende also uses prefetch size + bad size (ignored) */
if (!bao->cfg.audio_ignore_resource_size && bao->prefetch_size)
goto fail; goto fail;
} }
break; break;
@ -1855,6 +1864,22 @@ static int config_bao_version(ubi_bao_header* bao, STREAMFILE* sf) {
bao->cfg.file_type = UBI_FORGE_b; bao->cfg.file_type = UBI_FORGE_b;
return 1; return 1;
case 0x00260000: /* <michael Jackson: The Experience (X360)-package */
config_bao_entry(bao, 0xB8, 0x28);
config_bao_audio_b(bao, 0x08, 0x28, 0x30, 0x3c, 1, 1); //loop?
config_bao_audio_m(bao, 0x4c, 0x54, 0x5c, 0x64, 0x6c, 0x7c);
config_bao_layer_m(bao, 0x00, 0x2c, 0x34, 0x4c, 0x54, 0x58, 0x00, 0x00, 1);
config_bao_layer_e(bao, 0x34, 0x00, 0x04, 0x08, 0x1c);
bao->cfg.codec_map[0x03] = FMT_OGG;
bao->cfg.codec_map[0x04] = RAW_XMA2_NEW;
bao->cfg.audio_ignore_resource_size = 1; /* leave_me_alone.pk */
return 1;
case 0x00270102: /* Drawsome (Wii)-package */ case 0x00270102: /* Drawsome (Wii)-package */
config_bao_entry(bao, 0xAC, 0x28); config_bao_entry(bao, 0xAC, 0x28);

View File

@ -410,10 +410,21 @@ VGMSTREAM* init_vgmstream_wwise_bnk(STREAMFILE* sf, int* p_prefetch) {
vgmstream->coding_type = coding_FFmpeg; vgmstream->coding_type = coding_FFmpeg;
vgmstream->layout_type = layout_none; vgmstream->layout_type = layout_none;
//if (ww.prefetch) {
// ww.data_size = ww.file_size - ww.data_offset;
//}
/* seek table seems BE dpds */ /* seek table seems BE dpds */
vgmstream->num_samples = xwma_dpds_get_samples(sf, ww.seek_offset, ww.seek_size, ww.channels, ww.big_endian); vgmstream->num_samples = xwma_dpds_get_samples(sf, ww.seek_offset, ww.seek_size, ww.channels, ww.big_endian);
if (!vgmstream->num_samples) if (!vgmstream->num_samples)
vgmstream->num_samples = xwma_get_samples(sf, ww.data_offset, ww.data_size, ww.format, ww.channels, ww.sample_rate, ww.block_size); vgmstream->num_samples = xwma_get_samples(sf, ww.data_offset, ww.data_size, ww.format, ww.channels, ww.sample_rate, ww.block_size);
/* XWMA is VBR so this is very approximate percent, meh */
if (ww.prefetch) { /* Guardians of Middle Earth (X360) */
vgmstream->num_samples = (int32_t)(vgmstream->num_samples *
(double)(ww.file_size - start_offset) / (double)ww.data_size);
}
break; break;
} }
@ -921,7 +932,7 @@ static int parse_wwise(STREAMFILE* sf, wwise_header* ww) {
} }
if (ww->codec == PCM || ww->codec == IMA || ww->codec == VORBIS || ww->codec == DSP || ww->codec == XMA2 || if (ww->codec == PCM || ww->codec == IMA || ww->codec == VORBIS || ww->codec == DSP || ww->codec == XMA2 ||
ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM) { ww->codec == OPUSNX || ww->codec == OPUS || ww->codec == OPUSWW || ww->codec == PTADPCM || ww->codec == XWMA) {
ww->prefetch = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */ ww->prefetch = 1; /* only seen those, probably all exist (XWMA, AAC, HEVAG, ATRAC9?) */
} else { } else {
vgm_logi("WWISE: wrong expected size, maybe prefetch (report)\n"); vgm_logi("WWISE: wrong expected size, maybe prefetch (report)\n");

View File

@ -1,58 +1,64 @@
#include "meta.h" #include "meta.h"
#include "../coding/coding.h" #include "../coding/coding.h"
/* 04SW - found in Driver: Parallel Lines (Wii) */ /* 04SW - Reflections games [Driver: Parallel Lines (Wii), Emergency Heroes (Wii)] */
VGMSTREAM * init_vgmstream_xa_04sw(STREAMFILE *streamFile) { VGMSTREAM* init_vgmstream_xa_04sw(STREAMFILE* sf) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM* vgmstream = NULL;
off_t start_offset; off_t start_offset;
int loop_flag, channel_count; int loop_flag, channels, sample_rate;
size_t file_size, data_size; int32_t num_samples;
uint32_t data_size;
/* checks */
/* ".04sw" is just the ID, the real filename inside the file uses .XA */ /* checks */
if (!check_extensions(streamFile,"xa,04sw")) if (!is_id32be(0x00,sf, "04SW"))
goto fail; goto fail;
if (read_32bitBE(0x00,streamFile) != 0x30345357) /* "04SW" */
goto fail; if (!check_extensions(sf,"xa"))
goto fail;
/* after the ID goes a semi-standard DSP header */
if (read_32bitBE(0x10,streamFile) != 0) goto fail; /* should be non looping */ /* after the ID goes a modified DSP header x2 */
loop_flag = 0; if (read_u32be(0x04 + 0x0c,sf) != 0) /* should be non looping */
/* not in header it seems so just dual header check */ goto fail;
channel_count = (read_32bitBE(0x04,streamFile) == read_32bitBE(0x64,streamFile)) ? 2 : 1; loop_flag = 0;
/* not in header it seems, so just dual header check */
start_offset = read_32bitBE(0x04 + 0x60*channel_count,streamFile);
num_samples = read_s32be(0x04 + 0x00,sf);
file_size = get_streamfile_size(streamFile); data_size = read_u32be(0x04 + 0x04,sf);
data_size = read_32bitBE(0x04 + 0x60*channel_count + 0x04,streamFile); sample_rate = read_u32be(0x0c,sf);
if (data_size+start_offset != file_size) goto fail;
channels = (read_u32be(0x04 + 0x00,sf) == read_u32be(0x04 + 0x60,sf)) ? 2 : 1; /* some voice .xa */
/* build the VGMSTREAM */ /* After DSP header goes a base header with mostly unknown values (several repeats) and the filename.
vgmstream = allocate_vgmstream(channel_count,loop_flag); * Emergency Heroes has extra 0x10 at 0x10. */
if (!vgmstream) goto fail; start_offset = read_u32be(0x04 + 0x60 * 2 + 0x00, sf);
/* 0x04: data size (includes padding after DSP data in Driver, doesn't in Emergency Heroes */
vgmstream->sample_rate = read_32bitBE(0x0c,streamFile); /* 0x1c/2c: channels LE? */
vgmstream->num_samples = read_32bitBE(0x04,streamFile); /* 0x74/84: utf-16 path+filename */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = channel_count == 1 ? layout_none : layout_interleave; /* build the VGMSTREAM */
vgmstream->interleave_block_size = 0x8000; vgmstream = allocate_vgmstream(channels, loop_flag);
vgmstream->interleave_last_block_size = (read_32bitBE(0x08,streamFile) / 2 % vgmstream->interleave_block_size + 7) / 8 * 8; if (!vgmstream) goto fail;
dsp_read_coefs_be(vgmstream,streamFile,0x20, 0x60); vgmstream->sample_rate = sample_rate;
/* the initial history offset seems different thatn standard DSP and possibly always zero */ vgmstream->num_samples = num_samples;
vgmstream->meta_type = meta_XA_04SW; vgmstream->coding_type = coding_NGC_DSP;
/* the rest of the header has unknown values (several repeats) and the filename */ vgmstream->layout_type = channels == 1 ? layout_none : layout_interleave;
vgmstream->interleave_block_size = 0x8000;
vgmstream->interleave_last_block_size = (data_size / 2 % vgmstream->interleave_block_size + 7) / 8 * 8;
if (!vgmstream_open_stream(vgmstream,streamFile,start_offset))
goto fail; dsp_read_coefs_be(vgmstream, sf, 0x04 + 0x1c, 0x60);
return vgmstream; /* initial history offset seems different than standard DSP and possibly fixed/invalid */
fail: vgmstream->meta_type = meta_XA_04SW;
close_vgmstream(vgmstream);
return NULL;
} if (!vgmstream_open_stream(vgmstream, sf, start_offset))
goto fail;
return vgmstream;
fail:
close_vgmstream(vgmstream);
return NULL;
}

View File

@ -20,8 +20,10 @@ static void try_dual_file_stereo(VGMSTREAM* opened_vgmstream, STREAMFILE* sf, VG
VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = { VGMSTREAM* (*init_vgmstream_functions[])(STREAMFILE* sf) = {
init_vgmstream_adx, init_vgmstream_adx,
init_vgmstream_brstm, init_vgmstream_brstm,
init_vgmstream_brwav,
init_vgmstream_bfwav, init_vgmstream_bfwav,
init_vgmstream_bcwav, init_vgmstream_bcwav,
init_vgmstream_brwar,
init_vgmstream_nds_strm, init_vgmstream_nds_strm,
init_vgmstream_afc, init_vgmstream_afc,
init_vgmstream_ast, init_vgmstream_ast,