kopia lustrzana https://github.com/s-marley/ESP32_FFT_VU
Add files via upload
rodzic
24b2f028e2
commit
025a8f8dc8
|
@ -0,0 +1,256 @@
|
|||
// (Heavily) adapted from https://github.com/G6EJD/ESP32-8266-Audio-Spectrum-Display/blob/master/ESP32_Spectrum_Display_02.ino
|
||||
|
||||
#include <FastLED.h>
|
||||
#include <arduinoFFT.h>
|
||||
#include <JC_Button.h>
|
||||
|
||||
#define SAMPLES 1024 // Must be a power of 2
|
||||
#define SAMPLING_FREQ 40000 // Hz, must be 40000 or less due to ADC conversion time. Determines maximum frequency that can be analysed by the FFT Fmax=sampleF/2.
|
||||
#define AMPLITUDE 1000 // Depending on your audio source level, you may need to alter this value. Can be used as a 'sensitivity' control.
|
||||
#define AUDIO_IN_PIN 35 // Signal in on this pin
|
||||
#define LED_PIN 5 // LED strip data
|
||||
#define BTN_PIN 2 // Connect a push button to this pin to change patterns
|
||||
#define DEBOUNCE_MS 20 // Number of ms to debounce button
|
||||
#define COLOR_ORDER GRB // If colours look wrong, play with this
|
||||
#define CHIPSET WS2812B // LED strip type
|
||||
#define MAX_MILLIAMPS 500 // Careful with the amount of power here if running off USB port
|
||||
#define BRIGHTNESS 50 // Brightness 0 - 255, but won't exceed current specified above
|
||||
#define LED_VOLTS 5 // Usually 5 or 12
|
||||
#define NUM_BANDS 16 // To change this, you will need to change the bunch of if statements describing the mapping from bins to bands
|
||||
#define NOISE 500 // Used as a crude noise filter, values below this are ignored
|
||||
|
||||
const uint8_t kMatrixWidth = 16; // Matrix width
|
||||
const uint8_t kMatrixHeight = 16; // Matrix height
|
||||
#define NUM_LEDS (kMatrixWidth * kMatrixHeight) // Total number of LEDs
|
||||
#define BAR_WIDTH (kMatrixWidth / (NUM_BANDS - 1)) // If width >= 8 light 1 LED width per bar, >= 16 light 2 LEDs width bar etc
|
||||
#define TOP (kMatrixHeight - 1) // Don't allowthe bars to go offscreen
|
||||
|
||||
// Sampling and FFT stuff
|
||||
unsigned int sampling_period_us;
|
||||
byte peak[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // For more than 16 channels you must increase the size of these arrays
|
||||
int oldBarHeights[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
int bandValues[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
double vReal[SAMPLES];
|
||||
double vImag[SAMPLES];
|
||||
unsigned long newTime;
|
||||
arduinoFFT FFT = arduinoFFT(vReal, vImag, SAMPLES, SAMPLING_FREQ);
|
||||
|
||||
// Button stuff
|
||||
int buttonPushCounter = 0;
|
||||
Button modeBtn(BTN_PIN, DEBOUNCE_MS);
|
||||
|
||||
// FastLED stuff
|
||||
CRGB leds[NUM_LEDS];
|
||||
DEFINE_GRADIENT_PALETTE( purple_gp ) {
|
||||
0, 0, 212, 255, //blue
|
||||
255, 179, 0, 255 }; //purple
|
||||
DEFINE_GRADIENT_PALETTE( outrun_gp ) {
|
||||
0, 141, 0, 100, //purple
|
||||
127, 255, 192, 0, //yellow
|
||||
255, 0, 5, 255 }; //blue
|
||||
CRGBPalette16 purplePal = purple_gp;
|
||||
CRGBPalette16 outrunPal = outrun_gp;
|
||||
uint8_t colorTimer = 0;
|
||||
|
||||
// XY code for serpentine matrix with input in top left
|
||||
uint16_t XY( uint8_t x, uint8_t y) {
|
||||
uint16_t i;
|
||||
|
||||
y = kMatrixHeight - 1 - y; // Adjust y coordinate so (0,0) is bottom left
|
||||
|
||||
if( y & 0x01) {
|
||||
// Odd rows run backwards
|
||||
uint8_t reverseX = (kMatrixWidth - 1) - x;
|
||||
i = (y * kMatrixWidth) + reverseX;
|
||||
} else {
|
||||
// Even rows run forwards
|
||||
i = (y * kMatrixHeight) + x;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalSMD5050);
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(LED_VOLTS, MAX_MILLIAMPS);
|
||||
FastLED.setBrightness(BRIGHTNESS);
|
||||
FastLED.clear();
|
||||
|
||||
modeBtn.begin();
|
||||
|
||||
sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQ));
|
||||
}
|
||||
|
||||
void loop() {
|
||||
|
||||
FastLED.clear();
|
||||
|
||||
// Read the button
|
||||
modeBtn.read();
|
||||
if (modeBtn.wasReleased()) {
|
||||
buttonPushCounter = (buttonPushCounter + 1) % 4;
|
||||
Serial.println("Button");
|
||||
}
|
||||
|
||||
// Reset bandValues[]
|
||||
for (int i = 0; i<NUM_BANDS; i++){
|
||||
bandValues[i] = 0;
|
||||
}
|
||||
|
||||
// Sample the audio pin
|
||||
for (int i = 0; i < SAMPLES; i++) {
|
||||
newTime = micros();
|
||||
vReal[i] = analogRead(AUDIO_IN_PIN); // A conversion takes about 9.7uS on an ESP32
|
||||
vImag[i] = 0;
|
||||
while (micros() < (newTime + sampling_period_us)) { /* chill */ }
|
||||
}
|
||||
|
||||
// Compute FFT
|
||||
FFT.DCRemoval();
|
||||
FFT.Windowing(FFT_WIN_TYP_HAMMING, FFT_FORWARD);
|
||||
FFT.Compute(FFT_FORWARD);
|
||||
FFT.ComplexToMagnitude();
|
||||
|
||||
// Analyse FFT results
|
||||
for (int i = 2; i < (SAMPLES/2); i++){ // Don't use sample 0 and only first SAMPLES/2 are usable. Each array element represents a frequency bin and its value the amplitude.
|
||||
if (vReal[i] > NOISE) { // Add a crude noise filter
|
||||
|
||||
/*8 bands, 16kHz top band
|
||||
if (i<=3 ) bandValues[0] += (int)vReal[i];
|
||||
if (i>3 && i<=7 ) bandValues[1] += (int)vReal[i];
|
||||
if (i>7 && i<=15 ) bandValues[2] += (int)vReal[i];
|
||||
if (i>15 && i<=31 ) bandValues[3] += (int)vReal[i];
|
||||
if (i>31 && i<=66 ) bandValues[4] += (int)vReal[i];
|
||||
if (i>66 && i<=141) bandValues[5] += (int)vReal[i];
|
||||
if (i>141 && i<=301) bandValues[6] += (int)vReal[i];
|
||||
if (i>301 ) bandValues[7] += (int)vReal[i];*/
|
||||
|
||||
//16 bands, 12kHz top band
|
||||
if (i<=2 ) bandValues[0] += (int)vReal[i];
|
||||
if (i>2 && i<=3 ) bandValues[1] += (int)vReal[i];
|
||||
if (i>3 && i<=5 ) bandValues[2] += (int)vReal[i];
|
||||
if (i>5 && i<=7 ) bandValues[3] += (int)vReal[i];
|
||||
if (i>7 && i<=9 ) bandValues[4] += (int)vReal[i];
|
||||
if (i>9 && i<=13 ) bandValues[5] += (int)vReal[i];
|
||||
if (i>13 && i<=18 ) bandValues[6] += (int)vReal[i];
|
||||
if (i>18 && i<=25 ) bandValues[7] += (int)vReal[i];
|
||||
if (i>25 && i<=36 ) bandValues[8] += (int)vReal[i];
|
||||
if (i>36 && i<=50 ) bandValues[9] += (int)vReal[i];
|
||||
if (i>50 && i<=69 ) bandValues[10] += (int)vReal[i];
|
||||
if (i>69 && i<=97 ) bandValues[11] += (int)vReal[i];
|
||||
if (i>97 && i<=135) bandValues[12] += (int)vReal[i];
|
||||
if (i>135 && i<=189) bandValues[13] += (int)vReal[i];
|
||||
if (i>189 && i<=264) bandValues[14] += (int)vReal[i];
|
||||
if (i>264 ) bandValues[15] += (int)vReal[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Process the FFT data into bar heights
|
||||
for (byte band = 0; band < NUM_BANDS; band++) {
|
||||
|
||||
// Scale the bars for the display
|
||||
int barHeight = bandValues[band] / AMPLITUDE;
|
||||
if (barHeight > TOP) barHeight = TOP;
|
||||
|
||||
// Small amount of averaging between frames
|
||||
barHeight = ((oldBarHeights[band] * 1) + barHeight) / 2;
|
||||
|
||||
// Move peak up
|
||||
if (barHeight > peak[band]) {
|
||||
peak[band] = min(TOP, barHeight);
|
||||
}
|
||||
|
||||
// Draw bars
|
||||
switch (buttonPushCounter) {
|
||||
case 0:
|
||||
rainbowBars(band, barHeight);
|
||||
break;
|
||||
case 1:
|
||||
purpleBars(band, barHeight);
|
||||
break;
|
||||
case 2:
|
||||
// No bars on this one
|
||||
break;
|
||||
case 3:
|
||||
changingBars(band, barHeight);
|
||||
}
|
||||
|
||||
// Draw peaks
|
||||
switch (buttonPushCounter) {
|
||||
case 0:
|
||||
whitePeak(band);
|
||||
break;
|
||||
case 1:
|
||||
whitePeak(band);
|
||||
break;
|
||||
case 2:
|
||||
rainbowPeak(band);
|
||||
break;
|
||||
case 3:
|
||||
// No peaks on this one
|
||||
break;
|
||||
}
|
||||
|
||||
// Save oldBarHeights for averaging later
|
||||
oldBarHeights[band] = barHeight;
|
||||
}
|
||||
|
||||
// Decay peak
|
||||
EVERY_N_MILLISECONDS(60) {
|
||||
for (byte band = 0; band < NUM_BANDS; band++)
|
||||
if (peak[band] > 0) peak[band] -= 1;
|
||||
colorTimer++;
|
||||
}
|
||||
|
||||
// Used in some of the patterns
|
||||
EVERY_N_MILLISECONDS(10) {
|
||||
colorTimer++;
|
||||
}
|
||||
|
||||
FastLED.show();
|
||||
}
|
||||
|
||||
// PATTERNS BELOW
|
||||
void rainbowBars(int band, int barHeight) {
|
||||
int xStart = BAR_WIDTH * band;
|
||||
for (int x = xStart; x < xStart + BAR_WIDTH; x++) {
|
||||
for (int y = 0; y < barHeight; y++) {
|
||||
leds[XY(x,y)] = CHSV((x / BAR_WIDTH) * (255 / NUM_BANDS), 255, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void purpleBars(int band, int barHeight) {
|
||||
int xStart = BAR_WIDTH * band;
|
||||
for (int x = xStart; x < xStart + BAR_WIDTH; x++) {
|
||||
for (int y = 0; y < barHeight; y++) {
|
||||
leds[XY(x,y)] = ColorFromPalette(purplePal, y * (255 / barHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void changingBars(int band, int barHeight) {
|
||||
int xStart = BAR_WIDTH * band;
|
||||
for (int x = xStart; x < xStart + BAR_WIDTH; x++) {
|
||||
for (int y = 0; y < barHeight; y++) {
|
||||
leds[XY(x,y)] = CHSV(y * (255 / kMatrixHeight) + colorTimer, 255, 255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void whitePeak(int band) {
|
||||
int xStart = BAR_WIDTH * band;
|
||||
int peakHeight = peak[band];
|
||||
for (int x = xStart; x < xStart + BAR_WIDTH; x++) {
|
||||
leds[XY(x,peakHeight)] = CRGB::White;
|
||||
}
|
||||
}
|
||||
|
||||
void rainbowPeak(int band) {
|
||||
int xStart = BAR_WIDTH * band;
|
||||
int peakHeight = peak[band];
|
||||
for (int x = xStart; x < xStart + BAR_WIDTH; x++) {
|
||||
//leds[XY(x,peakHeight)] = CHSV(peakHeight * (255 / kMatrixHeight), 255, 255);
|
||||
leds[XY(x,peakHeight)] = ColorFromPalette(outrunPal, peakHeight * (255 / kMatrixHeight));
|
||||
}
|
||||
}
|
Plik binarny nie jest wyświetlany.
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 206 KiB |
Plik binarny nie jest wyświetlany.
Po Szerokość: | Wysokość: | Rozmiar: 101 KiB |
|
@ -0,0 +1,27 @@
|
|||
#define AUDIO_IN_PIN 35
|
||||
|
||||
int analogValue;
|
||||
unsigned long newTime;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
newTime = micros();
|
||||
|
||||
// Do 1 million reads and record time taken
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
analogValue = analogRead(AUDIO_IN_PIN);
|
||||
}
|
||||
|
||||
float conversionTime = (micros() - newTime) / 1000000.0;
|
||||
|
||||
Serial.print("Conversion time: ");
|
||||
Serial.print(conversionTime);
|
||||
Serial.println(" uS");
|
||||
|
||||
Serial.print("Max sampling frequency: ");
|
||||
Serial.print((1.0 / conversionTime) * 1000000);
|
||||
Serial.println(" Hz");
|
||||
}
|
Ładowanie…
Reference in New Issue