Audio spectrum visualizer with ESP32

This experiment displays audio spectrum using ESP32 module, a microphone and a TFT display.

In this sketch, the ESP32 module reads the analog microphone output and performs Fast Fourier Transform (FFT) during each sampling window. At the end of each sampling window, the FFT result is displayed using different colors according to the magnitude of each frequency.

Fast Fourier transform is an algorithm that computes the discrete Fourier transform of a sequence. Fourier analysis converts a signal from time domain to a representation in the frequency domain and vice versa.

The FFT can be performed via the arduinoFFT library, developed for Arduino and working also for ESP32.

This experiment may be improved by adding a low-pass filter between the analog microphone output and the analog input on ESP32, to reduce artifacts. Low-pass filter should cut-off at half the sampling frequency.



Hardware set-up

Following hardware is required to build the experiment: Implement following connections:
  • Connect GND(ESP32+TFT) together with GND(KY-037)
  • Connect 3V3(ESP32+TFT) together with Vcc(KY-037)
  • Connect GPIO39(ESP32) to microphone analog output(KY-037)

Confused about all acronyms? Here is a brief explanation: GND is the ground line, 3V3 and Vcc are the positive supply line, GPIO39 is the ADC1 channel 3 input (GPIO is generic purpose Input/Output).

The following picture shows the Audio Spectrum Visualizer breadboard:

Audio Spectrum Visualizer breadboard

ESP32 software

Before writing software make sure to have installed the software development environment, downloadable from Arduino Software web site. It may be needed to download some library if not already present. Libraries are required also to manage the external devices.

The sketch has to include the required libraries:

#include "arduinoFFT.h"
#include <TFT_eSPI.h> // Hardware-specific library
#include <SPI.h>


The loop() function implements the Audio Spectrum Visualizer functionality.

void loop() { tft.drawPixel(epoch, 0, color_cursor); do_sampling_FFT(); delay(10); tft.drawPixel(epoch, 0, 0);//<--black epoch++; if (epoch >= tft.width()) epoch = 0; } void do_sampling_FFT() {//get data from ADC, do FFT and display data /*SAMPLING*/ microseconds = micros(); for(int i=0; i < samples; i++) { vReal[i] = analogRead(analogInputPin); vImag[i] = 0; while(micros() - microseconds < sampling_period_us){ //empty loop to sync with sampling period } microseconds += sampling_period_us; } // calculate the mean of vReal double mean = 0; for (uint16_t i = 0; i < samples; i++) mean += vReal[i]; mean /= samples; for (uint16_t i = 0; i < samples; i++) vReal[i] -= mean; microseconds = micros(); /* Print the results of the sampling according to time */ FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD); /* Weigh data */ FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */ FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */ unsigned int top_y = tft.height() - 1; int max_k = 0; for (int j = 0; j < samples >> 1; j++) { int k = vReal[j] / attenuation; if (k > max_k) max_k = k; if (k > 127) k = 127; unsigned int color = palette_red[k] << 11 | palette_green[k] << 5 | palette_blue[k]; tft.drawPixel(epoch, top_y - j, color); } double tattenuation = max_k / 127.0; if (tattenuation > attenuation) attenuation = tattenuation;//performs AGC }


Download the complete sketch here and enjoy it.

Share Share on Facebook Share on Twitter Bookmark on Reddit Share via mail
Creative Commons Attribution-Share Alike | Terms and conditions | Privacy policy