mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-17 23:36:41 +01:00
Merge pull request #265 from NicknineTheEagle/ea-formats
More EA formats
This commit is contained in:
commit
637ec27998
@ -251,7 +251,7 @@ void ffmpeg_set_skip_samples(ffmpeg_codec_data * data, int skip_samples);
|
||||
|
||||
|
||||
size_t ffmpeg_make_opus_header(uint8_t * buf, int buf_size, int channels, int skip, int sample_rate);
|
||||
size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t real_size, STREAMFILE *streamFile);
|
||||
size_t ffmpeg_get_eaxma_virtual_size(int channels, int streamed, off_t real_offset, size_t real_size, STREAMFILE *streamFile);
|
||||
|
||||
size_t switch_opus_get_samples(off_t offset, size_t data_size, int sample_rate, STREAMFILE *streamFile);
|
||||
|
||||
|
@ -199,7 +199,7 @@ int64_t ffmpeg_custom_size_eaxma(ffmpeg_codec_data *data) {
|
||||
}
|
||||
|
||||
/* needed to know in meta for fake RIFF */
|
||||
size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t real_size, STREAMFILE *streamFile) {
|
||||
size_t ffmpeg_get_eaxma_virtual_size(int channels, int streamed, off_t real_offset, size_t real_size, STREAMFILE *streamFile) {
|
||||
size_t virtual_size = 0;
|
||||
size_t real_end_offset = real_offset + real_size;
|
||||
/* EA-XMA always uses late XMA2 streams (2ch + ... + 1/2ch) */
|
||||
@ -219,7 +219,6 @@ size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t rea
|
||||
if (block_flag == 0x45) /* exit on last block just in case (v1/SPS, empty) */
|
||||
break;
|
||||
|
||||
|
||||
max_packets = get_block_max_packets(num_streams, packets_offset, streamFile);
|
||||
if (max_packets == 0) goto fail;
|
||||
|
||||
@ -228,7 +227,7 @@ size_t ffmpeg_get_eaxma_virtual_size(int channels, off_t real_offset, size_t rea
|
||||
|
||||
real_offset += block_size;
|
||||
|
||||
if (block_flag == 0x80) /* exit on last block just in case (v0/SNS, full) */
|
||||
if (!streamed || block_flag == 0x80) /* exit on last block just in case (v0/SNS, full) */
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -159,6 +159,7 @@ static const char* extension_list[] = {
|
||||
"iadp",
|
||||
"idsp",
|
||||
"idvi", //fake extension for .pcm (to be removed)
|
||||
"idx",
|
||||
"ikm",
|
||||
"ild",
|
||||
"int",
|
||||
|
@ -6,6 +6,8 @@
|
||||
/* EAAudioCore formats, EA's current audio middleware */
|
||||
|
||||
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type);
|
||||
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset);
|
||||
static VGMSTREAM *parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset);
|
||||
|
||||
/* .SNR+SNS - from EA latest games (~2008-2013), v0 header */
|
||||
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
|
||||
@ -18,14 +20,7 @@ VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
|
||||
|
||||
/* SNR headers normally need an external SNS file, but some have data [Burnout Paradise, NFL2013 (iOS)] */
|
||||
if (get_streamfile_size(streamFile) > 0x10) {
|
||||
off_t start_offset;
|
||||
|
||||
switch(read_8bit(0x04,streamFile)) { /* flags */
|
||||
case 0x60: start_offset = 0x10; break;
|
||||
case 0x20: start_offset = 0x0c; break;
|
||||
default: start_offset = 0x08; break;
|
||||
}
|
||||
|
||||
off_t start_offset = get_snr_size(streamFile, 0x00);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, 0x00, start_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream) goto fail;
|
||||
}
|
||||
@ -155,6 +150,288 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA HDR/STH/DAT - seen in early 7th-gen games, used for storing speech */
|
||||
VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
|
||||
int target_stream = streamFile->stream_index;
|
||||
uint8_t userdata_size, total_sounds, block_id;
|
||||
uint8_t i;
|
||||
off_t snr_offset, sns_offset;
|
||||
size_t file_size, block_size;
|
||||
STREAMFILE *datFile = NULL, *sthFile = NULL;
|
||||
VGMSTREAM *vgmstream;
|
||||
|
||||
/* 0x00: ID */
|
||||
/* 0x02: userdata size */
|
||||
/* 0x03: number of files */
|
||||
/* 0x04: sub-ID (used for different police voices in NFS games) */
|
||||
/* 0x08: alt number of files? */
|
||||
/* 0x09: zero */
|
||||
/* 0x0A: ??? */
|
||||
/* 0x0C: zero */
|
||||
/* 0x10: table start */
|
||||
|
||||
sthFile = open_streamfile_by_ext(streamFile, "sth");
|
||||
if (!sthFile)
|
||||
goto fail;
|
||||
|
||||
datFile = open_streamfile_by_ext(streamFile, "dat");
|
||||
if (!datFile)
|
||||
goto fail;
|
||||
|
||||
/* STH always starts with the first offset of zero */
|
||||
sns_offset = read_32bitLE(0x00, sthFile);
|
||||
if (sns_offset != 0)
|
||||
goto fail;
|
||||
|
||||
/* check if DAT starts with a correct SNS block */
|
||||
block_id = read_8bit(0x00, datFile);
|
||||
if (block_id != 0x00 && block_id != 0x80)
|
||||
goto fail;
|
||||
|
||||
userdata_size = read_8bit(0x02, streamFile);
|
||||
total_sounds = read_8bit(0x03, streamFile);
|
||||
if (read_8bit(0x08, streamFile) > total_sounds)
|
||||
goto fail;
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0 || total_sounds == 0 || target_stream > total_sounds)
|
||||
goto fail;
|
||||
|
||||
/* offsets in HDR are always big endian */
|
||||
//snr_offset = (off_t)read_16bitBE(0x10 + (0x02+userdata_size) * (target_stream-1), streamFile) + 0x04;
|
||||
//sns_offset = read_32bit(snr_offset, sthFile);
|
||||
|
||||
/* we can't reliably detect byte endianness so we're going to find the sound the hacky way */
|
||||
/* go through blocks until we reach the goal sound */
|
||||
file_size = get_streamfile_size(datFile);
|
||||
snr_offset = 0;
|
||||
sns_offset = 0;
|
||||
|
||||
for (i = 0; i < total_sounds; i++) {
|
||||
snr_offset = (off_t)read_16bitBE(0x10 + (0x02+userdata_size) * i, streamFile) + 0x04;
|
||||
|
||||
if (i == target_stream - 1)
|
||||
break;
|
||||
|
||||
while (true) {
|
||||
if (sns_offset >= file_size)
|
||||
goto fail;
|
||||
|
||||
block_id = read_8bit(sns_offset, datFile);
|
||||
block_size = read_32bitBE(sns_offset, datFile) & 0x00FFFFFF;
|
||||
if (block_size == 0)
|
||||
goto fail;
|
||||
|
||||
if (block_id != 0x00 && block_id != 0x80)
|
||||
goto fail;
|
||||
|
||||
sns_offset += block_size;
|
||||
|
||||
if (block_id == 0x80)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
block_id = read_8bit(sns_offset, datFile);
|
||||
if (block_id != 0x00 && block_id != 0x80)
|
||||
goto fail;
|
||||
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(sthFile, datFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_streams = total_sounds;
|
||||
close_streamfile(sthFile);
|
||||
close_streamfile(datFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(sthFile);
|
||||
close_streamfile(datFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA ABK - ABK header seems to be same as in the old games but the sound table is different and it contains SNR/SNS sounds instead */
|
||||
VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
|
||||
int is_dupe, total_sounds = 0, target_stream = streamFile->stream_index;
|
||||
off_t bnk_offset, header_table_offset, base_offset, unk_struct_offset, table_offset, snd_entry_offset, ast_offset;
|
||||
off_t num_entries_off, base_offset_off, entries_off, sound_table_offset_off;
|
||||
uint32_t i, j, k, version, num_sounds, total_sound_tables;
|
||||
uint16_t num_tables, bnk_index, bnk_target_index;
|
||||
uint8_t num_entries, extra_entries;
|
||||
off_t sound_table_offsets[0x2000];
|
||||
STREAMFILE *astData = NULL;
|
||||
VGMSTREAM *vgmstream;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*);
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*);
|
||||
|
||||
/* check extension */
|
||||
if (!check_extensions(streamFile, "abk"))
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, streamFile) != 0x41424B43) /* "ABKC" */
|
||||
goto fail;
|
||||
|
||||
version = read_32bitBE(0x04, streamFile);
|
||||
if (version != 0x01010202)
|
||||
goto fail;
|
||||
|
||||
/* use table offset to check endianness */
|
||||
if (guess_endianness32bit(0x1C,streamFile)) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0)
|
||||
goto fail;
|
||||
|
||||
num_tables = read_16bit(0x0A, streamFile);
|
||||
header_table_offset = read_32bit(0x1C, streamFile);
|
||||
bnk_offset = read_32bit(0x20, streamFile);
|
||||
total_sound_tables = 0;
|
||||
bnk_target_index = 0xFFFF;
|
||||
|
||||
/* set up some common values */
|
||||
if (header_table_offset == 0x5C) {
|
||||
/* the usual variant */
|
||||
num_entries_off = 0x24;
|
||||
base_offset_off = 0x2C;
|
||||
entries_off = 0x3C;
|
||||
sound_table_offset_off = 0x04;
|
||||
}
|
||||
else if (header_table_offset == 0x78) {
|
||||
/* FIFA 08 has a bunch of extra zeroes all over the place, don't know what's up with that */
|
||||
num_entries_off = 0x40;
|
||||
base_offset_off = 0x54;
|
||||
entries_off = 0x68;
|
||||
sound_table_offset_off = 0x0C;
|
||||
}
|
||||
else {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < num_tables; i++) {
|
||||
num_entries = read_8bit(header_table_offset + num_entries_off, streamFile);
|
||||
extra_entries = read_8bit(header_table_offset + num_entries_off + 0x03, streamFile);
|
||||
base_offset = read_32bit(header_table_offset + base_offset_off, streamFile);
|
||||
if (num_entries == 0xff) goto fail; /* EOF read */
|
||||
|
||||
for (j = 0; j < num_entries; j++) {
|
||||
unk_struct_offset = read_32bit(header_table_offset + entries_off + 0x04 * j, streamFile);
|
||||
table_offset = read_32bit(base_offset + unk_struct_offset + sound_table_offset_off, streamFile);
|
||||
|
||||
/* For some reason, there are duplicate entries pointing at the same sound tables */
|
||||
is_dupe = 0;
|
||||
for (k = 0; k < total_sound_tables; k++)
|
||||
{
|
||||
if (table_offset==sound_table_offsets[k])
|
||||
{
|
||||
is_dupe = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dupe)
|
||||
continue;
|
||||
|
||||
sound_table_offsets[total_sound_tables++] = table_offset;
|
||||
num_sounds = read_32bit(table_offset, streamFile);
|
||||
if (num_sounds == 0xffffffff) goto fail; /* EOF read */
|
||||
|
||||
for (k = 0; k < num_sounds; k++) {
|
||||
/* 0x00: sound index */
|
||||
/* 0x02: ??? */
|
||||
/* 0x04: ??? */
|
||||
/* 0x08: streamed data offset */
|
||||
snd_entry_offset = table_offset + 0x04 + 0x0C * k;
|
||||
bnk_index = read_16bit(snd_entry_offset + 0x00, streamFile);
|
||||
|
||||
/* some of these are dummies */
|
||||
if (bnk_index == 0xFFFF)
|
||||
continue;
|
||||
|
||||
total_sounds++;
|
||||
if (target_stream == total_sounds) {
|
||||
bnk_target_index = bnk_index;
|
||||
ast_offset = read_32bit(snd_entry_offset + 0x08, streamFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header_table_offset += entries_off + num_entries * 0x04 + extra_entries * 0x04;
|
||||
}
|
||||
|
||||
if (bnk_target_index == 0xFFFF)
|
||||
goto fail;
|
||||
|
||||
vgmstream = parse_s10a_header(streamFile, bnk_offset, bnk_target_index, ast_offset);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
vgmstream->num_streams = total_sounds;
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA S10A header - seen inside new ABK files. Putting it here in case it's encountered stand-alone. */
|
||||
static VGMSTREAM * parse_s10a_header(STREAMFILE *streamFile, off_t offset, uint16_t target_index, off_t ast_offset) {
|
||||
uint32_t header, num_sounds;
|
||||
off_t snr_offset, sns_offset;
|
||||
STREAMFILE *astFile = NULL;
|
||||
VGMSTREAM *vgmstream;
|
||||
|
||||
/* header is always big endian */
|
||||
/* 0x00 - header magic */
|
||||
/* 0x04 - zero */
|
||||
/* 0x08 - number of files */
|
||||
/* 0x0C - offsets table */
|
||||
header = read_32bitBE(offset + 0x00, streamFile);
|
||||
if (header != 0x53313041) /* "S10A" */
|
||||
goto fail;
|
||||
|
||||
num_sounds = read_32bitBE(offset + 0x08, streamFile);
|
||||
if (num_sounds == 0 || target_index > num_sounds)
|
||||
goto fail;
|
||||
|
||||
snr_offset = offset + read_32bitBE(offset + 0x0C + 0x04 * target_index, streamFile);
|
||||
|
||||
if (ast_offset == 0xFFFFFFFF) {
|
||||
/* RAM asset */
|
||||
sns_offset = snr_offset + get_snr_size(streamFile, snr_offset);
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, streamFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
}
|
||||
else {
|
||||
/* streamed asset */
|
||||
astFile = open_streamfile_by_ext(streamFile, "ast");
|
||||
if (!astFile)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, astFile) != 0x53313053) /* "S10S" */
|
||||
goto fail;
|
||||
|
||||
sns_offset = ast_offset;
|
||||
vgmstream = init_vgmstream_eaaudiocore_header(streamFile, astFile, snr_offset, sns_offset, meta_EA_SNR_SNS);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
close_streamfile(astFile);
|
||||
}
|
||||
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(astFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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),
|
||||
* or together in pseudoformats (.SNU, .SBR+.SBS banks, .AEMS, .MUS, etc).
|
||||
@ -162,18 +439,26 @@ fail:
|
||||
static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, STREAMFILE * streamData, off_t header_offset, off_t start_offset, meta_t meta_type) {
|
||||
VGMSTREAM * vgmstream = NULL;
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
int channel_count, loop_flag = 0, version, codec, channel_config, sample_rate, flags;
|
||||
uint32_t num_samples, loop_start = 0, loop_end = 0;
|
||||
int channel_count, loop_flag = 0, streamed, version, codec, channel_config, flags;
|
||||
int32_t header1, header2, sample_rate, num_samples, loop_start = 0, loop_end = 0;
|
||||
|
||||
/* EA SNR/SPH header */
|
||||
version = (read_8bit(header_offset + 0x00,streamHead) >> 4) & 0x0F;
|
||||
codec = (read_8bit(header_offset + 0x00,streamHead) >> 0) & 0x0F;
|
||||
channel_config = read_8bit(header_offset + 0x01,streamHead) & 0xFE;
|
||||
sample_rate = read_32bitBE(header_offset + 0x00,streamHead) & 0x1FFFF; /* some Dead Space 2 (PC) uses 96000 */
|
||||
flags = (uint8_t)read_8bit(header_offset + 0x04,streamHead) & 0xFE; //todo upper nibble only? (the first bit is part of size)
|
||||
num_samples = (uint32_t)read_32bitBE(header_offset + 0x04,streamHead) & 0x01FFFFFF;
|
||||
/* rest is optional, depends on flags header used (ex. SNU and SPS may have bigger headers):
|
||||
* &0x20: 1 int (usually 0x00), &0x00/40: nothing, &0x60: 2 ints (usually 0x00 and 0x14) */
|
||||
/* 4 bits: version */
|
||||
/* 4 bits: codec */
|
||||
/* 6 bits: channel config */
|
||||
/* 18 bits: sample rate */
|
||||
/* 4 bits: flags */
|
||||
/* 28 bits: number of samples */
|
||||
header1 = read_32bitBE(header_offset + 0x00, streamHead);
|
||||
header2 = read_32bitBE(header_offset + 0x04, streamHead);
|
||||
version = (header1 >> 28) & 0x0F;
|
||||
codec = (header1 >> 24) & 0x0F;
|
||||
channel_config = (header1 >> 18) & 0x3F;
|
||||
sample_rate = (header1 & 0x03FFFF); /* some Dead Space 2 (PC) uses 96000 */
|
||||
flags = (header2 >> 28) & 0x0F; // TODO: maybe even 3 bits and not 4?
|
||||
num_samples = (header2 & 0x0FFFFFFF);
|
||||
/* rest is optional, depends on flags header used (ex. SNU and SPS may have bigger headers): */
|
||||
/* 0x02: loop start sample, 0x00/04: nothing, 0x06: loop start sample and loop start block offset */
|
||||
|
||||
/* V0: SNR+SNS, V1: SPR+SPS (no apparent differences, other than the block flags used) */
|
||||
if (version != 0 && version != 1) {
|
||||
@ -181,27 +466,30 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* 0x40: stream asset, 0x20: full loop, 0x00: default/RAM asset */
|
||||
if (flags != 0x60 && flags != 0x40 && flags != 0x20 && flags != 0x00) {
|
||||
/* 0x04: stream asset, 0x02: full loop, 0x00: default/RAM asset */
|
||||
if (flags != 0x06 && flags != 0x04 && flags != 0x02 && flags != 0x00) {
|
||||
VGM_LOG("EA SNS/SPS: unknown flag 0x%02x\n", flags);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* seen in sfx and Dead Space ambient tracks */
|
||||
if (flags & 0x20) {
|
||||
/* TODO: Properly implement looping, needed for Need for Speed: World (PC) */
|
||||
if (flags & 0x02) {
|
||||
loop_flag = 1;
|
||||
loop_start = 0;
|
||||
loop_end = num_samples;
|
||||
}
|
||||
|
||||
/* Non-streamed sounds are stored as a single block */
|
||||
streamed = (flags & 0x04) != 0;
|
||||
|
||||
/* accepted channel configs only seem to be mono/stereo/quad/5.1/7.1 */
|
||||
//channel_count = ((channel_config >> 2) & 0xf) + 1; /* likely, but better fail with unknown values */
|
||||
/* fail with unknown values just in case */
|
||||
switch(channel_config) {
|
||||
case 0x00: channel_count = 1; break;
|
||||
case 0x04: channel_count = 2; break;
|
||||
case 0x0c: channel_count = 4; break;
|
||||
case 0x14: channel_count = 6; break;
|
||||
case 0x1c: channel_count = 8; break;
|
||||
case 0x01: channel_count = 2; break;
|
||||
case 0x03: channel_count = 4; break;
|
||||
case 0x05: channel_count = 6; break;
|
||||
case 0x07: channel_count = 8; break;
|
||||
default:
|
||||
VGM_LOG("EA SNS/SPS: unknown channel config 0x%02x\n", channel_config);
|
||||
goto fail;
|
||||
@ -235,7 +523,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
ffmpeg_custom_config cfg = {0};
|
||||
|
||||
stream_size = get_streamfile_size(streamData) - start_offset;
|
||||
virtual_size = ffmpeg_get_eaxma_virtual_size(vgmstream->channels, start_offset,stream_size, streamData);
|
||||
virtual_size = ffmpeg_get_eaxma_virtual_size(vgmstream->channels, streamed, start_offset,stream_size, streamData);
|
||||
block_size = 0x10000; /* todo unused and not correctly done by the parser */
|
||||
block_count = stream_size / block_size + (stream_size % block_size ? 1 : 0);
|
||||
|
||||
@ -269,7 +557,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
|
||||
/* remove blocks on reads for some edge cases in L32P and to properly apply discard modes
|
||||
* (otherwise, and removing discards, it'd work with layout_blocked_ea_sns) */
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, version, codec, start_offset, 0);
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, version, codec, streamed, start_offset, 0);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
@ -305,7 +593,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
|
||||
vgmstream->layout_type = layout_none;
|
||||
|
||||
/* EATrax is "buffered" ATRAC9, uses custom IO since it's kind of complex to add to the decoder */
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, version, codec, start_offset, total_size);
|
||||
temp_streamFile = setup_eaac_streamfile(streamData, version, codec, streamed, start_offset, total_size);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
@ -341,3 +629,11 @@ fail:
|
||||
close_vgmstream(vgmstream);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) {
|
||||
switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */
|
||||
case 0x06: return 0x10;
|
||||
case 0x02: return 0x0C;
|
||||
default: return 0x08;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ typedef struct {
|
||||
/* config */
|
||||
int version;
|
||||
int codec;
|
||||
int streamed;
|
||||
off_t start_offset;
|
||||
size_t total_size; /* size of the resulting substream */
|
||||
} eaac_io_data;
|
||||
@ -110,7 +111,7 @@ static size_t eaac_io_read(STREAMFILE *streamfile, uint8_t *dest, off_t offset,
|
||||
data->logical_offset += data_size;
|
||||
}
|
||||
|
||||
if (data->version == 0 && block_flag == 0x80)
|
||||
if (data->version == 0 && (!data->streamed || block_flag == 0x80))
|
||||
break; /* stop on last block */
|
||||
}
|
||||
|
||||
@ -170,7 +171,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||
physical_offset += block_size;
|
||||
total_size += data_size;
|
||||
|
||||
if (data->version == 0 && block_flag == 0x80)
|
||||
if (data->version == 0 && (!data->streamed || block_flag == 0x80))
|
||||
break; /* stop on last block */
|
||||
}
|
||||
|
||||
@ -189,7 +190,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||
* - EALayer3: MPEG granule 1 can go in the next block (in V2"P" mainly, others could use layout blocked_sns)
|
||||
* - EATrax: ATRAC9 frames can be split between blooks
|
||||
*/
|
||||
static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, int codec, off_t start_offset, size_t total_size) {
|
||||
static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, int codec, int streamed, off_t start_offset, size_t total_size) {
|
||||
STREAMFILE *temp_streamFile = NULL, *new_streamFile = NULL;
|
||||
eaac_io_data io_data = {0};
|
||||
size_t io_data_size = sizeof(eaac_io_data);
|
||||
@ -197,6 +198,7 @@ static STREAMFILE* setup_eaac_streamfile(STREAMFILE *streamFile, int version, in
|
||||
io_data.version = version;
|
||||
io_data.codec = codec;
|
||||
io_data.start_offset = start_offset;
|
||||
io_data.streamed = streamed;
|
||||
io_data.total_size = total_size; /* optional */
|
||||
io_data.physical_offset = start_offset;
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
#define EA_CODEC1_NONE -1
|
||||
#define EA_CODEC1_PCM 0x00
|
||||
#define EA_CODEC1_VAG 0x01 // unsure
|
||||
#define EA_CODEC1_EAXA 0x07 // Need for Speed 2 PC, FIFA 98 SAT
|
||||
#define EA_CODEC1_EAXA 0x07 // Need for Speed II (PC), FIFA 98 (SAT)
|
||||
#define EA_CODEC1_MT10 0x09
|
||||
//#define EA_CODEC1_N64 ?
|
||||
|
||||
@ -132,13 +132,15 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA ABK - contains embedded BNK file or references streams in AST file */
|
||||
/* EA ABK - common soundbank format in 6th-gen games, can reference RAM and streamed assets */
|
||||
/* RAM assets are stored in embedded BNK file */
|
||||
/* streamed assets are stored externally in AST file (mostly seen in earlier 6th games) */
|
||||
VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
int bnk_target_stream, is_dupe, total_sounds = 0, target_stream = streamFile->stream_index;
|
||||
off_t bnk_offset, header_table_offset, base_offset, value_offset, table_offset, entry_offset, target_entry_offset, schl_offset;
|
||||
uint32_t i, j, k, num_sounds, total_sound_tables;
|
||||
uint32_t i, j, k, version, num_sounds, total_sound_tables;
|
||||
uint16_t num_tables;
|
||||
uint8_t version, sound_type, num_entries;
|
||||
uint8_t sound_type, num_entries;
|
||||
off_t sound_table_offsets[0x2000];
|
||||
STREAMFILE * astData = NULL;
|
||||
VGMSTREAM * vgmstream;
|
||||
@ -152,8 +154,11 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
if (read_32bitBE(0x00, streamFile) != 0x41424B43) /* "ABKC" */
|
||||
goto fail;
|
||||
|
||||
version = read_8bit(0x06, streamFile);
|
||||
if (version > 0x01)
|
||||
version = read_32bitBE(0x04, streamFile);
|
||||
if (version != 0x01010000 &&
|
||||
version != 0x01010100 &&
|
||||
version != 0x02010100 &&
|
||||
version != 0x02010202)
|
||||
goto fail;
|
||||
|
||||
/* use table offset to check endianness */
|
||||
@ -166,7 +171,8 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
}
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0) goto fail;
|
||||
if (target_stream < 0)
|
||||
goto fail;
|
||||
|
||||
num_tables = read_16bit(0x0A, streamFile);
|
||||
header_table_offset = read_32bit(0x1C, streamFile);
|
||||
@ -194,7 +200,8 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dupe) continue;
|
||||
if (is_dupe)
|
||||
continue;
|
||||
|
||||
sound_table_offsets[total_sound_tables++] = table_offset;
|
||||
num_sounds = read_32bit(table_offset, streamFile);
|
||||
@ -214,10 +221,13 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
}
|
||||
}
|
||||
|
||||
/* there can be another set of values, don't know what they mean */
|
||||
num_entries += read_8bit(header_table_offset + 0x27, streamFile);
|
||||
header_table_offset += 0x3C + num_entries * 0x04;
|
||||
}
|
||||
|
||||
if (target_entry_offset == 0) goto fail;
|
||||
if (target_entry_offset == 0)
|
||||
goto fail;
|
||||
|
||||
/* 0x00: type (0x00 - normal, 0x01 - streamed, 0x02 - streamed and prefetched(?) */
|
||||
/* 0x01: ??? */
|
||||
@ -227,21 +237,24 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
|
||||
switch (sound_type) {
|
||||
case 0x00:
|
||||
if (!bnk_offset) goto fail;
|
||||
if (!bnk_offset)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(bnk_offset, streamFile) != 0x424E4B6C && /* "BNKl" */
|
||||
read_32bitBE(bnk_offset,streamFile) != 0x424E4B62) /* BNKb */
|
||||
read_32bitBE(bnk_offset, streamFile) != 0x424E4B62) /* BNKb */
|
||||
goto fail;
|
||||
|
||||
bnk_target_stream = read_32bit(target_entry_offset + 0x04, streamFile) + 1;
|
||||
vgmstream = parse_bnk_header(streamFile, bnk_offset, bnk_target_stream, total_sounds);
|
||||
if (!vgmstream) goto fail;
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
astData = open_streamfile_by_ext(streamFile, "ast");
|
||||
if (!astData) goto fail;
|
||||
if (!astData)
|
||||
goto fail;
|
||||
|
||||
if (sound_type == 0x01)
|
||||
schl_offset = read_32bit(target_entry_offset + 0x04, streamFile);
|
||||
@ -252,7 +265,8 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
|
||||
goto fail;
|
||||
|
||||
vgmstream = parse_schl_block(astData, schl_offset, total_sounds);
|
||||
if (!vgmstream) goto fail;
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -268,63 +282,145 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA HDR/DAT combo - frequently used for storing speech */
|
||||
VGMSTREAM * init_vgmstream_ea_hdr(STREAMFILE *streamFile) {
|
||||
/* EA HDR/DAT combo - seen in late 6th-gen games, used for storing speech and other streamed sounds (except for music) */
|
||||
VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) {
|
||||
int target_stream = streamFile->stream_index;
|
||||
uint8_t userdata_size, total_sounds;
|
||||
size_t total_size;
|
||||
off_t schl_offset;
|
||||
STREAMFILE *datFile = NULL, *sthFile = NULL;
|
||||
off_t schl_offset, offset_mult;
|
||||
STREAMFILE *datFile = NULL;
|
||||
VGMSTREAM *vgmstream;
|
||||
//int32_t (*read_32bit)(off_t,STREAMFILE*);
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*);
|
||||
|
||||
/* No nice way to validate these so we do what we can */
|
||||
sthFile = open_streamfile_by_ext(streamFile, "sth");
|
||||
if (sthFile) goto fail; /* newer version using SNR/SNS */
|
||||
|
||||
datFile = open_streamfile_by_ext(streamFile, "dat");
|
||||
if (!datFile) goto fail;
|
||||
|
||||
/* 0x00: hash */
|
||||
/* main header's endianness is platform-native but we only care about one byte values */
|
||||
/* 0x00: ID */
|
||||
/* 0x02: sub-ID (used for different police voices in NFS games) */
|
||||
/* 0x04: userdata size (low nibble) */
|
||||
/* 0x05: number of files */
|
||||
/* 0x06: ??? */
|
||||
/* 0x07: offset multiplier flag */
|
||||
/* 0x08: combined size of all sounds without padding divided by 0x0100 */
|
||||
/* 0x0C: table start */
|
||||
|
||||
/* no nice way to validate these so we do what we can */
|
||||
/* must be accompanied by DAT file with SCHl sounds */
|
||||
datFile = open_streamfile_by_ext(streamFile, "dat");
|
||||
if (!datFile)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, datFile) != 0x5343486C) /* "SCHl */
|
||||
goto fail;
|
||||
|
||||
userdata_size = read_8bit(0x04, streamFile) & 0x0F;
|
||||
total_sounds = read_8bit(0x05, streamFile);
|
||||
offset_mult = (off_t)read_8bit(0x07, streamFile) * 0x0100 + 0x0100;
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
if (target_stream < 0 || total_sounds == 0 || target_stream > total_sounds) goto fail;
|
||||
|
||||
if (guess_endianness16bit(0x08,streamFile)) {
|
||||
//read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
//read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
total_size = (size_t)read_16bit(0x08, streamFile) * 0x0100;
|
||||
if (total_size > get_streamfile_size(datFile)) goto fail;
|
||||
if (target_stream < 0 || total_sounds == 0 || target_stream > total_sounds)
|
||||
goto fail;
|
||||
|
||||
/* offsets are always big endian */
|
||||
schl_offset = (off_t)read_16bitBE(0x0C + (0x02+userdata_size) * (target_stream-1), streamFile) * 0x0100;
|
||||
schl_offset = (off_t)read_16bitBE(0x0C + (0x02+userdata_size) * (target_stream-1), streamFile) * offset_mult;
|
||||
if (read_32bitBE(schl_offset, datFile) != 0x5343486C) /* "SCHl */
|
||||
goto fail;
|
||||
|
||||
vgmstream = parse_schl_block(datFile, schl_offset, total_sounds);
|
||||
if (!vgmstream) goto fail;
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
close_streamfile(datFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(datFile);
|
||||
close_streamfile(sthFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA IDX/BIG combo - basically a set of HDR/DAT compiled into one file */
|
||||
VGMSTREAM * init_vgmstream_ea_idx_big(STREAMFILE *streamFile) {
|
||||
int target_stream = streamFile->stream_index, total_sounds, subsound_index;
|
||||
uint32_t num_hdr;
|
||||
uint32_t i;
|
||||
uint16_t hdr_id, hdr_subid;
|
||||
uint8_t userdata_size, hdr_sounds;
|
||||
off_t entry_offset, hdr_offset, base_offset, schl_offset, offset_mult;
|
||||
size_t hdr_size;
|
||||
char stream_name[STREAM_NAME_SIZE];
|
||||
STREAMFILE *bigFile = NULL;
|
||||
VGMSTREAM *vgmstream = NULL;
|
||||
int32_t (*read_32bit)(off_t,STREAMFILE*);
|
||||
int16_t (*read_16bit)(off_t,STREAMFILE*);
|
||||
|
||||
/* seems to always start with 0x00000001 */
|
||||
if (read_32bitLE(0x00, streamFile) != 0x00000001 &&
|
||||
read_32bitBE(0x00, streamFile) != 0x00000001)
|
||||
goto fail;
|
||||
|
||||
bigFile = open_streamfile_by_ext(streamFile, "big");
|
||||
if (!bigFile)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(0x00, bigFile) != 0x5343486C) /* "SCHl */
|
||||
goto fail;
|
||||
|
||||
/* use number of files for endianness check */
|
||||
if (guess_endianness32bit(0x04,streamFile)) {
|
||||
read_32bit = read_32bitBE;
|
||||
read_16bit = read_16bitBE;
|
||||
} else {
|
||||
read_32bit = read_32bitLE;
|
||||
read_16bit = read_16bitLE;
|
||||
}
|
||||
|
||||
num_hdr = read_32bit(0x04, streamFile);
|
||||
if (read_32bit(0x54,streamFile) != num_hdr)
|
||||
goto fail;
|
||||
|
||||
if (target_stream == 0) target_stream = 1;
|
||||
schl_offset = 0;
|
||||
total_sounds = 0;
|
||||
schl_offset = 0xFFFFFFFF;
|
||||
|
||||
for (i = 0; i < num_hdr; i++) {
|
||||
entry_offset = 0x58 + 0x10 * i;
|
||||
hdr_size = read_32bit(entry_offset + 0x04, streamFile);
|
||||
hdr_offset = read_32bit(entry_offset + 0x08, streamFile);
|
||||
base_offset = read_32bit(entry_offset + 0x0C, streamFile);
|
||||
|
||||
hdr_id = read_16bit(hdr_offset + 0x00, streamFile);
|
||||
hdr_subid = read_16bit(hdr_offset + 0x02, streamFile);
|
||||
userdata_size = read_8bit(hdr_offset + 0x04, streamFile) & 0x0F;
|
||||
hdr_sounds = read_8bit(hdr_offset + 0x05, streamFile);
|
||||
offset_mult = (off_t)read_8bit(hdr_offset + 0x07, streamFile) * 0x0100 + 0x0100;
|
||||
|
||||
if (target_stream > total_sounds && target_stream <= total_sounds + hdr_sounds) {
|
||||
schl_offset = base_offset + (off_t)read_16bitBE(hdr_offset + 0x0C + (0x02+userdata_size) * (target_stream-total_sounds-1), streamFile) * offset_mult;
|
||||
subsound_index = target_stream - total_sounds;
|
||||
|
||||
/* There are no filenames but we can add IDs to stream name for better organization */
|
||||
if (hdr_subid != 0xFFFF)
|
||||
snprintf(stream_name, STREAM_NAME_SIZE, "%03d_%02d_%d", hdr_id, hdr_subid, subsound_index);
|
||||
else
|
||||
snprintf(stream_name, STREAM_NAME_SIZE, "%03d_%d", hdr_id, subsound_index);
|
||||
}
|
||||
|
||||
total_sounds += hdr_sounds;
|
||||
}
|
||||
|
||||
if (schl_offset == 0xFFFFFFFF)
|
||||
goto fail;
|
||||
|
||||
if (read_32bitBE(schl_offset, bigFile) != 0x5343486C) /* "SCHl */
|
||||
goto fail;
|
||||
|
||||
vgmstream = parse_schl_block(bigFile, schl_offset, total_sounds);
|
||||
if (!vgmstream)
|
||||
goto fail;
|
||||
|
||||
strncpy(vgmstream->stream_name, stream_name, STREAM_NAME_SIZE);
|
||||
close_streamfile(bigFile);
|
||||
return vgmstream;
|
||||
|
||||
fail:
|
||||
close_streamfile(bigFile);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -341,7 +437,7 @@ static VGMSTREAM * parse_schl_block(STREAMFILE *streamFile, off_t offset, int to
|
||||
|
||||
header_offset = offset + 0x08;
|
||||
|
||||
if (!parse_variable_header(streamFile, &ea, header_offset, header_size))
|
||||
if (!parse_variable_header(streamFile, &ea, header_offset, header_size - 0x08))
|
||||
goto fail;
|
||||
|
||||
start_offset = offset + header_size; /* starts in "SCCl" (skipped in block layout) or very rarely "SCDl" and maybe movie blocks */
|
||||
@ -377,7 +473,7 @@ static VGMSTREAM * parse_bnk_header(STREAMFILE *streamFile, off_t offset, int ta
|
||||
|
||||
/* check multi-streams */
|
||||
switch(bnk_version) {
|
||||
case 0x02: /* early (Need For Speed PC, Fifa 98 SS) */
|
||||
case 0x02: /* early [Need For Speed II (PC), FIFA 98 (SAT)] */
|
||||
table_offset = 0x0c;
|
||||
header_size = read_32bit(offset + 0x08,streamFile); /* full size */
|
||||
break;
|
||||
@ -431,14 +527,11 @@ static VGMSTREAM * parse_bnk_header(STREAMFILE *streamFile, off_t offset, int ta
|
||||
|
||||
start_offset = ea.offsets[0]; /* first channel, presumably needed for MPEG */
|
||||
|
||||
/* special case found in some tests (pcstream had hist, pcbnk no hist, no patch diffs)
|
||||
* Later console games don't need hist [FIFA 07 (Xbox): V3, NASCAR 06 (Xbox): V2].
|
||||
* I think this works but what decides if hist is used or not a secret to everybody */
|
||||
if (ea.codec2 == EA_CODEC2_EAXA && ea.codec1 == EA_CODEC1_NONE && ea.version >= EA_VERSION_V1) {
|
||||
/* it looks like BNKs never store ADPCM history for EA-XA */
|
||||
if (ea.codec2 == EA_CODEC2_EAXA) {
|
||||
ea.codec_version = 0;
|
||||
}
|
||||
|
||||
|
||||
/* rest is common */
|
||||
return init_vgmstream_ea_variable_header(streamFile, &ea, start_offset, bnk_version, total_streams ? total_streams : real_bnk_sounds);
|
||||
|
||||
@ -598,18 +691,25 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
}
|
||||
|
||||
case EA_CODEC2_ATRAC3PLUS: { /* regular ATRAC3plus chunked in SCxx blocks, including RIFF header */
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
if (!is_bnk) {
|
||||
STREAMFILE* temp_streamFile = NULL;
|
||||
/* remove blocks on reads to feed FFmpeg a clean .at3 */
|
||||
temp_streamFile = setup_schl_streamfile(streamFile, ea->codec2, ea->channels, start_offset, 0);
|
||||
if (!temp_streamFile) goto fail;
|
||||
|
||||
/* remove blocks on reads to feed FFmpeg a clean .at3 */
|
||||
temp_streamFile = setup_schl_streamfile(streamFile, ea->codec2, ea->channels, start_offset, 0);
|
||||
if (!temp_streamFile) goto fail;
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
start_offset = 0x00; /* must point to the custom streamfile's beginning */
|
||||
|
||||
//todo fix encoder delay
|
||||
vgmstream->codec_data = init_ffmpeg_offset(temp_streamFile, 0x00, get_streamfile_size(temp_streamFile));
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
//todo fix encoder delay
|
||||
vgmstream->codec_data = init_ffmpeg_offset(temp_streamFile, start_offset, get_streamfile_size(temp_streamFile));
|
||||
close_streamfile(temp_streamFile);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t riff_size = read_32bitLE(start_offset + 0x04, streamFile) + 0x08;
|
||||
vgmstream->codec_data = init_ffmpeg_offset(streamFile, start_offset, riff_size);
|
||||
if (!vgmstream->codec_data) goto fail;
|
||||
}
|
||||
|
||||
vgmstream->coding_type = coding_FFmpeg;
|
||||
vgmstream->layout_type = layout_none;
|
||||
@ -642,28 +742,13 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
|
||||
}
|
||||
}
|
||||
|
||||
/* setup ADPCM hist */
|
||||
switch(vgmstream->coding_type) {
|
||||
/* id, size, samples, hists-per-channel, stereo/interleaved data */
|
||||
case coding_EA_XA:
|
||||
/* read ADPCM history from all channels before data (not actually read in sx.exe) */
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x00,streamFile);
|
||||
//vgmstream->ch[i].adpcm_history2_32 = read_16bit(block_offset + 0x0C + (i*0x04) + 0x02,streamFile);
|
||||
vgmstream->ch[i].offset += vgmstream->channels*0x04;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* read ADPCM history before each channel if needed (not actually read in sx.exe) */
|
||||
if (vgmstream->codec_version == 1) {
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile);
|
||||
//vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile);
|
||||
vgmstream->ch[i].offset += 4;
|
||||
}
|
||||
}
|
||||
break;
|
||||
/* read ADPCM history before each channel if needed (not actually read in sx.exe) */
|
||||
if (vgmstream->codec_version == 1) {
|
||||
for (i = 0; i < vgmstream->channels; i++) {
|
||||
//vgmstream->ch[i].adpcm_history1_32 = read_16bit(vgmstream->ch[i].offset+0x00,streamFile);
|
||||
//vgmstream->ch[i].adpcm_history3_32 = read_16bit(vgmstream->ch[i].offset+0x02,streamFile);
|
||||
vgmstream->ch[i].offset += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (vgmstream->layout_type == layout_blocked_ea_schl) {
|
||||
@ -766,10 +851,12 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
case 0x0F: /* random volume range (BNK only) */
|
||||
case 0x10: /* detune (BNK only) */
|
||||
case 0x11: /* random detune range (BNK only) */
|
||||
case 0x12: /* unknown, rare (BNK only) [Need for Speed III: Hot Pursuit (PS1)] */
|
||||
case 0x13: /* effect bus (0..127) */
|
||||
case 0x14: /* emdedded user data (free size/value) */
|
||||
case 0x15: /* unknown, rare (BNK only) [Need for Speed: High Stakes (PS1)] */
|
||||
case 0x19: /* related to playback envelope (BNK only) */
|
||||
case 0x1A: /* unknown and very rare, size 0 (BNK only) [SSX3 (PS2)] */
|
||||
case 0x1A: /* unknown and very rare (BNK only) [SSX 3 (PS2)] */
|
||||
case 0x1B: /* unknown (movie only?) */
|
||||
case 0x1C: /* initial envelope volume (BNK only) */
|
||||
case 0x1D: /* unknown, rare [NASCAR 06 (Xbox)] */
|
||||
@ -867,11 +954,13 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
break;
|
||||
|
||||
case 0x8A: /* long padding (always 0x00000000) */
|
||||
case 0x8B: /* also padding? [Need for Speed: Hot Pursuit 2 (PC)] */
|
||||
case 0x8C: /* flags (ex. play type = 01=static/02=dynamic | spatialize = 20=pan/etc) */
|
||||
/* (ex. PS1 VAG=0, PS2 PCM/LAYER2=4, GC EAXA=4, 3DS DSP=512, Xbox EAXA=36, N64 BLK=05E800, N64 MT10=01588805E800) */
|
||||
case 0x8D: /* unknown, rare [FIFA 07 (GC)] */
|
||||
case 0x8E:
|
||||
case 0x92: /* bytes per sample? */
|
||||
case 0x93: /* unknown (BNK only) [Need for Speed III: Hot Pursuit (PC)] */
|
||||
case 0x98: /* embedded time stretch 1 (long data for who-knows-what) */
|
||||
case 0x99: /* embedded time stretch 2 */
|
||||
case 0x9C: /* azimuth ch1 */
|
||||
@ -1024,7 +1113,6 @@ static int parse_variable_header(STREAMFILE* streamFile, ea_header* ea, off_t be
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return offset;
|
||||
|
||||
fail:
|
||||
|
@ -661,7 +661,8 @@ VGMSTREAM * init_vgmstream_txth(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_hdr(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_idx_big(STREAMFILE * steeamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ea_schl_fixed(STREAMFILE * streamFile);
|
||||
|
||||
@ -694,6 +695,8 @@ VGMSTREAM * init_vgmstream_vxn(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_snu(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE * streamFile);
|
||||
VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE * streamFile);
|
||||
|
||||
|
@ -9,7 +9,7 @@ VGMSTREAM * init_vgmstream_sxd(STREAMFILE *streamFile) {
|
||||
off_t start_offset, chunk_offset, first_offset = 0x60, name_offset = 0;
|
||||
size_t chunk_size, stream_size = 0;
|
||||
|
||||
int is_dual, is_external;
|
||||
int is_dual = 0, is_external = 0;
|
||||
int loop_flag, channels, codec, location;
|
||||
int sample_rate, num_samples, loop_start_sample, loop_end_sample;
|
||||
uint32_t at9_config_data = 0;
|
||||
|
@ -359,7 +359,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_wii_04sw,
|
||||
init_vgmstream_ea_bnk,
|
||||
init_vgmstream_ea_abk,
|
||||
init_vgmstream_ea_hdr,
|
||||
init_vgmstream_ea_hdr_dat,
|
||||
init_vgmstream_ea_idx_big,
|
||||
init_vgmstream_ea_schl_fixed,
|
||||
init_vgmstream_sk_aud,
|
||||
init_vgmstream_stm,
|
||||
@ -380,6 +381,8 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_vxn,
|
||||
init_vgmstream_ea_snr_sns,
|
||||
init_vgmstream_ea_sps,
|
||||
init_vgmstream_ea_abk_new,
|
||||
init_vgmstream_ea_hdr_sth_dat,
|
||||
init_vgmstream_ngc_vid1,
|
||||
init_vgmstream_flx,
|
||||
init_vgmstream_mogg,
|
||||
|
Loading…
x
Reference in New Issue
Block a user