From 1742b08255fc498551dde0799f8b19f837d3c2ee Mon Sep 17 00:00:00 2001 From: Chip Audette Date: Mon, 19 Dec 2016 09:48:12 -0500 Subject: [PATCH] Examples: Adding AudioEffectMine --- .../MyAudioEffect_Float/AudioEffectMine_F32.h | 90 ++++++++++++ .../MyAudioEffect_Float.ino | 138 ++++++++++++++++++ 2 files changed, 228 insertions(+) create mode 100644 examples/MyAudioEffect_Float/AudioEffectMine_F32.h create mode 100644 examples/MyAudioEffect_Float/MyAudioEffect_Float.ino diff --git a/examples/MyAudioEffect_Float/AudioEffectMine_F32.h b/examples/MyAudioEffect_Float/AudioEffectMine_F32.h new file mode 100644 index 0000000..f7dc59a --- /dev/null +++ b/examples/MyAudioEffect_Float/AudioEffectMine_F32.h @@ -0,0 +1,90 @@ + +/* + AudioEffectMine + + Created: Chip Audette, December 2016 + Purpose; Here is the skeleton of a audio processing algorithm that will + (hopefully) make it easier for people to start making their own + algorithm. + + This processes a single stream fo audio data (ie, it is mono) + + MIT License. use at your own risk. +*/ + +#include //ARM DSP extensions. https://www.keil.com/pack/doc/CMSIS/DSP/html/index.html +#include + +class AudioEffectMine_F32 : public AudioStream_F32 +{ + public: + //constructor + AudioEffectMine_F32(void) : AudioStream_F32(1, inputQueueArray_f32) { + //do any setup activities here + }; + + //here's the method that is called automatically by the Teensy Audio Library + void update(void) { + //Serial.println("AudioEffectMine_F32: doing update()"); //for debugging. + audio_block_f32_t *audio_block; + audio_block = AudioStream_F32::receiveWritable_f32(); + if (!audio_block) return; + + //do your work + applyMyAlgorithm(audio_block); + + ///transmit the block and release memory + AudioStream_F32::transmit(audio_block); + AudioStream_F32::release(audio_block); + } + + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!11 + // Here is where you can add your algorithm. + // This function gets called block-wise...which is usually hard-coded to every 128 samples + void applyMyAlgorithm(audio_block_f32_t *audio_block) { + + //Add whatever you'd like here. I'm going to show a couple of examples below. + //you can delete all of these examples. They're just to illustrate. + //More examples of fast (DSP accelerated) operations are at: https://github.com/chipaudette/OpenAudio/blob/master/Docs/Programming%20Algorithms/Using%20DSP%20Exentions.md + + // //apply a fixed gain...the whole block is processed with this one command + //float32_t gain = 2.0; %here's 6 dB of gain + //arm_scale_f32(audio_block->data, gain, audio_block->data, audio_block->length); //uses ARM DSP for speed! + + // //compute the power of each sample...the whole block is processed with this one command + // audio_block_f32_t *audio_pow_block = AudioStream_F32::allocate_f32(); + // arm_mult_f32(audio_block->data, audio_block->data, audio_pow_block->data, audio_block->length); + + // //loop over each sample and do something on a point-by-point basis (when it cannot be done as a block) + //for (int i=0; i < audio_block->length; i++) { + // //as a boring example, let's add the user_parameter value to every sample. yes, this + // //addition operation could have been done with a DSP-accelerated function, but I'm + // //simply trying to illustrate how to loop on your audio samples. + // audio_block->data[i] = audio_block->data[i] + user_parameter; + //} + + // //clean up...if you allocated any memory in the lines above + //Audiostream_F32::release(audio_pow_block); + } //end of applyMyAlgorithms + // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + + + // Call this method in your main program if you want to set the value of your user parameter. + // The user parameter can be used in your algorithm above. The user_parameter variable was + // created in the "private:" section of this class, which appears a little later in this file. + // Feel free to create more user parameters (and to use better names for your variables) + // for use in this class. + float32_t setUserParameter(float val) { + return user_parameter = val; + } + + private: + //state-related variables + audio_block_f32_t *inputQueueArray_f32[1]; //memory pointer for the input to this module + + //this value can be set from the outside (such as from the potentiometer) to control + //a parameter within your algorithm + float32_t user_parameter = 0.0; + +}; //end class definition for AudioEffectMine_F32 + diff --git a/examples/MyAudioEffect_Float/MyAudioEffect_Float.ino b/examples/MyAudioEffect_Float/MyAudioEffect_Float.ino new file mode 100644 index 0000000..861a602 --- /dev/null +++ b/examples/MyAudioEffect_Float/MyAudioEffect_Float.ino @@ -0,0 +1,138 @@ +/* + BasicGain + + Created: Chip Audette, Dec 2016 + Purpose: Be a blank canvas for adding your own floating-point audio processing. + + Uses Teensy Audio Adapter. + Assumes microphones (or whatever) are attached to the LINE IN (stereo) + Listens potentiometer mounted to Audio Board to provde a control signal. + + MIT License. use at your own risk. +*/ + +//These are the includes from the Teensy Audio Library +#include //Teensy Audio Library +#include +#include +#include +#include + +#include //for AudioConvert_I16toF32, AudioConvert_F32toI16, and AudioEffectGain_F32 +#include "AudioEffectMine_F32.h"; + +//create audio library objects for handling the audio +AudioControlSGTL5000 sgtl5000_1; //controller for the Teensy Audio Board +AudioInputI2S i2s_in; //Digital audio *from* the Teensy Audio Board ADC. Sends Int16. Stereo. +AudioOutputI2S i2s_out; //Digital audio *to* the Teensy Audio Board DAC. Expects Int16. Stereo +AudioConvert_I16toF32 int2Float1, int2Float2; //Converts Int16 to Float. See class in AudioStream_F32.h +AudioEffectMine_F32 effect1, effect2; //This is your own algorithms +AudioConvert_F32toI16 float2Int1, float2Int2; //Converts Float to Int16. See class in AudioStream_F32.h + +//Make all of the audio connections +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 +AudioConnection_F32 patchCord10(int2Float1, 0, effect1, 0); //Left. makes Float connections between objects +AudioConnection_F32 patchCord11(int2Float2, 0, effect2, 0); //Right. makes Float connections between objects +AudioConnection_F32 patchCord12(effect1, 0, float2Int1, 0); //Left. makes Float connections between objects +AudioConnection_F32 patchCord13(effect2, 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 + +// 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 the 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("OpenAudio_ArduinoLibrary: MyAudioEffect_Float..."); + + // Audio connections require memory + AudioMemory(10); //allocate Int16 audio data blocks + AudioMemory_F32(10); //allocate Float32 audio data blocks + + // Enable the audio shield, select input, and enable output + sgtl5000_1.enable(); //start the audio board + sgtl5000_1.inputSelect(myInput); //choose line-in or mic-in + sgtl5000_1.volume(0.8); //volume can be 0.0 to 1.0. 0.5 seems to be the usual default. + sgtl5000_1.lineInLevel(10, 10); //level can be 0 to 15. 5 is the Teensy Audio Library's default + sgtl5000_1.adcHighPassFilterDisable(); //reduces noise. https://forum.pjrc.com/threads/27215-24-bit-audio-boards?p=78831&viewfull=1#post78831 + + // 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 +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. + + //service the potentiometer...if enough time has passed + servicePotentiometer(millis()); + + //update the memory and CPU usage...if enough time has passed + printMemoryAndCPU(millis()); +} //end loop() + + +//servicePotentiometer: listens to the blue potentiometer and sends the new pot value +// to the audio processing algorithm as a control parameter +void servicePotentiometer(unsigned long curTime_millis) { + static unsigned long updatePeriod_millis = 100; //how many milliseconds between updating the potentiometer reading? + static unsigned long lastUpdate_millis = 0; + static float prev_val = 0; + + //has enough time passed to update everything? + 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 + float val = float(analogRead(POT_PIN)) / 1024.0; //0.0 to 1.0 + val = 0.1 * (float)((int)(10.0 * val + 0.5)); //quantize so that it doesn't chatter + + //add code here to change the potentiometer value to something useful (like gain_dB?) + // ..... add code here if you'd like ...... + + //send the potentiometer value to your algorithm as a control parameter + if (abs(val - prev_val) > 0.05) { //is it different than befor? + Serial.print("Sending new value to my algorithms: "); Serial.println(val); + effect1.setUserParameter(val); effect2.setUserParameter(val); + } + prev_val = val; //use the value the next time around + } // end if +} //end servicePotentiometer(); + + +void printMemoryAndCPU(unsigned long curTime_millis) { + static unsigned long updatePeriod_millis = 2000; //how many milliseconds between updating gain reading? + static unsigned long lastUpdate_millis = 0; + + //has enough time passed to update everything? + 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? + Serial.print("CPU: Usage, Max: "); + Serial.print(AudioProcessorUsage()); + Serial.print(", "); + Serial.print(AudioProcessorUsageMax()); + Serial.print(" "); + Serial.print("Int16 Memory: "); + Serial.print(AudioMemoryUsage()); + Serial.print(", "); + Serial.print(AudioMemoryUsageMax()); + Serial.print(" "); + Serial.print("Float Memory: "); + Serial.print(AudioMemoryUsage_F32()); + Serial.print(", "); + Serial.print(AudioMemoryUsageMax_F32()); + Serial.println(); + lastUpdate_millis = curTime_millis; //we will use this value the next time around. + } +} +