SmoothValue for Compressor Threshold

Hi there, how’s everyone?
I’m trying to build a simple compressor in order to learn since I’m super new to the JUCE framework and to programming in general, and everything works extremely well except that when I move the threshold parameter you can hear some clear cracking.
This is something that is easily fixable in the Gain module via “setRampDurationInSeconds”.
I assumed that this would be done using SmoothValue but it doesn’t seem to work (the console output shows it working but it doesn’t when I actually load the plugin).

I declared smoothValue in my PluginProcessor.h and called it smoothing, and here’s the preparetoplay and processblock code:

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

inputModule.prepare(spec);
compressor.prepare(spec);
outputModule.prepare(spec);

smoother.reset(sampleRate, 0.5);
smoother.setCurrentAndTargetValue(threshold->get());

}

ProcessBlock

{
juce::ScopedNoDenormals noDenormals;
auto totalNumInputChannels = getTotalNumInputChannels();
auto totalNumOutputChannels = getTotalNumOutputChannels();

for (auto i = totalNumInputChannels; i < totalNumOutputChannels; ++i)
    buffer.clear (i, 0, buffer.getNumSamples());

smoother.setTargetValue(threshold->get());

smoother.getNextValue();

inputModule.setGainDecibels(input->get());
inputModule.setRampDurationSeconds(0.05);
compressor.setThreshold(threshold->get());
compressor.setRatio(ratio->getCurrentChoiceName().getFloatValue());
compressor.setAttack(attack->get());
compressor.setRelease(release->get());
outputModule.setGainDecibels(output->get());
outputModule.setRampDurationSeconds(0.05);

auto block = juce::dsp::AudioBlock<float> (buffer);
auto context = juce::dsp::ProcessContextReplacing(block);
context.isBypassed = bypass->get();

inputModule.process(context);
compressor.process(context);
outputModule.process(context);

}

If anyone could point me in the right direction, that would be fantastic! Been pulling my hair out over this but I suspect it’s a very simple fix.

Thanks!

You aren’t using the smoother to do anything here, you are still setting the threshold via the parameter directly, rather than using a value from the smoother.

You are also getting the next value from the smoother once per block, rather than every sample, which will throw your desired time out by a lot, once you fix the first issue.

Hey Fandausss, thanks for the reply!
That makes a lot of sense.
I managed to link the smoother to the compressor and now it sort of works, but I can still hear the crackling even tho the “ramping” is clearly there.
I did it like this: compressor.setThreshold(smoother.getCurrentValue());

I assume that the crackling is still there because of getNextValue, but I cant figure out how to get the value every sample as you say.
Any ideas?

Thanks again!

Something like this would do it:

smoother.setTargetValue(threshold->get());

for (int s = 0; s < numSamples; ++s)
{
    compressor.setThreshold(smoother.getNextValue();

    for (int ch = 0; ch < numChannels; ++ch)
    {
        channelData[s] = compressor.processSample(ch, channelData[s]);
    }
}

All rough, but hopefully that gets the idea across. There is no way to pre-apply the ramp like there is with a buffer. A buffer already contains all the values upfront, so you can apply the ramp with a single function. The threshold parameter is a single value, and the smoother computes a single value at a time.

Thanks a lot for the help Fandusss!
Gonna give that a go later!

Thanks again!

It’s interesting to look through the juce code for the gain module to see how it’s doing it, too. That class holds its own smoother, and in process it allocates a buffer for the block upfront (with alloca). You could also somewhat copy that design if you were to roll your own compressor class.

Anyway, good luck!

Hey there, sorry to bother you again Fandausss. I’ve implemented your recommendation and it works flawlessly on my Laptop, but when trying the plugin on my Desktop PC, as soon as compression starts to kick in, there’s a constant crackle going on instead of only when moving the parameter.

Any clue what that might be about?

Thanks a lot!

Is it the old thing where your plugin has stereo I/O but your dsp object (here, the Compressor) is only set up for mono? (Or a bug in your for loop that’s iterating channels, causing both channels to be fed into the same channel of the compressor – effectively, the same issue as the first.)

1 Like

Not too sure without more context. You should make the repo public and link us if you want more specific help. Always hard to diagnose issues like this without seeing the code!

That’d be my guess too