From 283a7284b491bf3d11f663b25d86bb17f20549b3 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 2 Oct 2024 09:15:46 -0400 Subject: [PATCH 01/39] ES8311 support added for the ESP32-P4 EV board with mic. --- usermods/audioreactive/audio_reactive.h | 16 +++- usermods/audioreactive/audio_source.h | 100 ++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index 1c46e33abf..cbf2152351 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -2022,7 +2022,16 @@ class AudioReactive : public Usermod { if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin; if (i2c_sda >= 0) sdaPin = -1; // -1 = use global if (i2c_scl >= 0) sclPin = -1; - + case 9: + DEBUGSR_PRINTLN(F("AR: ES8311 Source (Mic)")); + audioSource = new ES8311Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f); + //useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour + delay(100); + // WLEDMM align global pins + if ((sdaPin >= 0) && (i2c_sda < 0)) i2c_sda = sdaPin; // copy usermod prefs into globals (if globals not defined) + if ((sclPin >= 0) && (i2c_scl < 0)) i2c_scl = sclPin; + if (i2c_sda >= 0) sdaPin = -1; // -1 = use global + if (i2c_scl >= 0) sclPin = -1; if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); break; @@ -2934,6 +2943,11 @@ class AudioReactive : public Usermod { #else oappend(SET_F("addOption(dd,'AC101 ☾',8);")); #endif + #if SR_DMTYPE==9 + oappend(SET_F("addOption(dd,'ES8311 ☾ (⎌)',9);")); + #else + oappend(SET_F("addOption(dd,'ES8311 ☾',9);")); + #endif #ifdef SR_SQUELCH oappend(SET_F("addInfo(ux+':config:squelch',1,'⎌ ")); oappendi(SR_SQUELCH); oappend("');"); // 0 is field type, 1 is actual field #endif diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index 77111446b8..61f37c4f55 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -640,6 +640,106 @@ class ES8388Source : public I2SSource { }; +/* ES8311 Sound Module + This is an I2S sound processing unit that requires initialization over + I2C before I2S data can be received. +*/ +class ES8311Source : public I2SSource { + private: + // I2C initialization functions for es8311 + void _es8311I2cBegin() { + Wire.setClock(100000); + } + + void _es8311I2cWrite(uint8_t reg, uint8_t val) { + #ifndef ES8311_ADDR + #define ES8311_ADDR 0x18 // default address is... foggy + #endif + Wire.beginTransmission(ES8311_ADDR); + Wire.write((uint8_t)reg); + Wire.write((uint8_t)val); + uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK + if (i2cErr != 0) { + DEBUGSR_PRINTF("AR: ES8311 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X).\n", i2cErr, ES8311_ADDR, reg, val); + } + } + + void _es8311InitAdc() { + // + // Currently only tested with the ESP32-P4 EV board with the onboard mic. + // Datasheet with I2C commands: https://dl.xkwy2018.com/downloads/RK3588/01_Official%20Release/04_Product%20Line%20Branch_NVR/02_Key%20Device%20Specifications/ES8311%20DS.pdf + // + _es8311I2cBegin(); + _es8311I2cWrite(0x00, 0b00011111); // RESET, default value + _es8311I2cWrite(0x45, 0b00000000); // GP, default value + _es8311I2cWrite(0x01, 0b00111010); // CLOCK MANAGER was 0b00110000 trying 0b00111010 (MCLK enable?) + + _es8311I2cWrite(0x02, 0b00000000); // 22050hz calculated + _es8311I2cWrite(0x05, 0b00000000); // 22050hz calculated + _es8311I2cWrite(0x03, 0b00010000); // 22050hz calculated + _es8311I2cWrite(0x04, 0b00010000); // 22050hz calculated + _es8311I2cWrite(0x07, 0b00000000); // 22050hz calculated + _es8311I2cWrite(0x08, 0b11111111); // 22050hz calculated + _es8311I2cWrite(0x06, 0b11100011); // 22050hz calculated + + _es8311I2cWrite(0x16, 0b00100000); // ADC was 0b00000011 trying 0b00100100 now + _es8311I2cWrite(0x0B, 0b00000000); // SYSTEM at default + _es8311I2cWrite(0x0C, 0b00100000); // SYSTEM was 0b00001111 trying 0b00100000 + _es8311I2cWrite(0x10, 0b00010011); // SYSTEM was 0b00011111 trying 0b00010011 + _es8311I2cWrite(0x11, 0b01111100); // SYSTEM was 0b01111111 trying 0b01111100 + _es8311I2cWrite(0x00, 0b11000000); // *** RESET (again - seems important?) + _es8311I2cWrite(0x01, 0b00111010); // CLOCK MANAGER was 0b00111111 trying 0b00111010 (again??) + _es8311I2cWrite(0x14, 0b00010000); // *** SYSTEM was 0b00011010 trying 0b00010000 (or 0b01111010) (PGA gain) + _es8311I2cWrite(0x12, 0b00000000); // SYSTEM - DAC, likely don't care + _es8311I2cWrite(0x13, 0b00010000); // SYSTEM - output, likely don't cate + _es8311I2cWrite(0x09, 0b00001000); // SDP IN (likely don't care) was 0b00001100 (16-bit) - changed to 0b00001000 (I2S 32-bit) + _es8311I2cWrite(0x0A, 0b00001000); // *** SDP OUT, was 0b00001100 trying 0b00001000 (I2S 32-bit) + _es8311I2cWrite(0x0E, 0b00000010); // *** SYSTEM was 0b00000010 trying 0b00011010 (seems best so far!) (or 0b00000010) + _es8311I2cWrite(0x0F, 0b01000100); // SYSTEM was 0b01000100 + _es8311I2cWrite(0x15, 0b00000000); // ADC soft ramp (disabled) + _es8311I2cWrite(0x1B, 0b00000101); // ADC soft-mute was 0b00000101 + _es8311I2cWrite(0x1C, 0b01100101); // ADC EQ and offset freeze was 0b01100101 (bad at 0b00101100) + _es8311I2cWrite(0x17, 0b10111111); // ADC volume was 0b11111111 trying ADC volume 0b10111111 = 0db (maxgain) 0x16 + _es8311I2cWrite(0x44, 0b00000000); // 0b10000000 - loopback test. on: 0x88; off: 0x00; mic--" speak + + } + + public: + ES8311Source(SRate_t sampleRate, int blockSize, float sampleScale = 1.0f, bool i2sMaster=true) : + I2SSource(sampleRate, blockSize, sampleScale, i2sMaster) { + _config.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT; + }; + + void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) { + DEBUGSR_PRINTLN("es8311Source:: initialize();"); + + // if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too + // ERRORSR_PRINTF("\nAR: invalid I2S es8311 pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin); + // return; + // } + // BUG: "use global I2C pins" are valid as -1, and -1 is seen as invalid here. + // Workaround: Set I2C pins here, which will also set them globally. + // Bug also exists in ES7243. + if ((i2c_sda < 0) || (i2c_scl < 0)) { // check that global I2C pins are not "undefined" + ERRORSR_PRINTF("\nAR: invalid es8311 global I2C pins: SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); + return; + } + if (!pinManager.joinWire(i2c_sda, i2c_scl)) { // WLEDMM specific: start I2C with globally defined pins + ERRORSR_PRINTF("\nAR: failed to join I2C bus with SDA=%d, SCL=%d\n", i2c_sda, i2c_scl); + return; + } + + // First route mclk, then configure ADC over I2C, then configure I2S + _es8311InitAdc(); + I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); + } + + void deinitialize() { + I2SSource::deinitialize(); + } + +}; + class WM8978Source : public I2SSource { private: // I2C initialization functions for WM8978 From 3b46af1101212c2106cd04081edb5a8789ae3c38 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Sat, 23 Nov 2024 11:27:32 -0500 Subject: [PATCH 02/39] Make IP clickable via serial monitor --- wled00/wled.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 08f5171d01..17efdceb73 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -1352,9 +1352,19 @@ void WLED::handleConnection() initAP(); } } else if (!interfacesInited) { //newly connected - DEBUG_PRINTLN(""); - USER_PRINT(F("Connected! IP address: ")); + USER_PRINTLN(""); + USER_PRINT(F("Connected! IP address: http://")); USER_PRINTLN(Network.localIP()); + //if (Network.isEthernet()) { + // #if ESP32 + // USER_PRINT(ETH.localIP()); + // USER_PRINTLN(" via Ethernet"); + // #endif + //} else { + // USER_PRINT(Network.localIP()); + // USER_PRINTLN(" via WiFi"); + //} + if (improvActive) { if (improvError == 3) sendImprovStateResponse(0x00, true); sendImprovStateResponse(0x04); From 37c7bb11b366e07cd9f63c660789c71512361115 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 23 Nov 2024 18:34:53 +0000 Subject: [PATCH 03/39] Update animartrix for bugfixes for corrupt state for master_speed, speed issues with SM8, Scaledemo1 and Hot_Blob --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 0b8b92ed80..c47ddbd3ad 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1062,7 +1062,7 @@ AR_build_flags = -D USERMOD_AUDIOREACTIVE -D UM_AUDIOREACTIVE_USE_NEW_FFT ;; WLE AR_lib_deps = https://github.com/softhack007/arduinoFFT.git#develop @ 1.9.2 ;; used for USERMOD_AUDIOREACTIVE - optimized version, 10% faster on -S2/-C3 animartrix_build_flags = -D USERMOD_ANIMARTRIX ;; WLEDMM usermod: CC BY-NC 3.0 licensed effects by Stefan Petrick -animartrix_lib_deps = https://github.com/netmindz/animartrix.git#18bf17389e57c69f11bc8d04ebe1d215422c7fb7 +animartrix_lib_deps = https://github.com/netmindz/animartrix.git#ccb11dd9a4ec4ff6e7bdf617f6651cced4ed9826 ;; Speed fixes animartrix_lib_ignore = animartrix ;; to remove the animartrix lib dependancy (saves a few bytes) DMXin_build_flags = -D WLED_ENABLE_DMX_INPUT ;; WLEDMM DMX physical input - requires ESP-IDF v4.4.x From 61c2ba98b7dbed99554cf5d138b23fd9eeabc64c Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:32:59 +0100 Subject: [PATCH 04/39] HUB75 small speedup gave me 1-3 extra FPS on -S3 with 128x64 --- wled00/bus_manager.cpp | 12 ++++++------ wled00/bus_manager.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index e414bf61ef..5dd51d0afb 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -1056,7 +1056,7 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh USER_PRINT(F("heap usage: ")); USER_PRINTLN(int(lastHeap - ESP.getFreeHeap())); } -void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { +void __attribute__((hot)) IRAM_ATTR BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c) { if (!_valid || pix >= _len) return; // if (_cct >= 1900) c = colorBalanceFromKelvin(_cct, c); //color correction from CCT @@ -1097,12 +1097,12 @@ void __attribute__((hot)) BusHub75Matrix::setPixelColor(uint16_t pix, uint32_t c #endif } -uint32_t BusHub75Matrix::getPixelColor(uint16_t pix) const { +uint32_t IRAM_ATTR BusHub75Matrix::getPixelColor(uint16_t pix) const { if (!_valid || pix >= _len || !_ledBuffer) return BLACK; return uint32_t(_ledBuffer[pix].scale8(_bri)) & 0x00FFFFFF; // scale8() is needed to mimic NeoPixelBus, which returns scaled-down colours } -uint32_t __attribute__((hot)) BusHub75Matrix::getPixelColorRestored(uint16_t pix) const { +uint32_t __attribute__((hot)) IRAM_ATTR BusHub75Matrix::getPixelColorRestored(uint16_t pix) const { if (!_valid || pix >= _len || !_ledBuffer) return BLACK; return uint32_t(_ledBuffer[pix]) & 0x00FFFFFF; } @@ -1117,7 +1117,7 @@ void BusHub75Matrix::setBrightness(uint8_t b, bool immediate) { if (display) display->setBrightness(_bri); } -void __attribute__((hot)) BusHub75Matrix::show(void) { +void __attribute__((hot)) IRAM_ATTR BusHub75Matrix::show(void) { if (!_valid) return; MatrixPanel_I2S_DMA* display = BusHub75Matrix::activeDisplay; if (!display) return; @@ -1277,8 +1277,8 @@ void BusManager::removeAll() { lastend = 0; } -void BusManager::show() { - for (uint8_t i = 0; i < numBusses; i++) { +void __attribute__((hot)) BusManager::show() { + for (unsigned i = 0; i < numBusses; i++) { busses[i]->show(); } } diff --git a/wled00/bus_manager.h b/wled00/bus_manager.h index cef0286d00..69f3aa2d74 100644 --- a/wled00/bus_manager.h +++ b/wled00/bus_manager.h @@ -191,7 +191,7 @@ class Bus { inline static void setGlobalAWMode(uint8_t m) { if (m < 5) _gAWM = m; else _gAWM = AW_GLOBAL_DISABLED; } inline static uint8_t getGlobalAWMode() { return _gAWM; } - inline uint32_t restore_Color_Lossy(uint32_t c, uint8_t restoreBri) const { // shamelessly grabbed from upstream, who grabbed from NPB, who .. + inline static uint32_t restore_Color_Lossy(uint32_t c, uint8_t restoreBri) { // shamelessly grabbed from upstream, who grabbed from NPB, who .. if (restoreBri < 255) { uint8_t* chan = (uint8_t*) &c; for (uint_fast8_t i=0; i<4; i++) { From ce8fc8930e3d5547592f0103097eda6ed76d8c3e Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 24 Nov 2024 17:45:25 +0100 Subject: [PATCH 05/39] const const const small speedup by declaring some functions "const" --- wled00/FX.cpp | 4 ++-- wled00/FX.h | 6 +++--- wled00/FX_2Dfcn.cpp | 2 +- wled00/FX_fcn.cpp | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 2b45d37aa3..ce5bdc7302 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4763,7 +4763,7 @@ class AuroraWave { alive = true; } - CRGB getColorForLED(int ledIndex) { + CRGB getColorForLED(int ledIndex) const { if(ledIndex < center - width || ledIndex > center + width) return 0; //Position out of range of this wave CRGB rgb; @@ -4818,7 +4818,7 @@ class AuroraWave { } }; - bool stillAlive() { + bool stillAlive() const { return alive; }; }; diff --git a/wled00/FX.h b/wled00/FX.h index c06934629d..7f53202d5b 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -420,7 +420,7 @@ typedef struct Segment { }; size_t _dataLen; // WLEDMM uint16_t is too small static size_t _usedSegmentData; // WLEDMM uint16_t is too small - void setPixelColorXY_fast(int x, int y,uint32_t c, uint32_t scaled_col, int cols, int rows); // set relative pixel within segment with color - faster, but no error checking!!! + void setPixelColorXY_fast(int x, int y,uint32_t c, uint32_t scaled_col, int cols, int rows) const; // set relative pixel within segment with color - faster, but no error checking!!! bool _isSimpleSegment = false; // simple = no grouping or spacing - mirror, transpose or reverse allowed bool _isSuperSimpleSegment = false; // superSimple = no grouping or spacing, no mirror - only transpose or reverse allowed @@ -606,7 +606,7 @@ typedef struct Segment { // transition functions void startTransition(uint16_t dur); // transition has to start before actual segment values change void handleTransition(void); - uint16_t progress(void); //transition progression between 0-65535 + uint16_t progress(void) const; //transition progression between 0-65535 // WLEDMM method inlined for speed (its called at each setPixelColor) inline uint8_t currentBri(uint8_t briNew, bool useCct = false) { @@ -621,7 +621,7 @@ typedef struct Segment { uint8_t currentMode(uint8_t modeNew); uint32_t currentColor(uint8_t slot, uint32_t colorNew); - CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal); + CRGBPalette16 &loadPalette(CRGBPalette16 &tgt, uint8_t pal) const; void setCurrentPalette(void); // 1D strip diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index f6d2bc0b6c..6f7f97b236 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -272,7 +272,7 @@ void Segment::startFrame(void) { // Simplified version of Segment::setPixelColorXY - without error checking. Does not support grouping or spacing // * expects scaled color (final brightness) as additional input parameter, plus segment virtualWidth() and virtualHeight() -void IRAM_ATTR __attribute__((hot)) Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_t scaled_col, int cols, int rows) //WLEDMM +void IRAM_ATTR __attribute__((hot)) Segment::setPixelColorXY_fast(int x, int y, uint32_t col, uint32_t scaled_col, int cols, int rows) const //WLEDMM { unsigned i = UINT_MAX; bool sameColor = false; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index f98f5dcbc9..1c5779464b 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -311,7 +311,7 @@ void Segment::setUpLeds() { } } -CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { +CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) const { static unsigned long _lastPaletteChange = millis() - 990000; // perhaps it should be per segment //WLEDMM changed init value to avoid pure orange after startup static CRGBPalette16 randomPalette = CRGBPalette16(DEFAULT_COLOR); static CRGBPalette16 prevRandomPalette = CRGBPalette16(CRGB(BLACK)); @@ -452,7 +452,7 @@ void Segment::startTransition(uint16_t dur) { } // transition progression between 0-65535 -uint16_t IRAM_ATTR_YN Segment::progress() { +uint16_t IRAM_ATTR_YN Segment::progress() const { if (!transitional || !_t) return 0xFFFFU; unsigned long timeNow = millis(); if (timeNow - _t->_start > _t->_dur || _t->_dur == 0) return 0xFFFFU; From eb56a7638d827f456b713a217431a1b779117559 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 24 Nov 2024 17:37:11 +0000 Subject: [PATCH 06/39] Update animartrix version with no dirty state --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index c47ddbd3ad..13b45feb7c 100644 --- a/platformio.ini +++ b/platformio.ini @@ -1062,7 +1062,7 @@ AR_build_flags = -D USERMOD_AUDIOREACTIVE -D UM_AUDIOREACTIVE_USE_NEW_FFT ;; WLE AR_lib_deps = https://github.com/softhack007/arduinoFFT.git#develop @ 1.9.2 ;; used for USERMOD_AUDIOREACTIVE - optimized version, 10% faster on -S2/-C3 animartrix_build_flags = -D USERMOD_ANIMARTRIX ;; WLEDMM usermod: CC BY-NC 3.0 licensed effects by Stefan Petrick -animartrix_lib_deps = https://github.com/netmindz/animartrix.git#ccb11dd9a4ec4ff6e7bdf617f6651cced4ed9826 ;; Speed fixes +animartrix_lib_deps = https://github.com/netmindz/animartrix.git#657f754783268b648e1d56b3cd31c810379d0c89 ;; Dirty state fix animartrix_lib_ignore = animartrix ;; to remove the animartrix lib dependancy (saves a few bytes) DMXin_build_flags = -D WLED_ENABLE_DMX_INPUT ;; WLEDMM DMX physical input - requires ESP-IDF v4.4.x From 5a2096ab2133e2b0c56fefa5a448ff954abeca4a Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 24 Nov 2024 19:09:35 +0100 Subject: [PATCH 07/39] partly inline getPixelColorXY allows the compiler to inline access to ledsrgb[] , while still keeping the "no buffer" case in a separate function so program size does not blow up. --> up to 10% faster --- wled00/FX.h | 18 +++++++++++++++--- wled00/FX_2Dfcn.cpp | 14 ++++++++++++-- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index 7f53202d5b..beba051747 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -721,10 +721,21 @@ typedef struct Segment { uint32_t scaled_col = (_brightness == 255) ? col : color_fade(col, _brightness); // calculate final color setPixelColorXY_fast(x, y, col, scaled_col, int(_2dWidth), int(_2dHeight)); // call "fast" function - } -} + } + } + inline uint32_t getPixelColorXY(int x, int y) const { + // minimal sanity checks + if (!_isValid2D) return 0; // not active + if ((unsigned(x) >= _2dWidth) || (unsigned(y) >= _2dHeight)) return 0 ; // check if (x,y) are out-of-range - due to 2's complement, this also catches negative values + if (ledsrgb) { + int i = x + y*_2dWidth; // avoid error checking done by XY() - be optimistic about ranges of x and y + return RGBW32(ledsrgb[i].r, ledsrgb[i].g, ledsrgb[i].b, 0); + } + else return getPixelColorXY_part2(x, y, int(_2dWidth), int(_2dHeight)); // call "no ledsrgb" function to retrieve pixel from bus driver + } #else void setPixelColorXY(int x, int y, uint32_t c); // set relative pixel within segment with color + uint32_t __attribute__((pure)) getPixelColorXY(int x, int y) const { return getPixelColorXY_slow(x,y);} #endif inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColorXY(int(x), int(y), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColorXY(x, y, RGBW32(r,g,b,w)); } @@ -735,7 +746,8 @@ typedef struct Segment { inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColorXY(x, y, RGBW32(r,g,b,w), aa); } inline void setPixelColorXY(float x, float y, CRGB c, bool aa = true) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), aa); } //#endif - uint32_t __attribute__((pure)) getPixelColorXY(int x, int y) const; + uint32_t __attribute__((pure)) getPixelColorXY_part2(int x, int y, int cols, int rows) const; + uint32_t __attribute__((pure)) getPixelColorXY_slow(int x, int y) const; // 2D support functions void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend); inline void blendPixelColorXY(uint16_t x, uint16_t y, CRGB c, uint8_t blend) { blendPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), blend); } diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 6f7f97b236..4d58143bff 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -454,8 +454,18 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa, bool fast #endif } -// returns RGBW values of pixel -uint32_t IRAM_ATTR_YN Segment::getPixelColorXY(int x, int y) const { +// WLEDMM this function is only called by getPixelColorXY, in case we don't have the ledsrgb buffer! +uint32_t IRAM_ATTR_YN Segment::getPixelColorXY_part2(int x, int y, int cols, int rows) const { + if (reverse ) x = cols - x - 1; + if (reverse_y) y = rows - y - 1; + if (transpose) std::swap(x,y); // swap X & Y if segment transposed + const uint_fast16_t groupLength_ = groupLength(); // WLEDMM small optimization + x *= groupLength_; // expand to physical pixels + y *= groupLength_; // expand to physical pixels + return strip.getPixelColorXYRestored(start + x, startY + y); +} + +uint32_t IRAM_ATTR_YN Segment::getPixelColorXY_slow(int x, int y) const { // WLEDMM fallback for non-fastpath builds if (x<0 || y<0 || !isActive()) return 0; // not active or out-of range if (ledsrgb) { int i = XY(x,y); From 7ad67b5f64ae28f8eb43a0224bc86a89c04e7b70 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 25 Nov 2024 13:35:16 +0100 Subject: [PATCH 08/39] blurz effect upgrade * avoid black spots * better randomness on esp32 * new mode "FreqMap" (checkbox) - blob location follows major frequency * new mode "GEQ scanner" (checkbox) - blob location based on GEQ band --> looks cool with Pinwheel or Bar or Arc mapping --> will be even better with the new Waterfall mapping mode --- wled00/FX.cpp | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index ce5bdc7302..b7b61daf48 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7589,6 +7589,8 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. um_data_t *um_data = getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; float volumeSmth = *(float*)um_data->u_data[0]; + float FFT_MajorPeak = *(float*)um_data->u_data[4]; + if (FFT_MajorPeak < 1) FFT_MajorPeak = 1; if (SEGENV.call == 0) { SEGMENT.setUpLeds(); // not sure if necessary @@ -7598,6 +7600,10 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. SEGENV.step = 0; // last pixel color } + #if defined(ARDUINO_ARCH_ESP32) + random16_add_entropy(esp_random() & 0xFFFF); // improves randonmess + #endif + int fadeoutDelay = (256 - SEGMENT.speed) / 24; if ((fadeoutDelay <= 1 ) || ((SEGENV.call % fadeoutDelay) == 0)) SEGMENT.fadeToBlackBy(max(SEGMENT.speed, (uint8_t)1)); @@ -7606,10 +7612,25 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. } if ((SEGENV.aux1 < SEGLEN) && (volumeSmth > 1.0f)) SEGMENT.setPixelColor(SEGENV.aux1,SEGENV.step); // "repaint" last pixel after blur + unsigned freqBand = SEGENV.aux0 % 16; uint16_t segLoc = random16(SEGLEN); + + if (SEGENV.check1) { // FreqMap mode : blob location by major frequency + int freqLocn; + unsigned maxLen = (SEGENV.check2) ? max(1, SEGLEN-16): SEGLEN; // usable segment length - leave 16 pixels when embedding "GEQ scan" + freqLocn = roundf((log10f((float)FFT_MajorPeak) - 1.78f) * float(maxLen)/(MAX_FREQ_LOG10 - 1.78f)); // log10 frequency range is from 1.78 to 3.71. Let's scale to SEGLEN. // WLEDMM proper rounding + if (freqLocn < 1) freqLocn = 0; // avoid underflow + segLoc = (SEGENV.check2) ? freqLocn + freqBand : freqLocn; + } else if (SEGENV.check2) { // GEQ Scanner mode: blob location is defined by frequency band + random offset + float bandWidth = float(SEGLEN) / 16.0f; + int bandStart = roundf(bandWidth * freqBand); + segLoc = bandStart + random16(max(1, int(bandWidth))); + } + segLoc = max(uint16_t(0), min(uint16_t(SEGLEN-1), segLoc)); // fix overflows + if (SEGLEN < 2) segLoc = 0; // WLEDMM just to be sure - unsigned pixColor = (2*fftResult[SEGENV.aux0%16]*240)/max(1, SEGLEN-1); // WLEDMM avoid uint8 overflow, and preserve pixel parameters for redraw - unsigned pixIntensity = min((unsigned)(2.0f*fftResult[SEGENV.aux0%16]), 255U); + unsigned pixColor = (2*fftResult[freqBand]*240)/max(1, SEGLEN-1); // WLEDMM avoid uint8 overflow, and preserve pixel parameters for redraw + unsigned pixIntensity = min((unsigned)(2.0f*fftResult[freqBand]), 255U); if (volumeSmth > 1.0f) { SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint16_t)pixColor, false, PALETTE_SOLID_WRAP, 0),(uint8_t)pixIntensity)); @@ -7619,12 +7640,12 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline. SEGMENT.blur(max(SEGMENT.intensity, (uint8_t)1)); SEGENV.aux0 ++; SEGENV.aux0 %= 16; // make sure it doesn't cross 16 - SEGMENT.setPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint16_t)pixColor, false, PALETTE_SOLID_WRAP, 0),(uint8_t)pixIntensity)); // repaint center pixel after blur + SEGMENT.addPixelColor(segLoc, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint16_t)pixColor, false, PALETTE_SOLID_WRAP, 0),(uint8_t)pixIntensity/2)); // repaint center pixel after blur } else SEGMENT.blur(max(SEGMENT.intensity, (uint8_t)1)); // silence - just blur it again - return FRAMETIME_FIXED; + return SEGENV.check2 ? FRAMETIME : (3*FRAMETIME_FIXED/4); // faster updates in GEQ Scanner mode } // mode_blurz() -static const char _data_FX_MODE_BLURZ[] PROGMEM = "Blurz ☾@Fade rate,Blur;!,Color mix;!;01f;sx=48,ix=127,m12=0,si=0"; // Pixels, Beatsin +static const char _data_FX_MODE_BLURZ[] PROGMEM = "Blurz Plus ☾@Fade rate,Blur,,,,FreqMap ☾,GEQ Scanner ☾,;!,Color mix;!;01f;sx=48,ix=127,m12=7,si=0"; // Pinwheel, Beatsin #endif ///////////////////////// From 7d10bd0cd99982b4e2332d687c9f19f4e8dc566b Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:27:53 +0100 Subject: [PATCH 09/39] Allow TV Simulator on single LED segments I've checked the code - nothing preventing the effect to run with SEGLEN=1 --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index b7b61daf48..26bb99e259 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4720,7 +4720,7 @@ uint16_t mode_tv_simulator(void) { return FRAMETIME; } -static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;"; +static const char _data_FX_MODE_TV_SIMULATOR[] PROGMEM = "TV Simulator@!,!;;!;01"; /* From 12ef7cb2855c6e2d955ff33fc860fd4948b0076d Mon Sep 17 00:00:00 2001 From: Will Miles Date: Wed, 23 Oct 2024 19:47:44 -0400 Subject: [PATCH 10/39] Enable NON32XFER_HANDLER on ESP8266 This is a platform feature that asks forgiveness for PROGMEM misuse: it adds a handler such that incorrectly used PROGMEM will work without crashing, just really, *really* inefficiently. Given that most of our real-world use cases for PROGMEM strings are relatively infrequent text calls, we can err on the side of developer convenience and address performance problems if and when they arise. --- platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/platformio.ini b/platformio.ini index 13b45feb7c..e49c32dabd 100644 --- a/platformio.ini +++ b/platformio.ini @@ -291,6 +291,7 @@ build_flags = ; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48 ;; in case of linker errors like "section `.text1' will not fit in region `iram1_0_seg'" ; -D PIO_FRAMEWORK_ARDUINO_MMU_CACHE16_IRAM48_SECHEAP_SHARED ;; (experimental) adds some extra heap, but may cause slowdown -D USERMOD_AUDIOREACTIVE + -D NON32XFER_HANDLER ;; ask forgiveness for PROGMEM misuse lib_deps = #https://github.com/lorol/LITTLEFS.git From 827cf8786045eb2853ff640efd9407925d8db683 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 13 Oct 2024 11:01:05 +0200 Subject: [PATCH 11/39] Merge pull request #4188 from LuisFadini/0_15_brt_timezone Added BRT timezone --- wled00/data/settings_time.htm | 1 + wled00/ntp.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/wled00/data/settings_time.htm b/wled00/data/settings_time.htm index 52f3385ea2..0c6e68a790 100644 --- a/wled00/data/settings_time.htm +++ b/wled00/data/settings_time.htm @@ -182,6 +182,7 @@ Time setup AKST/AKDT (Anchorage) MX-CST PKT (Pakistan) + BRT (Brasília) UTC offset: seconds (max. 18 hours) Current local time is unknown. diff --git a/wled00/ntp.cpp b/wled00/ntp.cpp index fb5e85b3ae..ddebd9499a 100644 --- a/wled00/ntp.cpp +++ b/wled00/ntp.cpp @@ -48,6 +48,7 @@ Timezone* tz = nullptr; #define TZ_ANCHORAGE 20 #define TZ_MX_CENTRAL 21 #define TZ_PAKISTAN 22 +#define TZ_BRASILIA 23 #define TZ_INIT 255 byte tzCurrent = TZ_INIT; //uninitialized @@ -168,6 +169,11 @@ void updateTimezone() { tcrStandard = tcrDaylight; break; } + case TZ_BRASILIA : { + tcrDaylight = {Last, Sun, Mar, 1, -180}; //Brasília Standard Time = UTC - 3 hours + tcrStandard = tcrDaylight; + break; + } } tzCurrent = currentTimezone; From ae076727104040c5419b6b681f5f6d889643f46b Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 26 Nov 2024 14:20:07 +0100 Subject: [PATCH 12/39] swirl effect bugfix avoid drawing outside of visible area --- wled00/FX.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 26bb99e259..62edcfe7c1 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6214,9 +6214,9 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g uint16_t ms = strip.now; - SEGMENT.addPixelColorXY(i, m, ColorFromPalette(SEGPALETTE, ms/29, 255, LINEARBLEND)); - SEGMENT.addPixelColorXY(j, n, ColorFromPalette(SEGPALETTE, ms/41, 255, LINEARBLEND)); - SEGMENT.addPixelColorXY(k, p, ColorFromPalette(SEGPALETTE, ms/73, 255, LINEARBLEND)); + if (i Date: Tue, 26 Nov 2024 15:33:56 +0100 Subject: [PATCH 13/39] allow tri fade effect on 0D (single pixel) --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 62edcfe7c1..a985386252 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1743,7 +1743,7 @@ uint16_t mode_tricolor_fade(void) { return FRAMETIME; } -static const char _data_FX_MODE_TRICOLOR_FADE[] PROGMEM = "Tri Fade@!;1,2,3;!"; +static const char _data_FX_MODE_TRICOLOR_FADE[] PROGMEM = "Tri Fade@!;1,2,3;!;01"; /* From c44784071ef79d8e431d84a7e876a64add930394 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:07:56 +0100 Subject: [PATCH 14/39] small tails for rolling balls --- wled00/FX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index a985386252..9612070ee3 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -3048,7 +3048,8 @@ static uint16_t rolling_balls(void) { float cfac = float(scale8(8, 255-SEGMENT.speed) +1)*20000.0f; // this uses the Aircoookie conversion factor for scaling time using speed slider bool hasCol2 = SEGCOLOR(2); - if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); + //if (!SEGMENT.check2) SEGMENT.fill(hasCol2 ? BLACK : SEGCOLOR(1)); + if (!SEGMENT.check2) SEGMENT.fade_out(253); // WLEDMM adding a bit of trail for (int i = 0; i < numBalls; i++) { float timeSinceLastUpdate = float((strip.now - balls[i].lastBounceUpdate))/cfac; From 402786c14e15799b2d4910f8298c69ab5395cbd0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:11:07 +0100 Subject: [PATCH 15/39] GEQ FLat mode (1D) --- wled00/FX.cpp | 45 ++++++++++++++++++++++++++++++++++----------- wled00/wled.h | 2 +- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9612070ee3..37c0b8e8be 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8101,15 +8101,36 @@ static const char _data_FX_MODE_WATERFALL[] PROGMEM = "Waterfall@!,Adjust color, #ifndef WLED_DISABLE_2D ///////////////////////// -// ** 2D GEQ // +// 1D / 2D GEQ // ///////////////////////// -uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. - if (!strip.isMatrix) return mode_static(); // not a 2D set-up + +// GEQ helper: either draws 2D, or flattens pixels to 1D +static void setFlatPixelXY(bool flatMode, int x, int y, uint32_t color, unsigned cols, unsigned rows, unsigned offset) { + if ((unsigned(x) >= cols) || (unsigned(y) >= rows)) return; // skip invisible + + if (!flatMode) SEGMENT.setPixelColorXY(x, y, color); // normal 2D + else { + y = rows - y -1 ; // reverse y + if (y & 0x01) y = (rows + y) / 2; // center bars: odd pixels to the right + else y = (rows - 1 - y) / 2; // even pixels to the left + + int pix = x*rows + y + offset; // flatten -> transpose x y so that bars stay bars + if (unsigned(pix) >= SEGLEN) return; // skip invisible + SEGMENT.setPixelColor(pix, color); + } +} + +uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. Flat Mode added by softhack007 + //if (!strip.isMatrix) return mode_static(); // not a 2D set-up, not a problem + bool flatMode = !SEGMENT.is2D(); const int NUM_BANDS = map2(SEGMENT.custom1, 0, 255, 1, 16); - const uint16_t cols = SEGMENT.virtualWidth(); - const uint16_t rows = SEGMENT.virtualHeight(); - if ((cols <=1) || (rows <=1)) return mode_static(); // not really a 2D set-up + const int vLength = SEGLEN; // for flat mode + const uint16_t cols = flatMode ? min(max(2, NUM_BANDS), (vLength+1)/2) : SEGMENT.virtualWidth(); + const uint16_t rows = flatMode ? vLength / cols : SEGMENT.virtualHeight(); + const unsigned offset = flatMode ? max(0, (vLength - rows*cols +1) / 2) : 0; // flatmode: always center effect + + if ((cols <=1) || (rows <=1)) return mode_static(); // too small if (!SEGENV.allocateData(cols*sizeof(uint16_t))) return mode_static(); //allocation failed uint16_t *previousBarHeight = reinterpret_cast(SEGENV.data); //array of previous bar heights per frequency band @@ -8175,7 +8196,7 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. if (barHeight > previousBarHeight[x]) previousBarHeight[x] = barHeight; //drive the peak up uint32_t ledColor = BLACK; - if ((! SEGMENT.check1) && (barHeight > 0)) { // use faster drawLine when single-color bars are needed + if ((! SEGMENT.check1) && !flatMode && (barHeight > 0)) { // use faster drawLine when single-color bars are needed ledColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0); SEGMENT.drawLine(int(x), max(0,int(rows)-barHeight), int(x), int(rows-1), ledColor, false); // max(0, ...) to prevent negative Y } else { @@ -8184,23 +8205,25 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. colorIndex = map(y, 0, rows-1, 0, 255); ledColor = SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0); - SEGMENT.setPixelColorXY(x, rows-1 - y, ledColor); + setFlatPixelXY(flatMode, x, rows-1 - y, ledColor, cols, rows, offset); } } - if ((SEGMENT.intensity < 255) && (previousBarHeight[x] > 0) && (previousBarHeight[x] < rows)) // WLEDMM avoid "overshooting" into other segments - SEGMENT.setPixelColorXY(x, rows - previousBarHeight[x], (SEGCOLOR(2) != BLACK) ? SEGCOLOR(2) : ledColor); + if (!flatMode && (SEGMENT.intensity < 255) && (previousBarHeight[x] > 0) && (previousBarHeight[x] < rows)) // WLEDMM avoid "overshooting" into other segments - disable ripple pixels in 1D mode + setFlatPixelXY(flatMode, x, rows - previousBarHeight[x], (SEGCOLOR(2) != BLACK) ? SEGCOLOR(2) : ledColor, cols, rows, offset); if (rippleTime && previousBarHeight[x]>0) previousBarHeight[x]--; //delay/ripple effect } #ifdef SR_DEBUG + if (!flatMode) { // WLEDMM: abuse top left/right pixels for peak detection debugging SEGMENT.setPixelColorXY(cols-1, 0, (samplePeak > 0) ? GREEN : BLACK); if (samplePeak > 0) SEGMENT.setPixelColorXY(0, 0, GREEN); // WLEDMM end + } #endif return FRAMETIME; } // mode_2DGEQ() -static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ ☾@Fade speed,Ripple decay,# of bands,,,Color bars,Smooth bars ☾;!,,Peaks;!;2f;c1=255,c2=64,pal=11,si=0"; // Beatsin +static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ ☾@Fade speed,Ripple decay,# of bands,,,Color bars,Smooth bars ☾;!,,Peaks;!;12f;c1=255,c2=64,pal=11,si=0"; // Beatsin ///////////////////////// diff --git a/wled00/wled.h b/wled00/wled.h index 85a9fe8444..f2c0ac6eac 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2411150 +#define VERSION 2411270 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ From 8ff0223520edf4cc934a734ce7e9880b61c32fa2 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:59:13 +0100 Subject: [PATCH 16/39] GEQ flat mode for 2D MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit you still have to use a trick -> the "expand 1D" drop-down is hidden once you select a 2D-capable effect * Create your segment with 2 colums or 2 rows (might also need "transpose" * Select a 1D effect like chunchun * set expand to "Pixels" or "Bar" * now select the GEQ effect --> Flat GEQ runs in the previously set expand mode. --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 37c0b8e8be..838f763c33 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8122,7 +8122,7 @@ static void setFlatPixelXY(bool flatMode, int x, int y, uint32_t color, unsigned uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. Flat Mode added by softhack007 //if (!strip.isMatrix) return mode_static(); // not a 2D set-up, not a problem - bool flatMode = !SEGMENT.is2D(); + bool flatMode = !SEGMENT.is2D() || (SEGMENT.width() < 3) || (SEGMENT.height() < 3); // also use flat mode when less than 3 colums or rows const int NUM_BANDS = map2(SEGMENT.custom1, 0, 255, 1, 16); const int vLength = SEGLEN; // for flat mode From 59d5ff02c551d82abeccae6b61f68468ad10395a Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 27 Nov 2024 13:18:43 +0100 Subject: [PATCH 17/39] Flat GEQ improvement for shorter stips only center bars if we more than 4 pixels per bar. --- wled00/FX.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 838f763c33..694239d78e 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8110,10 +8110,11 @@ static void setFlatPixelXY(bool flatMode, int x, int y, uint32_t color, unsigned if (!flatMode) SEGMENT.setPixelColorXY(x, y, color); // normal 2D else { - y = rows - y -1 ; // reverse y - if (y & 0x01) y = (rows + y) / 2; // center bars: odd pixels to the right - else y = (rows - 1 - y) / 2; // even pixels to the left - + y = rows - y - 1; // reverse y + if (rows > 4) { // center y if we have more than 4 pixels per bar + if (y & 0x01) y = (rows + y) / 2; // center bars: odd pixels to the right + else y = (rows - 1 - y) / 2; // even pixels to the left + } int pix = x*rows + y + offset; // flatten -> transpose x y so that bars stay bars if (unsigned(pix) >= SEGLEN) return; // skip invisible SEGMENT.setPixelColor(pix, color); From f21b2949f1c470459f9d67656f10b0979b6e0af1 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 27 Nov 2024 21:13:46 +0100 Subject: [PATCH 18/39] fix for effect double restart problem when cross-fade is enabled we only use palette and brightness transitions, so effect restart at the transition end is not required. --- wled00/FX_fcn.cpp | 6 +++--- wled00/wled.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 1c5779464b..0f750b0f03 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -494,12 +494,12 @@ void Segment::setCurrentPalette() { } void Segment::handleTransition() { - if (!transitional) return; + if (!transitional || !_t) return; // Early exit if no transition active unsigned long maxWait = millis() + 20; if (mode == FX_MODE_STATIC && next_time > maxWait) next_time = maxWait; if (progress() == 0xFFFFU) { if (_t) { - if (_t->_modeP != mode) markForReset(); + //if (_t->_modeP != mode) markForReset(); // WLEDMM effect transition disabled as it does not work (flashes due to double effect restart) delete _t; _t = nullptr; } @@ -618,7 +618,7 @@ void Segment::setMode(uint8_t fx, bool loadDefaults, bool sliderDefaultsOnly) { sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) {if (oldPalette==-1) oldPalette = palette; setPalette(sOpt);} else {if (oldPalette!=-1) setPalette(oldPalette); oldPalette = -1;} } } - if (!fadeTransition) markForReset(); // WLEDMM quickfix for effect "double startup" bug. -> only works when "Crossfade" is disabled (led settings) + /*if (!fadeTransition)*/ markForReset(); // WLEDMM quickfix for effect "double startup" bug. stateChanged = true; // send UDP/WS broadcast } } diff --git a/wled00/wled.h b/wled00/wled.h index f2c0ac6eac..fe1761a2d2 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2411270 +#define VERSION 2411271 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ @@ -393,7 +393,7 @@ WLED_GLOBAL byte briS _INIT(128); // default brightness WLED_GLOBAL byte nightlightTargetBri _INIT(0); // brightness after nightlight is over WLED_GLOBAL byte nightlightDelayMins _INIT(60); WLED_GLOBAL byte nightlightMode _INIT(NL_MODE_FADE); // See const.h for available modes. Was nightlightFade -WLED_GLOBAL bool fadeTransition _INIT(false); // enable crossfading color transition // WLEDMM disabled - has bugs that will be solved in upstream beta4 +WLED_GLOBAL bool fadeTransition _INIT(true); // enable crossfading color transition // WLEDMM only do color x-fade -- effect x-fade has bugs that will be solved in upstream beta4 WLED_GLOBAL uint16_t transitionDelay _INIT(750); // default crossfade duration in ms WLED_GLOBAL uint_fast16_t briMultiplier _INIT(100); // % of brightness to set (to limit power, if you set it to 50 and set bri to 255, actual brightness will be 127) From 1670330b1b00a812d522e8bbbdc8773e97bb12f3 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 28 Nov 2024 17:51:39 +0100 Subject: [PATCH 19/39] Octopus Radial Wave mode --- wled00/FX.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 694239d78e..e77e72f19b 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8575,6 +8575,7 @@ static const char _data_FX_MODE_2DSOAP[] PROGMEM = "Soap@!,Smoothness;;!;2"; //Octopus (https://editor.soulmatelights.com/gallery/671-octopus) //Stepko and Sutaburosu // adapted for WLED by @blazoncek +// RadialWave mode added by @softhack007, based on https://editor.soulmatelights.com/gallery/1090-radialwave uint16_t mode_2Doctopus() { if (!strip.isMatrix) return mode_static(); // not a 2D set-up @@ -8632,12 +8633,19 @@ uint16_t mode_2Doctopus() { else SEGENV.step += SEGMENT.speed / 32 + 1; // 1-4 range + uint32_t octopusStep = SEGENV.step/2; // 1/2 for Octopus mode + uint32_t radialStep = 7*SEGENV.step/6; // 7/6 = 1.16 for RadialWave mode + for (int x = xStart; x < xEnd; x++) { for (int y = yStart; y < yEnd; y++) { byte angle = rMap[XY(x,y)].angle; byte radius = rMap[XY(x,y)].radius; //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); - uint16_t intensity = sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step/2) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); + uint16_t intensity; + if (SEGMENT.check3) + intensity = sin8(radialStep + sin8(radialStep - radius) + angle * (SEGMENT.custom3/4+1)); // RadialWave + else + intensity = sin8(sin8((angle * 4 - radius) / 4 + octopusStep) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); // Octopus intensity = map(intensity*intensity, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); SEGMENT.setPixelColorXY(x, y, c); @@ -8645,8 +8653,7 @@ uint16_t mode_2Doctopus() { } return FRAMETIME; } -static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs, SuperSync;;!;2;"; - +static const char _data_FX_MODE_2DOCTOPUS[] PROGMEM = "Octopus@!,,Offset X,Offset Y,Legs, SuperSync,,RadialWave ☾;;!;2;"; //Waving Cell //@Stepko (https://editor.soulmatelights.com/gallery/1704-wavingcells) From 9046ec4bde10322911eba36ec81197ce6fbc32e5 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:15:17 +0100 Subject: [PATCH 20/39] Octopus minor optimization replacing "map" with direct computation --- wled00/FX.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e77e72f19b..1b07127cea 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8646,7 +8646,8 @@ uint16_t mode_2Doctopus() { intensity = sin8(radialStep + sin8(radialStep - radius) + angle * (SEGMENT.custom3/4+1)); // RadialWave else intensity = sin8(sin8((angle * 4 - radius) / 4 + octopusStep) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); // Octopus - intensity = map(intensity*intensity, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display + //intensity = map(intensity*intensity, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display + intensity = (intensity * intensity) / 255; // WLEDMM same as above, but faster and a bit more accurate CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); SEGMENT.setPixelColorXY(x, y, c); } From 5ea9cb1907bfd8f6c0fc54b4b4658932c774ad9f Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Thu, 28 Nov 2024 22:21:47 +0100 Subject: [PATCH 21/39] Octopus code improvements * removed dead code * merge octopusStep and radialStep --> octoSpeed * improve speed slider resolution by first multiplying, then dividing Thanks @ewoudwijma --- wled00/FX.cpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 1b07127cea..9656d15efd 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -8628,13 +8628,14 @@ uint16_t mode_2Doctopus() { } } - if (true) // WLEDMM SuperSync - SEGENV.step = strip.now * (SEGMENT.speed / 32 + 1) / 25; // WLEDMM 40fps - else - SEGENV.step += SEGMENT.speed / 32 + 1; // 1-4 range + // WLEDMM SuperSync + SEGENV.step = (strip.now * (SEGMENT.speed+15)) / 33 / 25; // WLEDMM 40fps; speed range 0.4 ... 8 - uint32_t octopusStep = SEGENV.step/2; // 1/2 for Octopus mode - uint32_t radialStep = 7*SEGENV.step/6; // 7/6 = 1.16 for RadialWave mode + // speed of motion and color change + uint32_t colorSpeed = SEGENV.step / 2; + uint32_t octoSpeed; + if (SEGMENT.check3) octoSpeed = 4*SEGENV.step/5; // 4/5 = 0.8 for RadialWave mode + else octoSpeed = SEGENV.step/2; // 1/2 = 0.5 for Octopus mode for (int x = xStart; x < xEnd; x++) { for (int y = yStart; y < yEnd; y++) { @@ -8643,12 +8644,12 @@ uint16_t mode_2Doctopus() { //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); uint16_t intensity; if (SEGMENT.check3) - intensity = sin8(radialStep + sin8(radialStep - radius) + angle * (SEGMENT.custom3/4+1)); // RadialWave + intensity = sin8(octoSpeed + sin8(octoSpeed - radius) + angle * (SEGMENT.custom3/4+1)); // RadialWave else - intensity = sin8(sin8((angle * 4 - radius) / 4 + octopusStep) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); // Octopus + intensity = sin8(sin8((angle * 4 - radius) / 4 + octoSpeed) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); // Octopus //intensity = map(intensity*intensity, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display intensity = (intensity * intensity) / 255; // WLEDMM same as above, but faster and a bit more accurate - CRGB c = ColorFromPalette(SEGPALETTE, SEGENV.step / 2 - radius, intensity); + CRGB c = ColorFromPalette(SEGPALETTE, colorSpeed - radius, intensity); SEGMENT.setPixelColorXY(x, y, c); } } From e914417c7418e0688ba72d3c7b64e92a3d387473 Mon Sep 17 00:00:00 2001 From: Damian Schneider Date: Wed, 27 Nov 2024 22:27:56 +0100 Subject: [PATCH 22/39] Merge pull request #4181 from DedeHai/0_15_trig_math Added integer based `sin()/cos()` functions, changed all trig functions to wled_math --- usermods/Analog_Clock/Analog_Clock.h | 4 +- wled00/FX.cpp | 288 ++++++++++++++------------- wled00/fcn_declare.h | 59 ++++-- wled00/util.cpp | 41 +++- wled00/wled_math.cpp | 106 +++++++++- 5 files changed, 319 insertions(+), 179 deletions(-) diff --git a/usermods/Analog_Clock/Analog_Clock.h b/usermods/Analog_Clock/Analog_Clock.h index 596f0acb3b..9d82f7670c 100644 --- a/usermods/Analog_Clock/Analog_Clock.h +++ b/usermods/Analog_Clock/Analog_Clock.h @@ -102,9 +102,9 @@ class AnalogClockUsermod : public Usermod { void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) { uint32_t ms = time.ms % 1000; - uint8_t b0 = (cos8(ms * 64 / 1000) - 128) * 2; + uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(secondLed, gamma32(scale32(secondColor, b0))); - uint8_t b1 = (sin8(ms * 64 / 1000) - 128) * 2; + uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2; setPixelColor(inc(secondLed, 1, secondsSegment), gamma32(scale32(secondColor, b1))); } diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9656d15efd..d89108ed58 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -31,7 +31,7 @@ // effect utility functions static uint8_t sin_gap(uint16_t in) { if (in & 0x100) return 0; - return sin8(in + 192); // correct phase shift of sine so that it starts and stops at 0 + return sin8_t(in + 192); // correct phase shift of sine so that it starts and stops at 0 } static uint16_t triwave16(uint16_t in) { @@ -364,7 +364,7 @@ uint16_t mode_breath(void) { counter = (counter >> 2) + (counter >> 4); //0-16384 + 0-2048 if (counter < 16384) { if (counter > 8192) counter = 8192 - (counter - 8192); - var = sin16(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 + var = sin16_t(counter) / 103; //close to parabolic in range 0-8192, max val. 23170 } uint8_t lum = 30 + var; @@ -546,7 +546,7 @@ uint16_t running_base(bool saw, bool dual=false) { } a = 255 - a; } - uint8_t s = dual ? sin_gap(a) : sin8(a); + uint8_t s = dual ? sin_gap(a) : sin8_t(a); uint32_t ca = color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0), s); if (dual) { uint16_t b = (SEGLEN-1-i)*x_scale - counter; @@ -1934,13 +1934,13 @@ uint16_t mode_pride_2015(void) { uint16_t sPseudotime = SEGENV.step; uint16_t sHue16 = SEGENV.aux0; - uint8_t sat8 = beatsin88( 87, 220, 250); - uint8_t brightdepth = beatsin88( 341, 96, 224); - uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - uint8_t msmultiplier = beatsin88(147, 23, 60); + uint8_t sat8 = beatsin88_t( 87, 220, 250); + uint8_t brightdepth = beatsin88_t( 341, 96, 224); + uint16_t brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + uint8_t msmultiplier = beatsin88_t(147, 23, 60); uint16_t hue16 = sHue16;//gHue * 256; - uint16_t hueinc16 = beatsin88(113, 1, 3000); + uint16_t hueinc16 = beatsin88_t(113, 1, 3000); if(SEGENV.call == 0) { SEGMENT.setUpLeds(); // WLEDMM use lossless getPixelColor() @@ -1948,15 +1948,14 @@ uint16_t mode_pride_2015(void) { } sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88( 400, 5,9); + sHue16 += duration * beatsin88_t( 400, 5,9); uint16_t brightnesstheta16 = sPseudotime; - for (int i = 0 ; i < SEGLEN; i++) { hue16 += hueinc16; uint8_t hue8 = hue16 >> 8; brightnesstheta16 += brightnessthetainc16; - uint16_t b16 = sin16( brightnesstheta16 ) + 32768; + uint16_t b16 = sin16_t( brightnesstheta16 ) + 32768; uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -2047,7 +2046,7 @@ uint16_t mode_juggle(void) { CRGB fastled_col; byte dothue = 0; for (int i = 0; i < 8; i++) { - uint16_t index = 0 + beatsin88((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); + uint16_t index = 0 + beatsin88_t((16 + SEGMENT.speed)*(i + 7), 0, SEGLEN -1); fastled_col = CRGB(SEGMENT.getPixelColor(index)); fastled_col |= (SEGMENT.palette==0)?CHSV(dothue, 220, 255):ColorFromPalette(SEGPALETTE, dothue, 255); SEGMENT.setPixelColor(index, fastled_col); @@ -2174,15 +2173,15 @@ uint16_t mode_colorwaves() { uint16_t sPseudotime = SEGENV.step; uint16_t sHue16 = SEGENV.aux0; - uint8_t brightdepth = beatsin88(341, 96, 224); - uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256)); - uint8_t msmultiplier = beatsin88(147, 23, 60); + uint8_t brightdepth = beatsin88_t(341, 96, 224); + uint16_t brightnessthetainc16 = beatsin88_t( 203, (25 * 256), (40 * 256)); + uint8_t msmultiplier = beatsin88_t(147, 23, 60); uint16_t hue16 = sHue16;//gHue * 256; - uint16_t hueinc16 = beatsin88(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues + uint16_t hueinc16 = beatsin88_t(113, 60, 300)*SEGMENT.intensity*10/255; // Use the Intensity Slider for the hues sPseudotime += duration * msmultiplier; - sHue16 += duration * beatsin88(400, 5, 9); + sHue16 += duration * beatsin88_t(400, 5, 9); uint16_t brightnesstheta16 = sPseudotime; if(SEGENV.call == 0) { @@ -2201,7 +2200,7 @@ uint16_t mode_colorwaves() { } brightnesstheta16 += brightnessthetainc16; - uint16_t b16 = sin16(brightnesstheta16) + 32768; + uint16_t b16 = sin16_t(brightnesstheta16) + 32768; uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536; uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536; @@ -2221,7 +2220,7 @@ static const char _data_FX_MODE_COLORWAVES[] PROGMEM = "Colorwaves@!,Hue;!;!"; uint16_t mode_bpm() { //CRGB fastled_col; uint32_t stp = (strip.now / 20) & 0xFF; - uint8_t beat = beatsin8(SEGMENT.speed, 64, 255); + uint8_t beat = beatsin8_t(SEGMENT.speed, 64, 255); for (int i = 0; i < SEGLEN; i++) { //fastled_col = ColorFromPalette(SEGPALETTE, stp + (i * 2), beat - stp + (i * 10)); //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -2242,7 +2241,7 @@ uint16_t mode_fillnoise8() { //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0)); } - SEGENV.step += beatsin8(SEGMENT.speed, 1, 6); //10,1,4 + SEGENV.step += beatsin8_t(SEGMENT.speed, 1, 6); //10,1,4 return FRAMETIME; } @@ -2255,13 +2254,13 @@ uint16_t mode_noise16_1() { SEGENV.step += (1 + SEGMENT.speed/16); for (int i = 0; i < SEGLEN; i++) { - uint16_t shift_x = beatsin8(11); // the x position of the noise field swings @ 17 bpm + uint16_t shift_x = beatsin8_t(11); // the x position of the noise field swings @ 17 bpm uint16_t shift_y = SEGENV.step/42; // the y position becomes slowly incremented uint16_t real_x = (i + shift_x) * scale; // the x position of the noise field swings @ 17 bpm uint16_t real_y = (i + shift_y) * scale; // the y position becomes slowly incremented uint32_t real_z = SEGENV.step; // the z position becomes quickly incremented uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - uint8_t index = sin8(noise * 3); // map LED color based on noise data + uint8_t index = sin8_t(noise * 3); // map LED color based on noise data //fastled_col = ColorFromPalette(SEGPALETTE, index, 255, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -2282,7 +2281,7 @@ uint16_t mode_noise16_2() { uint16_t shift_x = SEGENV.step >> 6; // x as a function of time uint32_t real_x = (i + shift_x) * scale; // calculate the coordinates within the noise field uint8_t noise = inoise16(real_x, 0, 4223) >> 8; // get the noise data and scale it down - uint8_t index = sin8(noise * 3); // map led color based on noise data + uint8_t index = sin8_t(noise * 3); // map led color based on noise data //fastled_col = ColorFromPalette(SEGPALETTE, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -2306,7 +2305,7 @@ uint16_t mode_noise16_3() { uint32_t real_y = (i + shift_y) * scale; // based on the precalculated positions uint32_t real_z = SEGENV.step*8; uint8_t noise = inoise16(real_x, real_y, real_z) >> 8; // get the noise data and scale it down - uint8_t index = sin8(noise * 3); // map led color based on noise data + uint8_t index = sin8_t(noise * 3); // map led color based on noise data //fastled_col = ColorFromPalette(SEGPALETTE, index, noise, LINEARBLEND); // With that value, look up the 8 bit colour palette value and assign it to the current LED. //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -2395,14 +2394,14 @@ static const char _data_FX_MODE_COLORTWINKLE[] PROGMEM = "Colortwinkles@Fade spe //Calm effect, like a lake at night uint16_t mode_lake() { uint8_t sp = SEGMENT.speed/10; - int wave1 = beatsin8(sp +2, -64,64); - int wave2 = beatsin8(sp +1, -64,64); - uint8_t wave3 = beatsin8(sp +2, 0,80); + int wave1 = beatsin8_t(sp +2, -64,64); + int wave2 = beatsin8_t(sp +1, -64,64); + uint8_t wave3 = beatsin8_t(sp +2, 0,80); //CRGB fastled_col; for (int i = 0; i < SEGLEN; i++) { - int index = cos8((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; + int index = cos8_t((i*15)+ wave1)/2 + cubicwave8((i*23)+ wave2)/2; uint8_t lum = (index > wave3) ? index - wave3 : 0; //fastled_col = ColorFromPalette(SEGPALETTE, map(index,0,255,0,240), lum, LINEARBLEND); //SEGMENT.setPixelColor(i, fastled_col.red, fastled_col.green, fastled_col.blue); @@ -2569,7 +2568,7 @@ uint16_t ripple_base() propI /= 2; uint16_t cx = rippleorigin >> 8; uint16_t cy = rippleorigin & 0xFF; - uint8_t mag = scale8(sin8((propF>>2)), amp); + uint8_t mag = scale8(sin8_t((propF>>2)), amp); if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true); } else #endif @@ -2644,7 +2643,7 @@ CRGB twinklefox_one_twinkle(uint32_t ms, uint8_t salt, bool cat) uint16_t ticks = ms / SEGENV.aux0; uint8_t fastcycle8 = ticks; uint16_t slowcycle16 = (ticks >> 8) + salt; - slowcycle16 += sin8(slowcycle16); + slowcycle16 += sin8_t(slowcycle16); slowcycle16 = (slowcycle16 * 2053) + 1384; uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8); @@ -3115,7 +3114,7 @@ uint16_t sinelon_base(bool dual, bool rainbow=false) { if (SEGLEN == 1) return mode_static(); if (SEGENV.call == 0) { SEGENV.setUpLeds(); SEGMENT.fill(BLACK); } // WLEDMM use lossless getPixelColor() SEGMENT.fade_out(SEGMENT.intensity); - uint16_t pos = beatsin16(SEGMENT.speed/10,0,SEGLEN-1); + uint16_t pos = beatsin16_t(SEGMENT.speed/10,0,SEGLEN-1); if (SEGENV.call == 0) SEGENV.aux0 = pos; uint32_t color1 = SEGMENT.color_from_palette(pos, true, false, 0); uint32_t color2 = SEGCOLOR(2); @@ -3941,13 +3940,13 @@ uint16_t mode_plasma(void) { if (SEGENV.call == 0) { SEGENV.aux0 = random8(0,2); // add a bit of randomness } - uint8_t thisPhase = beatsin8(6+SEGENV.aux0,-64,64); - uint8_t thatPhase = beatsin8(7+SEGENV.aux0,-64,64); + uint8_t thisPhase = beatsin8_t(6+SEGENV.aux0,-64,64); + uint8_t thatPhase = beatsin8_t(7+SEGENV.aux0,-64,64); for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set color & brightness based on a wave as follows: uint8_t colorIndex = cubicwave8((i*(2+ 3*(SEGMENT.speed >> 5))+thisPhase) & 0xFF)/2 // factor=23 // Create a wave and add a phase change and add another wave with its own phase change. - + cos8((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. - uint8_t thisBright = qsub8(colorIndex, beatsin8(7,0, (128 - (SEGMENT.intensity>>1)))); + + cos8_t((i*(1+ 2*(SEGMENT.speed >> 5))+thatPhase) & 0xFF)/2; // factor=15 // Hey, you can even change the frequencies if you wish. + uint8_t thisBright = qsub8(colorIndex, beatsin8_t(7,0, (128 - (SEGMENT.intensity>>1)))); //CRGB color = ColorFromPalette(SEGPALETTE, colorIndex, thisBright, LINEARBLEND); //SEGMENT.setPixelColor(i, color.red, color.green, color.blue); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(colorIndex, false, PALETTE_SOLID_WRAP, 0, thisBright)); @@ -4076,10 +4075,10 @@ CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t uint16_t wavescale_half = (wavescale >> 1) + 20; waveangle += ((120 + SEGMENT.intensity) * i); //original 250 * i - uint16_t s16 = sin16(waveangle) + 32768; + uint16_t s16 = sin16_t(waveangle) + 32768; uint16_t cs = scale16(s16, wavescale_half) + wavescale_half; ci += (cs * i); - uint16_t sindex16 = sin16(ci) + 32768; + uint16_t sindex16 = sin16_t(ci) + 32768; uint8_t sindex8 = scale16(sindex16, 240); return ColorFromPalette(p, sindex8, bri, LINEARBLEND); } @@ -4111,34 +4110,34 @@ uint16_t mode_pacifica() uint64_t deltat = (strip.now >> 2) + ((strip.now * SEGMENT.speed) >> 7); strip.now = deltat; - uint16_t speedfactor1 = beatsin16(3, 179, 269); - uint16_t speedfactor2 = beatsin16(4, 179, 269); + uint16_t speedfactor1 = beatsin16_t(3, 179, 269); + uint16_t speedfactor2 = beatsin16_t(4, 179, 269); uint32_t deltams1 = (deltams * speedfactor1) / 256; uint32_t deltams2 = (deltams * speedfactor2) / 256; uint32_t deltams21 = (deltams1 + deltams2) / 2; - sCIStart1 += (deltams1 * beatsin88(1011,10,13)); - sCIStart2 -= (deltams21 * beatsin88(777,8,11)); - sCIStart3 -= (deltams1 * beatsin88(501,5,7)); - sCIStart4 -= (deltams2 * beatsin88(257,4,6)); + sCIStart1 += (deltams1 * beatsin88_t(1011,10,13)); + sCIStart2 -= (deltams21 * beatsin88_t(777,8,11)); + sCIStart3 -= (deltams1 * beatsin88_t(501,5,7)); + sCIStart4 -= (deltams2 * beatsin88_t(257,4,6)); SEGENV.aux0 = sCIStart1; SEGENV.aux1 = sCIStart2; SEGENV.step = sCIStart4; SEGENV.step = (SEGENV.step << 16) + sCIStart3; // Clear out the LED array to a dim background blue-green //SEGMENT.fill(132618); - uint8_t basethreshold = beatsin8( 9, 55, 65); + uint8_t basethreshold = beatsin8_t( 9, 55, 65); uint8_t wave = beat8( 7 ); for (int i = 0; i < SEGLEN; i++) { CRGB c = CRGB(2, 6, 10); // Render each of four layers, with different scales and speeds, that vary over time - c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16(3, 11 * 256, 14 * 256), beatsin8(10, 70, 130), 0-beat16(301)); - c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16(4, 6 * 256, 9 * 256), beatsin8(17, 40, 80), beat16(401)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8(9, 10,38) , 0-beat16(503)); - c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8(8, 10,28) , beat16(601)); + c += pacifica_one_layer(i, pacifica_palette_1, sCIStart1, beatsin16_t(3, 11 * 256, 14 * 256), beatsin8_t(10, 70, 130), 0-beat16(301)); + c += pacifica_one_layer(i, pacifica_palette_2, sCIStart2, beatsin16_t(4, 6 * 256, 9 * 256), beatsin8_t(17, 40, 80), beat16(401)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart3, 6 * 256 , beatsin8_t(9, 10,38) , 0-beat16(503)); + c += pacifica_one_layer(i, pacifica_palette_3, sCIStart4, 5 * 256 , beatsin8_t(8, 10,28) , beat16(601)); // Add extra 'white' to areas where the four layers of light have lined up brightly - uint8_t threshold = scale8( sin8( wave), 20) + basethreshold; + uint8_t threshold = scale8( sin8_t( wave), 20) + basethreshold; wave += 7; uint8_t l = c.getAverageLight(); if (l > threshold) { @@ -4262,7 +4261,7 @@ uint16_t mode_twinkleup(void) { // A very short twinkle routine for (int i = 0; i < SEGLEN; i++) { uint8_t ranstart = random8(); // The starting value (aka brightness) for each pixel. Must be consistent each time through the loop for this to work. - uint8_t pixBri = sin8(ranstart + 16 * strip.now/(256-SEGMENT.speed)); + uint8_t pixBri = sin8_t(ranstart + 16 * strip.now/(256-SEGMENT.speed)); if (random8() > SEGMENT.intensity) pixBri = 0; SEGMENT.setPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette(random8()+strip.now/100, false, PALETTE_SOLID_WRAP, 0), pixBri)); } @@ -4305,7 +4304,7 @@ uint16_t mode_noisepal(void) { // Slow noise SEGMENT.setPixelColor(i, color.red, color.green, color.blue); } - SEGENV.aux0 += beatsin8(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. + SEGENV.aux0 += beatsin8_t(10,1,4); // Moving along the distance. Vary it a bit with a sine wave. return FRAMETIME; } @@ -4388,7 +4387,7 @@ uint16_t mode_chunchun(void) for (int i = 0; i < numBirds; i++) { counter -= span; - uint16_t megumin = sin16(counter) + 0x8000; + uint16_t megumin = sin16_t(counter) + 0x8000; uint16_t bird = uint32_t(megumin * SEGLEN) >> 16; uint32_t c = SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping bird = constrain(bird, 0, SEGLEN-1); @@ -4558,7 +4557,7 @@ uint16_t mode_washing_machine(void) { SEGENV.step += (speed * 2048) / (512 - SEGMENT.speed); for (int i = 0; i < SEGLEN; i++) { - uint8_t col = sin8(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); + uint8_t col = sin8_t(((SEGMENT.intensity / 25 + 1) * 255 * i / SEGLEN) + (SEGENV.step >> 7)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(col, false, PALETTE_SOLID_WRAP, 3)); } @@ -4911,12 +4910,12 @@ static const char _data_FX_MODE_PERLINMOVE[] PROGMEM = "Perlin Move@!,# of pixel ///////////////////////// // Waveins // ///////////////////////// -// Uses beatsin8() + phase shifting. By: Andrew Tuline +// Uses beatsin8_t() + phase shifting. By: Andrew Tuline uint16_t mode_wavesins(void) { for (int i = 0; i < SEGLEN; i++) { - uint8_t bri = sin8(strip.now/4 + i * SEGMENT.intensity); - uint8_t index = beatsin8(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); + uint8_t bri = sin8_t(strip.now/4 + i * SEGMENT.intensity); + uint8_t index = beatsin8_t(SEGMENT.speed, SEGMENT.custom1, SEGMENT.custom1+SEGMENT.custom2, 0, i * (SEGMENT.custom3<<3)); // custom3 is reduced resolution slider //SEGMENT.setPixelColor(i, ColorFromPalette(SEGPALETTE, index, bri, LINEARBLEND)); SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(index, false, PALETTE_SOLID_WRAP, 0, bri)); } @@ -4938,9 +4937,9 @@ uint16_t mode_FlowStripe(void) { for (int i = 0; i < SEGLEN; i++) { int c = (abs(i - hl) / hl) * 127; - c = sin8(c); - c = sin8(c / 2 + t); - byte b = sin8(c + t/8); + c = sin8_t(c); + c = sin8_t(c / 2 + t); + byte b = sin8_t(c + t/8); SEGMENT.setPixelColor(i, CHSV(b + hue, 255, 255)); } @@ -4974,14 +4973,14 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma unsigned long t = strip.now; // timebase // outer stars for (unsigned i = 0; i < 8; i++) { - x = beatsin8(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio); - y = beatsin8(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio); + x = beatsin8_t(SEGMENT.custom1>>3, 0, cols - 1, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio); + y = beatsin8_t(SEGMENT.intensity>>3, 0, rows - 1, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio); SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255)); } // inner stars for (size_t i = 0; i < 4; i++) { - x = beatsin8(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio); - y = beatsin8(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio); + x = beatsin8_t(SEGMENT.custom2>>3, cols/4, cols - 1 - cols/4, 0, ((i % 2) ? 128 : 0) + (t * i)/ratio); + y = beatsin8_t(SEGMENT.custom3 , rows/4, rows - 1 - rows/4, 0, ((i % 2) ? 192 : 64) + (t * i)/ratio); SEGMENT.addPixelColorXY(x, y, CHSV(i*32, 255, 255)); } // central white dot @@ -5017,10 +5016,10 @@ uint16_t mode_2DColoredBursts() { // By: ldirko https://editor.so SEGENV.aux0++; // hue SEGMENT.fadeToBlackBy(40); for (size_t i = 0; i < numLines; i++) { - byte x1 = beatsin8(2 + SEGMENT.speed/16, 0, (cols - 1)); - byte x2 = beatsin8(1 + SEGMENT.speed/16, 0, (rows - 1)); - byte y1 = beatsin8(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); - byte y2 = beatsin8(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); + byte x1 = beatsin8_t(2 + SEGMENT.speed/16, 0, (cols - 1)); + byte x2 = beatsin8_t(1 + SEGMENT.speed/16, 0, (rows - 1)); + byte y1 = beatsin8_t(5 + SEGMENT.speed/16, 0, (cols - 1), 0, i * 24); + byte y2 = beatsin8_t(3 + SEGMENT.speed/16, 0, (rows - 1), 0, i * 48 + 64); CRGB color = ColorFromPalette(SEGPALETTE, i * 255 / numLines + (SEGENV.aux0&0xFF), 255, LINEARBLEND); byte xsteps = abs8(x1 - y1) + 1; @@ -5068,14 +5067,14 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa int lastY1 = -1; int lastY2 = -1; for (int i = 0; i < cols; i++) { - int posY1 = beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4 ); - int posY2 = beatsin8(SEGMENT.speed/8, 0, rows-1, 0, i*4+128); + int posY1 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ); + int posY2 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128); if ((i==0) || ((abs(lastY1 - posY1) < 2) && (abs(lastY2 - posY2) < 2))) { // use original code when no holes - SEGMENT.setPixelColorXY(i, posY1, ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.setPixelColorXY(i, posY2, ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, posY1, ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.setPixelColorXY(i, posY2, ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); } else { // draw line to prevent holes - SEGMENT.drawLine(i-1, lastY1, i, posY1, ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8(5, 55, 255, 0, i*10), LINEARBLEND)); - SEGMENT.drawLine(i-1, lastY2, i, posY2, ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8(5, 55, 255, 0, i*10+128), LINEARBLEND)); + SEGMENT.drawLine(i-1, lastY1, i, posY1, ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); + SEGMENT.drawLine(i-1, lastY2, i, posY2, ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); } lastY1 = posY1; lastY2 = posY2; @@ -5108,8 +5107,8 @@ uint16_t mode_2DDNASpiral() { // By: ldirko https://editor.soulma SEGMENT.fadeToBlackBy(135); for (int i = 0; i < rows; i++) { - uint16_t x = beatsin8(speeds, 0, cols - 1, 0, i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, i * freq + 128); - uint16_t x1 = beatsin8(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); + uint16_t x = beatsin8_t(speeds, 0, cols - 1, 0, i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, i * freq + 128); + uint16_t x1 = beatsin8_t(speeds, 0, cols - 1, 0, 128 + i * freq) + beatsin8_t(speeds - 7, 0, cols - 1, 0, 128 + 64 + i * freq); uint8_t hue = (i * 128 / rows) + ms; // skip every 4th row every now and then (fade it more) if ((i + ms / 8) & 3) { @@ -5241,9 +5240,9 @@ uint16_t mode_2DFrizzles(void) { // By: Stepko https://editor.so SEGMENT.fadeToBlackBy(16); for (size_t i = 8; i > 0; i--) { - SEGMENT.addPixelColorXY(beatsin8(SEGMENT.speed/8 + i, 0, cols - 1), - beatsin8(SEGMENT.intensity/8 - i, 0, rows - 1), - ColorFromPalette(SEGPALETTE, beatsin8(12, 0, 255), 255, LINEARBLEND)); + SEGMENT.addPixelColorXY(beatsin8_t(SEGMENT.speed/8 + i, 0, cols - 1), + beatsin8_t(SEGMENT.intensity/8 - i, 0, rows - 1), + ColorFromPalette(SEGPALETTE, beatsin8_t(12, 0, 255), 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom1>>3); @@ -5661,7 +5660,7 @@ uint16_t mode_2DHiphotic() { // By: ldirko https://edit for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8(cos8(x * SEGMENT.speed/16 + a / 3) + sin8(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); + SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(sin8_t(cos8_t(x * SEGMENT.speed/16 + a / 3) + sin8_t(y * SEGMENT.intensity/16 + a / 4) + a), false, PALETTE_SOLID_WRAP, 0)); } } @@ -5740,8 +5739,10 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; - reAl += sinf((float)strip.now/305.f)/20.f; - imAg += sinf((float)strip.now/405.f)/20.f; + //reAl += sinf((float)strip.now/305.f)/20.f; + //imAg += sinf((float)strip.now/405.f)/20.f; + reAl += (float)sin16_t(strip.now * 34) / 655340.f; + imAg += (float)sin16_t(strip.now * 26) / 655340.f; dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. dy = (ymax - ymin) / (rows); @@ -5820,8 +5821,8 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline int maxLoops = max(192, 4*(cols+rows)); maxLoops = ((maxLoops / 128) +1) * 128; // make sure whe have half or full turns => multiples of 128 for (int i=0; i < maxLoops; i ++) { - float xlocn = float(sin8(phase/2 + (i* SEGMENT.speed)/64)) / 255.0f; // WLEDMM align speed with original effect - float ylocn = float(cos8(phase/2 + i*2)) / 255.0f; + float xlocn = float(sin8_t(phase/2 + (i* SEGMENT.speed)/64)) / 255.0f; // WLEDMM align speed with original effect + float ylocn = float(cos8_t(phase/2 + i*2)) / 255.0f; //SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing unsigned palIndex = (256*ylocn) + phase/2 + (i* SEGMENT.speed)/64; //SEGMENT.setPixelColorXY(xlocn, ylocn, SEGMENT.color_from_palette(palIndex, false, PALETTE_SOLID_WRAP, 0)); // draw pixel with anti-aliasing - color follows rotation @@ -5832,8 +5833,8 @@ uint16_t mode_2DLissajous(void) { // By: Andrew Tuline } else for (int i=0; i < 256; i ++) { //WLEDMM: stick to the original calculations of xlocn and ylocn - uint_fast8_t xlocn = sin8(phase/2 + (i*SEGMENT.speed)/64); - uint_fast8_t ylocn = cos8(phase/2 + i*2); + uint_fast8_t xlocn = sin8_t(phase/2 + (i*SEGMENT.speed)/64); + uint_fast8_t ylocn = cos8_t(phase/2 + i*2); xlocn = (cols < 2) ? 1 : (map(2*xlocn, 0,511, 0,2*(cols-1)) +1) /2; // softhack007: "*2 +1" for proper rounding ylocn = (rows < 2) ? 1 : (map(2*ylocn, 0,511, 0,2*(rows-1)) +1) /2; // "rows > 2" is needed to avoid div/0 in map() SEGMENT.setPixelColorXY((uint8_t)xlocn, (uint8_t)ylocn, SEGMENT.color_from_palette(strip.now/100+i, false, PALETTE_SOLID_WRAP, 0)); @@ -5939,8 +5940,8 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have uint8_t y3 = map(inoise8(strip.now * speed, 25355, 22685), 0, 255, 0, rows-1); // and one Lissajou function - uint8_t x1 = beatsin8(23 * speed, 0, cols-1); - uint8_t y1 = beatsin8(28 * speed, 0, rows-1); + uint8_t x1 = beatsin8_t(23 * speed, 0, cols-1); + uint8_t y1 = beatsin8_t(28 * speed, 0, rows-1); for (int y = 0; y < rows; y++) { for (int x = 0; x < cols; x++) { @@ -6142,7 +6143,7 @@ uint16_t mode_2DPulser(void) { // By: ldirko https://edi uint32_t a = strip.now / (18 - SEGMENT.speed / 16); uint16_t x = (a / 14) % cols; - uint16_t y = map((sin8(a * 5) + sin8(a * 4) + sin8(a * 2)), 0, 765, rows-1, 0); + uint16_t y = map((sin8_t(a * 5) + sin8_t(a * 4) + sin8_t(a * 2)), 0, 765, rows-1, 0); SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, map(y, 0, rows-1, 0, 255), 255, LINEARBLEND)); SEGMENT.blur(1 + (SEGMENT.intensity>>4)); @@ -6169,10 +6170,10 @@ uint16_t mode_2DSindots(void) { // By: ldirko http SEGMENT.fadeToBlackBy(SEGMENT.custom1>>3); byte t1 = strip.now / (257 - SEGMENT.speed); // 20; - byte t2 = sin8(t1) / 4 * 2; + byte t2 = sin8_t(t1) / 4 * 2; for (int i = 0; i < 13; i++) { - byte x = sin8(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! - byte y = sin8(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! + byte x = sin8_t(t1 + i * SEGMENT.intensity/8)*(cols-1)/255; // max index now 255x15/255=15! + byte y = sin8_t(t2 + i * SEGMENT.intensity/8)*(rows-1)/255; // max index now 255x15/255=15! SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, i * 255 / 13, 255, LINEARBLEND)); } SEGMENT.blur(SEGMENT.custom2>>3); @@ -6206,12 +6207,12 @@ uint16_t mode_2Dsquaredswirl(void) { // By: Mark Kriegsman. https://g SEGMENT.blur(blurAmount); // Use two out-of-sync sine waves - uint8_t i = beatsin8(19, kBorderWidth, cols-kBorderWidth); - uint8_t j = beatsin8(22, kBorderWidth, cols-kBorderWidth); - uint8_t k = beatsin8(17, kBorderWidth, cols-kBorderWidth); - uint8_t m = beatsin8(18, kBorderWidth, rows-kBorderWidth); - uint8_t n = beatsin8(15, kBorderWidth, rows-kBorderWidth); - uint8_t p = beatsin8(20, kBorderWidth, rows-kBorderWidth); + uint8_t i = beatsin8_t(19, kBorderWidth, cols-kBorderWidth); + uint8_t j = beatsin8_t(22, kBorderWidth, cols-kBorderWidth); + uint8_t k = beatsin8_t(17, kBorderWidth, cols-kBorderWidth); + uint8_t m = beatsin8_t(18, kBorderWidth, rows-kBorderWidth); + uint8_t n = beatsin8_t(15, kBorderWidth, rows-kBorderWidth); + uint8_t p = beatsin8_t(20, kBorderWidth, rows-kBorderWidth); uint16_t ms = strip.now; @@ -6293,19 +6294,19 @@ uint16_t mode_2Dtartan(void) { // By: Elliott Kember https://editor.so uint8_t hue, bri; size_t intensity; - int offsetX = beatsin16(3, -360, 360); - int offsetY = beatsin16(2, -360, 360); + int offsetX = beatsin16_t(3, -360, 360); + int offsetY = beatsin16_t(2, -360, 360); int sharpness = SEGMENT.custom3 / 8; // 0-3 for (int x = 0; x < cols; x++) { for (int y = 0; y < rows; y++) { - hue = x * beatsin16(10, 1, 10) + offsetY; - intensity = bri = sin8(x * SEGMENT.speed/2 + offsetX); + hue = x * beatsin16_t(10, 1, 10) + offsetY; + intensity = bri = sin8_t(x * SEGMENT.speed/2 + offsetX); for (int i=0; i>= 8*sharpness; SEGMENT.setPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); hue = y * 3 + offsetX; - intensity = bri = sin8(y * SEGMENT.intensity/2 + offsetY); + intensity = bri = sin8_t(y * SEGMENT.intensity/2 + offsetY); for (int i=0; i>= 8*sharpness; SEGMENT.addPixelColorXY(x, y, ColorFromPalette(SEGPALETTE, hue, intensity, LINEARBLEND)); @@ -6345,9 +6346,9 @@ uint16_t mode_2Dspaceships(void) { //// Space ships by stepko (c)05.02.21 [ht SEGMENT.move(SEGENV.aux0, 1); for (size_t i = 0; i < 8; i++) { - byte x = beatsin8(12 + i, 2, cols - 3); - byte y = beatsin8(15 + i, 2, rows - 3); - CRGB color = ColorFromPalette(SEGPALETTE, beatsin8(12 + i, 0, 255), 255); + byte x = beatsin8_t(12 + i, 2, cols - 3); + byte y = beatsin8_t(15 + i, 2, rows - 3); + CRGB color = ColorFromPalette(SEGPALETTE, beatsin8_t(12 + i, 0, 255), 255); SEGMENT.addPixelColorXY(x, y, color); if (cols > 24 || rows > 24) { SEGMENT.addPixelColorXY(x+1, y, color); @@ -6772,8 +6773,8 @@ uint16_t mode_2Ddriftrose(void) { SEGMENT.fadeToBlackBy(32+(SEGMENT.speed>>3)); for (size_t i = 1; i < 37; i++) { float angle = float(DEG_TO_RAD) * i * 10; - uint32_t x = int((CX + (sinf(angle) * (beatsin8(i, 0, L2)-L))) * 255.f); - uint32_t y = int((CY + (cosf(angle) * (beatsin8(i, 0, L2)-L))) * 255.f); + uint32_t x = int((CX + (sinf(angle) * (beatsin8_t(i, 0, L2)-L))) * 255.f); + uint32_t y = int((CY + (cosf(angle) * (beatsin8_t(i, 0, L2)-L))) * 255.f); if ((x < wu_cols) && (y < wu_rows)) SEGMENT.wu_pixel(x, y, CHSV(i * 10, 255, 255)); } SEGMENT.blur((SEGMENT.intensity>>4)+1); @@ -6944,10 +6945,10 @@ uint16_t mode_2DSwirl(void) { SEGMENT.blur(SEGMENT.custom1); - unsigned i = beatsin8( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); - unsigned j = beatsin8( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); - unsigned ni = (cols - 1) - i; - unsigned nj = (cols - 1) - j; + int i = beatsin8_t( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); + int j = beatsin8_t( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); + int ni = (cols - 1) - i; + int nj = (cols - 1) - j; uint16_t ms = strip.now; um_data_t *um_data = getAudioData(); @@ -7214,7 +7215,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. for (size_t i=0; ithisphase += beatsin8(6,-4,4); // You can change direction and speed individually. - plasmoip->thatphase += beatsin8(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. + plasmoip->thisphase += beatsin8_t(6,-4,4); // You can change direction and speed individually. + plasmoip->thatphase += beatsin8_t(7,-4,4); // Two phase values to make a complex pattern. By Andrew Tuline. for (int i = 0; i < SEGLEN; i++) { // For each of the LED's in the strand, set a brightness based on a wave as follows. // updated, similar to "plasma" effect - softhack007 uint8_t thisbright = cubicwave8(((i*(1 + (3*SEGMENT.speed/32)))+plasmoip->thisphase) & 0xFF)/2; - thisbright += cos8(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. + thisbright += cos8_t(((i*(97 +(5*SEGMENT.speed/32)))+plasmoip->thatphase) & 0xFF)/2; // Let's munge the brightness a bit and animate it all with the phases. uint8_t colorIndex=thisbright; if (volumeSmth * SEGMENT.intensity / 64 < thisbright) {thisbright = 0;} @@ -8035,7 +8036,7 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac frTemp -=132; // This should give us a base musical note of C3 frTemp = fabsf(frTemp * 2.1f); // Fudge factors to compress octave range starting at 0 and going to 255; - uint16_t i = map(beatsin8(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); + uint16_t i = map(beatsin8_t(8+octCount*4, 0, 255, 0, octCount*8), 0, 255, 0, SEGLEN-1); // i will be always constrained between 0 and 0 if SEGLEN equals 1 i = constrain(i, 0, SEGLEN-1); SEGMENT.addPixelColor(i, color_blend(SEGCOLOR(1), SEGMENT.color_from_palette((uint8_t)frTemp, false, PALETTE_SOLID_WRAP, 0), volTemp)); @@ -8405,12 +8406,12 @@ uint16_t mode_2Ddistortionwaves() { uint16_t a2 = a/2; uint16_t a3 = a/3; - uint16_t cx = beatsin8(10-speed,0,cols-1)*scale; - uint16_t cy = beatsin8(12-speed,0,rows-1)*scale; - uint16_t cx1 = beatsin8(13-speed,0,cols-1)*scale; - uint16_t cy1 = beatsin8(15-speed,0,rows-1)*scale; - uint16_t cx2 = beatsin8(17-speed,0,cols-1)*scale; - uint16_t cy2 = beatsin8(14-speed,0,rows-1)*scale; + uint16_t cx = beatsin8_t(10-speed,0,cols-1)*scale; + uint16_t cy = beatsin8_t(12-speed,0,rows-1)*scale; + uint16_t cx1 = beatsin8_t(13-speed,0,cols-1)*scale; + uint16_t cy1 = beatsin8_t(15-speed,0,rows-1)*scale; + uint16_t cx2 = beatsin8_t(17-speed,0,cols-1)*scale; + uint16_t cy2 = beatsin8_t(14-speed,0,rows-1)*scale; uint16_t xoffs = 0; for (int x = 0; x < cols; x++) { @@ -8420,17 +8421,17 @@ uint16_t mode_2Ddistortionwaves() { for (int y = 0; y < rows; y++) { yoffs += scale; - byte rdistort = cos8((cos8(((x<<3)+a )&255)+cos8(((y<<3)-a2)&255)+a3 )&255)>>1; - byte gdistort = cos8((cos8(((x<<3)-a2)&255)+cos8(((y<<3)+a3)&255)+a+32 )&255)>>1; - byte bdistort = cos8((cos8(((x<<3)+a3)&255)+cos8(((y<<3)-a) &255)+a2+64)&255)>>1; + byte rdistort = cos8_t((cos8_t(((x<<3)+a )&255)+cos8_t(((y<<3)-a2)&255)+a3 )&255)>>1; + byte gdistort = cos8_t((cos8_t(((x<<3)-a2)&255)+cos8_t(((y<<3)+a3)&255)+a+32 )&255)>>1; + byte bdistort = cos8_t((cos8_t(((x<<3)+a3)&255)+cos8_t(((y<<3)-a) &255)+a2+64)&255)>>1; byte valueR = rdistort+ w* (a- ( ((xoffs - cx) * (xoffs - cx) + (yoffs - cy) * (yoffs - cy))>>7 )); byte valueG = gdistort+ w* (a2-( ((xoffs - cx1) * (xoffs - cx1) + (yoffs - cy1) * (yoffs - cy1))>>7 )); byte valueB = bdistort+ w* (a3-( ((xoffs - cx2) * (xoffs - cx2) + (yoffs - cy2) * (yoffs - cy2))>>7 )); - valueR = gamma8(cos8(valueR)); - valueG = gamma8(cos8(valueG)); - valueB = gamma8(cos8(valueB)); + valueR = gamma8(cos8_t(valueR)); + valueG = gamma8(cos8_t(valueG)); + valueB = gamma8(cos8_t(valueB)); SEGMENT.setPixelColorXY(x, y, RGBW32(valueR, valueG, valueB, 0)); } @@ -8622,8 +8623,11 @@ uint16_t mode_2Doctopus() { const uint16_t C_Y = rows / 2 + (SEGMENT.custom2 - 128)*rows/255; for (int x = xStart; x < xEnd; x++) { for (int y = yStart; y < yEnd; y++) { - rMap[XY(x, y)].angle = int(40.7436f * atan2f((y - C_Y), (x - C_X))); // avoid 128*atan2()/PI - rMap[XY(x, y)].radius = hypotf(x - C_X, y - C_Y) * mapp; //thanks Sutaburosu + int dx = (x - C_X); + int dy = (y - C_Y); + rMap[XY(x, y)].angle = int(40.7436f * atan2f(dy, dx)); // avoid 128*atan2()/PI + //rMap[XY(x, y)].radius = hypotf(x - C_X, y - C_Y) * mapp; //thanks Sutaburosu + rMap[XY(x, y)].radius = sqrtf(dx * dx + dy * dy) * mapp; //thanks Sutaburosu } } } @@ -8641,12 +8645,12 @@ uint16_t mode_2Doctopus() { for (int y = yStart; y < yEnd; y++) { byte angle = rMap[XY(x,y)].angle; byte radius = rMap[XY(x,y)].radius; - //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8(sin8((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); + //CRGB c = CHSV(SEGENV.step / 2 - radius, 255, sin8_t(sin8_t((angle * 4 - radius) / 4 + SEGENV.step) + radius - SEGENV.step * 2 + angle * (SEGMENT.custom3/3+1))); uint16_t intensity; if (SEGMENT.check3) - intensity = sin8(octoSpeed + sin8(octoSpeed - radius) + angle * (SEGMENT.custom3/4+1)); // RadialWave + intensity = sin8_t(octoSpeed + sin8_t(octoSpeed - radius) + angle * (SEGMENT.custom3/4+1)); // RadialWave else - intensity = sin8(sin8((angle * 4 - radius) / 4 + octoSpeed) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); // Octopus + intensity = sin8_t(sin8_t((angle * 4 - radius) / 4 + octoSpeed) + radius - SEGENV.step + angle * (SEGMENT.custom3/4+1)); // Octopus //intensity = map(intensity*intensity, 0, 65535, 0, 255); // add a bit of non-linearity for cleaner display intensity = (intensity * intensity) / 255; // WLEDMM same as above, but faster and a bit more accurate CRGB c = ColorFromPalette(SEGPALETTE, colorSpeed - radius, intensity); @@ -8671,7 +8675,7 @@ uint16_t mode_2Dwavingcell() { uint8_t aY = SEGMENT.custom2/16 + 1; uint8_t aZ = SEGMENT.custom3 + 1; for (int x = 0; x < cols; x++) for (int y = 0; y T atan_t(T x); - float cos_t(float phi) __attribute__((const)); - float sin_t(float x) __attribute__((const)); - float tan_t(float x) __attribute__((const)); - float acos_t(float x); - float asin_t(float x); - float atan_t(float x) __attribute__((const)); - float floor_t(float x) __attribute__((const)); - float fmod_t(float num, float denom) __attribute__((const)); -#else - #include // WLEDMM use "float" variants - #define sin_t sinf - #define cos_t cosf - #define tan_t tanf - #define asin_t asinf - #define acos_t acosf - #define atan_t atanf - #define fmod_t fmodf - #define floor_t floorf -#endif +//float cos_t(float phi); // use float math +//float sin_t(float phi); +//float tan_t(float x); +int16_t sin16_t(uint16_t theta); +int16_t cos16_t(uint16_t theta); +uint8_t sin8_t(uint8_t theta); +uint8_t cos8_t(uint8_t theta); + +float sin_approx(float theta); // uses integer math (converted to float), accuracy +/-0.0015 (compared to sinf()) +float cos_approx(float theta); +float tan_approx(float x); +//float atan2_t(float y, float x); +//float acos_t(float x); +//float asin_t(float x); +//template T atan_t(T x); +//float floor_t(float x); +//float fmod_t(float num, float denom); +#define sin_t sin_approx +#define cos_t cos_approx +#define tan_t tan_approx + +#include // standard math functions. use a lot of flash +#define atan2_t atan2f +#define asin_t asinf +#define acos_t acosf +#define atan_t atanf +#define fmod_t fmodf +#define floor_t floorf +/* +#define sin_t sinf +#define cos_t cosf +#define tan_t tanf +*/ //wled_serial.cpp void handleSerial(); diff --git a/wled00/util.cpp b/wled00/util.cpp index 87e14c2c99..3b380ce8cb 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -423,6 +423,39 @@ uint16_t crc16(const unsigned char* data_p, size_t length) { return crc; } +// fastled beatsin: 1:1 replacements to remove the use of fastled sin16() +// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint16_t beatsin88_t(accum88 beats_per_minute_88, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset) +{ + uint16_t beat = beat88( beats_per_minute_88, timebase); + uint16_t beatsin (sin16_t( beat + phase_offset) + 32768); + uint16_t rangewidth = highest - lowest; + uint16_t scaledbeat = scale16( beatsin, rangewidth); + uint16_t result = lowest + scaledbeat; + return result; +} + +// Generates a 16-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint16_t beatsin16_t(accum88 beats_per_minute, uint16_t lowest, uint16_t highest, uint32_t timebase, uint16_t phase_offset) +{ + uint16_t beat = beat16( beats_per_minute, timebase); + uint16_t beatsin = (sin16_t( beat + phase_offset) + 32768); + uint16_t rangewidth = highest - lowest; + uint16_t scaledbeat = scale16( beatsin, rangewidth); + uint16_t result = lowest + scaledbeat; + return result; +} + +// Generates an 8-bit sine wave at a given BPM that oscillates within a given range. see fastled for details. +uint8_t beatsin8_t(accum88 beats_per_minute, uint8_t lowest, uint8_t highest, uint32_t timebase, uint8_t phase_offset) +{ + uint8_t beat = beat8( beats_per_minute, timebase); + uint8_t beatsin = sin8_t( beat + phase_offset); + uint8_t rangewidth = highest - lowest; + uint8_t scaledbeat = scale8( beatsin, rangewidth); + uint8_t result = lowest + scaledbeat; + return result; +} /////////////////////////////////////////////////////////////////////////////// // Begin simulateSound (to enable audio enhanced effects to display something) @@ -487,8 +520,8 @@ um_data_t* simulateSound(uint8_t simulationId) default: case UMS_BeatSin: for (int i = 0; i<16; i++) - fftResult[i] = beatsin8(120 / (i+1), 0, 255); - // fftResult[i] = (beatsin8(120, 0, 255) + (256/16 * i)) % 256; + fftResult[i] = beatsin8_t(120 / (i+1), 0, 255); + // fftResult[i] = (beatsin8_t(120, 0, 255) + (256/16 * i)) % 256; volumeSmth = fftResult[8]; break; case UMS_WeWillRockYou: @@ -525,12 +558,12 @@ um_data_t* simulateSound(uint8_t simulationId) break; case UMS_10_13: for (int i = 0; i<16; i++) - fftResult[i] = inoise8(beatsin8(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3); + fftResult[i] = inoise8(beatsin8_t(90 / (i+1), 0, 200)*15 + (ms>>10), ms>>3); volumeSmth = fftResult[8]; break; case UMS_14_3: for (int i = 0; i<16; i++) - fftResult[i] = inoise8(beatsin8(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3); + fftResult[i] = inoise8(beatsin8_t(120 / (i+1), 10, 30)*10 + (ms>>14), ms>>3); volumeSmth = fftResult[8]; break; } diff --git a/wled00/wled_math.cpp b/wled00/wled_math.cpp index a4c9fc123c..bd5423389a 100644 --- a/wled00/wled_math.cpp +++ b/wled00/wled_math.cpp @@ -10,16 +10,25 @@ //#define WLED_DEBUG_MATH +// Note: cos_t, sin_t and tan_t are very accurate but slow +// the math.h functions use several kB of flash and are to be avoided if possible +// sin16_t / cos16_t are faster and much more accurate than the fastled variants +// sin_approx and cos_approx are float wrappers for sin16_t/cos16_t and have an accuracy better than +/-0.0015 compared to sinf() +// sin8_t / cos8_t are fastled replacements and use sin16_t / cos16_t. Slightly slower than fastled version but very accurate + + +// Taylor series approximations, replaced with Bhaskara I's approximation +/* #define modd(x, y) ((x) - (int)((x) / (y)) * (y)) float cos_t(float phi) { - float x = modd(phi, TWO_PI); + float x = modd(phi, M_TWOPI); if (x < 0) x = -1 * x; int8_t sign = 1; - if (x > PI) + if (x > M_PI) { - x -= PI; + x -= M_PI; sign = -1; } float xx = x * x; @@ -31,8 +40,8 @@ float cos_t(float phi) return res; } -float sin_t(float x) { - float res = cos_t(HALF_PI - x); +float sin_t(float phi) { + float res = cos_t(M_PI_2 - phi); #ifdef WLED_DEBUG_MATH Serial.printf("sin: %f,%f,%f,(%f)\n",x,res,sin(x),res-sin(x)); #endif @@ -48,6 +57,81 @@ float tan_t(float x) { #endif return res; } +*/ + +// 16-bit, integer based Bhaskara I's sine approximation: 16*x*(pi - x) / (5*pi^2 - 4*x*(pi - x)) +// input is 16bit unsigned (0-65535), output is 16bit signed (-32767 to +32767) +// optimized integer implementation by @dedehai +int16_t sin16_t(uint16_t theta) { + int scale = 1; + if (theta > 0x7FFF) { + theta = 0xFFFF - theta; + scale = -1; // second half of the sine function is negative (pi - 2*pi) + } + uint32_t precal = theta * (0x7FFF - theta); + uint64_t numerator = (uint64_t)precal * (4 * 0x7FFF); // 64bit required + int32_t denominator = 1342095361 - precal; // 1342095361 is 5 * 0x7FFF^2 / 4 + int16_t result = numerator / denominator; + return result * scale; +} + +int16_t cos16_t(uint16_t theta) { + return sin16_t(theta + 0x4000); //cos(x) = sin(x+pi/2) +} + +uint8_t sin8_t(uint8_t theta) { + int32_t sin16 = sin16_t((uint16_t)theta * 257); // 255 * 257 = 0xFFFF + sin16 += 0x7FFF + 128; //shift result to range 0-0xFFFF, +128 for rounding + return min(sin16, int32_t(0xFFFF)) >> 8; // min performs saturation, and prevents overflow +} + +uint8_t cos8_t(uint8_t theta) { + return sin8_t(theta + 64); //cos(x) = sin(x+pi/2) +} + +float sin_approx(float theta) { + uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) + int32_t result = sin16_t(scaled_theta); + float sin = float(result) / 0x7FFF; + return sin; +} + +float cos_approx(float theta) { + uint16_t scaled_theta = (int)(theta * (float)(0xFFFF / M_TWOPI)); // note: do not cast negative float to uint! cast to int first (undefined on C3) + int32_t result = sin16_t(scaled_theta + 0x4000); + float cos = float(result) / 0x7FFF; + return cos; +} + +float tan_approx(float x) { + float c = cos_approx(x); + if (c==0.0f) return 0; + float res = sin_approx(x) / c; + return res; +} + +#if 0 // WLEDMM we prefer libm functions that are accurate and fast. +#define ATAN2_CONST_A 0.1963f +#define ATAN2_CONST_B 0.9817f + +// atan2_t approximation, with the idea from https://gist.github.com/volkansalma/2972237?permalink_comment_id=3872525#gistcomment-3872525 +float atan2_t(float y, float x) { + float abs_y = fabs(y); + float abs_x = fabs(x); + float r = (abs_x - abs_y) / (abs_y + abs_x + 1e-10f); // avoid division by zero by adding a small nubmer + float angle; + if(x < 0) { + r = -r; + angle = M_PI_2 + M_PI_4; + } + else + angle = M_PI_2 - M_PI_4; + + float add = (ATAN2_CONST_A * (r * r) - ATAN2_CONST_B) * r; + angle += add; + angle = y < 0 ? -angle : angle; + return angle; +} //https://stackoverflow.com/questions/3380628 // Absolute error <= 6.7e-5 @@ -60,10 +144,10 @@ float acos_t(float x) { ret = ret * xabs; ret = ret - 0.2121144f; ret = ret * xabs; - ret = ret + HALF_PI; + ret = ret + M_PI_2; ret = ret * sqrt(1.0f-xabs); ret = ret - 2 * negate * ret; - float res = negate * PI + ret; + float res = negate * M_PI + ret; #ifdef WLED_DEBUG_MATH Serial.printf("acos: %f,%f,%f,(%f)\n",x,res,acos(x),res-acos(x)); #endif @@ -71,7 +155,7 @@ float acos_t(float x) { } float asin_t(float x) { - float res = HALF_PI - acos_t(x); + float res = M_PI_2 - acos_t(x); #ifdef WLED_DEBUG_MATH Serial.printf("asin: %f,%f,%f,(%f)\n",x,res,asin(x),res-asin(x)); #endif @@ -87,7 +171,7 @@ float atan_t(float x) { //For A/B/C, see https://stackoverflow.com/a/42542593 static const double A { 0.0776509570923569 }; static const double B { -0.287434475393028 }; - static const double C { ((HALF_PI/2) - A - B) }; + static const double C { ((M_PI_4) - A - B) }; // polynominal factors for approximation between 1 and 5 static const float C0 { 0.089494f }; static const float C1 { 0.974207f }; @@ -102,7 +186,7 @@ float atan_t(float x) { x = std::abs(x); float res; if (x > 5.0f) { // atan(x) converges to pi/2 - (1/x) for large values - res = HALF_PI - (1.0f/x); + res = M_PI_2 - (1.0f/x); } else if (x > 1.0f) { //1 < x < 5 float xx = x * x; res = (C4*xx*xx)+(C3*xx*x)+(C2*xx)+(C1*x)+C0; @@ -137,3 +221,5 @@ float fmod_t(float num, float denom) { #endif return res; } + +#endif // WLEDMM \ No newline at end of file From 6c87799ce5cf66bd33ebc03861f55233e8bc2e04 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:48:27 +0100 Subject: [PATCH 23/39] post merge --- wled00/FX.cpp | 8 ++++---- wled00/wled.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index d89108ed58..9186866fb9 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -6945,10 +6945,10 @@ uint16_t mode_2DSwirl(void) { SEGMENT.blur(SEGMENT.custom1); - int i = beatsin8_t( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); - int j = beatsin8_t( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); - int ni = (cols - 1) - i; - int nj = (cols - 1) - j; + unsigned i = beatsin8_t( 27*SEGMENT.speed/255, borderWidth, cols - borderWidth); + unsigned j = beatsin8_t( 41*SEGMENT.speed/255, borderWidth, rows - borderWidth); + unsigned ni = (cols - 1) - i; + unsigned nj = (cols - 1) - j; uint16_t ms = strip.now; um_data_t *um_data = getAudioData(); diff --git a/wled00/wled.h b/wled00/wled.h index fe1761a2d2..2811036532 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2411271 +#define VERSION 2411290 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ From b2364bf4a5b3310720f26300470ec8dc74d1acb8 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 29 Nov 2024 11:56:35 +0100 Subject: [PATCH 24/39] chunchun effect bugfixes (for strips >256 pixels) * avoid 16bit overflows * improve time resolution * limit to 32 birds (=max for 256 pixels) * fix fade_out --- wled00/FX.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 9186866fb9..238ce0ac33 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4377,20 +4377,20 @@ static const char _data_FX_MODE_FLOW[] PROGMEM = "Flow@!,Zones;;!;;m12=1"; //ver */ uint16_t mode_chunchun(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); if (SEGENV.call == 0) {SEGENV.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM use lossless getPixelColor() - SEGMENT.fade_out(254); // add a bit of trail - uint16_t counter = strip.now * (6 + (SEGMENT.speed >> 4)); - uint16_t numBirds = 2 + (SEGLEN >> 3); // 2 + 1/8 of a segment - uint16_t span = (SEGMENT.intensity << 8) / numBirds; + SEGMENT.fade_out(253); // add a bit of trail // WLEDMM fade rate above 253 has no effect + uint32_t counter = ((strip.now * (96 + SEGMENT.speed)) >> 4); // WLEDMM same result, better resolution + uint16_t numBirds = min(32, 2 + (SEGLEN >> 3)); // 2 + 1/8 of a segment - WLEDMM max 32 + uint32_t span = (SEGMENT.intensity << 8) / numBirds; - for (int i = 0; i < numBirds; i++) + for (unsigned i = 0; i < numBirds; i++) { counter -= span; uint16_t megumin = sin16_t(counter) + 0x8000; uint16_t bird = uint32_t(megumin * SEGLEN) >> 16; uint32_t c = SEGMENT.color_from_palette((i * 255)/ numBirds, false, false, 0); // no palette wrapping - bird = constrain(bird, 0, SEGLEN-1); + bird = min(bird, uint16_t(SEGLEN-1)); // WLEDMM unsigned is always >= 0 SEGMENT.setPixelColor(bird, c); } return FRAMETIME; From b0b6ec37fd795e1288dd6924cd0f548e744db63a Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:05:47 +0100 Subject: [PATCH 25/39] support for benchmarking FastLed vs. WLED triginometry --- wled00/FX.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 238ce0ac33..01314346a1 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -25,6 +25,16 @@ #define indexToVStrip(index, stripNr) ((index) | (int((stripNr)+1)<<16)) +#if 0 // for benchmarking - change to "#if 1" to use less accurate, but 30% faster FastLed sin8 and cos8 functions +#define sin8_t sin8 +#define cos8_t cos8 +#define sin16_t sin16 +#define cos16_t cos16 +#define beatsin8_t beatsin8 +#define beatsin88_t beatsin88 +#define beatsin16_t beatsin16 +#endif + // WLEDMM replace abs8 by abs, as abs8 does not work for numbers >127 #define abs8(x) abs(x) From 9ff235e1538cd1fbd984a3fe5112e9356fe10bd1 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Fri, 29 Nov 2024 18:29:28 +0100 Subject: [PATCH 26/39] Show "NO PSRAM" on info page ... to help diagnose problems that come from wrong PSRAM settings --- wled00/data/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index 86e6465bdd..7dced6a4a3 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -717,7 +717,7 @@ ${i.psram?inforow("PSRAM ☾",((i.tpram-i.psram)/1024).toFixed(0)+"/"+(i.tpram/1 ${i.psusedram?inforow("Max used PSRAM ☾",((i.tpram-i.psusedram)/1024).toFixed(0)+" kB",", "+((i.tpram-i.psusedram)*100.0/i.tpram).toFixed(1)+"%"):""} ${i.freestack?inforow("Free stack ☾",(i.freestack/1000).toFixed(3)," kB"):""} -${i.tpram?inforow("PSRAM " + (i.psrmode?"("+i.psrmode+" mode) ":"") + " ☾",(i.tpram/1024/1024).toFixed(0)," MB"):""} +${i.tpram?inforow("PSRAM " + (i.psrmode?"("+i.psrmode+" mode) ":"") + " ☾",(i.tpram/1024/1024).toFixed(0)," MB"):inforow("NO PSRAM found.", "")} ${i.e32flash?inforow("Flash mode "+i.e32flashmode+i.e32flashtext + " ☾",i.e32flash+" MB, "+i.e32flashspeed," Mhz"):""} ${i.e32model?inforow(i.e32model + " ☾",i.e32cores +" core(s),"," "+i.e32speed+" Mhz"):""} ${inforow("Environment",i.arch + " " + i.core + " (" + i.lwip + ")")} From a0e03766ef7cc12c42d3116ed3ad98a008f20fe0 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Sun, 1 Dec 2024 20:02:44 +0100 Subject: [PATCH 27/39] blends effect bugfix quick fix for "missing pixel 256" problem --- wled00/FX.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 01314346a1..f44db9da23 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4596,7 +4596,7 @@ uint16_t mode_blends(void) { uint16_t offset = 0; for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, pixels[offset++]); - if (offset > pixelLen) offset = 0; + if (offset >= pixelLen) offset = 0; } return FRAMETIME; From 994a9e7212189c6b8cb37224ddd708434325e114 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Mon, 2 Dec 2024 09:15:21 -0500 Subject: [PATCH 28/39] Fix Color Order GUI for Art-Net --- wled00/data/settings_leds.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wled00/data/settings_leds.htm b/wled00/data/settings_leds.htm index 62af94b7b7..375cfa39d5 100644 --- a/wled00/data/settings_leds.htm +++ b/wled00/data/settings_leds.htm @@ -222,7 +222,7 @@ } gId("rf"+n).onclick = (t == 31) ? (()=>{return false}) : (()=>{}); // prevent change for TM1814 gRGBW |= isRGBW = ((t > 17 && t < 22) || (t > 28 && t < 32) || (t > 40 && t < 46 && t != 43) || t == 88); // RGBW checkbox, TYPE_xxxx values from const.h - gId("co"+n).style.display = ((t >= 80 && t < 96) || (t >= 40 && t < 48)||(t >= 100 && t < 110)) ? "none":"inline"; // hide color order for PWM + gId("co"+n).style.display = ((t >= 83 && t < 96) || (t >= 40 && t < 48)||(t >= 100 && t < 110)) ? "none":"inline"; // hide color order for PWM gId("dig"+n+"w").style.display = (t > 28 && t < 32) ? "inline":"none"; // show swap channels dropdown gId("dig"+n+"O").style.display = (t == 82 || t == 83) ? "inline":"none"; // show Art-Net output number gId("dig"+n+"L").style.display = (t == 82 || t == 83) ? "inline":"none"; // show Art-Net LEDs per output From f2f621befcc493cad6e7058a3e6d8d8ee9b9f7df Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Dec 2024 12:48:11 +0100 Subject: [PATCH 29/39] minor FX improvements Fire2012: better randomness Julia: avoid darkening when using "blur" --- wled00/FX.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f44db9da23..c3a5c59564 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2128,12 +2128,16 @@ uint16_t mode_fire_2012() { const uint8_t ignition = max(3,SEGLEN/10); // ignition area: 10% of segment length or minimum 3 pixels + #if defined(ARDUINO_ARCH_ESP32) + random16_add_entropy(esp_random() & 0xFFFF); // improves randonmess + #endif + // Step 1. Cool down every cell a little for (int i = 0; i < SEGLEN; i++) { uint8_t cool = (it != SEGENV.step) ? random8((((20 + SEGMENT.speed/3) * 16) / SEGLEN)+2) : random8(4); uint8_t minTemp = (ixcen = 0.; julias->ycen = 0.; julias->xymag = 1.0; From 0dbde5a257999e85925d08aa46fc3c01e2cbb809 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:06:47 +0100 Subject: [PATCH 30/39] audioreactive multi-comet (backported from WELD-SR 0.13.4) --- wled00/FX.cpp | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 2 +- 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index c3a5c59564..0f7c7526db 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -1794,6 +1794,61 @@ uint16_t mode_multi_comet(void) { } static const char _data_FX_MODE_MULTI_COMET[] PROGMEM = "Multi Comet"; +// audioreactive multi-comet by @softhack007 +uint16_t mode_multi_comet_ar(void) { + constexpr unsigned MAX_COMETS = 16; // was 8 + uint32_t cycleTime = max(1, int((255 - SEGMENT.speed)/4)); + uint32_t it = strip.now / cycleTime; + if (SEGENV.step == it) return FRAMETIME; // too early + + if (!SEGENV.allocateData(sizeof(uint16_t) * MAX_COMETS)) return mode_static(); //allocation failed + uint16_t* comets = reinterpret_cast(SEGENV.data); + if (SEGENV.call == 0) { // do some initializations + SEGMENT.setUpLeds(); SEGMENT.fill(BLACK); + for(uint8_t i=0; i < MAX_COMETS; i++) comets[i] = SEGLEN; // WLEDMM make sure comments are started individually + SEGENV.aux0 = 0; + } + SEGMENT.fade_out(254 - SEGMENT.intensity/2); + + um_data_t *um_data; + if (!usermods.getUMData(&um_data, USERMOD_ID_AUDIOREACTIVE)) um_data = simulateSound(SEGMENT.soundSim); + float volumeSmth = *(float*) um_data->u_data[0]; + int16_t volumeRaw = *(int16_t*) um_data->u_data[1]; + uint8_t samplePeak = *(uint8_t*) um_data->u_data[3]; + + uint16_t armed = SEGENV.aux0; // allows to delay comet launch + + #if defined(ARDUINO_ARCH_ESP32) + random16_add_entropy(esp_random() & 0xFFFF); // improve randomness (esp32) + #endif + bool shotOne = false; // avoids starting several coments at the same time (invisible due to overlap) + for(unsigned i=0; i < MAX_COMETS; i++) { + if(comets[i] < SEGLEN) { + // draw comet + uint16_t index = comets[i]; + if (SEGCOLOR(2) != 0) + SEGMENT.setPixelColor(index, i % 2 ? SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0) : SEGCOLOR(2)); + else + SEGMENT.setPixelColor(index, SEGMENT.color_from_palette(index, true, PALETTE_SOLID_WRAP, 0)); + comets[i]++; // move + } else { + // randomly launch a new comet + if (random16(min(uint16_t(256), SEGLEN)) < 3) armed++; // new comet loaded and ready + if (armed > 2) armed = 2; // max three armed at once (avoid overlap) + // delay comet "launch" during silence, and wait until next beat + if ( (armed > 0) && (shotOne == false) + && (volumeSmth > 1.0f) && ((samplePeak > 0) || (volumeRaw > 104)) ) { // delayed lauch - wait until peak, don't launch in silence + comets[i] = 0; // start a new comet! + armed--; // un-arm one + shotOne = true; + } + } + } + SEGENV.aux0 = armed; + SEGENV.step = it; + return FRAMETIME; +} +static const char _data_FX_MODE_MULTI_COMET_AR[] PROGMEM = "Multi Comet audio ☾@Speed,Tail Length;!,!;!;1v;sx=160,ix=32,m12=7,si=1"; // Pinwheel, WeWillRockU /* * Running random pixels ("Stream 2") @@ -9017,6 +9072,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_LIGHTNING, &mode_lightning, _data_FX_MODE_LIGHTNING); addEffect(FX_MODE_ICU, &mode_icu, _data_FX_MODE_ICU); addEffect(FX_MODE_MULTI_COMET, &mode_multi_comet, _data_FX_MODE_MULTI_COMET); + addEffect(FX_MODE_MULTI_COMET_AR, &mode_multi_comet_ar, _data_FX_MODE_MULTI_COMET_AR); addEffect(FX_MODE_DUAL_LARSON_SCANNER, &mode_dual_larson_scanner, _data_FX_MODE_DUAL_LARSON_SCANNER); addEffect(FX_MODE_RANDOM_CHASE, &mode_random_chase, _data_FX_MODE_RANDOM_CHASE); addEffect(FX_MODE_OSCILLATE, &mode_oscillate, _data_FX_MODE_OSCILLATE); diff --git a/wled00/FX.h b/wled00/FX.h index beba051747..670c321a74 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -330,7 +330,7 @@ bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented // Experimental Audioresponsive modes from WLED-SR // #define FX_MODE_3DSphereMove 189 // experimental WLED-SR "cube" mode #define FX_MODE_POPCORN_AR 190 // WLED-SR audioreactive popcorn -// #define FX_MODE_MULTI_COMET_AR 191 // WLED-SR audioreactive multi-comet +#define FX_MODE_MULTI_COMET_AR 191 // WLED-SR audioreactive multi-comet #define FX_MODE_STARBURST_AR 192 // WLED-SR audioreactive fireworks starburst // #define FX_MODE_PALETTE_AR 193 // WLED-SR audioreactive palette #define FX_MODE_FIREWORKS_AR 194 // WLED-SR audioreactive fireworks From 9922d2aa8d01373a64b96a8685a0be14d264c4f2 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:44:46 +0100 Subject: [PATCH 31/39] bugfix: don't render segments that are "off" --- wled00/FX_fcn.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 0f750b0f03..a450dca76e 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1913,6 +1913,7 @@ void WS2812FX::service() { seg.resetIfRequired(); if (!seg.isActive()) continue; + if (!seg.on && !seg.transitional) continue; // WLEDMM skip disabled segments, unless a crossfade is ongoing // last condition ensures all solid segments are updated at the same time if(nowUp >= seg.next_time || _triggered || (doShow && seg.mode == FX_MODE_STATIC)) // WLEDMM ">=" instead of ">" From 23d41e66c94e5f111e6dec44e3ed731171c964d2 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:04:21 +0100 Subject: [PATCH 32/39] bugfix #2 for switched-off segments segments that are "off" were still rendered during transitions. --- wled00/FX.h | 2 ++ wled00/FX_fcn.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/wled00/FX.h b/wled00/FX.h index 670c321a74..c35c54fb87 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -380,6 +380,7 @@ typedef struct Segment { }; uint8_t grouping, spacing; uint8_t opacity; + uint8_t lastBri; // WLEDMM optimization for black-to-black "transitions" bool needsBlank; // WLEDMM indicates that Segment needs to be blanked (due to change of mirror / reverse / transpose / spacing) uint32_t colors[NUM_COLORS]; uint8_t cct; //0==1900K, 255==10091K @@ -490,6 +491,7 @@ typedef struct Segment { grouping(1), spacing(0), opacity(255), + lastBri(255), needsBlank(false), colors{DEFAULT_COLOR,BLACK,BLACK}, cct(127), diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a450dca76e..b2d7162f19 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1935,6 +1935,7 @@ void WS2812FX::service() { now = millis() + timebase; #endif seg.startFrame(); // WLEDMM + if (!_triggered && (seg.currentBri(seg.opacity) == 0) && (seg.lastBri == 0)) continue; // WLEDMM skip totally black segments // effect blending (execute previous effect) // actual code may be a bit more involved as effects have runtime data including allocated memory //if (seg.transitional && seg._modeP) (*_mode[seg._modeP])(progress()); @@ -1944,6 +1945,7 @@ void WS2812FX::service() { if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++; if (seg.transitional && frameDelay > FRAMETIME) frameDelay = FRAMETIME; // force faster updates during transition + seg.lastBri = seg.currentBri(seg.on ? seg.opacity:0); // WLEDMM remember for next time seg.handleTransition(); } From 86ed5a82e3d03df1e2a40af3110cb6935428c880 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:31:52 +0100 Subject: [PATCH 33/39] DNA effect: additional parameter "phases" (thanks @ewoudwijma ) controls the number of phases shown by the effect breaking - the old code was using a fixed width per wave, while the new one always fits the same number waves into the panel width. --- wled00/FX.cpp | 12 +++++++++--- wled00/wled.h | 2 +- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 0f7c7526db..f255fa5ada 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5124,6 +5124,7 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); + uint8_t phases = SEGMENT.custom1; if (SEGENV.call == 0) { SEGMENT.setUpLeds(); @@ -5136,8 +5137,13 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa int lastY1 = -1; int lastY2 = -1; for (int i = 0; i < cols; i++) { - int posY1 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ); - int posY2 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128); + // int posY1 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ); + ///int posY2 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128); + unsigned phase = cols * i / 8; // 256 is a complete phase; half a phase is dna is 128 + phase = i * 4 * phases / cols; // cols ==0 cannot happen due to the for loop + int posY1 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, phase ); + int posY2 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, phase+128); + if ((i==0) || ((abs(lastY1 - posY1) < 2) && (abs(lastY2 - posY2) < 2))) { // use original code when no holes SEGMENT.setPixelColorXY(i, posY1, ColorFromPalette(SEGPALETTE, i*5+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10), LINEARBLEND)); SEGMENT.setPixelColorXY(i, posY2, ColorFromPalette(SEGPALETTE, i*5+128+strip.now/17, beatsin8_t(5, 55, 255, 0, i*10+128), LINEARBLEND)); @@ -5152,7 +5158,7 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa return FRAMETIME; } // mode_2Ddna() -static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur;;!;2"; +static const char _data_FX_MODE_2DDNA[] PROGMEM = "DNA@Scroll speed,Blur,Phases;;!;2"; ///////////////////////// diff --git a/wled00/wled.h b/wled00/wled.h index 2811036532..7af6b43c3b 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -8,7 +8,7 @@ */ // version code in format yymmddb (b = daily build) -#define VERSION 2411290 +#define VERSION 2412030 // WLEDMM - you can check for this define in usermods, to only enabled WLEDMM specific code in the "right" fork. Its not defined in AC WLED. #define _MoonModules_WLED_ From 9ea2303ecbfc8a0bd5ebe3c8ada6b6c903756846 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Dec 2024 20:00:26 +0100 Subject: [PATCH 34/39] DNA effect optimization (phases) * non-breaking - reproduces the old behavior at phases = 127 * minor math optimizations * phase boost for large values (good for small panels) --- wled00/FX.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f255fa5ada..53d99886ee 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -5119,12 +5119,13 @@ static const char _data_FX_MODE_2DCOLOREDBURSTS[] PROGMEM = "Colored Bursts@Spee ///////////////////// // 2D DNA // ///////////////////// -uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pastebin.com/pCkkkzcs. Updated by Preyy. WLED conversion by Andrew Tuline. +uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pastebin.com/pCkkkzcs. Updated by Preyy. WLED conversion by Andrew Tuline. Phases added by @ewoudwijma if (!strip.isMatrix) return mode_static(); // not a 2D set-up const uint16_t cols = SEGMENT.virtualWidth(); const uint16_t rows = SEGMENT.virtualHeight(); - uint8_t phases = SEGMENT.custom1; + unsigned phases = SEGMENT.custom1; + if (phases > 179) phases = 179 + 2.5f * (phases - 179); // boost for values > 179 if (SEGENV.call == 0) { SEGMENT.setUpLeds(); @@ -5137,10 +5138,9 @@ uint16_t mode_2Ddna(void) { // dna originally by by ldirko at https://pa int lastY1 = -1; int lastY2 = -1; for (int i = 0; i < cols; i++) { - // int posY1 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4 ); - ///int posY2 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, i*4+128); - unsigned phase = cols * i / 8; // 256 is a complete phase; half a phase is dna is 128 - phase = i * 4 * phases / cols; // cols ==0 cannot happen due to the for loop + // 256 is a complete phase; half a phase of dna is 128 + // unsigned phase = i * 4 * phases / cols; // original formula; cols ==0 cannot happen due to the for loop + unsigned phase = i * 4 * phases / 128; // WLEDMM this reproduces the previous behaviour at phases=127 int posY1 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, phase ); int posY2 = beatsin8_t(SEGMENT.speed/8, 0, rows-1, 0, phase+128); From f4ac04b9f981659fc539e522d49b03e80b4554c4 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Tue, 3 Dec 2024 22:48:35 +0100 Subject: [PATCH 35/39] Update platformio.ini - fix for duplicate WLED_RELEASE_NAMEs esp32S3_4MB_S and esp32s3_8MB_M were used by two different buildenvs. --- platformio.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index e49c32dabd..b1ce10e269 100644 --- a/platformio.ini +++ b/platformio.ini @@ -2164,7 +2164,7 @@ board_build.partitions = tools/WLED_ESP32_4MB_256KB_FS.csv ;; 1.8MB firmware, ;; board_build.partitions = tools/WLED_ESP32_4MB_512KB_FS.csv ;; 1.7MB firmware, 500KB filesystem (esptool erase_flash needed when changing from "standard WLED" partitions) build_flags = ${common.build_flags} ${esp32s3.build_flags} -Wno-misleading-indentation -Wno-format-truncation ${common_mm.build_flags_S} - -D WLED_RELEASE_NAME=esp32S3_4MB_S + -D WLED_RELEASE_NAME=esp32S3_4MB_PSRAM_S -DBOARD_HAS_PSRAM ;; -D WLED_USE_PSRAM -D WLED_USE_PSRAM_JSON -DALL_JSON_TO_PSRAM ; WLEDMM --> force all JSON stuff into PSRAM; gives more free heap -DCONFIG_MBEDTLS_DYNAMIC_BUFFER=1 ;; optional - allows some buffers to use PSRAM @@ -2202,7 +2202,7 @@ board = lolin_s3_mini ;; -S3 mini: 4MB flash 2MB PSRAM board_build.partitions = ${esp32.default_partitions} build_flags = ${common.build_flags} ${esp32s3.build_flags} -Wno-misleading-indentation -Wno-format-truncation ${common_mm.build_flags_S} ${common_mm.build_flags_M} - -D WLED_RELEASE_NAME=esp32S3_4MB_M + -D WLED_RELEASE_NAME=esp32S3_4MB_PSRAM_M -DBOARD_HAS_PSRAM ;; -D WLED_USE_PSRAM -D WLED_USE_PSRAM_JSON -DALL_JSON_TO_PSRAM ; WLEDMM --> force all JSON stuff into PSRAM; gives more free heap -DCONFIG_MBEDTLS_DYNAMIC_BUFFER=1 ;; optional - allows some buffers to use PSRAM From 6763ca1f682b4478351258d8512abafe430ebf09 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:53:01 -0500 Subject: [PATCH 36/39] Cosmetic 2D Setup change: Start at Panel 1 instead of 0 --- wled00/data/settings_2D.htm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/data/settings_2D.htm b/wled00/data/settings_2D.htm index c57bf3d9ec..85f9dddb6f 100644 --- a/wled00/data/settings_2D.htm +++ b/wled00/data/settings_2D.htm @@ -98,7 +98,7 @@ var pw = parseInt(d.Sf.PW.value); var ph = parseInt(d.Sf.PH.value); //WLEDMM: change name to id - let b = `Panel ${i} + let b = `Panel ${i+1} 1st LED: Top Bottom @@ -334,7 +334,7 @@ ctx.font = '40px Arial'; ctx.fillStyle = "orange"; - ctx.fillText(p, topLeftX + pw/2*ppL - 10, topLeftY + ph/2*ppL + 10); + ctx.fillText(p+1, topLeftX + pw/2*ppL - 10, topLeftY + ph/2*ppL + 10); } gId("MD").innerHTML = "Matrix Dimensions (W*H=LC): " + maxWidth + " x " + maxHeight + " = " + maxWidth * maxHeight; } From e5b22bc8d190c7f0806d3d3e3c4ec70f012bdd80 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 4 Dec 2024 10:53:01 -0500 Subject: [PATCH 37/39] Cosmetic 2D Setup change: Start at Panel 1 instead of 0 --- wled00/data/settings_2D.htm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/data/settings_2D.htm b/wled00/data/settings_2D.htm index c57bf3d9ec..85f9dddb6f 100644 --- a/wled00/data/settings_2D.htm +++ b/wled00/data/settings_2D.htm @@ -98,7 +98,7 @@ var pw = parseInt(d.Sf.PW.value); var ph = parseInt(d.Sf.PH.value); //WLEDMM: change name to id - let b = `Panel ${i} + let b = `Panel ${i+1} 1st LED: Top Bottom @@ -334,7 +334,7 @@ ctx.font = '40px Arial'; ctx.fillStyle = "orange"; - ctx.fillText(p, topLeftX + pw/2*ppL - 10, topLeftY + ph/2*ppL + 10); + ctx.fillText(p+1, topLeftX + pw/2*ppL - 10, topLeftY + ph/2*ppL + 10); } gId("MD").innerHTML = "Matrix Dimensions (W*H=LC): " + maxWidth + " x " + maxHeight + " = " + maxWidth * maxHeight; } From 102d098e28dc762c426630a28420930f0de2d59d Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 4 Dec 2024 18:05:37 +0100 Subject: [PATCH 38/39] bugfix #3 for ghostly appearing switched-off segments --- wled00/FX_fcn.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index b2d7162f19..a62ee39b80 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -551,7 +551,7 @@ bool Segment::setColor(uint8_t slot, uint32_t c) { //returns true if changed if (slot == 0 && c == BLACK) return false; // on/off segment cannot have primary color black if (slot == 1 && c != BLACK) return false; // on/off segment cannot have secondary color non black } - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change + if (fadeTransition && on) startTransition(strip.getTransition()); // start transition prior to change // WLEDMM only on real change colors[slot] = c; stateChanged = true; // send UDP/WS broadcast return true; @@ -564,7 +564,7 @@ void Segment::setCCT(uint16_t k) { k = (k - 1900) >> 5; } if (cct == k) return; - if (fadeTransition) startTransition(strip.getTransition()); // start transition prior to change + if (fadeTransition && on) startTransition(strip.getTransition()); // start transition prior to change cct = k; stateChanged = true; // send UDP/WS broadcast } @@ -628,7 +628,7 @@ void Segment::setPalette(uint8_t pal) { if (pal < 245 && pal > GRADIENT_PALETTE_COUNT+13) pal = 0; // built in palettes if (pal > 245 && (strip.customPalettes.size() == 0 || 255U-pal > strip.customPalettes.size()-1)) pal = 0; // custom palettes if (pal != palette) { - if (strip.paletteFade) startTransition(strip.getTransition()); + if (strip.paletteFade && on) startTransition(strip.getTransition()); palette = pal; stateChanged = true; // send UDP/WS broadcast } From 972257a7ee8cf800b9ec3d445039727b30003eb4 Mon Sep 17 00:00:00 2001 From: Frank <91616163+softhack007@users.noreply.github.com> Date: Wed, 4 Dec 2024 22:18:39 +0100 Subject: [PATCH 39/39] minor code cleanup * removed dead code * prevent promotion to double * made constants constexpr * made some methods const * fixed a few typo's --- wled00/FX.cpp | 105 +++++++++++++++++++------------------------- wled00/FX.h | 1 - wled00/FX_2Dfcn.cpp | 5 +-- wled00/FX_fcn.cpp | 11 ----- 4 files changed, 46 insertions(+), 76 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 53d99886ee..4e6d702368 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -75,7 +75,7 @@ static int8_t tristate_square8(uint8_t x, uint8_t pulsewidth, uint8_t attdec) { return 0; } -// float version of map() // WLEDMM moved here so its available for all effects +// float version of map() // WLEDMM moved here so it is available for all effects static float mapf(float x, float in_min, float in_max, float out_min, float out_max){ if (in_max == in_min) return (out_min); // WLEDMM avoid div/0 return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; @@ -795,7 +795,7 @@ static const char _data_FX_MODE_MULTI_STROBE[] PROGMEM = "Strobe Mega@!,!;!,!;!; * Android loading circle */ uint16_t mode_android(void) { - + if (SEGLEN <= 1) return mode_static(); // WLEDMM to prevent division by zero for (int i = 0; i < SEGLEN; i++) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 1)); } @@ -1043,7 +1043,7 @@ static const char _data_FX_MODE_TRAFFIC_LIGHT[] PROGMEM = "Traffic Light@!,US st */ #define FLASH_COUNT 4 uint16_t mode_chase_flash(void) { - if (SEGLEN == 1) return mode_static(); + if (SEGLEN <= 1) return mode_static(); uint8_t flash_step = SEGENV.call % ((FLASH_COUNT * 2) + 1); for (int i = 0; i < SEGLEN; i++) { @@ -2091,7 +2091,7 @@ uint16_t mode_partyjerk() { CRGB rgb(CHSV(SEGENV.aux1, 255, activeColor)); SEGMENT.setPixelColor((uint16_t)i, rgb.r, rgb.g, rgb.b); - }; + } return FRAMETIME; } // mode_partyjerk() @@ -3012,7 +3012,7 @@ uint16_t mode_bouncing_balls(void) { if (SEGLEN == 1) return mode_static(); //allocate segment data const uint16_t strips = SEGMENT.nrOfVStrips(); // adapt for 2D - const size_t maxNumBalls = 16; + constexpr size_t maxNumBalls = 16; uint16_t dataSize = sizeof(ball) * maxNumBalls; if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed @@ -3165,7 +3165,7 @@ static uint16_t rolling_balls(void) { if (thisHeight < 0.0f) thisHeight = 0.0f; if (thisHeight > 1.0f) thisHeight = 1.0f; - uint16_t pos = round(thisHeight * (SEGLEN - 1)); + uint16_t pos = roundf(thisHeight * (SEGLEN - 1)); SEGMENT.setPixelColor(pos, color); balls[i].lastBounceUpdate = strip.now; balls[i].height = thisHeight; @@ -3808,7 +3808,7 @@ uint16_t mode_drip(void) if (SEGLEN == 1) return mode_static(); //allocate segment data uint16_t strips = SEGMENT.nrOfVStrips(); - const int maxNumDrops = 4; + constexpr int maxNumDrops = 4; uint16_t dataSize = sizeof(sparkdrop) * maxNumDrops; if (!SEGENV.allocateData(dataSize * strips)) return mode_static(); //allocation failed SparkDrop* drops = reinterpret_cast(SEGENV.data); @@ -4034,8 +4034,8 @@ uint16_t mode_percent(void) { uint8_t percent = SEGMENT.intensity; percent = constrain(percent, 0, 200); - uint16_t active_leds = (percent < 100) ? SEGLEN * percent / 100.0 - : SEGLEN * (200 - percent) / 100.0; + uint16_t active_leds = (percent < 100) ? SEGLEN * percent / 100.0f + : SEGLEN * (200 - percent) / 100.0f; uint8_t size = (1 + ((SEGMENT.speed * SEGLEN) >> 11)); if (SEGMENT.speed == 255) size = 255; @@ -4137,7 +4137,7 @@ static const char _data_FX_MODE_HEARTBEAT[] PROGMEM = "Heartbeat@!,!;!,!;!;01;m1 // Modified for WLED, based on https://github.com/FastLED/FastLED/blob/master/examples/Pacifica/Pacifica.ino // // Add one layer of waves into the led array -CRGB pacifica_one_layer(uint16_t i, CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff) +CRGB pacifica_one_layer(uint16_t i, const CRGBPalette16& p, uint16_t cistart, uint16_t wavescale, uint8_t bri, uint16_t ioff) { uint16_t ci = cistart; uint16_t waveangle = ioff; @@ -4294,7 +4294,7 @@ uint16_t phased_base(uint8_t moder) { // We're making sine wave uint8_t modVal = 5;//SEGMENT.fft1/8+1; // You can change the modulus. AKA FFT1 (was 5). uint8_t index = strip.now/64; // Set color rotation speed - *phase += SEGMENT.speed/32.0; // You can change the speed of the wave. AKA SPEED (was .4) + *phase += SEGMENT.speed/32.0f; // You can change the speed of the wave. AKA SPEED (was .4) for (int i = 0; i < SEGLEN; i++) { if (moder == 1) modVal = (inoise8(i*10 + i*10) /16); // Let's randomize our mod length with some Perlin noise. @@ -4518,7 +4518,7 @@ uint16_t mode_dancing_shadows(void) if (!initialize) { // advance the position of the spotlight int16_t delta = (float)(time - spotlights[i].lastUpdateTime) * - (spotlights[i].speed * ((1.0 + SEGMENT.speed)/100.0)); + (spotlights[i].speed * ((1.0f + SEGMENT.speed)/100.0f)); if (abs(delta) >= 1) { spotlights[i].position += delta; @@ -4533,15 +4533,15 @@ uint16_t mode_dancing_shadows(void) spotlights[i].colorIdx = random8(); spotlights[i].width = random8(1, 10); - spotlights[i].speed = 1.0/random8(4, 50); + spotlights[i].speed = 1.0f/random8(4, 50); if (initialize) { spotlights[i].position = random16(SEGLEN); - spotlights[i].speed *= random8(2) ? 1.0 : -1.0; + spotlights[i].speed *= random8(2) > 0 ? 1.0 : -1.0; } else { if (random8(2)) { spotlights[i].position = SEGLEN + spotlights[i].width; - spotlights[i].speed *= -1.0; + spotlights[i].speed *= -1.0f; }else { spotlights[i].position = -spotlights[i].width; } @@ -5038,7 +5038,7 @@ uint16_t mode_2DBlackHole(void) { // By: Stepko https://editor.soulma } SEGMENT.fadeToBlackBy(16 + (SEGMENT.speed>>3)); // create fading trails - const unsigned long ratio = 128; // rotation speed + constexpr unsigned long ratio = 128; // rotation speed unsigned long t = strip.now; // timebase // outer stars for (unsigned i = 0; i < 8; i++) { @@ -5342,7 +5342,7 @@ class GameOfLifeGrid { const int8_t offsetY[8] = {-1, -1, -1, 0, 0, 1, 1, 1}; public: GameOfLifeGrid(Cell* data, int c, int r) : cells(data), cols(c), rows(r), maxIndex(r * c) {} - void getNeighborIndexes(unsigned neighbors[9], unsigned cIndex, unsigned x, unsigned y, bool wrap) { + void getNeighborIndexes(unsigned neighbors[9], unsigned cIndex, unsigned x, unsigned y, bool wrap) const { unsigned neighborCount = 0; bool edgeCell = x == 0 || x == cols-1 || y == 0 || y == rows-1; for (unsigned i = 0; i < 8; ++i) { @@ -5363,7 +5363,7 @@ class GameOfLifeGrid { } neighbors[0] = neighborCount; } - void setCell(unsigned cIndex, unsigned x, unsigned y, bool alive, bool wrap) { + void setCell(unsigned cIndex, unsigned x, unsigned y, bool alive, bool wrap) const { Cell* cell = &cells[cIndex]; if (alive == cell->alive) return; // No change cell->alive = alive; @@ -5372,7 +5372,7 @@ class GameOfLifeGrid { int val = alive ? 1 : -1; for (unsigned i = 1; i <= neighbors[0]; ++i) cells[neighbors[i]].neighbors += val; } - void recalculateEdgeNeighbors(bool wrap) { + void recalculateEdgeNeighbors(bool wrap) const { unsigned cIndex = 0; for (unsigned y = 0; y < rows; ++y) for (unsigned x = 0; x < cols; ++x, ++cIndex) { Cell* cell = &cells[cIndex]; @@ -5811,7 +5811,7 @@ uint16_t mode_2DJulia(void) { // An animated Julia set maxIterations = SEGMENT.intensity/2; - // Resize section on the fly for some animaton. + // Resize section on the fly for some animation. reAl = -0.94299f; // PixelBlaze example imAg = 0.3162f; @@ -5820,8 +5820,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set reAl += (float)sin16_t(strip.now * 34) / 655340.f; imAg += (float)sin16_t(strip.now * 26) / 655340.f; - dx = (xmax - xmin) / (cols); // Scale the delta x and y values to our matrix size. - dy = (ymax - ymin) / (rows); + dx = (xmax - xmin) / cols; // Scale the delta x and y values to our matrix size. + dy = (ymax - ymin) / rows; // Start y float y = ymin; @@ -5867,8 +5867,8 @@ uint16_t mode_2DJulia(void) { // An animated Julia set if(SEGMENT.check2) SEGMENT.blur(64, true); // strong blurr if(SEGMENT.check3) { // draw crosshair - int screenX = lround((0.5f / maxCenter) * (julias->xcen + maxCenter) * float(cols)); - int screenY = lround((0.5f / maxCenter) * (julias->ycen + maxCenter) * float(rows)); + int screenX = lroundf((0.5f / maxCenter) * (julias->xcen + maxCenter) * float(cols)); + int screenY = lroundf((0.5f / maxCenter) * (julias->ycen + maxCenter) * float(rows)); int hair = min(min(cols-1, rows-1)/2, 3); SEGMENT.drawLine(screenX, screenY-hair, screenX, screenY+hair, GREEN, true); SEGMENT.drawLine(screenX-hair, screenY, screenX+hair, screenY, GREEN, true); @@ -6039,7 +6039,7 @@ uint16_t mode_2Dmetaballs(void) { // Metaballs by Stefan Petrick. Cannot have byte color = dist ? 1000 / dist : 255; // map color between thresholds - if (color > 0 and color < 60) { + if (color > 0 && color < 60) { SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(map(color * 9, 9, 531, 0, 255), false, PALETTE_SOLID_WRAP, 0)); } else { SEGMENT.setPixelColorXY(x, y, SEGMENT.color_from_palette(0, false, PALETTE_SOLID_WRAP, 0)); @@ -6458,8 +6458,6 @@ uint16_t mode_2Dcrazybees(void) { int8_t signX, signY; int16_t deltaX, deltaY, error; void aimed(uint_fast16_t w, uint_fast16_t h) { - if (!true) //WLEDMM SuperSync - random16_set_seed(strip.now); aimX = random8(0, min(UINT8_MAX, int(w))); aimY = random8(0, min(UINT8_MAX, int(h))); hue = random8(); @@ -6475,8 +6473,7 @@ uint16_t mode_2Dcrazybees(void) { bee_t *bee = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) { - if (true) //WLEDMM SuperSync - random16_set_seed(strip.now); + random16_set_seed(strip.now); //WLEDMM SuperSync SEGMENT.setUpLeds(); SEGMENT.fill(BLACK); for (size_t i = 0; i < n; i++) { @@ -7017,7 +7014,7 @@ uint16_t mode_2DSwirl(void) { SEGMENT.fill(BLACK); } - const uint8_t borderWidth = 2; + constexpr uint8_t borderWidth = 2; SEGMENT.blur(SEGMENT.custom1); @@ -7106,7 +7103,7 @@ typedef struct Gravity { /////////////////////// uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. - const uint16_t dataSize = sizeof(gravity); + constexpr uint16_t dataSize = sizeof(gravity); if (!SEGENV.allocateData(dataSize)) return mode_static(); //allocation failed Gravity* gravcen = reinterpret_cast(SEGENV.data); if (SEGENV.call == 0) { @@ -7123,7 +7120,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline. float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; segmentSampleAvg *= 0.125; // divide by 8, to compensate for later "sensitivity" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0, 32, 0, (float)SEGLEN/2.0); // map to pixels available in current segment + float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0, 32, 0, (float)SEGLEN/2.0f); // map to pixels available in current segment uint16_t tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -7171,10 +7168,10 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew //SEGMENT.fade_out(240); // twice? really? SEGMENT.fade_out(253); // 50% - float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0; + float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0); // map to pixels availeable in current segment + float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0.0f, 32.0f, 0.0f, (float)SEGLEN/2.0f); // map to pixels availeable in current segment int tempsamp = constrain(mySampleAvg, 0, SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -7226,7 +7223,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline. float realVolume = volumeSmth; if (SEGENV.check3 && SEGENV.check2) SEGENV.check2 = false; // only one option if (SEGENV.check2) volumeSmth = soundPressure; - if (SEGENV.check3) volumeSmth = 255.0 - agcSensitivity; + if (SEGENV.check3) volumeSmth = 255.0f - agcSensitivity; SEGMENT.fade_out(253); float sensGain = (float)(SEGMENT.intensity+2) / 257.0f; // min gain = 1/128 @@ -7287,7 +7284,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline. if (SEGENV.call == 0) {SEGENV.setUpLeds(); SEGMENT.fill(BLACK);} // WLEDMM use lossless getPixelColor() SEGMENT.fade_out(224); // 6.25% - uint16_t my_sampleAgc = fmax(fmin(volumeSmth, 255.0), 0); + uint16_t my_sampleAgc = max(min(volumeSmth, 255.0f), 0.0f); for (size_t i=0; iSEGLEN/2) maxLen = SEGLEN/2; @@ -7429,7 +7426,7 @@ uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline. uint8_t fadeRate = map2(SEGMENT.speed,0,255,200,254); SEGMENT.fade_out(fadeRate); - float tmpSound2 = volumeRaw * 2.0 * (float)SEGMENT.intensity / 255.0; + float tmpSound2 = volumeRaw * 2.0f * (float)SEGMENT.intensity / 255.0f; int maxLen = mapf(tmpSound2, 0, 255, 0, SEGLEN); // map to pixels availeable in current segment // Still a bit too sensitive. if (maxLen <0) maxLen = 0; if (maxLen >SEGLEN) maxLen = SEGLEN; @@ -7974,14 +7971,14 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun int lowerLimit = 80 + 3 * SEGMENT.custom1; // min 80hz-850hz i = lowerLimit!=upperLimit ? mapf(FFT_MajorPeak, lowerLimit, upperLimit, 0, 255) : FFT_MajorPeak; // may under/overflow - so we enforce uint8_t } else { - // Musical Scale (logarythmic scaling) + // Musical Scale (logarithmic scaling) float upperLimit = logf(80 + 42 * SEGMENT.custom2); // max 80hz-10Khz float lowerLimit = logf(80 + 3 * SEGMENT.custom1); // min 80hz-850hz float peakMapped = fabsf(lowerLimit - upperLimit)>0.05f ? mapf(logf(FFT_MajorPeak), lowerLimit, upperLimit, 0, 255) : FFT_MajorPeak; // may under/overflow if (peakMapped > 255) intensity = constrain((320-peakMapped), 0, intensity*100) / 100.0f; // too high: fade away i = constrain(peakMapped, 0, 255); // fix over / underflow } - uint16_t b = 255.0 * intensity; + uint16_t b = 255.0f * intensity; if (b > 255) b=255; color = CHSV(i, 176+(uint8_t)b/4, (uint8_t)b); // implicit conversion to RGB supplied by FastLED } @@ -8023,7 +8020,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline. float segmentSampleAvg = volumeSmth * (float)SEGMENT.intensity / 255.0f; segmentSampleAvg *= 0.125f; // divide by 8, to compensate for later "sensitivity" upscaling - float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0,32, 0, (float)SEGLEN/2.0); // map to pixels availeable in current segment + float mySampleAvg = mapf(segmentSampleAvg*2.0f, 0,32, 0, (float)SEGLEN/2.0f); // map to pixels available in current segment int tempsamp = constrain(mySampleAvg,0,SEGLEN/2); // Keep the sample from overflowing. uint8_t gravity = 8 - SEGMENT.speed/32; @@ -8542,21 +8539,12 @@ uint16_t mode_2Dsoap() { // init if (SEGENV.call == 0) { - if (true) {//WLEDMM SuperSync - random16_set_seed(535); - USER_PRINTF("SuperSync\n"); - } + random16_set_seed(535); //WLEDMM SuperSync SEGENV.setUpLeds(); SEGMENT.fill(BLACK); *noise32_x = random16(); *noise32_y = random16(); *noise32_z = random16(); - } else { - if (!true) { //WLEDMM SuperSync - *noise32_x += mov; - *noise32_y += mov; - *noise32_z += mov; - } } //WLEDMM: changing noise calculation for SuperSync to make it deterministic using strip.now @@ -8564,11 +8552,10 @@ uint16_t mode_2Dsoap() { uint32_t noise32_y_MM = *noise32_y; uint32_t noise32_z_MM = *noise32_z; - if (true) { //WLEDMM SuperSync - noise32_x_MM = *noise32_x + mov * strip.now / 100; //10 fps (original 20-40 fps, depending on realized fps) - noise32_y_MM = *noise32_y + mov * strip.now / 100; - noise32_z_MM = *noise32_z + mov * strip.now / 100; - } + //WLEDMM SuperSync + noise32_x_MM = *noise32_x + mov * strip.now / 100; //10 fps (original 20-40 fps, depending on realized fps) + noise32_y_MM = *noise32_y + mov * strip.now / 100; + noise32_z_MM = *noise32_z + mov * strip.now / 100; for (int i = 0; i < cols; i++) { int32_t ioffset = scale32_x * (i - cols / 2); @@ -8689,8 +8676,6 @@ uint16_t mode_2Doctopus() { // re-init if SEGMENT dimensions or offset changed if (SEGENV.call == 0 || SEGENV.aux0 != cols || SEGENV.aux1 != rows || SEGMENT.custom1 != *offsX || SEGMENT.custom2 != *offsY) { - if (!true) //WLEDMM SuperSync - SEGENV.step = 0; // t SEGENV.aux0 = cols; SEGENV.aux1 = rows; *offsX = SEGMENT.custom1; @@ -8968,7 +8953,7 @@ uint16_t mode_2DPaintbrush() { byte y1 = beatsin8_t(max(16,int(SEGMENT.speed))/16*3 + fftResult[0]/16, 0, (rows-1), fftResult[bin], SEGENV.aux1); byte y2 = beatsin8_t(max(16,int(SEGMENT.speed))/16*4 + fftResult[0]/16, 0, (rows-1), fftResult[bin], SEGENV.aux1); - int length = sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); + int length = sqrtf((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)); length = map8(fftResult[bin],0,length); if (length > max(1,int(SEGMENT.custom3))) { diff --git a/wled00/FX.h b/wled00/FX.h index c35c54fb87..5e8ae60acd 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -429,7 +429,6 @@ typedef struct Segment { // WLEDMM cache some values that won't change while drawing a frame bool _isValid2D = false; uint8_t _brightness = 255; // final pixel brightness - including transitions and segment opacity - bool _firstFill = true; // dirty HACK support uint16_t _2dWidth = 0; // virtualWidth uint16_t _2dHeight = 0; // virtualHeight uint16_t _virtuallength = 0; // virtualLength diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 4d58143bff..2c7d0fc851 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -259,9 +259,6 @@ void Segment::startFrame(void) { _2dHeight = calc_virtualHeight(); _2dWidth = _isValid2D ? calc_virtualWidth() : calc_virtualLength(); _virtuallength = calc_virtualLength(); - #if 0 && defined(WLED_ENABLE_HUB75MATRIX) - _firstFill = true; // dirty HACK - #endif #endif } // WLEDMM end @@ -402,7 +399,7 @@ void Segment::setPixelColorXY(float x, float y, uint32_t col, bool aa, bool fast if (Segment::maxHeight==1) return; // not a matrix set-up if (x<0.0f || x>1.0f || y<0.0f || y>1.0f) return; // not normalized -#if 0 // depricated +#if 0 // deprecated const uint_fast16_t cols = virtualWidth(); const uint_fast16_t rows = virtualHeight(); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index a62ee39b80..462bb7e7af 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -1399,17 +1399,6 @@ void Segment::refreshLightCapabilities() { */ void __attribute__((hot)) Segment::fill(uint32_t c) { if (!isActive()) return; // not active - - #if 0 && defined(WLED_ENABLE_HUB75MATRIX) && defined(WLEDMM_FASTPATH) - // DIRTY HACK - this ignores the first fill(black) in each frame, knowing that HUB75 has already blanked out the display. - if (_firstFill) { - _firstFill = false; - if (c == BLACK) { - if (ledsrgb && ledsrgbSize > 0) memset(ledsrgb, 0, ledsrgbSize); - return; - } - } - #endif const uint_fast16_t cols = is2D() ? virtualWidth() : virtualLength(); // WLEDMM use fast int types const uint_fast16_t rows = virtualHeight(); // will be 1 for 1D