From 94de52ec2dae6750a44852fd775ba0b98cc08796 Mon Sep 17 00:00:00 2001 From: bnnm Date: Sun, 3 Dec 2017 01:37:56 +0100 Subject: [PATCH] Clean EA-XA and fix some subsongs (don't use channel_start_offset) Also fix 'sample' type shadowing and Maxis-XA skipping a frame in mono --- src/coding/ea_xa_decoder.c | 163 ++++++++++++++++++------------------- src/meta/maxis_xa.c | 16 +--- src/vgmstream.c | 5 +- 3 files changed, 83 insertions(+), 101 deletions(-) diff --git a/src/coding/ea_xa_decoder.c b/src/coding/ea_xa_decoder.c index 0a9e03ba..f037d183 100644 --- a/src/coding/ea_xa_decoder.c +++ b/src/coding/ea_xa_decoder.c @@ -29,59 +29,57 @@ static const int EA_XA_TABLE[20] = { 0, -1, -3, -4 }; -/* EA XA v2; like ea_xa_int but with "PCM samples" flag and doesn't add 128 on expand or clamp (pre-adjusted by the encoder?) */ +/* EA XA v2 (always mono); like ea_xa_int but with "PCM samples" flag and doesn't add 128 on expand or clamp (pre-adjusted by the encoder?) */ void decode_ea_xa_v2(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do,int channel) { uint8_t frame_info; - int32_t sample_count; int32_t coef1, coef2; - int i, shift; - off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */ + int i, sample_count, shift; - first_sample = first_sample%28; + int pcm_frame_size = 0x01 + 2*0x02 + 28*0x02; + int xa_frame_size = 0x0f; + int frame_samples = 28; + first_sample = first_sample % frame_samples; /* header */ - frame_info = (uint8_t)read_8bit(stream->offset+channel_offset,stream->streamfile); - channel_offset++; + frame_info = read_8bit(stream->offset,stream->streamfile); if (frame_info == 0xEE) { /* PCM frame (used in later revisions), samples always BE */ - stream->adpcm_history1_32 = read_16bitBE(stream->offset+channel_offset+0x00,stream->streamfile); - stream->adpcm_history2_32 = read_16bitBE(stream->offset+channel_offset+0x02,stream->streamfile); - channel_offset += 4; + stream->adpcm_history1_32 = read_16bitBE(stream->offset + 0x01 + 0x00,stream->streamfile); + stream->adpcm_history2_32 = read_16bitBE(stream->offset + 0x01 + 0x02,stream->streamfile); for (i=first_sample,sample_count=0; ioffset+channel_offset,stream->streamfile); - channel_offset+=2; + outbuf[sample_count] = read_16bitBE(stream->offset + 0x01 + 2*0x02 + i*0x02,stream->streamfile); } - /* Only increment offset on complete frame */ - if (channel_offset-stream->channel_start_offset == (2*28)+5) - stream->channel_start_offset += (2*28)+5; - - } else { /* ADPCM frame */ + /* only increment offset on complete frame */ + if (i == frame_samples) + stream->offset += pcm_frame_size; + } + else { /* ADPCM frame */ coef1 = EA_XA_TABLE[(frame_info >> 4) + 0]; coef2 = EA_XA_TABLE[(frame_info >> 4) + 4]; shift = (frame_info & 0x0F) + 8; for (i=first_sample,sample_count=0; ioffset + channel_offset + i/2); + int32_t new_sample; + off_t byte_offset = (stream->offset + 0x01 + i/2); + int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */ sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile); - sample_nibble = (!(i%2) ? sample_byte >> 4 : sample_byte & 0x0F); /* i=even > high nibble */ - sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ - sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32) >> 8; - sample = clamp16(sample); + sample_nibble = (sample_byte >> nibble_shift) & 0x0F; + new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ + new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32) >> 8; + new_sample = clamp16(new_sample); - outbuf[sample_count] = sample; + outbuf[sample_count] = new_sample; stream->adpcm_history2_32 = stream->adpcm_history1_32; - stream->adpcm_history1_32 = sample; + stream->adpcm_history1_32 = new_sample; } - channel_offset += i/2; - /* Only increment offset on complete frame */ - if (channel_offset - stream->channel_start_offset == 0x0F) - stream->channel_start_offset += 0x0F; + /* only increment offset on complete frame */ + if (i == frame_samples) + stream->offset += xa_frame_size; } } @@ -90,43 +88,42 @@ void decode_ea_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing uint8_t frame_info; int32_t coef1, coef2; int i, sample_count, shift; - off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */ int hn = (channel==0); /* high nibble marker for stereo subinterleave, ch0/L=high nibble, ch1/R=low nibble */ - first_sample = first_sample % 28; + int frame_size = 0x1e; + int frame_samples = 28; + first_sample = first_sample % frame_samples; /* header (coefs ch0+ch1 + shift ch0+ch1) */ - frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); - channel_offset++; + frame_info = read_8bit(stream->offset+0x00,stream->streamfile); coef1 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 0]; coef2 = EA_XA_TABLE[(hn ? frame_info >> 4 : frame_info & 0x0F) + 4]; shift = (frame_info & 0x0F) + 8; - frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); - channel_offset++; + frame_info = read_8bit(stream->offset+0x01,stream->streamfile); shift = (hn ? frame_info >> 4 : frame_info & 0x0F) + 8; /* samples */ for (i=first_sample,sample_count=0; ioffset + channel_offset + i); + int32_t new_sample; + off_t byte_offset = (stream->offset + 0x02 + i); + int nibble_shift = (hn ? 4 : 0); /* high nibble first */ sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile); - sample_nibble = (hn ? sample_byte >> 4 : sample_byte & 0x0F); - sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ - sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8; - sample = clamp16(sample); + sample_nibble = (sample_byte >> nibble_shift) & 0x0F; + new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ + new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8; + new_sample = clamp16(new_sample); - outbuf[sample_count] = sample; + outbuf[sample_count] = new_sample; stream->adpcm_history2_32 = stream->adpcm_history1_32; - stream->adpcm_history1_32 = sample; + stream->adpcm_history1_32 = new_sample; } - channel_offset += i; - /* Only increment offset on complete frame */ - if(channel_offset - stream->channel_start_offset == 0x1E) - stream->channel_start_offset += 0x1E; + /* only increment offset on complete frame */ + if (i == frame_samples) + stream->offset += frame_size; } /* EA-XA v1 mono/interleave */ @@ -134,13 +131,13 @@ void decode_ea_xa_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa uint8_t frame_info; int32_t coef1, coef2; int i, sample_count, shift; - off_t channel_offset = stream->channel_start_offset; /* suboffset within frame */ - first_sample = first_sample % 28; + int frame_size = 0x0f; + int frame_samples = 28; + first_sample = first_sample % frame_samples; /* header (coefs+shift ch0) */ - frame_info = read_8bit(stream->offset+channel_offset,stream->streamfile); - channel_offset++; + frame_info = read_8bit(stream->offset,stream->streamfile); coef1 = EA_XA_TABLE[(frame_info >> 4) + 0]; coef2 = EA_XA_TABLE[(frame_info >> 4) + 4]; shift = (frame_info & 0x0F) + 8; @@ -148,39 +145,38 @@ void decode_ea_xa_int(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspa /* samples */ for (i=first_sample,sample_count=0; ioffset + channel_offset + i/2); + int32_t new_sample; + off_t byte_offset = (stream->offset + 0x01 + i/2); + int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */ sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile); - sample_nibble = (!(i%2) ? sample_byte >> 4 : sample_byte & 0x0F); /* i=even > high nibble */ - sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ - sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8; - sample = clamp16(sample); + sample_nibble = (sample_byte >> nibble_shift) & 0x0F; + new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ + new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8; + new_sample = clamp16(new_sample); - outbuf[sample_count] = sample; + outbuf[sample_count] = new_sample; stream->adpcm_history2_32 = stream->adpcm_history1_32; - stream->adpcm_history1_32 = sample; + stream->adpcm_history1_32 = new_sample; } - channel_offset += i/2; - /* Only increment offset on complete frame */ - if(channel_offset - stream->channel_start_offset == 0x0F) - stream->channel_start_offset += 0x0F; + /* only increment offset on complete frame */ + if (i == frame_samples) + stream->offset += frame_size; } -/* Maxis EA-XA v1 (mono+stereo), differing slightly in the header layout in stereo mode */ +/* Maxis EA-XA v1 (mono+stereo) with byte-interleave layout in stereo mode */ void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspacing, int32_t first_sample, int32_t samples_to_do, int channel) { uint8_t frame_info; int32_t coef1, coef2; int i, sample_count, shift; - off_t channel_offset = stream->channel_start_offset; - int frame_size = channelspacing * 15; /* mono samples have a frame of 15, stereo files have frames of 30 */ - first_sample = first_sample % 28; + int frame_size = 0x0f * channelspacing; /* varies in mono/stereo */ + int frame_samples = 28; + first_sample = first_sample % frame_samples; /* header (coefs+shift ch0 + coefs+shift ch1) */ - frame_info = read_8bit(channel_offset,stream->streamfile); - channel_offset += channelspacing; + frame_info = read_8bit(stream->offset + channel,stream->streamfile); coef1 = EA_XA_TABLE[(frame_info >> 4) + 0]; coef2 = EA_XA_TABLE[(frame_info >> 4) + 4]; shift = (frame_info & 0x0F) + 8; @@ -188,27 +184,22 @@ void decode_maxis_xa(VGMSTREAMCHANNEL * stream, sample * outbuf, int channelspac /* samples */ for (i=first_sample,sample_count=0; ioffset + channel_offset); + int32_t new_sample; + off_t byte_offset = (stream->offset + 0x01*channelspacing + (channelspacing == 2 ? i/2 + channel + (i/2)*0x01 : i/2)); + int nibble_shift = (!(i&1)) ? 4 : 0; /* high nibble first */ sample_byte = (uint8_t)read_8bit(byte_offset,stream->streamfile); - sample_nibble = (i&1) ? sample_byte & 0x0F : sample_byte >> 4; - sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ - sample = (sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8; - sample = clamp16(sample); + sample_nibble = (sample_byte >> nibble_shift) & 0x0F; + new_sample = (sample_nibble << 28) >> shift; /* sign extend to 32b and shift */ + new_sample = (new_sample + coef1 * stream->adpcm_history1_32 + coef2 * stream->adpcm_history2_32 + 128) >> 8; + new_sample = clamp16(new_sample); - outbuf[sample_count] = sample; + outbuf[sample_count] = new_sample; stream->adpcm_history2_32 = stream->adpcm_history1_32; - stream->adpcm_history1_32 = sample; - - if(i&1) - stream->offset+=channelspacing; + stream->adpcm_history1_32 = new_sample; } - channel_offset+=i; - /* Only increment offset on complete frame */ - if (channel_offset - stream->channel_start_offset == frame_size) { - stream->channel_start_offset += frame_size; - stream->offset=0; - } + /* only increment offset on complete frame */ + if (i == frame_samples) + stream->offset += frame_size; } diff --git a/src/meta/maxis_xa.c b/src/meta/maxis_xa.c index 73dcbebe..955aca45 100644 --- a/src/meta/maxis_xa.c +++ b/src/meta/maxis_xa.c @@ -5,7 +5,7 @@ VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) { VGMSTREAM * vgmstream = NULL; off_t start_offset; - int loop_flag, channel_count, i; + int loop_flag, channel_count; /* check extension, case insensitive */ if (!check_extensions(streamFile,"xa")) @@ -18,30 +18,22 @@ VGMSTREAM * init_vgmstream_maxis_xa(STREAMFILE *streamFile) { loop_flag = 0; channel_count = read_16bitLE(0x0A,streamFile); + start_offset = 0x18; /* build the VGMSTREAM */ vgmstream = allocate_vgmstream(channel_count,loop_flag); if (!vgmstream) goto fail; - start_offset = 0x18; - vgmstream->channels = channel_count; vgmstream->sample_rate = read_32bitLE(0x0C,streamFile); - vgmstream->coding_type = coding_MAXIS_XA; vgmstream->num_samples = read_32bitLE(0x04,streamFile)/2/channel_count; - vgmstream->layout_type = layout_none; vgmstream->meta_type = meta_MAXIS_XA; + vgmstream->coding_type = coding_MAXIS_XA; + vgmstream->layout_type = layout_none; /* open streams */ if (!vgmstream_open_stream(vgmstream,streamFile,start_offset)) goto fail; - - /* fix channel offsets as needed by the codec (could be simplified) */ - for (i = 0; i < channel_count; i++) { - vgmstream->ch[i].channel_start_offset = start_offset+i; - vgmstream->ch[i].offset = 0; - } - return vgmstream; fail: diff --git a/src/vgmstream.c b/src/vgmstream.c index 543ebf1e..7da50b27 100644 --- a/src/vgmstream.c +++ b/src/vgmstream.c @@ -1062,9 +1062,8 @@ int get_vgmstream_samples_per_frame(VGMSTREAM * vgmstream) { case coding_EA_XA: case coding_EA_XA_int: case coding_EA_XA_V2: - return 28; - case coding_MAXIS_XA: - return 14*vgmstream->channels; + case coding_MAXIS_XA: + return 28; case coding_EA_XAS: return 128; case coding_WS: