mirror of
https://github.com/vgmstream/vgmstream.git
synced 2024-11-25 07:20:10 +01:00
EAAC tweaks
This commit is contained in:
parent
611aa5ed11
commit
d5745c9d6e
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user