Skip to content

Instantly share code, notes, and snippets.

@samguyer
Created July 7, 2018 01:38
Show Gist options
  • Save samguyer/36d63d6b0b076c82edf0b1589365e49e to your computer and use it in GitHub Desktop.
Save samguyer/36d63d6b0b076c82edf0b1589365e49e to your computer and use it in GitHub Desktop.
Arduino sketch for a simple volume meter
#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