Example_5_Amplitie.ino
1 // SPDX-FileCopyrightText: 2017 Mikey Sklar for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 /* 6 LED VU meter for Arduino and Adafruit NeoPixel LEDs. More info: http://learn.adafruit.com/led-ampli-tie/ 7 8 Hardware requirements: 9 - Most Arduino or Arduino-compatible boards (ATmega 328P or better). 10 - Adafruit Electret Microphone Amplifier (ID: 1063) 11 - Adafruit Flora RGB Smart Pixels (ID: 1260) 12 OR 13 - Adafruit NeoPixel Digital LED strip (ID: 1138) 14 - Optional: battery for portable use (else power through USB or adapter) 15 Software requirements: 16 - Adafruit NeoPixel library 17 18 Connections: 19 - 3.3V to mic amp + 20 - GND to mic amp - 21 - Analog pin to microphone output (configurable below) 22 - Digital pin to LED data input (configurable below) 23 See notes in setup() regarding 5V vs. 3.3V boards - there may be an 24 extra connection to make and one line of code to enable or disable. 25 26 Written by Adafruit Industries. Distributed under the BSD license. 27 This paragraph must be included in any redistribution. 28 */ 29 30 #include <Adafruit_NeoPixel.h> 31 32 #define N_PIXELS 12 // Number of pixels in strand 33 #define MIC_PIN A9 // Microphone is attached to this analog pin 34 #define LED_PIN 6 // NeoPixel LED strand is connected to this pin 35 #define DC_OFFSET 0 // DC offset in mic signal - if unusure, leave 0 36 #define NOISE 10 // Noise/hum/interference in mic signal 37 #define SAMPLES 60 // Length of buffer for dynamic level adjustment 38 #define TOP (N_PIXELS + 2) // Allow dot to go slightly off scale 39 #define PEAK_FALL 40 // Rate of peak falling dot 40 41 byte 42 peak = 0, // Used for falling dot 43 dotCount = 0, // Frame counter for delaying dot-falling speed 44 volCount = 0; // Frame counter for storing past volume data 45 int 46 vol[SAMPLES], // Collection of prior volume samples 47 lvl = 10, // Current "dampened" audio level 48 minLvlAvg = 0, // For dynamic adjustment of graph low & high 49 maxLvlAvg = 512; 50 Adafruit_NeoPixel 51 strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800); 52 53 void setup() { 54 55 // This is only needed on 5V Arduinos (Uno, Leonardo, etc.). 56 // Connect 3.3V to mic AND TO AREF ON ARDUINO and enable this 57 // line. Audio samples are 'cleaner' at 3.3V. 58 // COMMENT OUT THIS LINE FOR 3.3V ARDUINOS (FLORA, ETC.): 59 // analogReference(EXTERNAL); 60 61 memset(vol, 0, sizeof(vol)); 62 strip.begin(); 63 } 64 65 void loop() { 66 uint8_t i; 67 uint16_t minLvl, maxLvl; 68 int n, height; 69 70 71 72 n = analogRead(MIC_PIN); // Raw reading from mic 73 n = abs(n - 512 - DC_OFFSET); // Center on zero 74 n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum 75 lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy) 76 77 // Calculate bar height based on dynamic min/max levels (fixed point): 78 height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg); 79 80 if(height < 0L) height = 0; // Clip output 81 else if(height > TOP) height = TOP; 82 if(height > peak) peak = height; // Keep 'peak' dot at top 83 84 85 // Color pixels based on rainbow gradient 86 for(i=0; i<N_PIXELS; i++) { 87 if(i >= height) strip.setPixelColor(i, 0, 0, 0); 88 else strip.setPixelColor(i,Wheel(map(i,0,strip.numPixels()-1,30,150))); 89 90 } 91 92 93 94 // Draw peak dot 95 if(peak > 0 && peak <= N_PIXELS-1) strip.setPixelColor(peak,Wheel(map(peak,0,strip.numPixels()-1,30,150))); 96 97 strip.show(); // Update strip 98 99 // Every few frames, make the peak pixel drop by 1: 100 101 if(++dotCount >= PEAK_FALL) { //fall rate 102 103 if(peak > 0) peak--; 104 dotCount = 0; 105 } 106 107 108 109 vol[volCount] = n; // Save sample for dynamic leveling 110 if(++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter 111 112 // Get volume range of prior frames 113 minLvl = maxLvl = vol[0]; 114 for(i=1; i<SAMPLES; i++) { 115 if(vol[i] < minLvl) minLvl = vol[i]; 116 else if(vol[i] > maxLvl) maxLvl = vol[i]; 117 } 118 // minLvl and maxLvl indicate the volume range over prior frames, used 119 // for vertically scaling the output graph (so it looks interesting 120 // regardless of volume level). If they're too close together though 121 // (e.g. at very low volume levels) the graph becomes super coarse 122 // and 'jumpy'...so keep some minimum distance between them (this 123 // also lets the graph go to zero when no sound is playing): 124 if((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP; 125 minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels 126 maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average) 127 128 } 129 130 // Input a value 0 to 255 to get a color value. 131 // The colors are a transition r - g - b - back to r. 132 uint32_t Wheel(byte WheelPos) { 133 if(WheelPos < 85) { 134 return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); 135 } else if(WheelPos < 170) { 136 WheelPos -= 85; 137 return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); 138 } else { 139 WheelPos -= 170; 140 return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); 141 } 142 } 143