Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# ------------------------------------------------------------------------------

# CI/release binaries
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods
default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Undefined environment in default_envs: esp32dev_V4

"default_envs" includes "esp32dev_V4", but there is no corresponding [env:esp32dev_V4] defined in this file. This will cause PlatformIO to fail when building CI/release binaries. The existing [env:esp32dev] already targets the V4 toolchain (esp32_idf_V4), so "esp32dev_V4" looks like a mistaken/duplicate entry.

Apply this diff to fix:

-default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods
+default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods

Run to confirm there is no such env:


🏁 Script executed:

#!/bin/bash
rg -nP '^\s*\[env:esp32dev_V4\]' platformio.ini || echo "OK: env:esp32dev_V4 not defined (should not be in default_envs)"

Length of output: 186


Remove undefined “esp32dev_V4” from default_envs

Confirmed there is no [env:esp32dev_V4] defined in platformio.ini, so including it in default_envs will break CI/builds.

Attention:

  • platformio.ini (line 13): default_envs list

Apply this diff:

-default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32dev_V4, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods
+default_envs = nodemcuv2, esp8266_2m, esp01_1m_full, nodemcuv2_160, esp8266_2m_160, esp01_1m_full_160, nodemcuv2_compat, esp8266_2m_compat, esp01_1m_full_compat, esp32dev, esp32_eth, lolin_s2_mini, esp32c3dev, esp32s3dev_16MB_opi, esp32s3dev_8MB_opi, esp32s3_4M_qspi, esp32_wrover, usermods
🤖 Prompt for AI Agents
In platformio.ini around line 13, the default_envs list includes a non-existent
env `esp32dev_V4` which will break CI/builds; remove `esp32dev_V4` from the
default_envs entry (or alternatively add a matching `[env:esp32dev_V4]` section
if that env is required), ensure commas and spacing remain consistent after
removal, and save the file so CI uses only defined environments.

Copy link
Member

@softhack007 softhack007 Dec 26, 2025

Choose a reason for hiding this comment

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

Veto ;-) to any changes in platformio.ini.

The modification to platformio.ini is not related to the scope of the PR. Please remove unrelated changes.


src_dir = ./wled00
data_dir = ./wled00/data
Expand Down
114 changes: 114 additions & 0 deletions wled00/FX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10644,6 +10644,118 @@ uint8_t WS2812FX::addEffect(uint8_t id, mode_ptr mode_fn, const char *mode_name)
}
}

