-
Notifications
You must be signed in to change notification settings - Fork 1
/
Dale_Coachella_Project_CP.ino
333 lines (289 loc) · 10.5 KB
/
Dale_Coachella_Project_CP.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/* ---------------------------------------------------------
* | Blinking Bracelet Project for Coachella |
* ---------------------------------------------------------
*
* Uses the adafruit libraries for wearable LED arrays as well as accelerometer code
*/
#include <Adafruit_NeoPixel.h>
#define PIN 17
#define TPIXEL 10 //The total amount of pixel's/led's in your connected strip/stick (Default is 60)
#define BUTTONPIN 4 // the number of the pushbutton pin
#define MIC_PIN A4 // Microphone is attached to this analog pin
#define DC_OFFSET -172 // DC offset in mic signal - if unusure, leave 0
#define NOISE 10 // Noise/hum/interference in mic signal
#define SAMPLES 60 // Length of buffer for dynamic level adjustment
#define TOP (TPIXEL + 2) // Allow dot to go slightly off scale
enum FadeDirection {FORWARD, REVERSE};
//color mode settings. These define the number of total number of color modes and the order that they are selected.
#define COLORFADE_MODE 0 //fade between two colors
//#define COLORWIPE_MODE 1 //color wipe mode
//#define RAINBOW_MODE 2 // rainbow mode
#define RAINBOWCYCLE_MODE 1 //rainbow cycle mode
#define THEATERCHASE_MODE 2 //
#define VUDOUBLE_MODE 3 // double vu mode constant
#define NUM_MODES 4 // sets the maximum number of color modes
const int longPressDuration = 750; // duration of a long press in milliseconds
const int brightnessLevels = 3; //defines how many brightness levels will be used
const int minBrightness = 80; //defines the lowest brightness level from 0-255
const int maxBrightness = 180; //defines the maximum brightness level from 0-255
// variables will change:
int
buttonState = 0, // variable for reading the pushbutton status
lastButtonState = 0, // variable for tracking the last button status
currentBrightness = 80; // keeps track of the current color that is displayed for fading purposes
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long
buttonStart = 0, // marks when the button was first pushed
lastDebounceTime = 0, // the last time the output pin was toggled
debounceDelay = 50; // the debounce time; increase if the output flickers
uint32_t currentColor = Adafruit_NeoPixel::Color(190,210,210),
fadeColor1 = Adafruit_NeoPixel::Color(190,210,210),
fadeColor2 = Adafruit_NeoPixel::Color(0,0,255); // set the first color to black;
FadeDirection fadeDir = FORWARD;
volatile int lightMode = 0; // how many times the button has been pressed
uint16_t
WaitTime = 80;
unsigned long previousMillis;
//vuMeter variables
byte
peak = 0, // Used for falling dot
dotCount = 0, // Frame counter for delaying dot-falling speed
volCount = 0, // Frame counter for storing past volume data
count1 = 0,
count2 = 0;
int
vol[SAMPLES], // Collection of prior volume samples
lvl = 10, // Current "dampened" audio level
minLvlAvg = 0, // For dynamic adjustment of graph low & high
maxLvlAvg = 512;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(TPIXEL, PIN, NEO_GRB + NEO_KHZ800);
// our RGB -> eye-recognized gamma color
byte gammatable[256];
void setup() {
pinMode(BUTTONPIN, INPUT); //Set the switch pin as input
pinMode(PIN, OUTPUT);
lastButtonState = digitalRead(BUTTONPIN);
buttonState = lastButtonState;
randomSeed(analogRead(0));
strip.setBrightness(currentBrightness); //adjust brightness here
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void loop() {
debounceButton();
if (lightMode == VUDOUBLE_MODE) {
vuDoubleMeterUpdate();
}
else {
if (millis() - previousMillis >= WaitTime) {
switch (lightMode) {
case COLORFADE_MODE:
colorFadeUpdate();
break;
// case COLORWIPE_MODE:
// colorWipeUpdate();
// break;
// case RAINBOW_MODE:
// rainbowUpdate();
// break;
case RAINBOWCYCLE_MODE:
rainbowCycleUpdate();
break;
case THEATERCHASE_MODE:
theaterChaseUpdateTrail();
}
previousMillis = millis();
}
}
}
void debounceButton() {
int reading = digitalRead(BUTTONPIN);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == HIGH) {
buttonStart = millis();
}
else {
int pressDuration = millis() - buttonStart; //calculate how long the button was pressed for
if (pressDuration < longPressDuration) {
swap(); //change modes if the press was short
}
else {
currentBrightness = currentBrightness + ((maxBrightness - minBrightness) / brightnessLevels); //step up our brightness, using 20 as our lowest light level
if (currentBrightness > maxBrightness) {
currentBrightness = minBrightness;
}
strip.setBrightness(currentBrightness); //fade gradually to a random color if it was a long press
}
}
}
}
lastButtonState = reading;
}
void swap() {
if (lightMode++ == NUM_MODES - 1) {
lightMode = 0;
}
currentColor = getRandomColor();
count1 = 0;
count2 = 0;
}
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
}
uint32_t getRandomColor() {
return Wheel(lowByte(random(0, 255)));
}
void colorWipeUpdate() {
strip.setPixelColor(count1++, currentColor);
strip.show();
if (count1 == strip.numPixels()) {
count1 = 0;
currentColor = getRandomColor();
}
}
void colorFadeUpdate() {
byte TotalSteps = 50;
int redColor, greenColor, blueColor;
uint8_t red = ((Red(fadeColor1) * (TotalSteps - count1)) + (Red(fadeColor2) * count1)) / TotalSteps;
uint8_t green = ((Green(fadeColor1) * (TotalSteps - count1)) + (Green(fadeColor2) * count1)) / TotalSteps;
uint8_t blue = ((Blue(fadeColor1) * (TotalSteps - count1)) + (Blue(fadeColor2) * count1)) / TotalSteps;
for (byte i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, red, green, blue);
}
strip.show();
if (fadeDir == FORWARD) {
if (++count1 >= TotalSteps) {
fadeDir = REVERSE;
}
}
else {
if (--count1 <= 0) {
fadeDir = FORWARD;
}
}
}
void rainbowUpdate() {
uint16_t i;
for (i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i + count1) & 255));
strip.show();
count1++;
if (count1 == 256) {
count1 = 0;
}
}
}
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycleUpdate() {
for (uint16_t i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + count1++) & 255));
}
strip.show();
if (count1 == 256 * 5) {
count1 = 0;
}
}
//Theatre-style crawling lights.
void theaterChaseUpdate() {
for (int i = 0; i < strip.numPixels(); i = i + 4) {
strip.setPixelColor(i + count1, currentColor); //turn every third pixel on
}
strip.show();
for (int i = 0; i < strip.numPixels(); i = i + 4) {
strip.setPixelColor(i + count1, 0); //turn every third pixel off
}
if (++count1 == 4) {
count1 = 0;
}
}
//Theatre-style crawling lights.
void theaterChaseUpdateTrail() {
for (int i = 0; i < strip.numPixels(); i = i + 4) {
strip.setPixelColor(i + count1, currentColor); //turn every third pixel on
strip.setPixelColor(i + count1 - 1, getHalfBrightness(currentColor));
}
strip.show();
for (int i = 0; i < strip.numPixels(); i = i + 4) {
strip.setPixelColor(i + count1, 0); //turn every third pixel off
strip.setPixelColor(i + count1 - 1, 0);
}
if (++count1 == 4) {
count1 = 0;
}
}
//VU Style Sound Meter with two bars
void vuDoubleMeterUpdate() {
uint8_t i;
uint16_t minLvl, maxLvl;
int n, height;
n = analogRead(MIC_PIN); // Raw reading from mic
n = abs(n - 512 - DC_OFFSET); // Center on zero
n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum
lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy)
// Calculate bar height based on dynamic min/max levels (fixed point):
height = TOP / 2 * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
if (height < 0L) height = 0; // Clip output
else if (height > TOP / 2) height = TOP / 2;
// Color pixels based on rainbow gradient
for (i = 0; i < TPIXEL / 2; i++) {
if (i >= height) {
strip.setPixelColor(i, 0, 0, 0);
strip.setPixelColor(TPIXEL - i - 1, 0, 0, 0);
}
else {
strip.setPixelColor(i, Wheel(map(i, 0, strip.numPixels() / 2 - 1, 100, 230)));
strip.setPixelColor(TPIXEL - i - 1, Wheel(map(i, 0, strip.numPixels() / 2 - 1, 100, 230)));
}
}
strip.show(); // Update strip
vol[volCount] = n; // Save sample for dynamic leveling
if (++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter
// Get volume range of prior frames
minLvl = maxLvl = vol[0];
for (i = 1; i < SAMPLES; i++) {
if (vol[i] < minLvl) minLvl = vol[i];
else if (vol[i] > maxLvl) maxLvl = vol[i];
}
// minLvl and maxLvl indicate the volume range over prior frames, used
// for vertically scaling the output graph (so it looks interesting
// regardless of volume level). If they're too close together though
// (e.g. at very low volume levels) the graph becomes super coarse
// and 'jumpy'...so keep some minimum distance between them (this
// also lets the graph go to zero when no sound is playing):
if ((maxLvl - minLvl) < TOP) maxLvl = minLvl + TOP;
minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)
}
// Returns the Red component of a 32-bit color
uint8_t Red(uint32_t color)
{
return (color >> 16) & 0xFF;
}
// Returns the Green component of a 32-bit color
uint8_t Green(uint32_t color)
{
return (color >> 8) & 0xFF;
}
// Returns the Blue component of a 32-bit color
uint8_t Blue(uint32_t color)
{
return color & 0xFF;
}
uint32_t getHalfBrightness (uint32_t color) {
return (color & 0xfcfcfc) >> 1;
}