0
$\begingroup$

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.

$\endgroup$
9
  • $\begingroup$ I have some questions about what your intended end result is. Are you trying to vary the speed of playback without changing pitch? Or is it your intent to change the pitch to somehow accommodate the change in playback speed? Or do you want the pitch to change along with the playback speed as it would with analog tape? $\endgroup$ Sep 8 at 16:15
  • $\begingroup$ @robertbristow-johnson my intended result is to change the pitch of the buffer in the real-time playback, at least around +-2 times up/down. So variable playback is pretty much == pitch change in this case, and that is what I'm trying to do. $\endgroup$
    – coldmind
    Sep 8 at 16:19
  • $\begingroup$ So would the pitch change be what naturally occurs by speeding up or slowing down playback? I.e. if you sped it up to 2x, the tempo would be double fast and the pitch an octave higher? $\endgroup$ Sep 8 at 16:26
  • 1
    $\begingroup$ Okay, so now I know there isn't splicing or "time-compression" involved. So it is only a matter of interpolation. There should be no problem of aliasing when you're slowing down, but there can be one when you're speeding up. If aliasing is a problem, you need to low-pass filter those high frequency components before striding through the audio samples with your interpolator. $\endgroup$ Sep 8 at 16:34
  • 1
    $\begingroup$ Yes. I believe you have that correctly. Because if you're speeding up to 2x, your 10 kHz sinusoid will become 20 kHz. You want to kill anything above 12 kHz, because it will be shifted to above 24 kHz and that will alias to below 24 kHz. $\endgroup$ Sep 8 at 16:46

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Browse other questions tagged or ask your own question.