diff --git a/esp8266-fastled-iot-webserver.ino b/esp8266-fastled-iot-webserver.ino index 8daff3304622db3272432b41a5e9eff4e2cef8d3..ac410ffdc9d1f9322b29a96f7571764e2e52be30 100644 --- a/esp8266-fastled-iot-webserver.ino +++ b/esp8266-fastled-iot-webserver.ino @@ -16,7 +16,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #define FASTLED_INTERRUPT_RETRY_COUNT 1 -#define FASTLED_ALLOW_INTERRUPTS 0 +//#define FASTLED_ALLOW_INTERRUPTS 0 #include <FastLED.h> FASTLED_USING_NAMESPACE extern "C" { @@ -142,10 +142,10 @@ extern "C" { //---------------------------------------------------------------------------------------------------------// //#define ACCESS_POINT_MODE // the esp8266 will create a wifi-access point instead of connecting to one, credentials must be in Secrets.h - //#define ENABLE_OTA_SUPPORT // requires ArduinoOTA - library, not working on esp's with 1MB memory (esp-01, Wemos D1 lite ...) + #define ENABLE_OTA_SUPPORT // requires ArduinoOTA - library, not working on esp's with 1MB memory (esp-01, Wemos D1 lite ...) //#define OTA_PASSWORD "passwd123" // password that is required to update the esp's firmware wireless - //#define ENABLE_MULTICAST_DNS // allows to access the UI via "http://<HOSTNAME>.local/", implemented by GitHub/WarDrake + #define ENABLE_MULTICAST_DNS // allows to access the UI via "http://<HOSTNAME>.local/", implemented by GitHub/WarDrake #define RANDOM_AUTOPLAY_PATTERN // if enabled the next pattern for autoplay is choosen at random #define AUTOPLAY_IGNORE_UDP_PATTERNS // remove visualization patterns from autoplay @@ -313,10 +313,11 @@ if you have connected the ring first it should look like this: const int twpOffs #define PACKET_LENGTH LENGTH #define NUM_LEDS (HEIGHT * LENGTH) #define PACKET_LENGTH LENGTH + #define BAND_GROUPING 1 #elif DEVICE_TYPE == 2 #define PACKET_LENGTH NUM_LEDS - + #define BAND_GROUPING 1 IPAddress timeServerIP; WiFiUDP udpTime; @@ -330,12 +331,15 @@ if you have connected the ring first it should look like this: const int twpOffs #elif DEVICE_TYPE == 3 #define NUM_LEDS (LINE_COUNT * LEDS_PER_LINE) #define PACKET_LENGTH LEDS_PER_LINE + #define BAND_GROUPING 1 #elif DEVICE_TYPE == 4 #define NUM_LEDS (PIXELS_PER_LEAF * LEAFCOUNT) #define PACKET_LENGTH (LEAFCOUNT * 3) + #define BAND_GROUPING 1 #elif VISUALIZER_TYPE == 5 + #define BAND_GROUPING 1 #ifdef TWENTYONEPILOTS #define NUM_LEDS (RING_LENGTH+DOT_LENGTH+DOUBLE_STRIP_LENGTH+ITALIC_STRIP_LENGTH) #endif @@ -353,7 +357,7 @@ if you have connected the ring first it should look like this: const int twpOffs // Misc Params #define AVG_ARRAY_SIZE 10 -#define BAND_START 1 +#define BAND_START 0 #define BAND_END 3 // can be increased when working with bigger spectrums (40+) #define UDP_PORT 4210 @@ -561,6 +565,9 @@ PatternAndNameList patterns = { { SolidColorComplementary, "Solid-Color Complementary Bullet Visualizer"}, { BluePurpleBullets, "Blue/Purple Bullet Visualizer"}, { BulletVisualizer, "Beat-Bullet Visualization"}, + //{ RainbowPeaks, "Rainbow Peak Visualizer"}, // broken + { RainbowBassRings, "Bass Ring Visualizer"}, + { RainbowKickRings, "Kick Ring Visualizer"}, //{ TrailingBulletsVisualizer, "Trailing Bullet Visualization"}, // obsolete //{ BrightnessVisualizer, "Brightness Visualizer"}, // broken { RainbowBandVisualizer, "Rainbow Band Visualizer"}, @@ -1249,7 +1256,8 @@ void loop() { FastLED.show(); // insert a delay to keep the framerate modest - FastLED.delay(1000 / FRAMES_PER_SECOND); + //FastLED.delay(1000 / FRAMES_PER_SECOND); + delay(1000 / FRAMES_PER_SECOND); } void loadSettings() @@ -2571,17 +2579,17 @@ bool parseUdp() int getVolume(uint8_t vals[], int start, int end, double factor) { - int result = 0; + double result = 0; int iter = 0; - //Serial.printf("%d, start: %d, end: %d\n", vals[iter], start, end); + int cnt = 0; + //Serial.printf("Nr: %d, %d, start: %d, end: %d\n", iter, vals[iter], start, end); for (iter = start; iter <= end && vals[iter] != '\0'; iter++) { - //Serial.println(vals[iter]); - result += vals[iter]; + //Serial.printf("Nr: %d, %d, start: %d, end: %d\n", iter, vals[iter], start, end); + result += ((double)vals[iter]*factor)/(end-start + 1); } - if (result == 0)return 0; - if(end > start)result = result / (end-start); - result = int(((double)result) * factor); + //Serial.println(result); + if (result <= 1) result = 0; if (result > 255)result = 255; return result; } @@ -2774,6 +2782,166 @@ void vuMeterTriColor() #endif } +int getPeakPosition() { + int pos = 0; + byte posval = 0; + for (int i = 0; i <= (PACKET_LENGTH - 1) && incomingPacket[i] != '\0'; i++) + { + if (incomingPacket[i] > posval) { + pos = i; + posval = incomingPacket[i]; + } + } + if (posval < 30) pos = -1; + return pos; +} + +void printPeak(CHSV c, int pos, int grpSize) { + fadeToBlackBy(leds, NUM_LEDS, 12); + leds[pos] = c; + CHSV c2 = c; + c2.v = 150; + for (int i = 0; i < ((grpSize - 1) / 2); i++) + { + leds[pos + i] = c; + leds[pos - i] = c; + } + +} + +void peakVisualizer(CHSV c, bool newValues) { + static int lastPos = 0; + static int moveDir = 1; // 1: up, 0: down, 2: static + int newPos = lastPos; + if (newValues) { + newPos = getPeakPosition(); + if (newPos > lastPos) moveDir = 1; + else if (newPos < lastPos) moveDir = 0; + else moveDir = 2; + } + + int v = 3; + if (moveDir == 1 && (lastPos +v) <= newPos) { + lastPos += v; + } + else if (moveDir == 0 && (lastPos - v) >= newPos) { + lastPos -= v; + } + + int update_rate = map(speed, 0, 70, 100, 0); + if (newPos == -1 || lastPos < 0) { + fadeToBlackBy(leds, NUM_LEDS, 5); + lastPos == -1; + moveDir = 2; + } + else if (update_rate >= 0) + { + printPeak(c, lastPos, v); + delay(update_rate); + } + else + { + int steps = map(update_rate, -264, 0, 8, 0); + ShiftLeds(steps); + } + //lastPos = newPos; +} + +void RainbowPeaks() +{ + if (!parseUdp()) + { + peakVisualizer(rgb2hsv_approximate(solidColor), false); + } else peakVisualizer(rgb2hsv_approximate(solidColor), true); +} + +void RainbowKickRings() +{ + if (!parseUdp()) + { + kickRingVisualizer(CHSV(gHue, 255, 255), false); + } + else kickRingVisualizer(CHSV(gHue, 255, 255), true); +} + +void RainbowBassRings() +{ + if (!parseUdp()) + { + bassRingVisualizer(CHSV(gHue, 255, 255), false); + } + else bassRingVisualizer(CHSV(gHue, 255, 255), true); +} + +#define RING_FILL_PERCENTAGE 0.35 +#define RING_FADED_PERCENTAGE 0.25 +void bassRingVisualizer(CHSV c, bool newValues) { + static double position = 5.0; + if (newValues) + { + double currentVolume = getVolume(incomingPacket, BAND_START, BAND_END, 1) / 200.0; + position += currentVolume * ((double)(map(speed, 0, 255, 10, 300) / 100.0)) * BAND_GROUPING; + if (position >= NUM_LEDS)position -= NUM_LEDS; + } + paintRing(c, position, NUM_LEDS * RING_FILL_PERCENTAGE, NUM_LEDS * RING_FADED_PERCENTAGE); +} + +void kickRingVisualizer(CHSV c, bool newValues) { + static double position = 5.0; + static int i_pos = 0; + static int arrsize = 5; + static uint8_t lastVals[5] = { 1,1,1,1,1 }; + int currentVolume = 0; + int avgVolume = 0; + double cd = 0; + if (newValues) + { + currentVolume = getVolume(incomingPacket, BAND_START, BAND_END, 1); + avgVolume = getVolume(lastVals, 0, arrsize - 1, 1); + if (avgVolume != 0)cd = ((double)currentVolume) / ((double)avgVolume); + if (currentVolume < 33)cd = 0; + if (currentVolume > 230) cd += 0.15; + cd -= 0.2; + if (cd <= 0 || currentVolume < 33)cd = 0; + else cd += 0.2; + position += cd * 2 * ((double)(map(speed, 0, 255, 10, 300) / 100.0)) * BAND_GROUPING; + //Serial.printf("cur: %d, avg: %d, cd: %lf, pos: %lf\n", currentVolume, avgVolume, cd, position); + while (position >= NUM_LEDS)position -= NUM_LEDS; + + if (i_pos >= arrsize)i_pos = 0; + lastVals[i_pos] = currentVolume; + i_pos++; + } + paintRing(c, position, NUM_LEDS * RING_FILL_PERCENTAGE, NUM_LEDS * RING_FADED_PERCENTAGE); +} + +void paintRing(CHSV c, int pos, int fillLength, int fadedLength) +{ + fill_solid(leds, NUM_LEDS, CRGB::Black); + for (int i = 0; i < fadedLength; i++) + { + leds[(i + pos) > (NUM_LEDS - 1) ? (i + pos - NUM_LEDS) : (i + pos)] = getFadedColor(c, fadedLength - i, fadedLength); + } + for (int i = 0; i < fillLength; i++) + { + leds[(i + pos + fadedLength) > (NUM_LEDS - 1) ? (i + pos + fadedLength - NUM_LEDS) : (i + pos + fadedLength)] = c; + } + for (int i = 0; i < fadedLength; i++) + { + leds[(i + pos + fadedLength + fillLength) > (NUM_LEDS - 1) ? (i + pos + fadedLength + fillLength - NUM_LEDS) : (i + pos + fadedLength + fillLength)] = getFadedColor(c, i, fadedLength);; + } +} + +CHSV getFadedColor(CHSV c, int iter, int amount) +{ + c.val = (int)((double)c.val * ((double)(amount - iter)) / ((double)(amount+1.0))); + return c; +} + +//void paintRing(CHSV c, int fillStart, int fillEnd, int fadedStart, int fadedEnd) +//{ +// return; +//} void vuMeterSolid() { @@ -3605,7 +3773,7 @@ void mainAlexaEvent(EspalexaDevice* d) { static int lb; if ((lr != NULL && lr != d->getR() && lg != d->getG() && lb != d->getB()) || currentPatternIndex == patternCount - 1) { - setSolidColor(d->getR(), d->getG(), d->getB()); + setSolidColor(d->getR(), d->getG(), d->getB(), true); setPattern(patternCount - 1); } lr = d->getR();