Created
July 7, 2018 01:38
-
-
Save samguyer/36d63d6b0b076c82edf0b1589365e49e to your computer and use it in GitHub Desktop.
Arduino sketch for a simple volume meter
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
#include <FastLED.h> | |
// Sound O Meter | |
// Visual display of ambient noise volume | |
// Copyright (c) 2017 Sam Guyer | |
#define MAX_BRIGHTNESS 100 | |
#define NOISE 8 | |
// -- Arduino pins | |
#define LED_PIN 25 | |
#define MIC_PIN 12 | |
#define NUM_LEDS 10 | |
// -- LED elements | |
CRGB leds[NUM_LEDS]; | |
// -- Color scheme (green, yellow, red) | |
uint8_t hues[NUM_LEDS]; | |
// ============================================================ | |
// Set up | |
// ------------------------------------------------------------ | |
void setup() | |
{ | |
delay(100); | |
// -- Create the LED entries | |
FastLED.addLeds<WS2812, LED_PIN, RGB>(leds, NUM_LEDS); | |
FastLED.setBrightness(MAX_BRIGHTNESS); | |
// -- Set up the pins | |
pinMode(LED_PIN, OUTPUT); | |
pinMode(MIC_PIN, INPUT); | |
Serial.begin(115200); | |
// -- Set up the color scheme for the volume bar | |
int leds_div_3 = NUM_LEDS/3 + 1; | |
// -- First 1/3 is green (quiet) | |
for (int i = 0; i < leds_div_3; i++) { | |
hues[i] = 28; | |
} | |
// -- Middle third is yellow | |
for (int i = leds_div_3; i < leds_div_3*2; i++) { | |
hues[i] = 68; | |
} | |
// -- Top third is red (loud) | |
for (int i = leds_div_3*2; i < NUM_LEDS; i++) { | |
hues[i] = 97; | |
} | |
} | |
// -- Collect a set of sound samples | |
// These are raw audio input values, so they rise and fall | |
// with the sound waves. The difference between the max and | |
// min values is the volume (amplitude of the wave). | |
#define NUM_SAMPLES 100 | |
int samples[NUM_SAMPLES]; | |
int cur = 0; | |
#define MAX_SHOW 1000 | |
int max_bar = -1; | |
int max_time = 0; | |
void loop() | |
{ | |
// -- Read time | |
unsigned long currentTime = millis(); | |
// -- Read one new value and add it to the samples | |
int raw = analogRead(MIC_PIN); | |
samples[cur] = raw; | |
cur = (cur+1) % NUM_SAMPLES; // Circular buffer | |
// -- Compute the min and max | |
int max = 0; | |
int min = 1024; | |
for (int i = 0; i < NUM_SAMPLES; i++) { | |
int v = samples[i]; | |
if (v > max) max = v; | |
if (v < min) min = v; | |
} | |
// -- Each time the buffer is filled, compute the | |
// volume and display it. | |
if (cur == 0) { | |
int vol = max - min; | |
// -- Ignore "noise" -- anything below a certain volume | |
if (vol < NOISE) vol = 0; | |
// -- Fade all of the LEDs a little bit | |
for (int i = 0; i < NUM_LEDS; i++) { | |
int fade = (i+1) * 5; | |
leds[i].fadeToBlackBy(fade); | |
} | |
/* Alternatively, you can set them all to black | |
for (int i = 0; i < NUM_LEDS; i++) { | |
leds[i] = CRGB::Black; | |
} | |
*/ | |
// -- Display the log of the volume, which is more like | |
// the decibel scale, and the way we actually | |
// perceive volume. This weird calculation is a | |
// cheesy way of computing log base 1.7 | |
int thelog = 0; | |
double upper = 1.0; | |
double base = 1.7; | |
double dvol = (double) vol; | |
while (dvol > upper) { | |
thelog++; | |
upper = upper * base; | |
} | |
// -- Clamp the value in the right range | |
int bar = thelog - 4; | |
if (bar >= NUM_LEDS) bar = NUM_LEDS; | |
if (bar < 0) bar = 0; | |
// -- Turn on the appropriate amount of the volume | |
// display, according to the precomputed color scheme | |
for (int i = 0; i < bar; i++) { | |
CHSV hsv(hues[i], 255, 255); | |
hsv2rgb_rainbow( hsv, leds[i]); | |
} | |
// -- This code keeps a high-water mark in the bar: it | |
// maintains the max volume a little longer than the | |
// other LEDs, just like a real equalizer. | |
if (bar > max_bar) { | |
max_bar = bar; | |
max_time = currentTime; | |
} | |
int max_since = currentTime - max_time; | |
if (max_bar > bar && max_bar > 4 && (max_since < MAX_SHOW)) { | |
int bright = 255; | |
if (max_since > 500) { | |
bright = map(max_since-1000, 0, MAX_SHOW, 255, 0); | |
} | |
CHSV hsv(hues[max_bar], 255, bright); | |
hsv2rgb_rainbow( hsv, leds[max_bar]); | |
} | |
if (max_since >= MAX_SHOW) { | |
max_bar = -1; | |
} | |
// -- Last step: show the LEDS | |
FastLED.show(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment