Resampling an AudioSampleBuffer


#1

Is there a "simple" way to resample an AudioSampleBuffer? I tried playing with ResamplingAudioSource but I couldn't really figure out how to use it for a fixed buffer (not live). 

What should I do or where should I look?

 


#2

There's also the LagrangeInterpolator, which is a bit more low-level, if that's what you're looking for?


#3

Thanks for the reply. I basically need to load a IR sample in a AudioSampleBuffer and stretch it according to the host samplerate and a stretch factor.

I tried the LagrangeInterpolator but there's something wrong with my implementation as it doesn't do exactly what it should (or at least what I think it should do). 

When then I use the new buffer for the convolution if the stretch is < 1 it looks like the sample is slower (while it should be faster) and usually when it's > 1 i get strange repetitions only on left channel (and sometimes a huge click/pop and no audio anymore).

I am probably overthinking here, but I just need to change the speed of this AudioSampleBuffer according to the host samplerate and a stretch factor.

 


#4

*bump*

Any help with this?

 


#5

Here’s my interpretation of how to use the LagrangeInterpolator, but unfortunately it crashes with an exception on the second channel, any idea why? I really need this to work.
waveBuffer (AudioSampleBuffer) is the destination buffer that’s in the class…

void Buffer::fillBuffer(AudioFormatReader *reader, double currentSampleRate)
 {
	AudioSampleBuffer temp;

	waveBuffer.clear();
	temp.clear();
	
	double ratio = currentSampleRate / reader->sampleRate;

	temp.setSize((int)reader->numChannels, (int)reader->lengthInSamples);
	waveBuffer.setSize((int)reader->numChannels, (int)((double)reader->lengthInSamples * ratio));

	reader->read(&temp, 0, (int)reader->lengthInSamples, 0, true, true);

	ScopedPointer<LagrangeInterpolator> resampler = new LagrangeInterpolator();

	const float **inputs  = temp.getArrayOfReadPointers();
	float **outputs = waveBuffer.getArrayOfWritePointers();
	for (int c = 0; c < waveBuffer.getNumChannels(); c++)
	{
		resampler->reset();
		resampler->process(ratio, inputs[c], outputs[c], waveBuffer.getNumSamples());
	}
}

#6

OK I’ve discovered the ratio was 1/ the correct value but it still crashes when down-sampling, it seems to work fine when up-sampling. Is the LagrangeAlgorithm code broken?
The ‘in’ gets unreadable here:-

 else
    {
        for (int i = numOut; --i >= 0;)
        {
            while (pos < actualRatio)
            {
                pushInterpolationSample (lastInputSamples, *in++);
                pos += 1.0;
            }

            pos -= actualRatio;
            *out++ = InterpolatorType::valueAtOffset (lastInputSamples, jmax (0.0f, 1.0f - (float) pos));
        }
    }

#7

OK I’ve got it now, there is no filtering in the Lagrange code but ho-hum, here’s the new version:
*Note I now divide the incoming length by the ratio.

AudioSampleBuffer temp;

sofar = 0;
waveBuffer.clear();
temp.clear();

double ratio =  reader->sampleRate / hostSampleRate;

temp.setSize((int)reader->numChannels, (int)reader->lengthInSamples);
waveBuffer.setSize((int)reader->numChannels, (int)(((double)reader->lengthInSamples) / ratio));

reader->read(&temp, 0, (int)reader->lengthInSamples, 0, true, true);

ScopedPointer<LagrangeInterpolator> resampler = new LagrangeInterpolator();

const float **inputs  = temp.getArrayOfReadPointers();
float **outputs = waveBuffer.getArrayOfWritePointers();
for (int c = 0; c < waveBuffer.getNumChannels(); c++)
{
	resampler->reset();
	resampler->process(ratio, inputs[c], outputs[c], waveBuffer.getNumSamples());
}