CTAGDRC
An audio compressor plugin created with JUCE
Install / Use
/learn @p-hlp/CTAGDRCREADME
CTAG Dynamic Range Compressor
<!-- omit in toc -->An audio compressor plugin created with JUCE
<img src="Documentation/CTAGDRC_Snap.png" width="70%"> <!-- omit in toc -->Contents
Introduction
This is a simple vst3/au compressor plugin that was build with the goal in mind to create a good sounding compressor for a wide variety of signals and applications. The GUI is kept minimalistic to improve usability and not clutter the screen. The project was mostly used to further my understanding and knowledge of digital signal processing and digital audio effects. A demonstration is available on YouTube.
Features
- Input Gain
- Threshold/Ratio/Knee
- Attack/Release
- Auto Attack/Release
- Makeup
- Auto Makeup
- Mix
- LookAHead
- Metering (Input/Output/Gain Reduction)
Manual
General
- Input: The Input knob adjusts the level of the signal before any processing happens. Driving the input signal harder into the compressor can be used as an alternative to lowering the threshold.
- Makeup: The Makeup knob adjusts the level of the output signal after the compression was applied. Generally speaking, compression lowers the output level of a signal by design. This lets you compensate for any loss or gain in volume.
- Mix: The Mix knob enables you to mix between the dry and processed signal. This can be used for parallel processing and enables use-cases like NY-Style drum compression.
- LookAhead: The LookAhead button enables the LookAhead-Mode. If the compressor is used as a limiter (Ratio infinity:1 & instant attack time) it will anticipate the incoming peaks and fade in the aggressive gain reductions, thus preventing distortion from happening.
Gain Computer
- Threshold: The Threshold knob adjusts the level above which the compressor starts attenuating the input signal. The Input knob alternatively can be used to drive the signal harder into the compressor, resulting in a less low threshold being needed. Be careful to not drive the signal too hard or it'll start clipping.
- Ratio: The Ratio knob determines how much the signal is attenuated above the chosen threshold. For a ratio of 4:1, one dB remains for every 4dB of input signal above the threshold. At a ratio of 1:1 no compression is happening, as the input is exactly the output. At a ratio of inifinity:1 (knob all the way to the right) the compressor is acting as a limiter, meaning that everything above the treshold is completely compressed away.
- Knee: The Knee knob is used to achieve a rounder compression curve. Having a hard knee (knob all the way to the left) means that the compressor will only start working if the input signal is above the threshold and will stop working immediately when it is below. Using a soft knee on the other hand will define a range (knee/2) above and under the threshold, where the compressor will slowly start or stop compressing, resulting in a more gradual and transparent compression.
Ballistics
- Attack: The Attack knob sets the time that determines how fast the compression will set in once the signal exceeds the threshold. Generally speaking you want a rather fast attack time for transient-rich signals like drums to minimize overshoot.
- Release: The Release knob sets the time that determines how fast the compressor will recover from the gain reduction once the signal falls under the threshold. Depending on the input signal, short release times may introduce a "pumping" effect and/or distortion.
Parameter Automation
- Auto Makeup: The AutoMakeup button enables automatic makeup gain. Based on the average attentuations applied to the input signal. This features tries to keep the input signal and the processed output signal as close as possible in perceived loudness. This is a time-varying effect and may introduce unwanted volume changes to the output signal.
- Auto Attack & Auto Release: The AutoAttack and AutoRelease buttons enable/disable the automation of the time constants. Based on the ratio of peak and rms level of the input signal the compressor can make assumptions about the "transient-richness" of the signal and automate the ballistics accordingly.
Metering
- Gainreduction: This is a simple gainreduction meter. Right-most indicator is 0dB gainreduction and therefore no compression. The left-most indicator is -30dB, middle indicator -15dB.
- Input/Output: The Input/Output meter is a "VU-Style" peak meter. Right-most indicator 0dBFS. Left-most indicator -50dBFS.
Technical
Design Approach
In general there are two topologies for compressor design:
- Feedback - Topology
- Feedforward - Topology
Most modern compressors use a feedforward topology due to limitations of the feedback topology such as the inability to allow a lookahead functionality aswell as to work as a limiter due to inifnite negative amplification needed.
Therefore the topology of choice is the feedforward topology

The control circuit is fed with a copy of the input signal and calculates the needed attenuations which are then multiplied with the input signal. One might recognize this diagram since it pretty much resembles an analog VCA-Compressor. In a VCA-Compressor the voltage controlled amplifier attenuates a signal according to an external control voltage coming from the control circuit.
Overview
Knowing that we are building "the ideal VCA-Compressor" the interesting question is how the control voltage is actually calculated in a digital implementation.
A basic compressor diagram:

Lets take a look at the components.
Level Detection
Two approaches - peak detection which is based on the absolute value of the signal and rms detection which is based on the square of the signal. Both are easily implemented in the digital domain, but rms detection introduces a significant delay, therefore peak detection was the choice for this implementation.
In C++ this is as simple as doing:
float input = std::abs(sample)
Log and Lin Conversion
One of the reason many compressors sound different. Calculation of attenuations and smoothing can be done either in linear or log. domain.
Converting from linear to log (decibel):
float log = 20 * std::log10 (gain)
and converting from log. to linear:
float lin = std::pow (10.0, decibels * 0.05)
In this implementation the gain computer as well as the ballistics are operating in the log. domain.
Gain Computer
The gain computer calculates how much the input signal needs to be attenuated given the current chosen characteristics. It also generates the control voltage which is used to attenuate the signal in the gain stage.
A typical compression curve looks like:

The Treshold, Ratio and Knee parameters define the input/output characteristics of the compressor.
If we ignore the knee parameter for now, the compressor starts to attenuate the signal according to the ratio once it exceeds the threshold.

Resulting in:

With xG being the input, yG the output, T the threshold and R the ratio.
In order to soften the compression we can smooth the transition between no compression and compression. This is called soft knee. The knee knob adjusts the dB-range which is equally distributed on both sides of the threshold.
To implement this we can replace the equation above with a second order interpolation function [[1]]:

With W being the knee-width and (xG - T) being the overshoot. When W is set to 0dB this function is identical to the hard knee.
A simplified implementation:
float applyCompression(const float& input)
{
const float kneeHalf = knee/2.0;
const float overshoot = input - threshold;
if (overshoot <= -kneeHalf)
return 0.0f;
if (overshoot > -kneeHalf && overshoot <= kneeHalf)
return 0.5f * slope * square(overshoot + kneeHalf) / knee;
return slope * overshoot;
}
This function returns the calculated attenuations which are then being fed into the smoothing filter aka. peak detector.
Ballistics
The time constants are another component that differs alot from compressor to compressor. The attack is usually defined as the time it takes for the compressor to attenuate the signal once the signal exceeds the threshold. Likewise release is defined as the time it takes for the compressor to recover once the signal falls under the threshold.
In a digital implementation the attack and release times are usually introduced through a digital one-pole filter, also known as smoothing filter.

Where r[n] is the input, s[n] the output and alpha the filter coefficient. With the step response:
