Merge pull request #272 from NicknineTheEagle/ea-fixes

EA Fixes
This commit is contained in:
Christopher Snowhill 2018-08-03 19:45:02 -07:00 committed by GitHub
commit a88591c0f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 214 additions and 167 deletions

View File

@ -5,6 +5,33 @@
/* EAAudioCore formats, EA's current audio middleware */
#define EAAC_VERSION_V0 0x00 /* SNR/SNS */
#define EAAC_VERSION_V1 0x01 /* SPS */
#define EAAC_CODEC_NONE 0x00 /* internal 'codec not set' flag */
#define EAAC_CODEC_RESERVED 0x01 /* not used/reserved? /MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */
#define EAAC_CODEC_PCM 0x02
#define EAAC_CODEC_EAXMA 0x03
#define EAAC_CODEC_XAS 0x04
#define EAAC_CODEC_EALAYER3_V1 0x05
#define EAAC_CODEC_EALAYER3_V2_PCM 0x06
#define EAAC_CODEC_EALAYER3_V2_SPIKE 0x07
#define EAAC_CODEC_DSP 0x08
#define EAAC_CODEC_EASPEEX 0x09
#define EAAC_CODEC_EATRAX 0x0a
#define EAAC_CODEC_EAOPUS 0x0c
#define EAAC_FLAG_NONE 0x00
#define EAAC_FLAG_LOOPED 0x02
#define EAAC_FLAG_STREAMED 0x04
#define EAAC_BLOCKID0_DATA 0x00
#define EAAC_BLOCKID0_END 0x80
#define EAAC_BLOCKID1_HEADER 0x48 /* 'H' */
#define EAAC_BLOCKID1_DATA 0x44 /* 'D' */
#define EAAC_BLOCKID1_END 0x45 /* 'E' */
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);
@ -50,7 +77,7 @@ VGMSTREAM * init_vgmstream_ea_sps(STREAMFILE * streamFile) {
goto fail;
/* SPS block start: 0x00(1): block flag (header=0x48); 0x01(3): block size (usually 0x0c-0x14) */
if (read_8bit(0x00, streamFile) != 0x48)
if (read_8bit(0x00, streamFile) != EAAC_BLOCKID1_HEADER)
goto fail;
start_offset = read_32bitBE(0x00, streamFile) & 0x00FFFFFF;
@ -150,111 +177,10 @@ 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 (1) {
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 = 0;
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;
@ -293,6 +219,7 @@ VGMSTREAM * init_vgmstream_ea_abk_new(STREAMFILE *streamFile) {
bnk_offset = read_32bit(0x20, streamFile);
total_sound_tables = 0;
bnk_target_index = 0xFFFF;
ast_offset = 0;
/* set up some common values */
if (header_table_offset == 0x5C) {
@ -431,6 +358,107 @@ 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;
uint32_t i;
uint8_t userdata_size, total_sounds, block_id;
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 != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
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 (1) {
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 != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
goto fail;
sns_offset += block_size;
if (block_id == EAAC_BLOCKID0_END)
break;
}
}
block_id = read_8bit(sns_offset, datFile);
if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END)
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 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).
@ -454,32 +482,32 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
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?
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) {
if (version != EAAC_VERSION_V0 && version != EAAC_VERSION_V1) {
VGM_LOG("EA SNS/SPS: unknown version\n");
goto fail;
}
/* 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);
if (flags != EAAC_FLAG_NONE &&
!(flags & (EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED))) {
VGM_LOG("EA SNS/SPS: unknown flags 0x%02x\n", flags);
goto fail;
}
/* TODO: Properly implement looping, needed for Need for Speed: World (PC) */
if (flags & 0x02) {
if (flags & EAAC_FLAG_LOOPED) {
loop_flag = 1;
loop_start = 0;
loop_end = num_samples;
}
/* Non-streamed sounds are stored as a single block */
streamed = (flags & 0x04) != 0;
streamed = (flags & EAAC_FLAG_STREAMED) != 0;
/* accepted channel configs only seem to be mono/stereo/quad/5.1/7.1 */
/* fail with unknown values just in case */
@ -508,14 +536,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
/* EA decoder list and known internal FourCCs */
switch(codec) {
case 0x02: /* "P6B0": PCM16BE [NBA Jam (Wii)] */
case EAAC_CODEC_PCM: /* "P6B0": PCM16BE [NBA Jam (Wii)] */
vgmstream->coding_type = coding_PCM16_int;
vgmstream->codec_endian = 1;
vgmstream->layout_type = layout_blocked_ea_sns;
break;
#ifdef VGM_USE_FFMPEG
case 0x03: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */
case EAAC_CODEC_EAXMA: { /* "EXm0": EA-XMA [Dante's Inferno (X360)] */
uint8_t buf[0x100];
int bytes, block_size, block_count;
size_t stream_size, virtual_size;
@ -542,15 +570,15 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
}
#endif
case 0x04: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */
case EAAC_CODEC_XAS: /* "Xas1": EA-XAS [Dead Space (PC/PS3)] */
vgmstream->coding_type = coding_EA_XAS;
vgmstream->layout_type = layout_blocked_ea_sns;
break;
#ifdef VGM_USE_MPEG
case 0x05: /* "EL31": EALayer3 v1 [Need for Speed: Hot Pursuit (PS3)] */
case 0x06: /* "L32P": EALayer3 v2 "PCM" [Battlefield 1943 (PS3)] */
case 0x07: { /* "L32S": EALayer3 v2 "Spike" [Dante's Inferno (PS3)] */
case EAAC_CODEC_EALAYER3_V1: /* "EL31": EALayer3 v1 [Need for Speed: Hot Pursuit (PS3)] */
case EAAC_CODEC_EALAYER3_V2_PCM: /* "L32P": EALayer3 v2 "PCM" [Battlefield 1943 (PS3)] */
case EAAC_CODEC_EALAYER3_V2_SPIKE: { /* "L32S": EALayer3 v2 "Spike" [Dante's Inferno (PS3)] */
mpeg_custom_config cfg = {0};
mpeg_custom_t type = (codec == 0x05 ? MPEG_EAL31b : (codec == 0x06) ? MPEG_EAL32P : MPEG_EAL32S);
@ -570,14 +598,14 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
}
#endif
case 0x08: /* "Gca0"?: DSP [Need for Speed: Nitro sfx (Wii)] */
case EAAC_CODEC_DSP: /* "Gca0"?: DSP [Need for Speed: Nitro sfx (Wii)] */
vgmstream->coding_type = coding_NGC_DSP;
vgmstream->layout_type = layout_blocked_ea_sns;
/* DSP coefs are read in the blocks */
break;
#ifdef VGM_USE_ATRAC9
case 0x0a: { /* EATrax */
case EAAC_CODEC_EATRAX: { /* EATrax */
atrac9_config cfg = {0};
size_t total_size;
@ -600,14 +628,10 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST
}
#endif
case 0x00: /* "NONE" (internal 'codec not set' flag) */
case 0x01: /* not used/reserved? /MP30/P6L0/P2B0/P2L0/P8S0/P8U0/PFN0? */
case 0x09: /* EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) */
case 0x0b: /* ? */
case 0x0c: /* EAOpus (inside each SNS/SPS block is 16b frame size + standard? Opus packet) */
case 0x0d: /* ? */
case 0x0e: /* ? */
case 0x0f: /* ? */
case EAAC_CODEC_EASPEEX: /* EASpeex (libspeex variant, base versions vary: 1.0.5, 1.2beta3) */
/* TODO */
case EAAC_CODEC_EAOPUS: /* EAOpus (inside each SNS/SPS block is 16b frame size + standard? Opus packet) */
/* TODO */
default:
VGM_LOG("EA SNS/SPS: unknown codec 0x%02x\n", codec);
goto fail;
@ -631,8 +655,8 @@ fail:
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;
case EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED: return 0x10;
case EAAC_FLAG_LOOPED: return 0x0C;
default: return 0x08;
}
}

View File

@ -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 II (PC), FIFA 98 (SAT)
#define EA_CODEC1_EAXA 0x07
#define EA_CODEC1_MT10 0x09
//#define EA_CODEC1_N64 ?
@ -47,10 +47,32 @@
#define EA_CODEC2_XBOXADPCM 0x14
#define EA_CODEC2_MT5 0x16
#define EA_CODEC2_EALAYER3 0x17
#define EA_CODEC2_ATRAC3PLUS 0x1B /* Medal of Honor Heroes 2 (PSP) */
#define EA_CODEC2_ATRAC3PLUS 0x1B
/* Block headers, SCxy - where x is block ID and y is endianness flag (always 'l'?) */
#define EA_BLOCKID_HEADER 0x5343486C /* "SCHl" */
#define EA_BLOCKID_COUNT 0x5343436C /* "SCCl" */
#define EA_BLOCKID_DATA 0x5343446C /* "SCDl" */
#define EA_BLOCKID_END 0x5343456C /* "SCEl" */
#define EA_MAX_CHANNELS 6
/* Localized block headers, Sxyy - where x is block ID and yy is lang code (e.g. "SHEN"), used in videos */
#define EA_BLOCKID_LOC_HEADER 0x53480000 /* "SH" */
#define EA_BLOCKID_LOC_COUNT 0x53430000 /* "SC" */
#define EA_BLOCKID_LOC_DATA 0x53440000 /* "SD" */
#define EA_BLOCKID_LOC_END 0x53450000 /* "SE" */
#define EA_BLOCKID_LOC_EN 0x0000454E
#define EA_BLOCKID_LOC_FR 0x00004652
#define EA_BLOCKID_LOC_GE 0x00004745
#define EA_BLOCKID_LOC_IT 0x00004954
#define EA_BLOCKID_LOC_SP 0x00005350
#define EA_BLOCKID_LOC_RU 0x00005255
#define EA_BLOCKID_LOC_JA 0x00004A41
#define EA_BNK_HEADER_LE 0x424E4B6C /* "BNKl" */
#define EA_BNK_HEADER_BE 0x424E4B62 /* "BNKb" */
#define EA_MAX_CHANNELS 6
typedef struct {
int32_t num_samples;
@ -89,14 +111,14 @@ VGMSTREAM * init_vgmstream_ea_schl(STREAMFILE *streamFile) {
goto fail;
/* check header */
if (read_32bitBE(0x00,streamFile) != 0x5343486C && /* "SCHl" */
read_32bitBE(0x00,streamFile) != 0x5348454E && /* "SHEN" */
read_32bitBE(0x00,streamFile) != 0x53484652 && /* "SHFR" */
read_32bitBE(0x00,streamFile) != 0x53484745 && /* "SHGE" */
read_32bitBE(0x00,streamFile) != 0x53484954 && /* "SHIT" */
read_32bitBE(0x00,streamFile) != 0x53485350 && /* "SHSP" */
read_32bitBE(0x00,streamFile) != 0x53485255 && /* "SHRU" */
read_32bitBE(0x00,streamFile) != 0x53484A41) /* "SHJA" */
if (read_32bitBE(0x00,streamFile) != EA_BLOCKID_HEADER && /* "SCHl" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_EN) && /* "SHEN" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_FR) && /* "SHFR" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_GE) && /* "SHGE" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_IT) && /* "SHIT" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_SP) && /* "SHSP" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_RU) && /* "SHRU" */
read_32bitBE(0x00,streamFile) != (EA_BLOCKID_LOC_HEADER | EA_BLOCKID_LOC_JA)) /* "SHJA" */
goto fail;
/* Stream is divided into blocks/chunks: SCHl=audio header, SCCl=count of SCDl, SCDl=data xN, SCLl=loop end, SCEl=end.
@ -118,10 +140,10 @@ VGMSTREAM * init_vgmstream_ea_bnk(STREAMFILE *streamFile) {
goto fail;
/* check header (doesn't use EA blocks, otherwise very similar to SCHl) */
if (read_32bitBE(0x00,streamFile) == 0x424E4B6C || /* "BNKl" (common) */
read_32bitBE(0x00,streamFile) == 0x424E4B62) /* "BNKb" (FIFA 98 SS) */
if (read_32bitBE(0x00,streamFile) == EA_BNK_HEADER_LE ||
read_32bitBE(0x00,streamFile) == EA_BNK_HEADER_BE)
offset = 0;
else if (read_32bitBE(0x100,streamFile) == 0x424E4B6C) /* "BNKl" (common) */
else if (read_32bitBE(0x100,streamFile) == EA_BNK_HEADER_LE)
offset = 0x100; /* Harry Potter and the Goblet of Fire (PS2) .mus have weird extra 0x100 bytes */
else
goto fail;
@ -134,7 +156,7 @@ fail:
/* 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) */
/* streamed assets are stored externally in AST file (mostly seen in earlier 6th-gen 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;
@ -157,6 +179,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
version = read_32bitBE(0x04, streamFile);
if (version != 0x01010000 &&
version != 0x01010100 &&
version != 0x02010000 &&
version != 0x02010100 &&
version != 0x02010202)
goto fail;
@ -209,7 +232,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
for (k = 0; k < num_sounds; k++) {
entry_offset = table_offset + 0x04 + 0x0C * k;
sound_type = read_8bit(entry_offset, streamFile);
sound_type = read_8bit(entry_offset + 0x00, streamFile);
/* some of these dummies pointing at sound 0 in BNK */
if (sound_type == 0x00 && read_32bit(entry_offset + 0x04, streamFile) == 0)
@ -233,15 +256,15 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
/* 0x01: ??? */
/* 0x04: index for normal sounds, offset for streamed sounds */
/* 0x08: offset for prefetched sounds */
sound_type = read_8bit(target_entry_offset, streamFile);
sound_type = read_8bit(target_entry_offset + 0x00, streamFile);
switch (sound_type) {
case 0x00:
if (!bnk_offset)
goto fail;
if (read_32bitBE(bnk_offset, streamFile) != 0x424E4B6C && /* "BNKl" */
read_32bitBE(bnk_offset, streamFile) != 0x424E4B62) /* BNKb */
if (read_32bitBE(bnk_offset, streamFile) != EA_BNK_HEADER_LE &&
read_32bitBE(bnk_offset, streamFile) != EA_BNK_HEADER_BE)
goto fail;
bnk_target_stream = read_32bit(target_entry_offset + 0x04, streamFile) + 1;
@ -261,7 +284,7 @@ VGMSTREAM * init_vgmstream_ea_abk(STREAMFILE *streamFile) {
else
schl_offset = read_32bit(target_entry_offset + 0x08, streamFile);
if (read_32bitBE(schl_offset, astData) != 0x5343486C) /* "SCHl */
if (read_32bitBE(schl_offset, astData) != EA_BLOCKID_HEADER)
goto fail;
vgmstream = parse_schl_block(astData, schl_offset, total_sounds);
@ -293,7 +316,8 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) {
/* 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) */
/* 0x04: (low nibble) userdata size */
/* 0x04: (high nibble) ??? */
/* 0x05: number of files */
/* 0x06: ??? */
/* 0x07: offset multiplier flag */
@ -306,7 +330,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) {
if (!datFile)
goto fail;
if (read_32bitBE(0x00, datFile) != 0x5343486C) /* "SCHl */
if (read_32bitBE(0x00, datFile) != EA_BLOCKID_HEADER)
goto fail;
userdata_size = read_8bit(0x04, streamFile) & 0x0F;
@ -319,7 +343,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_dat(STREAMFILE *streamFile) {
/* offsets are always big endian */
schl_offset = (off_t)read_16bitBE(0x0C + (0x02+userdata_size) * (target_stream-1), streamFile) * offset_mult;
if (read_32bitBE(schl_offset, datFile) != 0x5343486C) /* "SCHl */
if (read_32bitBE(schl_offset, datFile) != EA_BLOCKID_HEADER)
goto fail;
vgmstream = parse_schl_block(datFile, schl_offset, total_sounds);
@ -337,8 +361,7 @@ fail:
/* 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;
uint32_t i, num_hdr;
uint16_t hdr_id, hdr_subid;
uint8_t userdata_size, hdr_sounds;
off_t entry_offset, hdr_offset, base_offset, schl_offset, offset_mult;
@ -358,7 +381,7 @@ VGMSTREAM * init_vgmstream_ea_idx_big(STREAMFILE *streamFile) {
if (!bigFile)
goto fail;
if (read_32bitBE(0x00, bigFile) != 0x5343486C) /* "SCHl */
if (read_32bitBE(0x00, bigFile) != EA_BLOCKID_HEADER)
goto fail;
/* use number of files for endianness check */
@ -408,7 +431,7 @@ VGMSTREAM * init_vgmstream_ea_idx_big(STREAMFILE *streamFile) {
if (schl_offset == 0xFFFFFFFF)
goto fail;
if (read_32bitBE(schl_offset, bigFile) != 0x5343486C) /* "SCHl */
if (read_32bitBE(schl_offset, bigFile) != EA_BLOCKID_HEADER)
goto fail;
vgmstream = parse_schl_block(bigFile, schl_offset, total_sounds);
@ -473,7 +496,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 II (PC), FIFA 98 (SAT)] */
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 */
break;
@ -691,7 +714,7 @@ static VGMSTREAM * init_vgmstream_ea_variable_header(STREAMFILE *streamFile, ea_
}
#ifdef VGM_USE_FFMPEG
case EA_CODEC2_ATRAC3PLUS: { /* regular ATRAC3plus chunked in SCxx blocks, including RIFF header */
case EA_CODEC2_ATRAC3PLUS: { /* regular ATRAC3plus chunked in SCxx blocks, including RIFF header [Medal of Honor Heroes 2 (PSP)] */
if (!is_bnk) {
STREAMFILE* temp_streamFile = NULL;
/* remove blocks on reads to feed FFmpeg a clean .at3 */
@ -1133,7 +1156,7 @@ static int get_ea_stream_total_samples(STREAMFILE* streamFile, off_t start_offse
vgmstream->next_block_offset = start_offset;
do {
uint32_t block_id = read_32bitBE(vgmstream->next_block_offset+0x00,streamFile);
if (block_id == 0x5343486C) /* "SCHl" start block (movie "SHxx" shouldn't use multi files) */
if (block_id == EA_BLOCKID_HEADER) /* "SCHl" start block (movie "SHxx" shouldn't use multi files) */
new_schl = 1;
block_update_ea_schl(vgmstream->next_block_offset,vgmstream);
@ -1169,14 +1192,14 @@ static off_t get_ea_stream_mpeg_start_offset(STREAMFILE* streamFile, off_t start
block_size = read_32bitBE(block_offset+0x04,streamFile);
switch(block_id) {
case 0x5343446C: /* "SCDl" */
case 0x5344454E: /* "SDEN" */
case 0x53444652: /* "SDFR" */
case 0x53444745: /* "SDGE" */
case 0x53444954: /* "SDIT" */
case 0x53445350: /* "SDSP" */
case 0x53445255: /* "SDRU" */
case 0x53444A41: /* "SDJA" */
case EA_BLOCKID_DATA: /* "SCDl" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_EN: /* "SDEN" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_FR: /* "SDFR" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_GE: /* "SDGE" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_IT: /* "SDIT" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_SP: /* "SDSP" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_RU: /* "SDRU" */
case EA_BLOCKID_LOC_DATA | EA_BLOCKID_LOC_JA: /* "SDJA" */
offset = read_32bit(block_offset+0x0c,streamFile); /* first value seems ok, second is something else in EALayer3 */
return block_offset + 0x0c + ea->channels*0x04 + offset;
case 0x00000000: