Fix compact XWB [NFL Fever 2004 demo from Amped 2 (Xbox)]

This commit is contained in:
bnnm 2018-03-08 22:51:50 +01:00
parent 6fccb2a529
commit 51aa1660f2

View File

@ -44,7 +44,7 @@ typedef struct {
uint32_t base_flags; uint32_t base_flags;
size_t entry_elem_size; size_t entry_elem_size;
size_t entry_alignment; size_t entry_alignment;
int streams; int total_subsongs;
uint32_t entry_flags; uint32_t entry_flags;
uint32_t format; uint32_t format;
@ -63,27 +63,25 @@ typedef struct {
uint32_t loop_end_sample; uint32_t loop_end_sample;
} xwb_header; } xwb_header;
static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_header * xwb, STREAMFILE *streamFile); static void get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamFile);
/* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */ /* XWB - XACT Wave Bank (Microsoft SDK format for XBOX/XBOX360/Windows) */
VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) { VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
VGMSTREAM * vgmstream = NULL; VGMSTREAM * vgmstream = NULL;
off_t start_offset, off, suboff; off_t start_offset, off, suboff;
xwb_header xwb; xwb_header xwb = {0};
int target_stream = streamFile->stream_index; int target_subsong = streamFile->stream_index;
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL; int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
/* basic checks */ /* checks */
if (!check_extensions(streamFile,"xwb")) goto fail; if (!check_extensions(streamFile,"xwb"))
goto fail;
if ((read_32bitBE(0x00,streamFile) != 0x57424E44) && /* "WBND" (LE) */ if ((read_32bitBE(0x00,streamFile) != 0x57424E44) && /* "WBND" (LE) */
(read_32bitBE(0x00,streamFile) != 0x444E4257)) /* "DNBW" (BE) */ (read_32bitBE(0x00,streamFile) != 0x444E4257)) /* "DNBW" (BE) */
goto fail; goto fail;
memset(&xwb,0,sizeof(xwb_header));
xwb.little_endian = read_32bitBE(0x00,streamFile) == 0x57424E44;/* WBND */ xwb.little_endian = read_32bitBE(0x00,streamFile) == 0x57424E44;/* WBND */
if (xwb.little_endian) { if (xwb.little_endian) {
read_32bit = read_32bitLE; read_32bit = read_32bitLE;
@ -101,11 +99,11 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read segment offsets (SEGIDX) */ /* read segment offsets (SEGIDX) */
if (xwb.version <= XACT1_0_MAX) { if (xwb.version <= XACT1_0_MAX) {
xwb.streams = read_32bit(0x0c, streamFile); xwb.total_subsongs = read_32bit(0x0c, streamFile);
/* 0x10: bank name */ /* 0x10: bank name */
xwb.entry_elem_size = 0x14; xwb.entry_elem_size = 0x14;
xwb.entry_offset= 0x50; xwb.entry_offset= 0x50;
xwb.entry_size = xwb.entry_elem_size * xwb.streams; xwb.entry_size = xwb.entry_elem_size * xwb.total_subsongs;
xwb.data_offset = xwb.entry_offset + xwb.entry_size; xwb.data_offset = xwb.entry_offset + xwb.entry_size;
xwb.data_size = get_streamfile_size(streamFile) - xwb.data_offset; xwb.data_size = get_streamfile_size(streamFile) - xwb.data_offset;
} }
@ -128,7 +126,7 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* read base entry (WAVEBANKDATA) */ /* read base entry (WAVEBANKDATA) */
off = xwb.base_offset; off = xwb.base_offset;
xwb.base_flags = (uint32_t)read_32bit(off+0x00, streamFile); xwb.base_flags = (uint32_t)read_32bit(off+0x00, streamFile);
xwb.streams = read_32bit(off+0x04, streamFile); xwb.total_subsongs = read_32bit(off+0x04, streamFile);
/* 0x08 bank_name */ /* 0x08 bank_name */
suboff = 0x08 + (xwb.version <= XACT1_1_MAX ? 0x10 : 0x40); suboff = 0x08 + (xwb.version <= XACT1_1_MAX ? 0x10 : 0x40);
xwb.entry_elem_size = read_32bit(off+suboff+0x00, streamFile); xwb.entry_elem_size = read_32bit(off+suboff+0x00, streamFile);
@ -138,26 +136,32 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
/* suboff+0x10: build time 64b (XACT2/3) */ /* suboff+0x10: build time 64b (XACT2/3) */
} }
if (target_stream == 0) target_stream = 1; /* auto: default to 1 */ if (target_subsong == 0) target_subsong = 1; /* auto: default to 1 */
if (target_stream < 0 || target_stream > xwb.streams || xwb.streams < 1) goto fail; if (target_subsong < 0 || target_subsong > xwb.total_subsongs || xwb.total_subsongs < 1) goto fail;
/* read stream entry (WAVEBANKENTRY) */ /* read stream entry (WAVEBANKENTRY) */
off = xwb.entry_offset + (target_stream-1) * xwb.entry_elem_size; off = xwb.entry_offset + (target_subsong-1) * xwb.entry_elem_size;
if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) { /* compact entry */ if (xwb.base_flags & WAVEBANK_FLAGS_COMPACT) { /* compact entry [NFL Fever 2004 demo from Amped 2 (Xbox)] */
/* offset_in_sectors:21 and sector_alignment_in_bytes:11 */ uint32_t entry, size_deviation, sector_offset;
uint32_t entry = (uint32_t)read_32bit(off+0x00, streamFile); off_t next_stream_offset;
xwb.stream_offset = xwb.data_offset + (entry >> 11) * xwb.entry_alignment + (entry & 0x7FF);
/* find size (up to next entry or data end) */ entry = (uint32_t)read_32bit(off+0x00, streamFile);
if (xwb.streams > 1) { size_deviation = ((entry >> 21) & 0x7FF); /* 11b, padding data for sector alignment in bytes*/
entry = (uint32_t)read_32bit(off+xwb.entry_size, streamFile); sector_offset = (entry & 0x1FFFFF); /* 21b, offset within data in sectors */
xwb.stream_size = xwb.stream_offset -
(xwb.data_offset + (entry >> 11) * xwb.entry_alignment + (entry & 0x7FF)); xwb.stream_offset = xwb.data_offset + sector_offset*xwb.entry_alignment;
} else {
xwb.stream_size = xwb.data_size; /* find size using next offset */
if (target_subsong < xwb.total_subsongs) {
uint32_t next_entry = (uint32_t)read_32bit(off+0x04, streamFile);
next_stream_offset = xwb.data_offset + (next_entry & 0x1FFFFF)*xwb.entry_alignment;
} }
else { /* for last entry (or first, when subsongs = 1) */
next_stream_offset = xwb.data_offset + xwb.data_size;
}
xwb.stream_size = next_stream_offset - xwb.stream_offset - size_deviation;
} }
else if (xwb.version <= XACT1_0_MAX) { else if (xwb.version <= XACT1_0_MAX) {
xwb.format = (uint32_t)read_32bit(off+0x00, streamFile); xwb.format = (uint32_t)read_32bit(off+0x00, streamFile);
@ -353,10 +357,10 @@ VGMSTREAM * init_vgmstream_xwb(STREAMFILE *streamFile) {
vgmstream->num_samples = xwb.num_samples; vgmstream->num_samples = xwb.num_samples;
vgmstream->loop_start_sample = xwb.loop_start_sample; vgmstream->loop_start_sample = xwb.loop_start_sample;
vgmstream->loop_end_sample = xwb.loop_end_sample; vgmstream->loop_end_sample = xwb.loop_end_sample;
vgmstream->num_streams = xwb.streams; vgmstream->num_streams = xwb.total_subsongs;
vgmstream->stream_size = xwb.stream_size; vgmstream->stream_size = xwb.stream_size;
vgmstream->meta_type = meta_XWB; vgmstream->meta_type = meta_XWB;
get_xsb_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_stream, &xwb, streamFile); get_xsb_name(vgmstream->stream_name,STREAM_NAME_SIZE, target_subsong, &xwb, streamFile);
switch(xwb.codec) { switch(xwb.codec) {
case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */ case PCM: /* Unreal Championship (Xbox)[PCM8], KOF2003 (Xbox)[PCM16LE], Otomedius (X360)[PCM16BE] */
@ -535,7 +539,7 @@ typedef struct {
/* try to find the stream name in a companion XSB file, a comically complex cue format. */ /* try to find the stream name in a companion XSB file, a comically complex cue format. */
static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_header * xwb, STREAMFILE *streamXwb) { static void get_xsb_name(char * buf, size_t maxsize, int target_subsong, xwb_header * xwb, STREAMFILE *streamXwb) {
STREAMFILE *streamFile = NULL; STREAMFILE *streamFile = NULL;
int i,j, start_sound, cfg__start_sound = 0, cfg__selected_wavebank = 0; int i,j, start_sound, cfg__start_sound = 0, cfg__selected_wavebank = 0;
int xsb_version; int xsb_version;
@ -609,8 +613,8 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
xsb.xsb_sounds_offset = read_32bit(0x46, streamFile); xsb.xsb_sounds_offset = read_32bit(0x46, streamFile);
} }
VGM_ASSERT(xsb.xsb_sounds_count < xwb->streams, VGM_ASSERT(xsb.xsb_sounds_count < xwb->total_subsongs,
"XSB: number of streams in xsb lower than xwb (xsb %i vs xwb %i)\n", xsb.xsb_sounds_count, xwb->streams); "XSB: number of streams in xsb lower than xwb (xsb %i vs xwb %i)\n", xsb.xsb_sounds_count, xwb->total_subsongs);
VGM_ASSERT(xsb.xsb_simple_sounds_count + xsb.xsb_complex_sounds_count != xsb.xsb_sounds_count, VGM_ASSERT(xsb.xsb_simple_sounds_count + xsb.xsb_complex_sounds_count != xsb.xsb_sounds_count,
"XSB: number of xsb sounds doesn't match simple + complex sounds (simple %i, complex %i, total %i)\n", xsb.xsb_simple_sounds_count, xsb.xsb_complex_sounds_count, xsb.xsb_sounds_count); "XSB: number of xsb sounds doesn't match simple + complex sounds (simple %i, complex %i, total %i)\n", xsb.xsb_simple_sounds_count, xsb.xsb_complex_sounds_count, xsb.xsb_sounds_count);
@ -747,7 +751,7 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
//CHECK_EXIT(w->sound_count == 0, "ERROR: xsb wavebank %i has no sounds", i); //Ikaruga PC //CHECK_EXIT(w->sound_count == 0, "ERROR: xsb wavebank %i has no sounds", i); //Ikaruga PC
if (w->sound_count == xwb->streams) { if (w->sound_count == xwb->total_subsongs) {
if (!cfg__selected_wavebank) { if (!cfg__selected_wavebank) {
VGM_LOG("XSB: multiple xsb wavebanks with the same number of sounds, use -w to specify one of the wavebanks\n"); VGM_LOG("XSB: multiple xsb wavebanks with the same number of sounds, use -w to specify one of the wavebanks\n");
goto fail; goto fail;
@ -773,22 +777,22 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
} }
if (cfg__start_sound) { if (cfg__start_sound) {
if (xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - (cfg__start_sound-1) < xwb->streams) { if (xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - (cfg__start_sound-1) < xwb->total_subsongs) {
VGM_LOG("XSB: starting sound too high (max in selected wavebank is %i)\n", xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - xwb->streams + 1); VGM_LOG("XSB: starting sound too high (max in selected wavebank is %i)\n", xsb.xsb_wavebanks[cfg__selected_wavebank-1].sound_count - xwb->total_subsongs + 1);
goto fail; goto fail;
} }
} else { } else {
/* /*
if (!cfg->ignore_names_not_found) if (!cfg->ignore_names_not_found)
CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count > xwb->streams_count, "ERROR: number of streams in xsb wavebank bigger than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count); CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count > xwb->streams_count, "ERROR: number of streams in xsb wavebank bigger than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
if (!cfg->ignore_names_not_found) if (!cfg->ignore_names_not_found)
CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count < xwb->streams_count, "ERROR: number of streams in xsb wavebank lower than xwb (xsb %i vs xwb %i), use -n to ignore (some names won't be extracted)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count); CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count < xwb->streams_count, "ERROR: number of streams in xsb wavebank lower than xwb (xsb %i vs xwb %i), use -n to ignore (some names won't be extracted)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
*/ */
//if (!cfg->ignore_names_not_found) //if (!cfg->ignore_names_not_found)
// CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count != xwb->streams_count, "ERROR: number of streams in xsb wavebank different than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->streams_count); // CHECK_EXIT(xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count != xwb->streams_count, "ERROR: number of streams in xsb wavebank different than xwb (xsb %i vs xwb %i), use -s to specify (1=first)", xwb->xsb_wavebanks[cfg->selected_wavebank-1].sound_count, xwb->total_subsongs);
} }
/* *************************** */ /* *************************** */
@ -799,7 +803,7 @@ static void get_xsb_name(char * buf, size_t maxsize, int target_stream, xwb_head
for (i = start_sound; i < xsb.xsb_sounds_count; i++) { for (i = start_sound; i < xsb.xsb_sounds_count; i++) {
xsb_sound *s = &(xsb.xsb_sounds[i]); xsb_sound *s = &(xsb.xsb_sounds[i]);
if (s->wavebank == cfg__selected_wavebank-1 if (s->wavebank == cfg__selected_wavebank-1
&& s->stream_index == target_stream-1){ && s->stream_index == target_subsong-1){
name_offset = s->name_offset; name_offset = s->name_offset;
break; break;
} }