Skip to content

Comments

FastLED audio#130

Open
ewowi wants to merge 3 commits intomainfrom
FastLED-audio
Open

FastLED audio#130
ewowi wants to merge 3 commits intomainfrom
FastLED-audio

Conversation

@ewowi
Copy link
Collaborator

@ewowi ewowi commented Feb 22, 2026

Summary by CodeRabbit

  • New Features

    • Audio-responsive LED driver and a new audio-reactive visual effect with beat, vocal and frequency signals.
    • New "Tubes" layout option for arranging LEDs in tube/grid patterns.
  • Improvements

    • Waterfall effect updated for true 3D column-based rendering.
    • Shared telemetry expanded with vocal, bass, treble and beat metrics.
    • Stability tweaks for audio processing runtime.

Backend
=======
- Add D_FastLEDAudio.h
Add FastLED audio variables to SharedData - WIP
- Add Tubes Layout
- Add FastLEDAudioDriver
- Add FLAudioEffect
@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

 ________________________________________________________________________________
< Please don't use comments to explain what code should be doing. Make it do it. >
 --------------------------------------------------------------------------------
  \
   \   \
        \ /\
        ( )
      .( o ).

✏️ Tip: You can disable in-progress messages and the fortune message in your review settings.

Tip

CodeRabbit can scan for known vulnerabilities in your dependencies using OSV Scanner.

OSV Scanner will automatically detect and report security vulnerabilities in your project's dependencies. No additional configuration is required.

Walkthrough

Adds FastLED audio support: new I2S-based FastLEDAudioDriver that populates new shared audio fields, a reactive FLAudioEffect, a TubesLayout, registration updates, minor config bumps, and small refactors in existing FastLED driver/effects and main startup behavior.

Changes

Cohort / File(s) Summary
Configuration & Dependencies
platformio.ini
Increased DRIVERS_STACK_SIZE from 4096 → 6144; bumped FASTLED_BUILD and FastLED library ref from 2026022120260222.
Core shared data & headers
src/MoonBase/Nodes.h
Added audio-related SharedData fields: vocalsActive, vocalConfidence, bassLevel, trebleLevel, beat; changed LiveScriptNode destructor to ~LiveScriptNode() override; replaced D_FastLED.h include with D_FastLEDDriver.h and D_FastLEDAudio.h.
New audio driver
src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h
New FastLEDAudioDriver Node: I2S input init, fl::AudioProcessor callbacks (beat, vocals, confidence, bass, treble) updating SharedData, setup() and loop20ms() implementations.
FastLED driver header tweak
src/MoonLight/Nodes/Drivers/D_FastLEDDriver.h
Fixed header comment/reference (no behavioral changes).
New audio effect
src/MoonLight/Nodes/Effects/E_FastLED.h
Added FLAudioEffect Node: uses SharedData (beat/vocal/bass/treble) to render layered visuals with decay and beat handling; coexists with RainbowEffect.
Effects refactor (3D behavior)
src/MoonLight/Nodes/Effects/E_WLED.h
WaterfallEffect vertical shift changed from flat 1D shift to 3D coordinate-based y-axis shifts; peak/top-row writes now apply per (x,z) column.
New layout
src/MoonLight/Nodes/Layouts/L_MoonLight.h
Added TubesLayout (2D layout) with nrOfTubes, ledsPerTube, tubeDistance, reversed_order; composes SingleColumnLayout per tube and positions them.
Module registration updates
src/MoonLight/Modules/ModuleDrivers.h, src/MoonLight/Modules/ModuleEffects.h
Registered FastLEDAudioDriver and TubesLayout in driver/layout options; registered FLAudioEffect in effects list and creation path.
Startup change
src/main.cpp
Removed/enabled-out Serial.setDebugOutput(true) call while preserving Serial.flush(); reduces automatic debug output side effect.

Sequence Diagram(s)

sequenceDiagram
    participant I2S as I2S Audio HW
    participant AudioDrv as FastLEDAudioDriver
    participant Proc as AudioProcessor
    participant Shared as SharedData
    participant Effect as FLAudioEffect
    participant LEDs as LED Renderer

    I2S->>AudioDrv: provide audio samples
    AudioDrv->>Proc: feed samples
    Proc->>Proc: detect beat, vocals, freq bands
    Proc->>Shared: set beat, vocalsActive, vocalConfidence, bassLevel, trebleLevel
    Effect->>Shared: read audio fields
    alt vocalsActive
        Effect->>Effect: run vocal-driven rainbow animation
    else beat
        Effect->>Effect: trigger beat visuals, set beatLevel
    else
        Effect->>Effect: idle/random noise rendering
    end
    Effect->>LEDs: render pixels
    AudioDrv->>Shared: clear transient beat flag
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰
Beats in my whiskers, lights in my hop,
Tubes and hues make the night bop non-stop,
I2S sings and pixels glow so bright,
I nibble code and watch the LEDs light,
Hooray — a rabbit’s rave in LED delight!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'FastLED audio' directly and accurately describes the primary feature being added: audio processing integration for FastLED, which is evident throughout the changeset with new audio driver, audio effect, shared audio data fields, and related infrastructure.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch FastLED-audio

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (4)
src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h (4)

39-42: Unused member variables currentBPM and onsetCount.

currentBPM and onsetCount are declared but never read or written anywhere in this class. If they're planned for future use, consider removing them until needed to keep the interface clean (YAGNI).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h` around lines 39 - 42, The
members currentBPM (float) and onsetCount (uint32_t) in the D_FastLEDAudio class
are declared but never used; remove these two unused member declarations from
the class in D_FastLEDAudio.h to keep the interface clean (or, if they are
intentionally planned, add a clear TODO comment and minimal read/write usage to
avoid unused-variable warnings). Locate the declarations named currentBPM and
onsetCount in the D_FastLEDAudio class and delete them (or replace with a
commented TODO) and rebuild to ensure no references remain.

21-28: Hardcoded I2S pins and static globals in a header file.

