From bad4f7f790b6038450488d1c23d8b65329cea4b4 Mon Sep 17 00:00:00 2001 From: Pierre Bourdon Date: Fri, 25 Jan 2013 19:16:07 +0100 Subject: [PATCH] Rewrite the linear interpolation SRC to give the exact same results as the one in AXWii --- .../Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h | 64 +++++++++++++------ 1 file changed, 43 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h index 649ad3c37f..92c797ad14 100644 --- a/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h +++ b/Source/Core/Core/Src/HW/DSPHLE/UCodes/UCode_AX_Voice.h @@ -307,38 +307,60 @@ void GetInputSamples(PB_TYPE& pb, s16* samples, const s16* coeffs) // samples. u32 curr_pos = pb.src.cur_addr_frac; - // These are the two samples between which we interpolate. The initial - // values are stored in the PB, and we update them when resampling the - // input data. - s16 curr0 = pb.src.last_samples[2]; - s16 curr1 = pb.src.last_samples[3]; + // This is the circular buffer containing samples to use for the + // interpolation. It is initialized with the values from the PB, and it + // will be stored back to the PB at the end. + s16 temp[4]; + u32 idx = 0; + + temp[idx++ & 3] = pb.src.last_samples[0]; + temp[idx++ & 3] = pb.src.last_samples[1]; + temp[idx++ & 3] = pb.src.last_samples[2]; + temp[idx++ & 3] = pb.src.last_samples[3]; for (u32 i = 0; i < SAMPLES_PER_FRAME; ++i) { - // Get our current fractional position, used to know how much of - // curr0 and how much of curr1 the output sample should be. - s32 curr_frac_pos = curr_pos & 0xFFFF; - - // Linear interpolation: s1 + (s2 - s1) * pos - s16 sample = curr0 + (s16)(((curr1 - curr0) * (s32)curr_frac_pos) >> 16); - samples[i] = sample; - curr_pos += ratio; - // While our current position is >= 1.0, shift to the next 2 - // samples for interpolation. - while ((curr_pos >> 16) != 0) + // While our current position is >= 1.0, push new samples to the + // circular buffer. + while (curr_pos >= 0x10000) { - curr0 = curr1; - curr1 = AcceleratorGetSample(); + temp[idx++ & 3] = AcceleratorGetSample(); curr_pos -= 0x10000; } + + // Get our current fractional position, used to know how much of + // curr0 and how much of curr1 the output sample should be. + u16 curr_frac = curr_pos & 0xFFFF; + u16 inv_curr_frac = -curr_frac; + + // Interpolate! If curr_frac is 0, we can simply take the last + // sample without any multiplying. + s16 sample; + if (curr_frac) + { + s32 s0 = temp[idx++ & 3]; + s32 s1 = temp[idx++ & 3]; + + sample = ((s0 * inv_curr_frac) + (s1 * curr_frac)) >> 16; + idx += 2; + } + else + { + sample = temp[idx++ & 3]; + idx += 3; + } + + samples[i] = sample; } - // Update the two last_samples values in the PB as well as the current + // Update the four last_samples values in the PB as well as the current // position. - pb.src.last_samples[2] = curr0; - pb.src.last_samples[3] = curr1; + pb.src.last_samples[3] = temp[--idx & 3]; + pb.src.last_samples[2] = temp[--idx & 3]; + pb.src.last_samples[1] = temp[--idx & 3]; + pb.src.last_samples[0] = temp[--idx & 3]; pb.src.cur_addr_frac = curr_pos & 0xFFFF; } else // SRCTYPE_NEAREST