From 1344a78509e98fa1b426efb888576c7aff157a0c Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Mon, 28 Oct 2024 15:58:52 -0700 Subject: [PATCH 1/8] Test of RGBW Branch --- config/partitions_custom.csv | 14 +- include/deviceconfig.h | 4 +- include/effectmanager.h | 14 +- include/effects.h | 4 + include/effects/matrix/spectrumeffects.h | 165 ++++++++++++++++++++--- include/effects/strip/faneffects.h | 37 +++-- include/effects/strip/meteoreffect.h | 12 +- include/effects/strip/misceffects.h | 21 ++- include/gfxbase.h | 1 + include/globals.h | 88 ++++++++---- include/ledstripeffect.h | 37 ++--- include/ledstripgfx.h | 15 ++- include/screen.h | 2 + include/soundanalyzer.h | 13 ++ platformio.ini | 22 ++- samples/videoserver/pcstats.py | 8 +- src/audio.cpp | 2 +- src/drawing.cpp | 2 +- src/effectmanager.cpp | 2 +- src/effects.cpp | 31 +++-- src/ledmatrixgfx.cpp | 2 +- src/main.cpp | 10 ++ src/network.cpp | 3 +- src/remotecontrol.cpp | 26 +++- src/screen.cpp | 33 ++++- 25 files changed, 444 insertions(+), 124 deletions(-) diff --git a/config/partitions_custom.csv b/config/partitions_custom.csv index a1d7dd45a..518e7ff4a 100644 --- a/config/partitions_custom.csv +++ b/config/partitions_custom.csv @@ -1,12 +1,8 @@ -# ESP-IDF Partition Table -# This gives us some additional space for code. -# It should also fix the OTA regression. -# Name, Type, SubType, Offset, Size, Flags - -# Note that our NVS code assumes name 'storage' for the NVS partition +# Standard 4M partition layout with OTA (Over the air updates) +# Name, Type, SubType, Offset, Size, Flags nvs, data, nvs, 0x00b000, 0x002000, otadata, data, ota, 0x00d000, 0x002000, -app0, app, ota_0, 0x010000, 0x190000, -app1, app, ota_1, 0x1A0000, 0x190000, -storage, data, spiffs, 0x330000, 0x0D0000 \ No newline at end of file +app0, app, ota_0, 0x010000, 0x1A0000, +app1, app, ota_1, 0x1B0000, 0x1A0000, +storage, data, spiffs, 0x350000, 0x0B0000 diff --git a/include/deviceconfig.h b/include/deviceconfig.h index 7153945f5..db8bd2351 100644 --- a/include/deviceconfig.h +++ b/include/deviceconfig.h @@ -84,7 +84,9 @@ #define DEVICE_CONFIG_FILE "/device.cfg" #define NTP_SERVER_DEFAULT "0.pool.ntp.org" -#define BRIGHTNESS_MIN uint8_t(10) +#ifndef BRIGHTNESS_MIN + #define BRIGHTNESS_MIN uint8_t(10) +#endif #define BRIGHTNESS_MAX uint8_t(255) #define POWER_LIMIT_MIN 1000 #define POWER_LIMIT_DEFAULT 4500 diff --git a/include/effectmanager.h b/include/effectmanager.h index c81dfd0e1..4fbc9d6d2 100644 --- a/include/effectmanager.h +++ b/include/effectmanager.h @@ -153,9 +153,19 @@ class EffectManager : public IJSONSerializable ClearEffects(); } - std::shared_ptr GetBaseGraphics() + // SetTempEffect - Sets a temporary effect to be played until remote changes it. + // The effect must have already had its Init() function called. + + void SetTempEffect(std::shared_ptr effect) + { + _tempEffect = effect; + } + + // GetBaseGraphics - Returns the vector of GFXBase objects that the effects use to draw + + std::vector> & GetBaseGraphics() { - return _gfx[0]; + return _gfx; } bool IsNewFrameAvailable() const diff --git a/include/effects.h b/include/effects.h index 68479344d..622f440a6 100644 --- a/include/effects.h +++ b/include/effects.h @@ -83,6 +83,7 @@ #define EFFECT_STRIP_FAN_BEAT 37 #define EFFECT_STRIP_SPLASH_LOGO 38 #define EFFECT_STRIP_VUMETER 39 +#define EFFECT_STRIP_VUMETER_VERTICAL 40 // Matrix effects #define EFFECT_MATRIX_ALIEN_TEXT 101 @@ -147,6 +148,7 @@ #define EFFECT_MATRIX_STOCKS 159 #define EFFECT_MATRIX_SILON 160 #define EFFECT_MATRIX_PDPGRID 161 +#define EFFECT_MATRIX_AUDIOSPIKE 162 // Hexagon Effects #define EFFECT_HEXAGON_OUTER_RING 201 @@ -183,6 +185,7 @@ #define PTY_SPARKS "spc" #define PTY_SPARKING "spg" #define PTY_SPARKHEIGHT "sph" +#define PTY_SPARKTEMP "spt" #define PTY_COOLING "clg" #define PTY_PALETTE "plt" #define PTY_ORDER "ord" @@ -194,6 +197,7 @@ #define PTY_MAXSPEED "mxs" #define PTY_SPEEDDIVISOR "sdd" #define PTY_DELTAHUE "dth" +#define PTY_MIRRORED "mrd" #define PTY_EVERYNTH "ent" #define PTY_COLOR "clr" #define PTY_BLEND "bld" diff --git a/include/effects/matrix/spectrumeffects.h b/include/effects/matrix/spectrumeffects.h index ce96ec8a7..fa2e75cce 100644 --- a/include/effects/matrix/spectrumeffects.h +++ b/include/effects/matrix/spectrumeffects.h @@ -120,14 +120,14 @@ class VUMeter // // Draw i-th pixel in row y - void DrawVUPixels(std::shared_ptr pGFXChannel, int i, int yVU, int fadeBy = 0, const CRGBPalette16 * pPalette = nullptr) + virtual void DrawVUPixels(std::vector> & GFX, int i, int yVU, int fadeBy = 0, const CRGBPalette16 * pPalette = nullptr) { if (g_Analyzer.MicMode() == PeakData::PCREMOTE) pPalette = &vuPaletteBlue; - int xHalf = pGFXChannel->width()/2; - pGFXChannel->setPixel(xHalf-i-1, yVU, ColorFromPalette(pPalette ? *pPalette : vu_gpGreen, i*(256/xHalf)).fadeToBlackBy(fadeBy)); - pGFXChannel->setPixel(xHalf+i, yVU, ColorFromPalette(pPalette ? *pPalette : vu_gpGreen, i*(256/xHalf)).fadeToBlackBy(fadeBy)); + int xHalf = GFX[0]->width()/2; + GFX[0]->setPixel(xHalf-i-1, yVU, ColorFromPalette(pPalette ? *pPalette : vu_gpGreen, i*(256/xHalf)).fadeToBlackBy(fadeBy)); + GFX[0]->setPixel(xHalf+i, yVU, ColorFromPalette(pPalette ? *pPalette : vu_gpGreen, i*(256/xHalf)).fadeToBlackBy(fadeBy)); } @@ -140,25 +140,25 @@ class VUMeter public: - inline void EraseVUMeter(std::shared_ptr pGFXChannel, int start, int yVU) const + virtual inline void EraseVUMeter(std::vector> & GFX, int start, int yVU) const { - int xHalf = pGFXChannel->width()/2; + int xHalf = GFX[0]->width()/2; for (int i = start; i <= xHalf; i++) { - pGFXChannel->setPixel(xHalf-i, yVU, CRGB::Black); - pGFXChannel->setPixel(xHalf-1+i, yVU, CRGB::Black); + GFX[0]->setPixel(xHalf-i, yVU, CRGB::Black); + GFX[0]->setPixel(xHalf-1+i, yVU, CRGB::Black); } } - void DrawVUMeter(std::shared_ptr pGFXChannel, int yVU, const CRGBPalette16 * pPalette = nullptr) + virtual void DrawVUMeter(std::vector> & GFX, int yVU = 0, const CRGBPalette16 * pPalette = nullptr) { const int MAX_FADE = 256; - int xHalf = pGFXChannel->width()/2-1; + int xHalf = GFX[0]->width()/2-1; int bars = g_Analyzer._VURatioFade / 2.0 * xHalf; bars = min(bars, xHalf); - EraseVUMeter(pGFXChannel, bars, yVU); + EraseVUMeter(GFX, bars, yVU); if (bars >= iPeakVUy) { @@ -173,21 +173,74 @@ class VUMeter if (iPeakVUy > 1) { int fade = MAX_FADE * (millis() - msPeakVU) / (float) MS_PER_SECOND * 2; - DrawVUPixels(pGFXChannel, iPeakVUy, yVU, fade); - DrawVUPixels(pGFXChannel, iPeakVUy-1, yVU, fade); + DrawVUPixels(GFX, iPeakVUy, yVU, fade); + DrawVUPixels(GFX, iPeakVUy-1, yVU, fade); } for (int i = 0; i < bars; i++) - DrawVUPixels(pGFXChannel, i, yVU, i > bars ? 255 : 0, pPalette); + DrawVUPixels(GFX, i, yVU, i > bars ? 255 : 0, pPalette); } }; +class VUMeterVertical : public VUMeter +{ +private: + virtual inline void EraseVUMeter(std::vector> & GFX, int start, int yVU) const + { + for (int i = start; i <= GFX[0]->width(); i++) + for (auto& device : GFX) + device->setPixel(i, yVU, CRGB::Black); + } + + // DrawVUPixels + // + // Draw i-th pixel in row y + + virtual void DrawVUPixels(std::vector> & GFX, int i, int yVU, int fadeBy = 0, const CRGBPalette16 * pPalette = nullptr) override + { + for (auto& device : GFX) + device->setPixel(i, yVU, ColorFromPalette(pPalette ? *pPalette : vu_gpGreen, i*256/GFX[0]->width()).fadeToBlackBy(fadeBy)); + } + +public: + void DrawVUMeter(std::vector> & GFX, int yVU = 0, const CRGBPalette16 * pPalette = nullptr) + { + const int MAX_FADE = 256; + + int size = GFX[0]->width(); + int bars = g_Analyzer._VURatioFade / 2.0 * size; + bars = min(bars, size); + + EraseVUMeter(GFX, bars, yVU); + + if (bars >= iPeakVUy) + { + msPeakVU = millis(); + iPeakVUy = bars; + } + else if (millis() - msPeakVU > MS_PER_SECOND / 2) + { + iPeakVUy = 0; + } + + if (iPeakVUy > 1) + { + int fade = MAX_FADE * (millis() - msPeakVU) / (float) MS_PER_SECOND * 2; + DrawVUPixels(GFX, iPeakVUy, yVU, fade); + DrawVUPixels(GFX, iPeakVUy-1, yVU, fade); + } + + for (int i = 0; i < bars; i++) + DrawVUPixels(GFX, i, yVU, i > bars ? 255 : 0, pPalette); + } +}; + class VUMeterEffect : virtual public VUMeter, public LEDStripEffect { public: virtual void Draw() override { - DrawVUMeter(g(), 0); + DrawVUMeter(g_ptrSystem->EffectManager().GetBaseGraphics(), 0); } VUMeterEffect() : LEDStripEffect(EFFECT_STRIP_VUMETER, "VUMeter") @@ -205,6 +258,28 @@ class VUMeterEffect : virtual public VUMeter, public LEDStripEffect } }; +class VUMeterVerticalEffect : virtual public VUMeterVertical, public LEDStripEffect +{ +public: + virtual void Draw() override + { + DrawVUMeter(g_ptrSystem->EffectManager().GetBaseGraphics(), 0); + } + + VUMeterVerticalEffect() : LEDStripEffect(EFFECT_STRIP_VUMETER_VERTICAL, "Vertical VUMeter") + { + } + + VUMeterVerticalEffect(const JsonObjectConst& jsonObject) + : LEDStripEffect(jsonObject) + { + } + + bool SerializeToJSON(JsonObject& jsonObject) override + { + return true; + } +}; // SpectrumAnalyzerEffect // // An effect that draws an audio spectrum analyzer on a matrix. It is assumed that the @@ -779,4 +854,64 @@ class SpectrumBarEffect : public LEDStripEffect, public BeatEffectBase } }; +// AudioSpikeEffect [MATRIX EFFECT] +// +// Simply displays the raw audio sample buffer as a waveform + +class AudioSpikeEffect : public LEDStripEffect +{ + protected: + + public: + + AudioSpikeEffect(const String & pszFriendlyName) + : LEDStripEffect(EFFECT_MATRIX_AUDIOSPIKE, pszFriendlyName) + { + } + + AudioSpikeEffect(const JsonObjectConst& jsonObject) + : LEDStripEffect(jsonObject) + { + } + + virtual bool SerializeToJSON(JsonObject& jsonObject) override + { + StaticJsonDocument jsonDoc; + + JsonObject root = jsonDoc.to(); + LEDStripEffect::SerializeToJSON(root); + + assert(!jsonDoc.overflowed()); + return jsonObject.set(jsonDoc.as()); + } + + virtual size_t DesiredFramesPerSecond() const override + { + return 60; + } + + virtual void Draw() override + { + fadeAllChannelsToBlackBy(50); + + static int colorOffset = 0; + colorOffset+= 4; + + static int offset = 2; + + const int16_t * data = g_Analyzer.GetSampleBuffer(); + int lastY = map(data[offset], 0, 2500, 0, MATRIX_HEIGHT); + for (int32_t x = 0; x < MATRIX_WIDTH; ++x) + { + byte y1 = map(data[offset+x], 0, 2500, 0, MATRIX_HEIGHT); + CRGB color = ColorFromPalette(spectrumBasicColors, (y1 * 4) + colorOffset, 255, NOBLEND); + g()->drawLine(x, lastY, x+1, y1, color); + lastY = y1; + } + offset += MATRIX_WIDTH; + if (offset + MATRIX_WIDTH > g_Analyzer.GetSampleBufferSize()) + offset = 2; + } +}; + #endif diff --git a/include/effects/strip/faneffects.h b/include/effects/strip/faneffects.h index b7def5b2c..81610242b 100644 --- a/include/effects/strip/faneffects.h +++ b/include/effects/strip/faneffects.h @@ -952,10 +952,12 @@ class FireFanEffect : public LEDStripEffect float Cooling; // Rate at which the pixels cool off int Sparks; // How many sparks will be attempted each frame int SparkHeight; // If created, max height for a spark - int Sparking; // Probability of a spark each attempt + byte Sparking; // Probability of a spark each attempt bool bReversed; // If reversed we draw from 0 outwards bool bMirrored; // If mirrored we split and duplicate the drawing bool bMulticolor; // If true each channel spoke will be a different color + byte MaxSparkTemp; // How hot a spark can be + PixelOrder Order; std::unique_ptr abHeat; // Heat table to map temp to color @@ -977,13 +979,14 @@ class FireFanEffect : public LEDStripEffect int ledCount, int cellsPerLED = 1, float cooling = 20, - int sparking = 100, + byte sparking = 100, int sparks = 3, int sparkHeight = 4, PixelOrder order = Sequential, bool breversed = false, bool bmirrored = false, - bool bmulticolor = false) + bool bmulticolor = false, + byte maxSparkTemp = 255) : LEDStripEffect(EFFECT_STRIP_FIRE_FAN, "FireFanEffect"), Palette(palette), LEDCount(ledCount), @@ -995,7 +998,8 @@ class FireFanEffect : public LEDStripEffect bReversed(breversed), bMirrored(bmirrored), Order(order), - bMulticolor(bmulticolor) + bMulticolor(bmulticolor), + MaxSparkTemp(maxSparkTemp) { if (bMirrored) LEDCount = LEDCount / 2; @@ -1014,7 +1018,8 @@ class FireFanEffect : public LEDStripEffect bReversed(jsonObject[PTY_REVERSED]), bMirrored(jsonObject[PTY_MIRORRED]), Order((PixelOrder)jsonObject[PTY_ORDER]), - bMulticolor(jsonObject[PTY_MULTICOLOR] == 1) + bMulticolor(jsonObject[PTY_MULTICOLOR] == 1), + MaxSparkTemp(jsonObject[PTY_SPARKTEMP]) { abHeat.reset( psram_allocator().allocate(CellCount()) ); } @@ -1032,6 +1037,7 @@ class FireFanEffect : public LEDStripEffect jsonDoc[PTY_COOLING] = Cooling; jsonDoc[PTY_SPARKS] = Sparks; jsonDoc[PTY_SPARKHEIGHT] = SparkHeight; + jsonDoc[PTY_SPARKTEMP] = MaxSparkTemp; jsonDoc[PTY_SPARKING] = Sparking; jsonDoc[PTY_REVERSED] = bReversed; jsonDoc[PTY_MIRORRED] = bMirrored; @@ -1067,8 +1073,8 @@ class FireFanEffect : public LEDStripEffect { for (int i = 0; i < CellCount(); i++) { - float coolingAmount = random_range(0.0f, 2.0f); - abHeat[i] = ::max(0.0, abHeat[i] - coolingAmount * (2.0 - g_Analyzer._VURatio)); + float coolingAmount = random_range(0.0f, Cooling); + abHeat[i] = ::max(0.0, abHeat[i] - (double) coolingAmount); } } @@ -1089,10 +1095,10 @@ class FireFanEffect : public LEDStripEffect { for (int i = 0; i < Sparks; i++) { - if (random(255) < Sparking / 4 + Sparking * (g_Analyzer._VURatio / 2.0) * 0.5) + if (random(255) < Sparking) { int y = CellCount() - 1 - random(SparkHeight * CellsPerLED); - abHeat[y] = abHeat[y] + random(50, 255); // Can roll over which actually looks good! + abHeat[y] = ::min((long)MaxSparkTemp, abHeat[y] + random(0, MaxSparkTemp)); } } } @@ -1117,16 +1123,19 @@ class FireFanEffect : public LEDStripEffect color = hsv; } - // If we're reversed, we work from the end back. We don't reverse the bonus pixels - int j = (!bReversed || i > FAN_SIZE) ? i : LEDCount - 1 - i; uint x = GetFanPixelOrder(j, order); if (x < NUM_LEDS) { - FastLED[iChannel][x] = color; - if (bMirrored) - FastLED[iChannel][!bReversed ? (2 * LEDCount - 1 - i) : LEDCount + i] = color; + FastLED[iChannel][x] = color; + + if (bMirrored) + { + // Use bReversed here to match the reversal in the main index calculation + FastLED[iChannel][bReversed ? (2 * LEDCount - 1 - i) : LEDCount + i] = color; + } } + } } } diff --git a/include/effects/strip/meteoreffect.h b/include/effects/strip/meteoreffect.h index 194708371..04d699544 100644 --- a/include/effects/strip/meteoreffect.h +++ b/include/effects/strip/meteoreffect.h @@ -81,6 +81,16 @@ class MeteorChannel lastBeat[i] = g_Values.AppTime.FrameStartTime(); bLeft[i] = i & 2; } + + // Special case 2-meteor to be red on both ends + + if (meteorCount == 2) + { + hue[0] = HUE_RED; + hue[1] = HUE_RED; + iPos[0] = 0; + iPos[1] = pGFX->GetLEDCount() - 1; + } } virtual void Reverse(int iMeteor) @@ -92,7 +102,7 @@ class MeteorChannel { static CHSV hsv; hsv.val = 255; - hsv.sat = 240; + hsv.sat = 255; for (int j = 0; jGetLEDCount(); j++) // fade brightness all LEDs one step { diff --git a/include/effects/strip/misceffects.h b/include/effects/strip/misceffects.h index 9ef737d73..85e96c109 100644 --- a/include/effects/strip/misceffects.h +++ b/include/effects/strip/misceffects.h @@ -161,13 +161,15 @@ class RainbowFillEffect : public LEDStripEffect float _speedDivisor; int _deltaHue; + bool _mirrored; public: - RainbowFillEffect(float speedDivisor = 12.0f, int deltaHue = 14) + RainbowFillEffect(float speedDivisor = 12.0f, int deltaHue = 14, bool mirrored = false) : LEDStripEffect(EFFECT_STRIP_RAINBOW_FILL, "RainbowFill Rainbow"), _speedDivisor(speedDivisor), - _deltaHue(deltaHue) + _deltaHue(deltaHue), + _mirrored(mirrored) { debugV("RainbowFill constructor"); } @@ -175,7 +177,8 @@ class RainbowFillEffect : public LEDStripEffect RainbowFillEffect(const JsonObjectConst& jsonObject) : LEDStripEffect(jsonObject), _speedDivisor(jsonObject[PTY_SPEEDDIVISOR]), - _deltaHue(jsonObject[PTY_DELTAHUE]) + _deltaHue(jsonObject[PTY_DELTAHUE]), + _mirrored(jsonObject[PTY_MIRRORED]) { debugV("RainbowFill JSON constructor"); } @@ -189,6 +192,7 @@ class RainbowFillEffect : public LEDStripEffect jsonDoc[PTY_SPEEDDIVISOR] = _speedDivisor; jsonDoc[PTY_DELTAHUE] = _deltaHue; + jsonDoc[PTY_MIRRORED] = _mirrored; assert(!jsonDoc.overflowed()); @@ -205,7 +209,7 @@ class RainbowFillEffect : public LEDStripEffect hue += (float) msElapsed / _speedDivisor; hue = fmod(hue, 256.0); - fillRainbowAllChannels(0, _cLEDs, hue, _deltaHue); + fillRainbowAllChannels(0, _cLEDs, hue, _deltaHue, 1, _mirrored); delay(10); } }; @@ -229,6 +233,15 @@ class ColorFillEffect : public LEDStripEffect public: + ColorFillEffect(const String &name, CRGB color = CRGB(246,200,160), int everyNth = 10, bool ignoreGlobalColor = false) + : LEDStripEffect(EFFECT_STRIP_COLOR_FILL, name), + _everyNth(everyNth), + _color(color), + _ignoreGlobalColor(ignoreGlobalColor) + { + debugV("Color Fill constructor"); + } + ColorFillEffect(CRGB color = CRGB(246,200,160), int everyNth = 10, bool ignoreGlobalColor = false) : LEDStripEffect(EFFECT_STRIP_COLOR_FILL, "Color Fill"), _everyNth(everyNth), diff --git a/include/gfxbase.h b/include/gfxbase.h index ecc6078b9..3ed9887ec 100644 --- a/include/gfxbase.h +++ b/include/gfxbase.h @@ -65,6 +65,7 @@ #pragma once #include +#include #include "Adafruit_GFX.h" #include "pixeltypes.h" #include "effects/matrix/Boid.h" diff --git a/include/globals.h b/include/globals.h index 002d3ee1f..00e5e57be 100644 --- a/include/globals.h +++ b/include/globals.h @@ -1,4 +1,3 @@ -#pragma once //+-------------------------------------------------------------------------- // // File: Globals.h @@ -715,35 +714,67 @@ extern RemoteDebug Debug; // Let everyone in the project know about it #define PROJECT_NAME "Spiral Light" #endif + #define ENABLE_WIFI 1 // Connect to WiFi + #define INCOMING_WIFI_ENABLED 1 // Accepting incoming color data and commands + #define WAIT_FOR_WIFI 0 // Hold in setup until we have WiFi - for strips without effects + #define TIME_BEFORE_LOCAL 3 // How many seconds before the lamp times out and shows local content + + #define MAX_BUFFERS 30 // Times 4 channels, but they're only NUM_LEDS big + #define NUM_CHANNELS 2 // One per spoke + #define MATRIX_WIDTH 172 // Number of pixels wide (how many LEDs per channel) + #define MATRIX_HEIGHT 1 // Number of pixels tall + #define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT) + #define ENABLE_REMOTE 1 // IR Remote Control + #define IR_REMOTE_PIN 26 + #define ENABLE_AUDIO 1 // Listen for audio from the microphone and process it + #define USE_SCREEN 1 // Normally we use a tiny board inside the lamp with no screen + #define FAN_SIZE NUM_LEDS // Allows us to use fan effects on the spokes + #define NUM_FANS 1 // Our fans are on channels, not in sequential order, so only one "fan" + #define NUM_RINGS 1 + #define FULL_COLOR_REMOTE_FILL 1 // Remote control color buttons fill the whole strip + #define BRIGHTNESS_MIN 0 // Allow OFF button to turn lamp entirely off + + // Wiring is: + + #define TOGGLE_BUTTON_1 39 + #define TOGGLE_BUTTON_2 37 + + #define LED_PIN0 32 + #define LED_PIN1 33 + + #define DEFAULT_EFFECT_INTERVAL (1000*60*5) + +#elif PLATECOVER + + // This is the "Tiki Atomic Fire Lamp" project, which is an LED lamp with 4 arms of 53 LEDs each. + // Each arm is wired as a separate channel. + + #ifndef PROJECT_NAME + #define PROJECT_NAME "Plate Cover" + #endif + #define ENABLE_WIFI 1 // Connect to WiFi #define INCOMING_WIFI_ENABLED 1 // Accepting incoming color data and commands #define WAIT_FOR_WIFI 0 // Hold in setup until we have WiFi - for strips without effects #define TIME_BEFORE_LOCAL 3 // How many seconds before the lamp times out and shows local content - - #define MAX_BUFFERS 30 // Times 4 channels, but they're only NUM_LEDS big - #define NUM_CHANNELS 2 // One per spoke - #define MATRIX_WIDTH 172 // Number of pixels wide (how many LEDs per channel) - #define MATRIX_HEIGHT 1 // Number of pixels tall - #define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT) - #define ENABLE_REMOTE 1 // IR Remote Control - #define IR_REMOTE_PIN 26 - #define ENABLE_AUDIO 1 // Listen for audio from the microphone and process it - #define USE_SCREEN 1 // Normally we use a tiny board inside the lamp with no screen - #define FAN_SIZE NUM_LEDS // Allows us to use fan effects on the spokes - #define NUM_FANS 1 // Our fans are on channels, not in sequential order, so only one "fan" - #define NUM_RINGS 1 - #define LED_FAN_OFFSET_BU 0 - #define BONUS_PIXELS 0 - + #define MAX_BUFFERS 60 // Times 4 channels, but they're only NUM_LEDS big + #define NUM_CHANNELS 1 // One per spoke + #define MATRIX_WIDTH 40 // Number of pixels wide (how many LEDs per channel) + #define MATRIX_HEIGHT 1 // Number of pixels tall + #define NUM_LEDS 40 + #define ENABLE_REMOTE 1 // IR Remote Control + #define IR_REMOTE_PIN 26 + #define ENABLE_AUDIO 1 // Listen for audio from the microphone and process it + #define USE_SCREEN 1 // Normally we use a tiny board inside the lamp with no screen + #define FAN_SIZE NUM_LEDS // Allows us to use fan effects on the spokes // Wiring is: #define TOGGLE_BUTTON_1 39 #define TOGGLE_BUTTON_2 37 #define LED_PIN0 32 - #define LED_PIN1 33 - #define DEFAULT_EFFECT_INTERVAL (1000*60*5) + #define DEFAULT_EFFECT_INTERVAL 0 // No scheduled effect changes #elif UMBRELLA @@ -1244,7 +1275,7 @@ extern RemoteDebug Debug; // Let everyone in the project know about it #endif #ifndef MAX_BUFFERS -#define MAX_BUFFERS (500) // Just some reasonable guess, limiting it to 24 frames per second for 20 seconds +#define MAX_BUFFERS (180) // Six seconds at 30fps #endif #ifndef ENABLE_WEBSERVER @@ -1510,6 +1541,14 @@ extern RemoteDebug Debug; // Let everyone in the project know about it #define MATRIX_CENTER_Y ((MATRIX_HEIGHT + 1) / 2) #endif +// When you press a color button on the remote, the color is used to create a temporary fill effect, but +// only when this is set to 1. Otherwise, just the global colors are set, and it's up to the active effect +// to actually use them. + +#ifndef FULL_COLOR_REMOTE_FILL +#define FULL_COLOR_REMOTE_FILL 0 +#endif + // Common globals // g_aRingSizeTable @@ -1736,9 +1775,8 @@ inline bool SetSocketBlockingEnabled(int fd, bool blocking) inline String formatSize(size_t size, size_t threshold = 1000) { - // If the size is less than the threshold, we don't need to worry about precision because - // we'll be showing whole units - const int precision = size >= threshold ? 2 : 0; + // If the size is above the threshold, we want a precision of 2 to show more accurate value + const int precision = size < threshold ? 0 : 2; const char* suffixes[] = {"", "K", "M", "G", "T", "P", "E", "Z"}; size_t suffixIndex = 0; @@ -1752,9 +1790,11 @@ inline String formatSize(size_t size, size_t threshold = 1000) std::ostringstream oss; oss << std::fixed << std::setprecision(precision) << sizeDouble << suffixes[suffixIndex]; - return String(oss.str().c_str()); + std::string result = oss.str(); // Store the result to avoid dangling pointer + return String(result.c_str()); } + // to_array // // Because the ESP32 compiler, as of this writing, doesn't have std::to_array, we provide our own (davepl). diff --git a/include/ledstripeffect.h b/include/ledstripeffect.h index acbc1e74e..e01b7767a 100644 --- a/include/ledstripeffect.h +++ b/include/ledstripeffect.h @@ -392,15 +392,18 @@ class LEDStripEffect : public IJSONSerializable void fillSolidOnAllChannels(CRGB color, int iStart = 0, int numToFill = 0, uint everyN = 1) { - if (!_GFX[0]) - throw std::runtime_error("Graphics not set up properly"); + if (_GFX.size() == 0) + { + debugE("fillSolidOnAllChannels called with no GFX devices"); + throw std::runtime_error("Graphics not set up properly, no GFX devices"); + } if (numToFill == 0) numToFill = _cLEDs-iStart; if (iStart + numToFill > _cLEDs) { - printf("Boundary Exceeded in FillRainbow"); + debugE("Boundary Exceeded in FillRainbow"); return; } @@ -446,26 +449,28 @@ class LEDStripEffect : public IJSONSerializable // // Fill all channels with a progressive rainbow, using arbitrary start, length, step, and initial color and hue change rate - void fillRainbowAllChannels(int iStart, int numToFill, uint8_t initialhue, uint8_t deltahue, uint8_t everyNth = 1) + void fillRainbowAllChannels(int iStart, int numToFill, uint8_t initialhue, uint8_t deltahue, uint8_t everyNth = 1, bool bMirrored = false) { - if (iStart + numToFill > _cLEDs) - { - printf("Boundary Exceeded in FillRainbow"); - return; - } - CHSV hsv; - hsv.hue = initialhue; - hsv.val = 255; - hsv.sat = 240; for (int i = 0; i < numToFill; i+=everyNth) { + CHSV hsv; + hsv.hue = initialhue + i * deltahue; + hsv.val = 255; + hsv.sat = 255; CRGB rgb; hsv2rgb_rainbow(hsv, rgb); - setPixelOnAllChannels(iStart + i, rgb); - hsv.hue += deltahue; + if (bMirrored) + { + setPixelOnAllChannels(iStart + i, rgb); + setPixelOnAllChannels(iStart + numToFill - i - 1, rgb); + } + else + { + setPixelOnAllChannels(iStart + i, rgb); + } for (int q = 1; q < everyNth; q++) - _GFX[q]->setPixel(iStart + i + q, CRGB::Black); + setPixelOnAllChannels(iStart + i + q, CRGB::Black); } } diff --git a/include/ledstripgfx.h b/include/ledstripgfx.h index 10d7b739e..ecaa03c03 100644 --- a/include/ledstripgfx.h +++ b/include/ledstripgfx.h @@ -44,10 +44,17 @@ class LEDStripGFX : public GFXBase { // Macro to add LEDs to a channel - #define ADD_CHANNEL(channel) \ - debugI("Adding %zu LEDs to pin %d from channel %d on FastLED.", devices[channel]->GetLEDCount(), LED_PIN ## channel, channel); \ - FastLED.addLeds(devices[channel]->leds, devices[channel]->GetLEDCount()); \ - pinMode(LED_PIN ## channel, OUTPUT) + #if FASTLED_EXPERIMENTAL_ESP32_RGBW_ENABLED + #define ADD_CHANNEL(channel) \ + debugI("Adding %zu LEDs to pin %d from channel %d on FastLED.", devices[channel]->GetLEDCount(), LED_PIN ## channel, channel); \ + FastLED.addLeds(devices[channel]->leds, devices[channel]->GetLEDCount()).setRgbw(Rgbw(kRGBWDefaultColorTemp, FASTLED_EXPERIMENTAL_ESP32_RGBW_MODE )); \ + pinMode(LED_PIN ## channel, OUTPUT) + #else + #define ADD_CHANNEL(channel) \ + debugI("Adding %zu LEDs to pin %d from channel %d on FastLED.", devices[channel]->GetLEDCount(), LED_PIN ## channel, channel); \ + FastLED.addLeds(devices[channel]->leds, devices[channel]->GetLEDCount()); \ + pinMode(LED_PIN ## channel, OUTPUT) + #endif debugI("Adding LEDs to FastLED..."); diff --git a/include/screen.h b/include/screen.h index 085157ceb..830267c2c 100644 --- a/include/screen.h +++ b/include/screen.h @@ -228,6 +228,8 @@ class Screen : public GFXBase return; } + amoled.setBrightness(255); + // Register lvgl helper beginLvglHelper(amoled); diff --git a/include/soundanalyzer.h b/include/soundanalyzer.h index a2c8a35bb..f92932f0c 100644 --- a/include/soundanalyzer.h +++ b/include/soundanalyzer.h @@ -502,6 +502,19 @@ class SoundAnalyzer : public AudioVariables free(_vPeaks); } + // These functions allow access to the last-acquired sample buffer and its size so that + // effects can draw the waveform or do other things with the raw audio data + + const int16_t * GetSampleBuffer() const + { + return ptrSampleBuffer.get(); + } + + const size_t GetSampleBufferSize() const + { + return MAX_SAMPLES; + } + // BeatEnhance // // Looks like pure voodoo, but it returns the multiplier by which to scale a value to enhance it diff --git a/platformio.ini b/platformio.ini index 639085f99..6d04a3cf4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -33,7 +33,7 @@ extra_configs = upload_port = monitor_port = build_type = release -upload_speed = 1500000 +upload_speed = 2000000 build_flags = -std=gnu++2a -Dregister= ; Sinister: redefine 'register' so FastLED can use that keyword under C++17 and later C++ versions -g3 @@ -50,7 +50,7 @@ build_src_flags = -Wformat=2 ; Warnings for our code only check_flags = cppcheck: --suppress=*:*src/uzlib/src/* lib_deps = crankyoldgit/IRremoteESP8266 @ ^2.7.20 - fastled/FastLED @ ^3.4.0 + fastled/FastLED @ ^3.7.6 adafruit/Adafruit BusIO @ ^1.9.1 adafruit/Adafruit GFX Library @ ^1.10.12 olikraus/U8g2 @ ^2.28.8 @@ -412,10 +412,11 @@ build_flags = -DDEMO=1 -DUSE_SCREEN=0 ${dev_lilygo-tdisplay-s3.build_flags} -[env:ledstrip_amoled] +[env:demo_amoled] extends = dev_lilygo_amoled -build_flags = -DLEDSTRIP=1 +build_flags = -DDEMO=1 ${dev_lilygo_amoled.build_flags} + ;============= [env:ledstrip] @@ -710,7 +711,18 @@ extends = dev_m5stick-c-plus build_flags = -DSPIRALLAMP=1 ${remote_flags.build_flags} ${dev_m5stick-c-plus.build_flags} -board_build.partitions = config/partitions_custom_noota.csv +board_build.partitions = config/partitions_custom.csv + +[env:platecover] +extends = dev_m5stick-c-plus +build_flags = -DPLATECOVER=1 + -DFASTLED_EXPERIMENTAL_ESP32_RGBW_ENABLED=1 + -DFASTLED_EXPERIMENTAL_ESP32_RGBW_MODE=kRGBWMaxBrightness + -DCOLOR_ORDER=EOrder::BRG + -DLEDTYPE=WS2812 + ${remote_flags.build_flags} + ${dev_m5stick-c-plus.build_flags} +board_build.partitions = config/partitions_custom.csv [env:fanset] extends = dev_m5stick-c-plus diff --git a/samples/videoserver/pcstats.py b/samples/videoserver/pcstats.py index 7b847a1f7..71729fa91 100644 --- a/samples/videoserver/pcstats.py +++ b/samples/videoserver/pcstats.py @@ -23,13 +23,13 @@ # Constants -MATRIX_WIDTH = 64 +MATRIX_WIDTH = 64*8 MATRIX_HEIGHT = 32 -FUTURE_DELAY = 3 -ESP32_WIFI_ADDRESS = '192.168.8.235' +FUTURE_DELAY = 1 +ESP32_WIFI_ADDRESS = 'pi4-8g-02' PORT = 49152 WIFI_COMMAND_PIXELDATA64 = 3 -FPS = 20 +FPS = 120 # connect_to_socket # diff --git a/src/audio.cpp b/src/audio.cpp index 4ad5dd651..a25fc4b45 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -65,7 +65,7 @@ void IRAM_ATTR AudioSamplerTaskEntry(void *) static float lastVU = 0.0; constexpr auto VU_DECAY_PER_SECOND = 4.0; if (g_Analyzer._VURatio > lastVU) - lastVU = g_Analyzer._VURatio; + lastVU += (millis() - lastFrame) / 1000.0 * VU_DECAY_PER_SECOND * 2; else lastVU -= (millis() - lastFrame) / 1000.0 * VU_DECAY_PER_SECOND; lastVU = std::max(lastVU, 0.0f); diff --git a/src/drawing.cpp b/src/drawing.cpp index f2919d93a..6926a60e8 100644 --- a/src/drawing.cpp +++ b/src/drawing.cpp @@ -267,7 +267,7 @@ void IRAM_ATTR DrawLoopTaskEntry(void *) uint16_t wifiPixelsDrawn = 0; double frameStartTime = g_Values.AppTime.FrameStartTime(); - auto graphics = g_ptrSystem->EffectManager().GetBaseGraphics(); + auto graphics = g_ptrSystem->EffectManager().GetBaseGraphics()[0]; graphics->PrepareFrame(); diff --git a/src/effectmanager.cpp b/src/effectmanager.cpp index 25b75a808..87a3ef6f9 100644 --- a/src/effectmanager.cpp +++ b/src/effectmanager.cpp @@ -370,7 +370,7 @@ void EffectManager::ClearRemoteColor(bool retainRemoteEffect) void EffectManager::ApplyGlobalColor(CRGB color) { - debugI("Setting Global Color"); + debugI("Setting Global Color: %08X\n", (uint) color); auto& deviceConfig = g_ptrSystem->DeviceConfig(); deviceConfig.SetColorSettings(color, deviceConfig.GlobalColor()); diff --git a/src/effects.cpp b/src/effects.cpp index 7fa4ef526..b540ea4f7 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -276,7 +276,7 @@ void LoadEffectFactories() ADD_EFFECT(EFFECT_MATRIX_SMPICASSO3IN1, PatternSMPicasso3in1, "Lines", 38); ADD_EFFECT(EFFECT_MATRIX_SMPICASSO3IN1, PatternSMPicasso3in1, "Circles", 73); ADD_EFFECT(EFFECT_MATRIX_SMAMBERRAIN, PatternSMAmberRain); - ADD_EFFECT(EFFECT_MATRIX_SMSTROBE_DIFFUSION,PatternSMStrobeDiffusion); + // ADD_EFFECT(EFFECT_MATRIX_SMSTROBE_DIFFUSION,PatternSMStrobeDiffusion); ADD_EFFECT(EFFECT_MATRIX_SMRAINBOW_TUNNEL, PatternSMRainbowTunnel); ADD_EFFECT(EFFECT_MATRIX_SMSPIRO_PULSE, PatternSMSpiroPulse); ADD_EFFECT(EFFECT_MATRIX_SMTWISTER, PatternSMTwister); @@ -447,20 +447,29 @@ void LoadEffectFactories() ADD_EFFECT(EFFECT_STRIP_METEOR, MeteorEffect, 1, 1, 5, .15, .25); ADD_EFFECT(EFFECT_STRIP_METEOR, MeteorEffect); // Rainbow palette + #elif PLATECOVER + + ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid White", CRGB::White, 1); + ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid Red", CRGB::Red, 1); + ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid Amber", CRGB(255, 50, 0), 1); + ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, HeatColors_p, NUM_LEDS, 4, 5.0, 200, 8, 8, Sequential, true, true, true, 90); + ADD_EFFECT(EFFECT_STRIP_RAINBOW_FILL, RainbowFillEffect, 16, 3, true); + ADD_EFFECT(EFFECT_STRIP_METEOR, MeteorEffect, 2, 1, 15, .75, .75); + ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Off", CRGB::Black, 1); + #elif SPIRALLAMP - #ifndef EFFECT_SET_VERSION - #define EFFECT_SET_VERSION 2 // Bump version if default set changes in a meaningful way - #endif + ADD_EFFECT(EFFECT_STRIP_VUMETER_VERTICAL, VUMeterVerticalEffect); + ADD_EFFECT(EFFECT_STRIP_METEOR, MeteorEffect, 4, 4, 10, 1.0, 1.0); + ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid White", CRGB::White, 1); - ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, HeatColors_p, NUM_LEDS, 1, 1.6, 750, 2, 15, Sequential, true, false); - ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, GreenHeatColors_p, NUM_LEDS, 1, 1.6, 750, 2, 15, Sequential, true, false); - ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, BlueHeatColors_p, NUM_LEDS, 1, 1.6, 750, 2, 15, Sequential, true, false); - ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, RainbowColors_p, NUM_LEDS, 1, 1.6, 750, 2, 15, Sequential, true, false); - ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, HeatColors_p, NUM_LEDS, 1, 1.6, 750, 2, 15, Sequential, true, false, true); + ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, HeatColors_p, NUM_LEDS, 1, 2.5, 200, 2, 15, Sequential, true, false); + ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, GreenHeatColors_p, NUM_LEDS, 1, 2.5, 200, 2, 15, Sequential, true, false); + ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, BlueHeatColors_p, NUM_LEDS, 1, 2.5, 200, 2, 15, Sequential, true, false); + ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, RainbowColors_p, NUM_LEDS, 1, 2.5, 200, 2, 15, Sequential, true, false); + ADD_EFFECT(EFFECT_STRIP_FIRE_FAN, FireFanEffect, HeatColors_p, NUM_LEDS, 1, 2.5, 200, 2, 15, Sequential, true, false, true); ADD_EFFECT(EFFECT_STRIP_RAINBOW_FILL, RainbowFillEffect, 120, 0); - ADD_EFFECT(EFFECT_STRIP_COLOR_CYCLE, ColorCycleEffect, Sequential); ADD_EFFECT(EFFECT_STRIP_PALETTE, PaletteEffect, RainbowColors_p, 4, 0.1, 0.0, 1.0, 0.0); ADD_EFFECT(EFFECT_STRIP_BOUNCING_BALL, BouncingBallEffect, 3, true, true, 8); @@ -475,8 +484,6 @@ void LoadEffectFactories() ADD_STARRY_NIGHT_EFFECT(Star, "Green Sparkle Stars", GreenColors_p, STARRYNIGHT_PROBABILITY, 1, LINEARBLEND, 2.0, 0.0, STARRYNIGHT_MUSICFACTOR); // Blue Sparkle ADD_STARRY_NIGHT_EFFECT(MusicStar, "Green Stars", GreenColors_p, STARRYNIGHT_PROBABILITY, 1, LINEARBLEND, 2.0, 0.0, STARRYNIGHT_MUSICFACTOR); - ADD_EFFECT(EFFECT_STRIP_METEOR, MeteorEffect, 4, 4, 10, 1.0, 1.0); - ADD_EFFECT(EFFECT_STRIP_METEOR, MeteorEffect, 2, 4, 10, 0.25, 0.25); ADD_EFFECT(EFFECT_STRIP_TWINKLE, TwinkleEffect, NUM_LEDS / 2, 20, 50); ADD_EFFECT(EFFECT_STRIP_PALETTE, PaletteEffect, RainbowColors_p, .25, 1, 0, 1.0, 0.0, LINEARBLEND, true, 1.0); diff --git a/src/ledmatrixgfx.cpp b/src/ledmatrixgfx.cpp index 019f34667..124acb066 100644 --- a/src/ledmatrixgfx.cpp +++ b/src/ledmatrixgfx.cpp @@ -93,7 +93,7 @@ void LEDMatrixGFX::PrepareFrame() matrix.setCalcRefreshRateDivider(MATRIX_CALC_DIVIDER); matrix.setRefreshRate(MATRIX_REFRESH_RATE); - auto pMatrix = std::static_pointer_cast(g_ptrSystem->EffectManager().GetBaseGraphics()); + auto pMatrix = std::static_pointer_cast(g_ptrSystem->EffectManager().GetBaseGraphics()[0]); pMatrix->setLeds(GetMatrixBackBuffer()); // We set ourselves to the lower of the fader value or the brightness value, diff --git a/src/main.cpp b/src/main.cpp index 5dc6f2c82..728687064 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -253,6 +253,10 @@ Bounce2::Button Button1; Bounce2::Button Button2; #endif +#ifdef TOGGLE_BUTTON_3 +Bounce2::Button Button3; +#endif + // setup // // Invoked once at boot, does initial chip setup and application initial init, then spins off worker tasks and returns @@ -410,6 +414,12 @@ void setup() Button2.setPressedState(LOW); #endif + #ifdef TOGGLE_BUTTON_3 + Button3.attach(TOGGLE_BUTTON_3, INPUT_PULLUP); + Button3.interval(1); + Button3.setPressedState(LOW); + #endif + #if AMOLED_S3 #include "amoled/LilyGo_AMOLED.h" debugW("Creating AMOLED Screen"); diff --git a/src/network.cpp b/src/network.cpp index a39efd355..5503b7341 100644 --- a/src/network.cpp +++ b/src/network.cpp @@ -150,9 +150,8 @@ void SetupOTA(const String & strHostname) debugI("OTA Progress: %u%%\r", p); #if USE_HUB75 - auto pMatrix = std::static_pointer_cast(g_ptrSystem->EffectManager().GetBaseGraphics()); + auto pMatrix = std::static_pointer_cast(g_ptrSystem->EffectManager().GetBaseGraphics()[0]); pMatrix->SetCaption(str_sprintf("Update:%d%%", p), CAPTION_TIME); -// pMatrix->setLeds(_GFX[0]->GetMatrixBackBuffer()); #endif } else diff --git a/src/remotecontrol.cpp b/src/remotecontrol.cpp index 693928429..830721468 100644 --- a/src/remotecontrol.cpp +++ b/src/remotecontrol.cpp @@ -32,6 +32,8 @@ #if ENABLE_REMOTE +#include "systemcontainer.h" +#include "effects/strip/misceffects.h" #include "systemcontainer.h" #define BRIGHTNESS_STEP 20 @@ -91,7 +93,14 @@ void RemoteControl::handle() } else if (IR_OFF == result) { - deviceConfig.SetBrightness((int)deviceConfig.GetBrightness() - BRIGHTNESS_STEP); + #if HUB75 + deviceConfig.SetBrightness((int)deviceConfig.GetBrightness() - BRIGHTNESS_STEP); + #else + effectManager.ClearRemoteColor(); + effectManager.SetInterval(0); + effectManager.StartEffect(); + deviceConfig.SetBrightness(0); + #endif return; } else if (IR_BPLUS == result) @@ -132,12 +141,25 @@ void RemoteControl::handle() effectManager.ShowVU( !effectManager.IsVUVisible() ); } + debugI("Looking for match for remote color code: %08X\n", result); + for (int i = 0; i < std::size(RemoteColorCodes); i++) { if (RemoteColorCodes[i].code == result) { - debugV("Changing Color via remote: %08X\n", (uint) RemoteColorCodes[i].color); + // To set a solid color fill based on the remote buttons, we take the color from the table, + // crate a ColorFillEffect, and apply it as a temporary effect. This will override the current + // effect until the next effect change or remote command. + + debugI("Changing Color via remote: %08X\n", (uint) RemoteColorCodes[i].color); effectManager.ApplyGlobalColor(RemoteColorCodes[i].color); + #if FULL_COLOR_REMOTE_FILL + auto effect = make_shared_psram("Remote Color", RemoteColorCodes[i].color, 1, true); + if (effect->Init(g_ptrSystem->EffectManager().GetBaseGraphics())) + g_ptrSystem->EffectManager().SetTempEffect(effect); + else + debugE("Could not initialize new color fill effect"); + #endif return; } } diff --git a/src/screen.cpp b/src/screen.cpp index d3f789d2d..352d07a1b 100644 --- a/src/screen.cpp +++ b/src/screen.cpp @@ -240,6 +240,15 @@ void CurrentEffectSummary(bool bRedraw) auto& display = g_ptrSystem->Display(); display.StartFrame(); + // Force a full redraw if we've changed to a new display page + + static auto lastPage = g_InfoPage; + if (lastPage != g_InfoPage) + { + lastPage = g_InfoPage; + bRedraw = true; + } + if (bRedraw) display.fillScreen(BLACK16); @@ -267,7 +276,7 @@ void CurrentEffectSummary(bool bRedraw) screenFPS = 1.0f / screenFPS; lastScreen = millis(); - if (lastFullDraw == 0 || millis() - lastFullDraw > 1000) + if (bRedraw || lastFullDraw == 0 || millis() - lastFullDraw > 1000) { lastFullDraw = millis(); if (bRedraw != false || @@ -285,7 +294,7 @@ void CurrentEffectSummary(bool bRedraw) //display.setFont(); display.setTextColor(YELLOW16, backColor); - String sEffect = String("Current Effect: ") + + String sEffect = String("Effect: ") + String(g_ptrSystem->EffectManager().GetCurrentEffectIndex() + 1) + String("/") + String(g_ptrSystem->EffectManager().EffectCount()); @@ -472,9 +481,23 @@ void IRAM_ATTR ScreenUpdateLoopEntry(void *) Button2.update(); if (Button2.pressed()) { - debugI("Button 2 pressed on pin %d so advancing to next effect", TOGGLE_BUTTON_2); - g_ptrSystem->EffectManager().NextEffect(); - bRedraw = true; + if (g_InfoPage == 1) + { + // If we're on the effect summary page, the button advances the effect + debugI("Button 2 pressed on pin %d so advancing to next effect", TOGGLE_BUTTON_2); + g_ptrSystem->EffectManager().NextEffect(); + bRedraw = true; + } + else if (g_InfoPage == 0) + { + // If we're on the debug page the button will reduce the brightness + static int brightness = 255; + brightness /= 2; + if (brightness < 4) + brightness = 255; + auto &deviceConfig = g_ptrSystem->DeviceConfig(); + deviceConfig.SetBrightness(brightness); + } } #endif From f18142e22f2b7eb4b71190de38a1a36feee512a7 Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Wed, 30 Oct 2024 08:38:13 -0700 Subject: [PATCH 2/8] Basic text pattern for stocks --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 6d04a3cf4..9fab23217 100644 --- a/platformio.ini +++ b/platformio.ini @@ -50,7 +50,7 @@ build_src_flags = -Wformat=2 ; Warnings for our code only check_flags = cppcheck: --suppress=*:*src/uzlib/src/* lib_deps = crankyoldgit/IRremoteESP8266 @ ^2.7.20 - fastled/FastLED @ ^3.7.6 + fastled/FastLED @ 3.8.0 adafruit/Adafruit BusIO @ ^1.9.1 adafruit/Adafruit GFX Library @ ^1.10.12 olikraus/U8g2 @ ^2.28.8 From f0d5dc72c1f7b91dd5f2b36b1d70ed9e2c227b72 Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Wed, 30 Oct 2024 08:54:08 -0700 Subject: [PATCH 3/8] Fix mesmerizer build --- src/drawing.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/drawing.cpp b/src/drawing.cpp index 6926a60e8..2d6006964 100644 --- a/src/drawing.cpp +++ b/src/drawing.cpp @@ -122,7 +122,7 @@ uint16_t LocalDraw() #if SHOW_VU_METER static auto spectrum = std::static_pointer_cast(GetSpectrumAnalyzer(0)); if (effectManager.IsVUVisible()) - spectrum->DrawVUMeter(effectManager.g(), 0, g_Analyzer.MicMode() == PeakData::PCREMOTE ? & vuPaletteBlue : &vuPaletteGreen); + spectrum->DrawVUMeter(g_ptrSystem->EffectManager().GetBaseGraphics(), 0, g_Analyzer.MicMode() == PeakData::PCREMOTE ? & vuPaletteBlue : &vuPaletteGreen); #endif debugV("LocalDraw claims to have drawn %d pixels", NUM_LEDS); From 8cb9c4509af9542ba35803b12c590ea3eed8896a Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Wed, 30 Oct 2024 10:26:27 -0700 Subject: [PATCH 4/8] Fix audio reactivity --- src/audio.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/audio.cpp b/src/audio.cpp index a25fc4b45..ee81f1ddf 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -64,10 +64,17 @@ void IRAM_ATTR AudioSamplerTaskEntry(void *) static float lastVU = 0.0; constexpr auto VU_DECAY_PER_SECOND = 4.0; + + // Fade out the VU ratio... The current peak goes up at 10x the rate it comes back down, + // which is controlled by this constant + + constexpr auto VU_REACTIVITY_RATIO = 10.0; + if (g_Analyzer._VURatio > lastVU) - lastVU += (millis() - lastFrame) / 1000.0 * VU_DECAY_PER_SECOND * 2; + lastVU += (millis() - lastFrame) / 1000.0 * VU_DECAY_PER_SECOND * VU_REACTIVITY_RATIO; else lastVU -= (millis() - lastFrame) / 1000.0 * VU_DECAY_PER_SECOND; + lastVU = std::max(lastVU, 0.0f); lastVU = std::min(lastVU, 2.0f); g_Analyzer._VURatioFade = lastVU; From 582ac0eed430dc0b6140c309f1973a238f8ea9aa Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Wed, 30 Oct 2024 10:57:18 -0700 Subject: [PATCH 5/8] Last minute audio reactivity... --- include/globals.h | 3 +++ include/soundanalyzer.h | 6 ++++-- src/audio.cpp | 4 +--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/include/globals.h b/include/globals.h index 00e5e57be..e1b1116d2 100644 --- a/include/globals.h +++ b/include/globals.h @@ -1330,6 +1330,9 @@ extern RemoteDebug Debug; // Let everyone in the project know about it #ifndef SPECTRUMBARBEAT_ENHANCE #define SPECTRUMBARBEAT_ENHANCE 0.75 // How much the SpectrumBar effect "pulses" with the music #endif + #ifndef VU_REACTIVITY_RATIO + #define VU_REACTIVITY_RATIO 10.0 // How much the VU meter reacts to the music going up vs down + #endif #endif diff --git a/include/soundanalyzer.h b/include/soundanalyzer.h index f92932f0c..2dab02583 100644 --- a/include/soundanalyzer.h +++ b/include/soundanalyzer.h @@ -652,16 +652,18 @@ class SoundAnalyzer : public AudioVariables inline void UpdatePeakData() { + const float maxIncrease = std::max(0.0, g_Values.AppTime.LastFrameTime() * _peak1DecayRate * VU_REACTIVITY_RATIO); + for (int i = 0; i < NUM_BANDS; i++) { if (_Peaks[i] > _peak1Decay[i]) { - _peak1Decay[i] = _Peaks[i]; + _peak1Decay[i] = std::min(_Peaks[i], _peak1Decay[i] + maxIncrease); _lastPeak1Time[i] = millis(); } if (_Peaks[i] > _peak2Decay[i]) { - _peak2Decay[i] = _Peaks[i]; + _peak2Decay[i] = std::min(_Peaks[i], _peak2Decay[i] + maxIncrease); } } } diff --git a/src/audio.cpp b/src/audio.cpp index ee81f1ddf..1d8cde0cf 100644 --- a/src/audio.cpp +++ b/src/audio.cpp @@ -68,13 +68,11 @@ void IRAM_ATTR AudioSamplerTaskEntry(void *) // Fade out the VU ratio... The current peak goes up at 10x the rate it comes back down, // which is controlled by this constant - constexpr auto VU_REACTIVITY_RATIO = 10.0; - if (g_Analyzer._VURatio > lastVU) lastVU += (millis() - lastFrame) / 1000.0 * VU_DECAY_PER_SECOND * VU_REACTIVITY_RATIO; else lastVU -= (millis() - lastFrame) / 1000.0 * VU_DECAY_PER_SECOND; - + lastVU = std::max(lastVU, 0.0f); lastVU = std::min(lastVU, 2.0f); g_Analyzer._VURatioFade = lastVU; From 38345d1a180354783ba07be8a7b664d6bd6249b3 Mon Sep 17 00:00:00 2001 From: Dave Plummer Date: Thu, 31 Oct 2024 14:55:52 -0700 Subject: [PATCH 6/8] Update checkin comments --- include/gfxbase.h | 1 - include/soundanalyzer.h | 4 ++-- src/effects.cpp | 10 +++++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/include/gfxbase.h b/include/gfxbase.h index 3ed9887ec..ecc6078b9 100644 --- a/include/gfxbase.h +++ b/include/gfxbase.h @@ -65,7 +65,6 @@ #pragma once #include -#include #include "Adafruit_GFX.h" #include "pixeltypes.h" #include "effects/matrix/Boid.h" diff --git a/include/soundanalyzer.h b/include/soundanalyzer.h index 2dab02583..7c51a575e 100644 --- a/include/soundanalyzer.h +++ b/include/soundanalyzer.h @@ -652,17 +652,17 @@ class SoundAnalyzer : public AudioVariables inline void UpdatePeakData() { - const float maxIncrease = std::max(0.0, g_Values.AppTime.LastFrameTime() * _peak1DecayRate * VU_REACTIVITY_RATIO); - for (int i = 0; i < NUM_BANDS; i++) { if (_Peaks[i] > _peak1Decay[i]) { + const float maxIncrease = std::max(0.0, g_Values.AppTime.LastFrameTime() * _peak1DecayRate * VU_REACTIVITY_RATIO); _peak1Decay[i] = std::min(_Peaks[i], _peak1Decay[i] + maxIncrease); _lastPeak1Time[i] = millis(); } if (_Peaks[i] > _peak2Decay[i]) { + const float maxIncrease = std::max(0.0, g_Values.AppTime.LastFrameTime() * _peak2DecayRate * VU_REACTIVITY_RATIO); _peak2Decay[i] = std::min(_Peaks[i], _peak2Decay[i] + maxIncrease); } } diff --git a/src/effects.cpp b/src/effects.cpp index b540ea4f7..f1eaf4fbd 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -276,7 +276,7 @@ void LoadEffectFactories() ADD_EFFECT(EFFECT_MATRIX_SMPICASSO3IN1, PatternSMPicasso3in1, "Lines", 38); ADD_EFFECT(EFFECT_MATRIX_SMPICASSO3IN1, PatternSMPicasso3in1, "Circles", 73); ADD_EFFECT(EFFECT_MATRIX_SMAMBERRAIN, PatternSMAmberRain); - // ADD_EFFECT(EFFECT_MATRIX_SMSTROBE_DIFFUSION,PatternSMStrobeDiffusion); + ADD_EFFECT(EFFECT_MATRIX_SMSTROBE_DIFFUSION,PatternSMStrobeDiffusion); ADD_EFFECT(EFFECT_MATRIX_SMRAINBOW_TUNNEL, PatternSMRainbowTunnel); ADD_EFFECT(EFFECT_MATRIX_SMSPIRO_PULSE, PatternSMSpiroPulse); ADD_EFFECT(EFFECT_MATRIX_SMTWISTER, PatternSMTwister); @@ -449,6 +449,10 @@ void LoadEffectFactories() #elif PLATECOVER + #ifndef EFFECT_SET_VERSION + #define EFFECT_SET_VERSION 3 + #endif + ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid White", CRGB::White, 1); ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid Red", CRGB::Red, 1); ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid Amber", CRGB(255, 50, 0), 1); @@ -459,6 +463,10 @@ void LoadEffectFactories() #elif SPIRALLAMP + #ifndef EFFECT_SET_VERSION + #define EFFECT_SET_VERSION 3 + #endif + ADD_EFFECT(EFFECT_STRIP_VUMETER_VERTICAL, VUMeterVerticalEffect); ADD_EFFECT(EFFECT_STRIP_METEOR, MeteorEffect, 4, 4, 10, 1.0, 1.0); ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid White", CRGB::White, 1); From aaa7653613cb4ecbea94e30925ec9b46ea8c3875 Mon Sep 17 00:00:00 2001 From: Rutger van Bergen Date: Fri, 1 Nov 2024 00:11:50 +0100 Subject: [PATCH 7/8] Set EFFECT_SET_VERSION to 1 for PLATECOVER --- src/effects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/effects.cpp b/src/effects.cpp index f1eaf4fbd..8c8920f6b 100644 --- a/src/effects.cpp +++ b/src/effects.cpp @@ -450,7 +450,7 @@ void LoadEffectFactories() #elif PLATECOVER #ifndef EFFECT_SET_VERSION - #define EFFECT_SET_VERSION 3 + #define EFFECT_SET_VERSION 1 #endif ADD_EFFECT(EFFECT_STRIP_COLOR_FILL, ColorFillEffect, "Solid White", CRGB::White, 1); From 21ec184a6b8288df412f509e574db56bf41e0808 Mon Sep 17 00:00:00 2001 From: Rutger van Bergen Date: Fri, 1 Nov 2024 00:21:47 +0100 Subject: [PATCH 8/8] Add Heltec V3 project back to CI --- config/ci_exclude.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/ci_exclude.json b/config/ci_exclude.json index 69c2c42fb..0637a088a 100644 --- a/config/ci_exclude.json +++ b/config/ci_exclude.json @@ -1 +1 @@ -["heltecv3demo"] \ No newline at end of file +[] \ No newline at end of file