Two concerns:

  1. Pin configuration: The #define macros for I2S pins (6, 4, 5) are hardcoded and will silently shadow or collide with any same-named macros elsewhere. Consider making these configurable (e.g., via onUpdate/UI controls, as done for other drivers) or at minimum wrapping them in #ifndef guards.

  2. Static globals in a header: i2sConfig, config, and audioInput are static at file scope — each translation unit including this header gets its own copy. If this header is included from multiple .cpp files, you'll have duplicated state and the audioInput shared_ptr won't actually be shared. If single-TU inclusion is guaranteed by the build, this works but is fragile.

Consider moving the static variables inside the class (as static inline members or into the .cpp file), and making pin assignments configurable or at least guarded:

-  `#define` I2S_CLK_PIN 6
-  `#define` I2S_WS_PIN 4
-  `#define` I2S_SD_PIN 5
-  `#define` I2S_CHANNEL fl::Left
-
-static fl::AudioConfigI2S i2sConfig(I2S_WS_PIN, I2S_SD_PIN, I2S_CLK_PIN, 0, I2S_CHANNEL, 44100, 16, fl::Philips);
-static fl::AudioConfig config(i2sConfig);
-static fl::shared_ptr<fl::IAudioInput> audioInput;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h` around lines 21 - 28, The
header hardcodes I2S_PIN macros (I2S_CLK_PIN, I2S_WS_PIN, I2S_SD_PIN) and
declares file-scope static objects (i2sConfig, config, audioInput) which cause
macro collisions and duplicated state across TUs; change the pin defines to be
configurable or at minimum wrap them with `#ifndef` guards (so existing builds can
override them) and move i2sConfig, config, and audioInput out of the header into
the implementation (or declare them as static inline class members) so there is
a single shared instance — update the driver class to accept pin/runtime config
(e.g., via onUpdate/UI controls) and instantiate the AudioConfigI2S and
shared_ptr<fl::IAudioInput> in the .cpp or as inline static members instead of
file-scope statics in the header.

51-83: Callback capture lists are inconsistent — consider uniformity.

  • onBeat, onVocalStart, onVocalEnd capture [&] (by reference), which captures this and all locals. These callbacks only access sharedData (global) and member variables (beatCount, lastBeatTime).
  • onVocalConfidence, onBass, onTreble use [] (no capture) and only access sharedData (global).

The [&] captures are safe as long as the FastLEDAudioDriver instance outlives audioProcessor (which it does since it's a member). However, mixing capture styles is slightly inconsistent. The onVocalStart/onVocalEnd lambdas don't need [&] since they only touch the global sharedData.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h` around lines 51 - 83, The
callbacks use mixed capture styles; make them explicit and consistent: change
audioProcessor.onBeat's lambda to capture [this] (it modifies member variables
beatCount and lastBeatTime) and keep audioProcessor.onVocalStart / onVocalEnd as
[this] if they will ever touch members (or change them to [] if they only touch
the global sharedData), and leave audioProcessor.onVocalConfidence, onBass,
onTreble as [] (no capture) since they only use the global sharedData; update
the capture lists for the lambdas referenced by onBeat, onVocalStart,
onVocalEnd, onVocalConfidence, onBass, and onTreble accordingly so each lambda
explicitly captures only what it needs.

94-94: Stop audio input in destructor to release hardware resources.

The audioInput static shared_ptr is started in setup() but never stopped. When the driver is destroyed, the I2S hardware resource remains active. Call audioInput->stop() (designed per FastLED API for this purpose) to properly release the resource:

♻️ Proposed fix
- ~FastLEDAudioDriver() override {}
+ ~FastLEDAudioDriver() override {
+   if (audioInput) {
+     audioInput->stop();
+   }
+ }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h` at line 94, The destructor
~FastLEDAudioDriver() currently does nothing but must stop the shared audioInput
resource started in setup(); update the destructor for FastLEDAudioDriver to
check the static std::shared_ptr audioInput and call audioInput->stop() (and
optionally reset the pointer) to release the I2S hardware resource; locate the
static member audioInput and the setup() method for context and ensure the
destructor calls audioInput->stop() only if the pointer is non-null.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@platformio.ini`:
- Around line 207-209: Add the compiler define to force the legacy RMT4 driver:
in the platformio.ini's [moonlight] build_flags (the same place where -D
FASTLED_BUILD is set), append -D FASTLED_RMT5=0 so FastLED uses RMT4 instead of
RMT5; update the build_flags string that currently references FASTLED_BUILD so
it includes this new define to prevent the RMT5 ISR "Handler detached" issues
described.

In `@src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h`:
- Around line 47-49: Check the result of fl::IAudioInput::create by verifying
audioInput and errorMsg before calling audioInput->start(); if create fails, log
the descriptive errorMsg (or a fallback message) and avoid calling start so you
don't dereference a null pointer. Add a null guard in the class's loop20ms()
(e.g., if (!audioInput) return;) to skip audio processing when audioInput wasn't
created. Ensure all locations that use audioInput (construction/start and
loop20ms) handle the null case consistently and do not assume successful
creation.
- Around line 86-92: The beat flag is being cleared at the end of loop20ms(), so
any onBeat-set sharedData.beat is erased before FLAudioEffect::loop() can
observe it; move the sharedData.beat = false reset to the start of loop20ms()
(before the while loop that calls audioInput->read() and
audioProcessor.update(sample)) so the flag can be set by the onBeat callback
during processing and persist until the next cycle.

---

Nitpick comments:
In `@src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h`:
- Around line 39-42: The members currentBPM (float) and onsetCount (uint32_t) in
the D_FastLEDAudio class are declared but never used; remove these two unused
member declarations from the class in D_FastLEDAudio.h to keep the interface
clean (or, if they are intentionally planned, add a clear TODO comment and
minimal read/write usage to avoid unused-variable warnings). Locate the
declarations named currentBPM and onsetCount in the D_FastLEDAudio class and
delete them (or replace with a commented TODO) and rebuild to ensure no
references remain.
- Around line 21-28: The header hardcodes I2S_PIN macros (I2S_CLK_PIN,
I2S_WS_PIN, I2S_SD_PIN) and declares file-scope static objects (i2sConfig,
config, audioInput) which cause macro collisions and duplicated state across
TUs; change the pin defines to be configurable or at minimum wrap them with
`#ifndef` guards (so existing builds can override them) and move i2sConfig,
config, and audioInput out of the header into the implementation (or declare
them as static inline class members) so there is a single shared instance —
update the driver class to accept pin/runtime config (e.g., via onUpdate/UI
controls) and instantiate the AudioConfigI2S and shared_ptr<fl::IAudioInput> in
the .cpp or as inline static members instead of file-scope statics in the
header.
- Around line 51-83: The callbacks use mixed capture styles; make them explicit
and consistent: change audioProcessor.onBeat's lambda to capture [this] (it
modifies member variables beatCount and lastBeatTime) and keep
audioProcessor.onVocalStart / onVocalEnd as [this] if they will ever touch
members (or change them to [] if they only touch the global sharedData), and
leave audioProcessor.onVocalConfidence, onBass, onTreble as [] (no capture)
since they only use the global sharedData; update the capture lists for the
lambdas referenced by onBeat, onVocalStart, onVocalEnd, onVocalConfidence,
onBass, and onTreble accordingly so each lambda explicitly captures only what it
needs.
- Line 94: The destructor ~FastLEDAudioDriver() currently does nothing but must
stop the shared audioInput resource started in setup(); update the destructor
for FastLEDAudioDriver to check the static std::shared_ptr audioInput and call
audioInput->stop() (and optionally reset the pointer) to release the I2S
hardware resource; locate the static member audioInput and the setup() method
for context and ensure the destructor calls audioInput->stop() only if the
pointer is non-null.

