mirror of
https://github.com/vgmstream/vgmstream.git
synced 2025-01-29 19:37:30 +01:00
Added EA HDR/STH/DAT format support
This commit is contained in:
parent
4d10e91c27
commit
b6080f6bdc
@ -155,6 +155,113 @@ fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* EA HDR/STH/DAT - used for storing speech in some newer games */
|
||||
VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
|
||||
int target_stream = streamFile->stream_index;
|
||||
uint8_t userdata_size, total_sounds, block_id, flags;
|
||||
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;
|
||||
flags = (read_8bit(snr_offset + 0x04, sthFile) & 0xE0) >> 4;
|
||||
|
||||
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 (flags & 2) {
|
||||
if (block_id == 0x80)
|
||||
break;
|
||||
}
|
||||
else {
|
||||
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 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).
|
||||
|
@ -125,7 +125,7 @@ static size_t eaac_io_size(STREAMFILE *streamfile, eaac_io_data* data) {
|
||||
return data->total_size;
|
||||
|
||||
physical_offset = data->start_offset;
|
||||
max_physical_offset = get_streamfile_size(streamfile) - data->start_offset;
|
||||
max_physical_offset = get_streamfile_size(streamfile);
|
||||
|
||||
/* get size of the underlying, non-blocked data */
|
||||
while (physical_offset < max_physical_offset) {
|
||||
|
@ -695,6 +695,7 @@ 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_hdr_sth_dat(STREAMFILE * streamFile);
|
||||
|
||||
VGMSTREAM * init_vgmstream_ngc_vid1(STREAMFILE * streamFile);
|
||||
|
||||
|
@ -381,6 +381,7 @@ VGMSTREAM * (*init_vgmstream_functions[])(STREAMFILE *streamFile) = {
|
||||
init_vgmstream_vxn,
|
||||
init_vgmstream_ea_snr_sns,
|
||||
init_vgmstream_ea_sps,
|
||||
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