/* soundmems_ripple * * By: Andrew Tuline * * Date: August, 2015 * * Updated: January, 2020 * * Create a ripple from a calculated peak from a sampled microphone * * Note: If you are using a microphone powered by the 3.3V signal, such as the Sparkfun MEMS microphone, then connect 3.3V to the AREF pin. * */ //#define FASTLED_ALLOW_INTERRUPTS 0 // Used for ESP8266. #include // FastLED library. #include "zauberstab.h" // Fixed definitions cannot change on the fly. #define LED_DT LED_PIN // Data pin to connect to the strip. #define LED_CK 11 // Clock pin for WS2801 or APA102. #define COLOR_ORDER GRB // It's GRB for WS2812 and BGR for APA102. #define LED_TYPE WS2812 // Using APA102, WS2812, WS2801. Don't forget to modify LEDS.addLeds to suit. uint8_t squelch = 7; // Anything below this is background noise, so we'll make it '0'. int sample; // Current sample. float sampleAvg = 0; // Smoothed Average. float micLev = 0; // Used to convert returned value to have '0' as minimum. uint8_t maxVol = 11; // Reasonable value for constant volume for 'peak detector', as it won't always trigger. bool samplePeak = 0; // Boolean flag for peak. Responding routine must reset this flag. int max_bright = 255; CRGB leds[NUM_LEDS]; // Ripple variables uint8_t colour; // Ripple colour is randomized. int center = 0; // Center of the current ripple. int step = -1; // -1 is the initializing step. uint8_t myfade = 255; // Starting brightness. #define maxsteps 16 // Case statement wouldn't allow a variable. void setup() { //analogReference(EXTERNAL); // 3.3V reference for analog input. Serial.begin(115200); LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2812B // LEDS.addLeds(leds, NUM_LEDS); // Use this for WS2801 or APA102 FastLED.setBrightness(max_bright); //FastLED.setMaxPowerInVoltsAndMilliamps(5, 500); } // setup() void getSample() { int16_t micIn; // Current sample starts with negative values and large values, which is why it's 16 bit signed. static long peakTime; micIn = analogRead(MIC_PIN); // Poor man's analog Read. micLev = ((micLev * 31) + micIn) / 32; // Smooth it out over the last 32 samples for automatic centering. micIn -= micLev; // Let's center it to 0 now. micIn = abs(micIn); // And get the absolute value of each sample. sample = (micIn <= squelch) ? 0 : (sample + micIn) / 2; // Using a ternary operator, the resultant sample is either 0 or it's a bit smoothed out with the last sample. sampleAvg = ((sampleAvg * 31) + sample) / 32; // Smooth it out over the last 32 samples. if (sample > (sampleAvg+maxVol) && millis() > (peakTime + 50)) { // Poor man's beat detection by seeing if sample > Average + some value. samplePeak = 1; // Then we got a peak, else we don't. Display routines need to reset the samplepeak value in case they miss the trigger. peakTime=millis(); } } // getSample() void ripple() { if (samplePeak == 1) {step = -1; samplePeak = 0; } // If we have a peak, let's reset our ripple. fadeToBlackBy(leds, NUM_LEDS, 64); // 8 bit, 1 = slow, 255 = fast switch (step) { case -1: // Initialize ripple variables. center = random(NUM_LEDS); colour = random8(); // More peaks/s = higher the hue colour. step = 0; break; case 0: leds[center] = CHSV(colour, 255, 255); // Display the first pixel of the ripple. step ++; break; case maxsteps: // At the end of the ripples. // step = -1; break; default: // Middle of the ripples. leds[(center + step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade/step*2); // Simple wrap. leds[(center - step + NUM_LEDS) % NUM_LEDS] += CHSV(colour, 255, myfade/step*2); step ++; // Next step. break; } // switch step } // ripple() void loop() { getSample(); EVERY_N_MILLISECONDS(20) { ripple(); } FastLED.show(); } // loop()