Comment on lines +207 to +209
-D FASTLED_BUILD=\"20260222\"
lib_deps =
https://github.com/FastLED/FastLED#9d0b0eb9b5e59e4093982e0c2bdcfdff72ca80cb ; master 20260221
https://github.com/FastLED/FastLED#27c99130c83ab666c4c6dbf389425fec5f27db05 ; master 20260222
Copy link

@coderabbitai coderabbitai bot Feb 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# First, let's examine the platformio.ini file around the specified lines and check for build flags
cat -n platformio.ini | head -230 | tail -50

Repository: MoonModules/MoonLight

Length of output: 3265


🏁 Script executed:

#!/bin/bash
# Search for all FastLED-related configuration flags in the repo
rg -n "FASTLED_RMT5|FASTLED_RMT4|FASTLED_BUILD|FASTLED_" --type ini --type txt --type h --type cpp

Repository: MoonModules/MoonLight

Length of output: 92


🏁 Script executed:

#!/bin/bash
# Check the exact commit details and verify build string alignment
# Find the git repository containing the pinned FastLED commit
rg -n "27c99130c83ab666c4c6dbf389425fec5f27db05" --type ini

Repository: MoonModules/MoonLight

Length of output: 92


🏁 Script executed:

#!/bin/bash
# Search for FASTLED_RMT5, FASTLED_RMT4, and related driver flags without file type restrictions
rg -n "FASTLED_RMT5|FASTLED_RMT4|FASTLED_SPI" .

Repository: MoonModules/MoonLight

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Check the complete [moonlight] section and build_flags to see all configuration
sed -n '199,211p' platformio.ini

Repository: MoonModules/MoonLight

Length of output: 811


🏁 Script executed:

#!/bin/bash
# Check all build_flags sections across the entire platformio.ini
rg -B2 -A5 "build_flags|FASTLED" platformio.ini

Repository: MoonModules/MoonLight

Length of output: 2738


🏁 Script executed:

#!/bin/bash
# Verify the commit date by examining git if available, or search related documentation
# Check if there are any comments/docs about the FastLED version and RMT configuration
rg -n "27c99130c83ab666c4c6dbf389425fec5f27db05|RMT5|RMT4|Handler detached" .

Repository: MoonModules/MoonLight

Length of output: 181


🏁 Script executed:

#!/bin/bash
# Check platform-espressif32 version 55.03.37 for ESP-IDF details
# Look for package.json or version info in typical locations
rg -n "esp-idf|ESP-IDF|5\.[0-9]" platformio.ini | head -20

Repository: MoonModules/MoonLight

Length of output: 2966


🏁 Script executed:

#!/bin/bash
# Search for any Arduino core version or framework configuration
rg -n "framework|arduino|framework-esp32idf|framework-espidf" platformio.ini

Repository: MoonModules/MoonLight

Length of output: 3009


Add -D FASTLED_RMT5=0 to force legacy RMT4 driver and prevent ISR handler degradation.

The FASTLED_BUILD string aligns correctly with the pinned commit. However, platform 55.03.37 uses ESP-IDF 5.5+ with Arduino core 3.x, which causes FastLED to default to the RMT5 driver. RMT5 has documented ISR handler lifecycle issues (see FastLED issue #1903) causing repeated "Handler detached" messages and severe performance drops (~2 FPS). Add -D FASTLED_RMT5=0 to the [moonlight] build_flags to force the stable legacy RMT4 driver.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@platformio.ini` around lines 207 - 209, Add the compiler define to force the
legacy RMT4 driver: in the platformio.ini's [moonlight] build_flags (the same
place where -D FASTLED_BUILD is set), append -D FASTLED_RMT5=0 so FastLED uses
RMT4 instead of RMT5; update the build_flags string that currently references
FASTLED_BUILD so it includes this new define to prevent the RMT5 ISR "Handler
detached" issues described.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not true on newest FastLED

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🌐 Web query:

FastLED RMT5 driver fixes February 2026 handler detached

💡 Result:

I couldn’t find any FastLED change/issue (through the public repo + recent searches) specifically tied to a “handler detached” message for the ESP32 RMT5 driver in February 2026—so there doesn’t appear to be a known “Feb 2026” targeted fix labeled that way. (If you have the exact log line + platform/core version, I can search more precisely.)

