Amplitude Detection

Envelope Follower

An envelope follower is used to detect signal level. This signal level can then be used in dynamics processing: gating, compression, expansion, automatic gain control, etc. Typically a combination of rectification and filtering is used to create an envelope from an audio signal.

Mean Detection

One can use the mean of a signal to follow the envelope. Essentially, a buffer is allocated and filled with samples from the signal after rectification. Then the average of the buffer is taken to be the envelope. Naturally, the larger the buffer the smoother the output but more delayed (in time) the result.

int envPosition;
int envArraySize = 64;
float envArrayTotal;
float envArray[envArraySize];

float EFGetMean(float sample) 
{   
  // wrap the index pointer   
  if(envPosition >= envArraySize)     
    envPosition = 0;  
  if(envPosition < 0)
    envPosition = 0;   
  // FIRST: rectify the input  
  if(sample < 0.0)  
    sample = -1.0 * sample;   
  // SECOND: add to array to calculate mean   
  envArrayTotal = envArrayTotal - envArray[envPosition] + sample;      
  envArray[envPosition] = sample;   
  envPosition++;   
  // THIRD: mean is total/arraysize    
  return(envArrayTotal/(float)envArraySize); 
}

All:

Zoomed:

RMS Detection

One can also calculate the RMS amplitude in an envelope follower. Similar to using the mean, the RMS method also uses a buffer, the size of which determines the smoothness and responsiveness of the envelope follower.

int envPosition;
int envArraySize = 64;
float envArrayTotal;
float envArray[envArraySize];

float EFGetRMS(float sample) 
{ 
  float square, mean;  
  // wrap the index pointer   
  if(envPosition >= envArraySize)     
    envPosition = 0;  
  if(envPosition < 0)
    envPosition = 0;   
  // FIRST: square the new sample   
  // square range 0.0 to 1.0   
  square = sample * sample;      
  // SECOND: add to array to calculate mean   
  envArrayTotal = envArrayTotal - envArray[envPosition] + square;      
  envArray[envPosition] = square;   
  envPosition++;   
  // THIRD: mean is total/arraysize    
  mean = envArrayTotal/(float)envArraySize; 
  // FOURTH: RMS is square root of mean    
  return(sqrt(mean)); 
} 

All:

Zoomed:

Attack-Release Envelope Follower

The attack-release method does not use a buffer but instead takes a moving weighted average of the peak amplitude and the sample. Here, though, one must pass the samplerate which, in part, governs the responsiveness of the follower.

float EFGetPeakAttackRelase(float attackF, float releaseF, float sample) 
{  
  float attackMultiplier;  
  float releaseMultiplier;   
  // rectify  if(sample < 0.0)  
    sample = -sample;   
  // filter   
  attackMultiplier = exp((-6.283185 * attackF)/samplerate);     
  releaseMultiplier = exp((-6.283185 * releaseF)/samplerate);    
  if(sample > peak)  
    peak = attackMultiplier * (peak - sample) + sample;  
  else  
    peak = releaseMultiplier * (peak - sample) + sample;    
  return(peak); 
}

All:

Zoomed:

Envelope Followers Compared Aurally

Plotted below are three envelope followers: mean with a window of 16, RMS with a window of 16, and attack-release with time at 1ms (attack) and 200ms (release). To test the envelope followers, we can pass noise through our resulting envelope. Here are the three enveloped plotted below.

Funky Drummer Original
Funky Drummer extracted Attack-Release Envelope modulating noise

Leave a Reply

Your email address will not be published.