From 95b2b8b566c71b4ae28c1223ce9d6d5c71c3d949 Mon Sep 17 00:00:00 2001 From: Greg <{ID}+{username}@users.noreply.github.com> Date: Wed, 2 Jul 2025 15:51:00 -0700 Subject: [PATCH 1/6] Add a new effect for a single equalizer bar to the WLED project. --- wled00/FX.cpp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ wled00/FX.h | 1 + 2 files changed, 50 insertions(+) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 4a364ea654..1767172421 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7248,6 +7248,54 @@ uint16_t mode_2DGEQ(void) { // By Will Tatam. Code reduction by Ewoud Wijma. } // mode_2DGEQ() static const char _data_FX_MODE_2DGEQ[] PROGMEM = "GEQ@Fade speed,Ripple decay,# of bands,,,Color bars;!,,Peaks;!;2f;c1=255,c2=64,pal=11,si=0"; // Beatsin +///////////////////////// +// Single EQ Bar // +///////////////////////// +uint16_t mode_single_eqbar(void) { + if (!SEGENV.allocateData(sizeof(uint16_t))) return mode_static(); + uint16_t *prevBarHeight = (uint16_t*)SEGENV.data; + if (SEGENV.call == 0) *prevBarHeight = 0; + + // Grab audio data - we only need the fftResult here, as we want the frequency data + um_data_t *um_data = getAudioData(); + uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; + if (!fftResult) return mode_static(); + + // User controls. Speed is referenced directly instead of creating a new varible. + uint8_t freqBin = map(SEGMENT.custom1, 0, 255, 0, 15); // 0-15 (or up to available bins) + uint8_t peakDecay = (SEGMENT.intensity == 0) ? 0 : map(255 - SEGMENT.intensity, 1, 255, 1, 32); // Grab the intensity value for peak decay speed. Invert for ease of use. + + int barHeight = map(fftResult[freqBin], 0, 255, 0, SEGLEN); // Grab new bar height + if (barHeight > *prevBarHeight) *prevBarHeight = barHeight; // Update the previous bar height if the new height is greater + + SEGMENT.fade_out(SEGMENT.speed); // Always fade out existing bars according to speed slider. + + // Draw the main bar (but not peak pixel) + for (int i = 0; i < barHeight; i++) { + if (i < barHeight) { + // Draw the main bar according to the palette. Don't draw the top pixel, that's drawn by the peak handling. + SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + } + } + + if (peakDecay == 0 && barHeight > 0){ + // No peak pixel if decay is set to zero, just draw the bar. + SEGMENT.setPixelColor(barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); + } else { + // Peak decay, set pixel and handle decay. Clear pixels over peak (otherwise they would fadewith value from speed slider) + if (*prevBarHeight > 0 && (SEGENV.call % (peakDecay > 1 ? peakDecay : 1)) == 0) (*prevBarHeight)--; + + if (*prevBarHeight > 0) { + SEGMENT.setPixelColor(*prevBarHeight, SEGCOLOR(2)); + } + if (*prevBarHeight < SEGLEN) { + SEGMENT.setPixelColor(*prevBarHeight + 1, BLACK); // clear next pixel immediately. + } + } + + return FRAMETIME; +} +static const char _data_FX_MODE_SINGLE_EQBAR[] PROGMEM = "Single EQ Bar@Fade speed,Ripple decay,Frequency bin;!,,Peaks;!;!;1vf;c1=0,c2=8,si=0"; ///////////////////////// // ** 2D Funky plank // @@ -10818,5 +10866,6 @@ addEffect(FX_MODE_PS1DSONICSTREAM, &mode_particle1DsonicStream, _data_FX_MODE_PS addEffect(FX_MODE_PS1DSONICBOOM, &mode_particle1DsonicBoom, _data_FX_MODE_PS_SONICBOOM); addEffect(FX_MODE_PS1DSPRINGY, &mode_particleSpringy, _data_FX_MODE_PS_SPRINGY); #endif // WLED_DISABLE_PARTICLESYSTEM1D +addEffect(FX_MODE_SINGLE_EQBAR, &mode_single_eqbar, _data_FX_MODE_SINGLE_EQBAR); } diff --git a/wled00/FX.h b/wled00/FX.h index 82213179bd..0db5eeddd2 100755 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -374,6 +374,7 @@ extern byte realtimeMode; // used in getMappedPixelIndex() #define FX_MODE_PS1DSPRINGY 216 #define FX_MODE_PARTICLEGALAXY 217 #define MODE_COUNT 218 +#define FX_MODE_SINGLE_EQBAR 219 #define BLEND_STYLE_FADE 0x00 // universal From dbf1bb6e85175ed3a9954624cccf5558dc7da45e Mon Sep 17 00:00:00 2001 From: Greg <{ID}+{username}@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:01:27 -0700 Subject: [PATCH 2/6] Clean up redundant logic, add better comments. --- wled00/FX.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 1767172421..cce2c5a190 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7272,19 +7272,17 @@ uint16_t mode_single_eqbar(void) { // Draw the main bar (but not peak pixel) for (int i = 0; i < barHeight; i++) { - if (i < barHeight) { - // Draw the main bar according to the palette. Don't draw the top pixel, that's drawn by the peak handling. - SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); - } + SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } if (peakDecay == 0 && barHeight > 0){ - // No peak pixel if decay is set to zero, just draw the bar. + // No peak pixel if decay is set to zero, just draw the peak pixel of the bar. SEGMENT.setPixelColor(barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); } else { - // Peak decay, set pixel and handle decay. Clear pixels over peak (otherwise they would fadewith value from speed slider) + // Decrement prevBarHeight according to peakDecay if (*prevBarHeight > 0 && (SEGENV.call % (peakDecay > 1 ? peakDecay : 1)) == 0) (*prevBarHeight)--; + // Set peak pixel and clear pixels over peak (otherwise they would fadewith value from speed slider) if (*prevBarHeight > 0) { SEGMENT.setPixelColor(*prevBarHeight, SEGCOLOR(2)); } @@ -7295,7 +7293,7 @@ uint16_t mode_single_eqbar(void) { return FRAMETIME; } -static const char _data_FX_MODE_SINGLE_EQBAR[] PROGMEM = "Single EQ Bar@Fade speed,Ripple decay,Frequency bin;!,,Peaks;!;!;1vf;c1=0,c2=8,si=0"; +static const char _data_FX_MODE_SINGLE_EQBAR[] PROGMEM = "Single EQ Bar@Fade speed,Peak decay,Frequency bin;!,,Peaks;!;!;1vf;sx=128,ix=170,c1=128,si=0"; ///////////////////////// // ** 2D Funky plank // From 2137729f8dafd3d09dbc0bb422cd286e1650d230 Mon Sep 17 00:00:00 2001 From: Greg <{ID}+{username}@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:24:28 -0700 Subject: [PATCH 3/6] Fix peak pixel handling when peak decay is set to zero --- wled00/FX.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index cce2c5a190..14f785e792 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7275,9 +7275,11 @@ uint16_t mode_single_eqbar(void) { SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); } - if (peakDecay == 0 && barHeight > 0){ + if (peakDecay == 0){ // No peak pixel if decay is set to zero, just draw the peak pixel of the bar. - SEGMENT.setPixelColor(barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); + if (barHeight > 0) { + SEGMENT.setPixelColor(barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); + } } else { // Decrement prevBarHeight according to peakDecay if (*prevBarHeight > 0 && (SEGENV.call % (peakDecay > 1 ? peakDecay : 1)) == 0) (*prevBarHeight)--; From ca096fccafe81b624f74302ec0da9d5a7d8971b1 Mon Sep 17 00:00:00 2001 From: Greg <{ID}+{username}@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:28:12 -0700 Subject: [PATCH 4/6] Style fix - split conditional into a more standard form. --- wled00/FX.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 14f785e792..ad5f4654e0 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7263,8 +7263,11 @@ uint16_t mode_single_eqbar(void) { // User controls. Speed is referenced directly instead of creating a new varible. uint8_t freqBin = map(SEGMENT.custom1, 0, 255, 0, 15); // 0-15 (or up to available bins) - uint8_t peakDecay = (SEGMENT.intensity == 0) ? 0 : map(255 - SEGMENT.intensity, 1, 255, 1, 32); // Grab the intensity value for peak decay speed. Invert for ease of use. - + uint8_t peakDecay = SEGMENT.intensity; + if (peakDecay > 0){ + // Grab the intensity value for peak decay speed, bound it between 1 and 32, invert for ease of use. + peakDecay = map(255 - SEGMENT.intensity, 1, 255, 1, 32); + } int barHeight = map(fftResult[freqBin], 0, 255, 0, SEGLEN); // Grab new bar height if (barHeight > *prevBarHeight) *prevBarHeight = barHeight; // Update the previous bar height if the new height is greater From 63fd020f1c23b68ce74bfb6ece453cde6b49d20e Mon Sep 17 00:00:00 2001 From: Greg <{ID}+{username}@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:51:23 -0700 Subject: [PATCH 5/6] Add 2d handling to Single EQ Bar effect --- wled00/FX.cpp | 45 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index ad5f4654e0..f0e33afd29 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7268,20 +7268,39 @@ uint16_t mode_single_eqbar(void) { // Grab the intensity value for peak decay speed, bound it between 1 and 32, invert for ease of use. peakDecay = map(255 - SEGMENT.intensity, 1, 255, 1, 32); } - int barHeight = map(fftResult[freqBin], 0, 255, 0, SEGLEN); // Grab new bar height + int barHeight = 0; + if (strip.isMatrix || SEGMENT.is2D()){ + barHeight = map(fftResult[freqBin], 0, 255, 0, SEG_H); // Grab new bar height + } else { + barHeight = map(fftResult[freqBin], 0, 255, 0, SEGLEN); // Grab new bar height + } if (barHeight > *prevBarHeight) *prevBarHeight = barHeight; // Update the previous bar height if the new height is greater SEGMENT.fade_out(SEGMENT.speed); // Always fade out existing bars according to speed slider. // Draw the main bar (but not peak pixel) for (int i = 0; i < barHeight; i++) { - SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + if (strip.isMatrix || SEGMENT.is2D()){ + // If we are in a matrix or 2D segment, draw the bar vertically + for (int j = 0; j < SEG_W; j++) { + SEGMENT.setPixelColorXY(j, i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + } + } else { + // Otherwise draw the bar horizontally + SEGMENT.setPixelColor(i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); + } } if (peakDecay == 0){ // No peak pixel if decay is set to zero, just draw the peak pixel of the bar. if (barHeight > 0) { - SEGMENT.setPixelColor(barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); + if (strip.isMatrix || SEGMENT.is2D()) { + for (int j = 0; j < SEG_W; j++) { + SEGMENT.setPixelColorXY(j, barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); + } + } else { + SEGMENT.setPixelColor(barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); + } } } else { // Decrement prevBarHeight according to peakDecay @@ -7289,16 +7308,30 @@ uint16_t mode_single_eqbar(void) { // Set peak pixel and clear pixels over peak (otherwise they would fadewith value from speed slider) if (*prevBarHeight > 0) { - SEGMENT.setPixelColor(*prevBarHeight, SEGCOLOR(2)); + + if (strip.isMatrix || SEGMENT.is2D()) { + for (int j = 0; j < SEG_W; j++) { + SEGMENT.setPixelColorXY(j, *prevBarHeight, SEGCOLOR(2)); + } + } else { + SEGMENT.setPixelColor(*prevBarHeight, SEGCOLOR(2)); + } } if (*prevBarHeight < SEGLEN) { - SEGMENT.setPixelColor(*prevBarHeight + 1, BLACK); // clear next pixel immediately. + + if (strip.isMatrix || SEGMENT.is2D()) { + for (int j = 0; j < SEG_W; j++) { + SEGMENT.setPixelColorXY(j, *prevBarHeight + 1, BLACK); // clear next pixel immediately. + } + } else { + SEGMENT.setPixelColor(*prevBarHeight + 1, BLACK); // clear next pixel immediately. + } } } return FRAMETIME; } -static const char _data_FX_MODE_SINGLE_EQBAR[] PROGMEM = "Single EQ Bar@Fade speed,Peak decay,Frequency bin;!,,Peaks;!;!;1vf;sx=128,ix=170,c1=128,si=0"; +static const char _data_FX_MODE_SINGLE_EQBAR[] PROGMEM = "Single EQ Bar@Fade speed,Peak decay,Frequency bin;!,,Peaks;!;!;12vf;sx=128,ix=170,c1=128,si=0"; ///////////////////////// // ** 2D Funky plank // From 803cc200c147a2126341ee1b68ae248049638c0c Mon Sep 17 00:00:00 2001 From: Greg <{ID}+{username}@users.noreply.github.com> Date: Wed, 2 Jul 2025 16:53:57 -0700 Subject: [PATCH 6/6] Move 2d check to the top of the function --- wled00/FX.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index f0e33afd29..2de19ad54a 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -7260,6 +7260,7 @@ uint16_t mode_single_eqbar(void) { um_data_t *um_data = getAudioData(); uint8_t *fftResult = (uint8_t*)um_data->u_data[2]; if (!fftResult) return mode_static(); + bool is2d = (strip.isMatrix || SEGMENT.is2D()); // User controls. Speed is referenced directly instead of creating a new varible. uint8_t freqBin = map(SEGMENT.custom1, 0, 255, 0, 15); // 0-15 (or up to available bins) @@ -7280,7 +7281,7 @@ uint16_t mode_single_eqbar(void) { // Draw the main bar (but not peak pixel) for (int i = 0; i < barHeight; i++) { - if (strip.isMatrix || SEGMENT.is2D()){ + if (is2d){ // If we are in a matrix or 2D segment, draw the bar vertically for (int j = 0; j < SEG_W; j++) { SEGMENT.setPixelColorXY(j, i, SEGMENT.color_from_palette(i, true, PALETTE_SOLID_WRAP, 0)); @@ -7294,7 +7295,7 @@ uint16_t mode_single_eqbar(void) { if (peakDecay == 0){ // No peak pixel if decay is set to zero, just draw the peak pixel of the bar. if (barHeight > 0) { - if (strip.isMatrix || SEGMENT.is2D()) { + if (is2d) { for (int j = 0; j < SEG_W; j++) { SEGMENT.setPixelColorXY(j, barHeight, SEGMENT.color_from_palette(barHeight, true, PALETTE_SOLID_WRAP, 0)); } @@ -7309,7 +7310,7 @@ uint16_t mode_single_eqbar(void) { // Set peak pixel and clear pixels over peak (otherwise they would fadewith value from speed slider) if (*prevBarHeight > 0) { - if (strip.isMatrix || SEGMENT.is2D()) { + if (is2d) { for (int j = 0; j < SEG_W; j++) { SEGMENT.setPixelColorXY(j, *prevBarHeight, SEGCOLOR(2)); } @@ -7319,7 +7320,7 @@ uint16_t mode_single_eqbar(void) { } if (*prevBarHeight < SEGLEN) { - if (strip.isMatrix || SEGMENT.is2D()) { + if (is2d) { for (int j = 0; j < SEG_W; j++) { SEGMENT.setPixelColorXY(j, *prevBarHeight + 1, BLACK); // clear next pixel immediately. }