Code:
#include <Adafruit_NeoPixel.h>
#define PIN 15
Adafruit_NeoPixel strip = Adafruit_NeoPixel(64, PIN, NEO_GRB + NEO_KHZ800);
int numOfLeds = 64;
int audioPin = 14;
int pot_sensitivity_Pin = 16;
int pot_sensitivity_val = 0;
int pot_Speed_Pin = 17;
int pot_Speed_Val = 0;
int pot_Brightness_Pin = 18;
int pot_Brightness_Val = 0;
float pot_Brightness_Val2 = 0;
int pot_Brightness_Val3 = 0;
// THIS VARIABLE STAYS LOW ENOUGH TO PROTECT THE POWER SUPPLY BEING USED.
// WHEN USING COMPUTER USB I AM KEEPING THIS BELOW 64 !
int maxBright = 64;
// Initial multiplier for brightness.
int valueGain = 200;
// initial hue offset
int hueOffset = 150;
int micRemapMax = 128;
// interval for pushing led values down the chain..
long stepSize =100;
// Gamma lookup table
const byte dim_curve[] = {
0, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4,
4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6,
6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8,
8, 8, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11,
11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15,
15, 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 20,
20, 20, 21, 21, 22, 22, 22, 23, 23, 24, 24, 25, 25, 25, 26, 26,
27, 27, 28, 28, 29, 29, 30, 30, 31, 32, 32, 33, 33, 34, 35, 35,
36, 36, 37, 38, 38, 39, 40, 40, 41, 42, 43, 43, 44, 45, 46, 47,
48, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
63, 64, 65, 66, 68, 69, 70, 71, 73, 74, 75, 76, 78, 79, 81, 82,
83, 85, 86, 88, 90, 91, 93, 94, 96, 98, 99, 101, 103, 105, 107, 109,
110, 112, 114, 116, 118, 121, 123, 125, 127, 129, 132, 134, 136, 139, 141, 144,
146, 149, 151, 154, 157, 159, 162, 165, 168, 171, 174, 177, 180, 183, 186, 190,
193, 196, 200, 203, 207, 211, 214, 218, 222, 226, 230, 234, 238, 242, 248, 255,
};
// Initializing some led value holding arrays.
int ledValues_1_r[64];
int ledValues_1_g[64];
int ledValues_1_b[64];
int ledValues_2_r[64];
int ledValues_2_g[64];
int ledValues_2_b[64];
int ledValues_3_r[64];
int ledValues_3_g[64];
int ledValues_3_b[64];
void setup() {
strip.begin();
strip.show(); // Initialize all pixels to 'off'
// Set all values in led holding arrays to an initial 0.
for (int j = 0; j <= (numOfLeds-1); j++) {
ledValues_1_r[j] = 0;
ledValues_1_g[j] = 0;
ledValues_1_b[j] = 0;
ledValues_2_r[j] = 0;
ledValues_2_g[j] = 0;
ledValues_2_b[j] = 0;
ledValues_3_r[j] = 0;
ledValues_3_g[j] = 0;
ledValues_3_b[j] = 0;
}
}
// initialize some timing variables to count intervals.
unsigned long currentMillis;
unsigned long time;
long previousMillis = 0;
// Initializing some more timing and color variables.
float trans_normalized;
float previousStep = 0;
int audioValue = 0;
float currentOffset = 0;
int r_led = 0;
int g_led = 0;
int b_led = 0;
int rgbResult[3];
// Method to convert HSV to RGB, and store the valeus in the array: "rgbResult"
void getRGB(int hue, int sat, int val, int colors[3]) {
/* convert hue, saturation and brightness ( HSB/HSV ) to RGB
The dim_curve is used only on brightness/value and on saturation (inverted).
This looks the most natural.
*/
val = dim_curve[val];
sat = 255-dim_curve[255-sat];
int r;
int g;
int b;
int base;
if (sat == 0) { // Acromatic color (gray). Hue doesn't mind.
colors[0]=val;
colors[1]=val;
colors[2]=val;
} else {
base = ((255 - sat) * val)>>8;
switch(hue/60) {
case 0:
r = val;
g = (((val-base)*hue)/60)+base;
b = base;
break;
case 1:
r = (((val-base)*(60-(hue%60)))/60)+base;
g = val;
b = base;
break;
case 2:
r = base;
g = val;
b = (((val-base)*(hue%60))/60)+base;
break;
case 3:
r = base;
g = (((val-base)*(60-(hue%60)))/60)+base;
b = val;
break;
case 4:
r = (((val-base)*(hue%60))/60)+base;
g = base;
b = val;
break;
case 5:
r = val;
g = base;
b = (((val-base)*(60-(hue%60)))/60)+base;
break;
}
colors[0]=r;
colors[1]=g;
colors[2]=b;
}
}
// Main Loop
void loop() {
// update current milis to current time.
currentMillis = millis();
// Get some analog values.
pot_Speed_Val = analogRead(pot_Speed_Pin);
pot_sensitivity_val = analogRead(pot_sensitivity_Pin);
pot_Brightness_Val = analogRead(pot_Brightness_Pin);
// Remap some stuff.
pot_Speed_Val = map(pot_Speed_Val, 0, 1023, 1, 400);
stepSize = pot_Speed_Val;
pot_sensitivity_val = map(pot_sensitivity_val, 0, 1023, 64, 2048);
micRemapMax = pot_sensitivity_val;
pot_Brightness_Val2 = (float) pot_Brightness_Val;
pot_Brightness_Val2 = ( (pot_Brightness_Val2 / 1023.0) * -1) + 1.0;
// If enough time has passed, do the following.
if ( (currentMillis - previousMillis) > stepSize) {
// Read our envelope value from audioPin so that we can filter and use it.
audioValue = analogRead(audioPin);
// remapping it down from the raw input's range to a range that hue expects.
audioValue = map(audioValue, 0, 1023, 0, micRemapMax);
// Here we use a method we defined above to convert hsv to RGB for neoPixels
getRGB(abs(((audioValue + hueOffset) % 360)), 255, valueGain, rgbResult);
// Here we set the first item in ledvalue 1 to the direct result of our hsv to rgb method.
// We do this because we dont have any earlier pixels in the chain to take the value from, there for it must come from the live audio source.
ledValues_1_r[(numOfLeds-1)] = rgbResult[0];
ledValues_1_g[(numOfLeds-1)] = rgbResult[1];
ledValues_1_b[(numOfLeds-1)] = rgbResult[2];
// ledValue 3 is basically a holding array that will hold our old led rgb pattern for tweening from, to the new pattern.
// Here we are assigning the first item the direct result of the audio because it has no previous led's to take from.
ledValues_3_r[(numOfLeds-1)] = rgbResult[0];
ledValues_3_g[(numOfLeds-1)] = rgbResult[1];
ledValues_3_b[(numOfLeds-1)] = rgbResult[2];
// Here we assign the rest of the items in our led arrays. Since the color information needs to "shift" down the chain, we use ledValues 3 to hold
// the previous pattern, taken from ledValues 2. Then we take the newest pattern from ledValues 1 by referencing the same item + 1. effectively shifting
// everything down one. Since we read the value of our audio input into the first array item, it will be propogated as well.
for (int k = 0; k <= (numOfLeds-2); k++) {
if (k < (numOfLeds)) {
ledValues_3_r[k] = ledValues_2_r[k];
ledValues_3_g[k] = ledValues_2_g[k];
ledValues_3_b[k] = ledValues_2_b[k];
ledValues_2_r[k] = ledValues_1_r[k+1];
ledValues_2_g[k] = ledValues_1_g[k+1];
ledValues_2_b[k] = ledValues_1_b[k+1];
}
// Here we make sure we don't try and copy from an item that doesn't exist (total length of strip + 1) by using the above if statement.
// When it fails, we know we ran out of existing array items and we just do a direct assignment instead of +1. While this is technically
// incorrect it's the last one in the chain and wont really be noticeable..
ledValues_1_r[k] = ledValues_2_r[k];
ledValues_1_g[k] = ledValues_2_g[k];
ledValues_1_b[k] = ledValues_2_b[k];
}
// Here we update our interval timer, reseting it to the current time. When the difference beteween these two reach the specified max, the if statement
// is trigered again, and the colors are shifted yet again. Tweening happens between these events and uses the same information.
previousMillis = currentMillis;
}
// Here we calculate the normalized 0-1 count down from when the pixels were just updated, to when they will be updated again.
// We will use this value below to blend between before and next in realtime in timing with the actual shift.
trans_normalized = ((previousMillis + (float) stepSize) - currentMillis) / (float) stepSize;
// here we actually set the final rgb variables to set pixel colors with.
for (int i = 0; i <= (numOfLeds-1); i++) {
// By multiplying before by trans_normalized and next by (1 - trans_normalized) and adding the results we
// get a 1:1 brightness, a blend, or a cross fade if you will.
r_led = (float) ( (int) ((((float) ledValues_3_r[i]) * trans_normalized) + (((float) ledValues_1_r[i]) * (1.0 - trans_normalized))) ) * pot_Brightness_Val2;
g_led = (float) ( (int) ((((float) ledValues_3_g[i]) * trans_normalized) + (((float) ledValues_1_g[i]) * (1.0 - trans_normalized))) ) * pot_Brightness_Val2;
b_led = (float) ( (int) ((((float) ledValues_3_b[i]) * trans_normalized) + (((float) ledValues_1_b[i]) * (1.0 - trans_normalized))) ) * pot_Brightness_Val2;
// The next 3 lines are a massively important safety precaution for running this setup soley from the USB. no matter what shenannigans goes on above, we must clamp our
// max brightness to a value deemed safe for the power suppy. For usb I am keeping it at a very low and safe value of 64 which provides decent range for testing.
r_led = constrain( r_led, 0, maxBright);
g_led = constrain( g_led, 0, maxBright);
b_led = constrain( b_led, 0, maxBright);
// Actually setting the strip led's their respective colors.
strip.setPixelColor(i, r_led, g_led, b_led);
}
// refresh the strip and show off that hard work, microcontroller!
strip.show();
}