major redo of AudioFilterBiquad_F32

pull/6/merge
boblark 3 years ago
parent d6f30882a7
commit 86b0b29a20
  1. 41
      AudioFilterBiquad_F32.cpp
  2. 394
      AudioFilterBiquad_F32.h
  3. 121
      examples/TestBiquad/TestBiquad.ino

@ -1,41 +1,32 @@
/*
* AudioFilterBiquad_F32.cpp
*
* Chip Audette, OpenAudio, Apr 2017
*
* MIT License, Use at your own risk.
*
* This filter has been running in F32 as a single stage. This
* would work by using multiple instantations, but compute time and
* latency suffer. So, Feb 2021 convert to MAX_STAGES 4 as is the I16
* Teensy Audio library. Bob Larkin
*
* See AudioFilterBiquad_F32.h for more notes.
*/
#include "AudioFilterBiquad_F32.h"
void AudioFilterBiquad_F32::update(void)
{
void AudioFilterBiquad_F32::update(void) {
audio_block_f32_t *block;
block = AudioStream_F32::receiveWritable_f32();
if (!block) return;
// If there's no coefficient table, give up.
if (coeff_p == NULL) {
AudioStream_F32::release(block);
return;
}
if (!block) return; // Out of memory
// Serial.print(block->data[37],6); Serial.print(", IN "); Serial.println(block->data[38],6);
if(doBiquad) // Filter is defined, so go to it
arm_biquad_cascade_df1_f32(&iir_inst, block->data,
block->data, block->length);
// Serial.print(block->data[37],6); Serial.print(", OUT "); Serial.println(block->data[38],6);
// do passthru
if (coeff_p == IIR_F32_PASSTHRU) {
// Just passthrough
AudioStream_F32::transmit(block);
AudioStream_F32::release(block);
return;
}
// Add double filter call here
// do IIR
arm_biquad_cascade_df1_f32(&iir_inst, block->data, block->data, block->length);
//transmit the data
AudioStream_F32::transmit(block); // send the IIR output
// Transmit the data, filtered or unfiltered
AudioStream_F32::transmit(block);
AudioStream_F32::release(block);
}

@ -1,10 +1,29 @@
/*
* AudioFilterBiquad_F32
*
* Created: Chip Audette (OpenAudio) Feb 2017
* AudioFilterBiquad_F32.cpp
* Chip Audette, OpenAudio, Apr 2017
* MIT License, Use at your own risk.
*
* This filter has been running in F32 as a single stage. This
* would work by using multiple instantations, but compute time and
* latency suffer. So, Feb 2021 convert to MAX_STAGES 4 as is the I16
* Teensy Audio library. Bob Larrkin
*
* License: MIT License. Use at your own risk.
* Float vs Double. There are times when double precision in the
* BiQuad calculation is needed to prevent
* serious numerical errors. This can be a processor time problem for
* T3.x. This routine (NOT QUITE YET) allows for either by
* a function with float as the default. This allows different BiQuads
* to use float or double. RSL
*
* NOTE: If your INO is broken, we had to do it.
* Some setting of coefficients also did a
* begin of the ARM CMSIS. We can't do that with multiple stages. If you
* encouter this, add myBiquad.begin(); to your INO after the
* coefficients have been set. Feb 2021
*
* The sign of the coefficients for feedback, the a[], here use the
* convention of the ARM CMSIS library. Matlab reverses the signs of these.
* I believe these are treated per those rules!! Bob
*/
#ifndef _filter_iir_f32
@ -15,190 +34,235 @@
#include "arm_math.h"
// Indicates that the code should just pass through the audio
// without any filtering (as opposed to doing nothing at all)
// without any filtering (as opposed to doing nothing at all) ,,,,,REMOVE???? WE HAVE DO_BIQUAD THAT DOES THISS
#define IIR_F32_PASSTHRU ((const float32_t *) 1)
#define IIR_MAX_STAGES 1 //meaningless right now
// Changed Feb 2021
#define IIR_MAX_STAGES 4
// T4.x can generally use doubles, they may be a burden for T3.x
// Leave commented out to compile for BOTH float and double
// See the function useDouble(bool d) below
// #define NEVER_DOUBLE
class AudioFilterBiquad_F32 : public AudioStream_F32
{
//GUI: inputs:1, outputs:1 //this line used for automatic generation of GUI node
//GUI: shortName:IIR
public:
AudioFilterBiquad_F32(void): AudioStream_F32(1,inputQueueArray), coeff_p(IIR_F32_PASSTHRU) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE_EXACT);
}
AudioFilterBiquad_F32(const AudioSettings_F32 &settings):
AudioStream_F32(1,inputQueueArray), coeff_p(IIR_F32_PASSTHRU) {
setSampleRate_Hz(settings.sample_rate_Hz);
}
void begin(const float32_t *cp, int n_stages = 1) {
coeff_p = cp;
// Initialize FIR instance (ARM DSP Math Library)
if (coeff_p && (coeff_p != IIR_F32_PASSTHRU) && n_stages <= IIR_MAX_STAGES) {
//https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html
arm_biquad_cascade_df1_init_f32(&iir_inst, n_stages, (float32_t *)coeff_p, &StateF32[0]);
}
AudioFilterBiquad_F32(void): AudioStream_F32(1,inputQueueArray) {
setSampleRate_Hz(AUDIO_SAMPLE_RATE_EXACT);
sampleRate_Hz = AUDIO_SAMPLE_RATE_EXACT; // <<<<<<<<<<<<<<<<<<<<<< CHECK IF NEEDED??
doClassInit();
}
void end(void) {
coeff_p = NULL;
AudioFilterBiquad_F32(const AudioSettings_F32 &settings):
AudioStream_F32(1,inputQueueArray) {
setSampleRate_Hz(settings.sample_rate_Hz);
doClassInit();
}
void setSampleRate_Hz(float _fs_Hz) { sampleRate_Hz = _fs_Hz; }
void doClassInit(void) {
for(int ii=0; ii<5*IIR_MAX_STAGES; ii++) {
coeff32[ii] = 0.0;
coeff64[ii] = 0.0;
}
for(int ii=0; ii<4; ii++) {
coeff32[5*ii] = 1.0; // b0 = 1 for pass through
coeff64[5*ii] = 1.0;
}
numStagesUsed = 0; // Can be 0 to 4
doBiquad = false; // This is the way to jump over the biquad
}
// Up to 4 stages are allowed. Coefficients, either by design function
// or from direct setCoefficients() need to be added to the double array
// and also to the float
void setCoefficients(int iStage, double *cf) {
if (iStage > IIR_MAX_STAGES) {
if (Serial) {
Serial.print("AudioFilterBiquad_F32: setCoefficients:");
Serial.println(" *** MaxStages Error");
}
return;
}
if((iStage + 1) > numStagesUsed)
numStagesUsed = iStage + 1; // There may be blank pass throughs
for(int ii=0; ii<5; ii++) {
coeff64[ii + 5*iStage] = cf[ii]; // The local collection of double coefficients
coeff32[ii + 5*iStage] = (float)cf[ii]; // and of floats
}
doBiquad = true;
}
// ARM DSP Math library filter instance.
// Does the initialization of ARM CMSIS DSP BiQuad structure. This MUST follow the
// setting of coefficients to catch the max number of stages and do the
// double to float conversion for the CMSIS routine.
void begin(void) {
// Initialize FIR instance (ARM DSP Math Library)
//https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html
arm_biquad_cascade_df1_init_f32(&iir_inst, numStagesUsed, &coeff32[0], &StateF32[0]);
}
void end(void) {
doBiquad = false;
}
void setSampleRate_Hz(float _fs_Hz) { sampleRate_Hz = _fs_Hz; }
// Deprecated
void setBlockDC(void) {
//https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html#ga8e73b69a788e681a61bccc8959d823c5
//Use matlab to compute the coeff for HP at 40Hz: [b,a]=butter(2,40/(44100/2),'high'); %assumes fs_Hz = 44100
float32_t b[] = {8.173653471988667e-01, -1.634730694397733e+00, 8.173653471988667e-01}; //from Matlab
float32_t a[] = { 1.000000000000000e+00, -1.601092394183619e+00, 6.683689946118476e-01}; //from Matlab
// https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html#ga8e73b69a788e681a61bccc8959d823c5
// Use matlab to compute the coeff for HP at 40Hz: [b,a]=butter(2,40/(44100/2),'high'); %assumes fs_Hz = 44100
double b[] = {8.173653471988667e-01, -1.634730694397733e+00, 8.173653471988667e-01}; //from Matlab
double a[] = { 1.000000000000000e+00, -1.601092394183619e+00, 6.683689946118476e-01}; //from Matlab
setFilterCoeff_Matlab(b, a);
}
void setFilterCoeff_Matlab(float32_t b[], float32_t a[]) { //one stage of N=2 IIR
void setFilterCoeff_Matlab(double b[], double a[]) { //one stage of N=2 IIR
double coeff[5];
//https://www.keil.com/pack/doc/CMSIS/DSP/html/group__BiquadCascadeDF1.html#ga8e73b69a788e681a61bccc8959d823c5
//Use matlab to compute the coeff, such as: [b,a]=butter(2,20/(44100/2),'high'); %assumes fs_Hz = 44100
coeff[0] = b[0]; coeff[1] = b[1]; coeff[2] = b[2]; //here are the matlab "b" coefficients
coeff[3] = -a[1]; coeff[4] = -a[2]; //the DSP needs the "a" terms to have opposite sign vs Matlab ;
begin(coeff);
coeff[3] = -a[1]; coeff[4] = -a[2]; //the DSP needs the "a" terms to have opposite sign vs Matlab
setCoefficients(0, coeff);
}
//note: stage is currently ignored
void setCoefficients(int stage, float c[]) {
if (stage > 0) {
if (Serial) {
Serial.println(F("AudioFilterBiquad_F32: setCoefficients: *** ERROR ***"));
Serial.print(F(" : This module only accepts one stage."));
Serial.print(F(" : You are attempting to set stage "));Serial.print(stage);
Serial.print(F(" : Ignoring this filter."));
}
return;
}
coeff[0] = c[0];
coeff[1] = c[1];
coeff[2] = c[2];
coeff[3] = -c[3];
coeff[4] = -c[4];
begin(coeff);
}
// Compute common filter functions
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
//void setLowpass(uint32_t stage, float frequency, float q = 0.7071) {
void setLowpass(uint32_t stage, float frequency, float q = 0.7071) {
//int coeff[5];
double w0 = frequency * (2 * 3.141592654 / AUDIO_SAMPLE_RATE_EXACT);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
//double scale = 1073741824.0 / (1.0 + alpha);
double scale = 1.0 / (1.0+alpha); // which is equal to 1.0 / a0
/* b0 */ coeff[0] = ((1.0 - cosW0) / 2.0) * scale;
/* b1 */ coeff[1] = (1.0 - cosW0) * scale;
/* b2 */ coeff[2] = coeff[0];
/* a1 */ coeff[3] = (-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = (1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setHighpass(uint32_t stage, float frequency, float q = 0.7071) {
//int coeff[5];
double w0 = frequency * (2 * 3.141592654 / AUDIO_SAMPLE_RATE_EXACT);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
double scale = 1.0 / (1.0+alpha); // which is equal to 1.0 / a0
/* b0 */ coeff[0] = ((1.0 + cosW0) / 2.0) * scale;
/* b1 */ coeff[1] = -(1.0 + cosW0) * scale;
/* b2 */ coeff[2] = coeff[0];
/* a1 */ coeff[3] = (-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = (1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setBandpass(uint32_t stage, float frequency, float q = 1.0) {
//int coeff[5];
double w0 = frequency * (2 * 3.141592654 / AUDIO_SAMPLE_RATE_EXACT);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
double scale = 1.0 / (1.0+alpha); // which is equal to 1.0 / a0
/* b0 */ coeff[0] = alpha * scale;
/* b1 */ coeff[1] = 0;
/* b2 */ coeff[2] = (-alpha) * scale;
/* a1 */ coeff[3] = (-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = (1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setNotch(uint32_t stage, float frequency, float q = 1.0) {
//int coeff[5];
double w0 = frequency * (2 * 3.141592654 / AUDIO_SAMPLE_RATE_EXACT);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
double scale = 1.0 / (1.0+alpha); // which is equal to 1.0 / a0
/* b0 */ coeff[0] = scale;
/* b1 */ coeff[1] = (-2.0 * cosW0) * scale;
/* b2 */ coeff[2] = coeff[0];
/* a1 */ coeff[3] = (-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = (1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setLowShelf(uint32_t stage, float frequency, float gain, float slope = 1.0f) {
//int coeff[5];
double a = pow(10.0, gain/40.0);
double w0 = frequency * (2 * 3.141592654 / AUDIO_SAMPLE_RATE_EXACT);
double sinW0 = sin(w0);
//double alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
double cosW0 = cos(w0);
//generate three helper-values (intermediate results):
double sinsq = sinW0 * sqrt( (pow(a,2.0)+1.0)*(1.0/slope-1.0)+2.0*a );
double aMinus = (a-1.0)*cosW0;
double aPlus = (a+1.0)*cosW0;
double scale = 1.0 / ( (a+1.0) + aMinus + sinsq);
/* b0 */ coeff[0] = a * ( (a+1.0) - aMinus + sinsq ) * scale;
/* b1 */ coeff[1] = 2.0*a * ( (a-1.0) - aPlus ) * scale;
/* b2 */ coeff[2] = a * ( (a+1.0) - aMinus - sinsq ) * scale;
/* a1 */ coeff[3] = -2.0* ( (a-1.0) + aPlus ) * scale;
/* a2 */ coeff[4] = ( (a+1.0) + aMinus - sinsq ) * scale;
setCoefficients(stage, coeff);
}
void setHighShelf(uint32_t stage, float frequency, float gain, float slope = 1.0f) {
//int coeff[5];
double a = pow(10.0, gain/40.0);
double w0 = frequency * (2 * 3.141592654 / AUDIO_SAMPLE_RATE_EXACT);
double sinW0 = sin(w0);
//double alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
double cosW0 = cos(w0);
//generate three helper-values (intermediate results):
double sinsq = sinW0 * sqrt( (pow(a,2.0)+1.0)*(1.0/slope-1.0)+2.0*a );
double aMinus = (a-1.0)*cosW0;
double aPlus = (a+1.0)*cosW0;
double scale = 1.0 / ( (a+1.0) - aMinus + sinsq);
/* b0 */ coeff[0] = a * ( (a+1.0) + aMinus + sinsq ) * scale;
/* b1 */ coeff[1] = -2.0*a * ( (a-1.0) + aPlus ) * scale;
/* b2 */ coeff[2] = a * ( (a+1.0) + aMinus - sinsq ) * scale;
/* a1 */ coeff[3] = 2.0* ( (a-1.0) - aPlus ) * scale;
/* a2 */ coeff[4] = ( (a+1.0) - aMinus - sinsq ) * scale;
setCoefficients(stage, coeff);
}
//Two update() options, floats or doubles
void useDouble(bool ud) {
useDoubleCoefs = ud; // true is to use doubles
useDoubleCoefs = false; // Not implemented yet
}
// Compute common filter functions
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
//void setLowpass(uint32_t stage, float frequency, float q = 0.7071) {
void setLowpass(int stage, float frequency, float q) {
double coeff[5];
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
double scale = 1.0 / (1.0+alpha); // which is equal to 1.0 / a0
/* b0 */ coeff[0] = ((1.0 - cosW0) / 2.0) * scale;
/* b1 */ coeff[1] = (1.0 - cosW0) * scale;
/* b2 */ coeff[2] = coeff[0];
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = -(1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setHighpass(uint32_t stage, float frequency, float q) {
double coeff[5];
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
double scale = 1.0 / (1.0+alpha);
/* b0 */ coeff[0] = ((1.0 + cosW0) / 2.0) * scale;
/* b1 */ coeff[1] = -(1.0 + cosW0) * scale;
/* b2 */ coeff[2] = coeff[0];
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = -(1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setBandpass(uint32_t stage, float frequency, float q) {
double coeff[5];
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
double scale = 1.0 / (1.0+alpha);
/* b0 */ coeff[0] = alpha * scale;
/* b1 */ coeff[1] = 0;
/* b2 */ coeff[2] = (-alpha) * scale;
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = -(1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setNotch(uint32_t stage, float frequency, float q) {
double coeff[5];
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz);
double sinW0 = sin(w0);
double alpha = sinW0 / ((double)q * 2.0);
double cosW0 = cos(w0);
double scale = 1.0 / (1.0+alpha); // which is equal to 1.0 / a0
/* b0 */ coeff[0] = scale;
/* b1 */ coeff[1] = (-2.0 * cosW0) * scale;
/* b2 */ coeff[2] = coeff[0];
/* a1 */ coeff[3] = -(-2.0 * cosW0) * scale;
/* a2 */ coeff[4] = -(1.0 - alpha) * scale;
setCoefficients(stage, coeff);
}
void setLowShelf(uint32_t stage, float frequency, float gain, float slope) {
double coeff[5];
double a = pow(10.0, gain/40.0);
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz);
double sinW0 = sin(w0);
//double alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
double cosW0 = cos(w0);
//generate three helper-values (intermediate results):
double sinsq = sinW0 * sqrt( (pow(a,2.0)+1.0)*(1.0/slope-1.0)+2.0*a );
double aMinus = (a-1.0)*cosW0;
double aPlus = (a+1.0)*cosW0;
double scale = 1.0 / ( (a+1.0) + aMinus + sinsq);
/* b0 */ coeff[0] = a * ( (a+1.0) - aMinus + sinsq ) * scale;
/* b1 */ coeff[1] = 2.0*a * ( (a-1.0) - aPlus ) * scale;
/* b2 */ coeff[2] = a * ( (a+1.0) - aMinus - sinsq ) * scale;
/* a1 */ coeff[3] = 2.0* ( (a-1.0) + aPlus ) * scale;
/* a2 */ coeff[4] = - ( (a+1.0) + aMinus - sinsq ) * scale;
setCoefficients(stage, coeff);
}
void setHighShelf(uint32_t stage, float frequency, float gain, float slope) {
double coeff[5];
double a = pow(10.0, gain/40.0);
double w0 = frequency * (2 * 3.141592654 / sampleRate_Hz);
double sinW0 = sin(w0);
//double alpha = (sinW0 * sqrt((a+1/a)*(1/slope-1)+2) ) / 2.0;
double cosW0 = cos(w0);
//generate three helper-values (intermediate results):
double sinsq = sinW0 * sqrt( (pow(a,2.0)+1.0)*(1.0/slope-1.0)+2.0*a );
double aMinus = (a-1.0)*cosW0;
double aPlus = (a+1.0)*cosW0;
double scale = 1.0 / ( (a+1.0) - aMinus + sinsq);
/* b0 */ coeff[0] = a * ( (a+1.0) + aMinus + sinsq ) * scale;
/* b1 */ coeff[1] = -2.0*a * ( (a-1.0) + aPlus ) * scale;
/* b2 */ coeff[2] = a * ( (a+1.0) + aMinus - sinsq ) * scale;
/* a1 */ coeff[3] = -2.0* ( (a-1.0) - aPlus ) * scale;
/* a2 */ coeff[4] = -( (a+1.0) - aMinus - sinsq ) * scale;
setCoefficients(stage, coeff);
}
double* getCoeffs(void) {
return coeff64; // Pointer to 20 coefficients in double.
}
void update(void);
private:
audio_block_f32_t *inputQueueArray[1];
float32_t coeff[5 * 1] = {1.0, 0.0, 0.0, 0.0, 0.0}; //no filtering. actual filter coeff set later
float sampleRate_Hz = AUDIO_SAMPLE_RATE_EXACT; //default. from AudioStream.h??
// pointer to current coefficients or NULL or FIR_PASSTHRU
const float32_t *coeff_p;
// ARM DSP Math library filter instance
float coeff32[5 * IIR_MAX_STAGES]; // Local copies to be transferred with begin()
double coeff64[5 * IIR_MAX_STAGES];
float StateF32[4*IIR_MAX_STAGES];
//double StateF64[4*IIR_MAX_STAGES]; // Will need this for 64 bit version
float sampleRate_Hz = AUDIO_SAMPLE_RATE_EXACT; //default. from AudioStream.h??
int numStagesUsed = 0;
bool useDoubleCoefs = false; // As of now, all float <<<<<<<<<<<<<<<<<<<<
bool doBiquad = false;
/* Info - The structure from arm_biquad_casd_df1_inst_f32 consists of
* uint32_t numStages;
* const float32_t *pCoeffs; //Points to the array of coefficients, length 5*numStages.
* float32_t *pState; //Points to the array of state variables, length 4*numStages.
*/
// ARM DSP Math library filter instance.
arm_biquad_casd_df1_inst_f32 iir_inst;
float32_t StateF32[4*IIR_MAX_STAGES];
};
#endif

@ -0,0 +1,121 @@
/*
TestBiquad.ino Test the
* F32 library AudioFilterBiquad_F32
* Bob Larkin 26Feb 2021
* Public Domain
*/
#include "OpenAudio_ArduinoLibrary.h"
#include "AudioStream_F32.h"
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>
// T3.x supported sample rates: 2000, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 44117, 48000,
// 88200, 88235 (44117*2), 95680, 96000, 176400, 176470, 192000
// T4.x supports any sample rate the codec will handle.
const float sample_rate_Hz = 44117.0f ; // 24000, 44117, or other frequencies listed above (untested)
const int audio_block_samples = 128; // Others untested
AudioSettings_F32 audio_settings(sample_rate_Hz, audio_block_samples); // Not used
// GUItool: begin automatically generated code
AudioInputI2S_F32 audioInI2S1; //xy=73.5,556
AudioSynthWaveformSine_F32 sine1; //xy=89,595
AudioMixer4_F32 mixer4_1; //xy=263,572
AudioAnalyzeRMS_F32 rms1; //xy=411,528
AudioFilterBiquad_F32 biquad1; //xy=414,586
AudioAnalyzeRMS_F32 rms2; //xy=547,528
AudioOutputI2S_F32 audioOutI2S1; //xy=576,585
AudioConnection_F32 patchCord1(audioInI2S1, 0, mixer4_1, 0);
AudioConnection_F32 patchCord2(audioInI2S1, 1, mixer4_1, 1);
AudioConnection_F32 patchCord3(sine1, 0, mixer4_1, 2);
AudioConnection_F32 patchCord4(mixer4_1, biquad1);
AudioConnection_F32 patchCord5(mixer4_1, rms1);
AudioConnection_F32 patchCord6(biquad1, 0, audioOutI2S1, 1);
AudioConnection_F32 patchCord7(biquad1, 0, audioOutI2S1, 0);
AudioConnection_F32 patchCord8(biquad1, rms2);
AudioControlSGTL5000 sgtl5000_1; //xy=327,636
// GUItool: end automatically generated code
// Reminder: Check that AudioMemory_F32 is allocated and that
// settings are added to F32 objects as needed, including Memory.
void setup() {
Serial.begin(300);
delay(1000);
Serial.println("OpenAudio_ArduinoLibrary - TestBiquad");
AudioMemory(10); //allocate Int16 audio data blocks
AudioMemory_F32(20, audio_settings);
// Enable the audio shield, select input, and enable output
sgtl5000_1.enable(); //start the audio board
sgtl5000_1.inputSelect(AUDIO_INPUT_LINEIN); // or AUDIO_INPUT_MIC
sgtl5000_1.volume(0.8); //volume can be 0.0 to 1.0
sgtl5000_1.lineInLevel(10, 10); //level can be 0 to 15. 5 is the Teensy Audio Library's default
mixer4_1.gain(0, 1.0f); // Left in
mixer4_1.gain(1, 1.0f); // Right In
mixer4_1.gain(2, 0.0f); // Sine wave in
// **** BiQuad Filter Selection - Pick one of the next ****
//biquad1.setHighpass(0, 40.0f, 0.707f);
//biquad1.setHighpass(0, 1000.0f, 0.707f);
biquad1.setLowpass(0, 2500.0f, 0.707f);
//for(int jj=0; jj<4; jj++) biquad1.setLowpass(jj, 2000.0f, 0.707f);
//biquad1.setBandpass(0, 1000.0f, 1.5f);
//biquad1.setNotch(0, 1000.0f, 1.0f);
// Coeffs, a0=1.0 always b0 b1 b2 a1 a2
//double cfLP2500[] = {0.025157343556, 0.050314687112, 0.025157343556, 1.503844064936, -0.604473439160};
//biquad1.setCoefficients(0, cfLP2500); // (int iStage, double *cf) // Load cfLP2500, 1 stage
// ************************************************************
biquad1.begin();
// Download a pointer to the coefficients to see what is happening
double* pc=biquad1.getCoeffs();
Serial.println(" b0 b1 b2 a1 a2");
for(int ii=0; ii<4; ii++) {
Serial.print( *(pc + 0 + ii*5),12 ); Serial.print(", ");
Serial.print( *(pc + 1 + ii*5),12 ); Serial.print(", ");
Serial.print( *(pc + 2 + ii*5),12 ); Serial.print(", ");
Serial.print( *(pc + 3 + ii*5),12 ); Serial.print(", ");
Serial.print( *(pc + 4 + ii*5),12 ); Serial.println();
}
sine1.frequency(500.0); // Connect via mixer4_1.gain(2, 0.0f);
sine1.amplitude(0.02);
}
void loop() {
//update the memory and CPU usage...if enough time has passed
printMemoryAndCPU(millis());
}
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;
float r1, r2;
//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?
if( rms1.available() ) {
Serial.print("RMS in: ");
Serial.print(r1=rms1.read(), 6);
}
if( rms2.available() ) {
Serial.print(" RMS out: ");
Serial.print(r2=rms2.read(), 6);
Serial.print(" Gain, dB = ");
Serial.print( 20.0f*log10f(r2/r1));
}
Serial.print(" CPU: Usage, Max: ");
Serial.print(AudioProcessorUsageMax());
Serial.print(" Float Memory, Max: ");
Serial.println(AudioMemoryUsageMax_F32());
lastUpdate_millis = curTime_millis; //we will use this value the next time around.
}
}
Loading…
Cancel
Save