From c79abb1be92ae1bca8c36efa7bc2eab20de7693e Mon Sep 17 00:00:00 2001 From: Kai Vogelgesang Date: Sat, 28 Aug 2021 23:35:43 +0200 Subject: [PATCH] Add peak detection script --- microcontroller/peak_detection.ino | 106 +++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 microcontroller/peak_detection.ino diff --git a/microcontroller/peak_detection.ino b/microcontroller/peak_detection.ino new file mode 100644 index 0000000..dbdffd2 --- /dev/null +++ b/microcontroller/peak_detection.ino @@ -0,0 +1,106 @@ +// Arduino Beat Detector By Damian Peckett 2015 +// License: Public Domain. + +// 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 + +bool beat_bool=true; + +void setup() { + Serial.begin(9600); + // Set ADC to 77khz, max for 10bit + sbi(ADCSRA,ADPS2); + cbi(ADCSRA,ADPS1); + cbi(ADCSRA,ADPS0); + + //The pin with the LED + // pinMode(2, OUTPUT); +} + +// 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) / 3.f; // change here to values close to 2, to adapt for stronger or weeker sources of line level audio + + + 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]; +} + +void loop() { + unsigned long time = micros(); // Used to track rate + float sample, value, envelope, beat, thresh; + unsigned char i; + + for(i = 0;;++i){ + // Read ADC and center so +-512 + sample = (float)analogRead(1)-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(1); + + // If we are above threshold, light up LED + if(beat > thresh) { + if(beat_bool==true){ + //digitalWrite(2, HIGH); + Serial.println("beat"); + beat_bool=false; + } + } + else { + beat_bool=true; + Serial.println("-");// digitalWrite(2, LOW); + } + + //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()); + } +}