0

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);   
}
Thinium
  • 25
  • 7
  • 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. – dsp_user Apr 14 '20 at 18:12
  • @dsp_user do you mean there needs to be additional treatment in addition to what you just mentioned? If so, what is it? Thanks! – Thinium Apr 14 '20 at 19:10
  • 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. – dsp_user Apr 15 '20 at 05:55
  • @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! – Thinium Apr 15 '20 at 17:07
  • 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? – dsp_user Apr 15 '20 at 17:57
  • @dsp_user nope, I intentionally change the playback speed to change the original pitch. I am creating a sample based synthesizer (where people can play back part of the sample in arbitrary speed). – Thinium Apr 15 '20 at 18:07
  • how do you choose the interpolation factor based on the playback speed increase/decrease? – dsp_user Apr 15 '20 at 18:15
  • @dsp_user do you mean "filterFactor" in my example? currently it's just an hardcoded number. Based on wikipedia it seems like a good value for performance/quality. – Thinium Apr 15 '20 at 18:29
  • in your example, you're upsampling by a factor of 2 so you probably should run your signal through a lo-pass filter to prevent aliasing but since your sound generator needs to run in real-time, this probably isn't an option. Perhaps you can try using higher order interpolation methods (e.g spline), which could potentially produce less aliasing (although there're no guarantees) – dsp_user Apr 15 '20 at 19:34
  • I guess I am doing something totally wrong in my example then. With Lanczos I intended to interpolate the value, but if I understand you correctly, it's only up-sampling the signal by a factor of 2? I'll look into spline. Thanks! – Thinium Apr 15 '20 at 19:46

0 Answers0