Repository navigation
Added "Liquid" effect #5900
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Added "Liquid" effect #5900
Changes from all commits
d4474ba
f28e4d1
5dfb487
325c77e
d15021f
8f463cf
c183658
a3b111c
d36e996
5c54fb5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11024,6 +11024,126 @@ void mode_slow_transition(void) { | |||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| static const char _data_FX_MODE_SLOW_TRANSITION[] PROGMEM = "Slow Transition@Time (min),,,,,,Sweep;!;!;1;pal=2,sx=0,ix=0"; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| //////////////////////// | ||||||||||||||||||||||||||
| // Liquid // | ||||||||||||||||||||||||||
| //////////////////////// | ||||||||||||||||||||||||||
| /* | ||||||||||||||||||||||||||
| * Liquid: a calm, waving effect for 1-D strips. The field is the amplitude- | ||||||||||||||||||||||||||
| * weighted sum of up to 16 travelling sine waves (of decaying amplitude, rising frequency and alternating direction) | ||||||||||||||||||||||||||
| * rendered into the Primary and Secondary color wells (even / odd-indexed waves). | ||||||||||||||||||||||||||
| * Additionally, a 'shimmer' effect takes place within a configurable band around a configurable wave height, | ||||||||||||||||||||||||||
| * mimicking 'catching the light' of the wave, blending the pixel toward the Tertiary color. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * Sliders (0..255; "Shimmer Width" uses the 0..31 slider on WLED 17): | ||||||||||||||||||||||||||
| * 0 Speed wave motion (0 = frozen in place) | ||||||||||||||||||||||||||
| * 1 Waves number of active waves (byte / 16; 0 = off) | ||||||||||||||||||||||||||
| * 2 Wavelength spatial scale (0 = tiny waves; 255 = enormous but flat waves) | ||||||||||||||||||||||||||
| * 3 Shimmer Height weight height around which shimmer effect occurs, as a fraction (0..1) of field brightness. | ||||||||||||||||||||||||||
| * 4 Shimmer Width band half-width (0 = shimmer off; 31 = 0.2 brightness) around shimmer height | ||||||||||||||||||||||||||
| * Colors: | ||||||||||||||||||||||||||
| * Primary even-indexed waves | ||||||||||||||||||||||||||
| * Secondary odd-indexed waves | ||||||||||||||||||||||||||
| * Tertiary shimmer / "caught light" color | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * Wave table (index k): spatial cycles per strip, relative amplitude, Hz, | ||||||||||||||||||||||||||
| * direction, and a fixed phase offset in radians. | ||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||
| * AI: below section was generated by an AI | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| static const float LIQ_AMPS [16] = { 0.35f, 0.28f, 0.22f, 0.18f, 0.15f, 0.12f, 0.10f, 0.08f, | ||||||||||||||||||||||||||
| 0.07f, 0.06f, 0.05f, 0.05f, 0.04f, 0.04f, 0.03f, 0.03f }; | ||||||||||||||||||||||||||
| static const float LIQ_FREQ [16] = { 0.080f, 0.130f, 0.200f, 0.300f, 0.420f, 0.550f, 0.700f, 0.850f, | ||||||||||||||||||||||||||
| 1.000f, 1.150f, 1.300f, 1.400f, 1.500f, 1.600f, 1.700f, 1.800f }; | ||||||||||||||||||||||||||
| static const float LIQ_PHI [16] = { 0.00f, 1.30f, 2.60f, 3.90f, 5.20f, 6.30f, 7.40f, 8.60f, | ||||||||||||||||||||||||||
| 9.70f, 10.80f, 11.90f, 13.00f, 14.10f, 15.20f, 16.30f, 17.40f }; | ||||||||||||||||||||||||||
| static const float LIQ_DIR [16] = { 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1 }; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| void mode_liquid(void) { | ||||||||||||||||||||||||||
| if (SEGLEN <= 1) FX_FALLBACK_STATIC; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| unsigned len = SEGLEN; | ||||||||||||||||||||||||||
| unsigned waves = SEGMENT.intensity / 16; // "Waves": 0..15 | ||||||||||||||||||||||||||
| if (waves == 0) { // no waves -> off | ||||||||||||||||||||||||||
| SEGMENT.fill(0); | ||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Slider parameters | ||||||||||||||||||||||||||
| float cscale = 5.0f - (float)SEGMENT.custom1 / 51.0f; // "Wavelength" spatial scale | ||||||||||||||||||||||||||
| float center = (float)SEGMENT.custom2 / 255.0f; // "Shimmer Height" | ||||||||||||||||||||||||||
| float hw = 0.30f * (float)SEGMENT.custom3 / 31.0f; // "Shimmer Width" (0 = off) | ||||||||||||||||||||||||||
| float times = (float)SEGMENT.speed * 2.0f / 255.0f; // "Speed" (0 = frozen) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Well colors (RGBW32 -> RGB) | ||||||||||||||||||||||||||
| unsigned pR = (SEGCOLOR(0) >> 16) & 0xFF, pG = (SEGCOLOR(0) >> 8) & 0xFF, pB = SEGCOLOR(0) & 0xFF; | ||||||||||||||||||||||||||
| unsigned sR = (SEGCOLOR(1) >> 16) & 0xFF, sG = (SEGCOLOR(1) >> 8) & 0xFF, sB = SEGCOLOR(1) & 0xFF; | ||||||||||||||||||||||||||
| unsigned tR = (SEGCOLOR(2) >> 16) & 0xFF, tG = (SEGCOLOR(2) >> 8) & 0xFF, tB = SEGCOLOR(2) & 0xFF; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| float now = (float)strip.now; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Field time. Absolute seconds since boot scale by speed: the wave phases | ||||||||||||||||||||||||||
| // are absolute (2*pi*f*t), so the animation origin is fixed and the speed | ||||||||||||||||||||||||||
| // slider only slows or speeds the apparent motion (0 = frozen in place). | ||||||||||||||||||||||||||
| float t = now / 1000.0f * times; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| float twoPi = M_TWOPI; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Calculate color for all pixels | ||||||||||||||||||||||||||
| for (unsigned px = 0; px < len; px++) { | ||||||||||||||||||||||||||
| float primary = 0.0f, secondary = 0.0f, ampSum = 0.0f, briSum = 0.0f; | ||||||||||||||||||||||||||
| for (unsigned k = 0; k < waves; k++) { | ||||||||||||||||||||||||||
| float cycle = k + 1; | ||||||||||||||||||||||||||
| float direction = k % 2 != 0 ? -1 : 1; | ||||||||||||||||||||||||||
| float phase = twoPi * cycle * cscale * (float)px * direction / (float)len | ||||||||||||||||||||||||||
| + twoPi * LIQ_FREQ[k] * t | ||||||||||||||||||||||||||
| + LIQ_PHI[k]; | ||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. optimization: for more speed, try to move parts of this long computation out of the inner loop. For example, these parts of the above expression are not depending on twoPi * cscale * (float)px / (float)len
twoPi * t |
||||||||||||||||||||||||||
| float bri = 0.5f + 0.5f * sin_t(phase); // 0..1 | ||||||||||||||||||||||||||
| float w = LIQ_AMPS[k]; | ||||||||||||||||||||||||||
| if (k & 1) { | ||||||||||||||||||||||||||
| // Add individual wave to secondary color brightness | ||||||||||||||||||||||||||
| secondary += w * bri; | ||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||
| // Add individual wave to primary color brightness | ||||||||||||||||||||||||||
| primary += w * bri; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| ampSum += w; | ||||||||||||||||||||||||||
| briSum += bri; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| if (ampSum <= 0.0f) { | ||||||||||||||||||||||||||
| ampSum = 1.0f; | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Wave color: amplitude-weighted blend of the two colors (0..1) | ||||||||||||||||||||||||||
| float r = ((float)pR * primary + (float)sR * secondary) / ampSum; | ||||||||||||||||||||||||||
| float g = ((float)pG * primary + (float)sG * secondary) / ampSum; | ||||||||||||||||||||||||||
| float b = ((float)pB * primary + (float)sB * secondary) / ampSum; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Shimmer band gate (linear band around `center`, half-width `hw`), on mean brightness | ||||||||||||||||||||||||||
| float br = briSum / (float)waves; // 0..1 | ||||||||||||||||||||||||||
| float gate = 0.0f; | ||||||||||||||||||||||||||
| if (hw > 0.0f) { | ||||||||||||||||||||||||||
| float d = br - center; | ||||||||||||||||||||||||||
| if (d < 0.0f) { | ||||||||||||||||||||||||||
| d = -d; // make absolute | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| if (d < hw) { | ||||||||||||||||||||||||||
| gate = (hw - d) / hw; // 0 at edges, 1 at center | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| // Calculate amount of 'shimmer' to be mixed into the color | ||||||||||||||||||||||||||
| unsigned mix = (unsigned)(gate * 255.0f * 0.3f); // max 30% mix to avoid too much flashing | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Final: wave color blended toward the Tertiary shimmer color | ||||||||||||||||||||||||||
| SEGMENT.setPixelColor((int)px, | ||||||||||||||||||||||||||
| (unsigned)(((r * (float)(255 - mix)) + (float)tR * (float)mix) / 255.0f + 0.5f), | ||||||||||||||||||||||||||
| (unsigned)(((g * (float)(255 - mix)) + (float)tG * (float)mix) / 255.0f + 0.5f), | ||||||||||||||||||||||||||
| (unsigned)(((b * (float)(255 - mix)) + (float)tB * (float)mix) / 255.0f + 0.5f)); | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||
| static const char _data_FX_MODE_LIQUID[] PROGMEM = | ||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @coderabbitai please check if the metadata string is consistent with the effect code.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
rg -n -C3 'extractMode|modeData|effect metadata' wled00 -g '*.{cpp,h,js}' | head -180
fd -i '(^AGENTS\.md$|cpp\.instructions\.md$|copilot-instructions\.md$)'
rg -n -C3 'Liquid@|void mode_liquid' wled00/FX.cppLength of output: 10876 🏁 Script executed: #!/bin/bash
ast-grep outline wled00/util.cpp --match 'extractMode' --view expanded
sed -n '405,515p' wled00/util.cpp
rg -n -C4 "split\\(['\"];" --glob '*.js' .
rg -n -C4 'fxdef|fxdata|fxData|effectData' --glob '*.js' . | head -180Length of output: 12108
The remaining fields also match:
Two code comments do not match the implementation:
Optionally, make the 1-D flag explicit and label the color controls by role: static const char _data_FX_MODE_LIQUID[] PROGMEM =
"Liquid@Speed,Waves,Wavelength,Shimmer Height,Shimmer Width;Primary,Secondary,Shimmer;;1;sx=128,ix=128,c1=128,c2=227,c3=10";This is a clarity improvement, not a required metadata fix. You are interacting with an AI system. |
||||||||||||||||||||||||||
| "Liquid@Speed,Waves,Wavelength,Shimmer Height,Shimmer Width;!,!,!;;;sx=128,ix=128,c1=128,c2=227,c3=10"; | ||||||||||||||||||||||||||
| // AI: end | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| ////////////////////////////////////////////////////////////////////////////////////////// | ||||||||||||||||||||||||||
| // mode data | ||||||||||||||||||||||||||
| static const char _data_RESERVED[] PROGMEM = "RSVD"; | ||||||||||||||||||||||||||
|
|
@@ -11190,6 +11310,7 @@ void WS2812FX::setupEffectData() { | |||||||||||||||||||||||||
| addEffect(FX_MODE_DYNAMIC_SMOOTH, &mode_dynamic_smooth, _data_FX_MODE_DYNAMIC_SMOOTH); | ||||||||||||||||||||||||||
| addEffect(FX_MODE_PACMAN, &mode_pacman, _data_FX_MODE_PACMAN); | ||||||||||||||||||||||||||
| addEffect(FX_MODE_SLOW_TRANSITION, &mode_slow_transition, _data_FX_MODE_SLOW_TRANSITION); | ||||||||||||||||||||||||||
| addEffect(FX_MODE_LIQUID, &mode_liquid, _data_FX_MODE_LIQUID); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // --- 1D audio effects --- | ||||||||||||||||||||||||||
| addEffect(FX_MODE_PIXELS, &mode_pixels, _data_FX_MODE_PIXELS); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is just altering between 1 and -1, right?
could be simplified to something like
index % 2 != 0 ? -1 : 1