Skip to content

Instantly share code, notes, and snippets.

@damanm24
Created September 16, 2019 19:30
Show Gist options
  • Save damanm24/104506e19c067b5edff84c0261a27427 to your computer and use it in GitHub Desktop.
Save damanm24/104506e19c067b5edff84c0261a27427 to your computer and use it in GitHub Desktop.
music_reactive
/**
* LED Music Visualizer
* by Daman Mulye
* adapted from: https://github.com/hansjny/Natural-Nerd/tree/master/SoundReactive2
* using the FastLED library: http://fastled.io/
* June 9, 2019
*/
#include <FastLED.h>
#include "reactive_commons.h"
#define LED_PIN 6
#define NUM_LEDS 150
#define MIC_LOW 250
#define MIC_HIGH 450
#define SAMPLE_SIZE 10
#define LONG_TERM_SAMPLES 150
#define BUFFER_DEVIATION 400
#define BUFFER_SIZE 3
CRGB leds[NUM_LEDS];
struct averageCounter *samples;
struct averageCounter *longTermSamples;
struct averageCounter* sanityBuffer;
int reactiveCenter = 9;
float globalHue;
float globalBrightness = 255;
int hueOffset = 120;
float fadeScale = 1.1;
float hueIncrement = 1;
bool flag = false;
unsigned long lastUpdate = millis();
void setup() {
Serial.begin(9600);
globalHue = 0;
samples = new averageCounter(SAMPLE_SIZE);
longTermSamples = new averageCounter(LONG_TERM_SAMPLES);
sanityBuffer = new averageCounter(BUFFER_SIZE);
while (sanityBuffer->setSample(250) == true) {}
while (longTermSamples->setSample(200) == true) {}
FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
}
void loop() {
soundReactive(analogRead(0));
}
void soundReactive(int analogRaw) {
int sanityValue = sanityBuffer->computeAverage();
if (!(abs(analogRaw - sanityValue) > BUFFER_DEVIATION)) {
sanityBuffer->setSample(analogRaw);
}
analogRaw = fscale(MIC_LOW, MIC_HIGH, MIC_LOW, MIC_HIGH, analogRaw, 0.99);
if (samples->setSample(analogRaw))
return;
uint16_t longTermAverage = longTermSamples->computeAverage();
uint16_t useVal = samples->computeAverage();
longTermSamples->setSample(useVal);
//Incrementing the global hue creates the rainbow scrolling effect
int diff = (useVal - longTermAverage);
if (diff > 5)
{
globalHue += hueIncrement;
}
else if (diff < -5)
{
globalHue -= hueIncrement;
}
//Determines how many LEDS to light up from the average of previous analog values
int curshow = fscale(MIC_LOW, MIC_HIGH, 0.0, (float)NUM_LEDS, (float)useVal, 0);
//Scales down the number of LEDS from 0-100 to 0-20
int fixedShow = map(curshow, 0, 100, 0, 10);
fixedShow += 2;
for (int i = 0; i < 7; i++) {
int k = reactiveCenter + (20 * i);
k = k % 140;
//Handles the left half of the LEDs from the center
for (int j = 0; j <= 10; j++) {
int index = k - j;
if (index < 0) {
index += 140;
}
//If statementcontrols whether the LEDs should be full brightness or fade on downbeats
if (j < fixedShow) {
leds[index] = CHSV(globalHue + hueOffset + ((index) * 2), 255, 255);
} else {
leds[index] = CRGB(leds[index].r / fadeScale, leds[index].g / fadeScale, leds[index].b / fadeScale);
}
}
//Handles the right half of the LEDS from the center
for (int j = 0; j <= 10; j++) {
int index = (k + j) % 140;
if (j < fixedShow) {
leds[index] = CHSV(globalHue + hueOffset + ((index) * 2), 255, 255);
} else {
leds[index] = CRGB(leds[index].r / fadeScale, leds[index].g / fadeScale, leds[index].b / fadeScale);
}
}
}
delay(5);
FastLED.show();
}
//Function that maps from one range of values to another
float fscale(float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve) {
float OriginalRange = 0;
float NewRange = 0;
float zeroRefCurVal = 0;
float normalizedCurVal = 0;
float rangedValue = 0;
boolean invFlag = 0;
// condition curve parameter
// limit range
if (curve > 10)
curve = 10;
if (curve < -10)
curve = -10;
curve = (curve * -.1); // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output
curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function
// Check for out of range inputValues
if (inputValue < originalMin) {
inputValue = originalMin;
}
if (inputValue > originalMax) {
inputValue = originalMax;
}
// Zero Refference the values
OriginalRange = originalMax - originalMin;
if (newEnd > newBegin) {
NewRange = newEnd - newBegin;
} else {
NewRange = newBegin - newEnd;
invFlag = 1;
}
zeroRefCurVal = inputValue - originalMin;
normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float
// Check for originalMin > originalMax - the math for all other cases i.e. negative numbers seems to work out fine
if (originalMin > originalMax) {
return 0;
}
if (invFlag == 0) {
rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;
} else {
// invert the ranges
rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);
}
return rangedValue;
}
struct averageCounter{
uint16_t *samples;
uint16_t sample_size;
uint8_t counter;
averageCounter(uint16_t size) {
counter = 0;
sample_size = size;
samples = (uint16_t*) malloc(sizeof(uint16_t) * sample_size);
}
bool setSample(uint16_t val) {
if (counter < sample_size) {
samples[counter++] = val;
return true;
}
else {
counter = 0;
return false;
}
}
int computeAverage() {
int accumulator = 0;
for (int i = 0; i < sample_size; i++) {
accumulator += samples[i];
}
return (int)(accumulator / sample_size);
}
};
struct heartbeat_message {
uint32_t client_id;
uint32_t chk;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment