Created
June 9, 2019 20:19
-
-
Save damanm24/dfd5dffd675de4ff1bfe0b5aa24b7341 to your computer and use it in GitHub Desktop.
Music Reactive LED lights
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 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 200 | |
#define MIC_HIGH 800 | |
#define SAMPLE_SIZE 20 | |
#define LONG_TERM_SAMPLES 250 | |
#define BUFFER_DEVIATION 800 | |
#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 = 0.7; | |
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) | |
{ | |
if (globalHue > 2) | |
{ | |
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, 20); | |
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; | |
} |
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
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