Audio Spectrum Analyzer Display

In this Intractable I am going to show how to make a program in Processing that analyzes sound on your speaker and sends data to an Arduino that controls an LED matrix to show the spectrum analysis with out any wire connection.

Components:

1) Arduino Nano: https://roboman.in/59h4
2) Arduino Nano Type C : https://roboman.in/xkfu
3) TP-4056 Module : https://roboman.in/oa0m
4) DC-DC Boost Converter LM2587 or XL6019 : https://roboman.in/kkuj
5) MAX7219 Dot Matrix 4 in 1 Display Module: https://roboman.in/jekd
6) Sound Sensor : Sound Sensor :https://roboman.in/vs1e
7) 18650 Lithium Battery 2500mah 3C :https://roboman.in/utwc
7) 18650 Lithium Battery 2600mah 3C : https://roboman.in/mmab
7) 18650 Lithium Battery 2200mah 1C :https://roboman.in/70b5
7) 18650 Lithium Battery 2000mah 1C :https://roboman.in/7em9
7) 18650 Lithium Battery 1800mah 1C :https://roboman.in/ywss

Diagram:

Code:


#include <arduinoFFT.h>
#include <MD_MAX72xx.h>
#include <SPI.h>
#include <EEPROM.h>

#define SAMPLES 64                          // Must be a power of 2
#define HARDWARE_TYPE MD_MAX72XX::ICSTATION_HW   // Set display type  so that  MD_MAX72xx library treets it properly
#define MAX_DEVICES  4                      // Total number display modules
#define CLK_PIN   13                        // Clock pin to communicate with display
#define DATA_PIN  11                        // Data pin to communicate with display
#define CS_PIN    10                        // Control pin to communicate with display
#define  xres 32                            // Total number of  columns in the display, must be <= SAMPLES/2
#define  yres 8                             // Total number of  rows in the display

int audio_response = 10;                                              // put a value between 10 and 80. Smaller the number, higher the audio response

int MY_ARRAY[]={0, 128, 192, 224, 240, 248, 252, 254, 255};           // default = standard pattern
int MY_MODE_1[]={0, 128, 192, 224, 240, 248, 252, 255, 255};          // standard pattern
int MY_MODE_2[]={0, 128, 64, 32, 16, 8, 4, 2, 1};                     // only peak pattern
int MY_MODE_3[]={0, 128, 192, 160, 144, 136, 132, 130, 129};          // only peak +  bottom point
int MY_MODE_4[]={0, 128, 192, 160, 208, 232, 244, 250, 253};          // one gap in the top , 3rd light onwards
int MY_MODE_5[]={0, 1, 3, 7, 15, 31, 63, 127, 255};                   // standard pattern, mirrored vertically

 
double vReal[SAMPLES];
double vImag[SAMPLES];
char data_avgs[xres];

int yvalue;
int displaycolumn , displayvalue;
int peaks[xres];
const int buttonPin = 5;             // the number of the pushbutton pin
int state = HIGH;                    // the current reading from the input pin
int previousState = LOW;             // the previous reading from the input pin
int displaymode = 1;
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers


MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);   // display object
arduinoFFT FFT = arduinoFFT();                                    // FFT object
 


void setup() {
    EEPROM.update(1,1);                                           //(memory address, value), RUN THIS FOR THE FIRST TIME
    displaymode = EEPROM.read(1);
    ADCSRA = 0b11100101;                                          // set ADC to free running mode and set pre-scalar to 32 (0xe5)
    ADMUX = 0b00000000;                                           // use pin A0 and external voltage reference
    pinMode(buttonPin, INPUT);
    mx.begin();                                                   // initialize display
    delay(50);                                                    // wait to get reference voltage stabilized
    
}
 
void loop() {
   // ++ Sampling
   for(int i=0; i<SAMPLES; i++)
    {
      while(!(ADCSRA & 0x10));                // wait for ADC to complete current conversion ie ADIF bit set
      ADCSRA = 0b11110101 ;                   // clear ADIF bit so that ADC can do next operation (0xf5)
      int value = ADC - 512 ;                 // Read from ADC and subtract DC offset caused value
      vReal[i]= value/8;                      // Copy to bins after compressing
      vImag[i] = 0;                         
    }
    // -- Sampling

 
    // ++ FFT
    FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
    // -- FFT

    
    // ++ re-arrange FFT result to match with no. of columns on display ( xres )
    int step = (SAMPLES/2)/xres; 
    int c=0;
    for(int i=0; i<(SAMPLES/2); i+=step)  
    {
      data_avgs[c] = 0;
      for (int k=0 ; k< step ; k++) {
          data_avgs[c] = data_avgs[c] + vReal[i+k];
      }
      data_avgs[c] = data_avgs[c]/step; 
      c++;
    }
    // -- re-arrange FFT result to match with no. of columns on display ( xres )

    
    // ++ send to display according measured value 
    for(int i=0; i<xres; i++)
    {
      data_avgs[i] = constrain(data_avgs[i],0,80);               // set max & min values for buckets
      data_avgs[i] = map(data_avgs[i], 0, 80, 0, yres);          // remap averaged values to yres
      yvalue=data_avgs[i];

      peaks[i] = peaks[i]-1;    // decay by one light
      if (yvalue > peaks[i]) 
          peaks[i] = yvalue ;
      yvalue = peaks[i];    
      displayvalue=MY_ARRAY[yvalue];
      displaycolumn=31-i;
      mx.setColumn(displaycolumn, displayvalue);               // for left to right
     }
     // -- send to display according measured value 
     
    displayModeChange ();                                      // check if button pressed to change display mode
} 

void displayModeChange() {
  int reading = digitalRead(buttonPin);
  if (reading == HIGH && previousState == LOW && millis() - lastDebounceTime > debounceDelay) // works only when pressed
  
  {

   switch (displaymode) {
    case 1:    //       move from mode 1 to 2
      displaymode = 2;
      EEPROM.update(1,2);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_2[i];
      }
      break;
    case 2:    //       move from mode 2 to 3
      displaymode = 3;
      EEPROM.update(1,3);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_3[i];
      }
      break;
    case 3:    //     move from mode 3 to 4
      displaymode = 4;
      EEPROM.update(1,4);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_4[i];
      }
      break;
    case 4:    //     move from mode 4 to 5
      displaymode = 5;
      EEPROM.update(1,5);
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_5[i];
      }
      break;
    case 5:    //      move from mode 5 to 1
      displaymode = 1;
      EEPROM.update(1,1);      
      for (int i=0 ; i<=8 ; i++ ) {
        MY_ARRAY[i]=MY_MODE_1[i];
      }
      break;
  }

    lastDebounceTime = millis();
  }
  previousState = reading;
}