EAAC tweaks

This commit is contained in:
NicknineTheEagle 2018-07-21 23:09:44 +03:00
parent 611aa5ed11
commit d5745c9d6e
4 changed files with 53 additions and 39 deletions

View File

@ -250,7 +250,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);

View File

@ -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;
}

View File

@ -6,6 +6,7 @@
/* 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);
/* .SNR+SNS - from EA latest games (~2008-2013), v0 header */
VGMSTREAM * init_vgmstream_ea_snr_sns(STREAMFILE * streamFile) {
@ -18,14 +19,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;
}
@ -214,7 +208,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
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;
flags = (read_8bit(snr_offset + 0x04, sthFile) >> 4) & 0x0F;
if (i == target_stream - 1)
break;
@ -233,7 +227,7 @@ VGMSTREAM * init_vgmstream_ea_hdr_sth_dat(STREAMFILE *streamFile) {
sns_offset += block_size;
if (flags & 2) {
if (flags & 4) {
if (block_id == 0x80)
break;
}
@ -269,18 +263,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) {
@ -288,27 +290,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;
@ -342,7 +347,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);
@ -376,7 +381,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 */
@ -412,7 +417,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 */
@ -448,3 +453,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;
}
}

View File

@ -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 */
}
@ -184,7 +185,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);
@ -192,6 +193,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;