Last active
August 27, 2019 10:01
-
-
Save podstava/aad4e1259ee325b007789af35e66c6d3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
LED audio inputVisualizer for ES8266 | |
Hardware requirements: | |
- ESP8266 or any compatible controller. | |
- Microphone with amplifier | |
- LED strip ws2812b | |
- Optional: battery for portable use (else power through USB or adapter) | |
Software requirements: | |
- Adafruit NeoPixel library | |
Part of code was taken from adafruit and modified by myself(Podstava systems) | |
*/ | |
#include <Adafruit_NeoPixel.h> | |
#define N_PIXELS 52 // Number of pixels in strand | |
#define MIC_PIN A0 // Microphone is attached to this analog pin | |
#define LED_PIN 7 // LED strand is connected to this pin | |
#define DC_OFFSET 0 // DC offset in mic signal - if unusure, leave 0 | |
#define NOISE 10 // Noise/hum/interference in mic signal | |
#define SAMPLES 60 // Length of buffer for dynamic level adjustment | |
#define TOP (N_PIXELS + 2) // Allow dot to go slightly off scale | |
#define PEAK_FALL 4 // Rate of peak falling dot | |
byte | |
peak = 0, // Used for falling dot | |
dotCount = 0, // Frame counter for delaying dot-falling speed | |
volCount = 0; // Frame counter for storing past volume data | |
int | |
vol[SAMPLES], // Collection of prior volume samples | |
lvl = 10, // Current "dampened" audio level | |
minLvlAvg = 0, // For dynamic adjustment of graph low & high | |
maxLvlAvg = 512; | |
Adafruit_NeoPixel | |
strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800); | |
void setup() { | |
Serial.begin(9600); | |
memset(vol, 0, sizeof(vol)); | |
strip.begin(); | |
} | |
void loop() { | |
uint8_t i; | |
uint16_t minLvl, maxLvl; | |
int n, height; | |
n = analogRead(MIC_PIN); // Raw reading from mic | |
Serial.print("sensor = "); | |
Serial.print(n); | |
n = abs(n - 512 - DC_OFFSET); // Center on zero | |
n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum | |
lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy) | |
// Calculate bar height based on dynamic min/max levels (fixed point): | |
height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg); | |
if (height < 0L) height = 0; // Clip output | |
else if (height > TOP) height = TOP; | |
if (height > peak) peak = height; // Keep 'peak' dot at top | |
Serial.print("\t output = "); | |
Serial.println(n); | |
// Color pixels based on rainbow gradient | |
for (i = 0; i < N_PIXELS; i++) { | |
if (i >= height) strip.setPixelColor(i, 0, 0, 0); | |
else strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() - 1, 30, 150))); | |
} | |
// Draw peak dot | |
if (peak > 0 && peak <= N_PIXELS - 1) strip.setPixelColor(peak, Wheel(map(peak, 0, strip.numPixels() - 1, 30, 150))); | |
strip.show(); // Update strip | |
// Every few frames, make the peak pixel drop by 1: | |
if (++dotCount >= PEAK_FALL) { //fall rate | |
if (peak > 0) peak--; | |
dotCount = 0; | |
} | |
vol[volCount] = n; // Save sample for dynamic leveling | |
if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter | |
// Get volume range of prior frames | |
minLvl = maxLvl = vol[0]; | |
for (i = 1; i < SAMPLES; i++) { | |
if (vol[i] < minLvl) minLvl = vol[i]; | |
else if (vol[i] > maxLvl) maxLvl = vol[i]; | |
} | |
// minLvl and maxLvl indicate the volume range over prior frames, used | |
// for vertically scaling the output graph (so it looks interesting | |
// regardless of volume level). If they're too close together though | |
// (e.g. at very low volume levels) the graph becomes super coarse | |
// and 'jumpy'...so keep some minimum distance between them (this | |
// also lets the graph go to zero when no sound is playing): | |
if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP; | |
minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels | |
maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average) | |
} | |
// Input a value 0 to 255 to get a color value. | |
// The colors are a transition r - g - b - back to r. | |
uint32_t Wheel(byte WheelPos) { | |
if (WheelPos < 85) { | |
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0); | |
} else if (WheelPos < 170) { | |
WheelPos -= 85; | |
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3); | |
} else { | |
WheelPos -= 170; | |
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment