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

Software apps and online services

Arduino IDE
Arduino IDE

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)


Read more

Custom parts and enclosures

Enclosure Layout - Open Office Draw file

Enclosure Layout - PDF file


Breadboard Layout

Circuit Diagram

Pre-perforated Board Diagram


Arduino Sketch

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

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);

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;  //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
    hueTop=analogRead(hueTopPin); //read hueTop pot, 0-1023
    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; //show the colour

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

    //FFT computation
    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; //show the colour

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




0 projects • 0 followers