atuline

beat_detector.ino

Feb 19th, 2021 (edited)
1,575
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.06 KB | None | 0 0
  1. /*
  2.  * Arduino Beat Detector by: Damian Peckett 2015
  3.  *
  4.  * Adapted for FastLED by: Andrew Tuline 2021
  5.  *
  6.  * Location: https://pastebin.com/Sh7JFf7K
  7.  * https://www.youtube.com/watch?v=pbqkeJAcPck
  8.  *
  9.  * Please refer to Damian Peckett's article (with code) for more information on this project:
  10.  *
  11.  * https://damian.pecke.tt/2015/03/02/beat-detection-on-the-arduino.html
  12.  *
  13.  *
  14.  * This version was created with an ESP32, 30 WS2812 LED's and a MAX9814 @40db gain.
  15.  *
  16.  * A value called 'thresh', is adjustable and is used for beat threshold detection. It's  
  17.  * currently hard coded, although you could add a potentiometer for adjustment, or as
  18.  * Damian mentions, add some form of automatic gain control. I've added auto-zeroing for the
  19.  * data samples. As for Damian's filtering routines, that's beyond Andrew's paygrade.
  20.  *
  21.  * The FastLED component adds rotating Perlin Noise with continuously changing palettes.
  22.  *
  23.  * Andrew's modification:
  24.  *
  25.  *
  26.  * Here's a version implemented by someone in fixed point that should improve performance. According
  27.  * to the author, "no part of this project is currently released under any open source license", so I'm
  28.  * not touching it:
  29.  *
  30.  * https://github.com/ben-xo/vu2
  31.  *
  32.  */
  33.  
  34.  
  35.  
  36. #include <FastLED.h>
  37.  
  38. #define SAMPLEPERIODUS 200                                    // Our global sample rate, 5000hz (or 200 microseconds).
  39.  
  40. #define MIC_PIN 36
  41.  
  42. #define LED_DT 2                                              // Data pin to connect to the strip.
  43. #define COLOR_ORDER GRB                                       // It's GRB for WS2812 and BGR for APA102.
  44. #define LED_TYPE WS2812                                       // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit.
  45. #define NUM_LEDS 30
  46.  
  47. uint8_t max_bright = 64;                                      // Overall brightness.
  48.  
  49. struct CRGB leds[NUM_LEDS];                                   // Initialize our LED array.
  50. CRGBPalette16 currentPalette = RainbowColors_p;
  51. CRGBPalette16 targetPalette;
  52.  
  53.  
  54. void setup() {
  55.   Serial.begin(115200);
  56.   pinMode(LED_BUILTIN, OUTPUT);
  57.   LEDS.addLeds<LED_TYPE, LED_DT, COLOR_ORDER>(leds, NUM_LEDS);
  58.   FastLED.setBrightness(max_bright);
  59. }
  60.  
  61.  
  62. // 20 - 200hz Single Pole Bandpass IIR Filter
  63. float bassFilter(float sample) {
  64.   static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
  65.   xv[0] = xv[1]; xv[1] = xv[2];
  66.   xv[2] = sample / 9.1f;
  67.   yv[0] = yv[1]; yv[1] = yv[2];
  68.   yv[2] = (xv[2] - xv[0]) + (-0.7960060012f * yv[0]) + (1.7903124146f * yv[1]);
  69.   return yv[2];
  70. }
  71.  
  72.  
  73. // 10hz Single Pole Lowpass IIR Filter
  74. float envelopeFilter(float sample) {
  75.   static float xv[2] = {0,0}, yv[2] = {0,0};
  76.   xv[0] = xv[1];
  77.   xv[1] = sample / 160.f;
  78.   yv[0] = yv[1];
  79.   yv[1] = (xv[0] + xv[1]) + (0.9875119299f * yv[0]);
  80.   return yv[1];
  81. }
  82.  
  83.  
  84. // 1.7 - 3.0hz Single Pole Bandpass IIR Filter
  85. float beatFilter(float sample) {
  86.   static float xv[3] = {0,0,0}, yv[3] = {0,0,0};
  87.   xv[0] = xv[1]; xv[1] = xv[2];
  88.   xv[2] = sample / 7.015f;
  89.   yv[0] = yv[1]; yv[1] = yv[2];
  90.   yv[2] = (xv[2] - xv[0]) + (-0.7169861741f * yv[0]) + (1.4453653501f * yv[1]);
  91.   return yv[2];
  92. }
  93.  
  94.  
  95.  
  96. void loop() {
  97.  
  98.   unsigned long time = micros();          // Used to track rate
  99.   float sample, value, envelope, beat, thresh, micLev;
  100.    
  101.   for (uint8_t i = 0; ; ++i) {
  102.  
  103.    
  104.     sample = (float)analogRead(MIC_PIN);             // Sample the pin.
  105.     micLev = ((micLev*31)+sample)/32;                // Smooth it out over the last 32 samples for automatic centering.
  106.     sample -= micLev;                                // Let's center the sample it to 0.
  107.  
  108.     value = bassFilter(sample);
  109.     value = abs(value);                             // And get the absolute value of each sample.
  110.    
  111.     envelope = envelopeFilter(value);     // It's a filter of some kind. . .
  112.  
  113.     if (i == 200) {                       // Every 200 samples (25hz) filter the envelope
  114.       beat = beatFilter(envelope);        // Filter out repeating bass sounds 100 - 180bpm
  115.       thresh = 0.02f * 75.;              // Use ~350 for ESP32 and about 75 for UNO/Nano, or use potentiometer and map the range.
  116.    
  117.       if(beat > thresh) {                 // Test to see if we have a beat.
  118.         digitalWrite(LED_BUILTIN, LOW);   // We have a beat.
  119.        
  120.         int strt = random8(NUM_LEDS/2);         // Start of FastLED stuff. Get a starting point.
  121.         int ende = strt + random8(NUM_LEDS/2);  // And and end point.
  122.         for(int i = strt; i < ende; i++) {
  123.           uint8_t index = inoise8(i*30, millis()+i*30);   // Make Perlin noise beteween those points.
  124.           leds[i] = ColorFromPalette(currentPalette, index, 255, LINEARBLEND);   // And display it with palettes.
  125.         }
  126.       } else {
  127.         digitalWrite(LED_BUILTIN, HIGH);     // We don't have a beat.
  128.       }
  129.       i = 0;                      // Reset sample counter.
  130.     }
  131.  
  132.     EVERY_N_SECONDS(5) {                                       // Change the target palette to a random one every 5 seconds.
  133.       uint8_t baseC = random8();                        // You can use this as a baseline colour if you want similar hues in the next line.
  134.       targetPalette = CRGBPalette16(CHSV(baseC + random8(32), 255, random8(128, 255)),
  135.                                     CHSV(baseC + random8(64), 255, random8(128, 255)),
  136.                                     CHSV(baseC + random8(64), 192, random8(128, 255)),
  137.                                     CHSV(baseC + random8(),   255, random8(128, 255)));
  138.     }
  139.  
  140.     EVERY_N_MILLISECONDS(50) {                                // Awesome palette transitioning.
  141.       uint8_t maxChanges = 24;
  142.       nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges);
  143.     }
  144.  
  145.     EVERY_N_MILLIS(50){
  146.       fadeToBlackBy(leds, NUM_LEDS, 64);                       // Fade the LED's
  147.       FastLED.show();                                          // We can't show too often, or things break.
  148.     }
  149.  
  150.     for (unsigned long up = time+SAMPLEPERIODUS; time > 20 && time < up; time = micros()){  }    // Consume excess clock cycles, to keep at 5000 hz.
  151.    
  152.   } // for i
  153. } // loop()
  154.  
Add Comment
Please, Sign In to add comment