FFT to react have LED to react to game and music

I have been trying to create a program that will allow my Arduino to detect certain parts of the audio. I have been trying to us FFT but it doesn’t seem to be capturing all of the input from the audio. I have copied the code I found online bellow. have also attached a picture of my serial plotter results. any advice would be very much appreciated .

#include "arduinoFFT.h"

#define SAMPLES 128             //Must be a power of 2
#define SAMPLING_FREQUENCY 1000 //Hz, must be less than 10000 due to ADC

arduinoFFT FFT = arduinoFFT();

unsigned int sampling_period_us;
unsigned long microseconds;

double vReal[SAMPLES];
double vImag[SAMPLES];

void setup() {
  Serial.begin(115200);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(16, OUTPUT);
  pinMode(17, OUTPUT);
  pinMode(18, OUTPUT);
  pinMode(19, OUTPUT);
  sampling_period_us = round(1000000 * (1.0 / SAMPLING_FREQUENCY));
}

void loop() {

  /*SAMPLING*/
  for (int i = 0; i < SAMPLES; i++)
  {
    microseconds = micros();    //Overflows after around 70 minutes!

    vReal[i] = analogRead(0);
    vImag[i] = 0;

    while (micros() < (microseconds + sampling_period_us)) {
    }
  }

  /*FFT*/
  FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);
  double peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);

  /*PRINT RESULTS*/
  //Serial.println(peak);     //Print out what frequency is the most dominant.

  for (int i = 0; i < (SAMPLES / 2); i++)
  {
    /*View all these three lines in serial terminal to see which frequencies has which amplitudes*/

   // Serial.print((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES, 1);
   // Serial.print(" ");
    Serial.println(vReal[i], 1);    //View only this line in serial plotter to visualize the bins
    if (SAMPLING_FREQUENCY > 430) {
      digitalWrite(2, HIGH);
      digitalWrite(3, HIGH);
      digitalWrite(4, HIGH);
      digitalWrite(5, HIGH);
      digitalWrite(6, HIGH);
      digitalWrite(7, HIGH);
      digitalWrite(8, HIGH);
      digitalWrite(9, HIGH);
      digitalWrite(10, HIGH);
      digitalWrite(11, HIGH);
      digitalWrite(12, HIGH);
      digitalWrite(13, HIGH);
      digitalWrite(16, HIGH);
      digitalWrite(17, HIGH);
      digitalWrite(18, HIGH);
      digitalWrite(19, HIGH);
    }
    if (SAMPLING_FREQUENCY < 430) {
      digitalWrite(2, LOW);
      digitalWrite(3, LOW);
      digitalWrite(4, LOW);
      digitalWrite(5, LOW);
      digitalWrite(6, LOW);
      digitalWrite(7, LOW);
      digitalWrite(8, LOW);
      digitalWrite(9, LOW);
      digitalWrite(10, LOW);
      digitalWrite(11, LOW);
      digitalWrite(12, LOW);
      digitalWrite(13, LOW);
      digitalWrite(16, LOW);
      digitalWrite(17, LOW);
      digitalWrite(18, LOW);
      digitalWrite(19, LOW);

    }
  }

  //Repeat the process every second OR:
}

danieldesalvatore: I have copied the code I found online bellow.

That's never a good idea. The first step in solving your problem is understanding what the code does and how it does that. The author of the code you posted clearly has no idea what he's doing, so I'd suggest you start with the examples that come with the library.

If you don't understand these examples, it's best to do some research online. If you've got specific questions, we'll be happy to answer them here.

A few remarks: Since your input is real and not complex, you should be using an FHT instead of an FFT. It's twice as efficient. 1000 samples/s gives you a maximum frequency of 500 Hz. Audio frequencies range up to 20 kHz. This means that you either have to increase your sampling frequency, or add a very strong anti-aliasing filter in hardware. Otherwise, the result in the frequency domain will be completely meaningless. Rather than using a while loop for the sample timing (which will overflow in this case, you should always subtract time, never add them together), you should put the ADC in free running mode, allowing for much higher and accurate sample rates.

Pieter

PieterP: That's never a good idea. The first step in solving your problem is understanding what the code does and how it does that. The author of the code you posted clearly has no idea what he's doing, so I'd suggest you start with the examples that come with the library.

If you don't understand these examples, it's best to do some research online. If you've got specific questions, we'll be happy to answer them here.

A few remarks: Since your input is real and not complex, you should be using an FHT instead of an FFT. It's twice as efficient. 1000 samples/s gives you a maximum frequency of 500 Hz. Audio frequencies range up to 20 kHz. This means that you either have to increase your sampling frequency, or add a very strong anti-aliasing filter in hardware. Otherwise, the result in the frequency domain will be completely meaningless. Rather than using a while loop for the sample timing (which will overflow in this case, you should always subtract time, never add them together), you should put the ADC in free running mode, allowing for much higher and accurate sample rates.

