Pages: [1]   Go Down
Author Topic: Parsing Code together to Create LED Light show  (Read 580 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,


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 (similar to http://learn.adafruit.com/12mm-led-pixels/wiring)
and
2. a 3m LED strip from Adafruit (http://learn.adafruit.com/rgb-led-strips/usage)

I found this 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:
// 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);
    }
  }
}

To be continued...
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

They also supply this code for the Arduino:

Code:
// 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.

To be continued...I also wish to drive a LED strip. Adafruit supplies example code with it as such:

Code:
// 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.

-David
Logged

Manchester (England England)
Online Online
Brattain Member
*****
Karma: 508
Posts: 31397
Solder is electric glue
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Parsing means splitting apart, you are not "Parsing" anything. Please modify the title so it is not confusing.

For joining code together there is the following page that might help:-
http://www.thebox.myzen.co.uk/Tutorial/Merging_Code.html
Logged

Pages: [1]   Go Up
Jump to: