Skip to content

speed improvements to Aurora FX - #4926

Merged
DedeHai merged 3 commits into
wled:mainfrom
DedeHai:aurora_improvements
Nov 16, 2025
Merged

DedeHai merged 3 commits into
wled:mainfrom
DedeHai:aurora_improvements

Conversation

@DedeHai

@DedeHai DedeHai commented Sep 13, 2025 •

Copy link
Copy Markdown
Collaborator

Converted all calculations to integer math. There is very little impact to visual appearance if at all: I was not able to spot any differences.
FPS improve accross all ESPs:
ESP32: ~2x speed improvement thanks to caching and avoiding float divisions
C3: ~6x speed improvement
ESP8266: ~2x speed improvement, maybe more - did only a quick test

RAM usage is the same: new class uses also 32bytes (code of old version states 24bytes but that was ignoring stuffing bytes, it was also 32 bytes)

Changes made:

  • Using 16.16 shifted integer math instead of floats
  • Caching values in per-wave variables instead of re-calculating them for every pixel and every wave (i.e. up to 20 times per pixel)
  • Reduced peak brightness from 100% to 99% to avoid integer overflow (has no real visual impact)
  • Using CRGBW instead or CRGB, saving on color conversions and enabling white channel support
  • Using inverse gamma on base-brightness. I was unable to find the exact intent behind the base brightness and whether it still looks as originally intended.

Code size shrinks by ~300bytes (ESP32) or ~500 bytes on C3/ESP8266.

Can someone who is using this FX regularly please test?

Summary by CodeRabbit

  • New Features

    • Aurora now renders in RGBW with per-frame precomputation for richer colors and steadier waves.
  • Refactor

    • Internal math moved to fixed-point integer and added per-wave caching for smoother animations and reduced CPU on long segments.
  • Bug Fixes

    • Fewer edge artifacts and flicker; improved backlight handling and gamma behavior for more stable ambient brightness.

- converted to integer math, increasing speed on all ESPs, also shrinks code size
- caching values to avoid repeated calculations
- CRGBW instead or CRGB, adds white channel support when not using palette
- fix for new brightness/gamma handling
@DedeHai DedeHai added effect Awaiting testing optimization re-working an existing feature to be faster, or use less memory labels Sep 13, 2025
@coderabbitai

coderabbitai Bot commented Sep 13, 2025 •

Copy link
Copy Markdown
Contributor

Walkthrough

Reworks the Aurora effect in wled00/FX.cpp from floating-point to fixed-point arithmetic, changes AuroraWave public surface (CRGB → CRGBW, new fixed-point center and cached fields), and adds updateCachedValues() plus AW_SHIFT/AW_SCALE constants.

Changes

Cohort / File(s) Summary
AuroraWave fixed-point refactor
wled00/FX.cpp
Replaced FP math with fixed-point (added AW_SHIFT/AW_SCALE); changed AuroraWave layout: center→int32_t (scaled), basecolor→CRGBW, basealpha→uint16_t, added ageFactor_cached, wave_start, wave_end, speed_factor; updated init(...) and getColorForLED(...) signatures to use CRGBW; implemented updateCachedValues(); migrated per-LED computations to integer math.
mode_aurora integration & rendering
wled00/FX.cpp
Adjusted mode loop to initialize waves with new init(...), call update() then updateCachedValues() per frame, use cached wave extents/age when rendering, accumulate colors in CRGBW, and update final pixel/backlight handling to match CRGBW path.
Constants & comments
wled00/FX.cpp
Added AW_SHIFT (16) and AW_SCALE (1 << AW_SHIFT) and updated comments to reflect fixed-point transition and contributor notes.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45–75 minutes

Areas to pay extra attention:

  • Correctness of fixed-point arithmetic (scaling factors, shifts, overflow risks).
  • Boundary conditions using scaled center, wave_start, wave_end.
  • Consistency of color conversions between CRGB and CRGBW and any gamma/backlight paths.
  • New cached value invalidation and when updateCachedValues() is called.

Suggested reviewers

  • Aircoookie

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 'speed improvements to Aurora FX' accurately reflects the core objective of the PR, which implements fixed-point math and caching to improve Aurora effect performance.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (4)
wled00/FX.cpp (4)

4801-4803: Be explicit with CRGBW construction to avoid ctor ambiguity.

Prefer passing the W channel explicitly for clarity and future-proofing.

-    CRGBW mixedRgb = CRGBW(backlight, backlight, backlight);
+    CRGBW mixedRgb = CRGBW(backlight, backlight, backlight, 0);

4682-4685: Prefer constexpr over macros for type safety and scoping.

These are compile-time constants; constexpr uint32_t avoids macro pitfalls and conveys intent.

-#define AW_SHIFT 16
-#define AW_SCALE (1 << AW_SHIFT)  // 65536 representing 1.0
+constexpr uint32_t AW_SHIFT = 16;
+constexpr uint32_t AW_SCALE = (1u << AW_SHIFT);  // 65536 representing 1.0

4694-4696: Document/adjust fixed-point types to match “scaled by AW_SCALE” comment.

basealpha and speed_factor are labeled “scaled by AW_SCALE” but stored in uint16_t. This works due to the 99% cap, but leaves little headroom and invites accidental widening later. Consider uint32_t for clarity and future adjustments, or tighten the comment to “Q16.16 value truncated to 16 bits”.


4789-4793: Minor init flow tweak for safety on first frame.

update() is called before checking stillAlive(). If backing storage isn’t zero-initialized on some path, uninitialized speed_factor could be used once. Not a bug today (allocation zeroes data), but safer to init-dead-first:

-    waves[i].update(SEGLEN, SEGMENT.speed);
-    if (!(waves[i].stillAlive())) {
+    if (!waves[i].stillAlive()) {
       waves[i].init(SEGLEN, SEGMENT.color_from_palette(hw_random8(), false, false, hw_random8(0, 3)));
-    }
+    }
+    waves[i].update(SEGLEN, SEGMENT.speed);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 75f6de9 and 680d09c.