/*
Simple bit strobe
*/
uint16_t mode_music_strobe(void) {
um_data_t *um_data = getAudioData();
if (!um_data) return FRAMETIME;

bool samplePeak = *(bool*)um_data->u_data[3];
int volumeRaw = *(int16_t*)um_data->u_data[1];
Comment on lines +10654 to +10655
Copy link
Contributor

@coderabbitai coderabbitai bot Aug 8, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid raw pointer casts for audio flags.

*(bool*)um_data->u_data[3] assumes the pointer is valid and correctly aligned for a bool, which isn’t guaranteed across platforms.
If um_data already provides strongly-typed accessors (e.g. um_data->samplePeak or similar), use those instead; otherwise add a helper that hides the cast in one place.

🤖 Prompt for AI Agents
In wled00/FX.cpp around lines 10654 to 10655, avoid using raw pointer casts like
*(bool*)um_data->u_data[3] to access audio flags because it assumes pointer
validity and alignment that may not hold. Instead, check if um_data offers a
strongly-typed accessor for samplePeak and volumeRaw and use those. If not,
create a helper function that safely encapsulates the cast and access in one
place to improve safety and readability.

Copy link
Member

Choose a reason for hiding this comment

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

um_data is not strongly typed as different usermods can send different data. Sadly we can't return a strongly typed result from getAudioData as the AudioReactive usermod might not be included in the build and so dummy data is returned for effects that expect audio

Copy link
Contributor

Choose a reason for hiding this comment

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

@netmindz Thanks for the context. Agreed — since um_data is intentionally untyped (and can be simulated), we can’t introduce a strongly typed accessor.

Small, safe tweak we can still do to avoid aliasing through a bool pointer: read the documented byte and then convert to bool. That keeps the loose typing but eliminates potential alignment/aliasing pitfalls and matches the mapping comment in FX.cpp (samplePeak is uint8_t at u_data[3]).

Example minimal change in the new effects:

// before
bool samplePeak = *(bool*)um_data->u_data[3];

// after (safer and aligned with documented mapping)
bool samplePeak = (*(uint8_t*)um_data->u_data[3]) != 0;

Optionally, we can centralize this in tiny helpers near getAudioData() to keep casts in one place (still generic, no strong typing):

static inline bool ar_samplePeak(const um_data_t* d) {
  return (*(uint8_t*)d->u_data[3]) != 0;
}
static inline int16_t ar_volumeRaw(const um_data_t* d) {
  return *(int16_t*)d->u_data[1];
}
// usage
bool samplePeak = ar_samplePeak(um_data);
int  volumeRaw  = ar_volumeRaw(um_data);

If you’re OK with it, I’ll suggest the minimal bool change across mode_music_strobe and mode_flame_jet to stay consistent with the file’s mapping.


✏️ Learnings added
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.352Z
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.

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: 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.

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.

Learnt from: DedeHai
PR: wled/WLED#4750
File: usermods/audioreactive/audio_reactive.cpp:311-321
Timestamp: 2025-06-27T06:04:44.652Z
Learning: In WLED's AudioReactive usermod, FFT buffer memory (valFFT, windowFFT) is allocated once during initialization and never deallocated, following typical embedded system design where core functionality buffers persist for the application lifetime. Raw buffer pointers for aligned allocations don't need to be tracked in the current implementation since deallocation is never performed.

Learnt from: blazoncek
PR: wled/WLED#4667
File: usermods/user_fx/user_fx.cpp:27-30
Timestamp: 2025-04-30T05:41:03.633Z
Learning: In WLED, the Segment::allocateData() method already includes optimization to check if data is allocated and sufficiently sized, handling buffer reuse to reduce memory fragmentation. Adding an external check like `if (SEGENV.data == nullptr && !SEGENV.allocateData(dataSize))` is unnecessary and could be problematic, as it bypasses proper size verification.

Copy link
Member

Choose a reason for hiding this comment

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

those helper methods would certainly help code readability, but it does mean adding ar_ functions into the main codebase that relate to a usermod, so you might as well at that stage add strongly typed return of getAudioData as both is adding AR specific code into the general codebase

Copy link
Contributor

Choose a reason for hiding this comment

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

@netmindz Totally fair. Let’s keep core clean and avoid AR-specific helpers.

I’ll switch the samplePeak read to the safer inline form (aligned with the documented mapping) and leave everything else as-is:

// mode_music_strobe
um_data_t *um_data = getAudioData();
if (!um_data) return FRAMETIME;

bool    samplePeak = (*(uint8_t*)um_data->u_data[3]) != 0;
int     volumeRaw  = *(int16_t*)um_data->u_data[1];
// mode_flame_jet
um_data_t *um_data = getAudioData();
if (!um_data) return FRAMETIME;

bool    samplePeak = (*(uint8_t*)um_data->u_data[3]) != 0;
int     volumeRaw  = *(int16_t*)um_data->u_data[1];

This avoids aliasing through a bool pointer, preserves the untyped contract of um_data, and doesn’t introduce any AR-specific helpers into the codebase.


✏️ Learnings added
Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:31:47.296Z
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.

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: 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.

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.

Learnt from: netmindz
PR: wled/WLED#4819
File: wled00/FX.cpp:10654-10655
Timestamp: 2025-08-08T17:22:37.352Z
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: DedeHai
PR: wled/WLED#4750
File: usermods/audioreactive/audio_reactive.cpp:311-321
Timestamp: 2025-06-27T06:04:44.652Z
Learning: In WLED's AudioReactive usermod, FFT buffer memory (valFFT, windowFFT) is allocated once during initialization and never deallocated, following typical embedded system design where core functionality buffers persist for the application lifetime. Raw buffer pointers for aligned allocations don't need to be tracked in the current implementation since deallocation is never performed.

Learnt from: blazoncek
PR: wled/WLED#4667
File: usermods/user_fx/user_fx.cpp:27-30
Timestamp: 2025-04-30T05:41:03.633Z
Learning: In WLED, the Segment::allocateData() method already includes optimization to check if data is allocated and sufficiently sized, handling buffer reuse to reduce memory fragmentation. Adding an external check like `if (SEGENV.data == nullptr && !SEGENV.allocateData(dataSize))` is unnecessary and could be problematic, as it bypasses proper size verification.

Learnt from: KrX3D
PR: wled/WLED#4585
File: usermods/seven_segment_display_reloaded_v2/seven_segment_display_reloaded_v2.h:121-136
Timestamp: 2025-04-27T09:37:28.415Z
Learning: Using PROGMEM for the seven-segment font array (umSSDRNumbers) in the WLED SSDR usermod causes compilation problems, so it should be left as a regular array.

Learnt from: willmmiles
PR: wled/WLED#4623
File: usermods/word-clock-matrix/word-clock-matrix.cpp:332-332
Timestamp: 2025-03-29T01:22:54.617Z
Learning: In the WLED project, hardcoded usermod IDs (like 500 in the WordClockMatrix's getId() method) are intentionally used as part of a strategy to avoid modifying core code. There are plans to remove numeric usermod IDs entirely in the future.


long mappedSpeed = map(SEGMENT.speed, 0, 255, 0, 20);
uint8_t fadeBy = 255 - mappedSpeed;
SEGMENT.fade_out(fadeBy);

uint8_t threshold = SEGMENT.intensity;

if (samplePeak && volumeRaw > threshold) {
SEGMENT.fill(SEGCOLOR(0));
}

return FRAMETIME;
}

static const char _data_FX_MODE_MUSIC_STROBE[] PROGMEM = "Music Strobe@Fade speed,Threshold;!,!;!;1v;ix=128,sx=224,si=1";
Copy link
Member

Choose a reason for hiding this comment

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

Please verify if the metadata string is correct. I think that "1v" is for virtual strip effects, not for fx that support both 1D and 2D.


/*
Flame jet
*/
uint16_t mode_flame_jet(void) {
um_data_t *um_data = getAudioData();
if (!um_data) return FRAMETIME;

bool samplePeak = *(bool*)um_data->u_data[3];
int volumeRaw = *(int16_t*)um_data->u_data[1];

long mappedFade = map(SEGMENT.intensity, 0, 255, 0, 64);
uint8_t fade_by = 255 - mappedFade;
SEGMENT.fade_out(fade_by);

uint8_t threshold = SEGMENT.custom1;

if (samplePeak && volumeRaw > threshold && SEGENV.aux0 == 0) {
SEGENV.aux0 = 1; // start animation
}

// --- Animation ---
if (SEGENV.aux0 > 0) {
long mappedSpeed = map(SEGMENT.speed, 0, 255, 0, 32);
uint16_t rise_amount = 1 + (uint16_t)(volumeRaw * (1 + (uint16_t)mappedSpeed)) / 2000;

if (SEGMENT.is2D()) {
// --- 2D LOGIC ---
const uint16_t max_height = SEG_H;
uint16_t start_y = SEG_H - 1;

for (uint16_t y_offset = 0; y_offset < SEGENV.aux0; y_offset++) {
uint16_t current_y = start_y - y_offset;
if (current_y >= SEG_H) continue; // Boundary check

Comment on lines +10702 to +10705
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Potential unsigned underflow when current_y wraps.

When y_offset > start_y, current_y = start_y - y_offset wraps to 65 535, the subsequent >= SEG_H check skips the pixel but the loop keeps iterating. Break early to avoid wasted iterations:

if (y_offset > start_y) break;  // prevents under-flow
🤖 Prompt for AI Agents
In wled00/FX.cpp around lines 10702 to 10705, the calculation of current_y as
start_y minus y_offset can cause unsigned underflow when y_offset exceeds
start_y, resulting in a large value that passes the boundary check but wastes
iterations. To fix this, add a condition to break the loop early if y_offset is
greater than start_y, preventing the underflow and unnecessary loop iterations.

uint32_t base_color = SEGCOLOR(0);
CRGB fastled_color = CRGB(base_color);

uint8_t heat_reduction = map(y_offset, 0, SEG_H, 0, 180);
fastled_color.g = qsub8(fastled_color.g, heat_reduction);
fastled_color.b = qsub8(fastled_color.b, heat_reduction * 2);
Copy link
Member

Choose a reason for hiding this comment

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

What happens when one of the color channels is less than heat_reduction ? Will the value wrap around (= higher value), or will it be clamped at 0?


for (uint16_t x = 0; x < SEG_W; x++) {
CRGB final_color = fastled_color;
if (hw_random8() < 50) {
final_color.nscale8(220);
}
SEGMENT.setPixelColorXY(x, current_y, final_color);
}
}
SEGENV.aux0 += rise_amount;
if (SEGENV.aux0 >= max_height) {
SEGENV.aux0 = 0;
}

} else {
// --- 1D LOGIC ---
const uint16_t max_height = SEGLEN;
uint16_t start_index = 0; // Or SEGLEN - 1 if you want it from the other end

for (uint16_t i_offset = 0; i_offset < SEGENV.aux0; i_offset++) {
uint16_t current_index = start_index + i_offset;
if (current_index >= SEGLEN) continue; // Boundary check
Copy link
Member

@softhack007 softhack007 Dec 26, 2025

Choose a reason for hiding this comment

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

Better to use break; instead of continue


uint32_t base_color = SEGCOLOR(0);
CRGB fastled_color = CRGB(base_color);

uint8_t heat_reduction = map(i_offset, 0, SEGLEN, 0, 180);
fastled_color.g = qsub8(fastled_color.g, heat_reduction);
fastled_color.b = qsub8(fastled_color.b, heat_reduction * 2);
Copy link
Member

Choose a reason for hiding this comment

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

Same question as for the 2D case - how is qsub8 handling results <0 ?


if (hw_random8() < 50) {
fastled_color.nscale8(220);
}
SEGMENT.setPixelColor(current_index, fastled_color);
}
Comment on lines +10731 to +10746
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Break early when 1D index passes SEGLEN; honor segment direction.

  • The loop continues even after current_index exceeds SEGLEN, performing useless iterations. Break early to save cycles.
  • Consider drawing from the configured segment “end” when reversed. Many effects respect SEGMENT.reverse.
-      const uint16_t max_height = SEGLEN;
-      uint16_t start_index = 0; // Or SEGLEN - 1 if you want it from the other end
+      const uint16_t max_height = SEGLEN;
+      const bool rev = SEGMENT.reverse;
+      uint16_t start_index = rev ? (SEGLEN - 1) : 0;

-      for (uint16_t i_offset = 0; i_offset < SEGENV.aux0; i_offset++) {
-        uint16_t current_index = start_index + i_offset;
-        if (current_index >= SEGLEN) continue; // Boundary check
+      for (uint16_t i_offset = 0; i_offset < SEGENV.aux0; i_offset++) {
+        uint16_t current_index = rev ? (start_index - i_offset) : (start_index + i_offset);
+        if (current_index >= SEGLEN) break; // Boundary check & early exit
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (uint16_t i_offset = 0; i_offset < SEGENV.aux0; i_offset++) {
uint16_t current_index = start_index + i_offset;
if (current_index >= SEGLEN) continue; // Boundary check
uint32_t base_color = SEGCOLOR(0);
CRGB fastled_color = CRGB(base_color);
uint8_t heat_reduction = map(i_offset, 0, SEGLEN, 0, 180);
fastled_color.g = qsub8(fastled_color.g, heat_reduction);
fastled_color.b = qsub8(fastled_color.b, heat_reduction * 2);
if (hw_random8() < 50) {
fastled_color.nscale8(220);
}
SEGMENT.setPixelColor(current_index, fastled_color);
}
const uint16_t max_height = SEGLEN;
const bool rev = SEGMENT.reverse;
uint16_t start_index = rev ? (SEGLEN - 1) : 0;
for (uint16_t i_offset = 0; i_offset < SEGENV.aux0; i_offset++) {
uint16_t current_index = rev
? (start_index - i_offset)
: (start_index + i_offset);
if (current_index >= SEGLEN) break; // Boundary check & early exit
uint32_t base_color = SEGCOLOR(0);
CRGB fastled_color = CRGB(base_color);
uint8_t heat_reduction = map(i_offset, 0, SEGLEN, 0, 180);
fastled_color.g = qsub8(fastled_color.g, heat_reduction);
fastled_color.b = qsub8(fastled_color.b, heat_reduction * 2);
if (hw_random8() < 50) {
fastled_color.nscale8(220);
}
SEGMENT.setPixelColor(current_index, fastled_color);
}
🤖 Prompt for AI Agents
In wled00/FX.cpp around lines 10731 to 10746, the loop currently continues past
the segment end and ignores segment direction; change the logic to break the
loop when the computed 1D index would be out of bounds instead of continuing to
waste cycles, and compute the index using the segment direction (respect
SEGMENT.reverse) so pixels are drawn from the configured segment end when
reversed (e.g., derive current_index from start_index +/- i_offset based on
SEGMENT.reverse, check bounds once and break if out of range, then proceed with
color/heat logic).

SEGENV.aux0 += rise_amount;
if (SEGENV.aux0 >= max_height) {
SEGENV.aux0 = 0;
}
}
}

return FRAMETIME;
}

static const char _data_FX_MODE_FLAME_JET[] PROGMEM = "Flame Jet@Base Speed,Trail Length,Threshold;!;!;1v;ix=192,sx=128,c1=128,pal=35,si=1";
Copy link
Member

Choose a reason for hiding this comment

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

Same here - please verify if the metadata is correct.


void WS2812FX::setupEffectData() {
// Solid must be first! (assuming vector is empty upon call to setup)
_mode.push_back(&mode_static);
Expand Down Expand Up @@ -10778,6 +10890,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_DYNAMIC_SMOOTH, &mode_dynamic_smooth, _data_FX_MODE_DYNAMIC_SMOOTH);

// --- 1D audio effects ---
addEffect(FX_MODE_MUSIC_STROBE, &mode_music_strobe, _data_FX_MODE_MUSIC_STROBE);
addEffect(FX_MODE_PIXELS, &mode_pixels, _data_FX_MODE_PIXELS);
addEffect(FX_MODE_PIXELWAVE, &mode_pixelwave, _data_FX_MODE_PIXELWAVE);
addEffect(FX_MODE_JUGGLES, &mode_juggles, _data_FX_MODE_JUGGLES);
Expand Down Expand Up @@ -10851,6 +10964,7 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_2DOCTOPUS, &mode_2Doctopus, _data_FX_MODE_2DOCTOPUS);
addEffect(FX_MODE_2DWAVINGCELL, &mode_2Dwavingcell, _data_FX_MODE_2DWAVINGCELL);
addEffect(FX_MODE_2DAKEMI, &mode_2DAkemi, _data_FX_MODE_2DAKEMI); // audio
addEffect(FX_MODE_FLAME_JET, &mode_flame_jet, _data_FX_MODE_FLAME_JET);

#ifndef WLED_DISABLE_PARTICLESYSTEM2D
addEffect(FX_MODE_PARTICLEVOLCANO, &mode_particlevolcano, _data_FX_MODE_PARTICLEVOLCANO);
Expand Down
4 changes: 3 additions & 1 deletion wled00/FX.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,9 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
#define FX_MODE_PS1DSONICBOOM 215
#define FX_MODE_PS1DSPRINGY 216
#define FX_MODE_PARTICLEGALAXY 217
#define MODE_COUNT 218
#define FX_MODE_MUSIC_STROBE 218
#define FX_MODE_FLAME_JET 219
#define MODE_COUNT 220


#define BLEND_STYLE_FADE 0x00 // universal
Expand Down
Loading