Pieter

as I am so new to all, of this and I am self-taught I ten to try and find the code online and try and figure out what each part does by changing part and seeing what happens. i am not sure what you mean by ADC in free Running mode? but thank you for explaining to me the FHT would be better

On top of missing spectrum, using that code you're also going to suffer from temporal gaps. There are actually 2 temporal gap problems.

1: With such a simple structure, where you collect data and then analyze it, you'll miss all the signal events which occur during the time you're doing to computations. Your code isn't collecting samples during that time, so whatever happens with the signal during those moments will be missed.

2: The Hanning window also causes signal loss. Even though you've collected 128 samples, the window greatly attenuates the first and last 32 samples, so you're mostly analyzing what happened during the middle of those 128 samples and mostly ignoring the time not in the middle.

To not be "blind" to any part of the signal, you need to be continuously collecting samples (eg, interrupts or dma) even while doing the computations. To not be "blind" to the attenuated window area, you need to perform twice as many FFT computations, with 50% overlap.

If controlling LEDs, you also need to manage to accomplish all that while simultaneously transmitting the data to addressable LEDs!

Doing all that and using a higher sample rate to capture the entire audio spectrum adds up to needing a fairly powerful board. Slow 8 bit boards just aren't up to the task. With limited CPU performance, you're limited to only a fraction of the bandwidth and being "blind" to a good portion of the time of the signal.

With powerful 32 bit boards, this all becomes possible. Here's an example I added in the OctoWS2811 library a few years ago, which implements a 60 band, 32-level spectrum analyzer on 1920 addressable LEDs, with 86 Hz. It could be called zero-blind, since it has 20 kHz response and uses 50% overlapped 1024 point FFTs.

https://github.com/PaulStoffregen/OctoWS2811/blob/master/examples/SpectrumAnalyzer/SpectrumAnalyzer.ino

But you just can't get this sort of performance from 8 bit AVR boards. They're just not up to the task!

danieldesalvatore:
i am not sure what you mean by ADC in free Running mode?

See §28.9.7 of the ATmega328P datasheet.

I think this should get you somewhere:

#define FHT_N 256 // set to 256 point fht

#include <FHT.h> // include the library

#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))


void setup() {
  ADCSRB = 0; // Free running mode
  ADMUX = (DEFAULT << 6) | 0; // A0
  sbi(ADCSRA, ADEN); // Enable ADC
  sbi(ADCSRA, ADATE); // Auto trigger
  sbi(ADCSRA, ADSC); // Start conversion
  // 19.231 kHz
  sbi(ADCSRA, ADPS2);
  sbi(ADCSRA, ADPS1);
  cbi(ADCSRA, ADPS0);
}

void loop() {
    cli();  // UDRE interrupt slows this way down (not sure if this is still an issue)
    for (unsigned int i = 0; i < FHT_N; i++) { // save 256 samples
      while (!(ADCSRA & _BV(ADIF))); // wait for ADC result
      sbi(ADCSRA, ADIF); // Clear interrupt flag
      byte low = ADCL; // fetch ADC data
      byte high = ADCH;
      int16_t k = (high << 8) | low; // combine low and high bytes
      k -= 0x0200; // remove 2.5V DC bias
      k <<= 6; // maximum precision (15+1 significant bits instead of 9+1)
      fht_input[i] = k; // save sample
    }
    fht_window(); // apply windowing function
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // calculate the logarithmic magnitude output of each frequency bin
    sei(); // enable interrupts again
    // Print the results
    for (uint8_t i = 0 ; i < FHT_N / 2 ; i++) {
      Serial.print(i * 19231UL / FHT_N); Serial.print(" Hz:\t");
      Serial.println(fht_log_out[i]); // send out the data
    }
    Serial.flush();
}

PieterP:
#include <FHT.h> // include the library

where do I download this library?

danieldesalvatore: where do I download this library?

http://wiki.openmusiclabs.com/wiki/ArduinoFHT

PieterP:
ArduinoFHT - Open Music Labs Wiki

its saying fht_log_out was not declared
Serial.println(fht_log_out*); // send out the data?*

i have decided to just to buy this Graphic Equalizer Display Filter - MSGEQ7 to eliminate all of the math

danieldesalvatore: I have been trying to create a program that will allow my Arduino to detect certain parts of the audio. I have been trying to us FFT

Perhaps you should explain better what you are trying to achieve. FFT may be completely inappropriate anyway (and this is an xyproblem thread)...

danieldesalvatore:

its saying fht_log_out[i] was not declared 

Serial.println(fht_log_out[i]); // send out the data?

My bad, you have to add this line to the top:

#define LOG_OUT 1 // use the log output function