#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_SH1106.h>
#include <splash.h>
#include <Wire.h>
#include "arduinoFFT.h" // Standard Arduino FFT library
// https://github.com/kosme/arduinoFFT, in IDE, Sketch, Include Library, Manage Library, then search for FFT
arduinoFFT FFT = arduinoFFT();
#define OLED_SDA 26
#define OLED_SCL 25
Adafruit_SH1106 display(OLED_SDA, OLED_SCL);
#define SAMPLES 512 // Must be a power of 2
#define SAMPLING_FREQUENCY 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 200 // Depending on your audio source level, you may need to increase this value
unsigned int sampling_period_us;
unsigned long microseconds;
byte peak[] = { 0,0,0,0,0,0,0 };
double vReal[SAMPLES];
double vImag[SAMPLES];
unsigned long newTime, oldTime;
bool save = true;
void setup() {
Serial.begin(115200);
display.begin(SH1106_SWITCHCAPVCC, 0x3C);
display.clearDisplay(); // Adjust to suit or remove
display.setTextSize(1);
display.setTextColor(WHITE);
sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
}
void loop() {
display.clearDisplay();
display.setCursor(0, 0);
display.println(".1 .2 .5 1K 2K 4K 8K");
for (int i = 0; i < SAMPLES; i++) {
newTime = micros() - oldTime;
oldTime = newTime;
vReal[i] = analogRead(A0); // A conversion takes about 1uS on an ESP32
vImag[i] = 0;
while (micros() < (newTime + sampling_period_us)) { /* do nothing to wait */ }
}
FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
for (int i = 2; i < (SAMPLES / 2); i++) { // Don't use sample 0 and only first SAMPLES/2 are usable. Each array eleement represents a frequency and its value the amplitude.
if (vReal[i] > 2000) { // Add a crude noise filter, 10 x amplitude or more
if (i <= 2) displayBand(0, (int)vReal[i] / amplitude); // 125Hz
if (i >3 && i <= 5) displayBand(1, (int)vReal[i] / amplitude); // 250Hz
if (i >5 && i <= 7) displayBand(2, (int)vReal[i] / amplitude); // 500Hz
if (i >7 && i <= 15) displayBand(3, (int)vReal[i] / amplitude); // 1000Hz
if (i >15 && i <= 30) displayBand(4, (int)vReal[i] / amplitude); // 2000Hz
if (i >30 && i <= 53) displayBand(5, (int)vReal[i] / amplitude); // 4000Hz
if (i >53 && i <= 200) displayBand(6, (int)vReal[i] / amplitude); // 8000Hz
if (i >200) displayBand(7, (int)vReal[i] / amplitude); // 16000Hz
// Serial.println(vReal[i]);
}
for (byte band = 0; band <= 6; band++) drawHorizontalLine(18 * band, 64 - peak[band], 14);// display.drawHorizontalLine(18 * band, 64 - peak[band], 14);
}
if (millis() % 4 == 0) { for (byte band = 0; band <= 6; band++) { if (peak[band] > 0) peak[band] -= 1; } } // Decay the peak
display.display();
}
void displayBand(int band, int dsize)
{
int dmax = 50;
if (dsize > dmax) dsize = dmax;
if (band == 7) drawHorizontalLine(18 * 6, 0, 14);
for (int s = 0; s <= dsize; s = s + 2)
{ drawHorizontalLine(18 * band, 64 - s, 14); }
if (dsize > peak[band]) { peak[band] = dsize; }
}
void drawHorizontalLine(int16_t x, int16_t y, int16_t l)
{
display.drawLine(x, y, x + l, y, WHITE);
}