Using the Reverb class


#1

I’ve tried adding the reverb class to my audio plugin but aren’t able to get results.

Starting from scratch on a new audio plugin these are my steps,
In PluginProcessor.h’s private section:

Reverb theReverb;
Reverb::Parameters theReverbParameters;

In PluginProcessor.cpp’s constructor:

theReverbParameters.dryLevel = 0.2;
theReverbParameters.wetLevel = 1.0;
theReverbParameters.roomSize = 1.0;
theReverbParameters.damping = 0.1;
theReverb.setParameters(theReverbParameters);

In prepareToPlay:
> theReverb.setSampleRate(sampleRate);
(though this never actually gets reached?)

And processBlock:

> void ReverbTestAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
>     {
>         ScopedNoDenormals noDenormals;
>         const int totalNumInputChannels  = getTotalNumInputChannels();
>         const int totalNumOutputChannels = getTotalNumOutputChannels();
> 
>     for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
>         buffer.clear (i, 0, buffer.getNumSamples());
> 
>     // This is the place where you'd normally do the guts of your plugin's
>     // audio processing...
>     for (int channel = 0; channel < totalNumInputChannels; ++channel)
>     {
>         float* channelData = buffer.getWritePointer (channel);
> 
>         // ..do something to the data...
> 
>         theReverb.processStereo(buffer.getWritePointer(0), buffer.getWritePointer(1), buffer.getNumSamples());
>     }
> }

prepareToPlay never gets called (seen through DBG), I’m guessing this is the problem as the reverb never gets given a sample rate, although its initialised to 44100 anyway. I tried make a double variable to store a sample rate (in .h private, initialised to 44100 in .cpp’s constructor and set with theReverb.setSampleRate(theSampleRate);

Are there any steps I’m missing or am I putting anything in the wrong place?

Thanks for any guidance!


#2

You’re creating a single reverb object, and then passing ALL your channels through it, a chunk at a time. You need a reverb per channel (or sum all your channels and pass them through it once)

Creating a single-channel IIR/reverb/delay/etc and passing multiple channels through it is probably single most common mistake we get on this forum, I’ve seen almost identical posts hundreds of times!


#3

I see three problems there :

  • The function prepareToPlay should be called, I don’t know how you debugged your plug-in but that’s the basics, so either it worked but you didn’t see it, or it didn’t work and there is something wrong in your code or in your debug workflow
  • In that same function, don’t forget to call the reset function from the Reverb class
  • In the processBlock function, the way you handle the channels is wrong. But in contrary to what Jules said, you don’t need to create one Reverb object for each channel, since it has a process function called processStereo. However, you shouldn’t call it once for each channel, what your code does here is doing several times in a row the same thing on the input samples, and that’s wrong ! You should probably do something like that :
void ReverbTestAudioProcessor::processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages)
{
    ScopedNoDenormals noDenormals;

    const int totalNumInputChannels  = getTotalNumInputChannels();
    const int totalNumOutputChannels = getTotalNumOutputChannels();
 
    for (int i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
          buffer.clear (i, 0, buffer.getNumSamples());
 
    // This is the place where you'd normally do the guts of your plugin's 
    // audio processing...
    const auto numChannels = jmin (totalNumInputChannels, totalNumOutputChannels);
    
    if (numChannels == 1)
        theReverb.processMono (buffer.getWritePointer (0), buffer.getNumSamples());

    else if (numChannels == 2)
        theReverb.processStereo (buffer.getWritePointer (0), buffer.getWritePointer (1), buffer.getNumSamples());
}

However, for other processing classes in JUCE, in general they don’t have a function called processStereo, so to use them you need to create one object per channel, or the class dsp::ProcessorDuplicator when possible, and of course you need to handle the processing for each channel properly in your processBlock function code :wink: