mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-28 08:20:54 +01:00
commit
ab807c3416
@ -5,38 +5,52 @@
|
||||
/* EA SNS/SPS blocks */
|
||||
void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
STREAMFILE* streamFile = vgmstream->ch[0].streamfile;
|
||||
uint32_t block_size, block_samples;
|
||||
uint32_t block_id, block_size, block_samples;
|
||||
size_t file_size = get_streamfile_size(streamFile);
|
||||
off_t channel_start;
|
||||
size_t channel_interleave;
|
||||
int i;
|
||||
|
||||
/* always BE */
|
||||
block_size = read_32bitBE(block_offset + 0x00,streamFile);
|
||||
block_samples = read_32bitBE(block_offset + 0x04,streamFile);
|
||||
|
||||
/* EOF */
|
||||
if (block_size == 0 || block_offset >= file_size) {
|
||||
vgmstream->current_block_offset = file_size;
|
||||
vgmstream->next_block_offset = file_size + 0x04;
|
||||
vgmstream->current_block_samples = vgmstream->num_samples;
|
||||
/* EOF reads: signal we have nothing and let the layout fail */
|
||||
if (block_offset >= get_streamfile_size(streamFile)) {
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset;
|
||||
vgmstream->current_block_samples = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
/* always BE */
|
||||
block_size = read_32bitBE(block_offset + 0x00,streamFile);
|
||||
|
||||
/* At 0x00(1): block flag
|
||||
* - in SNS: 0x00=normal block, 0x80=last block (not mandatory)
|
||||
* - in SPS: 0x48=header, 0x44=normal block, 0x45=last block (empty) */
|
||||
block_id = (block_size & 0x00FFFFFF) >> 24;
|
||||
block_size &= 0x00FFFFFF;
|
||||
|
||||
switch(vgmstream->coding_type) {
|
||||
if (block_id == 0x00 || block_id == 0x80 || block_id == 0x44) {
|
||||
block_samples = read_32bitBE(block_offset + 0x04, streamFile);
|
||||
} else {
|
||||
block_samples = 0;
|
||||
}
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
vgmstream->current_block_samples = block_samples;
|
||||
|
||||
/* no need to setup offsets (plus could read over filesize near EOF) */
|
||||
if (block_samples == 0)
|
||||
return;
|
||||
|
||||
switch (vgmstream->coding_type) {
|
||||
case coding_NGC_DSP:
|
||||
/* 0x04: unknown (0x00/02), 0x08: some size?, 0x34: null? */
|
||||
channel_start = read_32bitBE(block_offset+0x08+0x00,streamFile);
|
||||
channel_interleave = read_32bitBE(block_offset+0x08+0x0c,streamFile);
|
||||
channel_start = read_32bitBE(block_offset + 0x08 + 0x00, streamFile);
|
||||
channel_interleave = read_32bitBE(block_offset + 0x08 + 0x0c, streamFile);
|
||||
/* guessed as all known EA DSP only have one block with subheader (maybe changes coefs every block?) */
|
||||
if (channel_start >= 0x40) {
|
||||
dsp_read_coefs_be(vgmstream,streamFile, block_offset+0x08+0x10,0x28);
|
||||
dsp_read_hist_be (vgmstream,streamFile, block_offset+0x08+0x30,0x28);//todo guessed and doesn't fix clicks in full loops
|
||||
dsp_read_coefs_be(vgmstream, streamFile, block_offset + 0x08 + 0x10, 0x28);
|
||||
dsp_read_hist_be(vgmstream, streamFile, block_offset + 0x08 + 0x30, 0x28);//todo guessed and doesn't fix clicks in full loops
|
||||
}
|
||||
break;
|
||||
|
||||
@ -47,15 +61,11 @@ void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) {
|
||||
}
|
||||
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = block_offset + 0x08 + channel_start + i*channel_interleave;
|
||||
vgmstream->ch[i].offset = block_offset + 0x08 + channel_start + i * channel_interleave;
|
||||
|
||||
/* also fix first offset (for EALayer3) */
|
||||
if (block_offset == vgmstream->ch[i].channel_start_offset) {
|
||||
vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset;
|
||||
}
|
||||
}
|
||||
|
||||
vgmstream->current_block_offset = block_offset;
|
||||
vgmstream->next_block_offset = block_offset + block_size;
|
||||
vgmstream->current_block_samples = block_samples;
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint1
|
||||
goto fail;
|
||||
|
||||
num_sounds = read_32bitBE(offset + 0x08, streamFile);
|
||||
if (num_sounds == 0 || target_index > num_sounds)
|
||||
if (num_sounds == 0 || target_index >= num_sounds)
|
||||
goto fail;
|
||||
|
||||
snr_offset = offset + read_32bitBE(offset + 0x0C + 0x04 * target_index, streamFile);
|
||||
@ -311,9 +311,8 @@ fail:
|
||||
|
||||
/* EA SBR/SBS - used in older 7th gen games for storing SFX */
|
||||
VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
|
||||
uint32_t num_sounds, type_desc;
|
||||
uint32_t i, num_sounds, type_desc;
|
||||
uint16_t num_metas, meta_type;
|
||||
uint32_t i;
|
||||
off_t table_offset, types_offset, entry_offset, metas_offset, data_offset, snr_offset, sns_offset;
|
||||
STREAMFILE *sbsFile = NULL, *streamData = NULL;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
@ -343,7 +342,7 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) {
|
||||
|
||||
for (i = 0; i < num_metas; i++) {
|
||||
entry_offset = metas_offset + 0x06 * i;
|
||||
meta_type = read_16bitBE(entry_offset, streamFile);
|
||||
meta_type = read_16bitBE(entry_offset + 0x00, streamFile);
|
||||
data_offset = read_32bitBE(entry_offset + 0x02, streamFile);
|
||||
|
||||
type_desc = read_32bitBE(types_offset + 0x06 * meta_type, streamFile);
|
||||
@ -498,7 +497,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
|
||||
uint32_t num_sounds;
|
||||
uint8_t version, sub_version, block_id;
|
||||
off_t table_offset, entry_offset, snr_offset, sns_offset;
|
||||
size_t /*snr_size,*/ sns_size;
|
||||
/* size_t snr_size sns_size; */
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*);
|
||||
STREAMFILE *musFile = NULL;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
@ -548,8 +547,10 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
|
||||
entry_offset = table_offset + (target_stream - 1) * 0x1c;
|
||||
snr_offset = read_32bit(entry_offset + 0x08, musFile) * 0x10;
|
||||
sns_offset = read_32bit(entry_offset + 0x0c, musFile) * 0x80;
|
||||
//snr_size = read_32bit(entry_offset + 0x10, musFile);
|
||||
/*
|
||||
snr_size = read_32bit(entry_offset + 0x10, musFile);
|
||||
sns_size = read_32bit(entry_offset + 0x14, musFile);
|
||||
*/
|
||||
|
||||
block_id = read_8bit(sns_offset, musFile);
|
||||
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
|
||||
@ -560,7 +561,6 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_streams = num_sounds;
|
||||
vgmstream->stream_size = sns_size;
|
||||
close_streamfile(musFile);
|
||||
return vgmstream;
|
||||
|
||||
@ -765,7 +765,7 @@ typedef struct {
|
||||
|
||||
static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac);
|
||||
static layered_layout_data* build_layered_eaaudiocore_eaxma(STREAMFILE *streamFile, eaac_header *eaac);
|
||||
|
||||
static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset);
|
||||
|
||||
/* EA newest header from RwAudioCore (RenderWare?) / EAAudioCore library (still generated by sx.exe).
|
||||
* Audio "assets" come in separate RAM headers (.SNR/SPH) and raw blocked streams (.SNS/SPS),
|
||||
@ -832,7 +832,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
eaac.loop_offset = eaac.stream_offset + eaac.loop_offset;
|
||||
}
|
||||
else {
|
||||
/* RAM assets only one block in case in case of full loops */
|
||||
/* RAM assets have only one block in case of full loops */
|
||||
eaac.loop_offset = eaac.stream_offset; /* implicit */
|
||||
}
|
||||
|
||||
@ -1024,9 +1024,13 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamData,start_offset))
|
||||
if (!vgmstream_open_stream(vgmstream, temp_streamFile ? temp_streamFile : streamData, start_offset))
|
||||
goto fail;
|
||||
|
||||
if (eaac.loop_start == 0) {
|
||||
vgmstream->stream_size = calculate_eaac_size(vgmstream, temp_streamFile ? temp_streamFile : streamData, &eaac, start_offset);
|
||||
}
|
||||
|
||||
close_streamfile(temp_streamFile);
|
||||
return vgmstream;
|
||||
|
||||
@ -1038,12 +1042,50 @@ fail:
|
||||
|
||||
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) {
|
||||
switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */
|
||||
case EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED: return 0x10;
|
||||
case EAAC_FLAG_LOOPED: return 0x0C;
|
||||
default: return 0x08;
|
||||
case EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED: return 0x10;
|
||||
case EAAC_FLAG_LOOPED: return 0x0C;
|
||||
default: return 0x08;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset) {
|
||||
uint32_t total_samples;
|
||||
size_t stream_size, file_size;
|
||||
|
||||
switch (eaac->codec) {
|
||||
case EAAC_CODEC_EAXMA:
|
||||
case EAAC_CODEC_EALAYER3_V1:
|
||||
case EAAC_CODEC_EALAYER3_V2_PCM:
|
||||
case EAAC_CODEC_EALAYER3_V2_SPIKE:
|
||||
case EAAC_CODEC_EATRAX:
|
||||
case EAAC_CODEC_EAMP3:
|
||||
case EAAC_CODEC_EAOPUS:
|
||||
stream_size = get_streamfile_size(streamFile);
|
||||
break;
|
||||
default:
|
||||
stream_size = 0;
|
||||
total_samples = 0;
|
||||
file_size = get_streamfile_size(streamFile);
|
||||
vgmstream->next_block_offset = start_offset;
|
||||
|
||||
while (vgmstream->next_block_offset < file_size && total_samples != vgmstream->num_samples) {
|
||||
block_update_ea_sns(vgmstream->next_block_offset, vgmstream);
|
||||
if (vgmstream->current_block_samples == 0)
|
||||
continue;
|
||||
|
||||
/* stream size is almost never provided in bank files so we have to calc it manually */
|
||||
stream_size += vgmstream->next_block_offset - vgmstream->ch[0].offset;
|
||||
total_samples += vgmstream->current_block_samples;
|
||||
}
|
||||
|
||||
/* reset once we're done */
|
||||
block_update(start_offset, vgmstream);
|
||||
break;
|
||||
}
|
||||
|
||||
return stream_size;
|
||||
}
|
||||
|
||||
|
||||
/* Actual looping uses 2 block sections, separated by a block end flag *and* padded.
|
||||
*
|
||||
@ -1109,6 +1151,8 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st
|
||||
|
||||
if (!vgmstream_open_stream(data->segments[i],temp_streamFile[i],0x00))
|
||||
goto fail;
|
||||
|
||||
data->segments[i]->stream_size = calculate_eaac_size(data->segments[i], temp_streamFile[i], eaac, 0x00);
|
||||
}
|
||||
|
||||
if (!setup_layout_segmented(data))
|
||||
|
@ -115,7 +115,7 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
|
||||
|
||||
/* check extension */
|
||||
/* they don't seem enforced by EA's tools but usually:
|
||||
* .asf: ~early (audio stream file?) [ex. Need for Speed (PC)]
|
||||
* .asf: ~early (audio stream file?) [ex. Need for Speed II (PC)]
|
||||
* .lasf: fake for plugins
|
||||
* .str: ~early [ex. FIFA 2002 (PS1)]
|
||||
* .eam: ~mid (fake?)
|
||||
@ -161,6 +161,7 @@ fail:
|
||||
/* EA BNK with variable header - from EA games SFXs; also created by sx.exe */
|
||||
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) {
|
||||
off_t offset;
|
||||
int target_stream = streamFile->stream_index;
|
||||
|
||||
/* check extension */
|
||||
/* .bnk: common
|
||||
@ -177,7 +178,9 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) {
|
||||
else
|
||||
offset = 0x00;
|
||||
|
||||
return parse_bnk_header(streamFile, offset, streamFile->stream_index, 0);
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
|
||||
return parse_bnk_header(streamFile, offset, target_stream - 1, 0);
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
@ -587,7 +590,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) {
|
||||
/* I can't figure it out, so let's just use a workaround for now */
|
||||
|
||||
if (version == 3 && sub_version == 1) { /* SSX Tricky */
|
||||
/* we need to go through the first two sections to find sound table */
|
||||
/* we need to go through the first two sections to find the sound table */
|
||||
sec1_num = read_16bit(0x12, streamFile);
|
||||
sec2_size = read_8bit(0x0d, streamFile) * read_8bit(0x0e, streamFile);
|
||||
sec2_num = read_8bit(0x0f, streamFile);
|
||||
@ -610,6 +613,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) {
|
||||
total_streams = (eof_offset - section_offset) / 0x08;
|
||||
off_mult = 0x04;
|
||||
} else if (version == 3 && sub_version == 4) { /* Harry Potter and the Chamber of Secrets */
|
||||
/* we need to go through the first two sections to find the sound table */
|
||||
sec1_num = read_16bit(0x12, streamFile);
|
||||
sec2_size = read_8bit(0x0d, streamFile) * read_8bit(0x0e, streamFile);
|
||||
sec2_num = read_8bit(0x0f, streamFile);
|
||||
@ -636,7 +640,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus(STREAMFILE *streamFile) {
|
||||
total_streams = (eof_offset - section_offset) / 0x08;
|
||||
off_mult = 0x04;
|
||||
} else if (version == 4) { /* SSX 3, Need for Speed: Underground 2 */
|
||||
/* we need to go through the first two sections to find sound table */
|
||||
/* we need to go through the first two sections to find the sound table */
|
||||
sec1_num = read_16bit(0x12, streamFile);
|
||||
sec2_num = read_8bit(0x0f, streamFile);
|
||||
|
||||
@ -724,37 +728,37 @@ fail:
|
||||
|
||||
/* EA BNK with variable header - from EA games SFXs; also created by sx.exe */
|
||||
static VGMSTREAM * parse_bnk_header(STREAMFILE *streamFile, off_t offset, int target_stream, int is_embedded) {
|
||||
uint32_t i;
|
||||
uint16_t num_sounds;
|
||||
off_t header_offset, start_offset, test_offset, table_offset;
|
||||
size_t header_size;
|
||||
ea_header ea = {0};
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*) = NULL;
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = NULL;
|
||||
ea_header ea = { 0 };
|
||||
int32_t(*read_32bit)(off_t, STREAMFILE*) = NULL;
|
||||
int16_t(*read_16bit)(off_t, STREAMFILE*) = NULL;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
int i, bnk_version;
|
||||
int total_bnk_sounds, real_bnk_sounds = 0;
|
||||
int bnk_version;
|
||||
int real_bnk_sounds = 0;
|
||||
|
||||
/* check header */
|
||||
/* BNK header endianness is platform-native */
|
||||
if (read_32bitBE(offset + 0x00, streamFile) == EA_BNK_HEADER_BE) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
}
|
||||
else if (read_32bitBE(offset + 0x00, streamFile) == EA_BNK_HEADER_LE) {
|
||||
} else if (read_32bitBE(offset + 0x00, streamFile) == EA_BNK_HEADER_LE) {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
bnk_version = read_8bit(offset + 0x04,streamFile);
|
||||
total_bnk_sounds = read_16bit(offset + 0x06,streamFile);
|
||||
bnk_version = read_8bit(offset + 0x04, streamFile);
|
||||
num_sounds = read_16bit(offset + 0x06, streamFile);
|
||||
|
||||
/* check multi-streams */
|
||||
switch(bnk_version) {
|
||||
switch (bnk_version) {
|
||||
case 0x02: /* early [Need For Speed II (PC/PS1), FIFA 98 (PC/PS1/SAT)] */
|
||||
table_offset = 0x0c;
|
||||
header_size = read_32bit(offset + 0x08,streamFile); /* full size */
|
||||
header_size = read_32bit(offset + 0x08, streamFile); /* full size */
|
||||
break;
|
||||
|
||||
case 0x04: /* mid (last used in PSX banks) */
|
||||
@ -769,32 +773,30 @@ static VGMSTREAM * parse_bnk_header(STREAMFILE *streamFile, off_t offset, int ta
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
header_offset = 0;
|
||||
|
||||
for (i = 0; i < total_bnk_sounds; i++) {
|
||||
/* some of these are dummies with zero offset */
|
||||
test_offset = read_32bit(offset + table_offset + 0x04 * i, streamFile);
|
||||
if (is_embedded) {
|
||||
if (target_stream < 0 || target_stream >= num_sounds)
|
||||
goto fail;
|
||||
|
||||
if (test_offset != 0) {
|
||||
real_bnk_sounds++;
|
||||
header_offset = read_32bit(offset + table_offset + 0x04 * target_stream, streamFile);
|
||||
} else {
|
||||
/* some of these are dummies with zero offset, skip them when opening standalone BNK */
|
||||
for (i = 0; i < num_sounds; i++) {
|
||||
test_offset = read_32bit(offset + table_offset + 0x04 * i, streamFile);
|
||||
|
||||
/* ABK points at absolute indexes, i.e. with dummies included */
|
||||
if (is_embedded != 0) {
|
||||
if (target_stream - 1 == i)
|
||||
header_offset = offset + table_offset + 0x04 * i + test_offset;
|
||||
}
|
||||
else {
|
||||
/* Ignore dummy streams when opening standalone BNK files */
|
||||
if (test_offset != 0) {
|
||||
if (target_stream == real_bnk_sounds)
|
||||
header_offset = offset + table_offset + 0x04 * i + test_offset;
|
||||
|
||||
real_bnk_sounds++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (target_stream < 0 || header_offset == 0 || real_bnk_sounds < 1) goto fail;
|
||||
if (header_offset == 0) goto fail;
|
||||
|
||||
if (!parse_variable_header(streamFile,&ea, header_offset, header_size - header_offset, bnk_version))
|
||||
if (!parse_variable_header(streamFile, &ea, header_offset, header_size - header_offset, bnk_version))
|
||||
goto fail;
|
||||
|
||||
/* fix absolute offsets so it works in next funcs */
|
||||
@ -843,22 +845,22 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* BNKs usually have absolute offsets for all channels ("full" interleave) except in some versions */
|
||||
if (vgmstream->channels > 1 && ea->codec1 == EA_CODEC1_PCM) {
|
||||
int interleave = (vgmstream->num_samples * (ea->bps == 8 ? 0x01 : 0x02)); /* full interleave */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
if (ea->channels > 1 && ea->codec1 == EA_CODEC1_PCM) {
|
||||
int interleave = (ea->num_samples * (ea->bps == 8 ? 0x01 : 0x02)); /* full interleave */
|
||||
for (i = 0; i < ea->channels; i++) {
|
||||
ea->offsets[i] = ea->offsets[0] + interleave*i;
|
||||
}
|
||||
}
|
||||
else if (vgmstream->channels > 1 && ea->codec1 == EA_CODEC1_VAG) {
|
||||
int interleave = (vgmstream->num_samples / 28 * 16); /* full interleave */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
else if (ea->channels > 1 && ea->codec1 == EA_CODEC1_VAG) {
|
||||
int interleave = (ea->num_samples / 28 * 16); /* full interleave */
|
||||
for (i = 0; i < ea->channels; i++) {
|
||||
ea->offsets[i] = ea->offsets[0] + interleave*i;
|
||||
}
|
||||
}
|
||||
else if (vgmstream->channels > 1 && ea->codec2 == EA_CODEC2_GCADPCM && ea->offsets[0] == ea->offsets[1]) {
|
||||
else if (ea->channels > 1 && ea->codec2 == EA_CODEC2_GCADPCM && ea->offsets[0] == ea->offsets[1]) {
|
||||
/* pcstream+gcadpcm with sx.exe v2, this is probably a bug (even with this parts of the wave are off) */
|
||||
int interleave = (vgmstream->num_samples / 14 * 8); /* full interleave */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
int interleave = (ea->num_samples / 14 * 8); /* full interleave */
|
||||
for (i = 0; i < ea->channels; i++) {
|
||||
ea->offsets[i] = ea->offsets[0] + interleave*i;
|
||||
}
|
||||
}
|
||||
@ -893,7 +895,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
break;
|
||||
|
||||
case EA_CODEC2_S16LE: /* PCM16LE */
|
||||
if (ea->version > 0) {
|
||||
if (ea->version > EA_VERSION_V0) {
|
||||
vgmstream->coding_type = coding_PCM16LE;
|
||||
} else { /* Need for Speed III: Hot Pursuit (PC) */
|
||||
vgmstream->coding_type = coding_PCM16_int;
|
||||
@ -915,7 +917,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
{
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*) = ea->big_endian ? read_16bitBE : read_16bitLE;
|
||||
|
||||
for (ch=0; ch < vgmstream->channels; ch++) {
|
||||
for (ch=0; ch < ea->channels; ch++) {
|
||||
for (i=0; i < 16; i++) { /* actual size 0x21, last byte unknown */
|
||||
vgmstream->ch[ch].adpcm_coef[i] = read_16bit(ea->coefs[ch] + i*2, streamFile);
|
||||
}
|
||||
@ -963,7 +965,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
|
||||
/* make relative loops absolute for the decoder */
|
||||
if (ea->loop_flag) {
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
for (i = 0; i < ea->channels; i++) {
|
||||
ea->loops[i] += ea->offsets[0];
|
||||
}
|
||||
}
|
||||
@ -1030,13 +1032,13 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
// vgmstream->ch[i].offset = ea->offsets[0] + vgmstream->interleave_block_size*i;
|
||||
// }
|
||||
//}
|
||||
else if (vgmstream->coding_type == coding_PCM16_int && ea->version == 0) {
|
||||
/* Need for Speed 2 (PC) bad offsets */
|
||||
else if (vgmstream->coding_type == coding_PCM16_int && ea->version == EA_VERSION_V0) {
|
||||
/* Need for Speed II (PC) bad offsets */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = ea->offsets[0] + 0x02*i;
|
||||
}
|
||||
}
|
||||
else if (vgmstream->coding_type == coding_PCM8 && ea->platform == EA_PLATFORM_PS2 && ea->version == 3) {
|
||||
else if (vgmstream->coding_type == coding_PCM8 && ea->platform == EA_PLATFORM_PS2 && ea->version == EA_VERSION_V3) {
|
||||
/* SSX3 (PS2) weird 0x10 mini header (codec/loop start/loop end/samples) */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
vgmstream->ch[i].offset = ea->offsets[0] + 0x10;
|
||||
@ -1471,7 +1473,7 @@ static void update_ea_stream_size_and_samples(STREAMFILE* streamFile, off_t star
|
||||
* music (.map/lin). Subfiles always share header, except num_samples. */
|
||||
num_samples += vgmstream->current_block_samples;
|
||||
|
||||
/* Stream size is almost never provided in bank files so we have to calc it manually */
|
||||
/* stream size is almost never provided in bank files so we have to calc it manually */
|
||||
stream_size += vgmstream->next_block_offset - vgmstream->ch[0].offset;
|
||||
}
|
||||
}
|
||||
|
@ -1354,7 +1354,22 @@ static int parse_internal_offset(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
* May exist even for external streams only, and they often use id 1 too. */
|
||||
|
||||
if (sb->is_map) {
|
||||
/* maps store internal sounds offsets in a separate subtable, find the matching entry */
|
||||
/* maps store internal sounds offsets in a separate subtable, find the matching entry
|
||||
* each sec3 entry consists of the header and two tables
|
||||
* 0x00: some ID? (always -1 for the first entry)
|
||||
* 0x04: table 1 offset
|
||||
* 0x08: table 1 entries
|
||||
* 0x0c: table 2 offset
|
||||
* 0x10: table 2 entries
|
||||
* table 1 - for each entry:
|
||||
* 0x00: sec2 entry index
|
||||
* 0x04: sound offset
|
||||
* table 2 - for each entry:
|
||||
* 0x00 - group ID
|
||||
* 0x04 - size with padding included
|
||||
* 0x08 - size without padding
|
||||
* 0x0c - absolute group offset */
|
||||
|
||||
for (i = 0; i < sb->section3_num; i++) {
|
||||
off_t offset = sb->section3_offset + 0x14 * i;
|
||||
off_t table_offset = read_32bit(offset + 0x04, streamFile) + sb->section3_offset;
|
||||
@ -1373,11 +1388,8 @@ static int parse_internal_offset(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
|
||||
sb->stream_offset = read_32bit(table_offset + 0x08 * j + 0x04, streamFile);
|
||||
for (k = 0; k < table2_num; k++) {
|
||||
/* entry layout:
|
||||
* 0x00 - group ID
|
||||
* 0x04 - size with padding included
|
||||
* 0x08 - size without padding
|
||||
* 0x0c - absolute offset */ uint32_t id = read_32bit(table2_offset + 0x10 * k + 0x00, streamFile);
|
||||
uint32_t id = read_32bit(table2_offset + 0x10 * k + 0x00, streamFile);
|
||||
|
||||
if (id == sb->group_id) {
|
||||
sb->stream_offset += read_32bit(table2_offset + 0x10 * k + 0x0c, streamFile);
|
||||
break;
|
||||
@ -1987,7 +1999,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Prince of Persia: Sands of Time (2003)(PS2)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
|
||||
/* Prince of Persia: The Sands of Time (2003)(PS2)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
|
||||
/* 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 */
|
||||
@ -2030,7 +2042,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Prince of Persia: Sands of Time (2003)(Xbox)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
|
||||
/* Prince of Persia: The Sands of Time (2003)(Xbox)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
|
||||
if ((sb->version == 0x000A0002 && sb->platform == UBI_XBOX) ||
|
||||
(sb->version == 0x000A0004 && sb->platform == UBI_XBOX)) {
|
||||
config_sb_entry(sb, 0x64, 0x78);
|
||||
@ -2047,7 +2059,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
/* Batman: Rise of Sin Tzu (2003)(GC)-map 0x000A0002 */
|
||||
/* Prince of Persia: Sands of Time (2003)(GC)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
|
||||
/* Prince of Persia: The Sands of Time (2003)(GC)-bank 0x000A0004 / 0x000A0002 (POP1 port) */
|
||||
/* Tom Clancy's Rainbow Six 3 (2003)(Xbox)-bank 0x000A0007 */
|
||||
if ((sb->version == 0x000A0002 && sb->platform == UBI_GC) ||
|
||||
(sb->version == 0x000A0004 && sb->platform == UBI_GC) ||
|
||||
@ -2254,7 +2266,7 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
/* Prince of Persia: The Two Thrones (2005)(Xbox)-bank 0x00150000 */
|
||||
/* Far Cry Instincts (2005)(Xbox)-bank 0x00150000 */
|
||||
/* Splinter Cell: Double Agent (2006)(Xbox)-map 0x00160002 */
|
||||
/* Far cry Instincts: Evolution (2006)(Xbox)-bank 0x00170000 */
|
||||
/* Far Cry Instincts: Evolution (2006)(Xbox)-bank 0x00170000 */
|
||||
if ((sb->version == 0x00150000 && sb->platform == UBI_XBOX) ||
|
||||
(sb->version == 0x00160002 && sb->platform == UBI_XBOX) ||
|
||||
(sb->version == 0x00170000 && sb->platform == UBI_XBOX)) {
|
||||
@ -2317,6 +2329,49 @@ static int config_sb_version(ubi_sb_header * sb, STREAMFILE *streamFile) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open Season (2006)(PC)-map 0x00180003 */
|
||||
/* Shaun White Snowboarding (2008)(PC)-map 0x00180003 */
|
||||
if (sb->version == 0x00180003 && sb->platform == UBI_PC) {
|
||||
config_sb_entry(sb, 0x68, 0x78);
|
||||
|
||||
config_sb_audio_fs(sb, 0x2c, 0x34, 0x30);
|
||||
config_sb_audio_he(sb, 0x5c, 0x54, 0x40, 0x48, 0x64, 0x60);
|
||||
|
||||
config_sb_sequence(sb, 0x2c, 0x14);
|
||||
|
||||
config_sb_layer_he(sb, 0x20, 0x38, 0x3c, 0x44);
|
||||
config_sb_layer_sh(sb, 0x34, 0x00, 0x08, 0x0c, 0x14);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open Season (2006)(Xbox)-map 0x00180003 */
|
||||
if (sb->version == 0x00180003 && sb->platform == UBI_XBOX) {
|
||||
config_sb_entry(sb, 0x48, 0x58);
|
||||
|
||||
config_sb_audio_fb(sb, 0x20, (1 << 3), (1 << 4), (1 << 10));
|
||||
config_sb_audio_he(sb, 0x44, 0x3c, 0x28, 0x30, 0x4c, 0x48);
|
||||
|
||||
config_sb_sequence(sb, 0x2c, 0x10);
|
||||
|
||||
config_sb_layer_he(sb, 0x20, 0x2c, 0x30, 0x38);
|
||||
config_sb_layer_sh(sb, 0x34, 0x00, 0x08, 0x0c, 0x14);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Open Season (2006)(GC)-map 0x00180003 */
|
||||
if (sb->version == 0x00180003 && sb->platform == UBI_GC) {
|
||||
config_sb_entry(sb, 0x68, 0x6c);
|
||||
|
||||
config_sb_audio_fs(sb, 0x28, 0x2c, 0x30);
|
||||
config_sb_audio_he(sb, 0x58, 0x50, 0x3c, 0x44, 0x60, 0x5c);
|
||||
|
||||
config_sb_sequence(sb, 0x2c, 0x14);
|
||||
|
||||
config_sb_layer_he(sb, 0x20, 0x38, 0x3c, 0x44);
|
||||
config_sb_layer_sh(sb, 0x34, 0x00, 0x08, 0x0c, 0x14);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Splinter Cell: Double Agent (2006)(PC)-map */
|
||||
if (sb->version == 0x00180006 && sb->platform == UBI_PC) {
|
||||
config_sb_entry(sb, 0x68, 0x7c);
|
||||
|
Loading…
Reference in New Issue
Block a user