Convolution for audio plug-in

Hi everyone,

I have been trying to implement Juce convolution from the DSP module in an audio plug-in. I know there are some example code, both at this forum as well as an Juce tutorial, but I can’t make it work in the Juce plug-in template. As a newbie, this may be easy to most of you and I really would appreciate it if anyone could help me.

Here is my code for Prepare to play:

void JConvAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    dsp::ProcessSpec spec;
    spec.sampleRate = sampleRate;
    spec.maximumBlockSize = samplesPerBlock;
    spec.numChannels = getTotalNumOutputChannels();
    
    conv.reset();
    conv.loadImpulseResponse("/Users/***/Source/impulse.wav", 245984, true, true, 0, true);
    conv.prepare(spec);
}

and here is my Processblock:

void JConvAudioProcessor::processBlock (AudioBuffer<float>& buffer, MidiBuffer& midiMessages)
{
    ScopedNoDenormals noDenormals;
    auto totalNumInputChannels  = getTotalNumInputChannels();
    auto totalNumOutputChannels = getTotalNumOutputChannels();
    
    for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
        buffer.clear (i, 0, buffer.getNumSamples());
    
    dsp::AudioBlock<float> block (buffer);
    dsp::ProcessContextReplacing<float> context (block);
    conv.process(context);
}

Variables are implemented in the header file. The only thing that happens is that the volume is decreased, but not if I comment away the conv.process(context); line. Then, as expected, the audio just passes through.

Thank you for your time!

Try calling the convolution processor’s prepare before loading the impulse response.

Thank you for reaching out but I have already tried that order. I have also tried to load the impulse in the constructor. But it is likely that I am doing something wrong in the loadImpulseResponse function.

loadImpulseResponse is a method which can have two different implementations:

  • void loadImpulseResponse (const void *sourceData, size_t sourceDataSize, bool wantsStereo, bool wantsTrimming, size_t size, bool wantsNormalisation=true)

  • void loadImpulseResponse (const File &fileImpulseResponse, bool wantsStereo, bool wantsTrimming, size_t size, bool wantsNormalisation=true)

See: https://docs.juce.com/master/classdsp_1_1Convolution.html#a0e712f0b1c11a26001e5f8b1f9af6371

You basically mixed both of them: you are calling the first one with a string, which is then converted to (or interpreted as) audio data (floats), representing your impulse response.

To make it work: drop 245984 and put a File() around your path :slight_smile:

Btw: it’s a funny mistake, I am wondering what my name sounds like :wink:

3 Likes

Perfect, thank you so much for the help! I have been trying for a while to interpret that part of the convolution class and to figure out which of the load methods I was supposed to use. This made my day :slight_smile:

it‘s like dancing your name -> convolve with your name :joy::ok_hand:

1 Like

Hello, thanks for the post and answers. @phultberg I’ve done everything like you, with appropriate loading of impuls response:

void Convolution_testAudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{

    dsp::ProcessSpec processSpec;
    processSpec.sampleRate = sampleRate;
    processSpec.maximumBlockSize = samplesPerBlock;
    processSpec.numChannels = getNumInputChannels();

    conv.reset();
    impulsResponse = "C:/Users/.../hall_impuls.wav";
    conv.loadImpulseResponse(impulsResponse, true , true, 0, true);
    conv.prepare(processSpec);
}

But sadly, the only thing that happens when I test the plugin, is that the signal is a lot more quiet. What am I doing wrong?

Not sure, but aren’t you kind of doing my mistake as well? Not putting File() around your path?

Don’t know if you solved this but I call Convolution’s prepare() method before its loadImpulseResponse() method. You can also load your .wav in as a binary and use that as the sourceData parameter for the implementation of the loadImpulseResponse() method that requires sourceData and sourceDataSize like so:

juceConvolution.prepare(spec);
juceConvolution.loadImpulseResponse(BinaryData::OutbackClimbingCenter_wav, BinaryData::OutbackClimbingCenter_wavSize, true, true, 0, true);

Yes I did solve it after the tip of putting FILE() around, but thank you for your reply and clarifying :slight_smile:

I have this in my code and it gives me an Error for convolution.loadImpulseResponse is there anything I am doing wrong
sorry if something obvious is missing, all this is very new to me.

VisualStudio 2019 is poniting the error just at “loadImpulseResponse” part

( E0304 no instance of overloaded function “juce::dsp::Convolution::loadImpulseResponse” matches the argument list test1_SharedCode C:\Users…\Documents\Juce\test1\Source\PluginProcessor.cpp 107 )

here is the code

void Test1AudioProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{

lastSampleRate = sampleRate;

dsp::ProcessSpec spec;
spec.sampleRate = sampleRate;
spec.maximumBlockSize = samplesPerBlock;
spec.numChannels = getTotalNumOutputChannels();

convolution.reset();
convolution.loadImpulseResponse(File ("/Users/.../guitar_amp.wav"), 
    true,
    true,
    0,
    true);
convolution.prepare(spec);

You’re passing booleans (true) instead of the expected types. Here is the function signature:

void dsp::Convolution::loadImpulseResponse	(	const File & 	 
fileImpulseResponse,
Stereo 	isStereo,
Trim 	requiresTrimming,
size_t 	size,
Normalise 	requiresNormalisation = Normalise::yes 
)	

You need to pass Stereo::yes, Trim::yes, and Normalize::yes, not true for those.

thank you Howard
when I try that the error stops pointing to (loadImpulseResponse) and starts pointing at whatever I replace the booleans (true) with.

Maybe you need to add juce:: in front of those names (as in juce::Stereo::yes)? They’re in the juce namespace.

Thanks a lot Howard I tried what you suggested and sorted out the problem writing it this way ( dsp::Convolution::Stereo::yes).

thank you again.

Interesting, they seemed to have replaced the booleans that used to be there in the loadImpulseResponse function. Glad you got it to work!