From 9103f6a4dfe4ed7e93b18bd4736496f8e66b5230 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Sat, 16 Mar 2024 12:07:26 -0400 Subject: [PATCH 01/19] Update for new AsyncWebSocketBuffer Eliminate the extra indirection and allocate shared buffers directly. --- wled00/ws.cpp | 65 ++++++++++++++------------------------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/wled00/ws.cpp b/wled00/ws.cpp index 5b8bda42..22c5afd2 100644 --- a/wled00/ws.cpp +++ b/wled00/ws.cpp @@ -108,7 +108,6 @@ void sendDataWs(AsyncWebSocketClient * client) { DEBUG_PRINTF("sendDataWs\n"); if (!ws.count()) return; - AsyncWebSocketMessageBuffer * buffer; if (!requestJSONBufferLock(12)) { if (client) { @@ -138,17 +137,7 @@ void sendDataWs(AsyncWebSocketClient * client) // DEBUG_PRINTF("%s min free stack %d\n", pcTaskGetTaskName(NULL), uxTaskGetStackHighWaterMark(NULL)); //WLEDMM #endif if (len < 1) return; // WLEDMM do not allocate 0 size buffer - - // WLEDMM use exceptions to catch out-of-memory errors - #if __cpp_exceptions - try{ - buffer = ws.makeBuffer(len); // will not allocate correct memory sometimes on ESP8266 - } catch(...) { - buffer = nullptr; - } - #else - buffer = ws.makeBuffer(len); // will not allocate correct memory sometimes on ESP8266 - #endif + AsyncWebSocketBuffer buffer(len); #ifdef ESP8266 size_t heap2 = ESP.getFreeHeap(); DEBUG_PRINT(F("heap ")); DEBUG_PRINTLN(ESP.getFreeHeap()); @@ -161,24 +150,19 @@ void sendDataWs(AsyncWebSocketClient * client) USER_PRINTLN(F("WS buffer allocation failed.")); ws.closeAll(1013); //code 1013 = temporary overload, try again later ws.cleanupClients(0); //disconnect all clients to release memory - ws._cleanBuffers(); errorFlag = ERR_LOW_WS_MEM; return; //out of memory } - - buffer->lock(); - serializeJson(doc, (char *)buffer->get(), len); + serializeJson(doc, (char *)buffer.data(), len); DEBUG_PRINT(F("Sending WS data ")); if (client) { - client->text(buffer); + client->text(std::move(buffer)); DEBUG_PRINTLN(F("to a single client.")); } else { - ws.textAll(buffer); + ws.textAll(std::move(buffer)); DEBUG_PRINTLN(F("to multiple clients.")); } - buffer->unlock(); - ws._cleanBuffers(); releaseJSONBufferLock(); } @@ -227,32 +211,21 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static" #endif size_t pos = (strip.isMatrix ? 4 : 2); size_t bufSize = pos + (used/n)*3; - - if ((bufSize < 1) || (used < 1)) return(false); // WLEDMM should not happen - //AsyncWebSocketMessageBuffer * wsBuf = ws.makeBuffer(bufSize); - // WLEDMM protect against exceptions due to low memory - AsyncWebSocketMessageBuffer * wsBuf = nullptr; -#if __cpp_exceptions - try{ -#endif - wsBuf = ws.makeBuffer(bufSize); -#if __cpp_exceptions - } catch(...) { -#else - if (wsBuf == nullptr) { // 8266 does not support exceptions -#endif - wsBuf = nullptr; - USER_PRINTLN(F("WS buffer allocation failed.")); - //ws.closeAll(1013); //code 1013 = temporary overload, try again later - //ws.cleanupClients(0); //disconnect all clients to release memory - ws._cleanBuffers(); - } - if (!wsBuf) return false; //out of memory - uint8_t* buffer = wsBuf->get(); - if (!buffer) return false; //out of memory + if ((bufSize < 1) || (used < 1)) return(false); // WLEDMM should not happen + AsyncWebSocketBuffer wsBuf(bufSize); + if (!wsBuf) { + USER_PRINTLN(F("WS buffer allocation failed.")); + errorFlag = ERR_LOW_WS_MEM; + return false; //out of memory + } + uint8_t* buffer = reinterpret_cast(wsBuf.data()); + if (!buffer) { + USER_PRINTLN(F("WS buffer allocation failed.")); + errorFlag = ERR_LOW_WS_MEM; + return false; //out of memory + } - wsBuf->lock(); // protect buffer from being cleaned by another WS instance buffer[0] = 'L'; buffer[1] = 1; //version #ifndef WLED_DISABLE_2D @@ -290,9 +263,7 @@ static bool sendLiveLedsWs(uint32_t wsClient) // WLEDMM added "static" } } - wsc->binary(wsBuf); - wsBuf->unlock(); // un-protect buffer - ws._cleanBuffers(); // cleans up if the message is not added to any clients. + wsc->binary(std::move(wsBuf)); return true; } From 775e07c6d6e210754c83c9826b05dbc3c1850b23 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Thu, 14 Mar 2024 22:06:51 -0400 Subject: [PATCH 02/19] serveLiveLeds: Use dynamic buffer There were three problems here: - AsyncWebServer is going to copy to a heap buffer anyways, so we might as well just pass it one it can use - The buffer size estimate was wrong -- we need 9 bytes per pixel ("RRGGBB",), so the buffer could overflow, and it was not considering the extra 2D requirements - On ESP8266, the stack allocation was overflowing the stack, causing corruption and crashes. --- wled00/json.cpp | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/wled00/json.cpp b/wled00/json.cpp index 5456b455..020c46c3 100644 --- a/wled00/json.cpp +++ b/wled00/json.cpp @@ -1554,10 +1554,20 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) uint16_t used = strip.getLengthTotal(); uint16_t n = (used -1) /MAX_LIVE_LEDS +1; //only serve every n'th LED if count over MAX_LIVE_LEDS - char buffer[2000]; - strcpy_P(buffer, PSTR("{\"leds\":[")); - obuf = buffer; - olen = 9; +#ifndef WLED_DISABLE_2D + if (strip.isMatrix) { + // ignore anything behid matrix (i.e. extra strip) + used = Segment::maxWidth*Segment::maxHeight; // always the size of matrix (more or less than strip.getLengthTotal()) + n = 1; + if (used > MAX_LIVE_LEDS) n = 2; + if (used > MAX_LIVE_LEDS*4) n = 4; + } +#endif + + DynamicBuffer buffer(9 + (9*MAX_LIVE_LEDS) + 7 + 5 + 6 + 5 + 6 + 5 + 2); + char* buf = buffer.data(); // assign buffer for oappnd() functions + strncpy_P(buffer.data(), PSTR("{\"leds\":["), buffer.size()); + buf += 9; // sizeof(PSTR()) from last line for (size_t i= 0; i < used; i += n) { @@ -1575,20 +1585,21 @@ bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient) g = qadd8(w, G(c)); b = qadd8(w, B(c)); } - olen += sprintf(obuf + olen, "\"%06X\",", RGBW32(r,g,b,0)); + buf += sprintf_P(buf, PSTR("\"%06X\","), RGBW32(r,g,b,0)); } - olen -= 1; - oappend((const char*)F("],\"n\":")); - oappendi(n); - oappend("}"); + buf--; // remove last comma + buf += sprintf_P(buf, PSTR("],\"n\":%d"), n); + (*buf++) = '}'; + (*buf++) = 0; + if (request) { - request->send(200, "application/json", buffer); + request->send(200, "application/json", toString(std::move(buffer))); } #ifdef WLED_ENABLE_WEBSOCKETS else { - wsc->text(obuf, olen); + wsc->text(toString(std::move(buffer))); } - #endif + #endif return true; } #endif From 543dfd206d59194e9ff14cabeda2ae4d3ad25c42 Mon Sep 17 00:00:00 2001 From: thatdonfc Date: Tue, 19 Mar 2024 14:04:24 -0700 Subject: [PATCH 03/19] Fix palette names when palette ID > 58 and not custom --- wled00/util.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wled00/util.cpp b/wled00/util.cpp index 896b57e3..bb8715d7 100644 --- a/wled00/util.cpp +++ b/wled00/util.cpp @@ -255,8 +255,8 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe } else return 0; } - if (src == JSON_palette_names && mode > GRADIENT_PALETTE_COUNT) { - snprintf_P(dest, maxLen, PSTR("~ Custom %d~"), 255-mode); + if (src == JSON_palette_names && mode > (GRADIENT_PALETTE_COUNT + 13)) { + snprintf_P(dest, maxLen, PSTR("~ Custom %d ~"), 255-mode); dest[maxLen-1] = '\0'; return strlen(dest); } From 3df3b9acafe8487e215b0ebe529774dad7263c86 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 17 Apr 2024 18:52:35 +0200 Subject: [PATCH 04/19] ArduinoFFT update shadow variables --- usermods/multi_relay/usermod_multi_relay.h | 2 +- wled00/json.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/usermods/multi_relay/usermod_multi_relay.h b/usermods/multi_relay/usermod_multi_relay.h index cf0aca22..dd47e767 100644 --- a/usermods/multi_relay/usermod_multi_relay.h +++ b/usermods/multi_relay/usermod_multi_relay.h @@ -626,7 +626,7 @@ void MultiRelay::addToJsonInfo(JsonObject &root) { for (int i=0; i()) { From c5283da32aa23f5dbbb7d84618b28917a7377914 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Wed, 24 Apr 2024 16:04:54 +0200 Subject: [PATCH 05/19] Fix for #3878 --- usermods/BH1750_v2/usermod_bh1750.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usermods/BH1750_v2/usermod_bh1750.h b/usermods/BH1750_v2/usermod_bh1750.h index 5b5fa25f..a6e7d653 100644 --- a/usermods/BH1750_v2/usermod_bh1750.h +++ b/usermods/BH1750_v2/usermod_bh1750.h @@ -76,7 +76,7 @@ private: bool sensorFound = false; // Home Assistant and MQTT - String mqttLuminanceTopic = FPSTR(""); + String mqttLuminanceTopic; bool mqttInitialized = false; bool HomeAssistantDiscovery = true; // Publish Home Assistant Discovery messages From 74e999b1e5c5bcb3b8854821b102ae220ad80f96 Mon Sep 17 00:00:00 2001 From: Pasquale Pizzuti Date: Tue, 30 Apr 2024 14:09:12 +0200 Subject: [PATCH 06/19] using brightness in analog clock overlay --- wled00/overlay.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index cfee7e81..96b15053 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -11,6 +11,7 @@ void _overlayAnalogClock() { _overlayAnalogCountdown(); return; } + uint8_t brightness = strip.getBrightness(); float hourP = ((float)(hour(localTime)%12))/12.0f; float minuteP = ((float)minute(localTime))/60.0f; hourP = hourP + minuteP/12.0f; @@ -25,11 +26,11 @@ void _overlayAnalogClock() { if (secondPixel < analogClock12pixel) { - strip.setRange(analogClock12pixel, overlayMax, 0xFF0000); - strip.setRange(overlayMin, secondPixel, 0xFF0000); + strip.setRange(analogClock12pixel, overlayMax, (uint32_t)brightness<<16); + strip.setRange(overlayMin, secondPixel, (uint32_t)brightness<<16); } else { - strip.setRange(analogClock12pixel, secondPixel, 0xFF0000); + strip.setRange(analogClock12pixel, secondPixel, (uint32_t)brightness<<16); } } if (analogClock5MinuteMarks) @@ -38,12 +39,12 @@ void _overlayAnalogClock() { int pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i); if (pix > overlayMax) pix -= overlaySize; - strip.setPixelColor(pix, 0x00FFAA); + strip.setPixelColor(pix, ((uint32_t)brightness<<8)|((uint32_t)brightness*2/3)); } } - if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, 0xFF0000); - strip.setPixelColor(minutePixel, 0x00FF00); - strip.setPixelColor(hourPixel, 0x0000FF); + if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, (uint32_t)brightness<<16); + strip.setPixelColor(minutePixel, (uint32_t)brightness<<8); + strip.setPixelColor(hourPixel, (uint32_t)brightness); } From feac33653f72aea364d6f3b2e83042e492765f61 Mon Sep 17 00:00:00 2001 From: Woody Date: Tue, 30 Apr 2024 16:53:47 +0200 Subject: [PATCH 07/19] Fix resizing bug The bug was that when resizing the window, it always jumped to the Colors tab instead of staying on the currently selected tab. --- wled00/data/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/wled00/data/index.js b/wled00/data/index.js index 1fcbfcaf..d193a730 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -279,7 +279,6 @@ function updateTablinks(tabI) { var tablinks = gEBCN("tablinks"); for (var i of tablinks) i.classList.remove('active'); - if (pcMode) return; tablinks[tabI].classList.add('active'); } @@ -3615,12 +3614,11 @@ function togglePcMode(fromB = false) if (fromB) { pcModeA = !pcModeA; localStorage.setItem('pcm', pcModeA); + openTab(0, true); } pcMode = (wW >= 1024) && pcModeA; if (cpick) cpick.resize(pcMode && wW>1023 && wW<1250 ? 230 : 260); // for tablet in landscape if (!fromB && ((wW < 1024 && lastw < 1024) || (wW >= 1024 && lastw >= 1024))) return; // no change in size and called from size() - openTab(0, true); - updateTablinks(0); gId('buttonPcm').className = (pcMode) ? "active":""; gId('bot').style.height = (pcMode && !cfg.comp.pcmbot) ? "0":"auto"; sCol('--bh', gId('bot').clientHeight + "px"); From b01f3118b441f4ca40e49c5de99021b7f45a8efe Mon Sep 17 00:00:00 2001 From: Pasquale Pizzuti Date: Tue, 30 Apr 2024 17:52:35 +0200 Subject: [PATCH 08/19] using color_fade --- wled00/overlay.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index 96b15053..71f7e081 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -26,11 +26,11 @@ void _overlayAnalogClock() { if (secondPixel < analogClock12pixel) { - strip.setRange(analogClock12pixel, overlayMax, (uint32_t)brightness<<16); - strip.setRange(overlayMin, secondPixel, (uint32_t)brightness<<16); + strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, brightness)); + strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, brightness)); } else { - strip.setRange(analogClock12pixel, secondPixel, (uint32_t)brightness<<16); + strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, brightness)); } } if (analogClock5MinuteMarks) @@ -39,12 +39,12 @@ void _overlayAnalogClock() { int pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i); if (pix > overlayMax) pix -= overlaySize; - strip.setPixelColor(pix, ((uint32_t)brightness<<8)|((uint32_t)brightness*2/3)); + strip.setPixelColor(pix, color_fade(0x00FFAA, brightness)); } } - if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, (uint32_t)brightness<<16); - strip.setPixelColor(minutePixel, (uint32_t)brightness<<8); - strip.setPixelColor(hourPixel, (uint32_t)brightness); + if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, brightness)); + strip.setPixelColor(minutePixel, color_fade(0x00FF00, brightness)); + strip.setPixelColor(hourPixel, color_fade(0x0000FF, brightness)); } From 383c7977468864a0209962559eec389025343a41 Mon Sep 17 00:00:00 2001 From: Woody Date: Tue, 30 Apr 2024 18:57:53 +0200 Subject: [PATCH 09/19] add Webpage shortcuts, resolves #2362 --- wled00/data/index.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/wled00/data/index.js b/wled00/data/index.js index d193a730..e89ad78e 100644 --- a/wled00/data/index.js +++ b/wled00/data/index.js @@ -247,6 +247,7 @@ function onLoad() selectSlot(0); updateTablinks(0); + handleLocationHash(); pmtLS = localStorage.getItem('wledPmt'); // Load initial data @@ -289,6 +290,21 @@ function openTab(tabI, force = false) _C.classList.toggle('smooth', false); _C.style.setProperty('--i', iSlide); updateTablinks(tabI); + switch (tabI) { + case 0: window.location.hash = "Colors"; break; + case 1: window.location.hash = "Effects"; break; + case 2: window.location.hash = "Segments"; break; + case 3: window.location.hash = "Presets"; break; + } +} + +function handleLocationHash() { + switch (window.location.hash) { + case "#Colors": openTab(0); break; + case "#Effects": openTab(1); break; + case "#Segments": openTab(2); break; + case "#Presets": openTab(3); break; + } } var timeout; @@ -3650,6 +3666,7 @@ size(); _C.style.setProperty('--n', N); window.addEventListener('resize', size, true); +window.addEventListener('hashchange', handleLocationHash); _C.addEventListener('mousedown', lock, false); _C.addEventListener('touchstart', lock, false); From c22c5b75a092e30e77ac7f9c48449cf151175247 Mon Sep 17 00:00:00 2001 From: Pasquale Pizzuti Date: Thu, 2 May 2024 09:04:07 +0200 Subject: [PATCH 10/19] using global brightness --- wled00/overlay.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/wled00/overlay.cpp b/wled00/overlay.cpp index 71f7e081..6ffc6c8e 100644 --- a/wled00/overlay.cpp +++ b/wled00/overlay.cpp @@ -11,7 +11,6 @@ void _overlayAnalogClock() { _overlayAnalogCountdown(); return; } - uint8_t brightness = strip.getBrightness(); float hourP = ((float)(hour(localTime)%12))/12.0f; float minuteP = ((float)minute(localTime))/60.0f; hourP = hourP + minuteP/12.0f; @@ -26,11 +25,11 @@ void _overlayAnalogClock() { if (secondPixel < analogClock12pixel) { - strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, brightness)); - strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, brightness)); + strip.setRange(analogClock12pixel, overlayMax, color_fade(0xFF0000, bri)); + strip.setRange(overlayMin, secondPixel, color_fade(0xFF0000, bri)); } else { - strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, brightness)); + strip.setRange(analogClock12pixel, secondPixel, color_fade(0xFF0000, bri)); } } if (analogClock5MinuteMarks) @@ -39,12 +38,12 @@ void _overlayAnalogClock() { int pix = analogClock12pixel + roundf((overlaySize / 12.0f) *i); if (pix > overlayMax) pix -= overlaySize; - strip.setPixelColor(pix, color_fade(0x00FFAA, brightness)); + strip.setPixelColor(pix, color_fade(0x00FFAA, bri)); } } - if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, brightness)); - strip.setPixelColor(minutePixel, color_fade(0x00FF00, brightness)); - strip.setPixelColor(hourPixel, color_fade(0x0000FF, brightness)); + if (!analogClockSecondsTrail) strip.setPixelColor(secondPixel, color_fade(0xFF0000, bri)); + strip.setPixelColor(minutePixel, color_fade(0x00FF00, bri)); + strip.setPixelColor(hourPixel, color_fade(0x0000FF, bri)); } From 87b5badd5b20f5db50ecd6a9a2840d0f77e6ae72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bla=C5=BE=20Kristan?= Date: Fri, 3 May 2024 09:56:14 +0200 Subject: [PATCH 11/19] Merge pull request #3944 from paspiz85/pas4 Using brightness in analog clock overlay From 2aad3f535618e5c58eda9728c88390e4932bf395 Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Fri, 10 May 2024 00:02:28 +0200 Subject: [PATCH 12/19] Antialiased line & circle --- wled00/FX.cpp | 6 +- wled00/FX.h | 23 +++-- wled00/FX_2Dfcn.cpp | 217 +++++++++++++++++++++++++++----------------- 3 files changed, 155 insertions(+), 91 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 416884cf..01fd923c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -2551,7 +2551,7 @@ uint16_t ripple_base() uint16_t cx = rippleorigin >> 8; uint16_t cy = rippleorigin & 0xFF; uint8_t mag = scale8(sin8((propF>>2)), amp); - if (propI > 0) SEGMENT.draw_circle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag)); + if (propI > 0) SEGMENT.drawCircle(cx, cy, propI, color_blend(SEGMENT.getPixelColorXY(cx + propI, cy), col, mag), true); } else #endif { @@ -6271,8 +6271,8 @@ uint16_t mode_2Dfloatingblobs(void) { } } uint32_t c = SEGMENT.color_from_palette(blob->color[i], false, false, 0); - if (blob->r[i] > 1.f) SEGMENT.fill_circle(blob->x[i], blob->y[i], roundf(blob->r[i]), c); - else SEGMENT.setPixelColorXY(blob->x[i], blob->y[i], c); + if (blob->r[i] > 1.f) SEGMENT.fillCircle(roundf(blob->x[i]), roundf(blob->y[i]), roundf(blob->r[i]), c); + else SEGMENT.setPixelColorXY((int)roundf(blob->x[i]), (int)roundf(blob->y[i]), c); // move x if (blob->x[i] + blob->r[i] >= cols - 1) blob->x[i] += (blob->sX[i] * ((cols - 1 - blob->x[i]) / blob->r[i] + 0.005f)); else if (blob->x[i] - blob->r[i] <= 0) blob->x[i] += (blob->sX[i] * (blob->x[i] / blob->r[i] + 0.005f)); diff --git a/wled00/FX.h b/wled00/FX.h index b8864db4..b53f3fce 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -122,6 +122,10 @@ bool strip_uses_global_leds(void); // WLEDMM implemented in FX_fcn. #define PURPLE (uint32_t)0x400080 #define ORANGE (uint32_t)0xFF3000 #define PINK (uint32_t)0xFF1493 +#define GREY (uint32_t)0x808080 +#define GRAY GREY +#define DARKGREY (uint32_t)0x333333 +#define DARKGRAY DARKGREY #define ULTRAWHITE (uint32_t)0xFFFFFFFF #define DARKSLATEGRAY (uint32_t)0x2F4F4F #define DARKSLATEGREY (uint32_t)0x2F4F4F @@ -665,6 +669,7 @@ typedef struct Segment { 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)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColorXY(int(x), int(y), RGBW32(c.r,c.g,c.b,0)); } //#ifdef WLED_USE_AA_PIXELS void setPixelColorXY(float x, float y, uint32_t c, bool aa = true, bool fast=true); 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); } @@ -684,8 +689,10 @@ typedef struct Segment { void moveX(int8_t delta, bool wrap = false); void moveY(int8_t delta, bool wrap = false); void move(uint8_t dir, uint8_t delta, bool wrap = false); - void draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); - void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c); + void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); + inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } + void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); + inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor = 0); @@ -693,7 +700,7 @@ typedef struct Segment { void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0); void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); - void blur1d(fract8 blur_amount); // blur all rows in 1 dimension + //void blur1d(fract8 blur_amount); // blur all rows in 1 dimension void blur2d(fract8 blur_amount) { blur(blur_amount); } void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } void nscale8(uint8_t scale); @@ -704,6 +711,7 @@ typedef struct Segment { inline void setPixelColorXY(unsigned x, unsigned y, uint32_t c) { setPixelColor(int(x), c); } inline void setPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0) { setPixelColor(x, RGBW32(r,g,b,w)); } inline void setPixelColorXY(int x, int y, CRGB c) { setPixelColor(x, RGBW32(c.r,c.g,c.b,0)); } + inline void setPixelColorXY(unsigned x, unsigned y, CRGB c) { setPixelColor(int(x), RGBW32(c.r,c.g,c.b,0)); } //#ifdef WLED_USE_AA_PIXELS inline void setPixelColorXY(float x, float y, uint32_t c, bool aa = true) { setPixelColor(x, c, aa); } inline void setPixelColorXY(float x, float y, byte r, byte g, byte b, byte w = 0, bool aa = true) { setPixelColor(x, RGBW32(r,g,b,w), aa); } @@ -722,9 +730,12 @@ typedef struct Segment { inline void moveX(int8_t delta, bool wrap = false) {} inline void moveY(int8_t delta, bool wrap = false) {} inline void move(uint8_t dir, uint8_t delta, bool wrap = false) {} - inline void fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c) {} - inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c) {} - inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) {} + inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {} + inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {} + inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false) {} + inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) {} + inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false) {} + inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) {} inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t = 0, int8_t = 0) {} inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB color) {} inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2, int8_t rotate = 0) {} diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 1d217ff0..320636d6 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -427,56 +427,38 @@ void Segment::blurCol(uint32_t col, fract8 blur_amount, bool smear) { } // 1D Box blur (with added weight - blur_amount: [0=no blur, 255=max blur]) -void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { //WLEDMM: use fast types - const uint_fast16_t cols = virtualWidth(); - const uint_fast16_t rows = virtualHeight(); - const uint_fast16_t dim1 = vertical ? rows : cols; - const uint_fast16_t dim2 = vertical ? cols : rows; +void Segment::box_blur(uint16_t i, bool vertical, fract8 blur_amount) { + if (!isActive() || blur_amount == 0) return; // not active + const int cols = virtualWidth(); + const int rows = virtualHeight(); + const int dim1 = vertical ? rows : cols; + const int dim2 = vertical ? cols : rows; if (i >= dim2) return; const float seep = blur_amount/255.f; const float keep = 3.f - 2.f*seep; // 1D box blur - CRGB tmp[dim1]; - for (uint_fast16_t j = 0; j < dim1; j++) { - uint_fast16_t x = vertical ? i : j; - uint_fast16_t y = vertical ? j : i; - int_fast16_t xp = vertical ? x : x-1; // "signed" to prevent underflow - int_fast16_t yp = vertical ? y-1 : y; // "signed" to prevent underflow - uint_fast16_t xn = vertical ? x : x+1; - uint_fast16_t yn = vertical ? y+1 : y; - CRGB curr = getPixelColorXY(x,y); - CRGB prev = (xp<0 || yp<0) ? CRGB::Black : getPixelColorXY(xp,yp); - CRGB next = ((vertical && yn>=dim1) || (!vertical && xn>=dim1)) ? CRGB::Black : getPixelColorXY(xn,yn); - uint16_t r, g, b; - r = (curr.r*keep + (prev.r + next.r)*seep) / 3; - g = (curr.g*keep + (prev.g + next.g)*seep) / 3; - b = (curr.b*keep + (prev.b + next.b)*seep) / 3; - tmp[j] = CRGB(r,g,b); + uint32_t out[dim1], in[dim1]; + for (int j = 0; j < dim1; j++) { + int x = vertical ? i : j; + int y = vertical ? j : i; + in[j] = getPixelColorXY(x, y); } - for (uint_fast16_t j = 0; j < dim1; j++) { - uint_fast16_t x = vertical ? i : j; - uint_fast16_t y = vertical ? j : i; - setPixelColorXY((int)x, (int)y, tmp[j]); + for (int j = 0; j < dim1; j++) { + uint32_t curr = in[j]; + uint32_t prev = j > 0 ? in[j-1] : BLACK; + uint32_t next = j < dim1-1 ? in[j+1] : BLACK; + uint8_t r, g, b, w; + r = (R(curr)*keep + (R(prev) + R(next))*seep) / 3; + g = (G(curr)*keep + (G(prev) + G(next))*seep) / 3; + b = (B(curr)*keep + (B(prev) + B(next))*seep) / 3; + w = (W(curr)*keep + (W(prev) + W(next))*seep) / 3; + out[j] = RGBW32(r,g,b,w); + } + for (int j = 0; j < dim1; j++) { + int x = vertical ? i : j; + int y = vertical ? j : i; + setPixelColorXY(x, y, out[j]); } -} - -// blur1d: one-dimensional blur filter. Spreads light to 2 line neighbors. -// blur2d: two-dimensional blur filter. Spreads light to 8 XY neighbors. -// -// 0 = no spread at all -// 64 = moderate spreading -// 172 = maximum smooth, even spreading -// -// 173..255 = wider spreading, but increasing flicker -// -// Total light is NOT entirely conserved, so many repeated -// calls to 'blur' will also result in the light fading, -// eventually all the way to black; this is by design so that -// it can be used to (slowly) clear the LEDs to black. - -void Segment::blur1d(fract8 blur_amount) { //WLEDMM: use fast types - const uint_fast16_t rows = virtualHeight(); - for (uint_fast16_t y = 0; y < rows; y++) blurRow(y, blur_amount); } void Segment::moveX(int8_t delta, bool wrap) { @@ -533,37 +515,71 @@ void Segment::move(uint8_t dir, uint8_t delta, bool wrap) { } } -void Segment::draw_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { - if (!isActive()) return; // not active - // Bresenham’s Algorithm - int d = 3 - (2*radius); - int y = radius, x = 0; - while (y >= x) { - setPixelColorXY(cx+x, cy+y, col); - setPixelColorXY(cx-x, cy+y, col); - setPixelColorXY(cx+x, cy-y, col); - setPixelColorXY(cx-x, cy-y, col); - setPixelColorXY(cx+y, cy+x, col); - setPixelColorXY(cx-y, cy+x, col); - setPixelColorXY(cx+y, cy-x, col); - setPixelColorXY(cx-y, cy-x, col); - x++; - if (d > 0) { - y--; - d += 4 * (x - y) + 10; - } else { - d += 4 * x + 6; +void Segment::drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) { + if (!isActive() || radius == 0) return; // not active + if (soft) { + // Xiaolin Wu’s algorithm + int rsq = radius*radius; + int x = 0; + int y = radius; + unsigned oldFade = 0; + while (x < y) { + float yf = sqrtf(float(rsq - x*x)); // needs to be floating point + unsigned fade = float(0xFFFF) * (ceilf(yf) - yf); // how much color to keep + if (oldFade > fade) y--; + oldFade = fade; + setPixelColorXY(cx+x, cy+y, color_blend(col, getPixelColorXY(cx+x, cy+y), fade, true)); + setPixelColorXY(cx-x, cy+y, color_blend(col, getPixelColorXY(cx-x, cy+y), fade, true)); + setPixelColorXY(cx+x, cy-y, color_blend(col, getPixelColorXY(cx+x, cy-y), fade, true)); + setPixelColorXY(cx-x, cy-y, color_blend(col, getPixelColorXY(cx-x, cy-y), fade, true)); + setPixelColorXY(cx+y, cy+x, color_blend(col, getPixelColorXY(cx+y, cy+x), fade, true)); + setPixelColorXY(cx-y, cy+x, color_blend(col, getPixelColorXY(cx-y, cy+x), fade, true)); + setPixelColorXY(cx+y, cy-x, color_blend(col, getPixelColorXY(cx+y, cy-x), fade, true)); + setPixelColorXY(cx-y, cy-x, color_blend(col, getPixelColorXY(cx-y, cy-x), fade, true)); + setPixelColorXY(cx+x, cy+y-1, color_blend(getPixelColorXY(cx+x, cy+y-1), col, fade, true)); + setPixelColorXY(cx-x, cy+y-1, color_blend(getPixelColorXY(cx-x, cy+y-1), col, fade, true)); + setPixelColorXY(cx+x, cy-y+1, color_blend(getPixelColorXY(cx+x, cy-y+1), col, fade, true)); + setPixelColorXY(cx-x, cy-y+1, color_blend(getPixelColorXY(cx-x, cy-y+1), col, fade, true)); + setPixelColorXY(cx+y-1, cy+x, color_blend(getPixelColorXY(cx+y-1, cy+x), col, fade, true)); + setPixelColorXY(cx-y+1, cy+x, color_blend(getPixelColorXY(cx-y+1, cy+x), col, fade, true)); + setPixelColorXY(cx+y-1, cy-x, color_blend(getPixelColorXY(cx+y-1, cy-x), col, fade, true)); + setPixelColorXY(cx-y+1, cy-x, color_blend(getPixelColorXY(cx-y+1, cy-x), col, fade, true)); + x++; + } + } else { + // Bresenham’s Algorithm + int d = 3 - (2*radius); + int y = radius, x = 0; + while (y >= x) { + setPixelColorXY(cx+x, cy+y, col); + setPixelColorXY(cx-x, cy+y, col); + setPixelColorXY(cx+x, cy-y, col); + setPixelColorXY(cx-x, cy-y, col); + setPixelColorXY(cx+y, cy+x, col); + setPixelColorXY(cx-y, cy+x, col); + setPixelColorXY(cx+y, cy-x, col); + setPixelColorXY(cx-y, cy-x, col); + x++; + if (d > 0) { + y--; + d += 4 * (x - y) + 10; + } else { + d += 4 * x + 6; + } } } } // by stepko, taken from https://editor.soulmatelights.com/gallery/573-blobs -void Segment::fill_circle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB col) { - if (!isActive()) return; // not active - const uint16_t cols = virtualWidth(); - const uint16_t rows = virtualHeight(); - for (int16_t y = -radius; y <= radius; y++) { - for (int16_t x = -radius; x <= radius; x++) { +void Segment::fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t col, bool soft) { + if (!isActive() || radius == 0) return; // not active + // draw soft bounding circle + if (soft) drawCircle(cx, cy, radius, col, soft); + // fill it + const int cols = virtualWidth(); + const int rows = virtualHeight(); + for (int y = -radius; y <= radius; y++) { + for (int x = -radius; x <= radius; x++) { if (x * x + y * y <= radius * radius && int16_t(cx)+x>=0 && int16_t(cy)+y>=0 && int16_t(cx)+x= cols || x1 >= cols || y0 >= rows || y1 >= rows) return; - const int16_t dx = abs(x1-x0), sx = x0dy ? dx : -dy)/2, e2; - for (;;) { - setPixelColorXY(x0,y0,c); - if (x0==x1 && y0==y1) break; - e2 = err; - if (e2 >-dx) { err -= dy; x0 += sx; } - if (e2 < dy) { err += dx; y0 += sy; } + + const int dx = abs(x1-x0), sx = x0 dx; + if (steep) { + // we need to go along longest dimension + std::swap(x0,y0); + std::swap(x1,y1); + } + if (x0 > x1) { + // we need to go in increasing fashion + std::swap(x0,x1); + std::swap(y0,y1); + } + float gradient = x1-x0 == 0 ? 1.0f : float(y1-y0) / float(x1-x0); + float intersectY = y0; + for (int x = x0; x <= x1; x++) { + unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep + unsigned seep = 0xFFFF - keep; // how much background to keep + int y = int(intersectY); + if (steep) std::swap(x,y); // temporaryly swap if steep + // pixel coverage is determined by fractional part of y co-ordinate + setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true)); + setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true)); + intersectY += gradient; + if (steep) std::swap(x,y); // restore if steep + } + } else { + // Bresenham's algorithm + int err = (dx>dy ? dx : -dy)/2; // error direction + for (;;) { + setPixelColorXY(x0, y0, c); + if (x0==x1 && y0==y1) break; + int e2 = err; + if (e2 >-dx) { err -= dy; x0 += sx; } + if (e2 < dy) { err += dx; y0 += sy; } + } } } From c07658a7cbcf8adffb39b5b2543e2f91e0fb40e3 Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 26 Jun 2024 23:41:38 +0200 Subject: [PATCH 13/19] post-merge * fix drawLine prototype * a few more "inline" * typo --- wled00/FX.h | 30 +++++++++++++++--------------- wled00/FX_2Dfcn.cpp | 2 +- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/wled00/FX.h b/wled00/FX.h index b53f3fce..4772dbe7 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -618,11 +618,11 @@ typedef struct Segment { // 1D strip uint16_t virtualLength(void) const; void setPixelColor(int n, uint32_t c); // set relative pixel within segment with color - void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline - void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } // automatically inline + inline void setPixelColor(int n, byte r, byte g, byte b, byte w = 0) { setPixelColor(n, RGBW32(r,g,b,w)); } // automatically inline + inline void setPixelColor(int n, CRGB c) { setPixelColor(n, RGBW32(c.r,c.g,c.b,0)); } // automatically inline void setPixelColor(float i, uint32_t c, bool aa = true); - void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } - void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } + inline void setPixelColor(float i, uint8_t r, uint8_t g, uint8_t b, uint8_t w = 0, bool aa = true) { setPixelColor(i, RGBW32(r,g,b,w), aa); } + inline void setPixelColor(float i, CRGB c, bool aa = true) { setPixelColor(i, RGBW32(c.r,c.g,c.b,0), aa); } uint32_t __attribute__((pure)) getPixelColor(int i); // WLEDMM attribute added // 1D support functions (some implement 2D as well) void blur(uint8_t, bool smear = false); @@ -630,10 +630,10 @@ typedef struct Segment { void fade_out(uint8_t r); void fadeToBlackBy(uint8_t fadeBy); void blendPixelColor(int n, uint32_t color, uint8_t blend); - void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } + inline void blendPixelColor(int n, CRGB c, uint8_t blend) { blendPixelColor(n, RGBW32(c.r,c.g,c.b,0), blend); } void addPixelColor(int n, uint32_t color, bool fast = false); - void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline - void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline + inline void addPixelColor(int n, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColor(n, RGBW32(r,g,b,w), fast); } // automatically inline + inline void addPixelColor(int n, CRGB c, bool fast = false) { addPixelColor(n, RGBW32(c.r,c.g,c.b,0), fast); } // automatically inline void fadePixelColor(uint16_t n, uint8_t fade); uint8_t get_random_wheel_index(uint8_t pos); uint32_t __attribute__((pure)) color_from_palette(uint_fast16_t, bool mapping, bool wrap, uint8_t mcol, uint8_t pbri = 255); @@ -678,10 +678,10 @@ typedef struct Segment { uint32_t __attribute__((pure)) getPixelColorXY(int x, int y); // 2D support functions void blendPixelColorXY(uint16_t x, uint16_t y, uint32_t color, uint8_t blend); - 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); } + 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); } void addPixelColorXY(int x, int y, uint32_t color, bool fast = false); - void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); } // automatically inline - void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); } + inline void addPixelColorXY(int x, int y, byte r, byte g, byte b, byte w = 0, bool fast = false) { addPixelColorXY(x, y, RGBW32(r,g,b,w), fast); } // automatically inline + inline void addPixelColorXY(int x, int y, CRGB c, bool fast = false) { addPixelColorXY(x, y, RGBW32(c.r,c.g,c.b,0), fast); } void fadePixelColorXY(uint16_t x, uint16_t y, uint8_t fade); void box_blur(uint16_t i, bool vertical, fract8 blur_amount); // 1D box blur (with weight) void blurRow(uint32_t row, fract8 blur_amount, bool smear = false); @@ -693,16 +693,16 @@ typedef struct Segment { inline void drawCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { drawCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, uint32_t c, bool soft = false); inline void fillCircle(uint16_t cx, uint16_t cy, uint8_t radius, CRGB c, bool soft = false) { fillCircle(cx, cy, radius, RGBW32(c.r,c.g,c.b,0), soft); } - void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c); - void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0)); } // automatic inline + void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint32_t c, bool soft = false); + inline void drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, CRGB c, bool soft = false) { drawLine(x0, y0, x1, y1, RGBW32(c.r,c.g,c.b,0), soft); } // automatic inline void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, uint32_t color, uint32_t fillColor = 0); - void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // automatic inline + inline void drawArc(uint16_t x0, uint16_t y0, uint16_t radius, CRGB color, CRGB fillColor = BLACK) { drawArc(x0, y0, radius, RGBW32(color.r,color.g,color.b,0), RGBW32(fillColor.r,fillColor.g,fillColor.b,0)); } // automatic inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, uint32_t color, uint32_t col2 = 0); - void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline + inline void drawCharacter(unsigned char chr, int16_t x, int16_t y, uint8_t w, uint8_t h, CRGB c, CRGB c2) { drawCharacter(chr, x, y, w, h, RGBW32(c.r,c.g,c.b,0), RGBW32(c2.r,c2.g,c2.b,0)); } // automatic inline void wu_pixel(uint32_t x, uint32_t y, CRGB c); //void blur1d(fract8 blur_amount); // blur all rows in 1 dimension void blur2d(fract8 blur_amount) { blur(blur_amount); } - void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } + inline void fill_solid(CRGB c) { fill(RGBW32(c.r,c.g,c.b,0)); } void nscale8(uint8_t scale); bool jsonToPixels(char *name, uint8_t fileNr); //WLEDMM for artifx #else diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 320636d6..061d8c19 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -632,7 +632,7 @@ void Segment::drawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint3 unsigned keep = float(0xFFFF) * (intersectY-int(intersectY)); // how much color to keep unsigned seep = 0xFFFF - keep; // how much background to keep int y = int(intersectY); - if (steep) std::swap(x,y); // temporaryly swap if steep + if (steep) std::swap(x,y); // temporarily swap if steep // pixel coverage is determined by fractional part of y co-ordinate setPixelColorXY(x, y, color_blend(c, getPixelColorXY(x, y), keep, true)); setPixelColorXY(x+int(steep), y+int(!steep), color_blend(c, getPixelColorXY(x+int(steep), y+int(!steep)), seep, true)); From 28cb5c88b6efffb6f618b069cd1561ff2385ea73 Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:20:44 -0400 Subject: [PATCH 14/19] Skeleton, not working yet. --- usermods/audioreactive/audio_reactive.h | 22 +++ usermods/audioreactive/audio_source.h | 174 ++++++++++++++++++++++++ 2 files changed, 196 insertions(+) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index b958184c..ff1c9ed5 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -1923,6 +1923,23 @@ class AudioReactive : public Usermod { if (i2c_sda >= 0) sdaPin = -1; // -1 = use global if (i2c_scl >= 0) sclPin = -1; + if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); + break; + case 8: + #ifdef use_ac101_mic + DEBUGSR_PRINTLN(F("AR: AC101 Source (Mic)")); + #else + DEBUGSR_PRINTLN(F("AR: AC101 Source (Line-In)")); + #endif + audioSource = new AC101Source(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; @@ -2802,6 +2819,11 @@ class AudioReactive : public Usermod { #else oappend(SET_F("addOption(dd,'WM8978 ☾',7);")); #endif + #if SR_DMTYPE==8 + oappend(SET_F("addOption(dd,'AC101 ☾ (⎌)',8);")); + #else + oappend(SET_F("addOption(dd,'AC101 ☾',8);")); + #endif #ifdef SR_SQUELCH oappend(SET_F("addInfo('AudioReactive: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 cf3e3b74..c83af476 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -736,6 +736,180 @@ class WM8978Source : public I2SSource { }; +class AC101Source : public I2SSource { + private: + // I2C initialization functions for WM8978 + void _ac101I2cBegin() { + Wire.setClock(400000); + } + + void _ac101I2cWrite(uint8_t reg_addr, uint16_t val) { + #ifndef AC101_ADDR + #define AC101_ADDR 0x1A + #endif + char send_buff[3]; + send_buff[0] = reg_addr; + send_buff[1] = (val >> 8) & 0xff; + send_buff[2] = val & 0xff; + Wire.beginTransmission(AC101_ADDR); + Wire.write((const uint8_t*)send_buff, 3); + uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK + if (i2cErr != 0) { + DEBUGSR_PRINTF("AR: AC101 I2C write failed with error=%d (addr=0x%X, reg 0x%X, val 0x%X).\n", i2cErr, AC101_ADDR, reg_addr, val); + } + } + + void _ac101InitAdc() { + // https://files.seeedstudio.com/wiki/ReSpeaker_6-Mics_Circular_Array_kit_for_Raspberry_Pi/reg/AC101_User_Manual_v1.1.pdf + // + _ac101I2cBegin(); + + #define CHIP_AUDIO_RS 0x00 + #define PLL_CTRL1 0x01 + #define PLL_CTRL2 0x02 + #define SYSCLK_CTRL 0x03 + #define MOD_CLK_ENA 0x04 + #define MOD_RST_CTRL 0x05 + #define I2S_SR_CTRL 0x06 + #define I2S1LCK_CTRL 0x10 + #define I2S1_SDOUT_CTRL 0x11 + #define I2S1_SDIN_CTRL 0x12 + #define I2S1_MXR_SRC 0x13 + #define I2S1_VOL_CTRL1 0x14 + #define I2S1_VOL_CTRL2 0x15 + #define I2S1_VOL_CTRL3 0x16 + #define I2S1_VOL_CTRL4 0x17 + #define I2S1_MXR_GAIN 0x18 + #define ADC_DIG_CTRL 0x40 + #define ADC_VOL_CTRL 0x41 + #define HMIC_CTRL1 0x44 + #define HMIC_CTRL2 0x45 + #define HMIC_STATUS 0x46 + #define DAC_DIG_CTRL 0x48 + #define DAC_VOL_CTRL 0x49 + #define DAC_MXR_SRC 0x4c + #define DAC_MXR_GAIN 0x4d + #define ADC_APC_CTRL 0x50 + #define ADC_SRC 0x51 + #define ADC_SRCBST_CTRL 0x52 + #define OMIXER_DACA_CTRL 0x53 + #define OMIXER_SR 0x54 + #define OMIXER_BST1_CTRL 0x55 + #define HPOUT_CTRL 0x56 + #define SPKOUT_CTRL 0x58 + #define AC_DAC_DAPCTRL 0xa0 + #define AC_DAC_DAPHHPFC 0xa1 + #define AC_DAC_DAPLHPFC 0xa2 + #define AC_DAC_DAPLHAVC 0xa3 + #define AC_DAC_DAPLLAVC 0xa4 + #define AC_DAC_DAPRHAVC 0xa5 + #define AC_DAC_DAPRLAVC 0xa6 + #define AC_DAC_DAPHGDEC 0xa7 + #define AC_DAC_DAPLGDEC 0xa8 + #define AC_DAC_DAPHGATC 0xa9 + #define AC_DAC_DAPLGATC 0xaa + #define AC_DAC_DAPHETHD 0xab + #define AC_DAC_DAPLETHD 0xac + #define AC_DAC_DAPHGKPA 0xad + #define AC_DAC_DAPLGKPA 0xae + #define AC_DAC_DAPHGOPA 0xaf + #define AC_DAC_DAPLGOPA 0xb0 + #define AC_DAC_DAPOPT 0xb1 + #define DAC_DAP_ENA 0xb5 + + _ac101I2cWrite(CHIP_AUDIO_RS, 0x123); // Reset (any value written does a reset) + vTaskDelay(1000 / portTICK_PERIOD_MS); + _ac101I2cWrite(SPKOUT_CTRL, 0xe880); + + //Enable the PLL from 256*44.1KHz MCLK source + _ac101I2cWrite(PLL_CTRL1, 0x014f); + //res |= ac101_write_reg(PLL_CTRL2, 0x83c0); + _ac101I2cWrite(PLL_CTRL2, 0x8600); + + //Clocking system + _ac101I2cWrite(SYSCLK_CTRL, 0x8b08); + _ac101I2cWrite(MOD_CLK_ENA, 0x800c); + _ac101I2cWrite(MOD_RST_CTRL, 0x800c); + _ac101I2cWrite(I2S_SR_CTRL, 0b0111000000000000); //sample rate 22050 Hz + //AIF config + _ac101I2cWrite(I2S1LCK_CTRL, 0x8850); //BCLK/LRCK + _ac101I2cWrite(I2S1_SDOUT_CTRL, 0xc000); // + _ac101I2cWrite(I2S1_SDIN_CTRL, 0xc000); + _ac101I2cWrite(I2S1_MXR_SRC, 0x2200); // + + _ac101I2cWrite(ADC_SRCBST_CTRL, 0xccc4); + _ac101I2cWrite(ADC_SRC, 0x2020); + _ac101I2cWrite(ADC_DIG_CTRL, 0x8000); + _ac101I2cWrite(ADC_APC_CTRL, 0xbbc3); + + //Path Configuration + _ac101I2cWrite(DAC_MXR_SRC, 0xcc00); + _ac101I2cWrite(DAC_DIG_CTRL, 0x8000); + _ac101I2cWrite(OMIXER_SR, 0x0081); + _ac101I2cWrite(OMIXER_DACA_CTRL, 0xf080); //} + + //* Enable Speaker output + // _ac101I2cWrite(0x58, 0xeabd); + + _ac101I2cWrite(ADC_SRC, 0b0000010000001000); // Line-in to ADC + _ac101I2cWrite(ADC_DIG_CTRL, 0x8000); + _ac101I2cWrite(ADC_APC_CTRL, 0x3bc0); + //I2S1_SDOUT_CTRL + //res |= _ac101I2cWrite(PLL_CTRL2, 0x8120); + _ac101I2cWrite(MOD_CLK_ENA, 0x800c); + _ac101I2cWrite(MOD_RST_CTRL, 0x800c); + //res |= _ac101I2cWrite(0x06, 0x3000); + //* Enable Headphoe output + _ac101I2cWrite(OMIXER_DACA_CTRL, 0xff80); + _ac101I2cWrite(HPOUT_CTRL, 0xc3c1); + _ac101I2cWrite(HPOUT_CTRL, 0xcb00); + vTaskDelay(100 / portTICK_PERIOD_MS); + _ac101I2cWrite(HPOUT_CTRL, 0xfbc0); + + _ac101I2cWrite(OMIXER_SR, 0b0000010000001000); // default all 0 + + //* Enable Speaker output + _ac101I2cWrite(SPKOUT_CTRL, 0xeabd); + + + } + + public: + AC101Source(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("AC101Source:: initialize();"); + + // if ((i2sckPin < 0) || (mclkPin < 0)) { // WLEDMM not sure if this check is needed here, too + // ERRORSR_PRINTF("\nAR: invalid I2S WM8978 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 AC101 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 + _ac101InitAdc(); + I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); + } + + void deinitialize() { + I2SSource::deinitialize(); + } + +}; + #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 2, 0) #if !defined(SOC_I2S_SUPPORTS_ADC) && !defined(SOC_I2S_SUPPORTS_ADC_DAC) #warning this MCU does not support analog sound input From 60fbf07bcad983344c63ebd1dcf47708050d3daa Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Wed, 10 Jul 2024 23:01:21 +0100 Subject: [PATCH 15/19] Fix mx_width and height for 4scan --- wled00/bus_manager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/wled00/bus_manager.cpp b/wled00/bus_manager.cpp index 2bd0a338..9ad6c948 100644 --- a/wled00/bus_manager.cpp +++ b/wled00/bus_manager.cpp @@ -513,6 +513,10 @@ BusHub75Matrix::BusHub75Matrix(BusConfig &bc) : Bus(bc.type, bc.start, bc.autoWh mxconfig.mx_height = 32 / 2; break; case 106: + mxconfig.mx_width = 64 * 2; + mxconfig.mx_height = 32 / 2; + break; + case 107: mxconfig.mx_width = 64 * 2; mxconfig.mx_height = 64 / 2; break; From 1fe871c42ce73463fb0177d118419f26e14aa57a Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 10 Jul 2024 18:54:02 -0400 Subject: [PATCH 16/19] Fully working with analog loopthru --- usermods/audioreactive/audio_source.h | 111 +++++--------------------- 1 file changed, 19 insertions(+), 92 deletions(-) diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index c83af476..f8156fe7 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -749,8 +749,8 @@ class AC101Source : public I2SSource { #endif char send_buff[3]; send_buff[0] = reg_addr; - send_buff[1] = (val >> 8) & 0xff; - send_buff[2] = val & 0xff; + send_buff[1] = uint8_t((val >> 8) & 0xff); + send_buff[2] = uint8_t(val & 0xff); Wire.beginTransmission(AC101_ADDR); Wire.write((const uint8_t*)send_buff, 3); uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK @@ -765,112 +765,39 @@ class AC101Source : public I2SSource { _ac101I2cBegin(); #define CHIP_AUDIO_RS 0x00 - #define PLL_CTRL1 0x01 - #define PLL_CTRL2 0x02 #define SYSCLK_CTRL 0x03 #define MOD_CLK_ENA 0x04 #define MOD_RST_CTRL 0x05 #define I2S_SR_CTRL 0x06 #define I2S1LCK_CTRL 0x10 #define I2S1_SDOUT_CTRL 0x11 - #define I2S1_SDIN_CTRL 0x12 #define I2S1_MXR_SRC 0x13 - #define I2S1_VOL_CTRL1 0x14 - #define I2S1_VOL_CTRL2 0x15 - #define I2S1_VOL_CTRL3 0x16 - #define I2S1_VOL_CTRL4 0x17 - #define I2S1_MXR_GAIN 0x18 #define ADC_DIG_CTRL 0x40 - #define ADC_VOL_CTRL 0x41 - #define HMIC_CTRL1 0x44 - #define HMIC_CTRL2 0x45 - #define HMIC_STATUS 0x46 - #define DAC_DIG_CTRL 0x48 - #define DAC_VOL_CTRL 0x49 - #define DAC_MXR_SRC 0x4c - #define DAC_MXR_GAIN 0x4d #define ADC_APC_CTRL 0x50 #define ADC_SRC 0x51 #define ADC_SRCBST_CTRL 0x52 #define OMIXER_DACA_CTRL 0x53 #define OMIXER_SR 0x54 - #define OMIXER_BST1_CTRL 0x55 #define HPOUT_CTRL 0x56 - #define SPKOUT_CTRL 0x58 - #define AC_DAC_DAPCTRL 0xa0 - #define AC_DAC_DAPHHPFC 0xa1 - #define AC_DAC_DAPLHPFC 0xa2 - #define AC_DAC_DAPLHAVC 0xa3 - #define AC_DAC_DAPLLAVC 0xa4 - #define AC_DAC_DAPRHAVC 0xa5 - #define AC_DAC_DAPRLAVC 0xa6 - #define AC_DAC_DAPHGDEC 0xa7 - #define AC_DAC_DAPLGDEC 0xa8 - #define AC_DAC_DAPHGATC 0xa9 - #define AC_DAC_DAPLGATC 0xaa - #define AC_DAC_DAPHETHD 0xab - #define AC_DAC_DAPLETHD 0xac - #define AC_DAC_DAPHGKPA 0xad - #define AC_DAC_DAPLGKPA 0xae - #define AC_DAC_DAPHGOPA 0xaf - #define AC_DAC_DAPLGOPA 0xb0 - #define AC_DAC_DAPOPT 0xb1 - #define DAC_DAP_ENA 0xb5 - _ac101I2cWrite(CHIP_AUDIO_RS, 0x123); // Reset (any value written does a reset) - vTaskDelay(1000 / portTICK_PERIOD_MS); - _ac101I2cWrite(SPKOUT_CTRL, 0xe880); - - //Enable the PLL from 256*44.1KHz MCLK source - _ac101I2cWrite(PLL_CTRL1, 0x014f); - //res |= ac101_write_reg(PLL_CTRL2, 0x83c0); - _ac101I2cWrite(PLL_CTRL2, 0x8600); - - //Clocking system - _ac101I2cWrite(SYSCLK_CTRL, 0x8b08); - _ac101I2cWrite(MOD_CLK_ENA, 0x800c); - _ac101I2cWrite(MOD_RST_CTRL, 0x800c); - _ac101I2cWrite(I2S_SR_CTRL, 0b0111000000000000); //sample rate 22050 Hz - //AIF config - _ac101I2cWrite(I2S1LCK_CTRL, 0x8850); //BCLK/LRCK - _ac101I2cWrite(I2S1_SDOUT_CTRL, 0xc000); // - _ac101I2cWrite(I2S1_SDIN_CTRL, 0xc000); - _ac101I2cWrite(I2S1_MXR_SRC, 0x2200); // - - _ac101I2cWrite(ADC_SRCBST_CTRL, 0xccc4); - _ac101I2cWrite(ADC_SRC, 0x2020); - _ac101I2cWrite(ADC_DIG_CTRL, 0x8000); - _ac101I2cWrite(ADC_APC_CTRL, 0xbbc3); - - //Path Configuration - _ac101I2cWrite(DAC_MXR_SRC, 0xcc00); - _ac101I2cWrite(DAC_DIG_CTRL, 0x8000); - _ac101I2cWrite(OMIXER_SR, 0x0081); - _ac101I2cWrite(OMIXER_DACA_CTRL, 0xf080); //} - - //* Enable Speaker output - // _ac101I2cWrite(0x58, 0xeabd); - - _ac101I2cWrite(ADC_SRC, 0b0000010000001000); // Line-in to ADC - _ac101I2cWrite(ADC_DIG_CTRL, 0x8000); - _ac101I2cWrite(ADC_APC_CTRL, 0x3bc0); - //I2S1_SDOUT_CTRL - //res |= _ac101I2cWrite(PLL_CTRL2, 0x8120); - _ac101I2cWrite(MOD_CLK_ENA, 0x800c); - _ac101I2cWrite(MOD_RST_CTRL, 0x800c); - //res |= _ac101I2cWrite(0x06, 0x3000); - //* Enable Headphoe output - _ac101I2cWrite(OMIXER_DACA_CTRL, 0xff80); - _ac101I2cWrite(HPOUT_CTRL, 0xc3c1); - _ac101I2cWrite(HPOUT_CTRL, 0xcb00); - vTaskDelay(100 / portTICK_PERIOD_MS); - _ac101I2cWrite(HPOUT_CTRL, 0xfbc0); - - _ac101I2cWrite(OMIXER_SR, 0b0000010000001000); // default all 0 - - //* Enable Speaker output - _ac101I2cWrite(SPKOUT_CTRL, 0xeabd); + _ac101I2cWrite(CHIP_AUDIO_RS, 0x123); // I think anything written here is a reset as 0x123 is kinda suss. + + delay(100); + _ac101I2cWrite(SYSCLK_CTRL, 0b0000100000001000); // System Clock is I2S MCLK + _ac101I2cWrite(MOD_CLK_ENA, 0b1000000000001000); // I2S and ADC Clock Enable + _ac101I2cWrite(MOD_RST_CTRL, 0b1000000000001000); // I2S and ADC Clock Enable + _ac101I2cWrite(I2S_SR_CTRL, 0b0100000000000000); // set to 22050hz just in case + _ac101I2cWrite(I2S1LCK_CTRL, 0b1000000000110000); // set I2S slave mode, 24-bit word size + _ac101I2cWrite(I2S1_SDOUT_CTRL, 0b1100000000000000); // I2S enable Left/Right channels + _ac101I2cWrite(I2S1_MXR_SRC, 0b0010001000000000); // I2S digital Mixer, ADC L/R data + _ac101I2cWrite(ADC_SRCBST_CTRL, 0b0000000000000100); // mute all boosts. last 3 bits are reserved/default + _ac101I2cWrite(OMIXER_SR, 0b0000010000001000); // Line L/R to output mixer + _ac101I2cWrite(ADC_SRC, 0b0000010000001000); // Line L/R to ADC + _ac101I2cWrite(ADC_DIG_CTRL, 0b1000000000000000); // Enable ADC + _ac101I2cWrite(ADC_APC_CTRL, 0b1011100100000000); // ADC L/R enabled, 0dB gain + _ac101I2cWrite(OMIXER_DACA_CTRL, 0b0011111110000000); // L/R Analog Output Mixer enabled, headphone DC offset default + _ac101I2cWrite(HPOUT_CTRL, 0b1111101111110001); // Headphone out from Analog Mixer stage, no reduction in volume } From f7e2f14ca4badfcbd8e45bbd88e752926ae3751d Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:03:38 -0400 Subject: [PATCH 17/19] Minor tab and comment clean-up. --- usermods/audioreactive/audio_source.h | 36 ++++++++++++++------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/usermods/audioreactive/audio_source.h b/usermods/audioreactive/audio_source.h index f8156fe7..d7c0478c 100644 --- a/usermods/audioreactive/audio_source.h +++ b/usermods/audioreactive/audio_source.h @@ -761,27 +761,29 @@ class AC101Source : public I2SSource { void _ac101InitAdc() { // https://files.seeedstudio.com/wiki/ReSpeaker_6-Mics_Circular_Array_kit_for_Raspberry_Pi/reg/AC101_User_Manual_v1.1.pdf - // - _ac101I2cBegin(); + // This supports mostly the older AI Thinkier AudioKit A1S that has an AC101 chip + // Newer versions use the ES3833 chip - which we also support. - #define CHIP_AUDIO_RS 0x00 - #define SYSCLK_CTRL 0x03 - #define MOD_CLK_ENA 0x04 - #define MOD_RST_CTRL 0x05 - #define I2S_SR_CTRL 0x06 - #define I2S1LCK_CTRL 0x10 - #define I2S1_SDOUT_CTRL 0x11 - #define I2S1_MXR_SRC 0x13 - #define ADC_DIG_CTRL 0x40 - #define ADC_APC_CTRL 0x50 - #define ADC_SRC 0x51 - #define ADC_SRCBST_CTRL 0x52 + _ac101I2cBegin(); + + #define CHIP_AUDIO_RS 0x00 + #define SYSCLK_CTRL 0x03 + #define MOD_CLK_ENA 0x04 + #define MOD_RST_CTRL 0x05 + #define I2S_SR_CTRL 0x06 + #define I2S1LCK_CTRL 0x10 + #define I2S1_SDOUT_CTRL 0x11 + #define I2S1_MXR_SRC 0x13 + #define ADC_DIG_CTRL 0x40 + #define ADC_APC_CTRL 0x50 + #define ADC_SRC 0x51 + #define ADC_SRCBST_CTRL 0x52 #define OMIXER_DACA_CTRL 0x53 - #define OMIXER_SR 0x54 - #define HPOUT_CTRL 0x56 + #define OMIXER_SR 0x54 + #define HPOUT_CTRL 0x56 _ac101I2cWrite(CHIP_AUDIO_RS, 0x123); // I think anything written here is a reset as 0x123 is kinda suss. - + delay(100); _ac101I2cWrite(SYSCLK_CTRL, 0b0000100000001000); // System Clock is I2S MCLK From 1c33a4bbea66b2bf6f6e002afe11e8551fe5dcbf Mon Sep 17 00:00:00 2001 From: Troy <5659019+troyhacks@users.noreply.github.com> Date: Wed, 10 Jul 2024 19:08:58 -0400 Subject: [PATCH 18/19] Remove references to AC101 mic mode (not implemented) --- usermods/audioreactive/audio_reactive.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/usermods/audioreactive/audio_reactive.h b/usermods/audioreactive/audio_reactive.h index ea43aa60..f7c91594 100644 --- a/usermods/audioreactive/audio_reactive.h +++ b/usermods/audioreactive/audio_reactive.h @@ -2013,11 +2013,7 @@ class AudioReactive : public Usermod { if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin); break; case 8: - #ifdef use_ac101_mic - DEBUGSR_PRINTLN(F("AR: AC101 Source (Mic)")); - #else DEBUGSR_PRINTLN(F("AR: AC101 Source (Line-In)")); - #endif audioSource = new AC101Source(SAMPLE_RATE, BLOCK_SIZE, 1.0f); //useInputFilter = 0; // to disable low-cut software filtering and restore previous behaviour delay(100); From 346914b9657ac64600df21b48a8198c8df0ca4d1 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 13 Jul 2024 01:37:43 +0200 Subject: [PATCH 19/19] setPixelColorXY small optimizations Caching a few segment vars gives a 5% speedup on big setups. Its 2024, and compilers are still stupid :-P --- wled00/FX_2Dfcn.cpp | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/wled00/FX_2Dfcn.cpp b/wled00/FX_2Dfcn.cpp index 061d8c19..cc91c2cf 100644 --- a/wled00/FX_2Dfcn.cpp +++ b/wled00/FX_2Dfcn.cpp @@ -214,7 +214,10 @@ uint32_t WS2812FX::getPixelColorXY(uint16_t x, uint16_t y) { void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: IRAM_ATTR conditionally { if (Segment::maxHeight==1) return; // not a matrix set-up - if (x<0 || y<0 || x >= virtualWidth() || y >= virtualHeight()) return; // if pixel would fall out of virtual segment just exit + const int_fast16_t cols = virtualWidth(); // WLEDMM optimization + const int_fast16_t rows = virtualHeight(); + + if (x<0 || y<0 || x >= cols || y >= rows) return; // if pixel would fall out of virtual segment just exit unsigned i = UINT_MAX; bool sameColor = false; @@ -231,11 +234,11 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: } #if 0 // this is a dangerous optimization - if ((i < UINT_MAX) && sameColor && (call > 0) && (ledsrgb[i] == CRGB(col)) && (_globalLeds == nullptr)) return; // WLEDMM looks like nothing to do (but we don't trust globalleds) + if ((i < UINT_MAX) && sameColor && (call > 0) && (!transitional) && (ledsrgb[i] == CRGB(col)) && (_globalLeds == nullptr)) return; // WLEDMM looks like nothing to do (but we don't trust globalleds) #endif - if (reverse ) x = virtualWidth() - x - 1; - if (reverse_y) y = virtualHeight() - y - 1; + if (reverse ) x = cols - x - 1; + if (reverse_y) y = rows - y - 1; if (transpose) { uint16_t t = x; x = y; y = t; } // swap X & Y if segment transposed // WLEDMM shortcut when no grouping/spacing used @@ -245,27 +248,32 @@ void IRAM_ATTR_YN Segment::setPixelColorXY(int x, int y, uint32_t col) //WLEDMM: return; } - x *= groupLength(); // expand to physical pixels - y *= groupLength(); // expand to physical pixels - if (x >= width() || y >= height()) return; // if pixel would fall out of segment just exit + const int_fast16_t glen_ = groupLength(); // WLEDMM optimization + const int_fast16_t wid_ = width(); + const int_fast16_t hei_ = height(); - for (int j = 0; j < grouping; j++) { // groupping vertically - for (int g = 0; g < grouping; g++) { // groupping horizontally + x *= glen_; // expand to physical pixels + y *= glen_; // expand to physical pixels + if (x >= wid_ || y >= hei_) return; // if pixel would fall out of segment just exit + + const int grp_ = grouping; // WLEDMM optimization + for (int j = 0; j < grp_; j++) { // groupping vertically + for (int g = 0; g < grp_; g++) { // groupping horizontally uint_fast16_t xX = (x+g), yY = (y+j); //WLEDMM: use fast types - if (xX >= width() || yY >= height()) continue; // we have reached one dimension's end + if (xX >= wid_ || yY >= hei_) continue; // we have reached one dimension's end strip.setPixelColorXY(start + xX, startY + yY, col); if (mirror) { //set the corresponding horizontally mirrored pixel - if (transpose) strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); - else strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); + if (transpose) strip.setPixelColorXY(start + xX, startY + hei_ - yY - 1, col); + else strip.setPixelColorXY(start + wid_ - xX - 1, startY + yY, col); } if (mirror_y) { //set the corresponding vertically mirrored pixel - if (transpose) strip.setPixelColorXY(start + width() - xX - 1, startY + yY, col); - else strip.setPixelColorXY(start + xX, startY + height() - yY - 1, col); + if (transpose) strip.setPixelColorXY(start + wid_ - xX - 1, startY + yY, col); + else strip.setPixelColorXY(start + xX, startY + hei_ - yY - 1, col); } if (mirror_y && mirror) { //set the corresponding vertically AND horizontally mirrored pixel - strip.setPixelColorXY(width() - xX - 1, height() - yY - 1, col); + strip.setPixelColorXY(wid_ - xX - 1, hei_ - yY - 1, col); } } }