📒 Files selected for processing (1)
  • wled00/FX.cpp (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware files

Files:

  • wled00/FX.cpp
🧠 Learnings (6)
📓 Common learnings
Learnt from: DedeHai
PR: wled/WLED#4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.
Learnt from: mval-sg
PR: wled/WLED#4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.
Learnt from: BobLoeffler68
PR: wled/WLED#4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.374Z
Learning: In WLED FX.cpp, um_data returned by getAudioData() is intentionally untyped because different usermods provide different payloads, and simulateSound() may supply dummy data when the AudioReactive usermod isn’t built. Strongly typed accessors are not feasible; prefer explicit casts (e.g., samplePeak as uint8_t at u_data[3]) or small helpers that encapsulate these casts.
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:31:47.330Z
Learning: In WLED core, avoid introducing AR-specific helper wrappers for um_data access. Keep um_data untyped and, when reading samplePeak, prefer `(*(uint8_t*)um_data->u_data[3]) != 0` over `*(bool*)` to avoid alignment/aliasing issues, while staying decoupled from the AudioReactive usermod.
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
PR: wled/WLED#4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-31T03:38:14.114Z
Learnt from: BobLoeffler68
PR: wled/WLED#4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-06-15T09:59:52.720Z
Learnt from: netmindz
PR: wled/WLED#4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-08T17:22:37.374Z
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.374Z
Learning: In WLED FX.cpp, um_data returned by getAudioData() is intentionally untyped because different usermods provide different payloads, and simulateSound() may supply dummy data when the AudioReactive usermod isn’t built. Strongly typed accessors are not feasible; prefer explicit casts (e.g., samplePeak as uint8_t at u_data[3]) or small helpers that encapsulate these casts.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-09-02T19:42:57.475Z
Learnt from: freakintoddles2
PR: wled/WLED#4904
File: wled00/FX.cpp:3915-3930
Timestamp: 2025-09-02T19:42:57.475Z
Learning: WLED wled00/FX.cpp::mode_percent — For time-based options (% of Minute/Hour/Day), behavior is clock-like: at rollover (elapsed==0) intentionally show SEGLEN lit for one tick to represent completion, then move to 1 LED at the next second. This is by design (not a progress bar) and should not be “fixed”.

Applied to files:

  • wled00/FX.cpp
🧬 Code graph analysis (1)
wled00/FX.cpp (2)
wled00/fcn_declare.h (6)
  • hw_random16 (430-430)
  • hw_random16 (431-431)
  • hw_random16 (432-432)
  • hw_random8 (433-433)
  • hw_random8 (434-434)
  • hw_random8 (435-435)
wled00/colors.cpp (2)
  • color_add (28-61)
  • color_add (28-28)

Comment thread wled00/FX.cpp
Comment thread wled00/FX.cpp Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
wled00/FX.cpp (2)

4715-4727: Clamping cached age factor resolves prior 32-bit overflow risk.

Clamping ageFactor_cached to AW_SCALE-1 is a clean alternative to widening to 64-bit and addresses the earlier overflow chain. Nice.


4753-4772: Signed bound checks fixed the left-side culling bug.

Switching to signed comparisons for center vs. bounds correctly expires left-moving waves off-screen.

🧹 Nitpick comments (4)
wled00/FX.cpp (4)

4682-4685: Good call moving to Q16 fixed-point; add a guard to prevent silent drift later.

Consider adding a compile-time check so future refactors don’t accidentally change AW_SHIFT and break assumptions elsewhere.

 #define AW_SHIFT 16
 #define AW_SCALE (1 << AW_SHIFT)  // 65536 representing 1.0
+static_assert(AW_SHIFT == 16, "Aurora fixed-point expects Q16 (AW_SHIFT == 16).");

4689-4697: Types vs. scale comment mismatch (clarify intent).

  • basealpha and speed_factor are Q16 fractions but stored in uint16_t. That’s fine with AW_SHIFT==16, yet the “scaled by AW_SCALE” comment suggests full 0..AW_SCALE which could mislead maintenance.
  • Recommend clarifying comments to “Q16 fraction (< AW_SCALE)” to prevent future widenings changing behavior.
-    uint16_t basealpha;           // scaled by AW_SCALE
-    uint16_t speed_factor;        // scaled by AW_SCALE
+    uint16_t basealpha;           // Q16 fraction (< AW_SCALE)
+    uint16_t speed_factor;        // Q16 fraction (< AW_SCALE)

4729-4746: Per-LED path is branch-light and fixed-point correct; a couple of small nits.

  • offsetFactor division relies on width ≥ 1 (it is). You can make it explicit to avoid future regressions.
  • Early cull via wave_start/wave_end is great.
-      uint32_t offsetFactor = offset / width;  // scaled by AW_SCALE
+      // width is always >= 1
+      uint32_t offsetFactor = (uint32_t)offset / (uint32_t)width;  // Q16

4795-4800: Backlight + inverse gamma: intent is clear; add a guardrails note.

Inverse-gamma on a 0..3 backlight produces a subtle floor; good for visual consistency. A short comment that this is per-author intent (effect-level shaping) will help future reviewers avoid “optimizing” it away.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 680d09c and c2a359e.

📒 Files selected for processing (1)
  • wled00/FX.cpp (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.{cpp,h}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use spaces (2 per level) for C++ firmware files

Files:

  • wled00/FX.cpp
🧠 Learnings (7)
📓 Common learnings
Learnt from: DedeHai
PR: wled/WLED#4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.
Learnt from: mval-sg
PR: wled/WLED#4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.
Learnt from: BobLoeffler68
PR: wled/WLED#4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:31:47.330Z
Learning: In WLED core, avoid introducing AR-specific helper wrappers for um_data access. Keep um_data untyped and, when reading samplePeak, prefer `(*(uint8_t*)um_data->u_data[3]) != 0` over `*(bool*)` to avoid alignment/aliasing issues, while staying decoupled from the AudioReactive usermod.
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.374Z
Learning: In WLED FX.cpp, um_data returned by getAudioData() is intentionally untyped because different usermods provide different payloads, and simulateSound() may supply dummy data when the AudioReactive usermod isn’t built. Strongly typed accessors are not feasible; prefer explicit casts (e.g., samplePeak as uint8_t at u_data[3]) or small helpers that encapsulate these casts.
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
PR: wled/WLED#4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-31T03:38:14.114Z
Learnt from: BobLoeffler68
PR: wled/WLED#4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-08T17:22:37.374Z
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.374Z
Learning: In WLED FX.cpp, um_data returned by getAudioData() is intentionally untyped because different usermods provide different payloads, and simulateSound() may supply dummy data when the AudioReactive usermod isn’t built. Strongly typed accessors are not feasible; prefer explicit casts (e.g., samplePeak as uint8_t at u_data[3]) or small helpers that encapsulate these casts.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-06-15T09:59:52.720Z
Learnt from: netmindz
PR: wled/WLED#4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-28T08:09:20.630Z
Learnt from: mval-sg
PR: wled/WLED#4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-09-02T19:42:57.475Z
Learnt from: freakintoddles2
PR: wled/WLED#4904
File: wled00/FX.cpp:3915-3930
Timestamp: 2025-09-02T19:42:57.475Z
Learning: WLED wled00/FX.cpp::mode_percent — For time-based options (% of Minute/Hour/Day), behavior is clock-like: at rollover (elapsed==0) intentionally show SEGLEN lit for one tick to represent completion, then move to 1 LED at the next second. This is by design (not a progress bar) and should not be “fixed”.

Applied to files:

  • wled00/FX.cpp
🧬 Code graph analysis (1)
wled00/FX.cpp (2)
wled00/fcn_declare.h (6)
  • hw_random16 (430-430)
  • hw_random16 (431-431)
  • hw_random16 (432-432)
  • hw_random8 (433-433)
  • hw_random8 (434-434)
  • hw_random8 (435-435)
wled00/colors.cpp (2)
  • color_add (28-61)
  • color_add (28-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: wled_build / Build Environments (esp32dev)
  • GitHub Check: wled_build / Build Environments (esp01_1m_full_compat)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32_wrover)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (nodemcuv2)
  • GitHub Check: wled_build / Build Environments (nodemcuv2_160)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32c3dev)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (esp8266_2m_160)
🔇 Additional comments (3)
wled00/FX.cpp (3)

4703-4713: Init math looks safe and overflow-aware.

  • basealpha capped to 99% avoids the AW_SCALE×AW_SCALE corner.
  • center initialization keeps the product < 2^32 even at max segment length, so int32_t center is OK.

4779-4785: Allocation and first-call bootstrapping are robust.

Calling update() on zeroed waves to force a quick “dead → init()” cycle avoids special-casing. Memory footprint stays bounded by aux1.


4802-4810: Color accumulation path LGTM.

Using color_add for CRGBW accumulation with per-wave pre-culling is efficient and visually safe (saturating add).

@blazoncek

Copy link
Copy Markdown
Contributor

Just 2¢. Aurora is a slow effect, no need to rush it. 😉

@DedeHai

DedeHai commented Sep 13, 2025

Copy link
Copy Markdown
Collaborator Author

yes, but 6FPS was a bit too slow for my taste ;)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2a359e and edd1724.

