Skip to content

Instantly share code, notes, and snippets.

@headphones81
Created July 13, 2017 11:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save headphones81/d3474359f1b3744ce203b16905f93d5f to your computer and use it in GitHub Desktop.
Save headphones81/d3474359f1b3744ce203b16905f93d5f to your computer and use it in GitHub Desktop.
ESP8266 + FASTLED
int rgbarray[] = {100,150,200};
int Rval = rgbarray[0];
int Gval = rgbarray[1];
int Bval = rgbarray[2];
int Speed = 100;
int BRIGHTNESS = 255;
#define LED_DITHER 255 // try 0 to disable flickering
String Preset = "pnoise";
String PresetArray = "AutoVu,AutoStat,Static,blur,pnoise,beatwave,cylon,ripple,rainbow1,ripple2,Twinkle,pattern2,juggle2,pattern3,bpm,fire,vu,vu2,Vu3,Vu4,Vu6,niko,vu7,vu8,vu9,vu10";
String onoff = "ON";
uint8_t qCurrentPatternNumber = 0; // Index number of which pattern is current
String vucheck = "false" ,statcheck = "false" ,autocheck = "false";
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <Wire.h>
//#include <SPI.h>
#include "./Javascript.h"
#include "./HTML.h"
#define ESP8266
#include <Adafruit_NeoPixel.h>
//#include <NeoPixelBus.h>
//#include <NeoPixelAnimator.h>
#define FASTLED_ALLOW_INTERRUPTS 0
#define INTERRUPT_THRESHOLD 1
#define FASTLED_INTERRUPT_RETRY_COUNT 2
#define FASTLED_DEBUG_COUNT_FRAME_RETRIES 2
#include <FastLED.h>
#include "water_torture.h"
#define PIN D5
#define N_PIXELS 300
#define BG 0
#define COLOR_ORDER GRB // Try mixing up the letters (RGB, GBR, BRG, etc) for a whole new world of color combinations
#define LED_TYPE WS2812B
#define MIC_PIN A0 // Microphone is attached to this analog pin
#define DC_OFFSET 0 // DC offset in mic signal - if unusure, leave 0
#define NOISE 25 // Noise/hum/interference in mic signal
#define SAMPLES 40 // Length of buffer for dynamic level adjustment 60(default)
#define TOP (N_PIXELS + 2) // Allow dot to go slightly off scale
#define TOP2 (N_PIXELS + 1) // Allow dot to go slightly off scale
#define PEAK_FALL 5 // Rate of peak falling dot
#define N_PIXELS_HALF (N_PIXELS/2)
#define PEAK_FALL_MILLIS 10 // Rate of peak falling dot
#define GRAVITY -9.81 // Downward (negative) acceleration of gravity in m/s^2
#define h0 1 // Starting height, in meters, of the ball (strip length)
#define SPEED .20 // Amount to increment RGB color by each cycle
#define SPARKING 60
#define COOLING 85
#define FRAMES_PER_SECOND 60
#define LAST_PIXEL_OFFSET N_PIXELS-1
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
#define qsubd(x, b) ((x>b)?wavebright:0) // A digital unsigned subtraction macro. if result <0, then => 0. Otherwise, take on fixed value.
#define qsuba(x, b) ((x>b)?x-b:0)
#define SEGMENTS 7 // Number of segments to carve amplitude bar into
#define COLOR_WAIT_CYCLES 10 // Loop cycles to wait between advancing pixel origin
#define COLOR_MIN 0
#define COLOR_MAX 255
#define DRAW_MAX 100
uint8_t BeatsPerMinute = 65;
uint8_t gHue = 0;
float
greenOffset = 30,
blueOffset = 150;
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
int
reading,
vol[SAMPLES], // Collection of prior volume samples
lvl = 10, // Current "dampened" audio level
minLvlAvg = 0, // For dynamic adjustment of graph low & high
maxLvlAvg = 512;
//vu 8 variables
int
origin = 0,
color_wait_count = 0,
scroll_color = COLOR_MIN,
last_intensity = 0,
intensity_max = 0,
origin_at_flip = 0;
uint32_t
draw[DRAW_MAX];
boolean
growing = false,
fall_from_left = true;
//NOISE VARS
static uint16_t dist = random16(1000); // A random number for our noise generator.
uint16_t scale = 30;
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, PIN, NEO_GRB + NEO_KHZ800);
//NeoPixelBus<NeoBrgFeature, Neo800KbpsMethod> strip(N_PIXELS, PIN);
// Water torture
WaterTorture water_torture = WaterTorture(&strip);
// Modes
enum
{
} MODE;
bool test = true;
int BRIGHTNESS_MAX = 80;
int brightness = 20;
// cycle variables
int CYCLE_MIN_MILLIS = 2;
int CYCLE_MAX_MILLIS = 1000;
int cycleMillis = 20;
bool paused = false;
long lastTime = 0;
bool boring = true;
bool gReverseDirection = false;
// FOR SYLON ETC
uint8_t thisbeat = 23;
uint8_t thatbeat = 28;
uint8_t thisfade = 4; // How quickly does it fade? Lower = slower fade rate.
uint8_t thissat = 255; // The saturation, where 255 = brilliant colours.
uint8_t thisbri = 255;
//FOR JUGGLE
uint8_t numdots = 3; // Number of dots in use.
uint8_t faderate = 6; // How long should the trails be. Very low value = longer trails.
uint8_t hueinc = 16; // Incremental change in hue between each dot.
uint8_t thishue = 0; // Starting hue.
uint8_t curhue = 0;
uint8_t thisbright = 255; // How bright should the LED/display be.
uint8_t basebeat = 5;
uint8_t max_bright = 255;
// Twinkle
float redStates[N_PIXELS];
float blueStates[N_PIXELS];
float greenStates[N_PIXELS];
float Fade = 0.96;
unsigned int sample;
//Samples
#define NSAMPLES 64
unsigned int samplearray[NSAMPLES];
unsigned long samplesum = 0;
unsigned int sampleavg = 0;
int samplecount = 0;
//unsigned int sample = 0;
unsigned long oldtime = 0;
unsigned long newtime = 0;
CRGB leds[N_PIXELS];
int myhue = 0;
//Ripple variables
int color;
int center = 0;
int step = -1;
int maxSteps = 16;
float fadeRate = 0.80;
int diff;
//vu ripple
uint8_t colour;
uint8_t myfade = 255; // Starting brightness.
#define maxsteps 16 // Case statement wouldn't allow a variable.
int peakspersec = 0;
int peakcount = 0;
uint8_t bgcol = 0;
int thisdelay = 20;
//background color
uint32_t currentBg = random(256);
uint32_t nextBg = currentBg;
CRGBPalette16 currentPalette;
CRGBPalette16 targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 192, random8(128,255)), CHSV(random8(), 255, random8(128,255)));
TBlendType currentBlending;
const char* ssid = "Your-Wifi-SSID";
const char* password = "Your-PASSWORD";
ESP8266WebServer server(80);
unsigned long wait000 = 0UL, wait001 = 1000UL;
//SETUP
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
// ESP.wdtDisable(); // Postoqnno restartira !!!
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) delay(500);
WiFi.mode(WIFI_STA);
WiFi.setSleepMode(WIFI_NONE_SLEEP);
Serial.println(WiFi.localIP());
server.on("/", handleWebsite);
server.on("/xml", handleXML);
server.on("/SetRGB", handleRGB);
server.on("/Fade", handleFade);
server.on("/Speed", handleSpeed);
server.on("/Preset", handlePreset);
server.on("/flip", handleFlip);
server.begin();
delay( 100 ); // power-up safety delay
FastLED.addLeds<WS2812B, PIN, COLOR_ORDER>(leds, N_PIXELS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness( BRIGHTNESS );
memset(vol, 0, sizeof(vol));
LEDS.addLeds<LED_TYPE, PIN, COLOR_ORDER>(leds, N_PIXELS);
strip.begin();
strip.show(); // Initialize all pixels to 'off'
}
void SimpleHandle() {
}
//LOOP
void loop() {
server.handleClient();
if (millis() > wait000) {
buildXML();
wait000 = millis() + 1000UL;
}
FastLED.setBrightness( BRIGHTNESS );
FastLED.setDither(LED_DITHER);
strip.setBrightness(BRIGHTNESS);
//for mic
uint8_t i;
uint16_t minLvl, maxLvl;
int n, height;
// end mic
ESP.wdtFeed(); //Nahrani kucheto !!! Zasega biva :)
if ( onoff == "ON"){
if ( Preset == "AutoVu"){
All2();}
else if ( Preset == "AutoStat"){
All();}
else if ( Preset == "blur"){
blur();}
else if ( Preset == "pnoise"){
pnoise();}
else if ( Preset == "beatwave"){
beatwave();}
else if ( Preset == "Static"){
colorWipe(strip.Color(Rval, Gval, Bval), 100);}
else if ( Preset == "cylon"){
cylon();}
else if ( Preset == "ripple"){
ripple();}
else if ( Preset == "rainbow1"){
rainbow1();}
else if ( Preset == "ripple2"){
ripple2();}
else if ( Preset == "Twinkle"){
Twinkle();}
else if ( Preset == "pattern2"){
pattern2();}
else if ( Preset == "juggle2"){
juggle2();}
else if ( Preset == "pattern3"){
pattern3();}
else if ( Preset == "bpm"){
bpm();}
else if ( Preset == "fire"){
fire();}
else if ( Preset == "vu"){
vu();}
else if ( Preset == "vu2"){
vu2();}
else if ( Preset == "Vu3"){
Vu3();}
else if ( Preset == "Vu4"){
Vu4();}
else if ( Preset == "Vu6"){
Vu6();}
else if ( Preset == "niko"){
niko();}
else if ( Preset == "vu7"){
vu7();}
else if ( Preset == "vu8"){
vu8();}
else if ( Preset == "vu9"){
vu9();}
else if ( Preset == "vu10"){
vu10();}
else if ( Preset == "Simple"){
SimpleHandle();}
}
else colorWipe(strip.Color(0, 0, 0), 10);
//delayMicroseconds(500);
}
void handleWebsite() {
buildWebsite();
server.send(200, "text/html", webSite);
}
void handleRGB() {
String Rstr = {server.arg("r")};
String Gstr = {server.arg("g")};
String Bstr = {server.arg("b")};
Rval = constrain(Rstr.toInt(),0,255);
Gval = constrain(Gstr.toInt(),0,255);
Bval = constrain(Bstr.toInt(),0,255);
rgbarray[0] = Rval;
rgbarray[1] = Gval;
rgbarray[2] = Bval;
buildXML();
String RGBStr = String(Rval) + "," + String(Gval) + "," + String(Bval);
Serial.println("RGB:" + RGBStr);
server.send(200, "text/xml", XML);
}
void handleFade() {
String fadestr = {server.arg("f")};
BRIGHTNESS = constrain(fadestr.toInt(),0,255);
buildXML();
Serial.println("Fade:" + fadestr);
server.send(200, "text/xml", XML);
}
void handleSpeed() {
String speedstr = {server.arg("s")};
Speed = constrain(speedstr.toInt(),0,255);
buildXML();
Serial.println("Speed:" + speedstr);
server.send(200, "text/xml", XML);
}
void handlePreset() {
String presetstr = {server.arg("p")};
Preset = presetstr;
buildXML();
if ( presetstr == "AutoVu") { autocheck = "false"; statcheck = "false"; vucheck = "true";}
else if ( presetstr == "Static") { autocheck = "false"; statcheck = "true"; vucheck = "false";}
else if ( presetstr == "AutoStat") { autocheck = "true"; statcheck = "false"; vucheck = "false";}
else { autocheck = "false"; statcheck = "false"; vucheck = "false";}
//Serial.println(autocheck + vucheck + statcheck);
Serial.println("Preset:" + Preset);
server.send(200, "text/xml", XML);
}
void handleFlip() {
String flipstr = {server.arg("o")};
onoff = flipstr;
buildXML();
Serial.println(onoff);
server.send(200, "text/xml", XML);
}
void handleXML() {
buildXML();
server.send(200, "text/xml", XML);
}
void buildXML() {
XML = "<?xml version='1.0'?>";
XML += "<xml>";
XML += "<onoff>";
XML += String(onoff);
XML += "</onoff>";
XML += "<rgbarray>";
for (int i = 0 ; i <3 ; i++) {
XML += "<rgbarray" + (String)i + ">";
XML += String(rgbarray[i]);
XML += "</rgbarray" + (String)i + ">";
}
XML += "</rgbarray>";
XML += "<fade>";
XML += String(BRIGHTNESS);
XML += "</fade>";
XML += "<speed>";
XML += String(Speed);
XML += "</speed>";
XML += "<preset>";
XML += Preset;
XML += "</preset>";
XML += "</xml>";
}
void colorWipe(uint32_t c, uint8_t wait) {
for(uint16_t i=0; i<strip.numPixels(); i++) {
strip.setPixelColor(i, c);
strip.show();
}
}
void vu() {
uint8_t i;
uint16_t minLvl, maxLvl;
int n, height;
n = analogRead(MIC_PIN); // Raw reading from mic
n = abs(n - 474 - DC_OFFSET);
n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum
lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy)
Serial.print(lvl);
Serial.print(" ");
Serial.print(n);
Serial.println(" ");
// Calculate bar height based on dynamic min/max levels (fixed point):
height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
if(height < 0L) height = 0; // Clip output
else if(height > TOP) height = TOP;
if(height > peak) peak = height; // Keep 'peak' dot at top
// Serial.println(height);
// Color pixels based on rainbow gradient
for(i=0; i<=N_PIXELS/2; i++) {
if(i >= height) {
strip.setPixelColor(i, 0, 0, 0);
strip.setPixelColor(N_PIXELS-i, 0, 0, 0);
//strip.setPixelColor(N_PIXELS/2-1, 250, 0, 0);
}
else strip.setPixelColor(i,Wheel(map(i,0,strip.numPixels()/2-1,30,140))); //30 - 150
strip.setPixelColor(N_PIXELS-i-1,Wheel(map(i,0,strip.numPixels()/2-1,30,140)));
}
// Draw peak dot
if(peak > 0 && peak <= N_PIXELS-1)
strip.setPixelColor(peak,Wheel(map(peak,0,strip.numPixels()/2-1,30,150)));
strip.setPixelColor(N_PIXELS-peak,Wheel(map(peak,0,strip.numPixels()/2-1,30,150)));
strip.show(); // Update strip
// Every few frames, make the peak pixel drop by 1:
if(++dotCount >= PEAK_FALL) { //fall rate
if(peak > 0) peak--;
dotCount = 0;
}
vol[volCount] = n; // Save sample for dynamic leveling
if(++volCount >= SAMPLES) volCount = 0; // Advance/rollover sample counter
//else volCount++;
// 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)
}
// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
if(WheelPos < 85) {
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
} else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
} else {
WheelPos -= 170;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
}
void vu2() {
uint8_t i;
uint16_t minLvl, maxLvl;
int n, height;
n = analogRead(MIC_PIN); // Raw reading from mic
n = (n <= NOISE) ? 0 : (n - NOISE); // Remove noise/hum
lvl = ((lvl * 7) + n) >> 3; // "Dampened" reading (else looks twitchy) dobavil sym -8 na N
// Calculate bar height based on dynamic min/max levels (fixed point):
height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
if(height < 0L) height = 0; // Clip output
else if(height > TOP) height = TOP;
if(height > peak) peak = height; // Keep 'peak' dot at top
// Color pixels based on rainbow gradient
for(i=0; i<N_PIXELS_HALF; i++) {
if(i >= height) {
strip.setPixelColor(N_PIXELS_HALF-i-1, 0, 0, 0);
strip.setPixelColor(N_PIXELS_HALF+i, 0, 0, 0);
}
else {
uint32_t color = Wheel(map(i,0,N_PIXELS_HALF-1,30,150));
strip.setPixelColor(N_PIXELS_HALF-i-1,color);
strip.setPixelColor(N_PIXELS_HALF+i,color);
}
}
// Draw peak dot
if(peak > 0 && peak <= N_PIXELS_HALF-1) {
uint32_t color = Wheel(map(peak,0,N_PIXELS_HALF-1,30,150));
strip.setPixelColor(N_PIXELS_HALF-peak-1,color);
strip.setPixelColor(N_PIXELS_HALF+peak,color);
}
strip.show(); // Update strip
// Every few frames, make the peak pixel drop by 1:
if(++dotCount >= PEAK_FALL) { //fall rate
if(peak > 0) peak--;
dotCount = 0;
}
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)
}
void Vu3() {
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) Dobaveno -8 na N
// Calculate bar height based on dynamic min/max levels (fixed point):
height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
if (height < 0L) height = 0; // Clip output
else if (height > TOP) height = TOP;
if (height > peak) peak = height; // Keep 'peak' dot at top
greenOffset += SPEED;
blueOffset += SPEED;
if (greenOffset >= 255) greenOffset = 0;
if (blueOffset >= 255) blueOffset = 0;
// Color pixels based on rainbow gradient
for(i=0; i<N_PIXELS/2-2; i++) {
if(i >= height) {
strip.setPixelColor(i, 0, 0, 0);
strip.setPixelColor(N_PIXELS-i, 0, 0, 0);
strip.setPixelColor(height*2+i, 0, 0, 0);
}
else {
strip.setPixelColor(i, Wheel( map(i, 0, strip.numPixels()/2 - 1, (int)greenOffset, (int)blueOffset) ));
strip.setPixelColor(N_PIXELS-i-1, Wheel( map(i, 0, strip.numPixels()/2 - 1, (int)greenOffset, (int)blueOffset) ));
}
}
// Draw peak dot
if(peak > 0 && peak <= N_PIXELS-1)
strip.setPixelColor(peak,Wheel(map(peak,0,strip.numPixels()/2-1,30,150)));
strip.setPixelColor(N_PIXELS-peak,Wheel(map(peak,0,strip.numPixels()/2-1,30,150)));
strip.show(); // Update strip
// Every few frames, make the peak pixel drop by 1:
if(++dotCount >= PEAK_FALL) { //fall rate
if(peak > 0) peak--;
dotCount = 0;
}
strip.show(); // Update strip
vol[volCount] = n;
if (++volCount >= SAMPLES) {
volCount = 0;
}
// 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)
}
void Vu4() {
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 -8 ) >> 3; // "Dobaveno -8 na N
// Calculate bar height based on dynamic min/max levels (fixed point):
height = TOP * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
if(height < 0L) height = 0; // Clip output
else if(height > TOP) height = TOP;
if(height > peak) peak = height; // Keep 'peak' dot at top
greenOffset += SPEED;
blueOffset += SPEED;
if (greenOffset >= 255) greenOffset = 0;
if (blueOffset >= 255) blueOffset = 0;
// Color pixels based on rainbow gradient
for(i=0; i<N_PIXELS_HALF; i++) {
if(i >= height) {
strip.setPixelColor(N_PIXELS_HALF-i-1, 0, 0, 0);
strip.setPixelColor(N_PIXELS_HALF+i, 0, 0, 0);
}
else {
uint32_t color = Wheel(map(i,0,N_PIXELS_HALF-1,(int)greenOffset, (int)blueOffset));
strip.setPixelColor(N_PIXELS_HALF-i-1,color);
strip.setPixelColor(N_PIXELS_HALF+i,color);
}
}
// Draw peak dot
if(peak > 0 && peak <= N_PIXELS_HALF-1) {
uint32_t color = Wheel(map(peak,0,N_PIXELS_HALF-1,30,150));
strip.setPixelColor(N_PIXELS_HALF-peak-1,color);
strip.setPixelColor(N_PIXELS_HALF+peak,color);
}
strip.show(); // Update strip
// Every few frames, make the peak pixel drop by 1:
if(++dotCount >= PEAK_FALL) { //fall rate
if(peak > 0) peak--;
dotCount = 0;
}
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)
}
void Vu5()
{
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 -8 na N
// Calculate bar height based on dynamic min/max levels (fixed point):
height = TOP2 * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
if(height < 0L) height = 0; // Clip output
else if(height > TOP2) height = TOP2;
if(height > peak) peak = height; // Keep 'peak' dot at top
// Color pixels based on rainbow gradient
for(i=0; i<N_PIXELS/2; i++) {
if(i >= height) {
strip.setPixelColor(i, 0, 0, 0);
// strip.setPixelColor(N_PIXELS/2-i, 0, 0, 0);
strip.setPixelColor(N_PIXELS-i, 0, 0, 0);
}
else
{
strip.setPixelColor(i,(35+i)/i,i,60/i);
strip.setPixelColor(N_PIXELS-i,(35+i)/i,i,60/i);
// strip.setPixelColor(N_PIXELS/2-i,(35+i)/i,i,60/i);
// strip.setPixelColor(N_PIXELS/2+i,(35+i)/i,i,60/i);
}
}
// Draw peak dot
if(peak > 0 && peak <= LAST_PIXEL_OFFSET)
{
strip.setPixelColor(peak,Wheel(map(n,0,N_PIXELS/2,0,60))); //30 - 150
strip.setPixelColor(N_PIXELS-peak,Wheel(map(n,0,N_PIXELS/2,0,60)));
strip.setPixelColor(peak+3,Wheel(map(n,0,N_PIXELS/2,60,80))); //30 - 150
strip.setPixelColor(N_PIXELS-peak-3,Wheel(map(n,0,N_PIXELS/2,60,80)));
strip.setPixelColor(peak+6,Wheel(map(n,0,N_PIXELS/2,80,120))); //30 - 150
strip.setPixelColor(N_PIXELS-peak-6,Wheel(map(n,0,N_PIXELS/2,80,120)));
strip.setPixelColor(peak+9,Wheel(map(n,0,N_PIXELS/2,200,80))); //30 - 150
strip.setPixelColor(N_PIXELS-peak-9,Wheel(map(n,0,N_PIXELS/2,200,80)));
}
// Every few frames, make the peak pixel drop by 1:
if (millis() - lastTime >= 50)
{
lastTime = millis();
strip.show(); // Update strip
//fall rate
if(peak > 0) peak--;
}
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) < TOP2) maxLvl = minLvl + TOP2;
minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)
}
void Vu6()
{
uint8_t i;
uint16_t minLvl, maxLvl;
int n, height;
n = analogRead(MIC_PIN); // Raw reading from mic
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 = TOP2 * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
if(height < 0L) height = 0; // Clip output
else if(height > TOP2) height = TOP2;
if(height > peak) peak = height; // Keep 'peak' dot at top
//#define CENTERED
#ifdef CENTERED
// Draw peak dot
if(peak > 0 && peak <= LAST_PIXEL_OFFSET)
{
strip.setPixelColor(((N_PIXELS/2) + peak),0,0,0); // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
strip.setPixelColor(((N_PIXELS/2) - peak),0,0,0); // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
}
#else
// Color pixels based on rainbow gradient
for(i=0; i<N_PIXELS/2; i++)
{
if(i >= height)
{
strip.setPixelColor(i, 0, 0, 0);
strip.setPixelColor(N_PIXELS-i-1, 0, 0, 0);
//fadeToBlackBy( leds, N_PIXELS-i-1, 1);
//fadeToBlackBy( leds,i, 1);
}
else
{
strip.setPixelColor(i,(255-i*15),0,constrain(height,0,205-peak));
strip.setPixelColor(N_PIXELS-i,(255-i*15),0,constrain(height,0,205-peak));
strip.setPixelColor(N_PIXELS_HALF,0,0,0);
}
}
// Draw peak dot
if(peak >0 && peak <= LAST_PIXEL_OFFSET)
{
//show_at_max_brightness_for_power();
strip.setPixelColor(peak+5,(int)sqrt(peak)*2,0+peak,200+(peak)); // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
strip.setPixelColor(N_PIXELS-peak-5,(int)sqrt(peak)*2,0+peak,200+(peak));
strip.setPixelColor(peak+(int)log(2*peak)*10,2*(int)sqrt(peak),10+peak/2,2*peak); // (peak,Wheel(map(peak,0,strip.numPixels()-1,30,150)));
strip.setPixelColor(N_PIXELS-peak-(int)log(2*peak)*10,2*(int)sqrt(peak),10+peak/2,2*peak);
if(peak >50 && peak <= LAST_PIXEL_OFFSET)
{
strip.setPixelColor(N_PIXELS_HALF,110,peak,110);
strip.setPixelColor(N_PIXELS_HALF+2,110,peak,110);} //center
if(peak >55 && peak == LAST_PIXEL_OFFSET)
{
strip.setPixelColor(N_PIXELS_HALF-14,255,peak,150); //corners
strip.setPixelColor(N_PIXELS_HALF+17,255,peak,150);
}
if(peak >40 && peak <= LAST_PIXEL_OFFSET)
{
strip.setPixelColor(N_PIXELS_HALF-peak/3,200,i,200); //corners
strip.setPixelColor(N_PIXELS_HALF+peak/3,random(140,220),i,random(180,220));}
if(peak >50 && peak <= LAST_PIXEL_OFFSET)
{
strip.setPixelColor(N_PIXELS_HALF-peak/4,250,i*2,250); //corners
strip.setPixelColor(N_PIXELS_HALF+peak/4,250,i*2,250);}
if(peak >=60 && peak <= LAST_PIXEL_OFFSET)
{
strip.setPixelColor(N_PIXELS_HALF+1,255,255,255);}
}
#endif
// Every few frames, make the peak pixel drop by 1:
if (millis() - lastTime >= PEAK_FALL_MILLIS)
{
lastTime = millis();
strip.show(); // Update strip
//fall rate
if(peak > 0) peak--;
}
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) < TOP2) maxLvl = minLvl + TOP2;
minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)
}
void vu7() {
EVERY_N_MILLISECONDS(1000) {
peakspersec = peakcount; // Count the peaks per second. This value will become the foreground hue.
peakcount = 0; // Reset the counter every second.
}
soundmems();
EVERY_N_MILLISECONDS(20) {
ripple3();
}
//FastLED.show();
show_at_max_brightness_for_power();
} // loop()
void soundmems() { // Rolling average counter - means we don't have to go through an array each time.
newtime = millis();
int tmp = analogRead(MIC_PIN); //- 512;
sample = abs(tmp);
int potin = map(Speed, 0, 255, 0, 60);
samplesum = samplesum + sample - samplearray[samplecount]; // Add the new sample and remove the oldest sample in the array
sampleavg = samplesum / NSAMPLES; // Get an average
samplearray[samplecount] = sample; // Update oldest sample in the array with new sample
samplecount = (samplecount + 1) % NSAMPLES; // Update the counter for the array
if (newtime > (oldtime + 200)) digitalWrite(13, LOW); // Turn the LED off 200ms after the last peak.
if ((sample > (sampleavg + potin)) && (newtime > (oldtime + 60)) ) { // Check for a peak, which is 30 > the average, but wait at least 60ms for another.
step = -1;
peakcount++;
digitalWrite(13, HIGH);
oldtime = newtime;
// Serial.println(potin);
}
} // soundmems()
void ripple3() {
for (int i = 0; i < N_PIXELS; i++) leds[i] = CHSV(bgcol, 255, sampleavg*2); // Set the background colour.
switch (step) {
case -1: // Initialize ripple variables.
center = random(N_PIXELS);
colour = (peakspersec*10) % 255; // More peaks/s = higher the hue colour.
step = 0;
bgcol = bgcol+8;
break;
case 0:
leds[center] = CHSV(colour, 255, 255); // Display the first pixel of the ripple.
step ++;
break;
case maxsteps: // At the end of the ripples.
// step = -1;
break;
default: // Middle of the ripples.
leds[(center + step + N_PIXELS) % N_PIXELS] += CHSV(colour, 255, myfade/step*2); // Simple wrap from Marc Miller.
leds[(center - step + N_PIXELS) % N_PIXELS] += CHSV(colour, 255, myfade/step*2);
step ++; // Next step.
break;
} // switch step
} // ripple()
//040216
void vu8() {
int intensity = calculateIntensity();
updateOrigin(intensity);
assignDrawValues(intensity);
writeSegmented();
//uint32_t *segmented = segmentAndResize(draw);
//writeToStrip(segmented);
updateGlobals();
}
int calculateIntensity() {
int intensity;
reading = analogRead(MIC_PIN); // Raw reading from mic
reading = (reading <= NOISE) ? 0 : (reading - NOISE); // Remove noise/hum
lvl = ((lvl * 7) + reading) >> 3; // "Dampened" reading (else looks twitchy)
// Calculate bar height based on dynamic min/max levels (fixed point):
intensity = DRAW_MAX * (lvl - minLvlAvg) / (long)(maxLvlAvg - minLvlAvg);
return constrain(intensity, 0, DRAW_MAX-1);
}
void updateOrigin(int intensity) {
// detect peak change and save origin at curve vertex
if (growing && intensity < last_intensity) {
growing = false;
intensity_max = last_intensity;
fall_from_left = !fall_from_left;
origin_at_flip = origin;
} else if (intensity > last_intensity) {
growing = true;
origin_at_flip = origin;
}
last_intensity = intensity;
// adjust origin if falling
if (!growing) {
if (fall_from_left) {
origin = origin_at_flip + ((intensity_max - intensity) / 2);
} else {
origin = origin_at_flip - ((intensity_max - intensity) / 2);
}
// correct for origin out of bounds
if (origin < 0) {
origin = DRAW_MAX - abs(origin);
} else if (origin > DRAW_MAX - 1) {
origin = origin - DRAW_MAX - 1;
}
}
}
void assignDrawValues(int intensity) {
// draw amplitue as 1/2 intensity both directions from origin
int min_lit = origin - (intensity / 2);
int max_lit = origin + (intensity / 2);
if (min_lit < 0) {
min_lit = min_lit + DRAW_MAX;
}
if (max_lit >= DRAW_MAX) {
max_lit = max_lit - DRAW_MAX;
}
for (int i=0; i < DRAW_MAX; i++) {
// if i is within origin +/- 1/2 intensity
if (
(min_lit < max_lit && min_lit < i && i < max_lit) // range is within bounds and i is within range
|| (min_lit > max_lit && (i > min_lit || i < max_lit)) // range wraps out of bounds and i is within that wrap
) {
draw[i] = Wheel(scroll_color);
} else {
draw[i] = 0;
}
}
}
void writeSegmented() {
int seg_len = N_PIXELS / SEGMENTS;
for (int s = 0; s < SEGMENTS; s++) {
for (int i = 0; i < seg_len; i++) {
strip.setPixelColor(i + (s*seg_len), draw[map(i, 0, seg_len, 0, DRAW_MAX)]);
}
}
strip.show();
}
uint32_t * segmentAndResize(uint32_t* draw) {
int seg_len = N_PIXELS / SEGMENTS;
uint32_t segmented[N_PIXELS];
for (int s = 0; s < SEGMENTS; s++) {
for (int i = 0; i < seg_len; i++) {
segmented[i + (s * seg_len) ] = draw[map(i, 0, seg_len, 0, DRAW_MAX)];
}
}
return segmented;
}
void writeToStrip(uint32_t* draw) {
for (int i = 0; i < N_PIXELS; i++) {
strip.setPixelColor(i, draw[i]);
}
strip.show();
}
void updateGlobals() {
uint16_t minLvl, maxLvl;
//advance color wheel
color_wait_count++;
if (color_wait_count > COLOR_WAIT_CYCLES) {
color_wait_count = 0;
scroll_color++;
if (scroll_color > COLOR_MAX) {
scroll_color = COLOR_MIN;
}
}
vol[volCount] = reading; // 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(uint8_t 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) < N_PIXELS) maxLvl = minLvl + N_PIXELS;
minLvlAvg = (minLvlAvg * 63 + minLvl) >> 6; // Dampen min/max levels
maxLvlAvg = (maxLvlAvg * 63 + maxLvl) >> 6; // (fake rolling average)
}
//monday
void vu9() {
currentBlending = LINEARBLEND;
EVERY_N_SECONDS(5) { // Change the target palette to a random one every 5 seconds.
static uint8_t baseC = random8(); // You can use this as a baseline colour if you want similar hues in the next line.
for (int i = 0; i < 16; i++) {
targetPalette[i] = CHSV(random8(), 255, 255);
}
}
EVERY_N_MILLISECONDS(100) {
uint8_t maxChanges = 24;
nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // AWESOME palette blending capability.
}
EVERY_N_MILLISECONDS(thisdelay) { // FastLED based non-blocking delay to update/display the sequence.
soundble();
FastLED.show();
}
} // loop()
void soundble() {
int n;
n = analogRead(MIC_PIN); // Raw reading from mic
n = qsuba(abs(n), 10); // Center on zero and get rid of low level noise
CRGB newcolour = ColorFromPalette(currentPalette, constrain(n,0,255), constrain(n,0,255), currentBlending);
nblend(leds[0], newcolour, 128);
for (int i = N_PIXELS-1; i>0; i--) {
leds[i] = leds[i-1];
}
} // soundmems()
void vu10() {
EVERY_N_MILLISECONDS(1000) {
peakspersec = peakcount; // Count the peaks per second. This value will become the foreground hue.
peakcount = 0; // Reset the counter every second.
}
soundrip();
EVERY_N_MILLISECONDS(20) {
rippled();
}
FastLED.show();
} // loop()
void soundrip() { // Rolling average counter - means we don't have to go through an array each time.
newtime = millis();
int tmp = analogRead(MIC_PIN);
sample = abs(tmp);
int potin = map(Speed, 0, 255, 0, 60);
samplesum = samplesum + sample - samplearray[samplecount]; // Add the new sample and remove the oldest sample in the array
sampleavg = samplesum / NSAMPLES; // Get an average
// Serial.println(sampleavg);
samplearray[samplecount] = sample; // Update oldest sample in the array with new sample
samplecount = (samplecount + 1) % NSAMPLES; // Update the counter for the array
if (newtime > (oldtime + 200)) digitalWrite(13, LOW); // Turn the LED off 200ms after the last peak.
if ((sample > (sampleavg + potin)) && (newtime > (oldtime + 60)) ) { // Check for a peak, which is 30 > the average, but wait at least 60ms for another.
step = -1;
peakcount++;
oldtime = newtime;
}
} // soundmems()
void rippled() {
fadeToBlackBy(leds, N_PIXELS, 64); // 8 bit, 1 = slow, 255 = fast
switch (step) {
case -1: // Initialize ripple variables.
center = random(N_PIXELS);
colour = (peakspersec*10) % 255; // More peaks/s = higher the hue colour.
step = 0;
break;
case 0:
leds[center] = CHSV(colour, 255, 255); // Display the first pixel of the ripple.
step ++;
break;
case maxsteps: // At the end of the ripples.
// step = -1;
break;
default: // Middle of the ripples.
leds[(center + step + N_PIXELS) % N_PIXELS] += CHSV(colour, 255, myfade/step*2); // Simple wrap from Marc Miller.
leds[(center - step + N_PIXELS) % N_PIXELS] += CHSV(colour, 255, myfade/step*2);
step ++; // Next step.
break;
} // switch step
} // ripple()
// Slightly different, this makes the rainbow equally distributed throughout
void rainbowCycle(int wait) {
uint16_t i, j;
for(j=0; j<256*5; j++) { // 5 cycles of all colors on wheel
for(i=0; i< strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
}
strip.show();
}
}
void ripple() {
if (currentBg == nextBg) {
nextBg = random(256);
}
else if (nextBg > currentBg) {
currentBg++;
} else {
currentBg--;
}
for(uint16_t l = 0; l < N_PIXELS; l++) {
leds[l] = CHSV(currentBg, 255, 50); // strip.setPixelColor(l, Wheel(currentBg, 0.1));
}
if (step == -1) {
center = random(N_PIXELS);
color = random(256);
step = 0;
}
if (step == 0) {
leds[center] = CHSV(color, 255, 255); // strip.setPixelColor(center, Wheel(color, 1));
step ++;
}
else {
if (step < maxSteps) {
// Serial.println(pow(fadeRate,step));
leds[wrap(center + step)] = CHSV(color, 255, pow(fadeRate, step)*255); // strip.setPixelColor(wrap(center + step), Wheel(color, pow(fadeRate, step)));
leds[wrap(center - step)] = CHSV(color, 255, pow(fadeRate, step)*255); // strip.setPixelColor(wrap(center - step), Wheel(color, pow(fadeRate, step)));
if (step > 3) {
leds[wrap(center + step - 3)] = CHSV(color, 255, pow(fadeRate, step - 2)*255); // strip.setPixelColor(wrap(center + step - 3), Wheel(color, pow(fadeRate, step - 2)));
leds[wrap(center - step + 3)] = CHSV(color, 255, pow(fadeRate, step - 2)*255); // strip.setPixelColor(wrap(center - step + 3), Wheel(color, pow(fadeRate, step - 2)));
}
step ++;
}
else {
step = -1;
}
}
LEDS.show();
delay(50);
}
int wrap(int step) {
if(step < 0) return N_PIXELS + step;
if(step > N_PIXELS - 1) return step - N_PIXELS;
return step;
}
void one_color_allHSV(int ahue, int abright) { // SET ALL LEDS TO ONE COLOR (HSV)
for (int i = 0 ; i < N_PIXELS; i++ ) {
leds[i] = CHSV(ahue, 255, abright);
}
}
void ripple2() {
if (BG){
if (currentBg == nextBg) {
nextBg = random(256);
}
else if (nextBg > currentBg) {
currentBg++;
} else {
currentBg--;
}
for(uint16_t l = 0; l < N_PIXELS; l++) {
strip.setPixelColor(l, Wheel(currentBg, 0.1));
}
} else {
for(uint16_t l = 0; l < N_PIXELS; l++) {
strip.setPixelColor(l, 0, 0, 0);
}
}
if (step == -1) {
center = random(N_PIXELS);
color = random(256);
step = 0;
}
if (step == 0) {
strip.setPixelColor(center, Wheel(color, 1));
step ++;
}
else {
if (step < maxSteps) {
strip.setPixelColor(wrap(center + step), Wheel(color, pow(fadeRate, step)));
strip.setPixelColor(wrap(center - step), Wheel(color, pow(fadeRate, step)));
if (step > 3) {
strip.setPixelColor(wrap(center + step - 3), Wheel(color, pow(fadeRate, step - 2)));
strip.setPixelColor(wrap(center - step + 3), Wheel(color, pow(fadeRate, step - 2)));
}
step ++;
}
else {
step = -1;
}
}
strip.show();
delay(50);
}
void fire(){
#define FRAMES_PER_SECOND 40
//random16_add_entropy( random());
// Array of temperature readings at each simulation cell
static byte heat[N_PIXELS];
// Step 1. Cool down every cell a little
for( int i = 0; i < N_PIXELS; i++) {
heat[i] = qsub8( heat[i], random8(0, ((COOLING * 10) / N_PIXELS) + 2));
}
// Step 2. Heat from each cell drifts 'up' and diffuses a little
for( int k= N_PIXELS - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
}
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
if( random8() < SPARKING ) {
int y = random8(7);
heat[y] = qadd8( heat[y], random8(160,255) );
}
// Step 4. Map from heat cells to LED colors
for( int j = 0; j < N_PIXELS; j++) {
// Scale the heat value from 0-255 down to 0-240
// for best results with color palettes.
byte colorindex = scale8( heat[j], 240);
CRGB color = ColorFromPalette( CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::Yellow, CRGB::White), colorindex);
int pixelnumber;
if( gReverseDirection ) {
pixelnumber = (N_PIXELS-1) - j;
} else {
pixelnumber = j;
}
leds[pixelnumber] = color;
}
FastLED.show();
}
void bpm(){
CRGBPalette16 palette = PartyColors_p;
uint8_t beat = beatsin8( map(Speed,0,100,20,150), 64, 255);
for( int i = 0; i < N_PIXELS; i++) { //9948
fadeToBlackBy( leds, N_PIXELS, thisfade);
leds[i] = ColorFromPalette(palette, gHue+(i*2), beat-gHue+(i*10));
blur1d( leds, N_PIXELS, random(100,172));
FastLED.show();
//for( int k = 1; k < i; k++) {
// leds[k] = CRGB::Black; }
}
gHue = gHue+50;
}
void Drip()
{
MODE_WATER_TORTURE:
if (cycle())
{
strip.setBrightness(BRIGHTNESS); // off limits
water_torture.animate(test);
strip.show();
//strip.setBrightness(brightness); // back to limited
}
}
bool cycle()
{
if (paused)
{
return false;
}
if (millis() - lastTime >= cycleMillis)
{
lastTime = millis();
return true;
}
return false;
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos, float opacity) {
if(WheelPos < 85) {
return strip.Color((WheelPos * 3) * opacity, (255 - WheelPos * 3) * opacity, 0);
}
else if(WheelPos < 170) {
WheelPos -= 85;
return strip.Color((255 - WheelPos * 3) * opacity, 0, (WheelPos * 3) * opacity);
}
else {
WheelPos -= 170;
return strip.Color(0, (WheelPos * 3) * opacity, (255 - WheelPos * 3) * opacity);
}
}
void pattern2() {
sinelon(); // Call our sequence.
show_at_max_brightness_for_power(); // Power managed display of LED's.
//FastLED.show();
} // loop()
void rainbow1(){
int raindelay = map(Speed,0,255,10,200);
rainbow(raindelay);
Serial.println(raindelay);
}
void sinelon() {
// a colored dot sweeping back and forth, with fading trails
fadeToBlackBy( leds, N_PIXELS, thisfade);
int pos1 = beatsin16(thisbeat,0,N_PIXELS);
int pos2 = beatsin16(thatbeat,0,N_PIXELS);
leds[(pos1+pos2)/2] += CHSV( myhue++/64, thissat, thisbri);
}
// Pattern 3 - JUGGLE
void pattern3() {
ChangeMe();
juggle();
//FastLED.show();
show_at_max_brightness_for_power(); // Power managed display of LED's.
} // loop()
void juggle() { // Several colored dots, weaving in and out of sync with each other
curhue = thishue; // Reset the hue values.
fadeToBlackBy(leds, N_PIXELS, faderate);
for( int i = 0; i < numdots; i++) {
leds[beatsin16(basebeat+i+numdots,0,N_PIXELS)] += CHSV(curhue, thissat, thisbright); //beat16 is a FastLED 3.1 function
curhue += hueinc;
}
} // juggle()
void ChangeMe() { // A time (rather than loop) based demo sequencer. This gives us full control over the length of each sequence.
uint8_t secondHand = (millis() / 1000) % 60; // IMPORTANT!!! Change '30' to a different value to change duration of the loop.
static uint8_t lastSecond = 99; // Static variable, means it's only defined once. This is our 'debounce' variable.
if (lastSecond != secondHand) { // Debounce to make sure we're not repeating an assignment.
lastSecond = secondHand;
if (secondHand == 0) {numdots=1; faderate=2;} // You can change values here, one at a time , or altogether.
if (secondHand == 10) {numdots=4; thishue=128; faderate=8;}
if (secondHand == 20) {hueinc=48; thishue=random8();} // Only gets called once, and not continuously for the next several seconds. Therefore, no rainbows.
}
} // ChangeMe()
void juggle2() { // Several colored dots, weaving in and out of sync with each other
// eight colored dots, weaving in and out of sync with each other
fadeToBlackBy( leds, N_PIXELS, 20);
byte dothue = 0;
for( int i = 0; i < 8; i++) {
leds[beatsin16(i+7,0,N_PIXELS)] |= CHSV(dothue, 200, 255);
dothue += 32;
}
FastLED.show();
}
void Twinkle () {
if (random(25) == 1) {
uint16_t i = random(N_PIXELS);
if (redStates[i] < 1 && greenStates[i] < 1 && blueStates[i] < 1) {
redStates[i] = random(256);
greenStates[i] = random(256);
blueStates[i] = random(256);
}
}
for(uint16_t l = 0; l < N_PIXELS; l++) {
if (redStates[l] > 1 || greenStates[l] > 1 || blueStates[l] > 1) {
strip.setPixelColor(l, redStates[l], greenStates[l], blueStates[l]);
if (redStates[l] > 1) {
redStates[l] = redStates[l] * Fade;
} else {
redStates[l] = 0;
}
if (greenStates[l] > 1) {
greenStates[l] = greenStates[l] * Fade;
} else {
greenStates[l] = 0;
}
if (blueStates[l] > 1) {
blueStates[l] = blueStates[l] * Fade;
} else {
blueStates[l] = 0;
}
} else {
strip.setPixelColor(l, 0, 0, 0);
}
}
strip.show();
delay(10);
}
void blur() {
uint8_t blurAmount = dim8_raw( beatsin8(map(Speed,0,255,1,7),64, 172) ); // A sinewave at 3 Hz with values ranging from 64 to 192.
blur1d( leds, N_PIXELS, blurAmount); // Apply some blurring to whatever's already on the strip, which will eventually go black.
uint8_t i = beatsin8(map(Speed,0,255,6,38), N_PIXELS,0 );
uint8_t j = beatsin8(map(Speed,0,255,4,34), 0, N_PIXELS);
uint8_t k = beatsin8(map(Speed,0,255,2,30), 0, N_PIXELS);
// The color of each point shifts over time, each at a different speed.
uint16_t ms = millis();
leds[constrain(abs(i+j)/2,0,N_PIXELS)] = leds[N_PIXELS - constrain(abs(i+j)/2,0,N_PIXELS)] = CHSV( ms / 29, 200, 255);
leds[constrain(abs(j+k),0,N_PIXELS)] = leds[N_PIXELS - constrain(abs(j+k),0,N_PIXELS)] = CHSV( ms / 41, 200, 255);
leds[constrain(abs(k+i)/2,0,N_PIXELS)] = leds[N_PIXELS - constrain(abs(k+i)/2,0,N_PIXELS)] = CHSV( ms / 73, 200, 255);
leds[abs(k)] = leds[abs(N_PIXELS-k)] = CHSV( ms / 53, 200, 255);
//show_at_max_brightness_for_power();
ESP.wdtFeed();
FastLED.show();
}
void rainbow(uint8_t wait) {
uint16_t i, j;
EVERY_N_MILLISECONDS(wait) {
for(j=0; j<256; j++) {
for(i=0; i<strip.numPixels(); i++) {
//strip.setPixelColor(i, Wheel((i+j) & 255));
leds[i] = CHSV(j-i, 200 , 255);
}
yield();
//strip.show();
// check if a button pressed
}
ESP.wdtFeed();
FastLED.show();
// delay(wait);
}
}
// List of patterns to cycle through. Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
SimplePatternList gPatterns = {blur,pnoise,beatwave,cylon,ripple,rainbow1,ripple2,Twinkle,pattern2,juggle2,pattern3,bpm,fire};
uint8_t gCurrentPatternNumber = 0; // Index number of which pattern is current
void nextPattern()
{
// add one to the current pattern number, and wrap around at the end
gCurrentPatternNumber = (gCurrentPatternNumber + 1) % ARRAY_SIZE( gPatterns);
}
void All()
{
// Call the current pattern function once, updating the 'leds' array
gPatterns[gCurrentPatternNumber]();
EVERY_N_SECONDS( 30 ) { nextPattern(); } // change patterns periodically
}
// second list
// List of patterns to cycle through. Each is defined as a separate function below.
typedef void (*SimplePatternList[])();
SimplePatternList qPatterns = {vu,vu2,Vu3,Vu4,Vu6,niko,vu7,vu8,vu9,vu10};
//uint8_t qCurrentPatternNumber = 0; // Index number of which pattern is current
void nextPattern2()
{
// add one to the current pattern number, and wrap around at the end
qCurrentPatternNumber = (qCurrentPatternNumber + 1) % ARRAY_SIZE( qPatterns);
}
void All2()
{
// Call the current pattern function once, updating the 'leds' array
qPatterns[qCurrentPatternNumber]();
EVERY_N_SECONDS( 30 ) { nextPattern2(); } // change patterns periodically
}
//Niko
void fadeall() { for(int i = 0; i < N_PIXELS; i++) { leds[i].nscale8(250); } }
void cylon() {
static uint8_t hue = 0;
for(int i = 0; i < N_PIXELS; i++) {
leds[i] = CHSV(hue++, 255, 255);
fadeall();
FastLED.delay(map(Speed,0,255,100,0));
}
for(int i = (N_PIXELS)-1; i >= 0; i--) {
leds[i] = CHSV(hue++, 255, 255);
fadeall();
FastLED.delay(map(Speed,0,255,100,0));
}
ESP.wdtFeed();
FastLED.show();
}
void beatwave() {
EVERY_N_MILLISECONDS(map(Speed,0,255,100,25)) {
uint8_t maxChanges = 24;
nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // AWESOME palette blending capability.
}
EVERY_N_SECONDS(map(Speed,0,255,60,1)) { // Change the target palette to a random one every 5 seconds.
targetPalette = CRGBPalette16(CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 255, random8(128,255)), CHSV(random8(), 192, random8(128,255)), CHSV(random8(), 255, random8(128,255)));
}
uint8_t wave1 = beatsin8(9, 0, 255); // That's the same as beatsin8(9);
uint8_t wave2 = beatsin8(8, 0, 255);
uint8_t wave3 = beatsin8(7, 0, 255);
uint8_t wave4 = beatsin8(6, 0, 255);
for (int i=0; i<N_PIXELS; i++) {
leds[i] = ColorFromPalette( currentPalette, i+wave1+wave2+wave3+wave4, 255, currentBlending);
}
FastLED.show();
ESP.wdtFeed();
} // beatwave()
void niko(){
Vu4();
vu();
} // Niko()}
void pnoise(){
uint8_t maxChanges = 48;
EVERY_N_MILLISECONDS(10) {
nblendPaletteTowardPalette(currentPalette, targetPalette, maxChanges); // Blend towards the target palette
fillnoise8(); // Update the LED array with noise at the new location
}
EVERY_N_SECONDS(map(Speed,0,255,300,5)) { // Change the target palette to a random one every N seconds.
targetPalette = CRGBPalette16(CHSV(random8(), 50, random8(20,255)), CHSV(random8(), 255, random8(5,128)), CHSV(random8(), 192, random8(50,100)), CHSV(random8(), 255, random8(128,255)));
dist = random16(1000);
}
LEDS.show(); // Display the LED's at every loop cycle.
ESP.wdtFeed();
} // loop()
void fillnoise8() {
for(int i = 0; i < N_PIXELS; i++) { // Just ONE loop to fill up the LED array as all of the pixels change.
uint8_t index = inoise8(i*30, dist+i*30) % 255; // Get a value from the noise function. I'm using both x and y axis.
leds[i] = ColorFromPalette(currentPalette, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED.
}
dist += beatsin8(3,1, 10); // Moving along the distance (that random number we started out with). Vary it a bit with a sine wave.
yield();
} // fillnoise8()
//#include "./Javascript.h"
void buildWebsite() {
buildJavascript();
//webSite = javaScript;
webSite = "<!DOCTYPE html>\n";
webSite += "<html>\n";
webSite += "<head>\n";
webSite += "<meta charset='utf-8'>\n";
webSite += "<meta name='viewport' content='width=device-width, initial-scale=1'>\n";
webSite += "<title>LED CONTROL APP</title>\n";
webSite += "<link rel='shortcut icon' href='http://forum.arduino.cc/favicon.ico'>\n";
webSite += "<link rel='stylesheet' href='http://fonts.googleapis.com/css?family=Open+Sans:300,400,700'>\n";
webSite += "<link rel='stylesheet' href='http://demos.jquerymobile.com/1.4.5/css/themes/default/jquery.mobile-1.4.5.min.css'>\n";
webSite += "<link rel='stylesheet' href='http://demos.jquerymobile.com/1.4.5/_assets/css/jqm-demos.css'>\n";
webSite += "<script src='http://demos.jquerymobile.com/1.4.5/js/jquery.js'></script>\n";
webSite += "<script src='http://demos.jquerymobile.com/1.4.5/_assets/js/index.js'></script>\n";
webSite += "<script src='http://demos.jquerymobile.com/1.4.5/js/jquery.mobile-1.4.5.min.js'></script>\n";
webSite += "</head>\n";
webSite += "<style>\n";
webSite += "#page {\n";
webSite += "height: device-height;\n";
webSite += "background: linear-gradient(to bottom , AliceBlue 0%,White 50%,Azure 100%);\n";
webSite += "}\n";
webSite += "input,select { background: linear-gradient(to bottom , Azure 0%,white 50%,AliceBlue 100%); }\n";
webSite += "</style>\n";
webSite += "<div data-role='page' id='page'>\n";
webSite += "<body onload='process()'>\n";
webSite += "<div class='ui-corner-all custom-corners style=text-align:center'>\n";
webSite += "<div class='ui-bar ui-bar-a'>\n";
webSite += "<h3>Led Control v.1.0b 20170609 (radiocheckboxes fixed ├┼─)</h3>\n";
webSite += "</div>\n";
webSite += "<select type='select' data-role='flipswitch' name='flip' id='flip' data-theme='a' data-inline='true' onchange='on1off()'>\n";
webSite += "<option value='ON'>ON</option>\n";
webSite += "<option value='OFF'>OFF</option>\n";
webSite += "</select>\n";
webSite += "<span id='udpvu'></span><br />\n";
webSite += "<form action='#' method='get' id='modeform'>\n";
webSite += "<div class='ui-field-contain'>\n";
webSite += "<fieldset data-role='controlgroup' data-type='horizontal' content='width=device-width, initial-scale=1'>\n";
webSite += "<input type='radio' name='radioName' id='VU' value='VU' onclick='VUselect()'>\n";
webSite += "<label for='VU'>VU</label>\n";
webSite += "<input type='radio' name='radioName' id='Static' value='Static' onclick='Statselect()'>\n";
webSite += "<label for='Static'>Static</label>\n";
webSite += "<input type='radio' name='radioName' id='Auto' value='Auto' onclick='Autoselect()'>\n";
webSite += "<label for='Auto'>Auto</label>\n";
webSite += "</fieldset>\n";
webSite += "</div>\n";
webSite += "<label for='select-choice' data-inline='true' >Preset:</label>\n";
webSite += "<select name='select-choice' id='select-choice' data-mini='false' data-native-menu='true' data-inline='true' onchange='presetF()'>\n";
webSite += "</select>\n";
webSite += "</form>\n";
webSite += "<script src='https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js'></script>\n";
webSite += "<div style='bold'>\n";
webSite += "<input id=\"chcolor\" type=\"button\" class=\"jscolor {mode:'HVS',position:'bottom',onFineChange:'update(this)',width:300, height:150,borderColor:'#FFF', insetColor:'#FFF',backgroundColor:'#666'}\" data-type=\"inline\" data-theme=\"b\" value=\"Color\" style=\"border:10px solid gray;text-align:center\" />\n";
webSite += "</div>\n";
webSite += "<p id='rect' style='border:1px solid gray; width:device-width; height:100px;text-align:center'>\n";
webSite += "<span id='rgbrect' ></span><br />\n";
webSite += "RGB:<span id='rgbtext' ></span><br />\n";
webSite += "<!-- toRGBString = <span id='rgb-str'></span><br />\n";
webSite += "R, G, B = <span id='rgb'></span><br /> -->\n";
webSite += "</p>\n";
webSite += "<form id='sliderform'>\n";
webSite += "<label for=\"slider-speed\">Speed:</label>\n";
webSite += "<input type='range' data-type='range' data-highlight='true' id='slider-speed' min='0' max='255' step='1' value=" + String(Speed) + " ONINPUT='sliderS()' onchange='sliderS()'>\n";
webSite += "<label for='slider-fade'>Fade:</label>\n";
webSite += "<input type='range' data-type='range' data-highlight='true' id='slider-fade' min='0' max='255' step='1' value=" + String(BRIGHTNESS) + " ONINPUT='sliderF()' onchange='sliderF()'>\n";
webSite += "</form>\n";
webSite += javaScript;
webSite += "</div></div><!-- /page --></body></html>\n";
//
}
String javaScript, XML, webSite;
void buildJavascript() {
javaScript = "<!-- AJAX ON CREATE -->\n";
javaScript += "<script>\n";
javaScript += "$( document ).on( \"pagecreate\", function() {\n";
javaScript += "var rgbarray = [" + (String)rgbarray[0] + "," + (String)rgbarray[1] + "," + (String)rgbarray[2] + "];\n";
javaScript += "var hexrgb = '#000080';\n";
javaScript += "var flip1 = \"ON\";\n";
//Select
javaScript += "var selectVU, fLen;\n";
//javaScript += "var selectVU = \"Auto,vu, vu2, Vu3, Vu4, Vu5, Vu6, vu7, vu8, vu9, vu10,neshto drugo,Още Нещо\";\n";
//javaScript += "var sVU = \"vu2\";\n";
javaScript += "var selectVU = \"" + PresetArray + "\";\n";
javaScript += "selectVU = selectVU.split(',');\n";
javaScript += "fLen = selectVU.length;\n";
javaScript += "text = \"\";\n";
javaScript += "for (i = 0; i < fLen; i++) {\n";
javaScript += "text += \"<option value='\" + selectVU[i] + \"'>\" + selectVU[i] + \"</option>\";\n";
javaScript += "}\n";
javaScript += "document.getElementById('select-choice').innerHTML = text;\n";
javaScript += "$('#select-choice').val(\"" + Preset + "\");\n";
javaScript += "$('#select-choice').selectmenu( \"refresh\" );\n";
javaScript += "$('#flip').val(\"" + onoff + "\").flipswitch(\"refresh\");\n";
javaScript += "$('#slider-speed').attr('value' ," + String(Speed) + ");\n";
javaScript += "$('#slider-fade').attr('value' ," + String(BRIGHTNESS) + ").slider('refresh');\n";
javaScript += "$('#rgbtext').text(\"" + (String)rgbarray[0] + "," + (String)rgbarray[1] + "," + (String)rgbarray[2] + "\");\n";
javaScript += "$('#rect').css('background-color', 'rgb(" + String(Rval) + "," + String(Gval) + "," + String(Bval) + ")');\n";
javaScript += "$('#udpvu').text(\"" + (String)Preset + "\");\n";
javaScript += "$('#VU').prop('checked', " + String(vucheck) + ").checkboxradio(\"refresh\");\n";
javaScript += "$('#Static').prop('checked', " + String(statcheck) + ").checkboxradio(\"refresh\");\n";
javaScript += "$('#Auto').prop('checked', " + String(autocheck) + ").checkboxradio(\"refresh\");\n";
javaScript += "});\n";
javaScript += "</script>\n";
javaScript += "<!-- AJAX ON CHANGE -->\n";
javaScript += "<script>\n";
javaScript += "$(\"#flip\").click(function() {\n";
javaScript += "var flip1 = $(this).value\n";
javaScript += "}); </script>\n";
//COLOR PICKER
javaScript += "<script>\n";
javaScript += "<!-- COLOR PICKER -->\n";
javaScript += "function update(picker) {\n";
javaScript += "var Rval = Math.round(picker.rgb[0]);\n";
javaScript += "var Gval = Math.round(picker.rgb[1]);\n";
javaScript += "var Bval = Math.round(picker.rgb[2]);\n";
javaScript += "document.getElementById('rect').style.backgroundColor = '#' + picker;\n";
javaScript += "var hexrgb = picker.toHEXString();\n";
javaScript += "var rgbarray = [ Math.round(picker.rgb[0]) , Math.round(picker.rgb[1]) , Math.round(picker.rgb[2]) ];\n";
javaScript += "document.getElementById('rgbtext').innerHTML = rgbarray;\n";
//XMLHTTP COLORPICKER
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','SetRGB?r='+Rval+'&g='+Gval+'&b='+Bval,true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
javaScript += "</script>\n";
//XMLHTTP
javaScript += "<SCRIPT>\n";
javaScript += "xmlHttp=createXmlHttpObject();\n";
javaScript += "function createXmlHttpObject(){\n";
javaScript += " if(window.XMLHttpRequest){\n";
javaScript += " xmlHttp=new XMLHttpRequest();\n";
javaScript += " }else{\n";
javaScript += " xmlHttp=new ActiveXObject('Microsoft.XMLHTTP');\n";
javaScript += " }\n";
javaScript += " return xmlHttp;\n";
javaScript += "}\n";
javaScript += "function process(){\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.onreadystatechange=function(){\n";
javaScript += " if(xmlHttp.readyState==4&&xmlHttp.status==200){\n";
javaScript += " xmlDoc=xmlHttp.responseXML;\n";
javaScript += " xmlmsg=xmlDoc.getElementsByTagName('rgbarray0')[0].firstChild.nodeValue;\n";
javaScript += " xmlmsg+=\",\"\n";
javaScript += " xmlmsg+=xmlDoc.getElementsByTagName('rgbarray1')[0].firstChild.nodeValue;\n";
javaScript += " xmlmsg+=\",\"\n";
javaScript += " xmlmsg+=xmlDoc.getElementsByTagName('rgbarray2')[0].firstChild.nodeValue;\n";
javaScript += " document.getElementById('rgbtext').innerHTML=xmlmsg;\n";
javaScript += " document.getElementById('rect').style.backgroundColor = 'rgb(xmlmsg)';\n";
javaScript += " xmlmsg=xmlDoc.getElementsByTagName('fade')[0].firstChild.nodeValue;\n";
javaScript += " document.getElementById('slider-fade').value=xmlmsg;\n";
javaScript += " xmlmsg=xmlDoc.getElementsByTagName('speed')[0].firstChild.nodeValue;\n";
javaScript += " document.getElementById('slider-speed').value=xmlmsg;\n";
javaScript += " xmlmsg=xmlDoc.getElementsByTagName('preset')[0].firstChild.nodeValue;\n";
javaScript += " document.getElementById('select-choice').value=xmlmsg;\n";
javaScript += " xmlmsg=xmlDoc.getElementsByTagName('onoff')[0].firstChild.nodeValue;\n";
javaScript += " document.getElementById('flip').value=xmlmsg;\n";
//javaScript += " document.getElementById('rect').style.backgroundColor = 'rgb(" + String(Rval) + "," + String(Gval) + "," + String(Bval) + ")';\n";
// javaScript += " for(i=0;i<" + (String)sliderMAX + ";i++){\n";
// javaScript += " xmlmsg=xmlDoc.getElementsByTagName('rgbarray')[0].firstChild.nodeValue;\n";
// javaScript += " document.getElementById('rgbarray').value=xmlmsg;\n";
//javaScript += " document.getElementById('rgbarray').innerHTML=xmlmsg;\n";
// javaScript += " xmlmsg=xmlDoc.getElementsByTagName('fade')[0].firstChild.nodeValue;\n";
//javaScript += " document.getElementById('slider-fade').value=" + String(Fade)+ " ;\n";
//javaScript += " }\n";
javaScript += " }\n";
javaScript += " }\n";
javaScript += " xmlHttp.open('PUT','xml',true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += " setTimeout('process()',1000);\n";
javaScript += "}\n";
//FADE
javaScript += "function sliderF(){\n";
javaScript += " sliderVal=document.getElementById('slider-fade').value;\n";
javaScript += " document.getElementById('slider-fade').innerHTML=sliderVal;\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','Fade?f=' + sliderVal,true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
//SPEED
javaScript += "function sliderS(){\n";
javaScript += " sliderVal=document.getElementById('slider-speed').value;\n";
javaScript += " document.getElementById('slider-speed').innerHTML=sliderVal;\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','Speed?s=' + sliderVal,true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
//PRESET
javaScript += "function presetF(){\n";
javaScript += " presetVal=document.getElementById('select-choice').value;\n";
javaScript += " document.getElementById('select-choice').value=presetVal;\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','Preset?p=' + presetVal,true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
//ON1OFF
javaScript += "function on1off() {\n";
javaScript += " onoff=document.getElementById('flip').value;\n";
javaScript += " document.getElementById('select-choice').value=onoff;\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','flip?o=' + onoff,true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
//VUselect
javaScript += "function VUselect() {\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','Preset?p=AutoVu',true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
//Statselect
javaScript += "function Statselect() {\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','Preset?p=Static',true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
//Autoselect
javaScript += "function Autoselect() {\n";
javaScript += " if(xmlHttp.readyState==0||xmlHttp.readyState==4){\n";
javaScript += " xmlHttp.open('PUT','Preset?p=AutoStat',true);\n";
javaScript += " xmlHttp.send(null);\n";
javaScript += " }\n";
javaScript += "}\n";
javaScript += "</SCRIPT>\n";
}
#ifndef RGB_H_
#define RGB_H_
namespace ws2811 {
/**
* Type that holds RGB values.
* The in-memory order of this type is actually GRB, but the constructor takes
* its values in RGB order.
*/
struct rgb
{
rgb(uint8_t red, uint8_t green, uint8_t blue)
:green(green),red(red),blue(blue)
{}
rgb()
:green(0),red(0),blue(0)
{}
uint8_t green;
uint8_t red;
uint8_t blue;
};
}
#endif /* RGB_H_ */
#ifndef RGB_OPERATORS_HPP_
#define RGB_OPERATORS_HPP_
#include "rgb.h"
namespace ws2811
{
namespace detail {
inline uint8_t add_clipped( uint16_t left, uint16_t right)
{
uint16_t result = left + right;
if (result > 255) result = 255;
return result;
}
}
inline void add_clipped( rgb &left, const rgb &right)
{
using detail::add_clipped;
left = rgb(
add_clipped(left.red, right.red),
add_clipped( left.green, right.green),
add_clipped( left.blue, right.blue)
);
}
}
#endif /* RGB_OPERATORS_HPP_ */
#ifndef WATER_TORTURE_HPP_
#define WATER_TORTURE_HPP_
#include "rgb_operators.h"
#include <Adafruit_NeoPixel.h>
#include <string.h>
namespace
{
using ws2811::rgb;
uint8_t mult( uint8_t value, uint16_t multiplier)
{
return (static_cast<uint16_t>( value) * multiplier) >> 8;
}
/// This class maintains the state and calculates the animations to render a falling water droplet
/// Objects of this class can have three states:
/// - inactive: this object does nothing
/// - swelling: the droplet is at the top of the led strip and swells in intensity
/// - falling: the droplet falls downwards and accelerates
/// - bouncing: the droplet has bounced of the ground. A smaller, less intensive droplet bounces up
/// while a part of the drop remains on the ground.
/// After going through the swelling, falling and bouncing phases, the droplet automatically returns to the
/// inactive state.
class droplet
{
public:
droplet( const rgb &color, uint16_t gravity)
:color( color), position(0), speed(0),
gravity( gravity), state(swelling)
{}
droplet()
:color(0,0,0), position(0), speed(0),
gravity(0), state( inactive)
{
}
/// calculate the next step in the animation for this droplet
void step( uint8_t maxpos)
{
if (state == falling || state == bouncing)
{
position += speed;
speed += gravity;
// if we hit the bottom...
const uint16_t maxpos16 = maxpos << 8;
if (position > maxpos16)
{
if (state == bouncing)
{
// this is the second collision,
// deactivate.
state = inactive;
}
else
{
// reverse direction and dampen the speed
position = maxpos16 - (position - maxpos16);
speed = -speed/4;
color = scale( color, 10);
state = bouncing;
}
}
}
else if (state == swelling)
{
++position;
if ( color.blue <= 10 || color.blue - position <= 10)
{
state = falling;
position = 0;
}
}
}
/// perform one step and draw.
void step( rgb *leds, uint8_t ledcount, bool reverse)
{
step( ledcount - 1);
draw( leds, ledcount - 1, reverse);
}
/// Draw the droplet on the led string
/// This will "smear" the light of this droplet between two leds. The closer
/// the droplets position is to that of a particular led, the brighter that
/// led will be
void draw( rgb *leds, uint8_t max_pos, bool reverse)
{
if (state == falling || state == bouncing)
{
uint8_t position8 = position >> 8;
uint8_t remainder = position; // get the lower bits
uint8_t last = max_pos;
uint8_t pos = position8;
uint8_t pos1 = position8+1;
if (reverse)
{
last = 0;
pos = max_pos-position8;
pos1 = pos-1;
}
else
{
last = max_pos;
pos = position8;
pos1 = pos+1;
}
add_clipped_to( leds[pos], scale( color, 256 - remainder ));
if (remainder)
{
add_clipped_to( leds[pos1], scale( color, remainder));
}
if (state == bouncing)
{
add_clipped_to( leds[last], color);
}
}
else if (state == swelling)
{
uint8_t first;
if (reverse)
{
first = max_pos;
}
else
{
first = 0;
}
add_clipped_to( leds[first], scale( color, position));
}
}
bool is_active() const
{
return state != inactive;
}
private:
/// Add two numbers and clip the result at 255.
static uint8_t add_clipped( uint16_t left, uint16_t right)
{
uint16_t result = left + right;
if (result > 255) result = 255;
return result;
}
/// Add the right rgb value to the left one, clipping if necessary
static void add_clipped_to( rgb &left, const rgb &right)
{
left.red = add_clipped(left.red, right.red);
left.green = add_clipped( left.green, right.green);
left.blue = add_clipped( left.blue, right.blue);
}
/// multiply an 8-bit value with an 8.8 bit fixed point number.
/// multiplier should not be higher than 1.00 (or 256).
static uint8_t mult( uint8_t value, uint16_t multiplier)
{
return (static_cast<uint16_t>( value) * multiplier) >> 8;
}
/// scale an rgb value up or down. amplitude > 256 means scaling up, while
/// amplitude < 256 means scaling down.
static rgb scale(rgb value, uint16_t amplitude)
{
return rgb(
mult( value.red, amplitude),
mult( value.green, amplitude),
mult( value.blue, amplitude)
);
}
// how much of a color is left when colliding with the floor, value
// between 0 and 256 where 256 means no loss.
static const uint16_t collision_scaling = 40;
rgb color;
uint16_t position;
int16_t speed;
uint16_t gravity;
enum stateval {
inactive,
swelling,
falling,
bouncing
};
stateval state;
};
uint8_t debugcount = 0;
volatile uint16_t random_scale()
{
return (rand() % 256);
}
void create_random_droplet( droplet &d)
{
d = droplet(
rgb(
mult( 100 ,random_scale()),
mult( 100, random_scale()),
mult(255, random_scale())
), 5);
}
}
class WaterTorture
{
public:
WaterTorture( Adafruit_NeoPixel *strip)
{
this->strip = strip;
current_droplet = 0; // index of the next droplet to be created
droplet_pause = 1; // how long to wait for the next one
}
void animate (bool reverse)
{
if (droplet_pause)
{
--droplet_pause;
}
else
{
if (!droplets[current_droplet].is_active())
{
create_random_droplet( droplets[current_droplet]);
++current_droplet;
if (current_droplet >= droplet_count) current_droplet = 0;
droplet_pause = 100 + rand() % 80;
}
}
rgb *leds = (rgb *)strip->getPixels();
memset( leds, 0, strip->numPixels()*sizeof(rgb));
for (uint8_t idx = 0; idx < droplet_count; ++idx)
{
droplets[idx].step( leds, strip->numPixels(), reverse);
}
// for (uint8_t i = 0; i < strip->numPixels(); i++)
// {
// strip->setPixelColor(i, leds->red, leds->green, leds->blue); // overwrite with brightness
// leds++;
// }
}
private:
Adafruit_NeoPixel *strip;
static const uint8_t droplet_count = 4;
droplet droplets[droplet_count]; // droplets that can animate simultaneously.
uint8_t current_droplet; // index of the next droplet to be created
uint8_t droplet_pause; // how long to wait for the next one
};
#endif /* WATER_TORTURE_HPP_ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment