Hello,
My code detects beats from an incoming mono audio signal. This data is used to then draw circles with random color, radius and position on an LED Matrix (16x32). The circles start small and get larger with time (like waterdroplets).
The code is pretty slow so far and some of the beats are missed because of that. Could I speed up my code somehow?
#include <Adafruit_GFX.h> // Core graphics library
#include <RGBmatrixPanel.h> // Hardware-specific library
#define RAND_MAX 31
#define CLK 8 // MUST be on PORTB! (Use pin 11 on Mega)
#define LAT 10
#define OE 9
#define A A0
#define B A1
#define C A2
RGBmatrixPanel matrix(A, B, C, CLK, LAT, OE, true);
// Our Global Sample Rate, 5000hz
#define SAMPLEPERIODUS 200
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
void setup() {
// Set ADC to 77khz, max for 10bit
sbi(ADCSRA,ADPS2);
cbi(ADCSRA,ADPS1);
cbi(ADCSRA,ADPS0);
matrix.begin();
}
// 20 - 200hz Single Pole Bandpass IIR Filter
float bassFilter(float sample) {
static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
xv[0] = xv[1]; xv[1] = xv[2];
xv[2] = (sample) / 36.f; // change here to values close to 2, to adapt for stronger or weeker sources of line level audio (36)
yv[0] = yv[1]; yv[1] = yv[2];
yv[2] = (xv[2] - xv[0])
+ (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]);
return yv[2];
}
// 10hz Single Pole Lowpass IIR Filter
float envelopeFilter(float sample) { //10hz low pass
static float xv[2] = {0,0}, yv[2] = {0,0};
xv[0] = xv[1];
xv[1] = sample / 50.f;
yv[0] = yv[1];
yv[1] = (xv[0] + xv[1]) + (0.9875119299f * yv[0]);
return yv[1];
}
// 1.7 - 3.0hz Single Pole Bandpass IIR Filter
float beatFilter(float sample) {
static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
xv[0] = xv[1]; xv[1] = xv[2];
xv[2] = sample / 2.7f;
yv[0] = yv[1]; yv[1] = yv[2];
yv[2] = (xv[2] - xv[0])
+ (-0.7169861741f * yv[0]) + (1.4453653501f * yv[1]);
return yv[2];
}
//Draw Circles when Beat is detected
void waterdrops (int x_pos, int y_pos,int r, int g, int b,int i){
matrix.drawCircle(x_pos, y_pos, i-1, matrix.Color333(r, g, b));
matrix.drawCircle(x_pos, y_pos, i, matrix.Color333(r, g, b));
}
void loop() {
unsigned long time = micros(); // Used to track rate
float sample, value, envelope, beat, thresh;
unsigned char i;
int r[]={0,0};
int g[]={0,0};
int b[]={0,0};
int x_pos[]={0,0};
int y_pos[]={0,0};
int radius[]={0,0};
int j[]={0,0};
int trig[]={0,0};
for(i = 0;;++i){
// Read ADC and center so +-512
sample = (float)analogRead(4)-503.f;
// Filter only bass component
value = bassFilter(sample);
// Take signal amplitude and filter
if(value < 0)value=-value;
envelope = envelopeFilter(value);
// Every 200 samples (25hz) filter the envelope
if(i == 200) {
// Filter out repeating bass sounds 100 - 180bpm
beat = beatFilter(envelope);
// Threshold it based on potentiometer on AN1
thresh = 0.02f * (float)analogRead(5);
// If we are above threshold, light LED MATRIX
if(beat > thresh && trig[0]==0) {
x_pos[0]=rand() % 31;
y_pos[0]=rand() % 15;
r[0]=rand() % 7;
g[0]=rand() % 7;
b[0]=rand() % 7;
trig[0]=1;
}
else if (beat > thresh && trig[1]==0){
x_pos[1]=rand() % 31;
y_pos[1]=rand() % 15;
r[1]=rand() % 7;
g[1]=rand() % 7;
b[1]=rand() % 7;
trig[1]=1;
}
else {
matrix.fillRect(0, 0, 32, 16, matrix.Color333(0, 0, 0)); //Draw Black Screen
}
matrix.fillRect(0, 0, 32, 16, matrix.Color333(0, 0, 0));
if(trig[0]==1) {
waterdrops (x_pos[0], y_pos[0],r[0],g[0],b[0],j[0]);
j[0]++;
if(j[0]>31){
trig[0]=0;
j[0]=0;
}
}
if(trig[1]==1) {
waterdrops (x_pos[1], y_pos[1],r[1],g[1],b[1],j[1]);
j[1]++;
if(j[1]>31){
trig[1]=0;
j[1]=0;
}
}
matrix.swapBuffers(false);
//Reset sample counter
i = 0;
}
// Consume excess clock cycles, to keep at 5000 hz
for(unsigned long up = time+SAMPLEPERIODUS; time > 20 && time < up; time = micros());
}
//Code Never Gets Here
}