📒 Files selected for processing (1)
  • wled00/FX.cpp (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
wled00/**/*.cpp

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use 2-space indentation for C++ source files (.cpp)

Files:

  • wled00/FX.cpp
🧠 Learnings (18)
📓 Common learnings
Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.
Learnt from: BobLoeffler68
Repo: wled/WLED PR: 4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.
Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.
Learnt from: netmindz
Repo: wled/WLED PR: 4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:31:47.330Z
Learning: In WLED core, avoid introducing AR-specific helper wrappers for um_data access. Keep um_data untyped and, when reading samplePeak, prefer `(*(uint8_t*)um_data->u_data[3]) != 0` over `*(bool*)` to avoid alignment/aliasing issues, while staying decoupled from the AudioReactive usermod.
Learnt from: netmindz
Repo: wled/WLED PR: 4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.374Z
Learning: In WLED FX.cpp, um_data returned by getAudioData() is intentionally untyped because different usermods provide different payloads, and simulateSound() may supply dummy data when the AudioReactive usermod isn’t built. Strongly typed accessors are not feasible; prefer explicit casts (e.g., samplePeak as uint8_t at u_data[3]) or small helpers that encapsulate these casts.
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.
Learnt from: netmindz
Repo: wled/WLED PR: 4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.
Learnt from: DedeHai
Repo: wled/WLED PR: 4997
File: wled00/e131.cpp:33-44
Timestamp: 2025-10-10T18:34:06.550Z
Learning: In WLED's DDP packet handling (ws.cpp and e131.cpp), only prevent out-of-bounds memory access rather than enforcing DDP spec compliance. Don't check the 1440-byte spec limit—accept out-of-spec packets assuming correct encoding. The bounds check `maxDataIndex = c + numLeds * ddpChannelsPerLed; if (maxDataIndex > dataLen) reject` is sufficient and already covers the timecode flag case (when c=4) without needing separate validation.
Learnt from: netmindz
Repo: wled/WLED PR: 4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.
📚 Learning: 2025-08-26T11:51:21.817Z
Learnt from: DedeHai
Repo: wled/WLED PR: 4798
File: wled00/FX.cpp:7531-7533
Timestamp: 2025-08-26T11:51:21.817Z
Learning: In WLED PR #4798, DedeHai confirmed that certain gamma-related calls in FX.cpp/FX_fcn.cpp/particle systems are intentional for effect-level shaping (e.g., brightness curves, TV sim, Pride 2015 pre-mix), distinct from final output gamma. Do not flag or remove these in future reviews; add comments when feasible to clarify intent.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-31T03:38:14.114Z
Learnt from: BobLoeffler68
Repo: wled/WLED PR: 4891
File: wled00/FX.cpp:3333-3349
Timestamp: 2025-08-31T03:38:14.114Z
Learning: WLED PacMan effect (wled00/FX.cpp): Keep pacmancharacters_t position fields as signed int (not int16_t). Maintainer preference (blazoncek) prioritizes avoiding potential overhead/regressions over minor RAM savings. Avoid type shrinking here unless memory pressure is demonstrated.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-11-14T13:37:11.994Z
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with appropriate defined constants when those constants are meaningful in the context of the PR. For example, the hardcoded value 32 should be replaced with WLED_MAX_SEGNAME_LEN when it represents a segment name length limit. This improves code maintainability and reduces the risk of inconsistencies.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-11-14T13:37:30.955Z
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, when code is modified or added, look for "magic numbers" (hardcoded numeric literals) and suggest replacing them with defined constants when meaningful constants exist in the codebase. For example, suggest replacing hardcoded "32" with WLED_MAX_SEGNAME_LEN if the context relates to segment name length limits.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-08T17:22:37.374Z
Learnt from: netmindz
Repo: wled/WLED PR: 4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.374Z
Learning: In WLED FX.cpp, um_data returned by getAudioData() is intentionally untyped because different usermods provide different payloads, and simulateSound() may supply dummy data when the AudioReactive usermod isn’t built. Strongly typed accessors are not feasible; prefer explicit casts (e.g., samplePeak as uint8_t at u_data[3]) or small helpers that encapsulate these casts.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-28T08:09:20.630Z
Learnt from: mval-sg
Repo: wled/WLED PR: 4876
File: wled00/xml.cpp:0-0
Timestamp: 2025-08-28T08:09:20.630Z
Learning: The WLED codebase has opportunities for refactoring hardcoded array bounds (like the "15" used for DMX channels) to use sizeof(array)/sizeof(array[0]) for more maintainable code, but such changes should be done consistently across the entire codebase in a dedicated refactoring effort.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-08-08T17:31:47.330Z
Learnt from: netmindz
Repo: wled/WLED PR: 4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:31:47.330Z
Learning: In WLED core, avoid introducing AR-specific helper wrappers for um_data access. Keep um_data untyped and, when reading samplePeak, prefer `(*(uint8_t*)um_data->u_data[3]) != 0` over `*(bool*)` to avoid alignment/aliasing issues, while staying decoupled from the AudioReactive usermod.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-09-16T18:08:42.848Z
Learnt from: DedeHai
Repo: wled/WLED PR: 4939
File: wled00/FX_fcn.cpp:1176-1187
Timestamp: 2025-09-16T18:08:42.848Z
Learning: In WLED finalizeInit() bus creation (wled00/FX_fcn.cpp), intentionally allowing memory overruns when bus configurations exceed MAX_LED_MEMORY is a deliberate design choice. The trade-off prioritizes creating buses with reduced LED counts over completely failing to create buses, which would cause no LED output and UI failures. This approach forces users to update configurations after migrating to version 0.16 while maintaining basic functionality.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-10-10T18:34:06.550Z
Learnt from: DedeHai
Repo: wled/WLED PR: 4997
File: wled00/e131.cpp:33-44
Timestamp: 2025-10-10T18:34:06.550Z
Learning: In WLED's DDP packet handling (ws.cpp and e131.cpp), only prevent out-of-bounds memory access rather than enforcing DDP spec compliance. Don't check the 1440-byte spec limit—accept out-of-spec packets assuming correct encoding. The bounds check `maxDataIndex = c + numLeds * ddpChannelsPerLed; if (maxDataIndex > dataLen) reject` is sufficient and already covers the timecode flag case (when c=4) without needing separate validation.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-09-02T19:42:57.475Z
Learnt from: freakintoddles2
Repo: wled/WLED PR: 4904
File: wled00/FX.cpp:3915-3930
Timestamp: 2025-09-02T19:42:57.475Z
Learning: WLED wled00/FX.cpp::mode_percent — For time-based options (% of Minute/Hour/Day), behavior is clock-like: at rollover (elapsed==0) intentionally show SEGLEN lit for one tick to represent completion, then move to 1 LED at the next second. This is by design (not a progress bar) and should not be “fixed”.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-11-14T13:22:20.525Z
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:22:20.525Z
Learning: In WLED's image_loader.cpp and similar contexts, when suggesting cleanup or de-allocation code in error handlers, first verify whether the underlying library or function already handles cleanup after failure. For example, `new` expressions that throw exceptions do not assign partial pointers and automatically clean up storage, making explicit dealloc() calls in catch blocks unnecessary. Only suggest "safety" cleanup when the library/function's documented semantics do not already provide graceful failure handling.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-10-15T03:12:37.106Z
Learnt from: Brandon502
Repo: wled/WLED PR: 4995
File: wled00/FX.cpp:5223-5226
Timestamp: 2025-10-15T03:12:37.106Z
Learning: In wled00/FX.cpp Game of Life (mode_2Dgameoflife), spaceship/glider repeat detection is primarily intended for small grids; the maintainer is okay with deprioritizing overflow concerns for very large matrices.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-11-14T13:37:30.955Z
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:30.955Z
Learning: In WLED code reviews, verify that file operations (especially file.open()) respect LittleFS filename limitations. Assume default WLED configuration with LittleFS default filename limit of 255 bytes. Do not assume extreme configuration values like WLED_MAX_SEGNAME_LEN = 512 which would not be standard configurations.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-11-14T13:37:11.994Z
Learnt from: softhack007
Repo: wled/WLED PR: 0
File: :0-0
Timestamp: 2025-11-14T13:37:11.994Z
Learning: In WLED code reviews, file operations (especially file.open()) should be checked to ensure they respect LittleFS filename limitations. The default LittleFS filename limit is 255 bytes (LFS_NAME_MAX). Reviews should assume default WLED configuration defines and not extreme edge-case values (e.g., WLED_MAX_SEGNAME_LEN = 512 would not be standard). File paths should be validated to stay within the 255-byte limit.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-06-15T09:59:52.720Z
Learnt from: netmindz
Repo: wled/WLED PR: 4728
File: wled00/FX.h:378-378
Timestamp: 2025-06-15T09:59:52.720Z
Learning: In WLED's FX.h, MODE_COUNT represents the highest FX_MODE_ ID + 1, not the total count of FX_MODE_ definitions. This is because some effects may have been removed but their IDs are not reused, creating gaps in the numbering sequence. MODE_COUNT is used for array bounds and range checking.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-10-20T09:41:50.374Z
Learnt from: blazoncek
Repo: wled/WLED PR: 4995
File: wled00/FX.cpp:5209-5212
Timestamp: 2025-10-20T09:41:50.374Z
Learning: In WLED 2D effects, SEGMENT.length() returns the physical pixel count (upper bound), while SEG_W * SEG_H can be smaller depending on mapping (mirroring/grouping). For per-cell state buffers (e.g., mode_2Dgameoflife in wled00/FX.cpp), allocate using SEGMENT.length() to ensure sufficient capacity and avoid reallocations, while bounding indexing by cols*rows.

Applied to files:

  • wled00/FX.cpp
📚 Learning: 2025-10-20T09:38:51.997Z
Learnt from: blazoncek
Repo: wled/WLED PR: 4995
File: wled00/FX.cpp:5223-5226
Timestamp: 2025-10-20T09:38:51.997Z
Learning: WLED matrices: each dimension (SEG_W, SEG_H) is limited to ≤255; 256 or larger per side is not supported/feasible on ESP32, so effects should assume per-dimension max 255.

Applied to files:

  • wled00/FX.cpp
🧬 Code graph analysis (1)
wled00/FX.cpp (2)
wled00/fcn_declare.h (6)
  • hw_random16 (432-432)
  • hw_random16 (433-433)
  • hw_random16 (434-434)
  • hw_random8 (435-435)
  • hw_random8 (436-436)
  • hw_random8 (437-437)
wled00/colors.cpp (2)
  • color_add (28-59)
  • color_add (28-28)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_16MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32s3_4M_qspi)
  • GitHub Check: wled_build / Build Environments (lolin_s2_mini)
  • GitHub Check: wled_build / Build Environments (usermods)
  • GitHub Check: wled_build / Build Environments (esp32s3dev_8MB_opi)
  • GitHub Check: wled_build / Build Environments (esp32dev_debug)
  • GitHub Check: wled_build / Build Environments (esp32_eth)
  • GitHub Check: wled_build / Build Environments (esp32dev)
🔇 Additional comments (4)
wled00/FX.cpp (4)

4685-4716: Fixed‑point constants and AuroraWave initialization look sound.

Using AW_SHIFT = 16/AW_SCALE = 1 << AW_SHIFT plus Q16‐scaled center, ageFactor_cached, and basealpha is consistent, and the basealpha range < AW_SCALE plus ttl/width ranges keep values in safe 32‑bit territory. The speed_factor computation correctly folds the 0–255 speed into the fixed‑point scale so step = speed_factor * speed stays within int32_t while producing a reasonable LED‑per‑frame rate. No issues here.


4718-4748: Brightness fixed‑point chain is now overflow‑safe.

ageFactor_cached is computed in Q16 and clamped to < AW_SCALE, and offsetFactor is derived as a Q16 ratio of distance/width. With brightness_factor = (AW_SCALE - offsetFactor) and all three factors < AW_SCALE, each uint32_t multiply (brightness_factor * ageFactor_cached, then * basealpha) stays below 2^32 before the >> AW_SHIFT downshift, avoiding the earlier 32‑bit overflow hazard without needing 64‑bit intermediates. The final per‑channel scales (basecolor.* * brightness_factor) >> AW_SHIFT are also comfortably within int32_t.


4753-4775: AuroraWave::update fixed‑point motion & bounds checks are consistent.

step = speed_factor * speed uses the pre‑scaled speed_factor so movement scales linearly with speed while remaining Q16; center is updated in signed 32‑bit space, and the new left/right culling logic (center < -width_scaled vs > segment_length_scaled + width_scaled) now uses fully signed arithmetic, avoiding the previous unsigned‑promotion bug at the left boundary. This aligns well with the cached extents and keeps life‑time and off‑screen termination robust.


4781-4813: mode_aurora wiring into the new AuroraWave API looks correct.

The effect now:

  • Allocates AuroraWave array based on SEGMENT.intensity and reuses it via SEGENV.data.
  • Updates each wave, re‑initializing only dead ones, then calls updateCachedValues() once per frame (not per pixel).
  • Accumulates per‑pixel color in CRGBW mixedRgb using the cached getColorForLED(), then writes via SEGMENT.setPixelColor().
  • Computes a simple backlight contribution and passes it through gamma8inv for effect‑level shaping, which aligns with prior gamma‑usage learnings.

Overall the wiring matches the new fixed‑point/caching model and should deliver the intended performance gains.

Comment thread wled00/FX.cpp
@DedeHai
DedeHai merged commit 8348089 into wled:main Nov 16, 2025
22 checks passed
@DedeHai
DedeHai deleted the aurora_improvements branch November 16, 2025 20:27
@coderabbitai coderabbitai Bot mentioned this pull request Mar 9, 2026
aenertia pushed a commit to aenertia/WLED that referenced this pull request Aug 18, 2026
* improvements to Aurora FX

- converted to integer math, increasing speed on all ESPs, also shrinks code size
- caching values to avoid repeated calculations
- CRGBW instead or CRGB, adds white channel support when not using palette
- fix for new brightness/gamma handling

* overflow & unsigned fix
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Awaiting testing effect optimization re-working an existing feature to be faster, or use less memory

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants