0
$\begingroup$

I am writing a sound generator that needs to scan through audio samples at an arbitrary rate. When the sample is played at it's original rate, it sounds fine. But when I change the playback speed, it produces aliasing noise.

I read this answer and it seems that I need to use Lanczos resampling to get a better outcome (I have tried the linear interpolation suggested in the answer. It improved the issue but still not optimal).

Based on Wikipedia's info about Lanczos, to calculate the value for sample at position x, I'll need the samples between x - a and x + a:

enter image description here

In the following example, the system periodically calls the function processAudio to get the next chunk of audio to playback. I applied the Lanczos function to the sample calculation, but the aliasing isn't improved at all, and it sounds worse than linear interpolation. Is there something wrong with my approach?

float samplePlaybackSpeed = 1.25f;
float currentPlayHead = 0.0f;
int filterFactor = 2;
// system callback function to fetch the next chunk of audio
void processAudio(float[] data)
{
    // output data is stereo
    for (int i = 0; i < data.Length; i += 2)
    {
        int flooredIndex = (int)Mathf.Floor(currentPlayHead);
        for (int j = flooredIndex - filterFactor + 1; j < flooredIndex + filterFactor; ++j)
        {
            if (j >= 0 && j < sampleLength)
            {
                float value = lanczos(currentPlayHead - j);
                // left channel
                data[i] += samples[j * 2] * value;
                // right channel
                data[i + 1] += samples[j * 2 + 1] * value;
            }
        }

        // round the playhead to the beginning when exceeding the sample length
        currentPlayHead = (currentPlayHead + samplePlaybackSpeed) % sampleLength;
    }
}

float lanczos(float pos)
{
    if (pos == 0)
        return 1;

    return filterFactor * Mathf.Sin(Mathf.PI * pos) * Mathf.Sin(Mathf.PI * pos / filterFactor) 
            / (Mathf.PI * Mathf.PI * pos * pos);   
}
$\endgroup$
  • $\begingroup$ use only x+a for the first sample and x-a for the last sample. Of course, the first and last a-1 samples will need special treatment and a slight adjustment of the original formula. $\endgroup$ – dsp_user Apr 14 at 18:12
  • $\begingroup$ @dsp_user do you mean there needs to be additional treatment in addition to what you just mentioned? If so, what is it? Thanks! $\endgroup$ – Thinium Apr 14 at 19:10
  • $\begingroup$ I meant if a is, say, 5 then not only the first sample needs special treatment but also 2nd, 3rd and 4th because you won't be able to apply the formula directly to them. For example, to handle the 3rd sample, you can't subtract 5 samples from it so you'll have to change either a accordingly (to 3 in this case) or simply not use subtraction for the first a samples. The same thing is true for addition regarding the last a samples. There might be other more clever solutions but I wouldn't worry much. $\endgroup$ – dsp_user Apr 15 at 5:55
  • $\begingroup$ @dsp_user thanks for the tips! I implemented it as you suggested but the aliasing issue remains. Could you please take a look what is wrong in my appraoch? Thanks! $\endgroup$ – Thinium Apr 15 at 17:07
  • $\begingroup$ you said that the aliasing is evident when you change the playback speed. I assume that the reason for changing the playback speed is that your audio files have different sampling rates so you're trying to handle such a situation by changing the playback speed after you've interpolated your signal to a new length. Is my understanding correct ? Do you need to keep the original pitch? $\endgroup$ – dsp_user Apr 15 at 17:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.