From c11a3f822d539e68ffb82ae7dbb94f85929b3653 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 1 Mar 2020 12:25:40 +0100 Subject: [PATCH] Fix some .awc [Max Payne 3 (PC)] --- src/layout/blocked_awc.c | 39 +++++++++++++++++++++++++++------------ src/meta/awc.c | 2 +- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/layout/blocked_awc.c b/src/layout/blocked_awc.c index b59ea861..3504e1d7 100644 --- a/src/layout/blocked_awc.c +++ b/src/layout/blocked_awc.c @@ -4,19 +4,21 @@ #include "../vgmstream.h" -static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, int channels, int big_endian); +static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian); +static size_t get_block_header_size(STREAMFILE* sf, off_t offset, size_t channel_header_size, int channels, int big_endian); /* AWC music chunks */ void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) { - STREAMFILE* streamFile = vgmstream->ch[0].streamfile; + STREAMFILE* sf = vgmstream->ch[0].streamfile; int32_t (*read_32bit)(off_t,STREAMFILE*) = vgmstream->codec_endian ? read_32bitBE : read_32bitLE; size_t header_size, entries, block_size, block_samples; + size_t channel_header_size; int i; /* assumed only AWC_IMA enters here, MPEG/XMA2 need special parsing as blocked layout is too limited */ - - entries = read_32bit(block_offset + 0x18*0 + 0x04, streamFile); /* assumed same for all channels */ - block_samples = entries * (0x800-4)*2; + entries = read_32bit(block_offset + 0x04, sf); /* se first channel, assume all are the same */ + //block_samples = entries * (0x800-4)*2; //todo use + block_samples = read_32bit(block_offset + 0x0c, sf); block_size = vgmstream->full_block_size; vgmstream->current_block_offset = block_offset; @@ -25,32 +27,45 @@ void block_update_awc(off_t block_offset, VGMSTREAM * vgmstream) { /* starts with a header block */ /* for each channel - * 0x00: start entry within channel (ie. entries * ch) + * 0x00: start entry within channel (ie. entries * ch) but may be off by +1/+2 * 0x04: entries * 0x08: samples to discard in the beginning of this block (MPEG only?) * 0x0c: samples in channel (for MPEG/XMA2 can vary between channels) - * 0x10: MPEG only: close to number of frames but varies a bit? - * 0x14: MPEG only: channel usable data size (not counting padding) + * (next fields don't exist in later versions for IMA) + * 0x10: (MPEG only, empty otherwise) close to number of frames but varies a bit? + * 0x14: (MPEG only, empty otherwise) channel usable data size (not counting padding) * for each channel * 32b * entries = global samples per frame in each block (for MPEG probably per full frame) */ - header_size = get_block_header_size(streamFile, block_offset, vgmstream->channels, vgmstream->codec_endian); + channel_header_size = get_channel_header_size(sf, block_offset, vgmstream->channels, vgmstream->codec_endian); + header_size = get_block_header_size(sf, block_offset, channel_header_size, vgmstream->channels, vgmstream->codec_endian); for (i = 0; i < vgmstream->channels; i++) { vgmstream->ch[i].offset = block_offset + header_size + 0x800*entries*i; + VGM_ASSERT(entries != read_32bit(block_offset + channel_header_size*i + 0x04, sf), "AWC: variable number of entries found at %lx\n", block_offset); } } -static size_t get_block_header_size(STREAMFILE *streamFile, off_t offset, int channels, int big_endian) { +static size_t get_channel_header_size(STREAMFILE* sf, off_t offset, int channels, int big_endian) { + int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; + + /* later games have an smaller channel header, try to detect using + * an empty field not in IMA */ + if (read_32bit(offset + 0x14, sf) == 0x00) + return 0x18; + return 0x10; +} + +static size_t get_block_header_size(STREAMFILE* sf, off_t offset, size_t channel_header_size, int channels, int big_endian) { size_t header_size = 0; int i; int entries = channels; int32_t (*read_32bit)(off_t,STREAMFILE*) = big_endian ? read_32bitBE : read_32bitLE; for (i = 0; i < entries; i++) { - header_size += 0x18; - header_size += read_32bit(offset + 0x18*i + 0x04, streamFile) * 0x04; /* entries in the table */ + header_size += channel_header_size; + header_size += read_32bit(offset + channel_header_size*i + 0x04, sf) * 0x04; /* entries in the table */ } if (header_size % 0x800) /* padded */ diff --git a/src/meta/awc.c b/src/meta/awc.c index 70e6cd78..9aeb3962 100644 --- a/src/meta/awc.c +++ b/src/meta/awc.c @@ -301,7 +301,7 @@ static int parse_awc_header(STREAMFILE* streamFile, awc_header* awc) { (awc->codec && awc->codec != codec)) { VGM_LOG("AWC: found header diffs in channel %i, ns=%i vs %i, sr=%i vs %i, c=%i vs %i\n", ch, awc->num_samples, num_samples, awc->sample_rate, sample_rate, awc->codec, codec); - goto fail; + //goto fail; //todo some Max Payne 3 cutscene channels have huge sample diffs } awc->num_samples = num_samples;