|
|
|
@ -18,6 +18,7 @@ typedef struct {
|
|
|
|
|
size_t section2_entry_size;
|
|
|
|
|
size_t section3_entry_size;
|
|
|
|
|
size_t resource_name_size;
|
|
|
|
|
size_t blk_table_size;
|
|
|
|
|
|
|
|
|
|
off_t audio_extra_offset;
|
|
|
|
|
off_t audio_stream_size;
|
|
|
|
@ -26,6 +27,8 @@ typedef struct {
|
|
|
|
|
off_t audio_group_id;
|
|
|
|
|
off_t audio_external_flag;
|
|
|
|
|
off_t audio_loop_flag;
|
|
|
|
|
off_t audio_loc_flag;
|
|
|
|
|
off_t audio_stereo_flag;
|
|
|
|
|
off_t audio_num_samples;
|
|
|
|
|
off_t audio_num_samples2;
|
|
|
|
|
off_t audio_sample_rate;
|
|
|
|
@ -36,6 +39,8 @@ typedef struct {
|
|
|
|
|
int audio_external_and;
|
|
|
|
|
int audio_loop_and;
|
|
|
|
|
int audio_group_and;
|
|
|
|
|
int audio_loc_and;
|
|
|
|
|
int audio_stereo_and;
|
|
|
|
|
int num_codec_flags;
|
|
|
|
|
int audio_has_internal_names;
|
|
|
|
|
size_t audio_interleave;
|
|
|
|
@ -59,7 +64,7 @@ typedef struct {
|
|
|
|
|
off_t layer_stream_type;
|
|
|
|
|
off_t layer_num_samples;
|
|
|
|
|
size_t layer_entry_size;
|
|
|
|
|
size_t layer_hijack;
|
|
|
|
|
int layer_hijack;
|
|
|
|
|
|
|
|
|
|
off_t silence_duration_int;
|
|
|
|
|
off_t silence_duration_float;
|
|
|
|
@ -80,6 +85,7 @@ typedef struct {
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
ubi_sb_platform platform;
|
|
|
|
|
int is_ps2_old;
|
|
|
|
|
int is_psp_old;
|
|
|
|
|
int big_endian;
|
|
|
|
|
int total_subsongs;
|
|
|
|
@ -92,12 +98,12 @@ typedef struct {
|
|
|
|
|
|
|
|
|
|
/* map base header info */
|
|
|
|
|
off_t map_start;
|
|
|
|
|
off_t map_num;
|
|
|
|
|
uint32_t map_num;
|
|
|
|
|
|
|
|
|
|
uint32_t map_type;
|
|
|
|
|
uint32_t map_zero;
|
|
|
|
|
off_t map_offset;
|
|
|
|
|
off_t map_size;
|
|
|
|
|
size_t map_size;
|
|
|
|
|
char map_name[0x28];
|
|
|
|
|
uint32_t map_unknown;
|
|
|
|
|
|
|
|
|
@ -105,24 +111,26 @@ typedef struct {
|
|
|
|
|
int is_bank;
|
|
|
|
|
int is_map;
|
|
|
|
|
int is_bnm;
|
|
|
|
|
int is_blk;
|
|
|
|
|
STREAMFILE *sf_header;
|
|
|
|
|
uint32_t version; /* 16b+16b major+minor version */
|
|
|
|
|
uint32_t version_empty; /* map sbX versions are empty */
|
|
|
|
|
/* events (often share header_id/type with some descriptors,
|
|
|
|
|
* but may exist without headers or header exist without them) */
|
|
|
|
|
size_t section1_num;
|
|
|
|
|
size_t section1_offset;
|
|
|
|
|
off_t section1_offset;
|
|
|
|
|
/* descriptors, audio header or other config types */
|
|
|
|
|
size_t section2_num;
|
|
|
|
|
size_t section2_offset;
|
|
|
|
|
off_t section2_offset;
|
|
|
|
|
/* internal streams table, referenced by each header */
|
|
|
|
|
size_t section3_num;
|
|
|
|
|
size_t section3_offset;
|
|
|
|
|
off_t section3_offset;
|
|
|
|
|
/* section with sounds in some map versions */
|
|
|
|
|
size_t section4_num;
|
|
|
|
|
size_t section4_offset;
|
|
|
|
|
off_t section4_offset;
|
|
|
|
|
/* extra table, config for certain types (DSP coefs, external resources, layer headers, etc) */
|
|
|
|
|
size_t sectionX_size;
|
|
|
|
|
size_t sectionX_offset;
|
|
|
|
|
off_t sectionX_offset;
|
|
|
|
|
/* unknown, usually -1 but can be others (0/1/2/etc) */
|
|
|
|
|
int flag1;
|
|
|
|
|
int flag2;
|
|
|
|
@ -139,6 +147,8 @@ typedef struct {
|
|
|
|
|
size_t stream_size; /* size of the audio data */
|
|
|
|
|
uint32_t stream_type; /* rough codec value */
|
|
|
|
|
uint32_t group_id; /* internal id to reference in section3 */
|
|
|
|
|
int is_localized;
|
|
|
|
|
int is_stereo;
|
|
|
|
|
|
|
|
|
|
int loop_flag; /* stream loops (normally internal sfx, but also external music) */
|
|
|
|
|
int loop_start; /* usually 0 */
|
|
|
|
@ -419,6 +429,7 @@ static int parse_bnm_header(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
|
|
|
|
|
/* PLATFORM DETECTION */
|
|
|
|
|
sb->platform = UBI_PC;
|
|
|
|
|
sb->big_endian = 0;
|
|
|
|
|
read_32bit = sb->big_endian ? read_32bitBE : read_32bitLE;
|
|
|
|
|
|
|
|
|
|
/* SB HEADER */
|
|
|
|
@ -454,22 +465,144 @@ static int is_bnm_other_bank(STREAMFILE *streamFile, int bank_number) {
|
|
|
|
|
return strcmp(current_name, bank_name) != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
/* .BLK - maps in separate .blk chunks [Donald Duck: Goin' Quackers (PS2), The Jungle Book Rhythm N'Groove (PS2)] */
|
|
|
|
|
VGMSTREAM * init_vgmstream_ubi_blk(STREAMFILE *streamFile) {
|
|
|
|
|
VGMSTREAM* vgmstream = NULL;
|
|
|
|
|
STREAMFILE *resData = NULL, *streamTest = NULL;
|
|
|
|
|
ubi_sb_header sb = { 0 };
|
|
|
|
|
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
|
|
|
|
|
int target_subsong = streamFile->stream_index;
|
|
|
|
|
|
|
|
|
|
/* Somewhat equivalent to a v0x00000003 map:
|
|
|
|
|
* - HEADER.BLK: base map header (slightly different?) + submaps headers
|
|
|
|
|
* - EVT.BLK: section1 from all submaps
|
|
|
|
|
* - RES.BLK: section2 + sectionX from all submaps
|
|
|
|
|
* - MAPS.BLK, MAPLANG.BLK: section3 variation?
|
|
|
|
|
* - STREAMED.BLK, STRLANG.BLK: audio data
|
|
|
|
|
* - HEADER.BLK: base map header + submaps headers
|
|
|
|
|
* - EVT.BLK: section1
|
|
|
|
|
* - RES.BLK: section2 + sectionX
|
|
|
|
|
* - MAPS.BLK, MAPLANG.BLK: section3's for each map
|
|
|
|
|
* - STREAMED.BLK, STRLANG.BLK: streamed sounds
|
|
|
|
|
*
|
|
|
|
|
* Parsing may be be simplified with multifile_streamfiles?
|
|
|
|
|
*
|
|
|
|
|
* The format is different from SMx in that there's a single sec1 and sec2
|
|
|
|
|
* shared by all maps so we can't determine which sounds belong to which map.
|
|
|
|
|
* Meanwhile, RAM sounds are stored in MAP.BLK/MAPLANG.BLK, which are split into blocks,
|
|
|
|
|
* one per map, which contain all RAM sounds that should be loaded for a given map.
|
|
|
|
|
* 0x00: version
|
|
|
|
|
* 0x04: number of maps
|
|
|
|
|
* 0x08: number of events (EVT.BLK)
|
|
|
|
|
* 0x0c: number of resources (RES.BLK)
|
|
|
|
|
* 0x10: flags?
|
|
|
|
|
* 0x14: size of extra section in RES.BLK
|
|
|
|
|
* for each map:
|
|
|
|
|
* 0x00: total size of common RAM sounds
|
|
|
|
|
* 0x04: total size of localized RAM sounds
|
|
|
|
|
* 0x08: offset of common sound table in MAP.BLK
|
|
|
|
|
* 0x0c: offset of localized sound table in MAPLANG.BLK
|
|
|
|
|
* 0x10: map name (0x20 bytes)
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* checks */
|
|
|
|
|
if (!check_extensions(streamFile, "blk"))
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
/* only known to be used on PS2 */
|
|
|
|
|
sb.platform = UBI_PS2;
|
|
|
|
|
sb.big_endian = 0;
|
|
|
|
|
read_32bit = sb.big_endian ? read_32bitBE : read_32bitLE;
|
|
|
|
|
|
|
|
|
|
/* must open HEADER.BLK */
|
|
|
|
|
sb.is_blk = 1;
|
|
|
|
|
sb.version = read_32bit(0x00, streamFile) & 0x7FFFFFFF;
|
|
|
|
|
if (read_32bit(0x00, streamFile) & 0x80000000) {
|
|
|
|
|
sb.cfg.blk_table_size = 0x2000;
|
|
|
|
|
} else {
|
|
|
|
|
sb.cfg.blk_table_size = 0x1800;
|
|
|
|
|
}
|
|
|
|
|
if (sb.version != 0x00000003)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
if (!config_sb_version(&sb, streamFile))
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
sb.sf_header = streamFile;
|
|
|
|
|
sb.map_num = read_32bit(0x04, streamFile);
|
|
|
|
|
sb.section1_num = read_32bit(0x08, streamFile);
|
|
|
|
|
sb.section1_offset = 0;
|
|
|
|
|
sb.section2_num = read_32bit(0x0c, streamFile);
|
|
|
|
|
sb.section2_offset = 0;
|
|
|
|
|
sb.sectionX_offset = sb.section2_num * sb.cfg.section2_entry_size;
|
|
|
|
|
sb.sectionX_size = read_32bit(0x14, streamFile);
|
|
|
|
|
|
|
|
|
|
/* ugh... */
|
|
|
|
|
resData = open_streamfile_by_filename(streamFile, "RES.BLK");
|
|
|
|
|
streamTest = reopen_streamfile(resData, 0x100);
|
|
|
|
|
if (target_subsong == 0) target_subsong = 1;
|
|
|
|
|
|
|
|
|
|
if (!parse_sb(&sb, streamTest, target_subsong))
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
/* CREATE VGMSTREAM */
|
|
|
|
|
vgmstream = init_vgmstream_ubi_sb_header(&sb, streamTest, resData);
|
|
|
|
|
close_streamfile(resData);
|
|
|
|
|
close_streamfile(streamTest);
|
|
|
|
|
return vgmstream;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
close_streamfile(resData);
|
|
|
|
|
close_streamfile(streamTest);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
static int blk_parse_offsets(ubi_sb_header *sb) {
|
|
|
|
|
STREAMFILE *sndData = NULL;
|
|
|
|
|
uint32_t i;
|
|
|
|
|
int32_t(*read_32bit)(off_t, STREAMFILE *) = sb->big_endian ? read_32bitBE : read_32bitLE;
|
|
|
|
|
|
|
|
|
|
/* correct offsets */
|
|
|
|
|
if (sb->is_external) {
|
|
|
|
|
sb->stream_offset *= sb->cfg.audio_interleave;
|
|
|
|
|
} else {
|
|
|
|
|
/* find the first map block which has this sound */
|
|
|
|
|
sndData = open_streamfile_by_filename(sb->sf_header, sb->resource_name);
|
|
|
|
|
for (i = 0; i < sb->map_num; i++) {
|
|
|
|
|
uint32_t entry_offset, cmn_table_offset, loc_table_offset, table_offset;
|
|
|
|
|
entry_offset = 0x18 + i * sb->cfg.map_entry_size;
|
|
|
|
|
cmn_table_offset = read_32bit(entry_offset + 0x08, sb->sf_header);
|
|
|
|
|
loc_table_offset = read_32bit(entry_offset + 0x0c, sb->sf_header);
|
|
|
|
|
table_offset = sb->is_localized ? loc_table_offset : cmn_table_offset;
|
|
|
|
|
|
|
|
|
|
sb->stream_offset = read_32bit(table_offset + sb->header_index * 0x04, sndData);
|
|
|
|
|
if (sb->stream_offset != 0xFFFFFFFF) {
|
|
|
|
|
sb->stream_offset += table_offset + sb->cfg.blk_table_size;
|
|
|
|
|
//sb->stream_size -= 0x04;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
close_streamfile(sndData);
|
|
|
|
|
|
|
|
|
|
if (sb->stream_offset == 0xFFFFFFFF) {
|
|
|
|
|
VGM_LOG("No map block contains resource %08x (%d)\n", sb->header_id, sb->header_index);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void blk_get_resource_name(ubi_sb_header *sb) {
|
|
|
|
|
if (sb->is_external) {
|
|
|
|
|
if (sb->is_localized) {
|
|
|
|
|
strcpy(sb->resource_name, "STRLANG.BLK");
|
|
|
|
|
} else {
|
|
|
|
|
strcpy(sb->resource_name, "../STREAMED.BLK");
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (sb->is_localized) {
|
|
|
|
|
strcpy(sb->resource_name, "MAPLANG.BLK");
|
|
|
|
|
} else {
|
|
|
|
|
strcpy(sb->resource_name, "../MAP.BLK");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ************************************************************************* */
|
|
|
|
|
|
|
|
|
@ -780,7 +913,7 @@ static VGMSTREAM * init_vgmstream_ubi_sb_audio(ubi_sb_header *sb, STREAMFILE *st
|
|
|
|
|
STREAMFILE *streamData = NULL;
|
|
|
|
|
|
|
|
|
|
/* open external stream if needed */
|
|
|
|
|
if (sb->is_external) {
|
|
|
|
|
if (sb->is_external || sb->is_blk) {
|
|
|
|
|
streamData = open_streamfile_by_filename(streamFile,sb->resource_name);
|
|
|
|
|
if (streamData == NULL) {
|
|
|
|
|
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
|
|
|
|
@ -797,11 +930,11 @@ static VGMSTREAM * init_vgmstream_ubi_sb_audio(ubi_sb_header *sb, STREAMFILE *st
|
|
|
|
|
if (!vgmstream) goto fail;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sb->is_external && streamData) close_streamfile(streamData);
|
|
|
|
|
if (streamData != streamFile) close_streamfile(streamData);
|
|
|
|
|
return vgmstream;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
if (sb->is_external && streamData) close_streamfile(streamData);
|
|
|
|
|
if (streamData != streamFile) close_streamfile(streamData);
|
|
|
|
|
close_vgmstream(vgmstream);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
@ -814,8 +947,13 @@ static VGMSTREAM * init_vgmstream_ubi_sb_layer(ubi_sb_header *sb, STREAMFILE *st
|
|
|
|
|
size_t full_stream_size = sb->stream_size;
|
|
|
|
|
int i, total_channels = 0;
|
|
|
|
|
|
|
|
|
|
if (sb->is_ps2_old) {
|
|
|
|
|
/* no blocked layout yet, just open as normal file */
|
|
|
|
|
return init_vgmstream_ubi_sb_audio(sb, streamTest, streamFile);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* open external stream if needed */
|
|
|
|
|
if (sb->is_external) {
|
|
|
|
|
if (sb->is_external || sb->is_blk) {
|
|
|
|
|
streamData = open_streamfile_by_filename(streamFile,sb->resource_name);
|
|
|
|
|
if (streamData == NULL) {
|
|
|
|
|
VGM_LOG("UBI SB: external stream '%s' not found\n", sb->resource_name);
|
|
|
|
@ -869,12 +1007,12 @@ static VGMSTREAM * init_vgmstream_ubi_sb_layer(ubi_sb_header *sb, STREAMFILE *st
|
|
|
|
|
vgmstream->layout_type = layout_layered;
|
|
|
|
|
vgmstream->layout_data = data;
|
|
|
|
|
|
|
|
|
|
if (sb->is_external && streamData) close_streamfile(streamData);
|
|
|
|
|
if (streamData != streamFile) close_streamfile(streamData);
|
|
|
|
|
|
|
|
|
|
return vgmstream;
|
|
|
|
|
fail:
|
|
|
|
|
close_streamfile(temp_streamFile);
|
|
|
|
|
if (sb->is_external && streamData) close_streamfile(streamData);
|
|
|
|
|
if (streamData != streamFile) close_streamfile(streamData);
|
|
|
|
|
if (vgmstream)
|
|
|
|
|
close_vgmstream(vgmstream);
|
|
|
|
|
else
|
|
|
|
@ -1120,6 +1258,9 @@ static void build_readable_name(char * buf, size_t buf_size, ubi_sb_header * sb)
|
|
|
|
|
else
|
|
|
|
|
grp_name = "bnm";
|
|
|
|
|
}
|
|
|
|
|
else if (sb->is_blk) {
|
|
|
|
|
grp_name = "blk";
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
grp_name = "bank";
|
|
|
|
|
}
|
|
|
|
@ -1145,7 +1286,7 @@ static void build_readable_name(char * buf, size_t buf_size, ubi_sb_header * sb)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (sb->is_external || sb->cfg.audio_has_internal_names)
|
|
|
|
|
if (sb->is_external || sb->cfg.audio_has_internal_names || sb->is_blk)
|
|
|
|
|
res_name = sb->resource_name;
|
|
|
|
|
else
|
|
|
|
|
res_name = NULL;
|
|
|
|
@ -1167,6 +1308,75 @@ static void build_readable_name(char * buf, size_t buf_size, ubi_sb_header * sb)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int parse_type_audio_ps2_old(ubi_sb_header *sb, off_t offset, STREAMFILE *streamFile) {
|
|
|
|
|
int32_t(*read_32bit)(off_t, STREAMFILE *) = sb->big_endian ? read_32bitBE : read_32bitLE;
|
|
|
|
|
|
|
|
|
|
sb->stream_size = read_32bit(offset + sb->cfg.audio_stream_size, streamFile);
|
|
|
|
|
sb->stream_offset = read_32bit(offset + sb->cfg.audio_stream_offset, streamFile);
|
|
|
|
|
sb->sample_rate = read_32bit(offset + sb->cfg.audio_sample_rate, streamFile);
|
|
|
|
|
|
|
|
|
|
if (sb->stream_size == 0) {
|
|
|
|
|
VGM_LOG("UBI SB: bad stream size\n");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sb->is_external = read_32bit(offset + sb->cfg.audio_external_flag, streamFile) & sb->cfg.audio_external_and;
|
|
|
|
|
sb->loop_flag = read_32bit(offset + sb->cfg.audio_loop_flag, streamFile) & sb->cfg.audio_loop_and;
|
|
|
|
|
sb->is_localized = read_32bit(offset + sb->cfg.audio_loc_flag, streamFile) & sb->cfg.audio_loc_and;
|
|
|
|
|
sb->is_stereo = read_32bit(offset + sb->cfg.audio_stereo_flag, streamFile) & sb->cfg.audio_stereo_and;
|
|
|
|
|
|
|
|
|
|
sb->num_samples = 0; /* calculate from size */
|
|
|
|
|
sb->channels = sb->is_stereo ? 2 : 1;
|
|
|
|
|
sb->stream_size *= sb->channels;
|
|
|
|
|
sb->group_id = 0; /* TODO: verify, flag could exist */
|
|
|
|
|
|
|
|
|
|
/* filenames are hardcoded */
|
|
|
|
|
if (sb->is_blk) {
|
|
|
|
|
blk_get_resource_name(sb);
|
|
|
|
|
} else if (sb->is_external) {
|
|
|
|
|
strcpy(sb->resource_name, sb->is_localized ? "STRM.LM1" : "STRM.SM1");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
fail:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int parse_type_layer_ps2_old(ubi_sb_header *sb, off_t offset, STREAMFILE *streamFile) {
|
|
|
|
|
int32_t(*read_32bit)(off_t, STREAMFILE *) = sb->big_endian ? read_32bitBE : read_32bitLE;
|
|
|
|
|
|
|
|
|
|
sb->layer_count = read_32bit(offset + sb->cfg.layer_layer_count, streamFile);
|
|
|
|
|
sb->stream_size = read_32bit(offset + sb->cfg.layer_stream_size, streamFile);
|
|
|
|
|
sb->stream_offset = read_32bit(offset + sb->cfg.layer_stream_offset, streamFile);
|
|
|
|
|
|
|
|
|
|
if (sb->stream_size == 0) {
|
|
|
|
|
VGM_LOG("UBI SB: bad stream size\n");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sb->layer_count > SB_MAX_LAYER_COUNT) {
|
|
|
|
|
VGM_LOG("Ubi SB: incorrect layer count\n");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* much simpler than later iteration */
|
|
|
|
|
sb->sample_rate = 44100; /* fixed? */
|
|
|
|
|
sb->num_samples = 0; /* calculate from size */
|
|
|
|
|
sb->channels = sb->layer_count * 2; /* layers are always stereo */
|
|
|
|
|
sb->stream_size *= sb->channels;
|
|
|
|
|
|
|
|
|
|
/* filenames are hardcoded */
|
|
|
|
|
if (sb->is_blk) {
|
|
|
|
|
blk_get_resource_name(sb);
|
|
|
|
|
} else if (sb->is_external) {
|
|
|
|
|
strcpy(sb->resource_name, sb->is_localized ? "STRM.LM1" : "STRM.SM1");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
fail:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int parse_type_audio(ubi_sb_header * sb, off_t offset, STREAMFILE* streamFile) {
|
|
|
|
|
int32_t (*read_32bit)(off_t,STREAMFILE*) = sb->big_endian ? read_32bitBE : read_32bitLE;
|
|
|
|
|
int16_t (*read_16bit)(off_t,STREAMFILE*) = sb->big_endian ? read_16bitBE : read_16bitLE;
|
|
|
|
@ -1174,6 +1384,9 @@ static int parse_type_audio(ubi_sb_header * sb, off_t offset, STREAMFILE* stream
|
|
|
|
|
/* audio header */
|
|
|
|
|
sb->type = UBI_AUDIO;
|
|
|
|
|
|
|
|
|
|
if (sb->is_ps2_old)
|
|
|
|
|
return parse_type_audio_ps2_old(sb, offset, streamFile);
|
|
|
|
|
|
|
|
|
|
sb->extra_offset = read_32bit(offset + sb->cfg.audio_extra_offset, streamFile) + sb->sectionX_offset;
|
|
|
|
|
sb->stream_size = read_32bit(offset + sb->cfg.audio_stream_size, streamFile);
|
|
|
|
|
sb->stream_offset = read_32bit(offset + sb->cfg.audio_stream_offset, streamFile);
|
|
|
|
@ -1188,9 +1401,7 @@ static int parse_type_audio(ubi_sb_header * sb, off_t offset, STREAMFILE* stream
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sb->cfg.audio_external_flag && sb->cfg.audio_external_and) {
|
|
|
|
|
sb->is_external = (read_32bit(offset + sb->cfg.audio_external_flag, streamFile) & sb->cfg.audio_external_and);
|
|
|
|
|
}
|
|
|
|
|
sb->is_external = read_32bit(offset + sb->cfg.audio_external_flag, streamFile) & sb->cfg.audio_external_and;
|
|
|
|
|
|
|
|
|
|
if (sb->cfg.audio_group_id && sb->cfg.audio_group_and) {
|
|
|
|
|
/* probably means "SW decoded" */
|
|
|
|
@ -1206,9 +1417,7 @@ static int parse_type_audio(ubi_sb_header * sb, off_t offset, STREAMFILE* stream
|
|
|
|
|
sb->group_id = (int)!(sb->stream_type & 0x01);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sb->cfg.audio_loop_flag && sb->cfg.audio_loop_and) {
|
|
|
|
|
sb->loop_flag = (read_32bit(offset + sb->cfg.audio_loop_flag, streamFile) & sb->cfg.audio_loop_and);
|
|
|
|
|
}
|
|
|
|
|
sb->loop_flag = read_32bit(offset + sb->cfg.audio_loop_flag, streamFile) & sb->cfg.audio_loop_and;
|
|
|
|
|
|
|
|
|
|
if (sb->loop_flag) {
|
|
|
|
|
sb->loop_start = read_32bit(offset + sb->cfg.audio_num_samples, streamFile);
|
|
|
|
@ -1256,8 +1465,8 @@ static int parse_type_sequence(ubi_sb_header * sb, off_t offset, STREAMFILE* str
|
|
|
|
|
|
|
|
|
|
/* sequence chain */
|
|
|
|
|
sb->type = UBI_SEQUENCE;
|
|
|
|
|
if (sb->cfg.sequence_entry_size == 0) {
|
|
|
|
|
VGM_LOG("Ubi SB: sequence entry size not configured at %x\n", (uint32_t)offset);
|
|
|
|
|
if (sb->cfg.sequence_sequence_count == 0) {
|
|
|
|
|
VGM_LOG("Ubi SB: sequence not configured at %x\n", (uint32_t)offset);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1318,11 +1527,17 @@ static int parse_type_layer(ubi_sb_header * sb, off_t offset, STREAMFILE* stream
|
|
|
|
|
|
|
|
|
|
/* layer header */
|
|
|
|
|
sb->type = UBI_LAYER;
|
|
|
|
|
if (sb->cfg.layer_entry_size == 0) {
|
|
|
|
|
VGM_LOG("Ubi SB: layer entry size not configured at %x\n", (uint32_t)offset);
|
|
|
|
|
if (sb->cfg.layer_layer_count == 0) {
|
|
|
|
|
VGM_LOG("Ubi SB: layers not configured at %x\n", (uint32_t)offset);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* all layers seem external */
|
|
|
|
|
sb->is_external = 1;
|
|
|
|
|
|
|
|
|
|
if (sb->is_ps2_old)
|
|
|
|
|
return parse_type_layer_ps2_old(sb, offset, streamFile);
|
|
|
|
|
|
|
|
|
|
sb->extra_offset = read_32bit(offset + sb->cfg.layer_extra_offset, streamFile) + sb->sectionX_offset;
|
|
|
|
|
sb->layer_count = read_32bit(offset + sb->cfg.layer_layer_count, streamFile);
|
|
|
|
|
sb->stream_size = read_32bit(offset + sb->cfg.layer_stream_size, streamFile);
|
|
|
|
@ -1340,17 +1555,17 @@ static int parse_type_layer(ubi_sb_header * sb, off_t offset, STREAMFILE* stream
|
|
|
|
|
|
|
|
|
|
/* get 1st layer header in extra table and validate all headers match */
|
|
|
|
|
table_offset = sb->extra_offset;
|
|
|
|
|
//sb->channels = (sb->cfg.layer_channels % 4) ? /* non-aligned offset is always 16b */
|
|
|
|
|
// (uint16_t)read_16bit(table_offset + sb->cfg.layer_channels, streamFile) :
|
|
|
|
|
// (uint32_t)read_32bit(table_offset + sb->cfg.layer_channels, streamFile);
|
|
|
|
|
sb->sample_rate = read_32bit(table_offset + sb->cfg.layer_sample_rate, streamFile);
|
|
|
|
|
sb->stream_type = read_32bit(table_offset + sb->cfg.layer_stream_type, streamFile);
|
|
|
|
|
sb->num_samples = read_32bit(table_offset + sb->cfg.layer_num_samples, streamFile);
|
|
|
|
|
//sb->channels = (sb->cfg.layer_channels % 4) ? /* non-aligned offset is always 16b */
|
|
|
|
|
// (uint16_t)read_16bit(table_offset + sb->cfg.layer_channels, streamFile) :
|
|
|
|
|
// (uint32_t)read_32bit(table_offset + sb->cfg.layer_channels, streamFile);
|
|
|
|
|
sb->sample_rate = read_32bit(table_offset + sb->cfg.layer_sample_rate, streamFile);
|
|
|
|
|
sb->stream_type = read_32bit(table_offset + sb->cfg.layer_stream_type, streamFile);
|
|
|
|
|
sb->num_samples = read_32bit(table_offset + sb->cfg.layer_num_samples, streamFile);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < sb->layer_count; i++) {
|
|
|
|
|
int channels = (sb->cfg.layer_channels % 4) ? /* non-aligned offset is always 16b */
|
|
|
|
|
(uint16_t)read_16bit(table_offset + sb->cfg.layer_channels, streamFile) :
|
|
|
|
|
(uint32_t)read_32bit(table_offset + sb->cfg.layer_channels, streamFile);
|
|
|
|
|
int channels = (sb->cfg.layer_channels % 4) ? /* non-aligned offset is always 16b */
|
|
|
|
|
(uint16_t)read_16bit(table_offset + sb->cfg.layer_channels, streamFile) :
|
|
|
|
|
(uint32_t)read_32bit(table_offset + sb->cfg.layer_channels, streamFile);
|
|
|
|
|
int sample_rate = read_32bit(table_offset + sb->cfg.layer_sample_rate, streamFile);
|
|
|
|
|
int stream_type = read_32bit(table_offset + sb->cfg.layer_stream_type, streamFile);
|
|
|
|
|
int num_samples = read_32bit(table_offset + sb->cfg.layer_num_samples, streamFile);
|
|
|
|
@ -1372,13 +1587,10 @@ static int parse_type_layer(ubi_sb_header * sb, off_t offset, STREAMFILE* stream
|
|
|
|
|
table_offset += sb->cfg.layer_entry_size;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* all layers seem external */
|
|
|
|
|
sb->is_external = 1;
|
|
|
|
|
|
|
|
|
|
/* external stream name can be found in the header (first versions) or the sectionX table (later versions) */
|
|
|
|
|
if (sb->cfg.layer_stream_name) {
|
|
|
|
|
read_string(sb->resource_name, sb->cfg.resource_name_size, offset + sb->cfg.layer_stream_name, streamFile);
|
|
|
|
|
} else {
|
|
|
|
|
} else if (sb->cfg.layer_extra_name) {
|
|
|
|
|
sb->cfg.layer_stream_name = read_32bit(offset + sb->cfg.layer_extra_name, streamFile);
|
|
|
|
|
if (sb->cfg.layer_stream_name != 0xFFFFFFFF)
|
|
|
|
|
read_string(sb->resource_name, sb->cfg.resource_name_size, sb->sectionX_offset + sb->cfg.layer_stream_name, streamFile);
|
|
|
|
@ -1473,11 +1685,17 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
|
|
|
|
if (sb->type == UBI_SEQUENCE)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (sb->is_ps2_old) {
|
|
|
|
|
/* early PS2 games don't support different codecs, it's always PSX ADPCM */
|
|
|
|
|
sb->codec = RAW_PSX;
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* in early versions, this is a bitfield with either 1 or 2 rightmost bits being flags */
|
|
|
|
|
sb->stream_type >>= sb->cfg.num_codec_flags;
|
|
|
|
|
|
|
|
|
|
if (sb->cfg.default_codec_for_group0 && sb->type == UBI_AUDIO && sb->group_id == 0) {
|
|
|
|
|
/* early Xbox games contain garbage in stream_type field in this case, it seems that 0x00 is assumed */
|
|
|
|
|
/* some Xbox games contain garbage in stream_type field in this case, it seems that 0x00 is assumed */
|
|
|
|
|
sb->stream_type = 0x00;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1560,6 +1778,9 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
|
|
|
|
|
|
|
|
|
case 0x02:
|
|
|
|
|
switch (sb->platform) {
|
|
|
|
|
case UBI_PC:
|
|
|
|
|
sb->codec = UBI_ADPCM;
|
|
|
|
|
break;
|
|
|
|
|
case UBI_PS3:
|
|
|
|
|
sb->codec = RAW_PSX; /* PS3 */
|
|
|
|
|
break;
|
|
|
|
@ -1567,8 +1788,8 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
|
|
|
|
sb->codec = UBI_IMA_SCE;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
sb->codec = UBI_ADPCM;
|
|
|
|
|
break;
|
|
|
|
|
VGM_LOG("UBI SB: unknown codec for stream_type %02x\n", sb->stream_type);
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
@ -1604,7 +1825,7 @@ static int parse_stream_codec(ubi_sb_header * sb) {
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 0x08:
|
|
|
|
|
sb->codec = FMT_AT3;
|
|
|
|
|
sb->codec = FMT_AT3; /* PS3 */
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
@ -1626,6 +1847,9 @@ static int parse_offsets(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
if (sb->type == UBI_SEQUENCE)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
if (sb->is_blk)
|
|
|
|
|
return blk_parse_offsets(sb);
|
|
|
|
|
|
|
|
|
|
VGM_ASSERT(!sb->is_map && sb->section3_num > 2, "UBI SB: section3 > 2 found\n");
|
|
|
|
|
|
|
|
|
|
if (sb->is_external)
|
|
|
|
@ -1661,7 +1885,7 @@ static int parse_offsets(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
uint32_t table2_num = read_32bit(offset + 0x10, streamFile);
|
|
|
|
|
|
|
|
|
|
for (j = 0; j < table_num; j++) {
|
|
|
|
|
int index = read_32bit(table_offset + 0x08 * j + 0x00, streamFile) & 0x0000FFFF;
|
|
|
|
|
int index = read_32bit(table_offset + 0x08 * j + 0x00, streamFile) & 0x7FFFFFFF;
|
|
|
|
|
|
|
|
|
|
if (index == sb->header_index) {
|
|
|
|
|
sb->stream_offset = read_32bit(table_offset + 0x08 * j + 0x04, streamFile);
|
|
|
|
@ -1680,8 +1904,7 @@ static int parse_offsets(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
if (sb->stream_offset)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
} else {
|
|
|
|
|
/* banks store internal sounds after all headers and adjusted by the group table, find the matching entry */
|
|
|
|
|
|
|
|
|
|
off_t sounds_offset = sb->section3_offset + sb->cfg.section3_entry_size*sb->section3_num;
|
|
|
|
@ -1899,6 +2122,17 @@ static void config_sb_audio_fb(ubi_sb_header * sb, off_t flag_bits, int external
|
|
|
|
|
sb->cfg.audio_group_and = group_and;
|
|
|
|
|
sb->cfg.audio_loop_and = loop_and;
|
|
|
|
|
}
|
|
|
|
|
static void config_sb_audio_fb_ps2_old(ubi_sb_header* sb, off_t flag_bits, int external_and, int loop_and, int loc_and, int stereo_and) {
|
|
|
|
|
/* audio header with bit flags */
|
|
|
|
|
sb->cfg.audio_external_flag = flag_bits;
|
|
|
|
|
sb->cfg.audio_loop_flag = flag_bits;
|
|
|
|
|
sb->cfg.audio_loc_flag = flag_bits;
|
|
|
|
|
sb->cfg.audio_stereo_flag = flag_bits;
|
|
|
|
|
sb->cfg.audio_external_and = external_and;
|
|
|
|
|
sb->cfg.audio_loop_and = loop_and;
|
|
|
|
|
sb->cfg.audio_loc_and = loc_and;
|
|
|
|
|
sb->cfg.audio_stereo_and = stereo_and;
|
|
|
|
|
}
|
|
|
|
|
static void config_sb_audio_hs(ubi_sb_header * sb, off_t channels, off_t sample_rate, off_t num_samples, off_t num_samples2, off_t stream_name, off_t stream_type) {
|
|
|
|
|
/* audio header with stream name */
|
|
|
|
|
sb->cfg.audio_channels = channels;
|
|
|
|
@ -1928,6 +2162,10 @@ static void config_sb_sequence(ubi_sb_header * sb, off_t sequence_count, off_t e
|
|
|
|
|
sb->cfg.sequence_sequence_loop = sequence_count - 0x0c;
|
|
|
|
|
sb->cfg.sequence_sequence_single= sequence_count - 0x08;
|
|
|
|
|
}
|
|
|
|
|
if (sb->is_blk) {
|
|
|
|
|
sb->cfg.sequence_sequence_loop = sequence_count - 0x14;
|
|
|
|
|
sb->cfg.sequence_sequence_single= sequence_count - 0x0c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
static void config_sb_layer_hs(ubi_sb_header * sb, off_t layer_count, off_t stream_size, off_t stream_offset, off_t stream_name) {
|
|
|
|
|
/* layer headers with stream name */
|
|
|
|
@ -2085,8 +2323,11 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
sb->cfg.map_version = 3;
|
|
|
|
|
|
|
|
|
|
sb->cfg.map_entry_size = (sb->cfg.map_version < 2) ? 0x30 : 0x34;
|
|
|
|
|
if (sb->is_blk) {
|
|
|
|
|
sb->cfg.map_entry_size = 0x30;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sb->version == 0x00000000 || sb->version == 0x00000200) {
|
|
|
|
|
if (sb->version == 0x00000000 || sb->version == 0x00000200 || sb->is_blk) {
|
|
|
|
|
sb->cfg.audio_stream_size = 0x0c;
|
|
|
|
|
sb->cfg.audio_stream_offset = 0x10;
|
|
|
|
|
//sb->cfg.audio_extra_offset = 0x10;
|
|
|
|
@ -2179,7 +2420,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Tonic Trouble Special Edition (1999)(PC)-bnm */
|
|
|
|
|
/* Tonic Trouble Special Edition (1998)(PC)-bnm */
|
|
|
|
|
if (sb->version == 0x00000000 && sb->platform == UBI_PC && is_ttse_pc) {
|
|
|
|
|
config_sb_entry(sb, 0x20, 0x5c);
|
|
|
|
|
|
|
|
|
@ -2237,6 +2478,38 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Donald Duck: Goin' Quackers (2000)(PS2)-blk */
|
|
|
|
|
/* The Jungle Book Rhythm N'Groove (PS2)-blk */
|
|
|
|
|
if (sb->version == 0x00000003 && sb->platform == UBI_PS2 && sb->is_blk) {
|
|
|
|
|
config_sb_entry(sb, 0x20, 0x40);
|
|
|
|
|
|
|
|
|
|
config_sb_audio_fb_ps2_old(sb, 0x18, (1 << 4), (1 << 5), (1 << 6), (1 << 7));
|
|
|
|
|
config_sb_audio_hs(sb, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00);
|
|
|
|
|
sb->cfg.audio_interleave = 0x800;
|
|
|
|
|
sb->is_ps2_old = 1; /* yikes */
|
|
|
|
|
|
|
|
|
|
config_sb_sequence(sb, 0x2c, 0x18); /* this is normal enough */
|
|
|
|
|
|
|
|
|
|
config_sb_layer_hs(sb, 0x1c, 0x0c, 0x10, 0x00);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Batman: Vengeance (2001)(PS2)-map */
|
|
|
|
|
/* Disney's Tarzan: Untamed (2001)(PS2)-map */
|
|
|
|
|
if (sb->version == 0x00000003 && sb->platform == UBI_PS2) {
|
|
|
|
|
config_sb_entry(sb, 0x30, 0x3c);
|
|
|
|
|
|
|
|
|
|
config_sb_audio_fb_ps2_old(sb, 0x1c, (1 << 4), (1 << 5), (1 << 6), (1 << 7));
|
|
|
|
|
config_sb_audio_hs(sb, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00);
|
|
|
|
|
sb->cfg.audio_interleave = 0x800;
|
|
|
|
|
sb->is_ps2_old = 1;
|
|
|
|
|
|
|
|
|
|
config_sb_sequence(sb, 0x2c, 0x18);
|
|
|
|
|
|
|
|
|
|
config_sb_layer_hs(sb, 0x20, 0x0c, 0x14, 0x00);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disney's Tarzan: Untamed (2001)(GC)-map */
|
|
|
|
|
/* Batman: Vengeance (2001)(GC)-map */
|
|
|
|
|
/* Donald Duck: Goin' Quackers (2002)(GC)-map */
|
|
|
|
@ -2253,26 +2526,6 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
//todo too weird
|
|
|
|
|
/* Batman: Vengeance (2001)(PS2)-map */
|
|
|
|
|
/* Disney's Tarzan: Untamed (2001)(PS2)-map */
|
|
|
|
|
if (sb->version == 0x00000003 && sb->platform == UBI_PS2) {
|
|
|
|
|
config_sb_entry(sb, 0x30, 0x3c);
|
|
|
|
|
|
|
|
|
|
config_sb_audio_fb(sb, 0x1c, (1 << 2), (1 << 3), (1 << 4)); /* not ok */
|
|
|
|
|
config_sb_audio_hs(sb, 0x00, 0x24, 0x28, 0x28, 0x00, 0x00);
|
|
|
|
|
/* channels: 0? maybe 2=external, 1=internal? */
|
|
|
|
|
/* stream type: always PS-ADPCM (interleave unknown) */
|
|
|
|
|
/* sb->cfg.audio_stream_string = "STRM.SM1"; */ /* fixed */
|
|
|
|
|
|
|
|
|
|
config_sb_sequence(sb, 0x2c, 0x10); /* this is normal enough */
|
|
|
|
|
|
|
|
|
|
/* layers have a weird format too */
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
//todo group flags and maybe num_samples for sfx are off
|
|
|
|
|
/* Myst III: Exile (2001)(PS2)-map */
|
|
|
|
@ -2333,7 +2586,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Splinter Cell (2002)(PS2)-map */
|
|
|
|
|
/* Splinter Cell: Pandora Tomorrow (2006)(PS2)-map 0x00000007 */
|
|
|
|
|
/* Splinter Cell: Pandora Tomorrow (2004)(PS2)-map */
|
|
|
|
|
if (sb->version == 0x00000007 && sb->platform == UBI_PS2) {
|
|
|
|
|
config_sb_entry(sb, 0x40, 0x70);
|
|
|
|
|
|
|
|
|
@ -2373,7 +2626,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tom Clancy's Rainbow Six 3: Raven Shield + addons (2003)(PC)-bank 0x0000000B */
|
|
|
|
|
/* Tom Clancy's Rainbow Six 3: Raven Shield + addons (2003)(PC)-bank */
|
|
|
|
|
if (sb->version == 0x0000000B && sb->platform == UBI_PC) {
|
|
|
|
|
config_sb_entry(sb, 0x5c, 0x7c);
|
|
|
|
|
|
|
|
|
@ -2388,7 +2641,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prince of Persia: The Sands of Time Demo (2003)(Xbox)-bank 0x0000000D */
|
|
|
|
|
/* Prince of Persia: The Sands of Time (Demo)(2003)(Xbox)-bank */
|
|
|
|
|
if (sb->version == 0x0000000D && sb->platform == UBI_XBOX) {
|
|
|
|
|
config_sb_entry(sb, 0x5c, 0x74);
|
|
|
|
|
|
|
|
|
@ -2396,21 +2649,21 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
config_sb_audio_hs(sb, 0x46, 0x40, 0x2c, 0x34, 0x4c, 0x48);
|
|
|
|
|
sb->cfg.audio_has_internal_names = 1;
|
|
|
|
|
|
|
|
|
|
config_sb_sequence(sb, 0x28, 0x34);
|
|
|
|
|
//config_sb_sequence(sb, 0x28, 0x34);
|
|
|
|
|
|
|
|
|
|
config_sb_layer_hs(sb, 0x20, 0x60, 0x58, 0x30);
|
|
|
|
|
config_sb_layer_sh(sb, 0x14, 0x00, 0x06, 0x08, 0x10);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prince of Persia: The Sands of Time Demo (2003)(Xbox)-bank 0x000A0000 */
|
|
|
|
|
/* Prince of Persia: The Sands of Time (Demo)(2003)(Xbox)-bank */
|
|
|
|
|
if (sb->version == 0x000A0000 && sb->platform == UBI_XBOX) {
|
|
|
|
|
config_sb_entry(sb, 0x64, 0x78);
|
|
|
|
|
|
|
|
|
|
config_sb_audio_fs(sb, 0x24, 0x28, 0x2c);
|
|
|
|
|
config_sb_audio_hs(sb, 0x4a, 0x44, 0x30, 0x38, 0x50, 0x4c);
|
|
|
|
|
|
|
|
|
|
config_sb_sequence(sb, 0x28, 0x14);
|
|
|
|
|
//config_sb_sequence(sb, 0x28, 0x14);
|
|
|
|
|
|
|
|
|
|
config_sb_layer_hs(sb, 0x20, 0x60, 0x58, 0x30);
|
|
|
|
|
config_sb_layer_sh(sb, 0x14, 0x00, 0x06, 0x08, 0x10);
|
|
|
|
@ -2448,7 +2701,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
/* Tom Clancy's Rainbow Six 3 (2003)(PS2)-bank 0x000A0007 */
|
|
|
|
|
/* Tom Clancy's Ghost Recon 2 (2004)(PS2)-bank 0x000A0007 */
|
|
|
|
|
/* Splinter Cell: Pandora Tomorrow (2006)(PS2)-bank 0x000A0008 (separate banks from main map) */
|
|
|
|
|
/* Prince of Persia: Warrior Within Demo (2004)(PS2)-bank 0x00100000 */
|
|
|
|
|
/* Prince of Persia: Warrior Within (Demo)(2004)(PS2)-bank 0x00100000 */
|
|
|
|
|
/* Prince of Persia: Warrior Within (2004)(PS2)-bank 0x00120009 */
|
|
|
|
|
if ((sb->version == 0x000A0002 && sb->platform == UBI_PS2) ||
|
|
|
|
|
(sb->version == 0x000A0004 && sb->platform == UBI_PS2) ||
|
|
|
|
@ -2471,8 +2724,8 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Brothers in Arms: Road to Hill 30 (2005)[PS2] */
|
|
|
|
|
/* Brothers in Arms: Earned in Blood (2005)[PS2] */
|
|
|
|
|
/* Brothers in Arms: Road to Hill 30 (2005)(PS2) */
|
|
|
|
|
/* Brothers in Arms: Earned in Blood (2005)(PS2) */
|
|
|
|
|
if (sb->version == 0x000A0007 && sb->platform == UBI_PS2 && is_bia_ps2) {
|
|
|
|
|
config_sb_entry(sb, 0x5c, 0x14c);
|
|
|
|
|
|
|
|
|
@ -2492,7 +2745,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Batman: Rise of Sin Tzu (2003)(Xbox)-map 0x000A0003 */
|
|
|
|
|
/* Batman: Rise of Sin Tzu (2003)(Xbox)-map */
|
|
|
|
|
if (sb->version == 0x000A0003 && sb->platform == UBI_XBOX) {
|
|
|
|
|
config_sb_entry(sb, 0x64, 0x80);
|
|
|
|
|
|
|
|
|
@ -2546,7 +2799,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tom Clancy's Rainbow Six 3 (2003)(Xbox)-bank 0x000A0007 */
|
|
|
|
|
/* Tom Clancy's Rainbow Six 3 (2003)(Xbox)-bank */
|
|
|
|
|
if (sb->version == 0x000A0007 && sb->platform == UBI_XBOX) {
|
|
|
|
|
config_sb_entry(sb, 0x64, 0x8c);
|
|
|
|
|
|
|
|
|
@ -2564,7 +2817,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Myst IV Demo (2004)(PC)-bank */
|
|
|
|
|
/* Myst IV (Demo)(2004)(PC)-bank */
|
|
|
|
|
if (sb->version == 0x00100000 && sb->platform == UBI_PC) {
|
|
|
|
|
config_sb_entry(sb, 0x68, 0xa4);
|
|
|
|
|
|
|
|
|
@ -2574,7 +2827,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Prince of Persia: Warrior Within Demo (2004)(PC)-bank 0x00120006 */
|
|
|
|
|
/* Prince of Persia: Warrior Within (Demo)(2004)(PC)-bank 0x00120006 */
|
|
|
|
|
/* Prince of Persia: Warrior Within (2004)(PC)-bank 0x00120009 */
|
|
|
|
|
if ((sb->version == 0x00120006 && sb->platform == UBI_PC) ||
|
|
|
|
|
(sb->version == 0x00120009 && sb->platform == UBI_PC)) {
|
|
|
|
@ -2830,7 +3083,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Open Season (2006)(PC)-map 0x00180003 */
|
|
|
|
|
/* Open Season (2006)(PC)-map */
|
|
|
|
|
if (sb->version == 0x00180003 && sb->platform == UBI_PC) {
|
|
|
|
|
config_sb_entry(sb, 0x68, 0x78);
|
|
|
|
|
|
|
|
|
@ -2846,7 +3099,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Open Season (2006)(Xbox)-map 0x00180003 */
|
|
|
|
|
/* Open Season (2006)(Xbox)-map */
|
|
|
|
|
if (sb->version == 0x00180003 && sb->platform == UBI_XBOX) {
|
|
|
|
|
config_sb_entry(sb, 0x48, 0x58);
|
|
|
|
|
|
|
|
|
@ -2862,7 +3115,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Open Season (2006)(GC)-map 0x00180003 */
|
|
|
|
|
/* Open Season (2006)(GC)-map */
|
|
|
|
|
if (sb->version == 0x00180003 && sb->platform == UBI_GC) {
|
|
|
|
|
config_sb_entry(sb, 0x68, 0x6c);
|
|
|
|
|
|
|
|
|
@ -3039,8 +3292,8 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Cranium Kabookii (2007)(Wii)-bank 0x001a0003 */
|
|
|
|
|
if (sb->version == 0x001a0003 && sb->platform == UBI_WII) {
|
|
|
|
|
/* Cranium Kabookii (2007)(Wii)-bank */
|
|
|
|
|
if (sb->version == 0x001A0003 && sb->platform == UBI_WII) {
|
|
|
|
|
config_sb_entry(sb, 0x6c, 0x78);
|
|
|
|
|
|
|
|
|
|
config_sb_audio_fs(sb, 0x2c, 0x30, 0x34);
|
|
|
|
|