Project tutorial
Arduino Audio Reactive Desk Light

Arduino Audio Reactive Desk Light © GPL3+

It is the amazing RGB LED desk light. It will be reacting on the surrounding sound and music and will be playing like a visualizer.

  • 18,447 views
  • 6 comments
  • 42 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)

Apps and online services

About this project

HELLO WORLD!!

Hi! In this build we’ll make a good looking light that dances to all sounds and music, using simple components and some basic Arduino programming. It makes an awesome effect while standing on the desk when gaming, playing music, and anything else that makes sound really. Let’s get going!

This is a project that i follow based on the youtuber's "Natural Nerd" that they done. This is my version of the project. All credit goes to them and a big shout out to them for provide me the detail on how to do the project.

Youtube link

STEP 1: MAIN SUPPLIES

First things first: what kind of supplies do we need and what do they cost? Well, they are largely optional, and can be made with much improvisation. Even so, some key items are needed if you want to follow this guide:

  • Individually Addressable LED strips 60 leds per. meter (buy link)

Depending on the look you want, you might want to arrange the strips differently or diffuse the light in another way. This is where you can be creative. If you like my approach, I used the following items:

  • A small length of PVC pipe.
  • Foam Board
  • Hot Glue Gun

All things considered I spent around RM 83.30 depending on the store that you go and buy the items, where the LED strips were by far the most expensive part that cost me RM 40 for only 1 Meter.

STEP 2: POWERING THE COMPONENTS

The powering the component will be a straight forward method. I just using the Arduino Nano's USB cable and directly plug in to the pc. If you using the external power supply such as AC to DC power source, you will be needed a step down module to help you reduce the amount of the current flow to your circuit. Otherwise, if you not using it and you might have a very high chance to burn the Arduino including the components that connected.

The star of the show is the sound detector module. This will provide an analog signal to the Arduino, which we can use to (hopefully) cleverly light the RGB lights. To be able to do this, we need to power both devices. Luckily they both require a 5 volt input. I am using a step down module to step down from 12 volts to 5 volts, but it would be easier to use a 5 volt power source directly. Wire the VIN on the Arduino and on the sound detector board to the positive input. Then wire the GND on the Arduino and the detector to the negative. Look at the black and the red wires on the attached schematic. We also need to hook the positive and negative input on the LED-strip to the power source.

STEP 3: DETECTOR & STRIPS

After having connected all three parts to the power, we need to connect them to each other.

The sound detector module will communicate with the Arduino over the analog input pins. I will be using pin number 0 in this case.

The LED strips need a digital pulse to be able to understand which LED we want to address. Hence we need to connect a digital output pin to the Arduino nano. I will using pin number 6.

Use the shrinking tube on to the choose area so that the cable won't collided with each other in a tight space later.

Just follow the schematic diagram that i provided in here and you will be fine!

Awesome, now we are mostly done with the electronics!

STEP 4: UPLOADING THE CODE

The most important part of this build will arguably be the code. It can change this build from pretty cool to insanely awesome. You can use the code that i provided together with this project. The main principle is to map the analog value we get from the sensor, to an amount of LEDs to show.

STEP 5: PREPARING THE CASING

First I thought the lid was made out of acrylic, after i bought the jar and realize it was not a acrylic but a glass. So i need to re-adjust my plan by making a cover that easy to poke and mount the Arduino and the led. So i choose the foam board.

First step, i need to cut the foam board having it exactly circular and have the same diameter as the jar's glass cover. I does not have the proper measuring diameter tools , so i improvise the method by using wet marker and mark the diameter of the glass and stamp it on a pieces of paper. After that, i paste the paper on to the foam board and but the board by following the edge of the circle on the paper. It's not perfect but it should be good enough to hold all the Arduino and led component.

Second step, i need to break the glass on the jar lid. CAUTION! please cover the jar with a thick plastic bag to prevent the glass scatter around the room and do it at the open space. Aware with your surrounding. After breaking the glass, please make sure all the glass that stuck at the side crack of the jar lid to be remove. This is to prevent you or other from getting an injury from cutting them self to the stuck glass.

