I'm trying to correctly implement the real-time variable speed playback of my buffer, to achieve the pitch shifting. I don't need to stretch to preserve the original length.
Buffer is calculated with 48000 sampling rate.
The code I have so far works well until some high-frequency audio is stored. Then when pitching up or down it starts to produce awful aliasing.
float MyClass::GetOutputSample() {
int integral = static_cast<int32_t>(interpolation_index_);
float frac = interpolation_index_ - static_cast<float>(integral);
interpolation_index_ += pitch_;
if(interpolation_index_ > BUF_LEN) {
interpolation_index_ = 0;
}
int t = (integral + BUF_LEN);
float y0 = output_buffer_[(t) % BUF_LEN];
float ym1 = output_buffer_[(t - 1) % BUF_LEN];
float ym2 = output_buffer_[(t - 2) % BUF_LEN];
float y1 = output_buffer_[(t + 1) % BUF_LEN];
float y2 = output_buffer_[(t + 2) % BUF_LEN];
float y3 = output_buffer_[(t + 3) % BUF_LEN];
// 6-point, 5th-order Hermite (x-form)
float eighthym2 = 1/8.0*ym2;
float eleventwentyfourthy2 = 11/24.0*y2;
float twelfthy3 = 1/12.0*y3;
float c0 = y0;
float c1 = 1/12.0*(ym2-y2) + 2/3.0*(y1-ym1);
float c2 = 13/12.0*ym1 - 25/12.0*y0 + 3/2.0*y1 - eleventwentyfourthy2 + twelfthy3 - eighthym2;
float c3 = 5/12.0*y0 - 7/12.0*y1 + 7/24.0*y2 - 1/24.0*(ym2+ym1+y3);
float c4 = eighthym2 - 7/12.0*ym1 + 13/12.0*y0 - y1 + eleventwentyfourthy2 - twelfthy3;
float c5 = 1/24.0*(y3-ym2) + 5/24.0*(ym1-y2) + 5/12.0*(y1-y0);
float result = ((((c5*frac+c4)*frac+c3)*frac+c2)*frac+c1)*frac + c0;
return result;
}
BUF_LEN
is 144000 samples of f32.
How I can mitigate aliasing in my case? If I understand correctly before doing the interpolation the original buffer should be upsampled to something like 96000 with another interpolation. I can do that at the time of buffer calculation so it can be performed once.
So what next? Should the upsampled buffer be low-passed filtered? I do not fully understand this step.
Also, how correctly downsample in real time after the pitch-shifting interpolation? Should another interpolation be executed?
The important note is that this is being executed in the embedded platform so computational resources are limited.