top of page
PROJECT 2
My last project emphasized the feelings I get when I have anxiety so I wanted to take a different approach with this project. I used the same idea as a 'cloud' light but this time it is focused on making a persons space feel more personal. By adding the feature of being able to change the light setting and using an outside source to choose your own music it is more customizable to someones specific taste.
About: About
About: Video
About: Video
About: Pro Gallery
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define LED_PIN A5
#define LED_TOTAL 60
#define LED_HALF LED_TOTAL/2
#define VISUALS 6
#define AUDIO_PIN A0
#define BUTTON_1 6
#define BUTTON_2 5
#define BUTTON_3 4
Adafruit_NeoPixel strand = Adafruit_NeoPixel(LED_TOTAL, LED_PIN, NEO_GRB + NEO_KHZ800);
uint16_t gradient = 0;
uint16_t thresholds[] = {1529, 1019, 764, 764, 764, 1274};
uint8_t palette = 0;
uint8_t visual = 0;
uint8_t volume = 0;
uint8_t last = 0;
float maxVol = 15;
float avgBump = 0;
float avgVol = 0;
float shuffleTime = 0;
bool shuffle = false;
bool bump = false;
//For Visual3 visual
int8_t pos[LED_TOTAL] = { -2};
uint8_t rgb[LED_TOTAL][3] = {0};
//For Visual4 visual
bool left = false;
int8_t dotPos = 0;
float timeBump = 0;
float avgTime = 0;
void setup() {
Serial.begin(9600);
pinMode(BUTTON_1, INPUT); pinMode(BUTTON_2, INPUT); pinMode(BUTTON_3, INPUT);
digitalWrite(BUTTON_1, HIGH); digitalWrite(BUTTON_2, HIGH); digitalWrite(BUTTON_3, HIGH);
strand.begin();
strand.show();
}
void loop() {
volume = analogRead(AUDIO_PIN);
if (volume < avgVol / 2.0 || volume < 15) volume = 0;
else avgVol = (avgVol + volume) / 2.0; //If non-zeo, take an "average" of volumes.
if (volume > maxVol) maxVol = volume;
CyclePalette();
CycleVisual();
ToggleShuffle();
if (gradient > thresholds[palette]) {
gradient %= thresholds[palette] + 1;
maxVol = (maxVol + volume) / 2.0;
}
if (volume - last > 10) avgBump = (avgBump + (volume - last)) / 2.0;
bump = (volume - last > avgBump * .9);
if (bump) {
avgTime = (((millis() / 1000.0) - timeBump) + avgTime) / 2.0;
timeBump = millis() / 1000.0;
}
Visualize();
gradient++;
last = volume;
delay(45);
}
void Visualize() {
switch (visual) {
case 0: return Visual1();
case 1: return Visual2();
case 2: return Visual3();
case 3: return Visual4();
case 4: return Visual5();
case 5: return Visual6();
case 6: return Visual7();
default: return Visual1();
}
}
uint32_t ColorPalette(float num) {
switch (palette) {
case 0: return (num < 0) ? Color1(gradient) : Color1(num);
case 1: return (num < 0) ? Color2(gradient) : Color2(num);
case 2: return (num < 0) ? Color3(gradient) : Color3(num);
case 3: return (num < 0) ? Color4(gradient) : Color4(num);
case 4: return (num < 0) ? Color5(gradient) : Color5(num);
case 5: return (num < 0) ? Color6(gradient) : Color6(num);
default: return Color1(gradient);
}
}
void Visual1() {
fade(0.75);
if (bump) gradient += thresholds[palette] / 24;
if (volume > 0) {
uint32_t col = ColorPalette(-1);
int start = LED_HALF - (LED_HALF * (volume / maxVol));
int finish = LED_HALF + (LED_HALF * (volume / maxVol)) + strand.numPixels() % 2;
for (int i = start; i < finish; i++) {
float damp = sin((i - start) * PI / float(finish - start));
damp = pow(damp, 2.0);
uint32_t col2 = strand.getPixelColor(i);
uint8_t colors[3];
float avgCol = 0, avgCol2 = 0;
for (int k = 0; k < 3; k++) {
colors[k] = split(col, k) * damp * pow(volume / maxVol, 2);
avgCol += colors[k];
avgCol2 += split(col2, k);
}
avgCol /= 3.0, avgCol2 /= 3.0;
if (avgCol > avgCol2) strand.setPixelColor(i, strand.Color(colors[0], colors[1], colors[2]));
}
}
strand.show();
}
void Visual2() {
fade(0.75);
if (bump) gradient += thresholds[palette] / 24;
if (volume > 0) {
int start = LED_HALF - (LED_HALF * (volume / maxVol));
int finish = LED_HALF + (LED_HALF * (volume / maxVol)) + strand.numPixels() % 2;
for (int i = start; i < finish; i++) {
float damp = sin((i - start) * PI / float(finish - start));
damp = pow(damp, 2.0);
int val = thresholds[palette] * (i - start) / (finish - start);
val += gradient;
uint32_t col = ColorPalette(val);
uint32_t col2 = strand.getPixelColor(i);
uint8_t colors[3];
float avgCol = 0, avgCol2 = 0;
for (int k = 0; k < 3; k++) {
colors[k] = split(col, k) * damp * pow(volume / maxVol, 2);
avgCol += colors[k];
avgCol2 += split(col2, k);
}
avgCol /= 3.0, avgCol2 /= 3.0;
if (avgCol > avgCol2) strand.setPixelColor(i, strand.Color(colors[0], colors[1], colors[2]));
}
}
strand.show();
}
void Visual3() {
fade(0.10);
if (bump) {
int8_t slot = 0;
for (slot; slot < sizeof(pos); slot++) {
if (pos[slot] < -1) break;
else if (slot + 1 >= sizeof(pos)) {
slot = -3;
break;
}
}
if (slot != -3) {
pos[slot] = (slot % 2 == 0) ? -1 : strand.numPixels();
uint32_t col = ColorPalette(-1);
gradient += thresholds[palette] / 24;
for (int j = 0; j < 3; j++) {
rgb[slot][j] = split(col, j);
}
}
}
if (volume > 0) {
for (int i = 0; i < sizeof(pos); i++) {
if (pos[i] < -1) continue;
pos[i] += (i % 2) ? -1 : 1;
if (pos[i] >= strand.numPixels()) pos[i] = -2;
strand.setPixelColor( pos[i], strand.Color(
float(rgb[i][0]) * pow(volume / maxVol, 2.0),
float(rgb[i][1]) * pow(volume / maxVol, 2.0),
float(rgb[i][2]) * pow(volume / maxVol, 2.0))
);
}
}
strand.show();
}
void Visual4() {
if (bump) {
gradient += thresholds[palette] / 30;
left = !left;
}
fade(0.975);
uint32_t col = ColorPalette(-1);
if (volume > 0) {
strand.setPixelColor(dotPos, strand.Color(
float(split(col, 0)) * pow(volume / maxVol, 1.5),
float(split(col, 1)) * pow(volume / maxVol, 1.5),
float(split(col, 2)) * pow(volume / maxVol, 1.5))
);
if (avgTime < 0.15) dotPos += (left) ? -1 : 1;
else if (avgTime >= 0.15 && avgTime < 0.5 && gradient % 2 == 0) dotPos += (left) ? -1 : 1;
else if (avgTime >= 0.5 && avgTime < 1.0 && gradient % 3 == 0) dotPos += (left) ? -1 : 1;
else if (gradient % 4 == 0) dotPos += (left) ? -1 : 1;
}
strand.show();
if (dotPos < 0) dotPos = strand.numPixels() - 1;
else if (dotPos >= strand.numPixels()) dotPos = 0;
}
void Visual5() {
if (bump) left = !left;
if (volume > avgVol) {
for (int i = 0; i < strand.numPixels(); i++) {
float sinVal = abs(sin(
(i + dotPos) *
(PI / float(strand.numPixels() / 1.25) )
));
sinVal *= sinVal;
sinVal *= volume / maxVol;
unsigned int val = float(thresholds[palette] + 1)
* (float(i + map(dotPos, -1 * (strand.numPixels() - 1), strand.numPixels() - 1, 0, strand.numPixels() - 1))
/ float(strand.numPixels()))
+ (gradient);
val %= thresholds[palette];
uint32_t col = ColorPalette(val);
strand.setPixelColor(i, strand.Color(
float(split(col, 0))*sinVal,
float(split(col, 1))*sinVal,
float(split(col, 2))*sinVal)
);
}
dotPos += (left) ? -1 : 1;
}
else fade(0.8);
strand.show();
if (dotPos < 0) dotPos = strand.numPixels() - strand.numPixels() / 6;
else if (dotPos >= strand.numPixels() - strand.numPixels() / 6) dotPos = 0;
}
void Visual6() {
gradient += thresholds[palette] / 204;
for (int i = 0; i < strand.numPixels(); i++) {
unsigned int val = float(thresholds[palette] + 1) *
(float(i) / float(strand.numPixels()))
+ (gradient);
val %= thresholds[palette];
uint32_t col = ColorPalette(val);
strand.setPixelColor(i, strand.Color(
split(col, 0) / 6.0,
split(col, 1) / 6.0,
split(col, 2) / 6.0)
);
}
if (bump) {
randomSeed(micros());
dotPos = random(strand.numPixels() - 1);
strand.setPixelColor(dotPos, strand.Color(
255.0 * pow(volume / maxVol, 2.0),
255.0 * pow(volume / maxVol, 2.0),
255.0 * pow(volume / maxVol, 2.0)
));
}
bleed(dotPos);
strand.show();
}
void Visual7() {
if ((millis() / 1000.0) - timeBump > avgTime * 2.0) fade(0.99);
bleed(dotPos);
if (bump) {
randomSeed(micros());
dotPos = random(strand.numPixels() - 1);
uint32_t col = ColorPalette(random(thresholds[palette]));
uint8_t colors[3];
for (int i = 0; i < 3; i++) colors[i] = split(col, i) * pow(volume / maxVol, 2.0);
strand.setPixelColor(dotPos, strand.Color(colors[0], colors[1], colors[2]));
for (int i = 0; i < 3; i++) colors[i] *= .8;
strand.setPixelColor(dotPos - 1, strand.Color(colors[0], colors[1], colors[2]));
strand.setPixelColor(dotPos + 1, strand.Color(colors[0], colors[1], colors[2]));
}
strand.show();
}
void Cycle() {
for (int i = 0; i < strand.numPixels(); i++) {
float val = float(thresholds[palette]) * (float(i) / float(strand.numPixels())) + (gradient);
val = int(val) % thresholds[palette];
strand.setPixelColor(i, ColorPalette(val));
}
strand.show();
gradient += 32;
}
void CyclePalette() {
if (!digitalRead(BUTTON_1)) {
palette++;
if (palette >= sizeof(thresholds) / 2) palette = 0;
gradient %= thresholds[palette];
delay(350);
maxVol = avgVol;
}
if (shuffle && millis() / 1000.0 - shuffleTime > 30 && gradient % 2) {
shuffleTime = millis() / 1000.0;
palette++;
if (palette >= sizeof(thresholds) / 2) palette = 0;
gradient %= thresholds[palette];
maxVol = avgVol;
}
}
void CycleVisual() {
if (!digitalRead(BUTTON_2)) {
visual++;
gradient = 0;
if (visual > VISUALS) visual = 0;
if (visual == 1) memset(pos, -2, sizeof(pos));
if (visual == 2 || visual == 3) {
randomSeed(analogRead(0));
dotPos = random(strand.numPixels());
}
delay(350);
maxVol = avgVol;
}
if (shuffle && millis() / 1000.0 - shuffleTime > 30 && !(gradient % 2)) {
shuffleTime = millis() / 1000.0; //Record the time this shuffle happened.
visual++;
gradient = 0;
if (visual > VISUALS) visual = 0;
if (visual == 1) memset(pos, -2, sizeof(pos));
if (visual == 2 || visual == 3) {
randomSeed(analogRead(0));
dotPos = random(strand.numPixels());
}
maxVol = avgVol;
}
}
void ToggleShuffle() {
if (!digitalRead(BUTTON_3)) {
shuffle = !shuffle;
delay(500);
maxVol = avgVol;
avgBump = 0;
}
}
void fade(float damper) {
for (int i = 0; i < strand.numPixels(); i++) {
uint32_t col = strand.getPixelColor(i);
if (col == 0) continue;
float colors[3];
for (int j = 0; j < 3; j++) colors[j] = split(col, j) * damper;
strand.setPixelColor(i, strand.Color(colors[0] , colors[1], colors[2]));
}
}
void bleed(uint8_t Point) {
for (int i = 1; i < strand.numPixels(); i++) {
int sides[] = {Point - i, Point + i};
for (int i = 0; i < 2; i++) {
int point = sides[i];
uint32_t colors[] = {strand.getPixelColor(point - 1), strand.getPixelColor(point), strand.getPixelColor(point + 1) };
strand.setPixelColor(point, strand.Color(
float( split(colors[0], 0) + split(colors[1], 0) + split(colors[2], 0) ) / 3.0,
float( split(colors[0], 1) + split(colors[1], 1) + split(colors[2], 1) ) / 3.0,
float( split(colors[0], 2) + split(colors[1], 2) + split(colors[2], 2) ) / 3.0)
);
}
}
}
uint8_t split(uint32_t color, uint8_t i ) {
//0 = Red, 1 = Green, 2 = Blue
if (i == 0) return color >> 16;
if (i == 1) return color >> 8;
if (i == 2) return color >> 0;
return -1;
}
uint32_t Color1(unsigned int i) {
if (i > 1529) return Color1(i % 1530);
if (i > 1274) return strand.Color(255, 0, 255 - (i % 255)); //violet -> red
if (i > 1019) return strand.Color((i % 255), 0, 255); //blue -> violet
if (i > 764) return strand.Color(0, 255 - (i % 255), 255); //aqua -> blue
if (i > 509) return strand.Color(0, 255, (i % 255)); //green -> aqua
if (i > 255) return strand.Color(255 - (i % 255), 255, 0); //yellow -> green
return strand.Color(255, i, 0); //red -> yellow
}
uint32_t Color2(unsigned int i) {
if (i > 1019) return Color2(i % 1020);
if (i > 764) return strand.Color((i % 255), 0, 255 - (i % 255)); //blue -> red
if (i > 509) return strand.Color(255 - (i % 255), 0, 255); //purple -> blue
if (i > 255) return strand.Color(255, 128 - (i % 255) / 2, (i % 255)); //orange -> purple
return strand.Color(255, i / 2, 0); //red -> orange
}
uint32_t Color3(unsigned int i) {
if (i > 764) return Color3(i % 765);
if (i > 509) return strand.Color(0, i % 255, 255 - (i % 255)); //blue -> green
if (i > 255) return strand.Color(0, 255 - (i % 255), 255); //aqua -> blue
return strand.Color(0, 255, i); //green -> aqua
}
uint32_t Color4(unsigned int i) {
if (i > 764) return Color4(i % 765);
if (i > 509) return strand.Color(255 - (i % 255) / 2, (i % 255) / 2, (i % 255) / 2); //red -> half white
if (i > 255) return strand.Color(255, 255 - (i % 255), 0); //yellow -> red
return strand.Color(128 + (i / 2), 128 + (i / 2), 128 - i / 2); //half white -> yellow
}
uint32_t Color5(unsigned int i) {
if (i > 764) return Color5(i % 765);
if (i > 509) return strand.Color(i % 255, 255, 255 - (i % 255)); //aqua -> yellow
if (i > 255) return strand.Color(0, 255, i % 255); //green -> aqua
return strand.Color(255 - i, 255, 0); //yellow -> green
}
uint32_t Color6(unsigned int i) {
if (i > 1274) return Color6(i % 1275);
if (i > 1019) return strand.Color(255, 0, 255 - (i % 255)); //violet -> red
if (i > 764) return strand.Color((i % 255), 0, 255); //blue -> violet
if (i > 509) return strand.Color(0, 255 - (i % 255), 255); //aqua -> blue
if (i > 255) return strand.Color(255 - (i % 255), 255, i % 255); //yellow -> aqua
return strand.Color(255, i, 0); //red -> yellow
}
About: Text
bottom of page