DIY Music Visualizer - Lights Not Responding Properly

Hello, I am making a music visualizer using a strip of neopixel LEDs and the arduinoFFT library. when trying to get the leds to respond to the microphone output, however, they just don't seem to work. I checked the lights and they work just fine with the program if I manually input the values, and the computer imputs the values they show up in the serial port just fine, but the lights don't respond. Any ideas on what the problem might be?
Here is the full code:

/*
Code by Ari Davidson
*/
#include "arduinoFFT.h"

arduinoFFT FFT = arduinoFFT(); 
#define CHANNEL A0

const uint16_t samples = 64; //This value MUST ALWAYS be a power of 2
const double samplingFrequency = 2093; //Hz, must be less than 10000 due to ADC

unsigned int sampling_period_us;
unsigned long microseconds;
/*
These are the input and output vectors
Input vectors receive computed results from FFT
*/
double vReal[samples];
double vImag[samples];

#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02
#define SCL_PLOT 0x03



#include <Adafruit_NeoPixel.h>
#include<arduinoFFT.h>
#define LED_PIN 13
#define LED_COUNT 6//number of rows(sub strips)
int pixNum = 5; //number of substrips
Adafruit_NeoPixel strip(LED_COUNT * pixNum, LED_PIN, NEO_GRB + NEO_KHZ800);//initalize led strip


int avol = 0;

int ledNum = 0;
int stripNum = 1;
uint32_t orange = strip.Color(255, 100, 0);
uint32_t yellow = strip.Color(255, 255, 0);
uint32_t green = strip.Color(0, 255, 0);
uint32_t blue = strip.Color(0, 0, 255);
uint32_t purple = strip.Color(255, 0, 255);

void setup(){
    strip.begin();
    strip.show();
      sampling_period_us = round(1000000*(1.0/samplingFrequency));
  Serial.begin(115200);
  while(!Serial);
  Serial.println("Ready");
}


void ledOn(int ledNum, int stripNum){
   if(ledNum == 1){
       strip.setPixelColor(ledNum+stripNum,orange);
   }
    else{
         if(ledNum == 2){
       strip.setPixelColor(ledNum+stripNum,yellow);
   }else{
        if(ledNum == 3){
       strip.setPixelColor(ledNum+stripNum,green);
   }
   else{
        if(ledNum == 4){
       strip.setPixelColor(ledNum+stripNum,blue);
   }
   else{
        if(ledNum == 5){
       strip.setPixelColor(ledNum+stripNum,purple);
   }
   else{
              strip.setPixelColor(ledNum+stripNum,0,0,0);

   }
   
   }
   }
   }
    }
}



void readMic()
{
  /*SAMPLING*/
  microseconds = micros();
  for(int i=0; i<samples; i++)
  {
      vReal[i] = analogRead(CHANNEL);
      vImag[i] = 0;
      while(micros() - microseconds < sampling_period_us){
        //empty loop
      }
      microseconds += sampling_period_us;
  }

  FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */

int aval1 = abs(vReal[1]);


avol = 0;
  if(100<aval1 && aval1<500){
    avol = 1;
  } if(499<aval1 && aval1<1000){
    avol = 2;
  } if(999<aval1 && aval1<1250){
    avol = 3;
  } if(1249<aval1 && aval1<1500){
    avol = 4;
  } if(1499<aval1 && aval1<2000){
    avol = 5;
  }
   
 Serial.print(avol);
 Serial.print(" ");
 Serial.println(aval1);

}
void PrintVector(double *vData, uint16_t bufferSize, uint8_t scaleType)
{
  for (uint16_t i = 0; i < bufferSize; i++)
  {
    
    double abscissa;
    switch (scaleType)
    {
      case SCL_INDEX:
        abscissa = (i * 1.0);
	break;
      case SCL_TIME:
        abscissa = ((i * 1.0) / samplingFrequency);
	break;
      case SCL_FREQUENCY:
        abscissa = ((i * 1.0 * samplingFrequency) / samples);
	break;
    }
    Serial.print(abscissa, 6);
    if(scaleType==SCL_FREQUENCY)
      Serial.print("Hz");
    Serial.print(" ");
    Serial.println(vData[i], 4);
  }
  Serial.println();
}


void loop(){
        readMic();
       
        for(int i = 0; i <= avol; i++){
        ledOn(i,0);
        
    }

    strip.show();
    strip.clear();
    delay(1000);
}

If you haven't done this already test it with some constant test tones at known frequencies. That should help when comparing the FFT numbers with your manually entered numbers.

Audacity can generate test-tones.

I didn't study your code but the 1-second delay in your loop seems "odd". FFT takes a lot of processing and NeoPixels take a lot of processing too (depending on the number of LEDs) so you usually want to run it as fast as possible with no delays, or maybe some very-short delays if you want to hold the display for a fraction of a second.

Writing to the serial monitor takes some time too so you might want to take that out after you're done debugging,

What does your serial monitor show?
Is your mic sufficient to drive avol to 500?

Why do you only read vReal[1] from FFT?
How is your microphone signal biased?
Does FFT expect biased values?
Can you print the result of FFT (vReal[])?

Also, you might want to read about switch case.
It will save you a lot of if else.

From the point of software design it is recommended that one function does one thing.
So you should have a function readSoundVolume() that returns the volume.
Then another function that classifies the volume (your if else block) and returns a number based on loudness.
You could further split of the reading of your mic input in a readMic() function. This function may be called from readSoundVolume.
All this requires you to make functions that take arguments and return values just like the FFT function you are using.

Where is PrintVector called? Or is it a relic?

Where is samplingperiodus set to a reasonable value?
It is global so it is initialized to 0...

Use ctrl-t to format your code...

You should set microseconds inside the for loop...

yep, I just have it in there for testing so I can be sure that the lights have the time to light up properly, I will check out audacity, thanks for the tip

I guess you're talking about the delay? I'm not 100% sure... Like I said, I didn't analyze your code, and although I know a little about FFT & NeoPixels I haven't used them.

But, I THINK more than 90% of the time it's just sitting there in the delay() and then it does a quick-read of the audio and updates the display and then sits there waiting again.

It's not doing ANYTHING during the delay.

The audio reading and analysis should probably be more-or-less continuous when the program isn't busy doing something else.

I have made several lighting effects and I typically "hold" the display for 50 or 100ms. But, it's continuously reading the audio in-between. I have some regular incandescent lights and they take about 1/10th of a second (100ms) to fully light-up and I think they take a little longer to go fully-dark. LEDs are "instant" but if you flash it on for less than 50ms you might not perceive full-brightness. And if it flickers-off for less than 50ms you might not notice it.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.