Resampling Audio using Lagrange Interpolator

Hi,

I am trying to re-sample audio using juce_LagrangeInterpolator. Could anyone please point to the juce example that explains how to use it the right way?

Thanks.

1 Like
void fileConvert(const File& file, const double& dOutSampleRate) {
	AudioFormatManager formatManager;
	formatManager.registerBasicFormats();
	AudioFormatReader* reader = formatManager.createReaderFor(file);
	if (reader) {
		if (reader->lengthInSamples > 0) {
			if (reader->sampleRate != dOutSampleRate) {
				//find the out file number of samples
				juce::int64 iSamples = ceil(dOutSampleRate * reader->lengthInSamples / reader->sampleRate);

			AudioSampleBuffer tempBuffer(reader->numChannels, iSamples);
			AudioSampleBuffer readBuffer(reader->numChannels, reader->lengthInSamples);

			//read the samples from file
			reader->read(&readBuffer, 0, readBuffer.getNumSamples(), 0, true, true);

			LagrangeInterpolator interpolator;
			int iResult = 0;
			for (int i = 0; i < reader->numChannels; i++) {
				iResult = interpolator.process(reader->sampleRate / dOutSampleRate,
					readBuffer.getReadPointer(i),
					tempBuffer.getWritePointer(i),
					tempBuffer.getNumSamples());
			}


			File sTempFile = File::createTempFile(String("temp_") + file.getFileNameWithoutExtension() + String(".wav"));
			AudioFormat* audioFormat = formatManager.findFormatForFileExtension(sTempFile.getFileExtension());
			juce::AudioFormatWriter* pTempWriter = audioFormat->createWriterFor(sTempFile.createOutputStream(),
				dOutSampleRate,
				reader->numChannels,
				reader->bitsPerSample ? reader->bitsPerSample : 24,
				reader->metadataValues,
				audioFormat->getQualityOptions().size() - 1);
			auto res = pTempWriter->writeFromAudioSampleBuffer(tempBuffer, 0, tempBuffer.getNumSamples());
			pTempWriter->flush();
			delete pTempWriter;

			jassert(res);
			delete reader;
		}
	}
	else {
		delete reader;
		AlertWindow::showMessageBox(AlertWindow::WarningIcon, "No Audio", "There is no enough audio for playing.");
	}
}
else {
	AlertWindow::showMessageBox(AlertWindow::WarningIcon, "Corrupt file Audio", "The audio file loaded is corrupted.");
}

}

4 Likes

Hello,
I am trying to use above lines of code, but getting error when trying to create writer. Because data type is different. So, how can I use same as above.

What format you want to write the data?
There are many format we can write. wave is one of them.

Yes,
I am trying to .wav format.

Let me clear about what error i got. Please check below lines of code.

juce::OutputStream* stream = (juce::OutputStream*)(sTempFile.createOutputStream());

                std::unique_ptr<juce::FileOutputStream> stream2 = sTempFile.createOutputStream();

                juce::AudioFormatWriter* pTempWriter = audioFormat->createWriterFor( stream/*(juce::OutputStream *)(sTempFile.createOutputStream())*/,
                    (double)dOutSampleRate,
                    /*(const juce::AudioChannelSet)*/(reader->numChannels),
                    (int)(reader->bitsPerSample ? reader->bitsPerSample : 24),
                    (const juce::StringPairArray)(reader->metadataValues),
                    (int)(audioFormat->getQualityOptions().size() - 1));

So, as per above lines of code i am trying to solve error.
You can see that i am trying to use stream and stream2.
So, when create writer, its require data type as like stream, but it gives error in 1st line.
So, stream2 is okay. but it can not use when create writer otherwise gives error.

Can you please reform your sentences. Its difficult to understand.
Also you can provide the error string here.
What type of error you get Compiler error or runtime error?

Okay,
I am getting compilation error when try same code as you provide.
Error: “No instance of overloaded function juce::AudioFormatWriter::createWriterFor”…

Because you can see the data type is different of 2 function as below:

std::unique_ptr< [FileOutputStream](https://docs.juce.com/master/classFileOutputStream.html) > [createOutputStream](https://docs.juce.com/master/classFile.html#aaecec01a67fe87f62dc83118c0b0ce28)

virtual [AudioFormatWriter](https://docs.juce.com/master/classAudioFormatWriter.html) * [createWriterFor](https://docs.juce.com/master/classAudioFormat.html#ae93a8144520e5bd2902a5daa97cc443b) ([OutputStream](https://docs.juce.com/master/classOutputStream.html) *streamToWriteTo, double sampleRateToUse, unsigned [int](https://docs.juce.com/master/group__juce__audio__plugin__client-Unity.html#ga966b05a42d98c7296097e073c627dcd0) numberOfChannels, [int](https://docs.juce.com/master/group__juce__audio__plugin__client-Unity.html#ga966b05a42d98c7296097e073c627dcd0) bitsPerSample, const [StringPairArray](https://docs.juce.com/master/classStringPairArray.html) &metadataValues, [int](https://docs.juce.com/master/group__juce__audio__plugin__client-Unity.html#ga966b05a42d98c7296097e073c627dcd0) qualityOptionIndex)=0

I am still not clear about the code you are using. May be you should elaborate much precisely.

The problem might be coming in terms of the smart pointer here.

try to use following code

juce::OutputStream* stream_raw_pointer = sTempFile.createOutputStream().get();
juce::AudioFormatWriter* pTempWriter     = audioFormat->createWriterFor( stream_raw_pointer,
                    (double)dOutSampleRate,
                    reader->numChannels,
                    (int)(reader->bitsPerSample ? reader->bitsPerSample : 24),
                    (const juce::StringPairArray)(reader->metadataValues),
                    (int)(audioFormat->getQualityOptions().size() - 1));

That won’t work, since sTempFile.createOutputStream().get() returns the requested raw pointer.
BUT the next moment the unique_ptr returned from createOutputStream() goes out of scope when the call finishes, and the raw pointer becomes dangling.

Therefore you need to use release() instead of get().

And don’t forget to delete the raw pointer in case createWriterFor failed (e.g. permissions or whatever reason).

auto* stream = sTempFile.createOutputStream().release();
auto* writer = audioFormat->createWriterFor( stream, /* ... */ );
if (writer == nullptr)
{
    delete stream;
    return;
}

We dont even know what he is doing.
Its just a small piece of code where we dont even see the scope of the variables.

Fair point, but in that case if there are things that need clarification, it’s better to ask :wink:

But I didn’t mean to lecture you, just pointing out that this line returnes a dangling pointer in any circumstance

Okay,
I used as above, now plugin crashed at location “headerPosition = out->getPosition();” in function definition of “class WavAudioFormatWriter : public AudioFormatWriter”.

You are right. Some nasty RAII there. Holding the Unique_ptr in a local varibale will do the trick.

That is right, but it is a trick indeed, because now the created writer AND the temp unique_ptr are owning the OutputStream (i.e. potentially deleting it). So it is better to call release() to make clear the ownership of unique_ptr ends here and is handed over to the writer.
The extra check to delete if no writer was created is a quirk owed to the JUCE API, that is documented in the createWriterFor documentation, so a code reviewer would have a chance to verify.

Hello Guys,
Now, i am not getting any error or crash. But audio not playing with changing sample rate.
I am sharing old lines of code and modified lines of code. Old lines of code can be play audio file as normal sample rate and i modified that code by using your suggestions to change sample rate. Please check both codes.

new_code.txt (4.5 KB) old_code.txt (2.2 KB)