Browse Source

Change FIR filter (as suggested by rheslip) to filter one channel instead of two. Updated example, added documenting file

dds
Pete (El Supremo) 10 years ago
parent
commit
191e65e02a
4 changed files with 82 additions and 42 deletions
  1. +51
    -20
      examples/fir_filter/fir_filter.ino
  2. +4
    -17
      filter_fir.cpp
  3. +9
    -5
      filter_fir.h
  4. +18
    -0
      filter_fir.md

+ 51
- 20
examples/fir_filter/fir_filter.ino View File

@@ -1,4 +1,8 @@
/*
c
- released
b
- Use FIR filters with fast_fft option

The audio board uses the following pins.
6 - MEMCS
@@ -25,14 +29,15 @@ The audio board uses the following pins.
#include <Bounce.h>
#include "filters.h"

// If this pin is grounded the FIR filter is turned which
// makes just pass through the audio
// If this pin is grounded the FIR filter is turned off
// which just passes the audio sraight through
// Don't use any of the pins listed above
#define PASSTHRU_PIN 1
// If this pin goes low the next FIR filter in the list
// is switched in.
#define FILTER_PIN 0

// debounce the passthru and filter switching pins
Bounce b_passthru = Bounce(PASSTHRU_PIN,15);
Bounce b_filter = Bounce(FILTER_PIN,15);

@@ -41,16 +46,18 @@ const int myInput = AUDIO_INPUT_LINEIN;


AudioInputI2S audioInput; // audio shield: mic or line-in
AudioFilterFIR myFilter;
// Use the fast FIR filter for left and right channels
AudioFilterFIR myFilterL(true);
AudioFilterFIR myFilterR(true);
AudioOutputI2S audioOutput; // audio shield: headphones & line-out

// Create Audio connections between the components
// Both channels of the audio input go to the FIR filter
AudioConnection c1(audioInput, 0, myFilter, 0);
AudioConnection c2(audioInput, 1, myFilter, 1);
// both channels from the FIR filter go to the audio output
AudioConnection c3(myFilter, 0, audioOutput, 0);
AudioConnection c4(myFilter, 1, audioOutput, 1);
// Route audio into the left and right filters
AudioConnection c1(audioInput, 0, myFilterL, 0);
AudioConnection c2(audioInput, 1, myFilterR, 0);
// Route the output of the filters to their respective channels
AudioConnection c3(myFilterL, 0, audioOutput, 0);
AudioConnection c4(myFilterR, 0, audioOutput, 1);
AudioControlSGTL5000 audioShield;


@@ -62,9 +69,9 @@ struct fir_filter {
// index of current filter. Start with the low pass.
int fir_idx = 0;
struct fir_filter fir_list[] = {
low_pass , 100, // low pass with cutoff at 1kHz and -60dB at 2kHz
band_pass, 100, // bandpass 1200Hz - 1700Hz
NULL, 0
{low_pass , 100}, // low pass with cutoff at 1kHz and -60dB at 2kHz
{band_pass, 100}, // bandpass 1200Hz - 1700Hz
{NULL, 0}
};


@@ -98,8 +105,8 @@ void setup() {
Serial.println(") is grounded");
}
// Initialize the filter
myFilter.begin(fir_list[0].coeffs,fir_list[0].num_coeffs);
myFilterL.begin(fir_list[0].coeffs,fir_list[0].num_coeffs);
myFilterR.begin(fir_list[0].coeffs,fir_list[0].num_coeffs);
Serial.println("setup done");
}

@@ -108,7 +115,7 @@ int old_idx = -1;

// audio volume
int volume = 0;
unsigned long last_time = millis();
void loop()
{
// Volume control
@@ -122,18 +129,20 @@ void loop()
b_passthru.update();
b_filter.update();

// If the passthru button is pushed, save the current
// filter index and then switch the filter to passthru
if(b_passthru.fallingEdge()) {
old_idx = fir_idx;
myFilter.begin(FIR_PASSTHRU,0);
myFilterL.begin(FIR_PASSTHRU,0);
myFilterR.begin(FIR_PASSTHRU,0);
}
// If passthru button is released, restore previous filter
if(b_passthru.risingEdge()) {
if(old_idx != -1)myFilter.begin(fir_list[fir_idx].coeffs,fir_list[fir_idx].num_coeffs);
if(old_idx != -1) {
myFilterL.begin(fir_list[fir_idx].coeffs,fir_list[fir_idx].num_coeffs);
myFilterR.begin(fir_list[fir_idx].coeffs,fir_list[fir_idx].num_coeffs);
}
old_idx = -1;
}
@@ -141,9 +150,31 @@ void loop()
if(b_filter.fallingEdge()) {
fir_idx++;
if(fir_list[fir_idx].num_coeffs == 0)fir_idx = 0;
myFilter.begin(fir_list[fir_idx].coeffs,fir_list[fir_idx].num_coeffs);
myFilterL.begin(fir_list[fir_idx].coeffs,fir_list[fir_idx].num_coeffs);
myFilterR.begin(fir_list[fir_idx].coeffs,fir_list[fir_idx].num_coeffs);
}


if(1) {
// With fast_fir
// Proc = 18 (18), Mem = 4 (6)

if(millis() - last_time >= 5000) {
Serial.print("Proc = ");
Serial.print(AudioProcessorUsage());
Serial.print(" (");
Serial.print(AudioProcessorUsageMax());
Serial.print("), Mem = ");
Serial.print(AudioMemoryUsage());
Serial.print(" (");
Serial.print(AudioMemoryUsageMax());
Serial.println(")");
last_time = millis();
}
}


}




+ 4
- 17
filter_fir.cpp View File

@@ -29,7 +29,6 @@ void AudioFilterFIR::begin(short *cp,int n_coeffs)
// Initialize FIR instances for the left and right channels
if(coeff_p && (coeff_p != FIR_PASSTHRU)) {
arm_fir_init_q15(&l_fir_inst, n_coeffs, coeff_p, &l_StateQ15[0], AUDIO_BLOCK_SAMPLES);
arm_fir_init_q15(&r_fir_inst, n_coeffs, coeff_p, &r_StateQ15[0], AUDIO_BLOCK_SAMPLES);
}
}

@@ -55,11 +54,6 @@ void AudioFilterFIR::update(void)
transmit(block,0);
release(block);
}
block = receiveReadOnly(1);
if(block) {
transmit(block,1);
release(block);
}
return;
}
// Left Channel
@@ -67,22 +61,15 @@ void AudioFilterFIR::update(void)
// get a block for the FIR output
b_new = allocate();
if(block && b_new) {
arm_fir_q15(&l_fir_inst, (q15_t *)block->data, (q15_t *)b_new->data, AUDIO_BLOCK_SAMPLES);
if(arm_fast)
arm_fir_fast_q15(&l_fir_inst, (q15_t *)block->data, (q15_t *)b_new->data, AUDIO_BLOCK_SAMPLES);
else
arm_fir_q15(&l_fir_inst, (q15_t *)block->data, (q15_t *)b_new->data, AUDIO_BLOCK_SAMPLES);
// send the FIR output to the left channel
transmit(b_new,0);
}
if(block)release(block);
if(b_new)release(b_new);

// Right Channel
block = receiveReadOnly(1);
b_new = allocate();
if(block && b_new) {
arm_fir_q15(&r_fir_inst, (q15_t *)block->data, (q15_t *)b_new->data, AUDIO_BLOCK_SAMPLES);
transmit(b_new,1);
}
if(block)release(block);
if(b_new)release(b_new);
}



+ 9
- 5
filter_fir.h View File

@@ -26,6 +26,10 @@
#include "AudioStream.h"
#include "arm_math.h"

#define USE_FAST_FIR true
#define USE_SLOW_FIR false


// Maximum number of coefficients in a FIR filter
// The audio breaks up with 128 coefficients so a
// maximum of 150 is more than sufficient
@@ -39,12 +43,12 @@ class AudioFilterFIR :
public AudioStream
{
public:
AudioFilterFIR(void):
AudioStream(2,inputQueueArray), coeff_p(NULL)
AudioFilterFIR(const boolean a_f):
AudioStream(2,inputQueueArray), arm_fast(a_f), coeff_p(NULL)
{
}

void begin(short *coeff_p,int f_pin);
void begin(short *coeff_p,int n_coeffs);
virtual void update(void);
void stop(void);
@@ -54,11 +58,11 @@ private:
// the state arrays are defined to handle a maximum of MAX_COEFFS
// coefficients in a filter
q15_t l_StateQ15[AUDIO_BLOCK_SAMPLES + MAX_COEFFS];
q15_t r_StateQ15[AUDIO_BLOCK_SAMPLES + MAX_COEFFS];
arm_fir_instance_q15 l_fir_inst;
arm_fir_instance_q15 r_fir_inst;
// pointer to current coefficients or NULL or FIR_PASSTHRU
short *coeff_p;
// Whether to use the fast arm FIR code
const boolean arm_fast;
};

#endif

+ 18
- 0
filter_fir.md View File

@@ -0,0 +1,18 @@
filter_fir 140418
Filters the audio stream using FIR coefficients supplied by the user.
The ARM library has two q15 functions which perform an FIR filter. One uses
a 64-bit accumulator (arm_fir_q15) and the other uses a 32-bit accumulator
(arm_fir_fast_q15). When instantiating a filter a boolean argument specifies
which version to use. Specifying USE_FAST_FIR (defined as boolean true) uses
the fast code otherwise the slower code is used. For example:
AudioFilterFIR myFilterL(USE_FAST_FIR);

void begin(short *cp,int n_coeffs)
Starts the filter using coefficients at *cp and the number of coefficients
is n_coeffs. The special value FIR_PASSTHRU can be used in place of the
address of the coefficient array, in which case the function will just pass
audio samples through without filtering.

void stop(void)
Stops the filter.


Loading…
Cancel
Save