#include <FastLED.h>
#define LED_PIN 5
#define LED_PIN_2 17
#define MIC_PIN 35
#define POT_PIN 34
#define BRIGHTNESS_POT_PIN 27
#define BUTTON_PIN 2
#define NUM_LEDS 360
#define LED_TYPE WS2812B
#define COLOR_ORDER GRB
#define MAX_BRIGHTNESS 255
#define MIN_BRIGHTNESS 20
#define FRAMES_PER_SECOND 60
CRGB leds[NUM_LEDS];
CRGB leds2[NUM_LEDS];
int animationMode = 0;
const int NUM_MODES = 6;
int center = NUM_LEDS / 2;
uint8_t currentBrightness = 200;
int micValue = 0;
int micBaseline = 2048;
int threshold = 512;
float soundLevel = 0;
float soundLevelFiltered = 0;
void setup() {
delay(1000);
Serial.begin(115200);
Serial.println("ESP32 Sound Reactive LED System Starting...");
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.addLeds<LED_TYPE, LED_PIN_2, COLOR_ORDER>(leds2, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(currentBrightness);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(MIC_PIN, INPUT);
pinMode(POT_PIN, INPUT);
pinMode(BRIGHTNESS_POT_PIN, INPUT);
for(int i = 0; i < 3; i++) {
fill_solid(leds, NUM_LEDS, CRGB::White);
fill_solid(leds2, NUM_LEDS, CRGB::White);
FastLED.setBrightness(50);
FastLED.show();
delay(100);
FastLED.clear();
FastLED.show();
delay(100);
}
analogReadResolution(12);
analogSetAttenuation(ADC_11db);
calibrateMicrophone();
randomSeed(esp_random());
FastLED.clear();
FastLED.show();
Serial.println("System Ready!");
}
void loop() {
readSound();
readPotentiometer();
readBrightnessPotentiometer();
checkButton();
switch(animationMode) {
case 0:
symmetricVU();
break;
case 1:
symmetricPulse();
break;
case 2:
symmetricRipple();
break;
case 3:
symmetricFireworks();
break;
case 4:
symmetricWave();
break;
case 5:
symmetricSparkle();
break;
}
FastLED.show();
FastLED.delay(1000 / FRAMES_PER_SECOND);
}
void calibrateMicrophone() {
long sum = 0;
int samples = 100;
for (int i = 0; i < samples; i++) {
int reading = analogRead(MIC_PIN);
sum += reading;
if (reading < micMin) micMin = reading;
if (reading > micMax) micMax = reading;
delay(1);
}
micBaseline = sum / samples;
Serial.print("Mic calibrated - Baseline: ");
Serial.println(micBaseline);
}
void readSound() {
micValue = analogRead(MIC_PIN);
if (micValue < micMin) micMin = micValue;
if (micValue > micMax) micMax = micValue;
int range = micMax - micMin;
if (range < 100) range = 100;
int deviation = abs(micValue - micBaseline);
soundLevel = (float)deviation / (float)(range / 2);
soundLevel = constrain(soundLevel, 0, 1);
float sensitivity = map(threshold, 100, 3000, 200, 50) / 100.0;
soundLevel = soundLevel * sensitivity;
soundLevel = constrain(soundLevel, 0, 1);
soundLevelFiltered = (soundLevelFiltered * soundSmoothingFactor) +
(soundLevel * (1.0 - soundSmoothingFactor));
}
void readPotentiometer() {
int potValue = analogRead(POT_PIN);
threshold = map(potValue, 0, 4095, 3000, 100);
}
void readBrightnessPotentiometer() {
int brightPotValue = analogRead(BRIGHTNESS_POT_PIN);
if (brightPotValue < 100) {
currentBrightness = MIN_BRIGHTNESS;
} else if (brightPotValue > 3995) {
currentBrightness = MAX_BRIGHTNESS;
} else {
currentBrightness = map(brightPotValue, 100, 3995, MIN_BRIGHTNESS, MAX_BRIGHTNESS);
}
FastLED.setBrightness(currentBrightness);
}
void checkButton() {
bool buttonState = digitalRead(BUTTON_PIN);
if (buttonState == LOW && lastButtonState == HIGH) {
if (millis() - lastButtonPress > debounceDelay) {
buttonPressed = true;
lastButtonPress = millis();
animationMode = (animationMode + 1) % NUM_MODES;
FastLED.clear();
FastLED.show();
Serial.println("Mode changed");
}
}
if (buttonState == HIGH && lastButtonState == LOW) {
buttonPressed = false;
}
lastButtonState = buttonState;
}
void symmetricVU() {
fadeToBlackBy(leds, NUM_LEDS, 60);
fadeToBlackBy(leds2, NUM_LEDS, 60);
if (soundLevelFiltered > 0.05) {
int level = map(soundLevelFiltered * 1000, 50, 1000, 1, center);
level = constrain(level, 0, center);
for (int i = 0; i < level; i++) {
int leftPos = center - i - 1;
int rightPos = center + i;
if (leftPos >= 0 && rightPos < NUM_LEDS) {
uint8_t brightness = 255 * soundLevelFiltered;
brightness = constrain(brightness, 50, 255);
CRGB color = CRGB(brightness, brightness, brightness);
leds[leftPos] = color;
leds[rightPos] = color;
leds2[leftPos] = color;
leds2[rightPos] = color;
}
}
}
}
void symmetricPulse() {
fadeToBlackBy(leds, NUM_LEDS, 30);
fadeToBlackBy(leds2, NUM_LEDS, 30);
if (soundLevelFiltered > 0.05) {
int pulseWidth = map(soundLevelFiltered * 1000, 50, 1000, 3, 40);
for (int i = 0; i < pulseWidth; i++) {
int leftPos = center - pos - i;
int rightPos = center + pos + i;
if (leftPos >= 0 && leftPos < NUM_LEDS && rightPos >= 0 && rightPos < NUM_LEDS) {
uint8_t brightness = map(i, 0, pulseWidth, 255, 50);
brightness = brightness * soundLevelFiltered;
CRGB color = CRGB(brightness, brightness, brightness);
leds[leftPos] = color;
leds[rightPos] = color;
leds2[leftPos] = color;
leds2[rightPos] = color;
}
}
pos += map(soundLevelFiltered * 100, 0, 100, 1, 4);
if (pos >= center) {
pos = 0;
}
} else {
if (pos > 0) {
pos--;
}
}
}
void symmetricRipple() {
fadeToBlackBy(leds, NUM_LEDS, 15);
fadeToBlackBy(leds2, NUM_LEDS, 15);
static float ripplePos[10] = {0};
static uint8_t rippleBrightness[10] = {0};
static bool rippleActive[10] = {false};
static unsigned long lastRippleTrigger = 0;
if ((soundLevelFiltered > 0.15 || peakLevel > 100) &&
(millis() - lastRippleTrigger > 100)) {
for (int i = 0; i < 10; i++) {
if (!rippleActive[i]) {
rippleActive[i] = true;
ripplePos[i] = 0;
rippleBrightness[i] = 150 + (soundLevelFiltered * 105);
lastRippleTrigger = millis();
break;
}
}
}
for (int i = 0; i < 10; i++) {
if (rippleActive[i]) {
int pos = (int)ripplePos[i];
int leftPos = center - pos;
int rightPos = center + pos - 1;
if (leftPos >= 0 && rightPos < NUM_LEDS) {
uint8_t brightness = map(pos, 0, center, rippleBrightness[i], 0);
brightness = brightness * (0.5 + soundLevelFiltered * 0.5);
if (brightness > 20) {
CRGB color = CRGB(brightness, brightness, brightness);
leds[leftPos] = color;
leds[rightPos] = color;
leds2[leftPos] = color;
leds2[rightPos] = color;
}
}
ripplePos[i] += 2.0 + (soundLevelFiltered * 4);
if (ripplePos[i] >= center) {
rippleActive[i] = false;
}
}
}
}
void symmetricFireworks() {
fadeToBlackBy(leds, NUM_LEDS, 20);
fadeToBlackBy(leds2, NUM_LEDS, 20);
static int sparkPos[20];
static int sparkVel[20];
static uint8_t sparkBrightness[20];
static bool sparkActive[20] = {false};
static unsigned long lastFirework = 0;
if ((soundLevelFiltered > 0.2 || peakLevel > 150) &&
(millis() - lastFirework > 50)) {
int sparksToLaunch = map(soundLevelFiltered * 150, 20, 100, 1, 3);
for (int j = 0; j < sparksToLaunch; j++) {
for (int i = 0; i < 20; i++) {
if (!sparkActive[i]) {
sparkActive[i] = true;
sparkPos[i] = 0;
sparkVel[i] = random(3, 10);
sparkBrightness[i] = 255;
lastFirework = millis();
break;
}
}
}
}
for (int i = 0; i < 20; i++) {
if (sparkActive[i]) {
int leftPos = center - sparkPos[i];
int rightPos = center + sparkPos[i] - 1;
if (leftPos >= 0 && rightPos < NUM_LEDS) {
uint8_t brightness = sparkBrightness[i];
CRGB color = CRGB(brightness, brightness, brightness);
leds[leftPos] = color;
leds[rightPos] = color;
leds2[leftPos] = color;
leds2[rightPos] = color;
}
sparkPos[i] += sparkVel[i];
sparkVel[i] = max(1, sparkVel[i] - 1);
if (sparkPos[i] < center / 2) {
sparkBrightness[i] = 255;
} else {
sparkBrightness[i] = map(sparkPos[i], center/2, center, 255, 30);
}
if (sparkPos[i] >= center) {
sparkActive[i] = false;
}
}
}
}
void symmetricWave() {
static float phase = 0;
for (int i = 0; i < center; i++) {
float wave = (sin((i * 0.1) + phase) + 1) * 0.5;
wave = wave * (0.2 + soundLevelFiltered * 1.8);
wave = constrain(wave, 0, 1);
uint8_t brightness = wave * 255;
uint8_t saturation = 255 - (wave * 100);
int leftPos = center - i - 1;
int rightPos = center + i;
if (leftPos >= 0 && rightPos < NUM_LEDS) {
CHSV waveColor = CHSV(hue + (i * 2), saturation, brightness);
leds[leftPos] = waveColor;
leds[rightPos] = waveColor;
leds2[leftPos] = waveColor;
leds2[rightPos] = waveColor;
}
}
phase += (0.02 + soundLevelFiltered * 0.3);
}
void symmetricSparkle() {
fadeToBlackBy(leds, NUM_LEDS, 10);
fadeToBlackBy(leds2, NUM_LEDS, 10);
int baseSparkles = 8;
int soundSparkles = soundLevelFiltered * 15;
int numSparkles = baseSparkles + soundSparkles;
for (int i = 0; i < numSparkles; i++) {
int pos = random(0, center);
int leftPos = center - pos - 1;
int rightPos = center + pos;
if (leftPos >= 0 && rightPos < NUM_LEDS) {
uint8_t baseBrightness = random(100, 255);
uint8_t sparkleBrightness = baseBrightness * (0.5 + soundLevelFiltered * 0.5);
sparkleBrightness = constrain(sparkleBrightness, 50, 255);
CRGB sparkleColor = CRGB(sparkleBrightness, sparkleBrightness, sparkleBrightness);
leds[leftPos] = sparkleColor;
leds[rightPos] = sparkleColor;
leds2[leftPos] = sparkleColor;
leds2[rightPos] = sparkleColor;
}
}
int glowSize = 3 + (soundLevelFiltered * 4);
for (int i = 0; i < glowSize; i++) {
int leftPos = center - i - 1;
int rightPos = center + i;
if (leftPos >= 0 && rightPos < NUM_LEDS) {
uint8_t glowBrightness = 30 + (soundLevelFiltered * 50);
glowBrightness = glowBrightness * (1.0 - (float)i / glowSize);
CRGB centerColor = CRGB(glowBrightness, glowBrightness, glowBrightness);
leds[leftPos] += centerColor;
leds[rightPos] += centerColor;
leds2[leftPos] += centerColor;
leds2[rightPos] += centerColor;
}
}
}