Compressor: add level-detector before the gain calc

pull/3/head
Chip Audette 8 years ago
parent d7dc90a7fc
commit c578607557
  1. 184
      AudioEffectCompressor_F32.h
  2. 81
      examples/BasicCompressor_Float/BasicCompressor_Float.ino

@ -1,7 +1,7 @@
/* /*
AudioEffectCompressor AudioEffectCompressor
Created: Chip Audette, December 2016 Created: Chip Audette, Dec 2016 - Jan 2017
Purpose; Apply dynamic range compression to the audio stream. Purpose; Apply dynamic range compression to the audio stream.
Assumes floating-point data. Assumes floating-point data.
@ -10,8 +10,8 @@
MIT License. use at your own risk. MIT License. use at your own risk.
*/ */
#ifndef _AudioEffectCompressor #ifndef _AudioEffectCompressor_F32
#define _AudioEffectCompressor #define _AudioEffectCompressor_F32
#include <arm_math.h> //ARM DSP extensions. https://www.keil.com/pack/doc/CMSIS/DSP/html/index.html #include <arm_math.h> //ARM DSP extensions. https://www.keil.com/pack/doc/CMSIS/DSP/html/index.html
#include <AudioStream_F32.h> #include <AudioStream_F32.h>
@ -21,20 +21,18 @@ class AudioEffectCompressor_F32 : public AudioStream_F32
public: public:
//constructor //constructor
AudioEffectCompressor_F32(void) : AudioStream_F32(1, inputQueueArray_f32) { AudioEffectCompressor_F32(void) : AudioStream_F32(1, inputQueueArray_f32) {
setThresh_dBFS(-20.0f); //default to this threshold setThresh_dBFS(-20.0f); //set the default value for the threshold for compression
setCompressionRatio(5.0f); //set the default copression ratio
setAttack_sec(0.005f, AUDIO_SAMPLE_RATE); //default to this value setAttack_sec(0.005f, AUDIO_SAMPLE_RATE); //default to this value
setRelease_sec(0.200f, AUDIO_SAMPLE_RATE); //default to this value setRelease_sec(0.200f, AUDIO_SAMPLE_RATE); //default to this value
setCompressionRatio(5.0f); //default to this value setHPFilterCoeff(); enableHPFilter(true); //enable the HP filter to remove any DC offset from the audio
setThresh_dBFS(-20.0f); //default to this value
setHPFilterCoeff();
resetStates(); resetStates();
}; };
//here's the method that does all the work //here's the method that does all the work
void update(void) { void update(void) {
//Serial.println("AudioEffectGain_F32: updating."); //for debugging. //Serial.println("AudioEffectGain_F32: updating."); //for debugging.
audio_block_f32_t *audio_block; audio_block_f32_t *audio_block = AudioStream_F32::receiveWritable_f32();
audio_block = AudioStream_F32::receiveWritable_f32();
if (!audio_block) return; if (!audio_block) return;
//apply a high-pass filter to get rid of the DC offset //apply a high-pass filter to get rid of the DC offset
@ -43,61 +41,134 @@ class AudioEffectCompressor_F32 : public AudioStream_F32
//apply the pre-gain...a negative gain value will disable //apply the pre-gain...a negative gain value will disable
if (pre_gain > 0.0f) arm_scale_f32(audio_block->data, pre_gain, audio_block->data, audio_block->length); //use ARM DSP for speed! if (pre_gain > 0.0f) arm_scale_f32(audio_block->data, pre_gain, audio_block->data, audio_block->length); //use ARM DSP for speed!
//compute the desired gain //calculate the level of the audio (ie, calculate a smoothed version of the signal power)
audio_block_f32_t *audio_level_dB_block = AudioStream_F32::allocate_f32();
calcAudioLevel_dB(audio_block, audio_level_dB_block); //returns through audio_level_dB_block
//compute the desired gain based on the observed audio level
audio_block_f32_t *gain_block = AudioStream_F32::allocate_f32(); audio_block_f32_t *gain_block = AudioStream_F32::allocate_f32();
calcGain(audio_block, gain_block); //returns through gain_block calcGain(audio_level_dB_block, gain_block); //returns through gain_block
//apply the gain...store it back into audio_block //apply the desired gain...store the processed audio back into audio_block
arm_mult_f32(audio_block->data, gain_block->data, audio_block->data, audio_block->length); arm_mult_f32(audio_block->data, gain_block->data, audio_block->data, audio_block->length);
///transmit the block and release memory ///transmit the block and release memory
AudioStream_F32::transmit(audio_block); AudioStream_F32::transmit(audio_block);
AudioStream_F32::release(audio_block); AudioStream_F32::release(audio_block);
AudioStream_F32::release(gain_block); AudioStream_F32::release(gain_block);
AudioStream_F32::release(audio_level_dB_block);
} }
void calcGain(audio_block_f32_t *wav_block, audio_block_f32_t *gain_block) { void calcAudioLevel_dB(audio_block_f32_t *wav_block, audio_block_f32_t *level_dB_block) {
//calculate the instantaneous signal power (square the signal)
//calculate the signal power...ie, square the signal: wav_pow = wav.^2
audio_block_f32_t *wav_pow_block = AudioStream_F32::allocate_f32(); audio_block_f32_t *wav_pow_block = AudioStream_F32::allocate_f32();
arm_mult_f32(wav_block->data, wav_block->data, wav_pow_block->data, wav_block->length); arm_mult_f32(wav_block->data, wav_block->data, wav_pow_block->data, wav_block->length);
//loop over each sample //apply a smoothing filter to wav_pow_block and convert to dB
float32_t gain_pow; float c1 = level_lp_const;
float c2 = 1.0f - c1;
for (int i = 0; i < wav_pow_block->length; i++) { for (int i = 0; i < wav_pow_block->length; i++) {
//compute target gain (well, we're actualy calculating gain^2) assuming we want to copress //compute target gain (well, we're actualy calculating gain^2) assuming we want to copress
gain_pow = thresh_pow_FS_wCR / powf(wav_pow_block->data[i], comp_ratio_const); wav_pow_block->data[i] = c1*prev_level_lp_pow + c2*wav_pow_block->data[i];
//if our signal level is below the threshold, don't compress (set target gain to 0dB, which is 1.0) //save state for next time (and for next data block)
if (wav_pow_block->data[i] < thresh_pow_FS) gain_pow = 1.0f; prev_level_lp_pow = wav_pow_block->data[i];
//are we in the attack mode or release mode? //convert to dB (but not yet multiplied by 10.0
float32_t c = attack_const; //at first, assume that we're in the attack phase level_dB_block->data[i] = log10f(wav_pow_block->data[i]);
if (gain_pow > prev_gain_pow) c = release_const; //here, we decide if we're really in the release phase }
//smooth the gain using the attack or release constants //limit the amount that the state of the smoothing filter can go toward negative infinity
gain_pow = c*prev_gain_pow + (1.0f-c)*gain_pow; if (prev_level_lp_pow < (1.0E-13)) prev_level_lp_pow = 1.0E-13; //never go less than -130 dBFS
//scale the wav_pow_block by 10.0 to complete the conversion to dB
arm_scale_f32(level_dB_block->data, 10.0f, level_dB_block->data, level_dB_block->length); //use ARM DSP for speed!
//release memory and return
AudioStream_F32::release(wav_pow_block);
return; //output is passed through level_dB_block
}
void calcGain(audio_block_f32_t *audio_level_dB_block, audio_block_f32_t *gain_block) {
//first, calculate the instantaneous target gain
audio_block_f32_t *inst_targ_gain_dB_block = AudioStream_F32::allocate_f32();
calcInstantaneousTargetGain(audio_level_dB_block, inst_targ_gain_dB_block);
//second, smooth in time (attack and release) by stepping through each sample
audio_block_f32_t *gain_dB_block = AudioStream_F32::allocate_f32();
calcSmoothedGain_dB(inst_targ_gain_dB_block,gain_dB_block);
//finally, convert from dB to linear gain: gain = 10^(gain_dB/20)
arm_scale_f32(gain_dB_block->data, 1.0f/20.0f, gain_dB_block->data, gain_dB_block->length); //divide by 20
for (int i = 0; i < gain_dB_block->length; i++) gain_block->data[i] = powf(10.0f,gain_dB_block->data[i]); //10^(x)
//release memory and return
AudioStream_F32::release(gain_dB_block);
AudioStream_F32::release(inst_targ_gain_dB_block);
return; //output is passed through gain_block
}
void calcInstantaneousTargetGain(audio_block_f32_t *audio_level_dB_block, audio_block_f32_t *inst_targ_gain_dB_block) {
// how much are we above the compression threshold?
audio_block_f32_t *above_thresh_dB_block = AudioStream_F32::allocate_f32();
arm_offset_f32(audio_level_dB_block->data, //CMSIS DSP for "add a constant value to all elements"
-thresh_dBFS, //this is the value to be added
above_thresh_dB_block->data, //this is the output
audio_level_dB_block->length);
// scale by the compression ratio...this is what the output level should be (this is our target level)
arm_scale_f32(above_thresh_dB_block->data, //CMSIS DSP for "multiply all elements by a constant value"
1.0f / comp_ratio, //this is the value to be multiplied
inst_targ_gain_dB_block->data, //this is the output
above_thresh_dB_block->length);
// compute the instantaneous gai...which is the difference between the target level and the original level
arm_sub_f32(inst_targ_gain_dB_block->data, //CMSIS DSP for "subtract two vectors element-by-element"
above_thresh_dB_block->data, //this is the vector to be subtracted
inst_targ_gain_dB_block->data, //this is the output
inst_targ_gain_dB_block->length);
//take he sqrt of gain^2 so that we simply get the gain // limit the target gain to attenuation only (this part of the compressor should not make things louder!)
//arm_sqrt_f32(gain_pow, &(gain_block->data[i])); //should use the DSP acceleration, if the right CMSIS library is used for (int i=0; i < inst_targ_gain_dB_block->length; i++) {
//gain_block->data[i] = __builtin_sqrtf(gain_pow); //seems to give the same speed as the arm_sqrt_f32 if (inst_targ_gain_dB_block->data[i] > 0.0f) inst_targ_gain_dB_block->data[i] = 0.0f;
gain_block->data[i] = sqrtf(gain_pow); //also give the same speed and is more portable }
// release memory before returning
AudioStream_F32::release(above_thresh_dB_block);
return; //output is passed through inst_targ_gain_dB_block
}
void calcSmoothedGain_dB(audio_block_f32_t *inst_targ_gain_dB_block, audio_block_f32_t *gain_dB_block) {
float32_t gain_dB;
float32_t one_minus_attack_const = 1.0f - attack_const;
float32_t one_minus_release_const = 1.0f - release_const;
for (int i = 0; i < inst_targ_gain_dB_block->length; i++) {
gain_dB = inst_targ_gain_dB_block->data[i];
//smooth the gain using the attack or release constants
if (gain_dB < prev_gain_dB) { //are we in the attack phase?
gain_dB_block->data[i] = attack_const*prev_gain_dB + one_minus_attack_const*gain_dB;
} else { //or, we're in the release phase
gain_dB_block->data[i] = release_const*prev_gain_dB + one_minus_release_const*gain_dB;
}
//save value for the next time through this loop //save value for the next time through this loop
prev_gain_pow = gain_pow; prev_gain_dB = gain_dB_block->data[i];
} }
//free up the memory and return //return
release(wav_pow_block);
return; //the output here is gain_block return; //the output here is gain_block
} }
//methods to set parameters of this module //methods to set parameters of this module
void resetStates(void) { void resetStates(void) {
prev_gain_pow = 1.0f; prev_level_lp_pow = 1.0f;
prev_gain_dB = 0.0f;
//initialize the HP filter (it also resets the filter states) //initialize the HP filter. (This also resets the filter states,)
arm_biquad_cascade_df1_init_f32(&hp_filt_struct, hp_nstages, hp_coeff, hp_state); arm_biquad_cascade_df1_init_f32(&hp_filt_struct, hp_nstages, hp_coeff, hp_state);
} }
void setPreGain(float g) { pre_gain = g; } void setPreGain(float g) { pre_gain = g; }
@ -109,30 +180,43 @@ class AudioEffectCompressor_F32 : public AudioStream_F32
void setAttack_sec(float a, float fs_Hz) { void setAttack_sec(float a, float fs_Hz) {
attack_sec = a; attack_sec = a;
attack_const = expf(-1.0f / (attack_sec * fs_Hz)); //expf() is much faster than exp() attack_const = expf(-1.0f / (attack_sec * fs_Hz)); //expf() is much faster than exp()
//also update the time constant for the envelope extraction
setLevelTimeConst_sec(min(attack_sec,release_sec) / 5.0, fs_Hz); //make the level time-constant one-fifth the gain time constants
} }
void setRelease_sec(float r, float fs_Hz) { void setRelease_sec(float r, float fs_Hz) {
release_sec = r; release_sec = r;
release_const = expf(-1.0f / (release_sec * fs_Hz)); //expf() is much faster than exp() release_const = expf(-1.0f / (release_sec * fs_Hz)); //expf() is much faster than exp()
//also update the time constant for the envelope extraction
setLevelTimeConst_sec(min(attack_sec,release_sec) / 5.0, fs_Hz); //make the level time-constant one-fifth the gain time constants
} }
void setThresh_dBFS(float thresh_dBFS) { setThreshPow(pow(10.0, thresh_dBFS / 10.0)); } void setLevelTimeConst_sec(float t_sec, float fs_Hz) {
void setThreshPow(float t_pow) { const float min_t_sec = 0.002f; //this is the minimum allowed value
thresh_pow_FS = t_pow; level_lp_sec = max(min_t_sec,t_sec);
updateThresholdAndCompRatioConstants(); level_lp_const = expf(-1.0f / (level_lp_sec * fs_Hz)); //expf() is much faster than exp()
}
void setThresh_dBFS(float val) {
thresh_dBFS = val;
setThreshPow(pow(10.0, thresh_dBFS / 10.0));
} }
void enableHPFilter(boolean flag) { use_HP_prefilter = flag; }; void enableHPFilter(boolean flag) { use_HP_prefilter = flag; };
//methods to return information about this module //methods to return information about this module
float32_t getPreGain_dB(void) { return 20.0 * log10(pre_gain); } float32_t getPreGain_dB(void) { return 20.0 * log10f(pre_gain); }
float32_t getAttack_sec(void) { return attack_sec; } float32_t getAttack_sec(void) { return attack_sec; }
float32_t getRelease_sec(void) { return release_sec; } float32_t getRelease_sec(void) { return release_sec; }
float32_t getThresh_dBFS(void) { return 10.0 * log10(thresh_pow_FS); } float32_t getLevelTimeConst_sec(void) { return level_lp_sec; }
float32_t getThresh_dBFS(void) { return thresh_dBFS; }
float32_t getCompressionRatio(void) { return comp_ratio; } float32_t getCompressionRatio(void) { return comp_ratio; }
float32_t getCurrentGain_dB(void) { return 10.0 * log10(prev_gain_pow); } float32_t getCurrentLevel_dBFS(void) { return 10.0* log10f(prev_level_lp_pow); }
float32_t getCurrentGain_dB(void) { return prev_gain_dB; }
private: private:
//state-related variables //state-related variables
audio_block_f32_t *inputQueueArray_f32[1]; //memory pointer for the input to this module audio_block_f32_t *inputQueueArray_f32[1]; //memory pointer for the input to this module
float32_t prev_gain_pow = 1.0; //last gain^2 used float32_t prev_level_lp_pow = 1.0;
float32_t prev_gain_dB = 0.0; //last gain^2 used
//HP filter state-related variables //HP filter state-related variables
arm_biquad_casd_df1_inst_f32 hp_filt_struct; arm_biquad_casd_df1_inst_f32 hp_filt_struct;
@ -149,7 +233,7 @@ class AudioEffectCompressor_F32 : public AudioStream_F32
} }
//private parameters related to gain calculation //private parameters related to gain calculation
float32_t attack_const, release_const; //used in calcGain(). set by setAttack_sec() and setRelease_sec(); float32_t attack_const, release_const, level_lp_const; //used in calcGain(). set by setAttack_sec() and setRelease_sec();
float32_t comp_ratio_const, thresh_pow_FS_wCR; //used in calcGain(); set in updateThresholdAndCompRatioConstants() float32_t comp_ratio_const, thresh_pow_FS_wCR; //used in calcGain(); set in updateThresholdAndCompRatioConstants()
void updateThresholdAndCompRatioConstants(void) { void updateThresholdAndCompRatioConstants(void) {
comp_ratio_const = 1.0f-(1.0f / comp_ratio); comp_ratio_const = 1.0f-(1.0f / comp_ratio);
@ -157,12 +241,18 @@ class AudioEffectCompressor_F32 : public AudioStream_F32
} }
//settings //settings
float32_t attack_sec, release_sec; float32_t attack_sec, release_sec, level_lp_sec;
float32_t thresh_pow_FS = 1.0f; //threshold for compression, relative to digital full scale float32_t thresh_dBFS = 0.0; //threshold for compression, relative to digital full scale
float32_t thresh_pow_FS = 1.0f; //same as above, but not in dB
void setThreshPow(float t_pow) {
thresh_pow_FS = t_pow;
updateThresholdAndCompRatioConstants();
}
float32_t comp_ratio = 1.0; //compression ratio float32_t comp_ratio = 1.0; //compression ratio
float32_t pre_gain = -1.0; //gain to apply before the compression. negative value disables float32_t pre_gain = -1.0; //gain to apply before the compression. negative value disables
boolean use_HP_prefilter = false; boolean use_HP_prefilter;
}; };
#endif #endif

