marcaubin
Published © GPL3+

Audio Spectrum Visualiser with Colour Selection

Choose the colours of the LED strip using Hue/Saturation/Value parameters, flick the switch and watch your music come to life through FFT.

IntermediateFull instructions provided749
Audio Spectrum Visualiser with Colour Selection

Things used in this project

Hardware components

Arduino Nano Every
Arduino Nano Every
×1
Resistor 4.7k ohm
×3
Resistor 10k ohm
Resistor 10k ohm
×1
Resistor 100k ohm
Resistor 100k ohm
×2
Capacitor 100 nF
Capacitor 100 nF
×2
Potentiometer 10k ohm
×5
Switch SPST or SPDT
×1
Buck Converter 9vdc to 5vdc
×1
Wall Adapter 9vdc
×1
Barrel Connector for Wall Adapter
×1
Audio Connector, 3.5mm stereo, panel mount
×1
Audio Cable
×1
Audio Y Adapter
×1
Junction Box, 158 x 90 x 60 mm
×1
Addressable RGB LED Strip, 29 LEDs are needed for this project
×1
Aluminum Bar, 1/2"x1/8", cut length to fit LED strip
×1
Neoprene Tubing, 12mm internal diameter, cut length to fit LED strip
×1
JST Connectors and Crimper (optional)
×1
Pre-perforated Prototype Board, 3cm x 7cm min.
×1

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Custom parts and enclosures

Enclosure Layout - Open Office Draw file

Enclosure Layout - PDF file

Schematics

Breadboard Layout

Circuit Diagram

Pre-perforated Board Diagram

Code

Arduino Sketch

Arduino
#include "Adafruit_NeoPixel.h"
#include <arduinoFFT.h>

//LED STRIP VARIABLES
int leds=29; //number of LEDs in strip
int brightness=64; //overall brightness level of entire strip, 0 (off) to 255
int sat=255; //saturation from 0(grayscale) to 255(max sat.)
int val=64; //value (individual brightness) from 0(off) to 255(max)
int valMax=255; //max value of individual led brightness
uint32_t rgbColour; //used to convert HSV colour to RGB colour
long hueBottom; //hue value for top LED, selected with pot at hueBottomPin
long hueBottomMapped; //mapped to hueMin, hueMax range
long hueTop; //hue value for bottom LED, selected with pot at hueBottomPin
long hueTopMapped; //mapped to hueMin, hueMax range
long hueStep; //hue range (mapped) per led
long hue=43691; //calculated final hue value, from 65536(violet) to 0(red)
float k; //steepness of s-curve, read from k Pot as 0-1023
long hueSig[29]; //array to store hue (with s-curve applied) for each LED
long hueMin=0; //min possible hue: red
long hueMax=65536; //max possible hue: violet
int ledPin=3; //digital output pin to LED strip
int modeSwitchPin=2; //digital input pin for FFT/Colour Set switch
int audioPin=A0; //audio input pin
int satPin=A2; //saturation potentiometer pin
int brightnessPin=A1; //overall brightness potentiometer pin
int hueTopPin=A3; //top hue potentiometer pin
int hueBottomPin=A4; //bottom hue potentiometer pin
int kPin=A5; //s-curve steepness (k) potentiometer pin

Adafruit_NeoPixel strip = Adafruit_NeoPixel(leds, ledPin, NEO_GRB + NEO_KHZ800);

//FFT VARIABLES
const int bands=32;   //total number of frequency bands, must be <= SAMPLES/2
const int SAMPLES=64; //2x the number of freq bands. Must be a power of 2
const int audioIn=A0; //audio input is analog pin A0
double vReal[SAMPLES];
double vImag[SAMPLES];
arduinoFFT FFT = arduinoFFT(); //creates an FFT object

//This function causes the Nano to reset. It is necessary to initiate the Colour Set mode.
void(* resetFunc) (void) = 0;

void setup() {
  pinMode(modeSwitchPin,INPUT); //set modeSwitchPin as input
  delay(3000); //power-up safety delay
  strip.begin(); //initialize LED strip
  strip.show();  //initialize all pixels
}
 
void loop() {
  
  //While mode switch is low, set colours. Otherwise, perform FFT.
  while (digitalRead(modeSwitchPin)==LOW){
    
    //analogRead gives 0-1023 & brightness requires 1-255, so divide reading by 4
    brightness=analogRead(brightnessPin)/4; //read brightness pot
    strip.setBrightness(brightness); // set overall brightness
    //analogRead gives 0-1023 & sat requires 1-255, so divide reading by 4
    sat=analogRead(satPin)/4; //read brightness pot
    //read hueTop & hueBottom pots. analogRead gives 0-1023
    hueBottom=analogRead(hueBottomPin); //read hueBottom pot, 0-1023
    hueBottomMapped=map(hueBottom,0,1023,hueMin,hueMax);
    hueTop=analogRead(hueTopPin); //read hueTop pot, 0-1023
    hueTopMapped=map(hueTop,0,1023,hueMin,hueMax);
    hueStep=(hueTopMapped-hueBottomMapped)/leds;
    k=analogRead(kPin); //read k pot, 0-1023

    for (int i=0;i<leds;i++) { 
      hue = hueBottomMapped+(i*hueStep); //calculate hue for each of the LEDs
      Serial.print ("hue: ");
      Serial.print (hue);
      hueSig[i] = hueMax/(1+(pow(2.718,(0-(k/4000000))*(hue-(hueMax/2))))); //apply s-curve
      Serial.print ("hueSig: ");
      Serial.println (hueSig[i]);
      rgbColour = strip.ColorHSV(hueSig[i],sat,val); //calculate colour setting from HSV values
      strip.setPixelColor(i,rgbColour); //output RGB colour setting to LED
      strip.show(); //show the colour
      delay(10);
    }
  }

   //FFT sampling
  for(int i = 0; i < SAMPLES; i++){
    vReal[i] = analogRead(audioIn);
    Serial.println(vReal[i]);
    vImag[i] = 0;
  }

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

    //re-arrange FFT result to match with number of LEDs in strip
    int step = (SAMPLES/2)/bands; 
    for(int i=0; i<(SAMPLES/2); i+=step)  
    {
    vReal[i] = constrain(vReal[i],0,2047); //set max value for vReal
    vReal[i] = map(vReal[i], 0, 2047, 0, valMax); //map vReal values to brightness value range
    }

    //send to LED strip according to desired values
    for(int i=0; i<leds; i++)
    {
      val=vReal[i+3]; //ignore the bottom 3 freq. bands 0, 1 and 2 (they're always on)
      //Therefore, 29 LEDs will be addressed. This is why leds is set to 29, not 32.
      rgbColour = strip.ColorHSV(hueSig[i],sat,val); //calculate colour setting from HSV values
      strip.setPixelColor(i,rgbColour); //output RGB colour setting to LED
      strip.show(); //show the colour
     }

  //if mode switch is moved to Colour Set mode, reset Nano to re-initialize colour parameters
  if (digitalRead(modeSwitchPin)==LOW){
    resetFunc();
  }
}

Credits

marcaubin

marcaubin

0 projects • 0 followers

Comments