Beginner: pitch shift with resampling

I am trying to implement my first pitch shifter and it seems I hit a wall with anti-aliasing. There are a lot of reading sources out there but most of them are overwhelming and I can’t wrap my head around the math. I would appreciate a solution for a simple use case to get the ball rolling.

So I am building a sampler which reads files from disk. Samples are clear piano sounds with defined pitch and I want to increment/decrement semi tones. No need to preserve the original length and assume I am working with a constant buffer size of 480 samples.

I figured the easiest way to go is with resampling. So if I want to increment 2 semi tones I get a calculated ratio of 1.11 and therefor grab 480*1.11 = 539 samples from disk into a temp buffer with intention to squeeze them into a 480 samples output buffer. I can do this with something like:

for (int i = 0; i < 480; i++)
{
int x = roundToInt(float(i) * 1.11f);
outBuffer[channel][i] = tempBuffer[channel][x];
}

Surprisingly simple (at least for me) but it works and gives a perfect result to my untrained ear. But if I do the same process for 1 semi tone which gives a ratio of 1.06 = 509 samples, I get an excellent result from the pitch perspective but also a high humming noise which I believe is some aliased frequency.

Enter: upsampling and FIR. I managed to get these guys to work but got no effect on the final result. Due to lack of understanding I just tried several combinations of tempBuffer upsampling and FIR parameters and the only thing that somehow worked was setting the FIR cutoff frequency at about 2KHz which killed the humming noise together with other valuable harmonics.

So in the case of x semi tones inc/dec, how do I calculate the needed upsampling rate and FIR parameters to block aliased frequencies and minimize the overall filter effect?

Use a better interpolation method. What you are doing at the moment is called „truncation“ which is the worst interpolation method (aka none). Trying to fix that with a FIR and upsampling will not work. Look up linear interpolation - there are much better algorithms out there but for a simple pitch shift this should be fine.

1 Like

Thanks. That was a step in the right direction. I called
interpolator.process(ratio, tempBuffer.getReadPointer(0), outputBuffer.getWritePointer(0), 480);
and without any FIR and upsampling the humming was gone, except for the attack transient part. I can hear the humming decreases as the sample progresses into the sustain part, which makes sense to me considering the nature of piano samples.

So from here should I experiment with upsampling and FIR to remove aliasing during the transient part?