@ -1,7 +1,7 @@
/* /*
BasicCompressor BasicCompressor_Float
Created: Chip Audette, Dec 2016 Created: Chip Audette, Dec 2016 - Jan 2017
Purpose: Process audio by applying a single-band compressor Purpose: Process audio by applying a single-band compressor
Demonstrates audio processing using floating point data type. Demonstrates audio processing using floating point data type.
@ -28,15 +28,29 @@ AudioConvert_I16toF32 int2Float1, int2Float2; //Converts Int16 to Float.
AudioConvert_F32toI16 float2Int1, float2Int2; //Converts Float to Int16. See class in AudioStream_F32.h AudioConvert_F32toI16 float2Int1, float2Int2; //Converts Float to Int16. See class in AudioStream_F32.h
AudioEffectCompressor_F32 comp1, comp2; AudioEffectCompressor_F32 comp1, comp2;
//Make all of the audio connections //Make all of the audio connections, with the option of USB audio in and out
AudioConnection patchCord1(i2s_in, 0, int2Float1, 0); //connect the Left input to the Left Int->Float converter //note that you ALWAYS have to have an I2S connection (either in or out) to have a clock
AudioConnection patchCord2(i2s_in, 1, int2Float2, 0); //connect the Right input to the Right Int->Float converter //that drives the system.
#define DO_USB 0 //set to 1 to enable USB audio. Be sure to go under the "Tools" menu and do "USB Type" -> "Audio"
#if DO_USB
AudioInputUSB usb_in;
AudioConnection patchCord1(usb_in, 0, int2Float1, 0);
AudioConnection patchCord2(usb_in, 1, int2Float2, 0);
#else
AudioConnection patchCord1(i2s_in, 0, int2Float1, 0); //connect the Left input to the Left Int->Float converter
AudioConnection patchCord2(i2s_in, 1, int2Float2, 0); //connect the Right input to the Right Int->Float converter
#endif
AudioConnection_F32 patchCord10(int2Float1, 0, comp1, 0); //Left. makes Float connections between objects AudioConnection_F32 patchCord10(int2Float1, 0, comp1, 0); //Left. makes Float connections between objects
AudioConnection_F32 patchCord11(int2Float2, 0, comp2, 0); //Right. makes Float connections between objects AudioConnection_F32 patchCord11(int2Float2, 0, comp2, 0); //Right. makes Float connections between objects
AudioConnection_F32 patchCord12(comp1, 0, float2Int1, 0); //Left. makes Float connections between objects AudioConnection_F32 patchCord12(comp1, 0, float2Int1, 0); //Left. makes Float connections between objects
AudioConnection_F32 patchCord13(comp2, 0, float2Int2, 0); //Right. makes Float connections between objects AudioConnection_F32 patchCord13(comp2, 0, float2Int2, 0); //Right. makes Float connections between objects
AudioConnection patchCord20(float2Int1, 0, i2s_out, 0); //connect the Left float processor to the Left output AudioConnection patchCord20(float2Int1, 0, i2s_out, 0); //connect the Left float processor to the Left output
AudioConnection patchCord21(float2Int2, 0, i2s_out, 1); //connect the Right float processor to the Right output AudioConnection patchCord21(float2Int2, 0, i2s_out, 1); //connect the Right float processor to the Right output
#if DO_USB
AudioOutputUSB usb_out;
AudioConnection patchCord30(float2Int1, 0, usb_out, 0); //connect the Left float processor to the Left output
AudioConnection patchCord31(float2Int2, 0, usb_out, 1); //connect the Right float processor to the Right output
#endif
// which input on the audio shield will be used? // which input on the audio shield will be used?
const int myInput = AUDIO_INPUT_LINEIN; const int myInput = AUDIO_INPUT_LINEIN;
@ -50,7 +64,7 @@ void setupMyAudioBoard(void) {
sgtl5000.enable(); //start the audio board sgtl5000.enable(); //start the audio board
sgtl5000.inputSelect(myInput); //choose line-in or mic-in sgtl5000.inputSelect(myInput); //choose line-in or mic-in
sgtl5000.volume(0.8); //volume can be 0.0 to 1.0. 0.5 seems to be the usual default. sgtl5000.volume(0.8); //volume can be 0.0 to 1.0. 0.5 seems to be the usual default.
sgtl5000.lineInLevel(10,10); //level can be 0 to 15. 5 is the Teensy Audio Library's default sgtl5000.lineInLevel(10, 10); //level can be 0 to 15. 5 is the Teensy Audio Library's default
sgtl5000.adcHighPassFilterDisable(); //reduces noise. https://forum.pjrc.com/threads/27215-24-bit-audio-boards?p=78831&viewfull=1#post78831 sgtl5000.adcHighPassFilterDisable(); //reduces noise. https://forum.pjrc.com/threads/27215-24-bit-audio-boards?p=78831&viewfull=1#post78831
sgtl5000.micBiasEnable(3.0); //enable the mic bias voltage...only in AudioControlSGTL5000_Extended sgtl5000.micBiasEnable(3.0); //enable the mic bias voltage...only in AudioControlSGTL5000_Extended
} }
@ -72,10 +86,9 @@ void setup() {
delay(500); //give the computer's USB serial system a moment to catch up. delay(500); //give the computer's USB serial system a moment to catch up.
Serial.println("Teensy Hearing Aid: BasicCompressor_Float..."); //identify myself over the USB serial Serial.println("Teensy Hearing Aid: BasicCompressor_Float..."); //identify myself over the USB serial
// Audio connections require memory, and the record queue // Audio connections require memory, and the record queue uses this memory to buffer incoming audio.
// uses this memory to buffer incoming audio. AudioMemory(14); //allocate Int16 audio data blocks
AudioMemory(12); //allocate Int16 audio data blocks AudioMemory_F32(16); //allocate Float32 audio data blocks
AudioMemory_F32(10); //allocate Float32 audio data blocks
// Enable the audio shield, select input, and enable output // Enable the audio shield, select input, and enable output
setupMyAudioBoard(); setupMyAudioBoard();
@ -84,11 +97,11 @@ void setup() {
boolean use_HP_filter = true; //enable the software HP filter to get rid of DC? boolean use_HP_filter = true; //enable the software HP filter to get rid of DC?
float knee_dBFS, comp_ratio, attack_sec, release_sec; float knee_dBFS, comp_ratio, attack_sec, release_sec;
if (false) { if (false) {
Serial.println("Configuring Compressor for fast response for use as a limitter."); Serial.println("Configuring Compressor for fast response for use as a limitter.");
knee_dBFS = -15.0; comp_ratio = 8.0; attack_sec = 0.005; release_sec = 0.200; knee_dBFS = -15.0f; comp_ratio = 5.0f; attack_sec = 0.005f; release_sec = 0.200f;
} else { } else {
Serial.println("Configuring Compressor for slow response more like an automatic volume control."); Serial.println("Configuring Compressor for slow response more like an automatic volume control.");
knee_dBFS = -50.0; comp_ratio = 5.0; attack_sec = 1.0; release_sec = 2.0; knee_dBFS = -50.0; comp_ratio = 5.0; attack_sec = 1.0; release_sec = 2.0;
} }
//configure the left and right compressors with the desired settings //configure the left and right compressors with the desired settings
@ -105,7 +118,7 @@ unsigned long updatePeriod_millis = 100; //how many milliseconds between updatin
unsigned long lastUpdate_millis = 0; unsigned long lastUpdate_millis = 0;
unsigned long curTime_millis = 0; unsigned long curTime_millis = 0;
int prev_gain_dB = 0; int prev_gain_dB = 0;
unsigned long lastMemUpdate_millis=0; unsigned long lastMemUpdate_millis = 0;
void loop() { void loop() {
//choose to sleep ("wait for interrupt") instead of spinning our wheels doing nothing but consuming power //choose to sleep ("wait for interrupt") instead of spinning our wheels doing nothing but consuming power
asm(" WFI"); //ARM-specific. Will wake on next interrupt. The audio library issues tons of interrupts, so we wake up often. asm(" WFI"); //ARM-specific. Will wake on next interrupt. The audio library issues tons of interrupts, so we wake up often.
@ -117,18 +130,20 @@ void loop() {
//read potentiometer //read potentiometer
float32_t val = float(analogRead(POT_PIN)) / 1024.0f; //0.0 to 1.0 float32_t val = float(analogRead(POT_PIN)) / 1024.0f; //0.0 to 1.0
val = 0.1*(float)((int)(10.0*val + 0.5)); //quantize so that it doesn't chatter val = 0.1 * (float)((int)(10.0 * val + 0.5)); //quantize so that it doesn't chatter
//compute desired digital gain //compute desired digital gain
const float min_gain_dB = -20.0, max_gain_dB = 40.0; //set desired gain range const float min_gain_dB = -20.0, max_gain_dB = 40.0; //set desired gain range
float gain_dB = min_gain_dB + (max_gain_dB - min_gain_dB)*val; //computed desired gain value in dB float gain_dB = min_gain_dB + (max_gain_dB - min_gain_dB) * val; //computed desired gain value in dB
//if the gain is different than before, set the new gain value //if the gain is different than before, set the new gain value
if (abs(gain_dB - prev_gain_dB) > 1.0) { //is it different than before if (abs(gain_dB - prev_gain_dB) > 1.0) { //is it different than before
prev_gain_dB = gain_dB; //we will use this value the next time around
//gain_dB = 0.0; //force to 0 dB for debugging
comp1.setPreGain_dB(gain_dB); //set the gain of the Left-channel gain processor comp1.setPreGain_dB(gain_dB); //set the gain of the Left-channel gain processor
comp2.setPreGain_dB(gain_dB); //set the gain of the Right-channel gain processor comp2.setPreGain_dB(gain_dB); //set the gain of the Right-channel gain processor
Serial.print("Setting Digital Pre-Gain dB = "); Serial.println(gain_dB); //print text to Serial port for debugging Serial.print("Setting Digital Pre-Gain dB = "); Serial.println(gain_dB); //print text to Serial port for debugging
prev_gain_dB = gain_dB; //we will use this value the next time around
} }
lastUpdate_millis = curTime_millis; //we will use this value the next time around. lastUpdate_millis = curTime_millis; //we will use this value the next time around.
@ -145,21 +160,25 @@ void loop() {
} //end loop(); } //end loop();
void printCompressorState(Stream *s) { void printCompressorState(Stream *s) {
s->print("Current Compressor: Pre-Gain (dB) = "); s->print("Current Compressor: Pre-Gain (dB) = ");
s->print(comp1.getPreGain_dB()); s->print(comp1.getPreGain_dB());
s->print(", Dynamic Gain L/R (dB) = "); s->print(", Level (dBFS) = ");
s->print(comp1.getCurrentGain_dB()); s->print(comp1.getCurrentLevel_dBFS());
s->print(", "); s->print(", ");
s->print(comp2.getCurrentGain_dB()); s->print(comp2.getCurrentLevel_dBFS());
s->println(); s->print(", Dynamic Gain L/R (dB) = ");
s->print(comp1.getCurrentGain_dB());
s->print(", ");
s->print(comp2.getCurrentGain_dB());
s->println();
}; };
void printCPUandMemoryUsage(Stream *s) { void printCPUandMemoryUsage(Stream *s) {
s->print("Usage/Max: "); s->print("Usage/Max: ");
s->print("comp1 CPU = "); s->print(comp1.processorUsage()); s->print("/"); s->print(comp1.processorUsageMax());s->print(", "); s->print("comp1 CPU = "); s->print(comp1.processorUsage()); s->print("/"); s->print(comp1.processorUsageMax()); s->print(", ");
s->print("all CPU = " ); s->print(AudioProcessorUsage()); s->print("/"); s->print(AudioProcessorUsageMax());s->print(", "); s->print("all CPU = " ); s->print(AudioProcessorUsage()); s->print("/"); s->print(AudioProcessorUsageMax()); s->print(", ");
s->print("Int16 Mem = ");s->print(AudioMemoryUsage()); s->print("/"); s->print(AudioMemoryUsageMax());s->print(", "); s->print("Int16 Mem = "); s->print(AudioMemoryUsage()); s->print("/"); s->print(AudioMemoryUsageMax()); s->print(", ");
s->print("Float Mem = ");s->print(AudioMemoryUsage_F32());s->print("/"); s->print(AudioMemoryUsageMax_F32()); s->print(", "); s->print("Float Mem = "); s->print(AudioMemoryUsage_F32()); s->print("/"); s->print(AudioMemoryUsageMax_F32()); s->print(", ");
s->println(); s->println();
}; };

Loading…
Cancel
Save