# Peak follower with independent Attack, Release and Level

**URL:** <https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455>\
**Category:** Audio Plugins\
**Created:** [March 22, 2023, 8:38am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455 "2023-03-22T08:38:31Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![damienr](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/damienr/32/15236_2.png) [@damienr](https://forum.juce.com/u/damienr)\
**Post date:** [March 22, 2023, 8:38am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455/1 "2023-03-22T08:38:31Z")

</div>

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](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&ved=2ahUKEwjx0uW6hu_9AhX7nf0HHTQjBa4QFnoECA8QAQ&url=https%3A%2F%2Fwww.eecs.qmul.ac.uk%2F~josh%2Fdocuments%2F2012%2FGiannoulisMassbergReiss-dynamicrangecompression-JAES2012.pdf&usg=AOvVaw2PBsEmNmS9p8aNG2dioFXe) 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!

---

<div class="post-metadata">

**Author:** ![PaulDriessen](https://avatars.discourse-cdn.com/v4/letter/p/a88e57/32.png) [@PaulDriessen](https://forum.juce.com/u/PaulDriessen)\
**Post date:** [March 22, 2023, 10:07am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455/2 "2023-03-22T10:07:49Z")

</div>

this is a simple compressor with independent attack and decay.

```auto

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);
  }

}

```

---

<div class="post-metadata">

**Author:** ![PaulDriessen](https://avatars.discourse-cdn.com/v4/letter/p/a88e57/32.png) [@PaulDriessen](https://forum.juce.com/u/PaulDriessen)\
**Post date:** [March 22, 2023, 10:35am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455/3 "2023-03-22T10:35:32Z")

</div>

if you want to smooth the compressionfactor, you use a global cmp\_factor with a surffactor

```auto
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;

```

---

<div class="post-metadata">

**Author:** ![damienr](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/damienr/32/15236_2.png) [@damienr](https://forum.juce.com/u/damienr)\
**Post date:** [March 22, 2023, 10:37am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455/4 "2023-03-22T10:37:04Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![PaulDriessen](https://avatars.discourse-cdn.com/v4/letter/p/a88e57/32.png) [@PaulDriessen](https://forum.juce.com/u/PaulDriessen)\
**Post date:** [March 22, 2023, 10:39am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455/5 "2023-03-22T10:39:34Z")

</div>

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;

---

<div class="post-metadata">

**Author:** ![damienr](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.juce.com/damienr/32/15236_2.png) [@damienr](https://forum.juce.com/u/damienr)\
**Post date:** [March 22, 2023, 10:48am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455/6 "2023-03-22T10:48:57Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![PaulDriessen](https://avatars.discourse-cdn.com/v4/letter/p/a88e57/32.png) [@PaulDriessen](https://forum.juce.com/u/PaulDriessen)\
**Post date:** [March 22, 2023, 11:09am UTC](https://forum.juce.com/t/peak-follower-with-independent-attack-release-and-level/55455/7 "2023-03-22T11:09:23Z")

</div>

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
