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- ... an-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
// 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);
}
}
}
Code: Select all
// 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);
}
}
I also wish to drive a LED strip. Adafruit supplies example code with it as such:
Code: Select all
// 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);
}
}
Thank you so much. Looking forward to the work. Hopefully this will be helpful to other users.
-David