Hello there,
I’m currently working on a compressor and I have some troubles getting the peak follower working properly. I followed this paper Digital Dynamic Range Compressor Design from Giannoulis, Massberg and Reiss and implemented the Smoothed Branching Peak Detector (eq 16, same as juce::BallisticsFilter
) and the Smoothed Decoupled Peak Detector (eq 17).
The issue I’m facing is that I can’t get independent control over attack, release and keep a level constant when changing those when the release time get smaller or in the same range as the attack time.
With the Smoothed Decoupled Peak Detector, the attack envelope is always impressed upon the release envelope (as indicated in the paper), i.e. the actual measurable release time is the sum of the attack and release times.
With the Smoothed Branching Peak Detector, when the release time gets shorter or in the same range as the attack time, the output level gets strongly affected when changing either the attack or release. In the paper, they mention that the attack and release times are often added to set the actual release time. The authors say
it guarantees that the release time can never be shorter than the attack time.
However I’d like to have the possibility to set a release time shorter than the attack time and have proper trajectories and level. I tried several commercial compressor and they manage to do it properly, so it must be possible .
Does anyone have any clues on what I should try to achieve the intended behavior?
Thanks for your help!
this is a simple compressor with independent attack and decay.
float cmp_attackFactor=0.01:
float cmp_decayFactor=0.0001:
float cmp_env=0;
float cmp_treshold= .5;
float cmp_reduction=.5; // 0..1 => fractional reduction over the treshold level
float compress(float sample)
{
float tryEnv = fabs(sample);
if (tryEnv > cmp_env)
{ // attack
cmp_env += (tryEnv-cmp_env) * cmp_attackFactor;
}else{
//decay
cmp_env += (tryEnv-cmp_env) * cmp_decayFactor;
}
if( cmp_env >cmp_ treshold)
{
// the .00001 is just a trcik to avoiud division by zero
float factor = cmp_treshold / (real_env+.00001); // you can smooth the factor also if needed
factor = 1. + cmp_reduction * (factor-1.);
return(factor * sample);
)else{
return(sample);
}
}
1 Like
if you want to smooth the compressionfactor, you use a global cmp_factor with a surffactor
float cmp_factor=1;
float cmp_factorSmoothing=0.01;
// rest of code here..
if( cmp_env >cmp_ treshold)
{
// the .00001 is just a trcik to avoiud division by zero
float factor = cmp_treshold / (real_env+.00001); // you can smooth the factor also if needed
factor = 1. + cmp_reduction * (factor-1.);
cmp_factor += (factor - cmp_factor) * cmp_factorSmoothing
)else{
cmp_factor += (1. - cmp_factor) * cmp_factorSmoothing
}
return cmp_factor * sample;
Yes, your code corresponds to the Smoothed Branching Peak Detector I was mentioning. I have implemented it and the issue is that the output level moves a lot when changing the attack or release, as if I was moving the threshold as well.
if you move the treshold, the output volume will change. that is when you need “makeup”
The max makeup you need is 1./cmp_treshold
this will work fine for low to medium hard compression
cmp_makeup = 1./cmp_treshold; // treshold can not be 0!
return cmp_factor * cmp_makeup * sample;
My issue is that I have the output volume changing with the attack or release changing (when the release is shorter or in the same range as the attack). I don’t move the threshold when this happens.
Of course if I moved the threshold it would be normal to observe a volume change.
this would not happen in the code above. the att/decay logic does not influence the volume here.
Such things can happen when you reset the cmp_env or cmp_factorSmooth when dialing
Or when separate attack and decay envs are created in parallel: my example uses a signle “stitched” env