Help using GenericInterpolator

I’m trying to use GenericInterpolator (LinearInterpolator) to resample and correct the speed of a sample. I started with the processBlock() code from the Sampler tutorial, and then tried to add in the interpolator. It plays back correctly if the speed is 1 (i.e. if the sample and system bitrates match), but if the speed is less that 1, it comes out garbled. I’m really bad at this low level DSP code and it would be great if someone could help.

Here’s what I have so far:

void SingleSample::processBlock(juce::AudioBuffer<float>& outputBuffer)
{
    if (!playing || sampleBuffer->getNumSamples() == 0) return;


    auto numInputChannels = sampleBuffer->getNumChannels();
    auto numOutputChannels = outputBuffer.getNumChannels();

    auto outputSamplesRemaining = outputBuffer.getNumSamples();
    auto outputSamplesOffset = 0;

    const auto speed = thisSampleRate / systemSampleRate;

    while (outputSamplesRemaining > 0)
    {
        auto bufferSamplesRemaining = sampleBuffer->getNumSamples() - position;
        auto samplesThisTime = juce::jmin(outputSamplesRemaining, bufferSamplesRemaining);

        for (auto channel = 0; channel < numOutputChannels; ++channel)
        {
            const auto chan = channel % numInputChannels;

            auto interpolator = (*interpolators)[chan];

            interpolator->process(speed, sampleBuffer->getReadPointer(chan, position),
                resampleBuffer->getWritePointer(chan), samplesThisTime, bufferSamplesRemaining, 0);

            outputBuffer.addFrom(channel,
                outputSamplesOffset,
                *resampleBuffer,
                chan,
                0,
                samplesThisTime);
        }

        outputSamplesRemaining -= samplesThisTime;
        outputSamplesOffset += samplesThisTime;
        position += samplesThisTime;

        if (position == sampleBuffer->getNumSamples())
        {
            position = 0;
            playing = false;
        }
    }
}

A few notes:

resampleBuffer is initialized to have the default buffer size. My idea is that it will resample sampleBuffer to the right speed, and then copy that across to outputBuffer in the same pass. But I’m not really sure if this is correct or not.

–Someone might tell me that I don’t actually need GenericInterpolator if all I’m doing is correcting for the sample’s bitrate. I’d be interested to hear this, but in my case I think I actually do want to use it, since I’m going to have more dynamic options for playback speed once I’ve gotten this basic version working.

–For now, let’s assume that I’ve got all threading issues solved (i.e. that’s not what I’m trying to work through here).

Perhaps this code is assuming that samples are consumed from the buffer at the same rate at which samples are output? But that is not always the case.

e.g. if you are playing back the sample at say 2x normal speed, then the sampleBuffer will be consumed twice as fast. So in this example for every 100 samples you add to ‘outputSamplesRemaining’ you should really be adding 200 to ‘position’.

So you need to cleanly separate the concept of how many samples you are consuming from the sampleBuffer..vs how many samples you are outputting from the plugin.

Hope that makes sense.

Thanks Jeff, this makes a lot of sense. I’ll have a go at updating it.