What is documented/fixed recently around ESP32 RMT5 stability:

  • FastLED 3.10.1 fixed an ESP32‑S3 RMT5 break where an internal improvement accidentally set DMA mode true, breaking RMT5. Updating beyond 3.10.1 is recommended if you hit DMA-related failures. [1]
  • Ongoing RMT5 reliability discussions (especially Wi‑Fi flicker/jitter) note RMT5’s limits and practical mitigations (e.g., raising RMT interrupt priority to the max the driver allows and increasing buffering), but these are about underruns/flicker rather than a “handler detached” teardown error. [2]
  • If you need a robust workaround today, FastLED explicitly recommends switching away from RMT5 in some cases:
    • Force legacy RMT4 with -D FASTLED_RMT5=0 (typically requires older ESP32 Arduino core / IDF4-era setups; also note RMT4 and RMT5 can’t coexist). [3]
    • Or use alternative output paths (I2S/SPI/Adafruit bridge), which users/reporting/dev notes often suggest when RMT5 is unstable under load. [3]

Most actionable next step: confirm whether your “handler detached” happens only with DMA enabled. If yes, try updating FastLED (>= 3.10.1) first. [1] If it persists, try FASTLED_RMT5=0 (RMT4) or switch to a non-RMT driver as above. [3]

Sources:
[1] FastLED releases (3.10.1 notes: DMA mode accidentally set true, breaking RMT5) https://github.com/fastled/fastled/releases
[2] FastLED issue #2082 (RMT5 + Wi‑Fi flicker; buffering/priority limits/knobs discussion) FastLED/FastLED#2082
[3] FastLED repository documentation (RMT4 vs RMT5 selection; FASTLED_RMT5=0; alternative drivers) https://github.com/FastLED/FastLED


@ewowi, thank you for the correction! I appreciate you letting me know that the RMT5 "Handler detached" issues have been resolved in the newest FastLED version.

Since you originally provided the learning about RMT5 issues (learning ID 9bb17d59-f1a1-4505-b40f-39a68c64be29) and you're now confirming it's no longer applicable with the latest FastLED, would you like me to remove that outdated learning from the knowledge base? This will prevent it from being referenced in future reviews.


