/* sound_wave * * By: Andrew Tuline * * Date: February, 2017 * * Basic code to read from the Sparkfun INMP401 microphone, and create waves based on sampled input. This does NOT include sensitivity adjustment. * * My hardware setup: * * Arduino Nano & Addressable LED strips * - Powered by USB power bank * - APA102 or WS2812 data connected to pin 12. * - APA102 clock connected to pin 11. * - 5V on APA102 or WS2812 connected to 5V on Nano (good for short strips). * - Gnd to Gnd on Nano. * * * Sparkfun MEMS microphone * - Vcc on microphone is connected to 3.3V on Nano. * - AREF on Nano connected to 3.3V on Nano. * - Mic out connected to A5. * - Gnd to Gnd on Nano. * * 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" 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 sampleAgc, multAgc; uint8_t targetAgc = 60; // This is our setPoint at 20% of max for the adjusted output. // 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. struct CRGB leds[NUM_LEDS]; // Initialize our LED array. int max_bright = 255; CRGBPalette16 currentPalette = OceanColors_p; CRGBPalette16 targetPalette = OceanColors_p; TBlendType currentBlending = LINEARBLEND; // NOBLEND or LINEARBLEND void setup() { //analogReference(EXTERNAL); // 3.3V reference for analog input. Serial.begin(115200); // Initialize serial port for debugging. delay(1000); // Soft startup to ease the flow of electrons. 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); // FastLED Power management set at 5V, 500mA. } // 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)>>2; // 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 agcAvg() { // A simple averaging multiplier to automatically adjust sound sensitivity. multAgc = (sampleAvg < 1) ? targetAgc : targetAgc / sampleAvg; // Make the multiplier so that sampleAvg * multiplier = setpoint sampleAgc = sample * multAgc; if (sampleAgc > 255) sampleAgc = 255; //------------ Oscilloscope output --------------------------- Serial.print(targetAgc); Serial.print(" "); Serial.print(multAgc); Serial.print(" "); Serial.print(sampleAgc); Serial.print(" "); Serial.print(micLev); Serial.print(" "); Serial.print(sample); Serial.println(" "); // Serial.print(sampleAvg); Serial.print(" "); // Serial.print(samplePeak); Serial.print(" "); samplePeak = 0; // Serial.print(100); Serial.print(" "); // Serial.print(0); Serial.print(" "); // Serial.println(" "); } // agcAvg() void sndwave() { leds[NUM_LEDS/2] = ColorFromPalette(currentPalette, sampleAgc, sampleAgc, currentBlending); // Put the sample into the center for (int i = NUM_LEDS - 1; i > NUM_LEDS/2; i--) { //move to the left // Copy to the left, and let the fade do the rest. leds[i] = leds[i - 1]; } for (int i = 0; i < NUM_LEDS/2; i++) { // move to the right // Copy to the right, and let the fade to the rest. leds[i] = leds[i + 1]; } } // sndwave() void loop() { EVERY_N_SECONDS(5) { // Change the palette every 5 seconds. for (int i = 0; i < 16; i++) { targetPalette[i] = CHSV(random8(), 255, 255); } } EVERY_N_MILLISECONDS(100) { // AWESOME palette blending capability once they do change. uint8_t maxChanges = 24; nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); } EVERY_N_MILLIS_I(thistimer,20) { // For fun, let's make the animation have a variable rate. uint8_t timeval = beatsin8(10,20,50); // Use a sinewave for the line below. Could also use peak/beat detection. thistimer.setPeriod(timeval); // Allows you to change how often this routine runs. fadeToBlackBy(leds, NUM_LEDS, 16); // 1 = slow, 255 = fast fade. Depending on the faderate, the LED's further away will fade out. getSample(); agcAvg(); sndwave(); } FastLED.show(); } // loop()