/*
*
      
_______
                       
_____
   
_____ _____
  

*
     
|__
   
__|
                     
|
  
__ \ / ____|__ \
 

*
        
| | __ _ _ __ ___
  
______| || | (___ | |__) |
*
        
| |/ _` | '__/ __|/ _ \/ __| |
  
| |\___ \|___/
 

*
        
| | (_| | |
  
\__ \ (_) \__ \ |__| |____) | |
     

*
        
|_|\__,_|_|
  
|___/\___/|___/_____/|_____/|_|
     

*
                                                         

* -------------------------------------------------------------
*
* TarsosDSP is developed by Joren Six at IPEM, University Ghent
*
  

* -------------------------------------------------------------
*
*
  
Info:
 
http://0110.be/tag/TarsosDSP
*
  
Github:
 
https://github.com/JorenSix/TarsosDSP
*
  
Releases:
 
http://0110.be/releases/TarsosDSP/
*
  

*
  
TarsosDSP includes modified source code by various authors,
*
  
for credits and info, see README.
*
 

*/


package be.tarsos.dsp;

/**
 
* An envelope follower follows the envelope of a signal. Sometimes the name
 
* envelope detector is used. From wikipedia:
 
*
  
<blockquote> An envelope detector
 
* is an electronic circuit that takes a high-frequency signal as input and
 
* provides an output which is the envelope of the original signal. The
 
* capacitor in the circuit stores up charge on the rising edge, and releases it
 
* slowly through the resistor when the signal falls. The diode in series
 
* rectifies the incoming signal, allowing current flow only when the positive
 
* input terminal is at a higher potential than the negative input terminal.
 
* </blockquote>
 
*
 
* The resulting envelope is stored in the buffer in the processed AudioEvent. The class can be used thusly:
 
*
 
* <pre>
 
* EnvelopeFollower follower = new EnvelopeFollower(44100);
 
*
 		

 
* AudioDispatcher dispatcher = AudioDispatcher.fromFloatArray(sine, 44100, 1024, 0);
 
*
 	

 
*
 	

 
*
 	
dispatcher.addAudioProcessor(follower);
 
*
 	
dispatcher.addAudioProcessor(new AudioProcessor() {
 
*
 	

 
*
 		
public boolean process(AudioEvent audioEvent) {
 
*
 			
//envelope
 
*
 			
float buffer[] = audioEvent.getFloatBuffer();
 
*
 			
for(int i = 0 ; i < buffer.length ; i++){
 
*
 				
System.out.println(buffer[i]);
 
*
 			
}
 
*
 			
return true;
 
*
 		
}
 
*
 			

 
*
 		
public void processingFinished() {
 
*
  	
}
 
*
 	
});
 
*
 	
dispatcher.run();
 
*
  
</pre>
 
*
  

 
*
 
* @author Joren Six
 
*
 
*/

public class EnvelopeFollower implements AudioProcessor {
	

	
/**
	 
* Defines how fast the envelope raises, defined in seconds.
	 
*/

	
private static final double DEFAULT_ATTACK_TIME =
  
0.0002;//in seconds
	
/**
	 
* Defines how fast the envelope goes down, defined in seconds.
	 
*/

	
private static final double DEFAULT_RELEASE_TIME =
  
0.0004;//in seconds
	

	
float gainAttack ;
	
float gainRelease;
	
float envelopeOut = 0.0f;
	

	
/**
	 
* Create a new envelope follower, with a certain sample rate.
	 
* @param sampleRate The sample rate of the audio signal.
	 
*/

	
public EnvelopeFollower(double sampleRate){
		
this(sampleRate,DEFAULT_ATTACK_TIME,DEFAULT_RELEASE_TIME);
	
}
	

	
/**
	 
* Create a new envelope follower, with a certain sample rate.
	 
* @param sampleRate The sample rate of the audio signal.
	 
* @param attackTime Defines how fast the envelope raises, defined in seconds.
	 
* @param releaseTime Defines how fast the envelope goes down, defined in seconds.
	 
*/

	
public EnvelopeFollower(double sampleRate, double attackTime,double releaseTime){
		
gainAttack = (float) Math.exp(-1.0/(sampleRate*attackTime));
		
gainRelease = (float) Math.exp(-1.0/(sampleRate*releaseTime));
	
}
	

	
@Override
	
public boolean process(AudioEvent audioEvent) {
		
float[] buffer = audioEvent.getFloatBuffer();
		
calculateEnvelope(buffer);
		
return true;
	
}
	

	
public void calculateEnvelope(float[] buffer){
		
for(int i = 0 ; i < buffer.length ; i++){
			
float envelopeIn = Math.abs(buffer[i]);
			
if(envelopeOut < envelopeIn){
				
envelopeOut = envelopeIn + gainAttack * (envelopeOut - envelopeIn);
			
} else {
				
envelopeOut = envelopeIn + gainRelease * (envelopeOut - envelopeIn);
			
}
			
buffer[i] = envelopeOut;
		
}
	
}

	
@Override
	
public void processingFinished() {
		

	
}
}