Third step, place the circle shaped foam board at the center of the jar lid. Make sure the foam are tight and not too loose that they just fit nicely with the jar.

Forth step, i just realize that i need to change the layout of this project. i would like to make that the user will be easy to access the Arduino component's in case of faulty. So, i decided to use the mini breadboard and placed it at the center of the lid. Not only that, i cut two holes for the cable from the Sound Module that i will be placing at bottom of the jar lid to go inside the jar and onto the breadboard and one more hole for the Arduino to connect with the USB cable to act as the power supply for the circuit.

Fifth step, I mark the pvc pipe with masking tape and draw the line at the center of the tape. Then, i tape it at the pvc pipe. The marking are the indicator of me to cut the pvc pipe evenly and trying to having a clean cut.

After measuring the amount of length of pvc i need to use, i cut it carefully by following the mark that i provided. The length of the pvc pipe are depend on your jar height. You may use any length that you desire.

Sixth step, i warp the PVC pipe that i cut with the LED strip around it and make it slightly slanted and going spiral to the top of the PVC. I make sure that i create a small hole for the excess cable length to be hide inside the PVC jar for cable management. I then need to find a way to stand the PVC onto the breadboard. Using hot glue gun or the double-sided tape, i able to tape the PVC pipe on to the extra foam board then paste it on the unused area at the breadboard. During this step, i able to connect some of the component to the breadboard.

Use the schematic diagram provided to connect all the component.

