Last active
December 21, 2015 14:49
-
-
Save smukkejohan/6322733 to your computer and use it in GitHub Desktop.
Burning Man Lanterns - Lost Connections
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <lightuino5.h> | |
static int lantern_number=8; // number of lanterns | |
float x1,y1,x2,y2,persistence; | |
int octaves; | |
int i=0,val,volume; | |
int numPatterns = 6; // store the number of patterns | |
int currentPattern=0; // the current pattern being shown on the LEDs | |
long switchTime=60000; // time (in ms) between switching patterns | |
long lastPatternTime; // last time in millis that the light pattern was changed | |
long lastsamplemicros; // store the last time a microphone sample was taken, so the next read will be 1ms later. | |
long lastsamplelooptime; // store the last time we started sampling for performance testing. | |
////// Sound Sampling | |
float subbassr, subbassi, subbass; // real and imaginary parts of each frequency being sampled, and the measured amplitude at that frequency | |
float bassr, bassi, bass; | |
float midr, midi, mid; | |
float trebr, trebi, treb; | |
const prog_int8_t Sinewave[256] PROGMEM = { | |
0, 3, 6, 9, 12, 15, 18, 21, | |
24, 28, 31, 34, 37, 40, 43, 46, | |
48, 51, 54, 57, 60, 63, 65, 68, | |
71, 73, 76, 78, 81, 83, 85, 88, | |
90, 92, 94, 96, 98, 100, 102, 104, | |
106, 108, 109, 111, 112, 114, 115, 117, | |
118, 119, 120, 121, 122, 123, 124, 124, | |
125, 126, 126, 127, 127, 127, 127, 127, | |
127, 127, 127, 127, 127, 127, 126, 126, | |
125, 124, 124, 123, 122, 121, 120, 119, | |
118, 117, 115, 114, 112, 111, 109, 108, | |
106, 104, 102, 100, 98, 96, 94, 92, | |
90, 88, 85, 83, 81, 78, 76, 73, | |
71, 68, 65, 63, 60, 57, 54, 51, | |
48, 46, 43, 40, 37, 34, 31, 28, | |
24, 21, 18, 15, 12, 9, 6, 3, | |
0, -3, -6, -9, -12, -15, -18, -21, | |
-24, -28, -31, -34, -37, -40, -43, -46, | |
-48, -51, -54, -57, -60, -63, -65, -68, | |
-71, -73, -76, -78, -81, -83, -85, -88, | |
-90, -92, -94, -96, -98, -100, -102, -104, | |
-106, -108, -109, -111, -112, -114, -115, -117, | |
-118, -119, -120, -121, -122, -123, -124, -124, | |
-125, -126, -126, -127, -127, -127, -127, -127, | |
-127, -127, -127, -127, -127, -127, -126, -126, | |
-125, -124, -124, -123, -122, -121, -120, -119, | |
-118, -117, -115, -114, -112, -111, -109, -108, | |
-106, -104, -102, -100, -98, -96, -94, -92, | |
-90, -88, -85, -83, -81, -78, -76, -73, | |
-71, -68, -65, -63, -60, -57, -54, -51, | |
-48, -46, -43, -40, -37, -34, -31, -28, | |
-24, -21, -18, -15, -12, -9, -6, -3 | |
}; | |
// timer code is taken from http://www.uchobby.com/index.php/2007/11/24/arduino-interrupts/ | |
#define TIMER_CLOCK_FREQ (F_CPU/1024.0) //Found this frequency by trial and error | |
unsigned int timer1Latency; | |
unsigned int timer1LoadValue; | |
unsigned char timerCounter = 0; | |
ISR(TIMER1_OVF_vect) { | |
val = analogRead(0)/4 -128; | |
subbassr += val * Sinewave[timerCounter * 16 % 256]; //62 hertz | |
subbassi += val * Sinewave[(timerCounter * 16 + 64 ) % 256]; | |
bassr += val * Sinewave[timerCounter * 31 % 256]; // 121 hertz | |
bassi += val * Sinewave[(timerCounter * 31 + 64 ) % 256]; | |
midr += val * Sinewave[timerCounter * 200 % 256]; //781 hertz | |
midi += val * Sinewave[(timerCounter * 130 + 64 ) % 256]; | |
trebr += val * Sinewave[timerCounter * 768 % 256]; //3000 hertz | |
trebi += val * Sinewave[(timerCounter * 768 + 64 ) % 256]; | |
timerCounter++; | |
//Capture the current timer value. This is how much error we have | |
//due to interrupt latency and the work in this function | |
timer1Latency=TCNT1; | |
//Reload the timer and correct for latency. | |
TCNT1=timer1Latency+timer1LoadValue; | |
} | |
void StartSoundSampling(float timeoutFrequency) | |
{ | |
//Calculate the timer load value | |
timer1LoadValue=(unsigned int)((65535-(TIMER_CLOCK_FREQ/timeoutFrequency))+0.5); //the 0.5 is for rounding; | |
TCCR1A = 0; | |
TCCR1B = 1<<CS22 | 0<<CS21 | 1<<CS20; | |
//Timer2 Overflow Interrupt Enable | |
TIMSK1 = 1<<TOIE2; | |
//load the timer for its first cycle | |
TCNT1=timer1LoadValue; | |
} | |
// Create the basic Lightuino 70 LED sink controller (the pins in the 2 40-pin IDE connectors) | |
LightuinoSink sinks; | |
// Create the Lightuino 16 channel source driver controller (the 16 pin connector) | |
LightuinoSourceDriver sources; | |
// This object PWMs the Lightuino sinks allowing individual LED brightness control, and provides array-based access to the Leds | |
FlickerBrightness pwm(sinks); | |
//?? Turn all the LEDs and source drivers off | |
void AllOff(void) | |
{ | |
sources.set(0); | |
sinks.set(0,0,0); | |
} | |
// set a lantern color with RGB values, each from 0 to 8192 | |
void setLanternColor(int lantern, int r, int g, int b) | |
{ | |
// only 35 sink pins on each side, so we have to subtract 1 to compensate for laterns 6-11. | |
pwm.brightness[lantern * 6 - (lantern > 5)]= r; | |
pwm.brightness[lantern * 6 - (lantern > 5) + 1]= g; | |
pwm.brightness[lantern * 6 - (lantern > 5) + 2]= b; | |
} | |
// set a lantern color with a hue (between 0 and 360) and brightness value | |
void setLanternColor(int lantern, int hue, int brightness) | |
{ | |
// when hue is between 0 and 60, r = brightness, b = 0.0 and g goes linearly from | |
// 0.0 to brightness; similarly, r goes down when 60<hue<120, b ramps up when 120<hue<180, | |
// g goes down when 180<hue<240, r ramps up when 240<hue<300 and b - down when 300<hue<360. | |
static int r, g, b; | |
r = (60*(hue<60) + (120-hue)*((hue>=60)&&(hue<120)) + /* 0*((hue>=120)&&(hue<240))/60 + */ | |
(hue-240)*((hue>=240)&&(hue<300)) + 60*(hue>=300))*(brightness/60); | |
g = (hue*(hue<60) + 60*((hue>=60)&&(hue<180)) + (240-hue)*((hue>=180)&&(hue<240)) | |
/* + 0*(hue>240) */ )*(brightness/60); | |
b = (/* 0*(hue<120) + */ (hue-120)*((hue>=120)&&(hue<180)) + 60*((hue>=180)&&(hue<300)) + | |
(360-hue)*(hue>=300))*(brightness/60); | |
setLanternColor(lantern, r, g, b); | |
} | |
void setUV(int lantern, int brightness) | |
{ | |
pwm.brightness[lantern * 6 - (lantern > 5) + 3]= brightness; | |
} | |
void setup() | |
{ | |
setup_noise(); | |
analogReference(DEFAULT); // Use default (5v) aref voltage. | |
// Start up the serial port. I don't think this is actually working, but the USB works. | |
Serial.begin(9600); | |
Serial.println("serial initialized"); | |
// Start up the Lightuino's USB serial port. | |
#ifdef Lightuino_USB // This #ifdef,#endif wrapper means the the code inside will only compile if your Lightuino has a USB port. | |
// That way this sketch will work with multiple versions of the circuitboard. | |
// But since you probably don't care that your sketch does so, you can leave these lines out. | |
Usb.begin(); | |
#endif // This line need to be removed if #ifdef is removed too! | |
AllOff(); // When the board boots up there will be random values in various chips resulting in some lights being on. | |
pwm.StartAutoLoop(3000); | |
StartSoundSampling(1000); | |
setLanternColor(10, Lightuino_MAX_BRIGHTNESS/2, Lightuino_MAX_BRIGHTNESS/2, Lightuino_MAX_BRIGHTNESS/2); | |
setLanternColor(11, Lightuino_MAX_BRIGHTNESS/2, Lightuino_MAX_BRIGHTNESS/2, Lightuino_MAX_BRIGHTNESS/2); | |
lastPatternTime = millis(); | |
}; | |
void loop() | |
{ | |
Usb.print("Time since last read loop (ms): "); | |
Usb.println(millis()-lastsamplelooptime); | |
lastsamplelooptime = millis(); | |
Usb.print("Number of samples since last loop: "); | |
Usb.println(timerCounter); | |
////// Analyze Sound | |
subbass = sqrt(subbassr * subbassr + subbassi * subbassi)/ timerCounter; | |
bass = sqrt(bassr * bassr + bassi * bassi)/ timerCounter; | |
mid = sqrt(midr * midr + midi * midi)/ timerCounter; | |
treb = sqrt(trebr * trebr + trebi * trebi)/ timerCounter; | |
subbassr=0; subbassi=0; | |
bassr=0; bassi=0; | |
midr=0; midi=0; | |
trebr=0; trebi=0; | |
timerCounter=0; | |
volume = (subbass + bass + mid + treb)/4; | |
Usb.print(" Volume: "); | |
Usb.println(volume); | |
////// Change the light pattern every so often | |
if (millis()-lastPatternTime > switchTime){ | |
currentPattern = (currentPattern + 1) % numPatterns; // just scroll through for now | |
lastPatternTime = millis(); | |
} | |
////// Update LEDs | |
switch(currentPattern){ // for diagnostic mode, change this to switch(-1) | |
case (-1): | |
diagnostic(); | |
break; | |
case (0): | |
whiteVolumeMeter(); | |
break; | |
case (1): | |
rgbuLoop(); | |
break; | |
case(2): | |
high_center_linear_equalizer(); | |
break; | |
case(3): | |
pressured_hues(); | |
break; | |
case(4): | |
color_wheel_chase(); | |
break; | |
default: | |
color_wheel_static(); | |
break; | |
} | |
}; | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
// Light Patterns for the LED Lights | |
//////////////////////////////////////////////////////////////////////////////////////////////////////////// | |
void whiteVolumeMeter() // sets all lanters to produce white light proportional to the current volume... unsure why *4? Should work for the new pattern | |
{ | |
int brightness; | |
brightness = max(500, min(Lightuino_MAX_BRIGHTNESS, volume*4)); | |
for (i=0; i<10; i++){ | |
setLanternColor(i, brightness, brightness, brightness); | |
} | |
} | |
void rgbuLoop() // Should be fine for linear | |
{ | |
static int color=0; | |
static long lastColorTime=0; | |
if (millis()-lastColorTime>1000){ | |
color = (color +1) %4; | |
lastColorTime=millis(); | |
for (i=0; i<10; i++){ | |
setLanternColor(i, ((color + i) % 4 == 0 || (color + i) % 4 == 3) * Lightuino_MAX_BRIGHTNESS, | |
((color + i) % 4 == 1 || (color + i) % 4 == 3) * Lightuino_MAX_BRIGHTNESS, | |
((color + i) % 4 == 2 || (color + i) % 4 == 3) * Lightuino_MAX_BRIGHTNESS); | |
} | |
} | |
} | |
void high_center_linear_equalizer()//setup for new pattern. Function to attach frequency ranges to each of R,G,B and UV lights in a descending from the center 2 lights (3 and 4) | |
{ | |
const float incre = 0.2; // incremental decrease in brightness from center | |
int Vsubbass, Vbass, Vmid,Vtreb,Vvolume; | |
//set volume variables to ranged values either 0 or from 500 to 8912 | |
Vsubbass = subbass*2; | |
if (Vsubbass < 500) Vsubbass = 0; | |
Vbass = bass*2; | |
if (Vbass < 500) Vbass = 0; | |
Vmid = mid*2; | |
if (Vmid < 500) Vmid = 0; | |
Vtreb = treb*2; | |
if (Vtreb < 500) Vtreb = 0; | |
Vvolume = volume*2; | |
if (Vvolume < 500) Vvolume = 0; | |
//set intensity of light in lanterns so that R,G,B and UV track different frequency ranges with the center lanterns being the most powerful. | |
setLanternColor(0, (1-incre*3)*Vbass,(1-incre*3)*Vmid,(1-incre*3)*Vtreb); | |
setLanternColor(1, (1-incre*2)*Vbass,(1-incre*2)*Vmid,(1-incre*2)*Vtreb); | |
setLanternColor(2, (1-incre)*Vbass,(1-incre)*Vmid,(1-incre)*Vtreb); | |
setLanternColor(3, Vbass,Vmid,Vtreb); | |
setLanternColor(4, Vbass,Vmid,Vtreb); | |
setLanternColor(5, (1-incre)*Vbass,(1-incre)*Vmid,(1-incre)*Vtreb); | |
setLanternColor(6, (1-incre*2)*Vbass,(1-incre*2)*Vmid,(1-incre*2)*Vtreb); | |
setLanternColor(7, (1-incre*3)*Vbass,(1-incre*3)*Vmid,(1-incre*3)*Vtreb); | |
setUV(0,(1-3*incre)*Vsubbass); | |
setUV(1,(1-2*incre)*Vsubbass); | |
setUV(2,(1-incre)*Vsubbass); | |
setUV(3,Vsubbass); | |
setUV(7,(1-3*incre)*Vsubbass); | |
setUV(6,(1-2*incre)*Vsubbass); | |
setUV(5,(1-incre)*Vsubbass); | |
setUV(4,Vsubbass); | |
setUV(8,Vsubbass/2); | |
setUV(9,Vsubbass/2); | |
setLanternColor(8, Vvolume,Vvolume,Vvolume); | |
setLanternColor(9, Vvolume,Vvolume,Vvolume); | |
} | |
void pressured_hues() //show a cycle of hues going outward from the center and inwards from the edges. Meeting in 'nodes' between A and B | |
{ | |
const int hue_inc = 5; | |
const int brightness = 4500; | |
static int hue_pos = 0; | |
static int dhue_pos = 0; | |
static long last_time = 0; | |
if (millis() - last_time > 500) //wait until 0.5 second has gone by | |
{ | |
setLanternColor(0, 360 - hue_pos, brightness); | |
setLanternColor(1, 360 - dhue_pos, brightness); | |
setLanternColor(2, dhue_pos, brightness); | |
setLanternColor(3, hue_pos, brightness); | |
setLanternColor(4, 360 - hue_pos, brightness); | |
setLanternColor(5, 360 - dhue_pos, brightness); | |
setLanternColor(6, dhue_pos, brightness); | |
setLanternColor(7, hue_pos, brightness); | |
setLanternColor(8,abs(dhue_pos - hue_pos),brightness); | |
setLanternColor(9, 360 - abs(dhue_pos - hue_pos),brightness); | |
setUV(8,brightness); | |
setUV(9,brightness); | |
hue_pos = (hue_pos + hue_inc) % 360; | |
dhue_pos = (dhue_pos + hue_inc*2) % 360; | |
last_time = millis(); | |
} | |
} | |
void color_wheel_chase() //not setup for new pattern -Paul: I had this running earlier, and it actually doesn't look that bad. | |
{ | |
static int hue=0; // the hue | |
static int lantern_number=10; // number of lanterns | |
int h=hue; | |
for (int i=0; i<lantern_number; i++) { | |
setLanternColor(i, h, max(4000, min(volume*2, Lightuino_MAX_BRIGHTNESS))); | |
h = (h + (360/lantern_number)) % 360; | |
} | |
hue = (hue + max(1, volume/50-15)) % 360; | |
} | |
void color_wheel_static() // not setup for new pattern -Paul: this one doesn't look great with the new setup, but leaving it in until we have more patterns | |
{ | |
static int h=0; // the hue | |
static int uvTimer=0; | |
for (int i=0; i<10; i++) { | |
setLanternColor(i, h, Lightuino_MAX_BRIGHTNESS); | |
setUV(i, 0 + (uvTimer>30) * Lightuino_MAX_BRIGHTNESS ); | |
} | |
h = (h + 1) % 360; | |
uvTimer = (uvTimer+1) %60; | |
} | |
/* | |
OLD CODE from 2011 | |
void twin_light_chase() // not yet modified for new light setup | |
{ | |
static int hue=0; // the hue | |
static int lantern=0; // current lantern position | |
static int timeSinceSwitch=0; | |
if (30-timeSinceSwitch++ < min(15, max(0, volume / 30 - 20))) | |
{ | |
setLanternColor(lantern, 0,0,0); | |
setLanternColor((lantern + 4) % 8, 0,0,0); | |
lantern = (lantern + 1) % 8; | |
setLanternColor(lantern, hue, Lightuino_MAX_BRIGHTNESS); | |
setLanternColor((lantern + 4) % 8, hue, Lightuino_MAX_BRIGHTNESS); | |
timeSinceSwitch=0; | |
} | |
hue = (hue + 1) % 360; | |
} | |
*/ | |
/*void equalizer() // not setup for new light pattern | |
{ | |
setLanternColor(0, 0, max(500, subbass*2)); | |
setLanternColor(1, 0, max(500, subbass*2)); | |
setLanternColor(2, 90, max(500, bass*2)); | |
setLanternColor(3, 90, max(500, bass*2)); | |
setLanternColor(4, 180, max(500, mid*2)); | |
setLanternColor(5, 180, max(500, mid*2)); | |
setLanternColor(6, 270, max(500, treb*2)); | |
setLanternColor(7, 270, max(500, treb*2)); | |
setLanternColor(8, max(500, volume*2), max(500, volume*2), max(500, volume*2)); | |
setLanternColor(9, max(500, volume*2), max(500, volume*2), max(500, volume*2)); | |
}*/ | |
void diagnostic() | |
{ | |
static long lastColorTime=0; | |
static int color=0; | |
if (millis()-lastColorTime>1000){ | |
lastColorTime=millis(); | |
color=(color + 1) % 5; | |
for (int i=0; i<12; i++) { | |
setLanternColor(i, (color ==0)*Lightuino_MAX_BRIGHTNESS, (color ==1)*Lightuino_MAX_BRIGHTNESS, (color ==2)*Lightuino_MAX_BRIGHTNESS); | |
setUV(i, (color ==3)*Lightuino_MAX_BRIGHTNESS); | |
} | |
} | |
} | |
void monochrome_perlin_waves() | |
{ | |
// rgb up to 8192 Lightuino_MAX_BRIGHTNESS | |
int half = Lightuino_MAX_BRIGHTNESS/2; | |
for (int i=0; i<lantern_number; i++) { | |
float offset = i * 10.0f; | |
x1 = float(millis() + offset)/100.0f; | |
y1 = 10.0f; | |
//x2 = float(millis())/100.0f; | |
//y2 = 11.0f; | |
int b = int(PerlinNoise2(x1,y1,persistence,octaves)*half+half); // 0 - Max | |
setLanternColor(i, b, b, b ); | |
} | |
} | |
void red_perlin_waves() | |
{ | |
// rgb up to 8192 Lightuino_MAX_BRIGHTNESS | |
int half = Lightuino_MAX_BRIGHTNESS/2; | |
for (int i=0; i<lantern_number; i++) { | |
float offset = i * 15.0f; | |
x1 = float(millis() + offset)/110.0f; | |
y1 = 10.0f; | |
int b = int(PerlinNoise2(x1,y1,persistence,octaves)*half+half); // 0 - Max | |
setLanternColor(i, b, 0, 0 ); | |
} | |
} | |
void hue_perlin_waves() | |
{ | |
// rgb up to 8192 Lightuino_MAX_BRIGHTNESS | |
int half = Lightuino_MAX_BRIGHTNESS/2; | |
for (int i=0; i<lantern_number; i++) { | |
float offset = i * 15.0f; | |
x1 = float(millis() + offset)/110.0f; | |
y1 = 10.0f; | |
int h = int(PerlinNoise2(x1,y1,persistence,octaves)*180+180); // 0 - 360 | |
setLanternColor(i, h, Lightuino_MAX_BRIGHTNESS); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
copyright 2007 Mike Edwards | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; version 2 of the License. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
*/ | |
#include <math.h> | |
void setup_noise() | |
{ | |
//pinMode(5,OUTPUT); | |
//pinMode(6,OUTPUT); | |
//analogWrite(5,0); | |
//analogWrite(6,0); | |
//persistence affects the degree to which the "finer" noise is seen | |
persistence = 0.25; | |
//octaves are the number of "layers" of noise that get computed | |
octaves = 3; | |
} | |
/* | |
void loop() | |
{ | |
x1 = float(millis())/100.0f; | |
y1 = 10.0f; | |
x2 = float(millis())/100.0f; | |
y2 = 11.0f; | |
//PerlinNoise2 results in a float between -1 and 1 | |
//below we convert to a n int between 0 and 255 | |
int m = int(PerlinNoise2(x1,y1,persistence,octaves)*128+128); | |
int n = int(PerlinNoise2(x2,y2,persistence,octaves)*128+128); | |
} */ | |
//using the algorithm from http://freespace.virgin.net/hugo.elias/models/m_perlin.html | |
// thanks to hugo elias | |
float Noise2(float x, float y) | |
{ | |
long noise; | |
noise = x + y * 57; | |
noise = pow(noise << 13,noise); | |
return ( 1.0 - ( long(noise * (noise * noise * 15731L + 789221L) + 1376312589L) & 0x7fffffff) / 1073741824.0); | |
} | |
float SmoothNoise2(float x, float y) | |
{ | |
float corners, sides, center; | |
corners = ( Noise2(x-1, y-1)+Noise2(x+1, y-1)+Noise2(x-1, y+1)+Noise2(x+1, y+1) ) / 16; | |
sides = ( Noise2(x-1, y) +Noise2(x+1, y) +Noise2(x, y-1) +Noise2(x, y+1) ) / 8; | |
center = Noise2(x, y) / 4; | |
return (corners + sides + center); | |
} | |
float InterpolatedNoise2(float x, float y) | |
{ | |
float v1,v2,v3,v4,i1,i2,fractionX,fractionY; | |
long longX,longY; | |
longX = long(x); | |
fractionX = x - longX; | |
longY = long(y); | |
fractionY = y - longY; | |
v1 = SmoothNoise2(longX, longY); | |
v2 = SmoothNoise2(longX + 1, longY); | |
v3 = SmoothNoise2(longX, longY + 1); | |
v4 = SmoothNoise2(longX + 1, longY + 1); | |
i1 = Interpolate(v1 , v2 , fractionX); | |
i2 = Interpolate(v3 , v4 , fractionX); | |
return(Interpolate(i1 , i2 , fractionY)); | |
} | |
float Interpolate(float a, float b, float x) | |
{ | |
//cosine interpolations | |
return(CosineInterpolate(a, b, x)); | |
} | |
float LinearInterpolate(float a, float b, float x) | |
{ | |
return(a*(1-x) + b*x); | |
} | |
float CosineInterpolate(float a, float b, float x) | |
{ | |
float ft = x * 3.1415927; | |
float f = (1 - cos(ft)) * .5; | |
return(a*(1-f) + b*f); | |
} | |
float PerlinNoise2(float x, float y, float persistance, int octaves) | |
{ | |
float frequency, amplitude; | |
float total = 0.0; | |
for (int i = 0; i <= octaves - 1; i++) | |
{ | |
frequency = pow(2,i); | |
amplitude = pow(persistence,i); | |
total = total + InterpolatedNoise2(x * frequency, y * frequency) * amplitude; | |
} | |
return(total); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment