From 519659fd3e15ff335ba20ddf4ab5ddf5319d5f31 Mon Sep 17 00:00:00 2001 From: NicknineTheEagle Date: Wed, 23 Jan 2019 06:40:42 +0300 Subject: [PATCH] EAAC: Properly calculate stream size for bitrate --- src/layout/blocked_ea_sns.c | 50 ++++++++++++++++----------- src/meta/ea_eaac.c | 67 +++++++++++++++++++++++++++++++------ 2 files changed, 86 insertions(+), 31 deletions(-) diff --git a/src/layout/blocked_ea_sns.c b/src/layout/blocked_ea_sns.c index dda45807..c31dab29 100644 --- a/src/layout/blocked_ea_sns.c +++ b/src/layout/blocked_ea_sns.c @@ -5,38 +5,52 @@ /* EA SNS/SPS blocks */ void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) { STREAMFILE* streamFile = vgmstream->ch[0].streamfile; - uint32_t block_size, block_samples; + uint32_t block_id, block_size, block_samples; size_t file_size = get_streamfile_size(streamFile); off_t channel_start; size_t channel_interleave; int i; - /* always BE */ - block_size = read_32bitBE(block_offset + 0x00,streamFile); - block_samples = read_32bitBE(block_offset + 0x04,streamFile); - - /* EOF */ - if (block_size == 0 || block_offset >= file_size) { - vgmstream->current_block_offset = file_size; - vgmstream->next_block_offset = file_size + 0x04; - vgmstream->current_block_samples = vgmstream->num_samples; + /* EOF reads: signal we have nothing and let the layout fail */ + if (block_offset >= get_streamfile_size(streamFile)) { + vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset; + vgmstream->current_block_samples = -1; return; } + /* always BE */ + block_size = read_32bitBE(block_offset + 0x00,streamFile); + /* At 0x00(1): block flag * - in SNS: 0x00=normal block, 0x80=last block (not mandatory) * - in SPS: 0x48=header, 0x44=normal block, 0x45=last block (empty) */ + block_id = (block_size & 0x00FFFFFF) >> 24; block_size &= 0x00FFFFFF; - switch(vgmstream->coding_type) { + if (block_id == 0x00 || block_id == 0x80 || block_id == 0x44) { + block_samples = read_32bitBE(block_offset + 0x04, streamFile); + } else { + block_samples = 0; + } + + vgmstream->current_block_offset = block_offset; + vgmstream->next_block_offset = block_offset + block_size; + vgmstream->current_block_samples = block_samples; + + /* no need to setup offsets (plus could read over filesize near EOF) */ + if (block_samples == 0) + return; + + switch (vgmstream->coding_type) { case coding_NGC_DSP: /* 0x04: unknown (0x00/02), 0x08: some size?, 0x34: null? */ - channel_start = read_32bitBE(block_offset+0x08+0x00,streamFile); - channel_interleave = read_32bitBE(block_offset+0x08+0x0c,streamFile); + channel_start = read_32bitBE(block_offset + 0x08 + 0x00, streamFile); + channel_interleave = read_32bitBE(block_offset + 0x08 + 0x0c, streamFile); /* guessed as all known EA DSP only have one block with subheader (maybe changes coefs every block?) */ if (channel_start >= 0x40) { - dsp_read_coefs_be(vgmstream,streamFile, block_offset+0x08+0x10,0x28); - dsp_read_hist_be (vgmstream,streamFile, block_offset+0x08+0x30,0x28);//todo guessed and doesn't fix clicks in full loops + dsp_read_coefs_be(vgmstream, streamFile, block_offset + 0x08 + 0x10, 0x28); + dsp_read_hist_be(vgmstream, streamFile, block_offset + 0x08 + 0x30, 0x28);//todo guessed and doesn't fix clicks in full loops } break; @@ -47,15 +61,11 @@ void block_update_ea_sns(off_t block_offset, VGMSTREAM * vgmstream) { } for (i = 0; i < vgmstream->channels; i++) { - vgmstream->ch[i].offset = block_offset + 0x08 + channel_start + i*channel_interleave; + vgmstream->ch[i].offset = block_offset + 0x08 + channel_start + i * channel_interleave; /* also fix first offset (for EALayer3) */ if (block_offset == vgmstream->ch[i].channel_start_offset) { vgmstream->ch[i].channel_start_offset = vgmstream->ch[i].offset; } } - - vgmstream->current_block_offset = block_offset; - vgmstream->next_block_offset = block_offset + block_size; - vgmstream->current_block_samples = block_samples; } diff --git a/src/meta/ea_eaac.c b/src/meta/ea_eaac.c index 2630c454..6395023f 100644 --- a/src/meta/ea_eaac.c +++ b/src/meta/ea_eaac.c @@ -342,7 +342,7 @@ VGMSTREAM * init_vgmstream_ea_sbr(STREAMFILE *streamFile) { for (i = 0; i < num_metas; i++) { entry_offset = metas_offset + 0x06 * i; - meta_type = read_16bitBE(entry_offset, streamFile); + meta_type = read_16bitBE(entry_offset + 0x00, streamFile); data_offset = read_32bitBE(entry_offset + 0x02, streamFile); type_desc = read_32bitBE(types_offset + 0x06 * meta_type, streamFile); @@ -497,7 +497,7 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) { uint32_t num_sounds; uint8_t version, sub_version, block_id; off_t table_offset, entry_offset, snr_offset, sns_offset; - size_t /*snr_size,*/ sns_size; + /* size_t snr_size sns_size; */ int32_t(*read_32bit)(off_t, STREAMFILE*); STREAMFILE *musFile = NULL; VGMSTREAM *vgmstream = NULL; @@ -547,8 +547,10 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) { entry_offset = table_offset + (target_stream - 1) * 0x1c; snr_offset = read_32bit(entry_offset + 0x08, musFile) * 0x10; sns_offset = read_32bit(entry_offset + 0x0c, musFile) * 0x80; - //snr_size = read_32bit(entry_offset + 0x10, musFile); + /* + snr_size = read_32bit(entry_offset + 0x10, musFile); sns_size = read_32bit(entry_offset + 0x14, musFile); + */ block_id = read_8bit(sns_offset, musFile); if (block_id != EAAC_BLOCKID0_DATA && block_id != EAAC_BLOCKID0_END) @@ -559,7 +561,6 @@ VGMSTREAM * init_vgmstream_ea_mpf_mus_eaac(STREAMFILE *streamFile) { goto fail; vgmstream->num_streams = num_sounds; - vgmstream->stream_size = sns_size; close_streamfile(musFile); return vgmstream; @@ -764,7 +765,7 @@ typedef struct { static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *streamData, eaac_header *eaac); static layered_layout_data* build_layered_eaaudiocore_eaxma(STREAMFILE *streamFile, eaac_header *eaac); - +static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset); /* 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), @@ -831,7 +832,7 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST eaac.loop_offset = eaac.stream_offset + eaac.loop_offset; } else { - /* RAM assets only one block in case in case of full loops */ + /* RAM assets have only one block in case of full loops */ eaac.loop_offset = eaac.stream_offset; /* implicit */ } @@ -1023,9 +1024,13 @@ static VGMSTREAM * init_vgmstream_eaaudiocore_header(STREAMFILE * streamHead, ST goto fail; } - - if (!vgmstream_open_stream(vgmstream,temp_streamFile ? temp_streamFile : streamData,start_offset)) + if (!vgmstream_open_stream(vgmstream, temp_streamFile ? temp_streamFile : streamData, start_offset)) goto fail; + + if (eaac.loop_start == 0) { + vgmstream->stream_size = calculate_eaac_size(vgmstream, temp_streamFile ? temp_streamFile : streamData, &eaac, start_offset); + } + close_streamfile(temp_streamFile); return vgmstream; @@ -1037,12 +1042,50 @@ fail: static size_t get_snr_size(STREAMFILE *streamFile, off_t offset) { switch (read_8bit(offset + 0x04, streamFile) >> 4 & 0x0F) { /* flags */ - case EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED: return 0x10; - case EAAC_FLAG_LOOPED: return 0x0C; - default: return 0x08; + case EAAC_FLAG_LOOPED | EAAC_FLAG_STREAMED: return 0x10; + case EAAC_FLAG_LOOPED: return 0x0C; + default: return 0x08; } } +static size_t calculate_eaac_size(VGMSTREAM *vgmstream, STREAMFILE *streamFile, eaac_header *eaac, off_t start_offset) { + uint32_t total_samples; + size_t stream_size, file_size; + + switch (eaac->codec) { + case EAAC_CODEC_EAXMA: + case EAAC_CODEC_EALAYER3_V1: + case EAAC_CODEC_EALAYER3_V2_PCM: + case EAAC_CODEC_EALAYER3_V2_SPIKE: + case EAAC_CODEC_EATRAX: + case EAAC_CODEC_EAMP3: + case EAAC_CODEC_EAOPUS: + stream_size = get_streamfile_size(streamFile); + break; + default: + stream_size = 0; + total_samples = 0; + file_size = get_streamfile_size(streamFile); + vgmstream->next_block_offset = start_offset; + + while (vgmstream->next_block_offset < file_size && total_samples != vgmstream->num_samples) { + block_update_ea_sns(vgmstream->next_block_offset, vgmstream); + if (vgmstream->current_block_samples == 0) + continue; + + /* stream size is almost never provided in bank files so we have to calc it manually */ + stream_size += vgmstream->next_block_offset - vgmstream->ch[0].offset; + total_samples += vgmstream->current_block_samples; + } + + /* reset once we're done */ + block_update(start_offset, vgmstream); + break; + } + + return stream_size; +} + /* Actual looping uses 2 block sections, separated by a block end flag *and* padded. * @@ -1108,6 +1151,8 @@ static segmented_layout_data* build_segmented_eaaudiocore_looping(STREAMFILE *st if (!vgmstream_open_stream(data->segments[i],temp_streamFile[i],0x00)) goto fail; + + data->segments[i]->stream_size = calculate_eaac_size(data->segments[i], temp_streamFile[i], eaac, 0x00); } if (!setup_layout_segmented(data))