LED Light Show - Parsing Multiple Codes Together
Moderators: adafruit_support_bill, adafruit

LED Light Show - Parsing Multiple Codes Together

by davnirvana on Sun Dec 09, 2012 3:14 pm

Hi.

This is a continuation of a previous thread: http://forums.adafruit.com/viewtopic.php?f=25&t=34995. I thought I would make a new topic as we are entering a different subject.

I am trying to put together some code to power my light show which uses two LED sets --
1. a set of 50 12mm pixels, powered by 5V power supply. (similar to http://learn.adafruit.com/12mm-led-pixels/wiring)
and
2. a 3m LED strip from Adafruit, powered by 12V power supply. (http://learn.adafruit.com/rgb-led-strips/usage)

I found this person's code here http://projects.mathfarmer.com/home/12-band-color-organ-rgb-led which is used to control a rgd strand with Processing and minim to make the show react to frequency etc..

This is the processing code:

Code: Select all | TOGGLE FULL SIZE
// Requires Minim: http://code.compartmental.net/tools/minim/

import ddf.minim.analysis.*;
import ddf.minim.*;
import processing.serial.*;

// Sound Input and processing objects
Serial myPort;
Minim minim;
AudioInput myInput;
AudioOutput myOutput;
BeatDetect beat;
FFT fftL;
FFT fftR;
int bufferSize = 2048;
int minBeatPeriod = 300; // if new "beat" is < 300 ms after last beat, ignore it.

// Frequency analysis
float decay = 0.99f;
float thresBot = 0.3;
float thresTop = 0.9;
float[] peaks;
float[] peakSinceUpdate;
float[] noiseLvl;
float minPeak = 0.1; // Used to stop lights flickering at start due to inaudible noise
boolean trackNoiseLvl = false;
float maxPeak = 0;
int maxPeakIdx = 0;
int bandNumber;

// Color state
int posOffset = 0;
byte rr;
byte gg;
byte bb;

// Communications
boolean inputReady=false;
long lastUpdate;
byte[] drawState; // I'm assuming 15-bit light data
byte lowByte;
byte highByte;

// Constants to configure
int ledCount = 50;  //How many LEDs in your string.
int[] colorIndex = {
  0xff0000, 0xff0000, 0xff0000, 0xffff00, 0x00ff00, 0x00ff00,
  0x00ff00, 0x0000ff, 0x0000ff, 0x0000ff, 0xff00ff, 0xff00ff
}; // Standard HTML 24-bit RGB hex color notation.
int bandLimit = 12;
int startingQ = 55;
int octaveDivisions = 2;

// ********** BEGIN ***********
void setup() { 
  // Init all the sound objects
  minim = new Minim(this);
  myInput = minim.getLineIn(Minim.STEREO, bufferSize);
  fftL = new FFT(myInput.bufferSize(), myInput.sampleRate());
  fftL.logAverages(startingQ,octaveDivisions);
  fftL.window(FFT.HAMMING);
  fftR = new FFT(myInput.bufferSize(), myInput.sampleRate());
  fftR.logAverages(startingQ,octaveDivisions);
  fftR.window(FFT.HAMMING);
  beat = new BeatDetect(myInput.bufferSize(), myInput.sampleRate());
  beat.setSensitivity(minBeatPeriod);

  // Init tracking data
  drawState = new byte[ledCount*2 + 2];
  drawState[ledCount*2] = 0; drawState[ledCount*2 + 1] = 0; // Terminating bytes
  bandNumber = min(bandLimit, fftL.avgSize());
  peaks = new float[bandNumber];
  peakSinceUpdate = new float[bandNumber];
  noiseLvl = new float[bandNumber];
  for (int i = 0; i < bandNumber; ++i) peaks[i] = minPeak;

  // Init communications
  String portName = Serial.list()[0];
  println(portName);
  myPort = new Serial(this, portName, 57600);
  lastUpdate = millis();
}

void draw() {
  beat.detect(myInput.mix);
  fftL.forward(myInput.left);
  fftR.forward(myInput.right);

  checkPeaks();

  colorOrgan();

  updateScreen();
}

void checkPeaks() {
  boolean newPeak = false;
  boolean newMaxPeak = false;

  // Grab the new level data. Check to see if it represents a new peak.
  //   Also check to see if there is a new max peak.
  //   If there are no new peaks, decay the levels of the current peaks.
  //     (this acts as a primitive auto-level control, and helps emphasize
  //      changes in volume)
  for (int i=0; i < bandNumber; i++) {
    if (fftL.getAvg(i) + fftR.getAvg(i) > peaks[i]) {
      peaks[i] = fftL.getAvg(i) + fftR.getAvg(i);
     
      if (peaks[i] > maxPeak) {
        newMaxPeak = true;
        maxPeak = peaks[i];
        maxPeakIdx = i;
      }
    }
    if (!newPeak) {
      peaks[i] *= decay;
      if (peaks[i] < minPeak) peaks[i] = minPeak;
    }
  }
  if (!newMaxPeak) {
    maxPeak *= decay;
    if (maxPeak < minPeak) maxPeak = minPeak;
  }

  // Raise the other peaks based on the max peak. This allows a few
  //   fequency bands to dominate the display when those frequencies also
  //   dominate the sound spectrum. The power function makes more distant
  //   frequency bands less affected by this shaping. The value of 0.8
  //   (and heck, the function) was the result of crude experimentation.
  //   There are probably better methods for this, but it seems to do
  //   about what I want.
  for (int i = 0; i < bandNumber; i++) {
    float peakTop = maxPeak*(pow(0.8,abs(i-maxPeakIdx)));
    if (peaks[i] < peakTop) peaks[i] = peakTop;
  }

  if (trackNoiseLvl) setNoiseFloor();
 
  // I'm not sure I'm totally sold on this. It seems a little busy.
  if (beat.isKick()) posOffset++;
  if (posOffset >= bandNumber) posOffset = 0;
}

void colorOrgan() {

  for (int i=0; i < bandNumber; i++) {
    int col = colorIndex[i%colorIndex.length];
    float amp = fftL.getAvg(i) + fftR.getAvg(i);
   
    // Check noise threshold. If above, normalize amp to [0-1].
    if (amp > noiseLvl[i]) amp = (amp)/peaks[i];
    else amp = 0;

    // Shape the band levels. Peg values above or below the upper and lower
    //   bounds. Remap the middle so that it covers the full range. Less space
    //   between the bounds makes things blinkier.
    if (amp < thresBot) amp = 0;
    else if (amp > thresTop) amp = 1;
    else amp = amp/(thresTop - thresBot) - thresBot;
    if (amp < 0) amp = 0;
    else if (amp > 1) amp = 1;

    // Hold on the biggest amplitudes we've seen since the last update. This
    //   is so that we don't lose transients if it takes too long to communicate
    //   with the lights. I'm not sure how much of a difference this makes
    //   though.
    if (amp > peakSinceUpdate[i]) peakSinceUpdate[i]=amp; else amp=peakSinceUpdate[i];

    // Set the colors from the amplitudes
    rr = (byte)( ((col&0xff0000) >> 16)*amp );
    gg = (byte)( ((col&0x00ff00) >> 8)*amp  );
    bb = (byte)( ((col&0x0000ff)     )*amp  );

    // Set the communications byte array from the colors.
    lowByte = (byte)(rgbTo15bit(rr, gg, bb) >>> 8);
    highByte = (byte)(rgbTo15bit(rr, gg, bb) &0x00ff);

    // Place the bytes in the array. If there fewer bands than lights,
    //   repeat until we run out of lights.
    //   (There is almost certainly a better way to do this...)
    for (int j=0; ((i+posOffset)%bandNumber)*2+j+1 < ledCount*2; j+=bandNumber*2) {
      drawState[((i+posOffset)%bandNumber)*2+j] = lowByte;
      drawState[((i+posOffset)%bandNumber)*2+j+1] = highByte;
    }
  }
}

void updateScreen() {
  // Wait until the controller sends back a byte to indicate that it is ready, then
  //   send the current state.
  if (myPort.available() > 0) {
    myPort.clear();
    myPort.write(0); myPort.write(0);
    myPort.write(drawState);
   
    clearPSU();
   
    lastUpdate = millis();
  } // else println(millis() - lastUpdate);
}

public void stop() {
  // always close Minim audio classes when you are done with them
  myInput.close();
  myOutput.close();
  minim.stop();

  super.stop();
}

int rgbTo15bit( byte rr, byte gg, byte bb ) {
  return ((rr&0xf8)<<7)|((gg&0xf8)<<2)|((bb&0xf8)>>>3)|0x8000;
}

void clearPSU() {
  for (int i = 0; i<bandNumber; ++i) {
    peakSinceUpdate[i] = 0;
  }
}

// This is used primarily when taking audio from an external input. Since
//   I automatically reset levels based on recent input volume, even a
//   small amount of noise from the external source will eventually light
//   up some of the lights, which can ruin the effect of quiet passages
//   in the music. The somewhat crude solution is to set a noise threshold
//   when no music is playing. Sound must exceed the volume of the noise in
//   order to be recognized. This check is done on a per-band basis, so a
//   lot of noise in one band (e.g. a 60Hz hum) won't interfere with the
//   sensitivity of other bands.
//
//   Anyways, to set the noise threshold, hold down 'n' when no music is
//   playing to sample the noise.
void keyPressed() {
  if ( key == 'n' ) {
    if (!trackNoiseLvl) {
      for (int i=0; i < fftL.avgSize(); i++) {

        noiseLvl[i] = 0;
      }
      trackNoiseLvl = true;
    }
  }
}

void keyReleased() {
  if ( key == 'n' ) {
    trackNoiseLvl = false;
  }
}

void setNoiseFloor() {
  for (int i=0; i < bandNumber; i++) {
    if (fftL.getAvg(i)+fftR.getAvg(i) > noiseLvl[i]) {
      noiseLvl[i] = fftL.getAvg(i)+fftR.getAvg(i);
    }
  }
}


They also supply this code for the Arduino:

Code: Select all | TOGGLE FULL SIZE
// Requires the SPI library found here: http://arduino.cc/playground/Code/SPI

#include <SPI.h>

#define MAX_LED_COUNT 1000

byte counter;
byte inByte;
byte zeroCount = 0;

void setup()
{
  SPI.transfer(0);
  SPI.transfer(0);
  for (int i = 0; i <  MAX_LED_COUNT; ++i) {
    SPI.transfer(0x80);
    SPI.transfer(0x00);
  }
  SPI.transfer(0);
  SPI.transfer(0);
  Serial.begin(57600);
  counter = 0;
}

void loop() {
  if (Serial.available() > 0) {
    // get incoming byte
    inByte = Serial.read();
    counter++;
   
    if (inByte == 0) zeroCount++;
    else zeroCount = 0;
   
    SPI.transfer(inByte);
   
    if (zeroCount >= 2) {
      SPI.transfer(0);
      SPI.transfer(0);
      counter = 0;
      Serial.write(17);
    }
  }
  else if (counter == 0) {
    Serial.write(17);
  }
}


That said, I have been unable to make this work as I am using a strip with the LPD6803 chip. I have looked into different drivers for this but I am unsure how that all fits in with the above.

I also wish to drive a LED strip. Adafruit supplies example code with it as such:
Code: Select all | TOGGLE FULL SIZE
// color swirl! connect an RGB LED to the PWM pins as indicated
// in the #defines
// public domain, enjoy!
 
#define REDPIN 5
#define GREENPIN 6
#define BLUEPIN 3
 
#define FADESPEED 5     // make this higher to slow down
 
void setup() {
  pinMode(REDPIN, OUTPUT);
  pinMode(GREENPIN, OUTPUT);
  pinMode(BLUEPIN, OUTPUT);
}
 
 
void loop() {
  int r, g, b;
 
  // fade from blue to violet
  for (r = 0; r < 256; r++) {
    analogWrite(REDPIN, r);
    delay(FADESPEED);
  }
  // fade from violet to red
  for (b = 255; b > 0; b--) {
    analogWrite(BLUEPIN, b);
    delay(FADESPEED);
  }
  // fade from red to yellow
  for (g = 0; g < 256; g++) {
    analogWrite(GREENPIN, g);
    delay(FADESPEED);
  }
  // fade from yellow to green
  for (r = 255; r > 0; r--) {
    analogWrite(REDPIN, r);
    delay(FADESPEED);
  }
  // fade from green to teal
  for (b = 0; b < 256; b++) {
    analogWrite(BLUEPIN, b);
    delay(FADESPEED);
  }
  // fade from teal to blue
  for (g = 255; g > 0; g--) {
    analogWrite(GREENPIN, g);
    delay(FADESPEED);
  }
}


So how should I start to put all of this together in a workable program?

Thank you so much. Looking forward to the work. Hopefully this will be helpful to other users.

-David
davnirvana
 
Posts: 10
Joined: Tue Sep 04, 2012 12:50 pm

Re: LED Light Show - Parsing Multiple Codes Together

by adafruit_support_bill on Mon Dec 10, 2012 7:03 am

Moved to "Glowy Things"...
User avatar
adafruit_support_bill
 
Posts: 31676
Joined: Sat Feb 07, 2009 10:11 am



cron