// Do not hook up LED pixels directly to the ESP32
// LEDs draw too much current and will break the ESP32
// LEDs need direct power supply input
// All GNDs need to be connected for LEDs to work
#include <Adafruit_NeoPixel.h>
#include <arduinoFFT.h>
// --- Microphone Setup (MAX9814 Analog Input) ---
#define MIC_PIN 34 // Analog pin connected to the microphone output (MAX9814)
// --- LED Strip Setup ---
#define LED_PIN 15 // Data pin connected to the LED strip
#define NUM_LEDS 20 // Number of LEDs in your strip. Increased for finer resolution
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
// --- FFT Setup ---
#define SAMPLES 128 // Must be a power of 2
#define SAMPLING_FREQUENCY 10000.0 // Use a double literal (add .0)
// --- Global declaration of vReal and vImag ---
float vReal[SAMPLES];
float vImag[SAMPLES];
// Declare FFT object with explicit <float> template
ArduinoFFT<float> FFT = ArduinoFFT<float>(vReal, vImag, SAMPLES, SAMPLING_FREQUENCY);
unsigned long microseconds;
// --- Smoothing Setup (for averaging over time) ---
#define AVERAGE_SAMPLES 4
int magnitudeHistory[NUM_LEDS][AVERAGE_SAMPLES] = {0};
int historyIndex[NUM_LEDS] = {0};
// --- Sensitivity Adjustment ---
#define SENSITIVITY_PIN 35 // Analog pin for potentiometer
double sensitivity = 1500.0; // Initial sensitivity value. Adjust as needed
// --- Color Cycling ---
uint8_t hue = 0; // Global hue value for color cycling
#define HUE_INCREMENT 2 // Amount to increment hue each frame (adjust for speed)
#define SATURATION 255 // Fixed saturation value (for vivid colors)
// --- Minimum Brightness ---
#define MIN_BRIGHTNESS_PERCENT 80 // Minimum brightness percentage
// Function to perform FFT and update LEDs
void displaySpectrum() {
FFT.windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.compute(FFT_FORWARD);
FFT.complexToMagnitude();
int step = SAMPLES / (2.0 * NUM_LEDS); // Use only the first half of the samples
for (int i = 0; i < NUM_LEDS; i++) {
int peak = 0;
// Sample a range of frequencies for each LED
for (int j = i * step; j < (i + 1) * step; j++) {
if (vReal[j] > peak) {
peak = vReal[j];
}
}
// Map peak value to a magnitude
int magnitude = map(peak, 0, sensitivity, 0, 255);
magnitudeHistory[i][historyIndex[i]] = magnitude;
historyIndex[i] = (historyIndex[i] + 1) % AVERAGE_SAMPLES;
int avgMagnitude = 0;
for (int j = 0; j < AVERAGE_SAMPLES; j++) {
avgMagnitude += magnitudeHistory[i][j];
}
avgMagnitude /= AVERAGE_SAMPLES;
// Calculate minimum brightness
uint8_t minBrightness = (uint8_t)(255 * (MIN_BRIGHTNESS_PERCENT / 100.0));
// Map the magnitude to a brightness value, ensuring it's always at least minBrightness
uint8_t brightness = map(avgMagnitude, 0, 255, minBrightness, 255);
uint32_t color = Wheel((i * 2 + hue) & 255); // More varied color distribution
// Extract R, G, B components
uint8_t r = (color >> 16) & 255;
uint8_t g = (color >> 8) & 255;
uint8_t b = color & 255;
// Adjust each component's brightness while ensuring it doesn't go below minBrightness
r = map(r, 0, 255, minBrightness, brightness);
g = map(g, 0, 255, minBrightness, brightness);
b = map(b, 0, 255, minBrightness, brightness);
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
hue += HUE_INCREMENT; // Increment hue for the next frame
}
void setup() {
Serial.begin(115200);
analogReadResolution(12); // Set ADC resolution to 12 bits
strip.begin();
strip.show(); // Initialize all pixels to 'off'
strip.setBrightness(255); // Start with full brightness
pinMode(SENSITIVITY_PIN, INPUT);
}
void loop() {
microseconds = micros();
for (int i = 0; i < SAMPLES; i++) {
vReal[i] = analogRead(MIC_PIN);
vImag[i] = 0;
while ((micros() - microseconds) < (1000000 / SAMPLING_FREQUENCY)) {
// Maintain the sampling rate
}
microseconds += (1000000 / SAMPLING_FREQUENCY);
}
sensitivity = map(analogRead(SENSITIVITY_PIN), 0, 4095, 500, 5000);
displaySpectrum();
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if(WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
5V Power Supply
Adjust
Sensitivity
Mic