✏️ Learnings added
Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 130
File: platformio.ini:207-209
Timestamp: 2026-02-22T12:37:03.751Z
Learning: FastLED RMT5 driver issues (ISR handler "Handler detached" messages and performance degradation) have been resolved in FastLED versions as of commit 27c99130c83ab666c4c6dbf389425fec5f27db05 (master 20260222). The `-D FASTLED_RMT5=0` workaround is no longer needed.
<!-- </add_learning>

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-02-05T13:20:46.001Z
Learning: In MoonLight with FastLED 3.11 on ESP-IDF 5.x+ (Arduino core 3.x): FastLED defaults to RMT5 driver (wraps Espressif's led_strip component), which has known ISR handler lifecycle issues causing repeated "Handler detached" messages every ~500ms and severe performance degradation (e.g., 2 FPS). RMT5 is more prone to Wi-Fi/interrupt jitter than legacy RMT4. Solution: force legacy RMT4 by adding `-D FASTLED_RMT5=0` to build flags in platformio.ini, or switch to FastLED's parallel I/O drivers which don't use RMT. RMT4 and RMT5 cannot coexist in the same binary.

Learnt from: CR
Repo: MoonModules/MoonLight PR: 0
File: misc/parking/GEMINI.md:0-0
Timestamp: 2025-11-29T16:17:30.619Z
Learning: Applies to misc/parking/**/platformio.ini : Use PlatformIO to build and upload the ESP32 backend C++ code

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-16T15:53:11.236Z
Learning: For ESP32-PICO-MINI-02 (and similar ESP32 boards with PSRAM), the critical configuration to enable PSRAM is `board_build.arduino.memory_type = qio_qspi` in platformio.ini. The board JSON may already include `-DBOARD_HAS_PSRAM` and `flash_mode: qio`, but without the memory_type setting, PSRAM won't be properly initialized, causing LoadStoreError crashes when code tries to access PSRAM addresses.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-28T18:06:23.868Z
Learning: ESP32-P4 observed lower headroom for httpd task stack in MoonLight: NodeManager rename (create new node + rebuild controls + remove old) can overflow httpd stack when onUpdate runs in httpd. Mitigation: defer only NodeManager rename heavy work to SvelteKit loop via a small pendingRenames queue; keep identity short-circuit in compareRecursive and equality-guarded controls updates. Increasing httpd stack_size for P4 builds is an optional, broader fix.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 121
File: src/MoonLight/Nodes/Drivers/D_FastLED.h:176-176
Timestamp: 2026-02-08T20:43:12.857Z
Learning: In MoonLight FastLED 3.11 driver (src/MoonLight/Nodes/Drivers/D_FastLED.h): Affinity is applied per-channel via fl::ChannelOptions.mAffinity passed to fl::ChannelConfig (not via FastLED.setExclusiveDriver). Keeping setExclusiveDriver commented out leaves all drivers available; FastLED then selects the appropriate driver for each channel based on the mAffinity preference ("RMT", "I2S", "SPI", "PARLIO", or "" for auto). This allows per-channel driver preferences rather than a global restriction.

Learnt from: CR
Repo: MoonModules/MoonLight PR: 0
File: misc/parking/GEMINI.md:0-0
Timestamp: 2025-11-29T16:17:30.619Z
Learning: Applies to misc/parking/**/factory_settings.ini : Configure default or factory-set ESP32 parameters in `factory_settings.ini`

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-18T17:07:33.344Z
Learning: FastLED library does not support direct 4-byte-per-pixel (CRGBW) buffers. It always expects CRGB (3-byte) arrays and internally generates the W channel from RGB using .setRgbw() API. Casting a 4-byte RGBW buffer to CRGB* causes misalignment (W becomes next pixel's R). For MoonLight's FastLED driver with channelsPerLight=4: must either (1) repack RGB in-place before FastLED.show() then restore after, (2) use driver-specific channelsPerLight=3 layout, or (3) allocate temporary RGB-only buffer. Option 1 (in-place repacking) is best for ESP32-D0 memory constraints.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-06T13:45:03.067Z
Learning: For MoonLight on ESP32 at extreme loads (e.g., 49K channels @ 100 fps): Task watchdog can fire when AppDrivers/AppEffects process many nodes without yielding. Even with vTaskDelay(1) at loop end, the node iteration for-loops (PhysicalLayer::loopDrivers line 108-111, PhysicalLayer::loop line 73-75) can take >5 seconds without yielding, starving IDLE task (priority 0). Solution: add taskYIELD() or vTaskDelay(1) inside the node/layer iteration loops to give IDLE task chances to run and reset watchdog. Lowering task priority won't help since IDLE is already at 0 (lowest).

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-18T12:49:07.297Z
Learning: In MoonLight channel reordering architecture: Keep rgbwBufferMapping in driver task (not effect task) because: (1) Driver has spare CPU cycles waiting for DMA/I2S/Art-Net timing; effect task is CPU-bound and starvation-prone. (2) Contiguous RGB writes in effects are cache-friendly; scattered writes at final offsets are cache-hostile for non-RGB orders (GRB, BGR, etc.). (3) forEachLightIndex already handles sparse mapping iteration; moving reordering to effects adds complexity without benefit since drivers must send full frames anyway (can't skip iteration). (4) rgbwBufferMapping does brightness/gamma LUT + white extraction + reordering—moving just reordering creates code duplication. (5) Effects should express color intent (CRGB), not hardware details (offsetRed/Green/Blue). Driver-side transformation maintains separation of concerns and task load balance for scaling to 98K+ pixels.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes remove it please

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ewowi, I've removed the outdated learning about the FastLED RMT5 driver issues. The knowledge base now reflects the current state: that RMT5 issues have been resolved in FastLED as of commit 27c99130c83ab666c4c6dbf389425fec5f27db05 (master 20260222), and the -D FASTLED_RMT5=0 workaround is no longer needed. Thank you for keeping the information up to date!

🐰💭
(Learning tidied up!)
/) /)
( •.• )
/>📝✨


⛔ Learnings removed
Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-02-05T13:20:46.001Z
Learning: In MoonLight with FastLED 3.11 on ESP-IDF 5.x+ (Arduino core 3.x): FastLED defaults to RMT5 driver (wraps Espressif's led_strip component), which has known ISR handler lifecycle issues causing repeated "Handler detached" messages every ~500ms and severe performance degradation (e.g., 2 FPS). RMT5 is more prone to Wi-Fi/interrupt jitter than legacy RMT4. Solution: force legacy RMT4 by adding `-D FASTLED_RMT5=0` to build flags in platformio.ini, or switch to FastLED's parallel I/O drivers which don't use RMT. RMT4 and RMT5 cannot coexist in the same binary.

🧠 Learnings used
Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-02-05T13:20:46.001Z
Learning: In MoonLight with FastLED 3.11 on ESP-IDF 5.x+ (Arduino core 3.x): FastLED defaults to RMT5 driver (wraps Espressif's led_strip component), which has known ISR handler lifecycle issues causing repeated "Handler detached" messages every ~500ms and severe performance degradation (e.g., 2 FPS). RMT5 is more prone to Wi-Fi/interrupt jitter than legacy RMT4. Solution: force legacy RMT4 by adding `-D FASTLED_RMT5=0` to build flags in platformio.ini, or switch to FastLED's parallel I/O drivers which don't use RMT. RMT4 and RMT5 cannot coexist in the same binary.

Learnt from: CR
Repo: MoonModules/MoonLight PR: 0
File: misc/parking/GEMINI.md:0-0
Timestamp: 2025-11-29T16:17:30.619Z
Learning: Applies to misc/parking/**/platformio.ini : Use PlatformIO to build and upload the ESP32 backend C++ code

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-16T15:53:11.236Z
Learning: For ESP32-PICO-MINI-02 (and similar ESP32 boards with PSRAM), the critical configuration to enable PSRAM is `board_build.arduino.memory_type = qio_qspi` in platformio.ini. The board JSON may already include `-DBOARD_HAS_PSRAM` and `flash_mode: qio`, but without the memory_type setting, PSRAM won't be properly initialized, causing LoadStoreError crashes when code tries to access PSRAM addresses.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-28T18:06:23.868Z
Learning: ESP32-P4 observed lower headroom for httpd task stack in MoonLight: NodeManager rename (create new node + rebuild controls + remove old) can overflow httpd stack when onUpdate runs in httpd. Mitigation: defer only NodeManager rename heavy work to SvelteKit loop via a small pendingRenames queue; keep identity short-circuit in compareRecursive and equality-guarded controls updates. Increasing httpd stack_size for P4 builds is an optional, broader fix.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 130
File: platformio.ini:207-209
Timestamp: 2026-02-22T12:37:03.751Z
Learning: FastLED RMT5 driver issues (ISR handler "Handler detached" messages and performance degradation) have been resolved in FastLED versions as of commit 27c99130c83ab666c4c6dbf389425fec5f27db05 (master 20260222). The `-D FASTLED_RMT5=0` workaround is no longer needed.
<!-- </add_learning>

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 121
File: src/MoonLight/Nodes/Drivers/D_FastLED.h:176-176
Timestamp: 2026-02-08T20:43:12.857Z
Learning: In MoonLight FastLED 3.11 driver (src/MoonLight/Nodes/Drivers/D_FastLED.h): Affinity is applied per-channel via fl::ChannelOptions.mAffinity passed to fl::ChannelConfig (not via FastLED.setExclusiveDriver). Keeping setExclusiveDriver commented out leaves all drivers available; FastLED then selects the appropriate driver for each channel based on the mAffinity preference ("RMT", "I2S", "SPI", "PARLIO", or "" for auto). This allows per-channel driver preferences rather than a global restriction.

Learnt from: CR
Repo: MoonModules/MoonLight PR: 0
File: misc/parking/GEMINI.md:0-0
Timestamp: 2025-11-29T16:17:30.619Z
Learning: Applies to misc/parking/**/factory_settings.ini : Configure default or factory-set ESP32 parameters in `factory_settings.ini`

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-18T12:49:07.297Z
Learning: In MoonLight channel reordering architecture: Keep rgbwBufferMapping in driver task (not effect task) because: (1) Driver has spare CPU cycles waiting for DMA/I2S/Art-Net timing; effect task is CPU-bound and starvation-prone. (2) Contiguous RGB writes in effects are cache-friendly; scattered writes at final offsets are cache-hostile for non-RGB orders (GRB, BGR, etc.). (3) forEachLightIndex already handles sparse mapping iteration; moving reordering to effects adds complexity without benefit since drivers must send full frames anyway (can't skip iteration). (4) rgbwBufferMapping does brightness/gamma LUT + white extraction + reordering—moving just reordering creates code duplication. (5) Effects should express color intent (CRGB), not hardware details (offsetRed/Green/Blue). Driver-side transformation maintains separation of concerns and task load balance for scaling to 98K+ pixels.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-18T17:07:33.344Z
Learning: FastLED library does not support direct 4-byte-per-pixel (CRGBW) buffers. It always expects CRGB (3-byte) arrays and internally generates the W channel from RGB using .setRgbw() API. Casting a 4-byte RGBW buffer to CRGB* causes misalignment (W becomes next pixel's R). For MoonLight's FastLED driver with channelsPerLight=4: must either (1) repack RGB in-place before FastLED.show() then restore after, (2) use driver-specific channelsPerLight=3 layout, or (3) allocate temporary RGB-only buffer. Option 1 (in-place repacking) is best for ESP32-D0 memory constraints.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2026-01-06T13:45:03.067Z
Learning: For MoonLight on ESP32 at extreme loads (e.g., 49K channels @ 100 fps): Task watchdog can fire when AppDrivers/AppEffects process many nodes without yielding. Even with vTaskDelay(1) at loop end, the node iteration for-loops (PhysicalLayer::loopDrivers line 108-111, PhysicalLayer::loop line 73-75) can take >5 seconds without yielding, starving IDLE task (priority 0). Solution: add taskYIELD() or vTaskDelay(1) inside the node/layer iteration loops to give IDLE task chances to run and reset watchdog. Lowering task priority won't help since IDLE is already at 0 (lowest).

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 84
File: src/MoonLight/Modules/ModuleLightsControl.h:367-379
Timestamp: 2025-12-28T10:28:24.157Z
Learning: In MoonLight PR `#84`: wrapping effectTask's layerP.loop() with monitorMutex while reading channelsE for monitor emission is thread-safe and prevents partial frames, but introduces serialization between effects rendering and monitor emission. Reading from channelsD (driver/front buffer) instead—with monitorMutex held only during the brief pointer swap—is superior because it maintains full parallelism (effects ║ monitor ║ driver), shows actual LED output, and minimizes mutex hold time.

Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 0
File: :0-0
Timestamp: 2025-12-25T13:34:40.097Z
Learning: For the MoonLight LED system: Effects task can run on Core 0 (PRO_CPU) since it only performs computation (calculating colors, writing to channels array) without timing-critical hardware interaction. WiFi preemption is acceptable for pure computation tasks. Only the driver task (using DMA, I2S, LCD, PARLIO) requires Core 1 (APP_CPU) for uninterrupted timing-critical hardware operations.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain
🏁 Script executed:

#!/bin/bash
# First, let's examine the platformio.ini file around the specified lines and check for build flags
cat -n platformio.ini | head -230 | tail -50

Repository: MoonModules/MoonLight

Length of output: 3265

🏁 Script executed:

#!/bin/bash
# Search for all FastLED-related configuration flags in the repo
rg -n "FASTLED_RMT5|FASTLED_RMT4|FASTLED_BUILD|FASTLED_" --type ini --type txt --type h --type cpp

Repository: MoonModules/MoonLight

Length of output: 92

🏁 Script executed:

#!/bin/bash
# Check the exact commit details and verify build string alignment
# Find the git repository containing the pinned FastLED commit
rg -n "27c99130c83ab666c4c6dbf389425fec5f27db05" --type ini

Repository: MoonModules/MoonLight

Length of output: 92

🏁 Script executed:

#!/bin/bash
# Search for FASTLED_RMT5, FASTLED_RMT4, and related driver flags without file type restrictions
rg -n "FASTLED_RMT5|FASTLED_RMT4|FASTLED_SPI" .

Repository: MoonModules/MoonLight

Length of output: 47

🏁 Script executed:

#!/bin/bash
# Check the complete [moonlight] section and build_flags to see all configuration
sed -n '199,211p' platformio.ini

Repository: MoonModules/MoonLight

Length of output: 811

🏁 Script executed:

#!/bin/bash
# Check all build_flags sections across the entire platformio.ini
rg -B2 -A5 "build_flags|FASTLED" platformio.ini

Repository: MoonModules/MoonLight

Length of output: 2738

🏁 Script executed:

#!/bin/bash
# Verify the commit date by examining git if available, or search related documentation
# Check if there are any comments/docs about the FastLED version and RMT configuration
rg -n "27c99130c83ab666c4c6dbf389425fec5f27db05|RMT5|RMT4|Handler detached" .

Repository: MoonModules/MoonLight

Length of output: 181

🏁 Script executed:

#!/bin/bash
# Check platform-espressif32 version 55.03.37 for ESP-IDF details
# Look for package.json or version info in typical locations
rg -n "esp-idf|ESP-IDF|5\.[0-9]" platformio.ini | head -20

Repository: MoonModules/MoonLight

Length of output: 2966

🏁 Script executed:

#!/bin/bash
# Search for any Arduino core version or framework configuration
rg -n "framework|arduino|framework-esp32idf|framework-espidf" platformio.ini

Repository: MoonModules/MoonLight

Length of output: 3009

Add -D FASTLED_RMT5=0 to force legacy RMT4 driver and prevent ISR handler degradation.

The FASTLED_BUILD string aligns correctly with the pinned commit. However, platform 55.03.37 uses ESP-IDF 5.5+ with Arduino core 3.x, which causes FastLED to default to the RMT5 driver. RMT5 has documented ISR handler lifecycle issues (see FastLED issue #1903) causing repeated "Handler detached" messages and severe performance drops (~2 FPS). Add -D FASTLED_RMT5=0 to the [moonlight] build_flags to force the stable legacy RMT4 driver.

🤖 Prompt for AI Agents

Disabling RMT5 should not be necessary now? The RMT5 driver now allocates more memory during WIFI active mode. Please let me know if this isn't the case. RMT5 will have stress testing either this week if ai credits sustain. Otherwise post friday on refresh.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/MoonBase/Nodes.h (1)

350-356: Optional: prefer 0.0f literals for float member initializers.

float vocalConfidence = 0, float bassLevel = 0, and float trebleLevel = 0 are valid C++ but using integer literals for float members is less explicit than 0.0f.

✨ Proposed style fix
-  float vocalConfidence = 0;
-  float bassLevel = 0;
-  float trebleLevel = 0;
+  float vocalConfidence = 0.0f;
+  float bassLevel = 0.0f;
+  float trebleLevel = 0.0f;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/MoonBase/Nodes.h` around lines 350 - 356, Update the float member
initializers to use explicit float literals: change the initializers for
vocalConfidence, bassLevel, and trebleLevel from integer zero (e.g. = 0) to
0.0f; keep the boolean members vocalsActive and beat unchanged. This ensures
types are explicit for members vocalConfidence, bassLevel, and trebleLevel in
the class/struct where they are declared.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/MoonBase/Nodes.h`:
- Around line 350-356: Update the float member initializers to use explicit
float literals: change the initializers for vocalConfidence, bassLevel, and
trebleLevel from integer zero (e.g. = 0) to 0.0f; keep the boolean members
vocalsActive and beat unchanged. This ensures types are explicit for members
vocalConfidence, bassLevel, and trebleLevel in the class/struct where they are
declared.

@ewowi
Copy link
Collaborator Author

ewowi commented Feb 22, 2026

@coderabbitai, can you verify this issue FastLED/FastLED#2170 and compare it with the commits in this PR and come with a review summary and propose follow up actions to do in this PR

@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🌐 Web query:

FastLED GitHub issue 2170

💡 Result:

FastLED/FastLED Issue #2170 is titled “Audio library issues and opportunities” and is Open. It was opened by @4wheeljive on February 11, 2026. The issue provides feedback on FastLED’s newest pre-release audio library, noting that while the overall architecture/API is good, the DSP/implementations have significant gaps; it specifically calls out the need for a signal conditioning / preprocessing stage (e.g., DC removal, spike filtering, noise gating, auto-gain) before detectors run, because otherwise users end up re-implementing that work themselves. [1]

Source: [1]


🏁 Script executed:

#!/bin/bash
# Get detailed information about the audio-related changes in this PR
echo "=== Examining FastLEDAudioDriver implementation ==="
cat src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h

echo -e "\n=== Examining FLAudioEffect implementation ==="
cat src/MoonLight/Nodes/Effects/E_FastLED.h

echo -e "\n=== Checking for audio processor configuration ==="
rg -n "AudioProcessor|audioProcessor" --type=cpp --type=h -C3

echo -e "\n=== Checking platformio.ini changes ==="
cat platformio.ini | grep -A5 -B5 "FASTLED\|DRIVERS_STACK"

Length of output: 10286


@ewowi, I've analyzed FastLED issue #2170 and compared it with your PR changes. Here's my findings:

FastLED Issue #2170 Summary

FastLED issue #2170 titled "Audio library issues and opportunities" is open and was created by @4wheeljive on February 11, 2026. The issue notes that while the FastLED audio library's "overall architecture/API is good", the "DSP/implementations have significant gaps", specifically calling out the need for a "signal conditioning / preprocessing stage" (e.g., DC removal, spike filtering, noise gating, auto-gain) before detectors run.

PR #130 Implementation Analysis

Your PR integrates FastLED's audio library through:

  1. FastLEDAudioDriver (D_FastLEDAudio.h):

    • Creates I2S audio input with hardcoded pins and configuration
    • Uses fl::AudioProcessor directly
    • Registers callbacks for beat, vocals, bass, and treble
    • Passes raw audio samples to audioProcessor.update() with no preprocessing
    • Only applies minimal 0.01f threshold filtering in bass/treble callbacks
  2. FLAudioEffect (E_FastLED.h):

    • Visualizes audio data with 4 vertical bars (bass, treble, vocal, beat)
    • Implements adaptive scaling using max values with slow decay
    • Basic visual effect to demonstrate audio integration
  3. Infrastructure:

    • Stack size increased from 4096 to 6144 bytes (50% increase)
    • Note in platformio.ini suggests considering moving audio to separate task
    • FastLED updated to latest commit (20260222)

Gap Analysis

The implementation does NOT address the preprocessing concerns raised in issue #2170:

  • ❌ No DC removal
  • ❌ No spike filtering
  • ❌ No noise gating
  • ❌ No auto-gain control
  • ⚠️ Only basic threshold filtering (0.01f)

Your implementation relies entirely on FastLED's AudioProcessor as-is, which according to the issue has the DSP gaps mentioned above.

Proposed Follow-up Actions

Immediate (This PR)

  1. Document known limitations - Add comments in D_FastLEDAudio.h noting reliance on FastLED's audio processing without additional preprocessing
  2. Make audio config more flexible - Consider exposing I2S pin configuration as UI controls instead of hardcoded defines
  3. Add error handling - The current implementation continues if audioInput creation fails; consider more robust handling
  4. ⚠️ Stack size consideration - Monitor if 6144 bytes is sufficient; your own note suggests potentially moving to separate task

Short-term Testing

  1. 📊 Real-world testing - Test with various audio sources (music, speech, ambient) to identify if preprocessing gaps cause issues
  2. 📊 Monitor for symptoms - Watch for: false beat triggers, poor vocal detection, level instability, DC offset issues
  3. 📊 Benchmark performance - Verify the stack increase is adequate and monitor CPU usage

Medium-term Improvements

  1. 🔧 Consider preprocessing layer - If issues surface, implement signal conditioning before AudioProcessor:
    • High-pass filter for DC removal
    • Moving average or median filter for spike suppression
    • Threshold-based noise gate
    • AGC (automatic gain control) for level normalization
  2. 🔧 Expose tuning parameters - Add UI controls for thresholds, sensitivity, etc.
  3. 🤝 Contribute upstream - If you implement preprocessing, consider contributing back to FastLED to address issue #2170

Documentation

  1. 📝 Update PR description - Note the dependency on FastLED's audio library and any observed limitations
  2. 📝 User guidance - Document recommended audio input levels and hardware setup for best results

Recommendation

Proceed with merging, but treat this as an initial integration that may require refinement. The FastLED audio library is evolving (issue #2170 is still open), and your implementation provides a good foundation for testing. Monitor real-world performance and be prepared to add a preprocessing layer if the gaps mentioned in #2170 manifest as actual issues in your use case.

Would you like me to help implement any of these follow-up actions, such as adding configuration flexibility or documenting the known limitations?


🧠 Learnings used
Learnt from: ewowi
Repo: MoonModules/MoonLight PR: 130
File: platformio.ini:207-209
Timestamp: 2026-02-22T12:37:03.751Z
Learning: FastLED RMT5 driver issues (ISR handler "Handler detached" messages and performance degradation) have been resolved in FastLED versions as of commit 27c99130c83ab666c4c6dbf389425fec5f27db05 (master 20260222). The `-D FASTLED_RMT5=0` workaround is no longer needed.
<!-- </add_learning>

@ewowi
Copy link
Collaborator Author

ewowi commented Feb 22, 2026

@coderabbitai, regarding

static fl::AudioConfigI2S i2sConfig(I2S_WS_PIN, I2S_SD_PIN, I2S_CLK_PIN, 0, I2S_CHANNEL, 44100, 16, fl::Philips);
static fl::AudioConfig config(i2sConfig);
static fl::shared_ptrfl::IAudioInput audioInput;

How can I bring these in the FastLEDAudioDriver class: create them in setup() and destroy in the destructor

@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Examine the current FastLEDAudioDriver implementation to see the static variables and class structure
cat src/MoonLight/Nodes/Drivers/D_FastLEDAudio.h

Length of output: 2830


@ewowi, here's how to move those static variables into the FastLEDAudioDriver class as member variables:

Recommended Approach (using pointers)

class FastLEDAudioDriver : public Node {
 private:
  // Member variables for audio configuration
  fl::unique_ptr<fl::AudioConfigI2S> i2sConfig;
  fl::unique_ptr<fl::AudioConfig> config;
  fl::shared_ptr<fl::IAudioInput> audioInput;

 public:
  static const char* name() { return "FastLED Audio"; }
  static uint8_t dim() { return _NoD; }
  static const char* tags() { return "☸️"; }

  fl::AudioProcessor audioProcessor;

  void setup() override {
    Node::setup();  // !!

    // Create configuration objects
    i2sConfig = fl::make_unique<fl::AudioConfigI2S>(
        I2S_WS_PIN, I2S_SD_PIN, I2S_CLK_PIN, 0, 
        I2S_CHANNEL, 44100, 16, fl::Philips);
    
    config = fl::make_unique<fl::AudioConfig>(*i2sConfig);

    // Create audio input using the config
    fl::string errorMsg;
    audioInput = fl::IAudioInput::create(*config, &errorMsg);
    if (!audioInput) {
      EXT_LOGE(ML_TAG, "Failed to create audio input: %s", errorMsg.c_str());
      return;
    }
    audioInput->start();

    // ... rest of your setup code (callbacks, etc.)
  }

  void loop20ms() override {
    if (!audioInput) return;
    sharedData.beat = false;
    while (fl::AudioSample sample = audioInput->read()) {
      audioProcessor.update(sample);
    }
  }

  ~FastLEDAudioDriver() override {
    if (audioInput) {
      audioInput->stop();
    }
    // unique_ptr will automatically clean up i2sConfig and config
  }
};

Alternative: If fl::unique_ptr is not available

If FastLED doesn't provide unique_ptr, use raw pointers with manual cleanup:

class FastLEDAudioDriver : public Node {
 private:
  fl::AudioConfigI2S* i2sConfig = nullptr;
  fl::AudioConfig* config = nullptr;
  fl::shared_ptr<fl::IAudioInput> audioInput;

 public:
  // ... static methods ...
  
  fl::AudioProcessor audioProcessor;

  void setup() override {
    Node::setup();

    // Create configuration objects
    i2sConfig = new fl::AudioConfigI2S(
        I2S_WS_PIN, I2S_SD_PIN, I2S_CLK_PIN, 0, 
        I2S_CHANNEL, 44100, 16, fl::Philips);
    
    config = new fl::AudioConfig(*i2sConfig);

    // Create audio input
    fl::string errorMsg;
    audioInput = fl::IAudioInput::create(*config, &errorMsg);
    // ... rest of setup ...
  }

  ~FastLEDAudioDriver() override {
    if (audioInput) {
      audioInput->stop();
      audioInput.reset();  // Explicitly release shared_ptr
    }
    
    // Clean up raw pointers
    delete config;
    config = nullptr;
    
    delete i2sConfig;
    i2sConfig = nullptr;
  }
};

Key Points

  1. Initialization order matters: Create i2sConfig first, then config (which references i2sConfig), then audioInput
  2. Destruction order: The destructor automatically handles the reverse order - audioInput is stopped first, then configs are cleaned up
  3. Memory management:
    • unique_ptr provides automatic cleanup (preferred)
    • Raw pointers require manual delete in destructor
    • shared_ptr for audioInput is already reference-counted
  4. Remove the static variables: Delete the three static lines at file scope once you move them into the class

This approach ensures proper object lifetime management and allows multiple instances of FastLEDAudioDriver if needed in the future.

FastLED Audio driver
- Move static variables inside class
- add controls (gain etc)
- add onUpdate to set controls
- add readPins to get I2S pins from IO module
- add initAudio and stopAudio
- destructor

FLAudio effect
- add Mid
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants