How to make VU Meter with Pixel LEDs using Sound Sensor







            CODE 

 #include <Adafruit_NeoPixel.h>


#define LED_PIN 6

#define LED_COUNT 60

#define MIC_PIN A0


Adafruit_NeoPixel strip(LED_COUNT, LED_PIN, NEO_GRB + NEO_KHZ800);


int center = LED_COUNT / 2;


float smoothedLevel = 0;

float ballPos = 0;


const float fallSpeed = 0.20;   // Gravity fall speed

float sensitivity = 5.0;        // Adjust: 2–6 for bass intensity


int noiseFloor = 0;


void setup() {

  strip.begin();

  strip.show();

  Serial.begin(9600);


  // Detect ambient noise floor

  long sum = 0;

  for (int i = 0; i < 300; i++) {

    sum += analogRead(MIC_PIN);

    delay(4);

  }

  noiseFloor = sum / 300;

}


void loop() {

  int micValue = analogRead(MIC_PIN);

  int soundLevel = abs(micValue - noiseFloor);


  if (soundLevel < 5) soundLevel = 0;


  soundLevel *= sensitivity;


  int level = map(soundLevel, 0, 50, 0, center);

  level = constrain(level, 0, center);


  // Smooth bar movement

  smoothedLevel = (smoothedLevel * 0.85) + (level * 0.15);


  // 🔴 Gravity ball control

  if (smoothedLevel > ballPos) ballPos = smoothedLevel;   // Jump

  ballPos -= fallSpeed;                                   // Fall slowly

  if (ballPos < 0) ballPos = 0;


  strip.clear();


  // 🔴 Center LED always RED

  strip.setPixelColor(center, 255, 0, 0);


  // 🎨 Smooth gradient color bars

  for (int i = 1; i < smoothedLevel; i++) {

    int leftPixel  = center - i;

    int rightPixel = center + i;


    byte r = 0, g = 0, b = 0;

    float percent = (float)i / center;


    if (percent <= 0.25) { // Blue → Green

      float t = percent / 0.25;

      r = 0;

      g = 255 * t;

      b = 255 * (1 - t);

    }

    else if (percent <= 0.50) { // Green → Yellow

      float t = (percent - 0.25) / 0.25;

      r = 255 * t;

      g = 255;

      b = 0;

    }

    else if (percent <= 0.75) { // Yellow → Orange

      float t = (percent - 0.50) / 0.25;

      r = 255;

      g = 255 - (175 * t);

      b = 0;

    }

    else { // Orange → Red

      float t = (percent - 0.75) / 0.25;

      r = 255;

      g = 10 * (1 - t);

      b = 0;

    }


    // ⚠ Skip pixels that overlap with ball or center

    if (leftPixel != center - ballPos && leftPixel >= 0)

      strip.setPixelColor(leftPixel, r, g, b);


    if (rightPixel != center + ballPos && rightPixel < LED_COUNT)

      strip.setPixelColor(rightPixel, r, g, b);

  }


  // 🔵 Dynamic 0–5 blue LEDs per side (bass reactive)

  int bassLEDs = map(soundLevel, 0, 300, 0, 5);

  bassLEDs = constrain(bassLEDs, 0, 5);


  for (int j = 0; j < bassLEDs; j++) {

    int leftPeak  = center - ballPos - j;

    int rightPeak = center + ballPos + j;


    // ⚠ Only if not center or ball position

    if (leftPeak >= 0 && leftPeak != center && leftPeak != center - ballPos)

      strip.setPixelColor(leftPeak, 0, 0, 255);


    if (rightPeak < LED_COUNT && rightPeak != center && rightPeak != center + ballPos)

      strip.setPixelColor(rightPeak, 0, 0, 255);

  }


  // 🔴 Gravity balls (RED)

  int leftBall  = center - ballPos;

  int rightBall = center + ballPos;


  if (leftBall >= 0)

    strip.setPixelColor(leftBall, 255, 0, 0);


  if (rightBall < LED_COUNT)

    strip.setPixelColor(rightBall, 255, 0, 0);


  strip.show();

  delay(1);

}

Post a Comment

Previous Post Next Post

Contact Form