Rewrite the linear interpolation SRC to give the exact same results as the one in AXWii

This commit is contained in:
Pierre Bourdon 2013-01-25 19:16:07 +01:00
parent 9776f135e2
commit bad4f7f790
1 changed files with 43 additions and 21 deletions

View File

@ -307,38 +307,60 @@ void GetInputSamples(PB_TYPE& pb, s16* samples, const s16* coeffs)
// samples. // samples.
u32 curr_pos = pb.src.cur_addr_frac; u32 curr_pos = pb.src.cur_addr_frac;
// These are the two samples between which we interpolate. The initial // This is the circular buffer containing samples to use for the
// values are stored in the PB, and we update them when resampling the // interpolation. It is initialized with the values from the PB, and it
// input data. // will be stored back to the PB at the end.
s16 curr0 = pb.src.last_samples[2]; s16 temp[4];
s16 curr1 = pb.src.last_samples[3]; 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) 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; curr_pos += ratio;
// While our current position is >= 1.0, shift to the next 2 // While our current position is >= 1.0, push new samples to the
// samples for interpolation. // circular buffer.
while ((curr_pos >> 16) != 0) while (curr_pos >= 0x10000)
{ {
curr0 = curr1; temp[idx++ & 3] = AcceleratorGetSample();
curr1 = AcceleratorGetSample();
curr_pos -= 0x10000; 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. // position.
pb.src.last_samples[2] = curr0; pb.src.last_samples[3] = temp[--idx & 3];
pb.src.last_samples[3] = curr1; 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; pb.src.cur_addr_frac = curr_pos & 0xFFFF;
} }
else // SRCTYPE_NEAREST else // SRCTYPE_NEAREST