/*
BasicCompressor_Float
Created : Chip Audette , Dec 2016 - Jan 2017
Purpose : Process audio by applying a single - band compressor
Demonstrates audio processing using floating point data type .
Uses Teensy Audio Adapter .
Assumes microphones ( or whatever ) are attached to the LINE IN ( stereo )
MIT License . use at your own risk .
*/
//These are the includes from the Teensy Audio Library
# include <Audio.h> //Teensy Audio Librarya
# include <Wire.h>
# include <SPI.h>
# include <SD.h>
# include <SerialFlash.h>
# include <OpenAudio_ArduinoLibrary.h> //for AudioConvert_I16toF32, AudioConvert_F32toI16, and AudioEffectGain_F32
//create audio library objects for handling the audio
AudioControlSGTL5000_Extended sgtl5000 ; //controller for the Teensy Audio Board
AudioInputI2S i2s_in ; //Digital audio *from* the Teensy Audio Board ADC. Sends Int16. Stereo.
AudioConvert_I16toF32 int2Float1 , int2Float2 ; //Converts Int16 to Float. See class in AudioStream_F32.h
AudioEffectCompressor_F32 comp1 , comp2 ;
AudioConvert_F32toI16 float2Int1 , float2Int2 ; //Converts Float to Int16. See class in AudioStream_F32.h
AudioOutputI2S i2s_out ; //Digital audio *to* the Teensy Audio Board DAC. Expects Int16. Stereo
//Make all of the audio connections, with the option of USB audio in and out
//note that you ALWAYS have to have an I2S connection (either in or out) to have a clock
//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 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 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 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?
const int myInput = AUDIO_INPUT_LINEIN ;
//const int myInput = AUDIO_INPUT_MIC;
//I have a potentiometer on the Teensy Audio Board
# define POT_PIN A1 //potentiometer is tied to this pin
//define a function to setup the Teensy Audio Board how I like it
void setupMyAudioBoard ( void ) {
sgtl5000 . enable ( ) ; //start the audio board
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 . 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 . micBiasEnable ( 3.0 ) ; //enable the mic bias voltage...only in AudioControlSGTL5000_Extended
}
//define a function to configure the left and right compressors
void setupMyCompressors ( boolean use_HP_filter , float knee_dBFS , float comp_ratio , float attack_sec , float release_sec ) {
comp1 . enableHPFilter ( use_HP_filter ) ; comp2 . enableHPFilter ( use_HP_filter ) ;
comp1 . setThresh_dBFS ( knee_dBFS ) ; comp2 . setThresh_dBFS ( knee_dBFS ) ;
comp1 . setCompressionRatio ( comp_ratio ) ; comp2 . setCompressionRatio ( comp_ratio ) ;
float fs_Hz = AUDIO_SAMPLE_RATE ;
comp1 . setAttack_sec ( attack_sec , fs_Hz ) ; comp2 . setAttack_sec ( attack_sec , fs_Hz ) ;
comp1 . setRelease_sec ( release_sec , fs_Hz ) ; comp2 . setRelease_sec ( release_sec , fs_Hz ) ;
}
// define the overall setup() function, the function that is called once when the device is booting
void setup ( ) {
Serial . begin ( 115200 ) ; //open the USB serial link to enable debugging messages
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
// Audio connections require memory, and the record queue uses this memory to buffer incoming audio.
AudioMemory ( 14 ) ; //allocate Int16 audio data blocks
AudioMemory_F32 ( 16 ) ; //allocate Float32 audio data blocks
// Enable the audio shield, select input, and enable output
setupMyAudioBoard ( ) ;
//choose the compressor parameters...note that preGain is set by the potentiometer in the main loop()
boolean use_HP_filter = true ; //enable the software HP filter to get rid of DC?
float knee_dBFS , comp_ratio , attack_sec , release_sec ;
if ( false ) {
Serial . println ( " Configuring Compressor for fast response for use as a limitter. " ) ;
knee_dBFS = - 15.0f ; comp_ratio = 5.0f ; attack_sec = 0.005f ; release_sec = 0.200f ;
} else {
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 ;
}
//configure the left and right compressors with the desired settings
setupMyCompressors ( use_HP_filter , knee_dBFS , comp_ratio , attack_sec , release_sec ) ;
// setup any other other features
pinMode ( POT_PIN , INPUT ) ; //set the potentiometer's input pin as an INPUT
} //end setup()
// define the loop() function, the function that is repeated over and over for the life of the device
unsigned long updatePeriod_millis = 100 ; //how many milliseconds between updating gain reading?
unsigned long lastUpdate_millis = 0 ;
unsigned long curTime_millis = 0 ;
int prev_gain_dB = 0 ;
unsigned long lastMemUpdate_millis = 0 ;
void loop ( ) {
//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.
//has enough time passed to try updating the GUI?
curTime_millis = millis ( ) ; //what time is it right now
if ( curTime_millis < lastUpdate_millis ) lastUpdate_millis = 0 ; //handle wrap-around of the clock
if ( ( curTime_millis - lastUpdate_millis ) > updatePeriod_millis ) { //is it time to update the user interface?
//read potentiometer
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
//compute desired digital gain
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
//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
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
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
}
lastUpdate_millis = curTime_millis ; //we will use this value the next time around.
} // end if
//print status information to the Serial port
if ( ( curTime_millis - lastMemUpdate_millis ) > 2000 ) { // print a summary of the current & maximum usage
//printCompressorState(&Serial);
printCPUandMemoryUsage ( & Serial ) ;
lastMemUpdate_millis = curTime_millis ; //we will use this value the next time around.
}
} //end loop();
void printCompressorState ( Stream * s ) {
s - > print ( " Current Compressor: Pre-Gain (dB) = " ) ;
s - > print ( comp1 . getPreGain_dB ( ) ) ;
s - > print ( " , Level (dBFS) = " ) ;
s - > print ( comp1 . getCurrentLevel_dBFS ( ) ) ;
s - > print ( " , " ) ;
s - > print ( comp2 . getCurrentLevel_dBFS ( ) ) ;
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 ) {
s - > print ( " Usage/Max: " ) ;
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 ( " 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 - > println ( ) ;
} ;