(The left-area of breadboard will be the positive and the right-area of the breadboard will be the negative. `

Seventh step, i placed the sound module at the outside of the jar lid. This is purposely done for the module ease of picking the sound outside the jar later. After placing the module, connect it with cable and match it as stated in the schematic diagram given. Then, connect all the cable with the sensor and Arduino to breadboard. The Arduino being setup vertically so that the cable for powering up the curcuit will able to connect with Arduino board easily through the foam board.

And thus, I complete the project. I takes a while plus with the try and error but I managed to complete it.

Final Product that match with my gaming desk

Code

Coding For the ArduinoArduino
This code will enable the LED to react to the sound that being detected by the sound module.
#include <FastLED.h>

/** BASIC CONFIGURATION  **/

//The amount of LEDs in the setup
#define NUM_LEDS 60
//The pin that controls the LEDs
#define LED_PIN 6
//The pin that we read sensor values form
#define ANALOG_READ 0

//Confirmed microphone low value, and max value
#define MIC_LOW 0.0
#define MIC_HIGH 200.0
/** Other macros */
//How many previous sensor values effects the operating average?
#define AVGLEN 5
//How many previous sensor values decides if we are on a peak/HIGH (e.g. in a song)
#define LONG_SECTOR 20

//Mneumonics
#define HIGH 3
#define NORMAL 2

//How long do we keep the "current average" sound, before restarting the measuring
#define MSECS 30 * 1000
#define CYCLES MSECS / DELAY

/*Sometimes readings are wrong or strange. How much is a reading allowed
to deviate from the average to not be discarded? **/
#define DEV_THRESH 0.8

//Arduino loop delay
#define DELAY 1

float fscale( float originalMin, float originalMax, float newBegin, float newEnd, float inputValue, float curve);
void insert(int val, int *avgs, int len);
int compute_average(int *avgs, int len);
void visualize_music();

//How many LEDs to we display
int curshow = NUM_LEDS;

/*Not really used yet. Thought to be able to switch between sound reactive
mode, and general gradient pulsing/static color*/
int mode = 0;

//Showing different colors based on the mode.
int songmode = NORMAL;

//Average sound measurement the last CYCLES
unsigned long song_avg;

//The amount of iterations since the song_avg was reset
int iter = 0;

//The speed the LEDs fade to black if not relit
float fade_scale = 1.2;

//Led array
CRGB leds[NUM_LEDS];

/*Short sound avg used to "normalize" the input values.
We use the short average instead of using the sensor input directly */
int avgs[AVGLEN] = {-1};

//Longer sound avg
int long_avg[LONG_SECTOR] = {-1};

//Keeping track how often, and how long times we hit a certain mode
struct time_keeping {
  unsigned long times_start;
  short times;
};

//How much to increment or decrement each color every cycle
struct color {
  int r;
  int g;
  int b;
};

struct time_keeping high;
struct color Color; 

void setup() {
  Serial.begin(9600);
  //Set all lights to make sure all are working as expected
  FastLED.addLeds<NEOPIXEL, LED_PIN>(leds, NUM_LEDS);
  for (int i = 0; i < NUM_LEDS; i++) 
    leds[i] = CRGB(0, 0, 255);
  FastLED.show(); 
  delay(1000);  

  //bootstrap average with some low values
  for (int i = 0; i < AVGLEN; i++) {  
    insert(250, avgs, AVGLEN);
  }

  //Initial values
  high.times = 0;
  high.times_start = millis();
  Color.r = 0;  
  Color.g = 0;
  Color.b = 1;
}

/*With this we can change the mode if we want to implement a general 
lamp feature, with for instance general pulsing. Maybe if the
sound is low for a while? */
void loop() {
  switch(mode) {
    case 0:
      visualize_music();
      break;
    default:
      break;
  }
    delay(DELAY);       // delay in between reads for stability
}


/**Funtion to check if the lamp should either enter a HIGH mode,
or revert to NORMAL if already in HIGH. If the sensors report values
that are higher than 1.1 times the average values, and this has happened
more than 30 times the last few milliseconds, it will enter HIGH mode. 
TODO: Not very well written, remove hardcoded values, and make it more
reusable and configurable.  */
void check_high(int avg) {
  if (avg > (song_avg/iter * 1.1))  {
    if (high.times != 0) {
      if (millis() - high.times_start > 200.0) {
        high.times = 0;
        songmode = NORMAL;
      } else {
        high.times_start = millis();  
        high.times++; 
      }
    } else {
      high.times++;
      high.times_start = millis();

    }
  }
  if (high.times > 30 && millis() - high.times_start < 50.0)
    songmode = HIGH;
  else if (millis() - high.times_start > 200) {
    high.times = 0;
    songmode = NORMAL;
  }
}

//Main function for visualizing the sounds in the lamp
void visualize_music() {
  int sensor_value, mapped, avg, longavg;
  
  //Actual sensor value
  sensor_value = analogRead(ANALOG_READ);
  
  //If 0, discard immediately. Probably not right and save CPU.
  if (sensor_value == 0)
    return;

  //Discard readings that deviates too much from the past avg.
  mapped = (float)fscale(MIC_LOW, MIC_HIGH, MIC_LOW, (float)MIC_HIGH, (float)sensor_value, 2.0);
  avg = compute_average(avgs, AVGLEN);

  if (((avg - mapped) > avg*DEV_THRESH)) //|| ((avg - mapped) < -avg*DEV_THRESH))
    return;
  
  //Insert new avg. values
  insert(mapped, avgs, AVGLEN); 
  insert(avg, long_avg, LONG_SECTOR); 

  //Compute the "song average" sensor value
  song_avg += avg;
  iter++;
  if (iter > CYCLES) {  
    song_avg = song_avg / iter;
    iter = 1;
  }
    
  longavg = compute_average(long_avg, LONG_SECTOR);

  //Check if we enter HIGH mode 
  check_high(longavg);  

  if (songmode == HIGH) {
    fade_scale = 3;
    Color.r = 5;
    Color.g = 3;
    Color.b = -1;
  }
  else if (songmode == NORMAL) {
    fade_scale = 2;
    Color.r = -1;
    Color.b = 2;
    Color.g = 1;
  }

  //Decides how many of the LEDs will be lit
  curshow = fscale(MIC_LOW, MIC_HIGH, 0.0, (float)NUM_LEDS, (float)avg, -1);

  /*Set the different leds. Control for too high and too low values.
          Fun thing to try: Dont account for overflow in one direction, 
    some interesting light effects appear! */
  for (int i = 0; i < NUM_LEDS; i++) 
    //The leds we want to show
    if (i < curshow) {
      if (leds[i].r + Color.r > 255)
        leds[i].r = 255;
      else if (leds[i].r + Color.r < 0)
        leds[i].r = 0;
      else
        leds[i].r = leds[i].r + Color.r;
          
      if (leds[i].g + Color.g > 255)
        leds[i].g = 255;
      else if (leds[i].g + Color.g < 0)
        leds[i].g = 0;
      else 
        leds[i].g = leds[i].g + Color.g;

      if (leds[i].b + Color.b > 255)
        leds[i].b = 255;
      else if (leds[i].b + Color.b < 0)
        leds[i].b = 0;
      else 
        leds[i].b = leds[i].b + Color.b;  
      
    //All the other LEDs begin their fading journey to eventual total darkness
    } else {
      leds[i] = CRGB(leds[i].r/fade_scale, leds[i].g/fade_scale, leds[i].b/fade_scale);
    }
  FastLED.show(); 
}
//Compute average of a int array, given the starting pointer and the length
int compute_average(int *avgs, int len) {
  int sum = 0;
  for (int i = 0; i < len; i++)
    sum += avgs[i];

  return (int)(sum / len);

}

//Insert a value into an array, and shift it down removing
//the first value if array already full 
void insert(int val, int *avgs, int len) {
  for (int i = 0; i < len; i++) {
    if (avgs[i] == -1) {
      avgs[i] = val;
      return;
    }  
  }

  for (int i = 1; i < len; i++) {
    avgs[i - 1] = avgs[i];
  }
  avgs[len - 1] = val;
}

//Function imported from the arduino website.
//Basically map, but with a curve on the scale (can be non-uniform).
float fscale( float originalMin, float originalMax, float newBegin, float
    newEnd, float inputValue, float curve){

  float OriginalRange = 0;
  float NewRange = 0;
  float zeroRefCurVal = 0;
  float normalizedCurVal = 0;
  float rangedValue = 0;
  boolean invFlag = 0;


  // condition curve parameter
  // limit range

  if (curve > 10) curve = 10;
  if (curve < -10) curve = -10;

  curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output 
  curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function

  // Check for out of range inputValues
  if (inputValue < originalMin) {
    inputValue = originalMin;
  }
  if (inputValue > originalMax) {
    inputValue = originalMax;
  }

  // Zero Refference the values
  OriginalRange = originalMax - originalMin;

  if (newEnd > newBegin){ 
    NewRange = newEnd - newBegin;
  }
  else
  {
    NewRange = newBegin - newEnd; 
    invFlag = 1;
  }

  zeroRefCurVal = inputValue - originalMin;
  normalizedCurVal  =  zeroRefCurVal / OriginalRange;   // normalize to 0 - 1 float

  // Check for originalMin > originalMax  - the math for all other cases i.e. negative numbers seems to work out fine 
  if (originalMin > originalMax ) {
    return 0;
  }

  if (invFlag == 0){
    rangedValue =  (pow(normalizedCurVal, curve) * NewRange) + newBegin;

  }
  else     // invert the ranges
  {   
    rangedValue =  newBegin - (pow(normalizedCurVal, curve) * NewRange); 
  }

  return rangedValue;
}

Schematics

Schematic Diagram
Fn6z310iy3ct3yu large  sgq3pbxrei

Comments

Similar projects you might like

Music Reactive LED Strip

Project showcase by buzzandy

  • 60,124 views
  • 74 comments
  • 132 respects

Rings of Saturn LED Music Visualizing Pendant Light

Project tutorial by Modustrial Maker

  • 6,427 views
  • 2 comments
  • 36 respects

Arduino-Powered Smart Light (Works with Amazon Echo)

Project tutorial by Tinker Project

  • 22,338 views
  • 8 comments
  • 40 respects

Arduino Traffic Light Simulator

Project tutorial by Zachary Haslam

  • 15,708 views
  • 5 comments
  • 35 respects

Light Sequence Creator

Project tutorial by Reid Paulhus

  • 10,110 views
  • 3 comments
  • 22 respects

The Light Box

Project tutorial by Wpeeters

  • 4,687 views
  • 2 comments
  • 21 respects
Add projectSign up / Login