LED timing issue when detecting Beats

Hello!

I Have this beat detector code, which runs fine on my arduino Uno. Everytime a beat is detected, a circle is drawn with increasing radius (sort of like waterdrops) on the Adafruit LED MATRIX(16x32).

My issue is that some beats are missed because the arduino is still busy drawing circles. How can I realize that two circles are drawn simultaneously, so that no beats are missed?

I thought Interrupts might work but I have no experience with them and I read that you shouldnt spend too much time in an interrupt.

Any help would be greatly appreciated :art:

Code:

#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

int trigger=0; //Beat Trigger true or false


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){
  for(int i = 1;i<32;++i){
    matrix.drawCircle(x_pos, y_pos, i-1, matrix.Color333(r, g, b));
    if (i<16){
    matrix.drawCircle(x_pos, y_pos, i, matrix.Color333(r, g, b));
    }
    matrix.swapBuffers(false);
    matrix.fillRect(0, 0, 32, 16, matrix.Color333(0, 0, 0));
    delay(i+10);
  }
  
}

void loop() {
  unsigned long time = micros(); // Used to track rate
  float sample, value, envelope, beat, thresh;
  unsigned char i;
  int r,g,b,x_pos,y_pos,radius;

  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) {
                  x_pos=rand() % 31;
                  y_pos=rand() % 15;
                  //radius=(rand() % 10)+10;
                  r=rand() % 7;
                  g=rand() % 7;
                  b=rand() % 7;
                  
                  waterdrops (x_pos,y_pos,r,g,b);
                 }
                else {
                  matrix.fillRect(0, 0, 32, 16, matrix.Color333(0, 0, 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
}

How can I realize that two circles are drawn simultaneously, so that no beats are missed?

Basically you can’t.

The best you can do is have the beats trigger an interrupt, then the interrupt service routine will add the beat to a list of things to draw in a FIFO arrangement. Then your normal code will look at this list and if it sees it contains something, remove to top beat information and draw it.