IMPORTANT: Before attempting to compile this fork of WLED, make sure you can compile the original WLED - instructions are here. If you are unable to compile WLED, please consider flashing your device with binaries instead.
If you managed to compile original WLED, test your new skills and compile the soundreactive fork of WLED.
Download the CH340 drivers at https://www.wemos.cc/en/latest/ch340_driver.html
The Sound Reactive WLED binaries for ESP32 are located here.
SR WLED releases are also included in this web-based installer: https://wled-install.github.io
Warning: We had to change the partition size on the ESP32 in order to 'fit' all the new features. This means that the 'old way' of upgrading/flashing, no longer work unfortunately. You cannot use ESPHome Flasher, and you cannot use OTA from a build prior to v0.13.0-b5.
Assuming you copied esptool and both binaries to the same directory, you could clear the contents of the ESP32 with:
esptool.exe erase_flash
Then burn the bootloader with:
esptool.exe write_flash 0x0 esp32_bootloader_v4.bin
Once complete, you can now burn the sound reactive binary with:
esptool write_flash 0x10000 soundReactive_WLED_0.13.X-bY_ESP32dev.bin
You can optionally add the port, such as '-p COM6'.
Note: If you Flash via another method, you will definitely need to perform a Factory Reset. Cycling the power is also a requirement if you're doing anything with I2S.
You can find some unofficial SR WLED binaries, including intermediate development builds for ESP32, here:
Please keep in mind that these sites are not maintained by the SR WLED team. You may find old outdated binaries, or binaries that might not work on generic ESP32 hardware. So please compare build number and dates, and read descriptions before installing one of these.
⇛ first read https://kno.wled.ge/advanced/compiling-wled/
→ use source code from https://github.com/atuline/WLED/tree/master
→ start with one of the sound reactive compile environments, like env:soundReactive_esp32dev
→ read wled00/wled.h
, add your own settings to wled00/my_config.h
→ put your own compile environment(s) into platformio_override.ini.
SoundReactive has some additional compile time options - see wled00/audio_reactive.h
and wled00/audio_source.h
.
Note: We have long since stopped compiling WLED with the Arduino IDE.
Some features of "standard WLED" are by default disabled in SR WLED. These extended features have shown negative impacts on performance and stability - we need all available "power" to run sound analysis. For example, they possibly use too much memory (FLASH or RAM), can lead to lags in animations, or may cause slow responses to sound input.
The same is true for many WLED usermods: they might work (like 4LineDisplay), but could have side-effects on our sound reactive features so we disabled them in our "official" firmware builds.
If you're keen to use a disabled WLED feature, in your personal build of SR-WLED:
-D DISABLE_...
flag in your build environment (platformio.ini, or platformio_override.ini), and comment it out or remove it.If a feature has been disabled explicitly in wled.h, then there is usually a good technical reason for that decision. Please don't write bug reports for feature that were disabled explicitly.
If you still want that feature, you can un-disable it like this
Add to your wled00/my_config.h
// re-activate Alexa support. Yes I know this is not supported officially.
// I don't mind if animations will sometimes "stutter" and lag behind the sound.
#ifdef WLED_DISABLE_ALEXA
#undef WLED_DISABLE_ALEXA
#endif
// re-activate MQTT support. Yes I know this is not supported officially.
// I am ready to take good care of my hung, non-responsive device if necessary.
#ifndef WLED_ENABLE_MQTT
#define WLED_ENABLE_MQTT
#ifdef WLED_DISABLE_MQTT
#undef WLED_DISABLE_MQTT
#endif
#endif
// re-activate IR receiver support. Yes I know this is not supported officially.
// I can live with my LEDs flickering sometimes, and effects stuttering randomly.
#ifdef WLED_DISABLE_INFRARED
#undef WLED_DISABLE_INFRARED
#endif
The sound reactive version of WLED provides all of the functionality of WLED with a few caveats:
After uploading WLED to the ESP, use your phone and connect to the WLED-AP using the password 'wled1234'. Click 'Login to network' when the notification about this shows up. You are then transfered to the WLED's start page, and here we should click "WIFI SETTINGS" to connect to the local network. Fill in the settings for your local Wifi network, and then click 'Save & Connect'. The device will reboot and if everything worked it will now be connected to the local network. Finding it's IP-address can be done via the network routers administration page, or via an mobile app like Fing were you can find a new device called "wled-WLED". Open this IP in a webbrowser to access WLED's control page.
Disclaimer: The information below is for the latest release version of SR WLED. _If you use an older release, please divide Gain values by 4._
Here's a starting point table of Squelch and Gain settings for different input types:
Input (I2S digital) | Squelch | Gain | Type | seen in |
---|---|---|---|---|
INMP441 | 6 | 60 | Generic I2S | |
ICS-43434 | 16 | 30 | Generic I2S | |
SPM1423 | tbd | tbd | Generic I2S PDM | M5StickC, M5AtomU |
SPH0654 | tbd | tbd | SPH0654 | |
ES7243 | tbd | tbd | ES7243 | ESP32 Lyra-T Mini |
Input (ADC analog) | Squelch | Gain | Type |
---|---|---|---|
MAX9814 @40dB | 10 | 80 | Generic Analog |
Line-In | 8 | 120 | Generic Analog |
INMP411 | 20 | 80 | Generic Analog |
MAX4466 | 16 | 120 | Generic Analog |
We recommend using an I2S digital microphone, like INMP441, ICS-43434, or PDM microphones.
Analog input (Microphone or Line-in) is also possible, however you might have power fluctuation (3.3V) and noise issues when using these. Analog devices are handled by the "ADC1" unit of your ESP32. Problems can be expected when connecting "analog buttons" (Potentiometer) to the same ADC1 unit.
Finally Analog Microphones often work best when placed close to the sound source, while digital ones like the INMP441 can easily pick up sound from several meters apart. With the analog MAX4466, we found that 30-50cm is an optimal distance.
Automatic gain control (AGC) is not enabled by default in SR WLED, because of so many different input types and ambient noise in different environments. We don't know what your 'quiet' is. In addition, the LED's should NOT be reacting when it IS quiet, so it's up to you to first make those adjustments. In addition, sensitivity can be further adjusted with either the Intensity or Speed slider in many of the animations.
While an improved autonomous gain control (iAGC) feature is available since version 0.13.1, it is still very important that you first find a good Squelch setting for your environment. Afterwards you can enable AGC and let the controller adjust input levels automatically.
While providing a lot of functionality, the ESP8266 and the ESP32 boards (typical ones) we have been using, have experienced a lot of spurious noise on their ADC pins. This has also been discussed at length on various ESP related forums. Methods that may help remediate this include:
Disable the WiFi sleep mode.
Use shielded wiring for your analog sampling pin.
In order to accommodate 2D effects we have modified how Segment settings are used and added 2D Matrix and panel variables on the Led Preferences settings. Note: Currently only working in dev. You are invited to test this and give feedback on Beta testing discord channel
WLED SR distinguishes between the following levels
An effect is plotted on a segment. A segment is a rectangle on a matrix (logical level). A matrix is implemented by one or more identical led panels, with a specific layout (e.g. first led bottom left, serpentine, physical level).
Note: 2D effects can also be projected on a 1D LED Strip instead of a 2D Panel. e.g. for a led strip of 144 leds you can define width=height=12 and each zone of 12 leds is a row of a matrix. Rows are then side by side instead of above each other. Some 2D effects, e.g. graphic equalizer look still pretty cool on strips (as is the other way around with 1D effects on a 2D matrix like NoiseMove or Sparkle).
As WLED supports multiple segments, all effects and therefore also 2D effects are first projected on a segment. In 1D, a segment is a zone on a LED strip and is specified by Start Led and a Stop Led (note that Stop Led is one led after the last led in the segment).
In 2D, a segment is a rectangle on a 2D matrix and 2D effects plot on this rectangle using x,y coordinates of the SEGMENT. A rectangle can be defined in the Segment UI where the start led specifies the top-left and the stop led specifies the bottom-right of the rectangle. Multiple segments can be specified this way. Segments can overlap. In fact overlapping creates very nice effects.
See Segment start stop charts to easy find matrix start and stop values
A segment can be rotated 90ΒΊ degrees and reversed on the X or Y-axis and can be specified in the Segment-UI. The SegmentRotation branch of dev supports this and is currently in beta-test. This will move to dev and release over time.
The following table shows the effect setting these values:
Value | Rotation | Reverse X | Reverse Y| Effect |---|---|---|---|---| 0|-|-|-|0ΒΊ rotation and no reverse 1|-|-|+|Reverse horizontal 2|-|+|-|Reverse vertical 3|-|+|+|180ΒΊ rotation 4|+|-|-|90ΒΊ rotation 5|+|-|+|90ΒΊ and reverse horizontal 6|+|+|-|90ΒΊ and vertical 7|+|+|+|270ΒΊ rotation
See Led Preferences
(Created by Harry Baas)
To get the (x,y) coordinates from the start and stop led:
Example of 1 segment (default) covering a whole 16x16 matrix:
Example of a segment covering a middle part rectangle of the 16x16 matrix:
Example of a segment covering the left part of the 16x16 matrix:
matrixWidth = 16, matrixHeight = 12.
Total led count 192 leds
left and right binmap effect. In the middle noisemove.
Add the following Api command into a preset. This will show the Saw effect rotated and reversed in 16 8*8 segments.
After that you, if you select all 16 segments and select another effect, this effect will also be populated to all 16 segments, resulting in surprising new effects
{"on":true,"bri":89,"transition":7,"mainseg":0,"seg":[{"id":0,"start":0,"stop":232,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":false,"mi":false,"rot2D":false},{"id":1,"start":8,"stop":240,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":false,"mi":false,"rot2D":false},{"id":2,"start":16,"stop":248,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":false,"mi":false,"rot2D":false},{"id":3,"start":24,"stop":256,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":false,"mi":false,"rot2D":false},{"id":4,"start":256,"stop":488,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":true,"mi":false,"rot2D":false},{"id":5,"start":264,"stop":496,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":true,"mi":false,"rot2D":false},{"id":6,"start":272,"stop":504,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":true,"mi":false,"rot2D":false},{"id":7,"start":280,"stop":512,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":true,"mi":false,"rot2D":false},{"id":8,"start":512,"stop":744,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":false,"mi":false,"rot2D":false},{"id":9,"start":520,"stop":752,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":false,"mi":false,"rot2D":false},{"id":10,"start":528,"stop":760,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":false,"mi":false,"rot2D":false},{"id":11,"start":536,"stop":768,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":false,"mi":false,"rot2D":false},{"id":12,"start":768,"stop":1000,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":true,"mi":false,"rot2D":false},{"id":13,"start":776,"stop":1008,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":true,"mi":false,"rot2D":false},{"id":14,"start":784,"stop":1016,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":false,"rev2D":true,"mi":false,"rot2D":false},{"id":15,"start":792,"stop":1024,"grp":1,"spc":0,"on":true,"bri":255,"col":[[255,0,0],[59,42,27],[0,0,255]],"fx":16,"sx":47,"ix":142,"f1x":89,"f2x":74,"f3x":111,"pal":12,"sel":true,"rev":true,"rev2D":true,"mi":false,"rot2D":false},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0}]}
The sound reactive fork of WLED supports multiple layouts of a 2D matrix led panel as well as multiple identical 2D matrix led panels. Many effects were written with a 16x16 panel in mind, so some 2D effects may not display properly on a panel/matrix of a different size.
2D effects are projected on a 2 dimensional matrix.
A specific led is identified by led[x,y] where led[0,0] is in the top left corner (logical layer)
Setting name | Value Range | Description | Master/Dev |---|---|---|---| Width| 1..x | Width of the matrix | Master Height| 1..y | Height of the matrix | Master
Note: width x height should match LED count!
A matrix is made of 1 or more identical physical led panels (physical layer) Setting name | Value Range | Description | Master/Dev |---|---|---|---| Multiple panels| Y/N | No if only one panel, yes if more than one | Dev Horizontal panels| 1..x | Number of panels side by side | Dev Vertical panels| 1..y | Number of panels above each other | Dev
Note: Panel width = matrix width / horizontal panels and panel height = matrix height / vertical panels
Note: Total panels = horizontal * vertical
Specify how a led panel is wired.
This is in most cases different from the logical layer (first led top left). Parameters here translate the logical layer (led[x,y]) to the physical layer (led[0] .. led[n]).
Setting name | Value Range | Description | Master/Dev |---|---|---|---| First led position| Top/Bottom & Left/Right | Where is the first led positioned | Dev (replacing flipmajor/minor) Orientation| Horizontal / Vertical | Are rows of leds wired horizontal or vertical | Dev (replacing rowMajor) Serpentine| Y/N | Are rows of leds wired zig-zag or not | Master Transpose| Y/N | Swap the axes (otherwise no swap). Don't use on non-square panels | Dev
Note: If multiple panels are used, they must be identical.
I have a 2D matrix of 6 - 8x8 panels. They are connected sequentially with a total of 24 led's wide and 16 led's high.
The first led of each panel starts in the top left corner, the subsequent led is to the right of it (horizontally), and the panel is in a serpentine layout. These should be the settings for that layout:
Disclaimer: The information below is for the latest release version of SR WLED. If you use an older release, you will not have all options.
In order to accommodate a wide range of audio inputs, ambient environments and string lengths, we have added user configurable squelch (noise reduction/suppression) and gain controls on the sound settings page that apply to all sound reactive animations.
After changing the sound source (either GPIO pins or Microphone type), it is important to press the "reset" button on your ESP32 - don't forget to "save" first. WLED cannot change the sound input configuration "on the fly", due to a known hardware problem of ESP32. See https://github.com/espressif/esp-idf/issues/7442 "only a hard CPU reset can disconnect the I2S signal from built-in ADC".
We typically recommend using GPIO 36, aka VP or ADC1_CH0 for analog input, however the following pins should also work:
GPIO 32 => ADC1_CH4
GPIO 33 => ADC1_CH5
GPIO 34 => ADC1_CH6
GPIO 35 => ADC1_CH7
GPIO 36 => ADC1_CH0
GPIO 37 => ADC1_CH1
GPIO 38 => ADC1_CH2
GPIO 39 => ADC1_CH3
Do NOT use any of the pins from ADC2, as they will conflict with the WiFi and with I2S sampling.
Remember to press Reset after saving your new analog input configuration.
We have observed problems when using "analog buttons" (potentiometer) together with ADC analog sound input. It seems that different drivers (I2S-ADC for sound, analogRead() for potentiometer) are getting into conflict. If you plan to attach a potentiometer to your WLED device, we recommend to use an I2S digital microphone to avoid these problems.
More information about analog inputs on our analog microphones page.
Adjust this value on the Sound Settings page so that the leds are only activated above a certain 'background noise' level.
Line-in signals are typically much lower than that of some of the microphones. Rather than use an auto gain function, you can manually adjust the gain from 1 to 255, which translates to 0.1 up to almost 6.5 gain. That's equivalent to a range of -20dB up to +16dB.
In addition, the 'Intensity' and "input level" sliders can sometimes adjust an animation to simulate increased gain.
Here's a method to setup squelch and gain for your SR WLED Device.
From faulty microphones to flaky wiring, to WiFi related issues, particularly in AP mode, getting reliable and spike free sound sampling with WLED and in particular analog sampling has been a challenge. Digital microphones such as the INMP441, the ICS-43434 provide the best results.
Currently the following I2S options are available:
Some more information can be found on our I2S digital microphones page.
to be extended soon
There are solutions available for line-in via I2S. For example, boards/shields with "es7243" chip should work already (we have a special driver for these), and we're investigating "es8388". Please check our I2S digital microphone hookup - I2S audio boards/modules page for more information.
We have recently improved the AGC (automatic gain control) algorithm in WLED-SR. It's not enabled by default, however we encourage you to give it a try - all sound reactive effects now support AGC, including 2D and frequency-reactive effects. The only prerequisite for using AGC is that you first adjust "Squelch" to define 'silence' (ambient noise level) in your environment - see previous section.
AGC will automatically perform sound input amplification, based on current sound loudness. For example, if you play music and then increase the speaker volume, WLED-SR will adjust internal gain factors to follow your music. Forget about manually changing "gain" settings. Just relax and let WLED-SR do it autonomously.
Currently WLED-SR offers four different AGC presets that can be selected in sound settings:
to be extended soon
When you first connect to a WLED device in AP mode, there is some really annoying behavior on the captive portal implementation in Android. The captive portal is the limited browser you are forwarded to in order to login to a web site. What happens is that if you go into 'Effects', you can't scroll up. In order to get around that, click the three dots at the top right of the page, select 'Use Network as is', then open up Chrome and navigate to the site at 4.3.2.1.
On the "Sound Settings" page, configure the Squelch for a value (default is 10) to reduce your background noise for volume reactive effects. Volume reactive effects start with a single '*'. Typically, values between 10 and 20 should suffice. The higher the number, the greater the background noise is suppressed.
Configure the Gain setting (default is 60) to change the "perceived volume" of the input signal. More info on Squelch and Gain here.
When changing any values in the LED settings page, you'll need to update the 2D settings. If not using a 2D matrix, you can set them to 1 x <number of LED's> or vice versa. If using a 2D matrix, configure these values for width x height. A value of less than 4 in either dimension will not work with some of the 2D animations.
The serpentine parameter configures whether the LED's are wired up in a continuous/serpentine layout or top to bottom and repeat.
Devices can be configured as 'disabled', 'transmit' or 'receive' UDP sound. This is completely independent of the 'Sync' button, which synchronizes effects.
As a result, you can run multiple types of sound reactive animations when UDP Sound Sync is enabled. This feature provides a subset of the sound and FFT data to several 'slave' devices. As a result, some FFT enabled routines will not function in this mode. You must RESET the ESP32 after you enable/disable this on the Sync settings page.
Note 1: Effects beginning with '*' are volume only and run on both ESP32 and ESP8266 (unless they are 2D).
Note 2: Effects beginning with '' use FFT (Fast Fourier Transforms) for frequency detection and only run on the ESP32.
Note 3: We have also not added 2D animations to the ESP8266 platform.
Note 4: The 2D routines require a minimum of 4 pixels in both directions. If you see blinking red, your 2D settings don't match the requirements. (not required in latest dev)
Note 5: As we continue to develop SR WLED, some animations may appear or disappear. It's still a work very much in progress. Some may only appear in the dev branch for now.
Note 6:** In dev branch, sliders have been renamed from FFT Low to Custom 1, FFT High to Custom 2 and FFT Custom to Custom 3.
See also Non reactive animations
See List of effects and palettes for AC Animations.
See ScottrBaileys GIF visualizer for animations of the effects
Effect | Description | Sliders |
---|---|---|
* 2D Swirl | Several blurred circles. Looks good with pink plasma palette. Supports AGC. | Speed: Speed Intensity: Sensitivity FFT Low: Blur |
* 2D Waverly | Noise waves with some sound | Speed: Amplification Intensity: Sensitivity |
* Gravcenter | Volume reactive vu-meter from center with gravity and perlin noise. | Speed: Rate of fall Intensity: Sensitivity |
* Gravcentric | Volume reactive vu-meter from center with gravity. Volume provides index to (time rotating) palette colour. | Speed: Rate of fall Intensity: Sensitivity |
* Gravimeter | Volume reactive vu-meter with gravity and perlin noise. | Speed: Rate of fall Intensity: Sensitivity |
* Juggles | Juggling balls. | Speed: Yes Intensity: # of balls |
* Matripix | Similar to Matrix. | Speed: yes Intensity: Brightness |
* Midnoise | Perlin noise emanating from center. | Speed: Fade rate Intensity: Maximum length |
* Noisefire | A perlin noise based volume reactive fire routine. | n/a |
* Noisemeter | Volume reactive vu-meter. | Speed: Fade rate Intensity: Width |
* Pixels | Random pixels. | Speed: Fade rate Intensity: # of pixels |
* Pixelwave | Pixels emanating from center. | Speed: yes Intensity: Sensitivity |
* Plasmoid | Sine wave based plasma. | Intensity: # of pixels |
* Puddlepeak | Blast coloured puddles randomly up and down the strand with the 'beat'. | Speed: Adjust fade rate. Intensity: Size of puddles FFT High: 256 freq bin select on ESP32. FFT Custom: Volume comparator on ESP32 |
* Puddles | Blast coloured puddles based on volume. | Speed: Fade rate Intensity: Size of puddle |
* Ripple Peak | Peak detection triggers ripples. | Intensity: Max number of ripples. FFT High: 256 freq bin select on ESP32 FFT Custom: Volume comparator on ESP32 |
* Waterfall | A volume AND FFT version of a Waterfall that has 'beat' support. | Speed: Speed Intensity: Adjust colour |
** 2D CenterBars | A 16x16 spectral analysis routine emanating from the center | Speed: Bar Speed Intensity: Ripple time FFT Custom1: Center horizontally FFT Custom2: Center vertically FFT Custom3: Color vertically |
** 2D Funky Plank | A 2D wall of reactivity running from bottom to top | Speed: Scroll Speed FFT Custom1: Number of bands |
** 2D GEQ | A 16x16 graphic equalizer. | Speed: Bar Speed Intensity: Ripple time FFT Custom1: Number of bands |
** Binmap | Map bins 3-255 throughout the length of the LEDs. This does not work with UDP sync. Values are not normalized. |
Intensity: Max volume |
** Blurz | Flash an fftResult bin per frame and then blur/fade. | Speed: Fade Rate Intensity: Blurring |
** DJLight | An effect emanating from the center to the edges. | Speed: Speed |
** Freqmap | Map the loudest frequency throughout the length of the LED's. | Speed: Fade rate Intensity: Starting colour |
** Freqmatrix | See below | See below |
** Freqpixels | Random pixels coloured by frequency. | Speed: Fade rate Intensity: Starting colour and number of pixels |
** Freqwave | See below | See below |
** Gravfreq | VU Meter from center. Log of frequency is index to center colour. | Speed: Rate of fall Intensity: Sensitivity |
** Noisemove | Using perlin noise as movement for different frequency bins. | Speed: Speed of perlin movement Intensity: Fade rate |
** Rocktaves | Colours the same for each note between octaves, with sine wave going back and forth. | Speed: n/a Intensity: n/a |
** Waterfall | FFT version of a Waterfall. | Speed: Speed Intensity: Adjust colour FFT High: 256 freq bin select on ESP32 FFT Custom: Volume comparator on ESP32 |
** DJ Light | tbd | |
** 2D Akemi | tbd |
Please see the brief slider descripion for each effect in the rightmost column above.
These typically reflect the value of their namesake. Intensity would typically be number of LED's lit, or brightness of the LED's
These may get renamed in the future and could be used for FFT routines OR for additional effect adjustments.
This is NOT beat detection, but rather samples that are louder than a the current average plus a slider adjustable value.
We are just beginning to add Automatic Gain Control to the routines, starting with 2D Swirl. This setting is only available on the LED Preferences page on the ESP32.
The temporal tail for this animation starts at the beginning of the Segment rather than in the center of the segment.
Sliders used:
Slider usage is described in the rightmost column for each effect. In general, the sliders are configured for:
This effect maps the major frequencies from the incoming signal to colors in the HSV color space. From the low notes being mapped to red (0) to the high notes being mapped to blue (255) and everything in between. The band you are looking at can be restricted by the FFT Low and FFT High sliders. We are digitizing at 10240Hz, meaning the highest frequency bin that you can find is 5120Hz, which for most music is just fine.
Sliders used:
Note 1: Due to its limited capability, we have disabled 2D animations on the ESP8266 platform.
Note 2: The 2D routines require a minimum of 4 pixels in both directions. If you see blinking red, your 2D settings don't match the requirements. (not required in latest dev)
Note 3: As we continue to develop SR WLED, some animations may appear or disappear. It's still a work very much in progress. Some may only appear in the dev branch for now.
Note 6: In dev branch, sliders have been renamed from FFT Low to Custom 1, FFT High to Custom 2 and FFT Custom to Custom 3.
See also Reactive animations
See List of effects and palettes for AC Animations.
See ScottrBaileys GIF visualizer for animations of the effects
Effect | Description | Sliders | |||
---|---|---|---|---|---|
βοΈ Custom effect (New) | Define your own effects, see here | No controls (yet) | |||
Flow Stripe | Strip with rotating colours. | Speed: Controls a speed timer Intensity: Controls another timer |
|||
Perlin Move | Using Perlin Noise for movement. | Speed: Speed of elements Intensity: # of pixels FFT Low: Fade rate |
|||
Wavesins | Beat waves and phase shifting. Looks OK in 2D'ish as well. | Speed: Speed Intensity: Varying brightness FFT Low: Starting colour FFT High: Range of colours FFT Custom: More fun to adjust |
|||
2D Black Hole | Stars moving around black hole. | FFT Low: one beat FFT High: Another beat FFT Custom: last beat |
|||
2D Colored Bursts | Multiple lines. | Speed: Speed of lines Intensity: Number of lines |
|||
2D DNA | A very cool DNA like pattern. Select a palette. | Speed: Scroll speed Intensity: Blur |
|||
2D DNA Spiral | Spiraling DNA pattern. | Speed: Speed. Intensity: Frequency |
|||
2D Drift | A rotating caleidoscope. | Speed: Speed of rotation. Intensity: Blur |
|||
2D Fire2012 | Mark Kriegsman's fire routine. | n/a | |||
2D Firenoise | Using Perlin Noise for fire. | Speed: Yscale. Intensity: Scale |
|||
2D Frizzles | Moving patterns. | Speed: One thing Intensity: Another thing |
|||
2D Gameoflife | Scrolling game of life. | Speed: Speed Intensity: Starting grid |
|||
2D Hiphotic | A moving plasma. | Speed: One direction Intensity: Other direction |
|||
2D Lissajous | A frequency based Lissajous pattern. | Speed: Frequency of cos Intensity: Frequency of sin |
|||
2D Matrix | The Matrix in 2D. | Speed: Affects the speed of the movement Intensity: Number of lines |
|||
2D Metaballs | A cool plasma type effect. | n/a | |||
2D Plasma | A plasma effect. | Speed: Affects the speed of the movement FFT Low: Shifts the colours FFT High: Distance from the plasma |
|||
2D Plasma Ball | A ball of plasma. | Speed: Speed. Intensity: |
|||
2D Polar Lights | The northern lights. | Speed: Speed. Intensity: Frequency. FFT Low: Palette rotation |
|||
2D Pool Noise | Looking at a pool. | n/a | |||
2D Pulser | Travelling waves. | Speed: Speed. Intensity: Blur |
|||
2D Sindots | Moving/rotating pattern. | Speed: Speed. Intensity: Length/size |
|||
2D Squared Swirl | Boxes moving around. | fft3: Blur amount | |||
2D Sun radiation | The sun! Doesn't support segments. | Speed: Variance Intensity: Brightness |
|||
2D Twister | A large twister. | Speed: Speed Intensity: Phases |
|||
2D Tartan | tbd | ||||
2D Julia | tbd | ||||
2D Game of life | tbd | ||||
2D Black hole | tbd | ||||
2D Noise | tbd |
To configure, go to Time & Macros setting
Time setup: fill in required parameters
Clock: Clock overlay; Analog Clock, check Show 5min marks, uncheck the rest
Oh, and special thanks are in order for urish for creating wokwi, Elliot and his team for soulmatelights and Stepko and ldirko for some awesome 2D animations. With their approval, we were able to convert and publish several of their animations to use with WLED.
Table of contents generated with markdown-toc
Custom effects are effects which are not compiled in the WLED repository but specified by a file (program file) which is interpreted in real time.
The big advantage of this is that effects are not limited by what is made by WLED programmers but anybody can create effects without releasing a new version of WLED. Furthermore any change in the effect code is instantly shown on leds allowing fast developing of effects.
A disadvantage is that the file needs to be loaded, examined and then run in real-time which is 'per definition' slower then pre-compiled code, although performance is promising already and will get better over time.
To get your first Custom Effect running, perform the following steps
Custom Effects examples are stored in Github repository
If you develop effects which you want to share, ask for access on Github.
These effects can be loaded easily within WLED: Give a Custom Effects segment name the same name as an effect in this repository (case sensitive, without .wled), click on Custom Effect Editor and click Download 'effect'.wled and press Save.
Alternatively, if you want all the effects in this folder at once, go to the Custom Effect Editor and click Download presets.json (Segment stop is set to 50! This will overwrite any existing presets you have). Refresh the WLED page or reboot to see the new presets.
A Custom Effects program typically looks like this:
A program contains structures like if statements, for loops, assignments, calls (e.g. renderFrame) etc., commands like setPixelcolor and variables like ledCount.
program: Once every effect. Can contain global variables and internal functions. There are 2 special internal functions: renderFrame and renderLed
Global variables: Once every effect, reused between functions. Variables (global and local) are defined by using an assignment e.g. t=0
renderFrame: Once every frame
renderLed: Once every led within a frame
Functions and variables give access to the WLED functionality. The list of functions and variables will grow as we go. A function has parameters (even empty parameters) e.g. setPixelColor(x,y), variables haven't e.g. ledCount.
"ledCount": {},
"setPixelColor": {"pixelNr":"int", "color":"int"},
"leds": {},
"setPixels": {"leds": "array"},
"hsv": {"h":"uint8", "s":"uint8", "v":"uint8"},
"setRange": {"from":"uint16", "to":"uint16", "color":"uint32"},
"fill": {"color":"uint32"},
"colorBlend": {"color1":"uint32", "color2":"uint32", "blend":"uint16"},
"colorWheel": {"pos":"uint8"},
"colorFromPalette": {"index":"uint8", "brightness":"uint8"},
"segcolor": {"index":"uint8"},
"speedSlider": {"return":"uint8"},
"intensitySlider": {"return":"uint8"},
"beatSin": { "bpm":"uint16", "lowest":"uint8", "highest":"uint8", "timebase":"uint32", "phase_offset":"uint8"},
"fadeToBlackBy": {"fadeBy":"uint8"},
"iNoise": {"x":"uint32", "y":"uint32"},
"fadeOut": {"rate":"uint8"},
"custom1Slider": {"return":"uint8"},
"custom2Slider": {"return":"uint8"},
"custom3Slider": {"return":"uint8"},
"sampleAvg": {"return": "double"},
"counter": {"return": "uint32"},
"shift": {"delta": "int"},
"circle2D": {"degrees": "int"},
"constrain": {"amt":"any", "low":"any", "high":"any"},
"map": {"x":"int", "in_min":"int", "in_max":"int", "out_min":"int", "out_max":"int"},
"seed": {"seed": "uint16"},
"random": {"return": "uint16"},
"sin": {"degrees": "double", "return": "double"},
"cos": {"degrees": "double", "return": "double"},
"abs": {"value": "double", "return": "double"},
"min": {"value1": "double", "value2": "double", "return": "double"},
"max": {"value1": "double", "value2": "double", "return": "double"},
"hour": {"return":"uint8"},
"minute": {"return":"uint8"},
"second": {"return":"uint8"},
"millis": {"return": "uint32"},
"time": {"inVal":"double", "return": "double"},
"triangle": {"t":"double", "return": "double"},
"wave": {"v":"double", "return": "double"},
"square": {"v":"double", "t":"double", "return": "double"},
"printf": {"args": "__VA_ARGS__"}
All variables and values are internally stored as doubles and where needed converted to (unsigned) integers, e.g. to WLED functions or operators like %.
Technical details about external variables and functions can be found in arti_wled.h. Look for arti_external_function, arti_set_external_variable and arti_get_external_variable. Some examples:
UDP Sound Sync is a feature to synchronize (share) the sound input of a 'master' device with one or more 'slave' devices. All devices must be running the same release of SR WLED, and they must be in the same local network. Sound Sync is not availeable in "upstream" WLED by Aircookie. Sound Sync is also different from direct LEDs control using protocols like E1.31, DMX, DDP or AdaLight.
UDP Sound Sync does not sync the actual animations, but rather transmits summary audio sampling information to several devices that still run their own animations locally. In a nutshell, it means that several devices can share a single microphone.
Before configuring UDP Sound Sync, make sure you have gone into the WiFi Preferences and clicked on 'Disable WiFi sleep' at the bottom of the page. It has caused us innumerable problems in the past.
In order to configure UDP sound sync, the βmasterβ needs to be an ESP32 along with an audio input.
You would then to go the βSync Interfacesβ page and configure the 'Audio Sync' at the bottom of the page. Transmit
for the ESP32 and Receive
for devices without an audio input (either ESP32's or ESP8266's). Make sure the UDP port is the same on all devices.
This does not sync the actual animations, but rather just the transmission of summary audio sampling information (as best we can).
In order to change the UDP Sync Mode (Disabled/Transmit/Receive), you need to power-cycle the ESP32/ESP8266.
When an ESP32 is configured for audio transmission, it will connect to a UDP Multicast address, and begin sending a single UDP Multicast packet containing the data used to generate sound-reactive animations out to any other devices that are configured to receive on the same network. The following information is transmitted:
char header[6] = UDP_SYNC_HEADER;
uint8_t myVals[32]; // 32 Bytes
int sampleAgc; // 04 Bytes
int sample; // 04 Bytes
float sampleAvg; // 04 Bytes
bool samplePeak; // 01 Bytes
uint8_t fftResult[16]; // 16 Bytes
double FFT_Magnitude; // 08 Bytes
double FFT_MajorPeak; // 08 Bytes
UDP_SYNC_HEADER is a versioning number that's defined in audio_reactive.h
When an ESP32 or ESP8266 is configured to receive audio data from another device, the receiver will disable any onboard microphone sampling and FFT processing, in favor of audio data received from the network. Any time a UDP Multicast packet is received from a transmitter, it will be treated as a discrete microphone sample and stored in memory the same way it would be if it were a local microphone.
An ESP8266 will not be able to use any FFT data transmitted from an ESP32, as a result of the differences in hardware and software.
The default UDP Multicast IP is 239.0.0.1, and the default port is 11988.
UDP multicast is generally not very reliable with typical "consumer grade hardware". Some users found that creating a "port forwarding rule" on their local Wifi router helps. For example, you could create a "dynamic port forwarding rule" for UDP port 11988.
UDP Sound sync brought to you by @spedione on Discord.
Reference: https://github.com/Aircoookie/WLED/wiki/UDP-Realtime-Control
Generally we recommend using I2S digital sound input - like INMP441, SPH0645, ICS-43434, or PDM I2S microphones. Additionally there are solutions for line-in via I2S. For example, boards/shields with "es7243" chip should work already (we have a special driver for these), and we're investigating "es8388".
Below are a number of popular Arduino compatible analog microphones that have been tested.
Model | Compatibility | Notes |
---|---|---|
INMP401 | Good | Some Chinese ones are not reliable. |
MAX4466 | Fair | Is very sensitive to 3.3V noise and voltage dropout due to Wifi activity. Avoid powering your LED stripe from ESP32, as the stripe causes a lot of noise on the 3.3V/5V power lines. |
MAX9812 | Good | Only 20dB gain, but worked OK. |
MAX9814 | Good | Best to set the gain to 40dB. |
If you are using the MAX9814, you need to connect gain to vdd to set the gain to 40dB as the default 60db has far too much background noise.
Important: there are some inexpensive sound sensors you can buy from Aliexpress or elsewhere (such as LM393, KY-038 or KY-037). Typically these have an on/off output only (detecting "sound" or "silence"), sometimes there is an additional "analog data out" with very low quality. They may or may not work adequately. For more information on our microphone test results, see our Arduino Compatible Microphones document.
If the LED's are active when the ambient volume is low while running volume only effects beginning with a single '*', you can increase the background noise filtering (or squelch) by navigating to the 'Config | Sound Settings' and increase the Squelch value. You can also make it more sensitive by lowering that Squelch value. In addition, there is a gain setting, which is required especially for the much lower signal level provided by the line-in configuration. Gain, Squelch and AGC are affecting all soundreactive, volumereactive and frequency (FFT) reactive effects.
Note 1: Do NOT connect input devices to 5V (or Vin). The power should be connected to the 3.3V pin.
Note 2: A piezo vibration sensor (from aliexpress) was successfully hooked up and tested.
Note 3: On the ESP32, the default ADC pin is GPI36 (also known as VP), while the ESP8266 uses A0. On ESP32, any GPIO related to ADC1 can be used - see next note.
Note 4: If your ESP32 doesn't have pin 36, any of the other ADC1 (and not ADC2) pins should work.
Note 5: On the ESP32, the ADC and I2S pins are defined in audio_reactive.h. You can also select them in the sound settings UI.
Microphone Wiring Example (MAX9814) | Line In Wiring Example |
---|---|
![]() |
![]() |
Some folks have mentioned that they don't need this line-in circuit, which is fine. Here's an explanation of that circuit.
The 680 ohm resistors provide termination so that you don't get reflection on the incoming signals. The 100nf capacitors remove any DC offset from the incoming signal. Remember that the ESP goes from 0V to 3.3V. Beyond that lay dragons. Finally, the 1M resistors provide DC centering of the incoming (now) AC only signal halfway between 0 and 3.3V.
Note 1: If you are just using a single L or R channel for the line-in, disconnect the capacitor for the other channel, or the resultant sample will be significantly reduced in amplitude.
Note 2: Providing a 'T' connector so that you can hear the music as it goes into the circuit is highly recommended. In the author's case, there was considerable static when the ESP32 was powered by the computer's USB port, but was fine when the ESP32 was powered by a USB powerbank.
The following diagram shows one way of connecting a 3.5mm jack and an analog microphone to the ESP8266/32 while being able to change your desired input with a simple SPDT switch.
The left and right channels of the TRS Jack are connected together to sample both channels simultaneously as one channel.
Connect the output of the capacitor to the ADC pin for your board.
On the ESP32, the ADC pin used is pin 36 (also known as VP), while the ESP8266 uses A0. Power is connected to the 3.3V pin. These pins are defined in wled00/audio_reactive.h.
The volume and frequency reactive routines (starting with a single or double *), support a squelch or background noise suppression. This can be configured on the Sound Settings page.
Line-in signals are typically much lower than that of some of the microphones. Rather than use an auto gain function, you can manually adjust the gain from 1 to 255, which translate to a gain factor from 0.1 up to 6.5 gain. That's equivalent to a range of -20dB up to +16dB.
We've often seen spikes when using an analog microphone in conjunction with WLED. There's an article that should shed light on the issue at ESP32 microcontroller generates noise on microphone.
The INMP441 is a high-performance, low power, digital output, omni-directional MEMS microphone and consists of a MEMS sensor, signal conditioning, an analog-to-digital converter, anti-aliasing filters, power management, and an industry-standard 24-bit IΒ²S interface. The IΒ²S interface allows the INMP441 to connect directly to an ESP32 (but NOT an ESP8266). The recently tested ICS-43434 (thanks to Serg74) also works well, and just requires a slightly higher squelch setting (~10).
from INMP441, ICS-43434 | from PDM | from SPH0645, Other | to ESP32 GPIO | |
---|---|---|---|---|
L/R | SEL | SEL | Gnd | ground => left channel |
SD | DATA | DOUT | 32 | serial data |
WS | CLK | LRCK | 15 | left right clock |
SCK | - | BCLK | 14 | serial clock |
VDD | 3V3 | VDD | 3.3V | power don't use 5V! |
GND | GND | GND | Gnd | ground, 0V |
Important: please make sure that your I2S device provides sound input on the LEFT audio channel! For the INMP441 this is achieved by wiring the 'L/R' connection to GND (ground). Only exception is the "ES7243" driver, which is always using the RIGHT audio channel.
Since 0.12.0, you can change I2S GPIO pins in the Sound Settings interface; on ESP32 any available GPIO can be used for IΒ²S. The 'SD' signal could also be mapped to an input-only (GPI) pin (*), if you are low on GPIO pins. You'll need to reboot when done with pin assignment - don't forget to "save". To reboot, please press 'reset' on your ESP32. Unfortunately a restart by software ("soft reboot") is not always sufficient to activate new driver settings.
Important: (*) Due to a problem that was fixed very recently, its not possible to use input-only GPI pins in older releases of SR WLED. There will be no warning if you try to do so. This problem is solved in the latest release version of SR WLED.
In older releases, you need to change pins used by defining I2S_WS
, I2S_SD
, and I2S_SCK
in your PlatformIO config, or by editing the values in audio_reactive.h.
In addition to I2S microphones, there are solutions available for line-in via I2S. We already have driver support for Boards/Shields with "es7243" chip, and we're investigating "es8388".
Other I2S ADC (analog-to-digital-converter) devices and microphones that have a standard I2S interface may already work with WLED-SR, by using one of the I2S "Generic" drivers (Generic I2S
, Generic I2S PDM
, or Generic I2S with Mclk
). It is important however that sound input comes on the LEFT audio channel. Please keep in mind that this is a spare-time open source project - we do our best to make generic drivers but we cannot test with all available devices.
We do not have these digital microphones running on an ESP8266.
Having problems getting the INMP441 running with WLED? Here's a test sketch (which you can compile with the Arduino IDE): https://pastebin.com/Ua7s7LYF . If you are still having a problem with that sketch, change the line with ONLY_LEFT to ONLY_RIGHT. If that works, you'll need to go into audio_source.h and change that line.
Initial I2S support by @spedione
This is the IMNP441; you can find it in many shops including Amazon and Aliexpress. It works very well with SR WLED.
Here's the first board I've seen with the ICS-43434 at: https://www.tindie.com/products/serg74/digital-i2s-microphone-ics-43434-add-on/
Looking to add line-in with I2S support? You might want to try I2S ADC boards that use one of these chips:
Many I2S ADC boards expect a MCLK (master clock aka system clock) signal. For these boards, use our Generic I2S with MCLK
input driver, and connect MCLK to GPIO pin 0, 1, or 3.
with I2S on-board microphone and I2S Line-In (SR WLED support not available yet, but being developed)
Q. Is it possible to use my PC for the sound and without using the microphone, or any ADC pins on the board.
The sound reactive fork of WLED was designed as an all-in-one unit that doesn't require the intervention of a PC. You can setup a display and have it run completely independently. It supports your PC's analog line-out signal, several analog microphones, an INMP441 digital microphone, as well as UDP sound sync:
https://github.com/atuline/WLED/wiki/UDP-Sound-Sync
To answer this question, not directly, except for the line-out signal. Although we support UDP sound sync, someone would have to write a program for their OS of choice to capture the sound from the PC, perform FFT calculations, and UDP transmit the sampled data (the packet matching our sound reactive WLED data structure). That's a non-trivial course of action.
All that being said, LedFx (as found at https://github.com/LedFx/LedFx) may be just the solution for this use case. Since WLED supports UDP, DDP, and E1.31 DMX protocols, you can use the sound reactive LedFx running on your PC to control a WLED device. There's an excellent video on setting this environment up at https://www.youtube.com/watch?v=ipSfQdfX4fE
LedFx will then directly control the LED's on your WLED device, although you can still revert to native WLED animations.
What's possibly on the horizon (no dates given):
We've since added several 2D routines to WLED and in the process have determined that our ESP32 binary now consumes about 98.5% of flash memory, or in oil industry terms. . . We have reached peak Flash. As a result, we're going to look carefully into ALL of the animations and see which ones consume the most flash and with the least coolness. In the meantime, we've updated SR WLED to support a very recent Master of 0.12.0, which has seen some changes/fixes since it was originally released. Special thanks to THATDONFC for keeping SR WLED in sync with Aircoookie's updates. It's not a small job.
If you'd like some help with your device, these are the types of things we would be asking:
We have disabled (and do not support) additional services such as IR, Alexa, Blynk, MQTT and so on. In order to enable them, you'll need to go into the code (see wled.h), enable the service and then compile/upload. The WLED SR team does not support these services.
If you are referring to code, please provide a link to the version you are referring to.
Is your device working in AP mode?
Got too much noise? Try lowering the current draw/brightness and clean up the wiring.
MAX4466/ESP32 Sampling results - Quiet room
MAX4466/ESP32 Sampling results - Talking
The other analog input options should provide something similar.
We received a support request reporting that UDP sound synchronization will take down a Wi-Fi network. The challenge with troubleshooting WiFi is that you need to configure your packet sniffer in monitor mode, something which is very difficult to achieve with most workstations. As a result, we are unable to see a lot of Wi-Fi network traffic.
One setting to change on 'WiFi Setup' is to check on "Disable WiFi sleep" mode.
As for UDP support, this article may shed some light on the challenges:
https://superuser.com/questions/1287485/udp-broadcasting-not-working-on-some-routers
In the meantime, UDP Sound sync has been configured to transmit 50 packets per second.
During the development of our sound reactive version of WLED, we've had several challenges with WiFi along with the ADC capability of the ESP devices.
After the code refactoring of WLED from .ino to .cpp files around April 2020, our ESP8266 code lost connection between the user interface and the ESP8266's web server. This eventually culimated in a re-write of a stripped down version of SR WLED dedicated just for the ESP8266. It included the UDP sound sync as a receiver (only), but supported none of the FFT or 2D functionality. This stripped down version seems to be stable, however that platform is now deprecated from further development.
Although the ESP32 did lose connection with the web server, it was nowhere near as bad as the ESP8266.
On both platforms, we encountered significant spikes when using the analog ADC when the WiFi is active. There are numerous articles on this issue, along with various methods to reduce the noise. We've found that an I2S microphone, such as the INMP441 or ICS-43434 will provide a better response than any of the analog microphones or input methods that we support.
Here's some test results with the analog input.
Here's some references:
Note: According to atomic14 in the above videos, the I2S microphones do not exhibit the issues found with the analog microphones.
We've sometimes been unable to connect to one or more of our WLED enabled devices. Here are some things to try:
Note: This page has been brought to you by our Discord friend @tuantrung2905. Thanks for your continued and persistent testing efforts!
This version of WLED contains sound reactive routines, which are prefaced with a * FX_NAME
for volume reactive routines and ** FX_NAME
for FFT routines. Each is controllable by the intensity and/or speed sliders. Some routines also include 3 dedicated FFT control sliders.
**Caveat: As our sound reactive fork of WLED evolves, some of this content may become out of date. We'll update as we become aware of any issues.
Contents:
Caveat: Some information on this page is in our 'dev' branch only and not yet ready for prime time.
I hope to work on an Android application in the future, so I'm keeping notes on the HTTP API.
Append the new function(s) and use current functions as templates. Cannot add any functions without accompanying index entry.
fade_out(uint8_t rate);
- This is CRITICAL!!!blur(uint8_t blur_amount);
- Can be useful.color_wheel(uint8_t index);
- This has history with NeoPixel library. I use palettes instead.SEGLEN
// uint16_t - Segment length._segment_index
// uint8_t - Current segment being displayed.
SEGMENT.length
// uint16_t - Segment length (but not for ESP8266 :^/ )
SEGMENT.intensity
// uint8_t - You can use this from the slider.SEGMENT.speed
// uint8_t - You can use this from the slider.SEGMENT.palette
// uint8_t - Current palette. Otherwise SEGCOLOR(0) and SEGCOLOR(1).SEGMENT.mode
// uint8_t - Current mode.now
// uint32_t β Millis counter.SEGENV.call
// uint32_t β Counter each time a routine is called. Can be used for 'setup'.SEGENV.next_time
// uint32_t β Millis counter.SEGENV.step
// uint32_t - Counter each time a routine is called.SEGENV.aux0
// uint16_t - Available for use as a SEGMENT specific persistent variable.SEGENV.aux1
// uint16_t - Available for use as a SEGMENT specific persistent variable.You DO NOT use delay statements here, except to keep the watchdog happy. Here is the awesome FastLED method of timing/scheduling (which DOES NOT work with segments):
EVERY_N_MILLISECONDS_I(pixTimer, SEGMENT.speed) {
pixTimer.setPeriod(256 - SEGMENT.speed);
// Put your display code here.
}
Here's the standard blink without delay version:
long lastTime = 0;
int delayMs = 2000; // We want to do something every 2 seconds.
void userLoop()
{
if (millis()-lastTime > delayMs)
{
lastTime = millis();
//do something you want to do every 2 seconds
}
}
We were used to FastLED.show(). Well, no longer, and this has some disadvantages.
CRGB myCol = ColorFromPalette(currentPalette, index, brightness, LINEARBLEND); setPixelColor(myLED, myCol.red, myCol.green, myCol.blue);
The next line supports SEGCOLOR(0) and SEGCOLOR(1) if no palette (i.e. default) is selected:
setPixelColor(i, color_blend(SEGCOLOR(1), color_from_palette(index, false, PALETTE_SOLID_WRAP, 0), pixBri));
where, i
is the location, index
is the color and pixBri
is the brightness.
Now, onto the disadvantage. . The problem is that you can perform a getPixelColor
and move it to another LED with setPixelColor
. After moving to about 10 pixels, the LED is now black. This is because of the built-in scaling and addressing the memory that's used for DMA transfer. Unfortunately, we don't get a nice lossless leds[location]
as we do with FastLED.
WLED uses the NeoPixelBus library to drive the LED's directly, however, a significant amount of FastLED functionality has been enabled in WLED. Things included:
What is NOT included:
FastLED.show()
leds[x]
arrayfill_rainbow
and related routines that directly affect the arrayfade
/nscale
, you need to use the WLED equivalentThese will be used so that we can address leds[x] in our routines with the known and lossless FastLED method rather than the lossy NeoPixelBus method. We'll also be using these for ancillary functions, i.e. heat[x] as used in fire2012.
Since you cannot define variable arrays in C, we need other methods to do so for our functions.
The WLED method has been to malloc() some memory as follows:
if (!SEGENV.allocateData(SEGLEN)) return mode_static();
byte *heat = SEGENV.data;
heat[value] = 25;
For the 2D and FastLED data array functionality, the developers of this fork are not comfortable with the malloc()
method of memory allocation and have decided to create large fixed arrays instead and to create pointers for use with variable-length arrays.
Already declared in FX.cpp:
uint32_t ledData[MAX_LEDS]; // Currently 1500 as defined in const.h. Used for conversion from NeoPixelBus to FastLED. RGB or RGBW.
uint32_t dataStore[4096]; // For ancillary functions. Can use any data type.
CRGB *leds = (CRGB *)ledData; // Define the pointer and override the default data type.
leds[0] = CRGB::Red;
leds[1] = ColorFromPalette(currentPalette, index, bright, LINEARBLEND);
First, define a function and add to FX.h
void WS2812FX::setPixels(CRGB* leds) {
for (int i=0; i<SEGLEN; i++) {
setPixelColor(i, leds[i].red, leds[i].green, leds[i].blue);
}
}
You can now use FastLED address methods, AND it works with segments.
Then, you can call this function at the end of your routine as follows:
setPixels(leds);
return FRAMETIME;
} // End of your routine.
CHSV *leds = (CHSV *)ledData;
leds[i] = CHSV(25, 255,255);
The leds[]
array is already defined in the CHSV color space.
CRGB color;
for (int i=0; i<SEGLEN; i++) {
color = leds[i];
setPixelColor(i, color.red, color.green, color.blue);
}
As used in one of the FFT animations (** Freqmatrix) in FX.cpp around line 4079.
uint32_t *leds = ledData;
CHSV c;
c = CHSV(20, 255, 255);
leds[i] = (c.h << 16) + (c.s << 8) + (c.v );
for (int i=0; i<SEGLEN; i++) {
c.h = (leds[i] >> 16) & 0xFF;
c.s = (leds[i] >> 8) &0xFF;
c.v = leds[i] & 0xFF;
color = c;
setPixelColor(i, color.red, color.green, color.blue);
}
We'll use that large dataStore array that was defined globally in FX.cpp. Although it was defined as a unint32_t
, you can still use smaller dynamic arrays and override the data type using pointers with a function:
uint8_t *myArray = (uint8_t *)dataStore; // Just make sure you don't go over.
You can now use it as a 1D or quasi 2D array, i.e.
myArray[5] = 4; // 1D array
myArray[5*matrixWidth + 4] = 10; // 2D array
We have implemented an advanced XY() function to support not only panels of varying sizes and orientations, but also for multiple (identical) panels.
Animations have been written so that the top left led in the panel(s) is, well, at the top left.
We do not (yet) have animation specific orientation settings. If you would like to do so, for any given 2D animation, you'll need to swap the parameters for the XY() function as well as changing the for loop parameter from height to width (or vice versa).
We've expanded EEPSIZE
in const.h to 4095 for ESP32 and 3300 for ESP8266 due to our additional requirements. We started saving values at 3072 defined as EEP_AUDIO
. Although we'd like to apply SEGMENT specific settings, we may have some challenges with the FFT sliders. We're not sure at this point.
Byte | Data |
---|---|
EEP_AUDIO | Sound Squelch Setting |
EEP_AUDIO+1 | Audio Sync Port |
EEP_AUDIO+2 | Audio Sync Port |
EEP_AUDIO+3 | Audio Sync Enabled |
EEP_AUDIO+4 | FFT1 Slider Value |
EEP_AUDIO+5 | FFT2 Slider Value |
EEP_AUDIO+6 | FFT3 Slider Value |
EEP_AUDIO+7 | Begin 2D Matrix Values |
EEP_AUDIO+11 | End 2D Matrix Values |
EEP_AUDIO+12 | Input Gain Setting |
How do we store FFT slider values in EEPROM for WLED presets? WLED Presets are 20-byte blocks (slots) stored in EEPROM. There is space reserved in EEPROM for 25 slots from 400-899. Currently, 18 of the 20 bytes are being used by WLED. This presents a problem for us since, at the time of writing, we have 3 bytes that we need to store for our FFT sliders. We didn't want to attempt to rewrite the entire WLED preset protocol as that would surely introduce unnecessary headaches.
To solve this problem, we reserved 25 5-byte blocks (slots) in EEPROM from 3175-3299. With the space in EEPROM allocated, we can now save/retrieve FFT slider data to/from WLED presets.
Byte | Data |
---|---|
0 | FFT1 Slider Value |
1 | FFT2 Slider Value |
2 | FFT3 Slider Value |
3 | ZERO (Reserved) |
4 | ZERO (Reserved) |
WLED limits the frame rate, and it's apparently because the LED's start flashing if the frame rate is too high. The standard for maintaining a consistent frame rate when writing any animations is to make sure you add to the end of your animation:
return FRAMETIME;
If you wish to increase the frame rate, have a look at fx.h with:
#define MIN_SHOW_DELAY 15
Also, in fx_fcn.h, there's:
if (nowUp - _lastShow<MIN_SHOW_DELAY) return;
Some animations may break when the users start implementing SEGMENTS. Issues encountered were:
Here's a replacement for EVERY_N_MILLIS()
uint8_t secondHand = millis()/(256-SEGMENT.speed) % 10;
if (SEGENV.aux0 != secondHand) {
SEGENV.aux0 = secondHand;
<rest of code goes here>
}
In the FastLED world, we could cascade led information with things like:
leds[i+1] = leds[i];
That's not an option with WLED (unless you use the *ledData method described above), because it doesn't have the leds[] array. Instead, you have:
setPixelColor(i+1,getPixelColor(i));
The problem, however is that while the FastLED method preserves the original pixel information, the 'WLED' method is lossy, and eventually the cascaded led's will fade out entirely. The workaround, as previously shown, is to create an array used by the segment that preserves the LED information. AirCoookie's method is to allocate memory on the fly for this. For instance:
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); // allocation failed
SEGENV.data[SEGLEN-1] = 0; // a byte value
If you want, you can give it another name with:
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); // allocation failed
byte* heat = SEGENV.data;
heat[SEGLEN-1] = 0; // a byte value
You now have SEGENV.data[SEGLEN] allocated for your use. Adding a structure for use with your segment is a whole other level of complexity and can be found by examining mode_multi_comet and mode_oscillate among others. Just search for SEGENV.allocateData in FX.cpp.
In order to conserve space, Web UI interface are represented as a series of wled00/html_ui.h, wled00/html_settings.h and wled00/html_other.h files which contain C/C++ strings with specific parts of the Web UI.
These files are automatically created from source files available in wled00/data folder. To generate files, install NodeJS 11.0+ globally. After that, recreate html_*.h files by running in the repo directory:
> npm install > npm run build
If you want to test changes to the UI, it is easiest to work with the local wled00/data/index.htm file. You just need to enter the IP address of a WLED 0.10.0 or newer instance into the popup. If you accidentally input an incorrect IP or want to test with a different instance, clear the local storage (in Chrome: Developer Tools -> Application -> Local Storage)
If you continuously modify files in the wled00/data directory, you want to monitor these changes to make local html_*.h files being updated automatically. To do this, run this in repo directory:
> npm run dev
This will start monitoring wled00/data folder for changes.
WARNING!!! Be careful with changing the javascript in HTML files! For example function GetV() {}
must be the last javascript function in the <script>
element as it will be replaced by automatically generated code to fetch relevant settings from EEPROM. See tools/cdata.js for the replacement rules which run for every *.htm file in wled00/data.
We've had a lot of fun creating our audio reactive fork of WLED, and we've got more to come.
Topic | Notes | Skills Required |
---|---|---|
βοΈ Dynamic sliders/controls | Allow additional sliders to be hidden by default, or displayed depending on the effect. | Javascript, XML, JSON, HTML, CSS |
βοΈ Improved default values for sliders | Allow improved default values for sliders and on a per SEGMENT basis. | Javascript, XML, JSON, HTML |
Add 2D Library support | Add a full 2D library for FastLED functionality | C, System |
βοΈ Add SEGMENT support for 2D | Improve SEGMENT capabilities | Everything |
Improved/documented QA process | We need to be able to better test our significant updates. A test/release plan would be a good start. | ITIL |
Coordinated light show | To have delayed/coordinated lighting effects in different devices. To run on Android. | Kotlin (for Android), C |
Multi-pin | To support SR WLED with SEGMENTS and multi-pin | |
per-device squelch + gain | see https://github.com/atuline/WLED/issues/221 for users who configure several sound inputs (use one at a time) it might be useful to have squelch/gain settings for each device. |
C++ |
Our focus for new functionality should be specific to sound reactivity. Otherwise, we should get some idea as to if/when AirCoookie is planning to implement this functionality.
Issue | Notes |
---|---|
This page outlines the methods we used and the files that must be modified to add a Sound Settings page to the WLED UI.
I first added a new file in the data folder named settings_sound.htm
. I did a copy/paste from settings_leds.htm
to have a base for the new settings page. Let's break down this file.
<title>
tags.<script>
tags we have a few functions that are necessary for the page to function.function H()
is our help button function. When called, the UI will direct you to the relevant wiki page inside the window.open()
function.function B()
is our back button function. When called, the UI will direct you to the previous main settings page via window.open("/settings","_self")
.function GetV()
injects the values from the relevant settings stored in EEPROM to the settings page.<style>
tag we @import
the relevant style.css
file. This closes our <head>
tag.GetV()
is called. This can vary depending on the functions that need to be called when the page loads.<body>
tag we have our form. This form holds the layout for the settings page. xml.cpp
and are used to retrieve and save these settings from/to EEPROM.This file holds the settings page button layout. We want to add an entry so we can access our new settings page. This was pretty straight forward. I added the following line, in the position I wanted it to appear on the page, using the previous entries as an example.
<form action="/settings/sound"><button type="submit">Sound Settings</button></form>
I also made some changes to the style of the buttons so they all show on the same page. This was not necessary but I feel it gave a more polished look.
This is our map, so to speak. Each setting is given a unique 2 character string that will be used to reference it in the UI. In our case, "SQ" and "GN". This file is also the map for the XML response when querying the API. Our settings aren't used in the API at this time so I won't go into that right now.
There are two important functions in xml.cpp that relates to our task which are void sappend()
and void sappends()
sappend()
takes a numeric setting and appends it to the string buffer. Valid cases for this function are:sappends()
takes a string setting and appends it to the string buffer. Valid cases for this function are:Around line 192 in xml.cpp we have the function getSettingsJS()
which retrieves the settings values from EEPROM based on the current sub-page which is defined in wled_server.cpp.
We want to add a sub-page so we need to change the following line from if (subPage <1 || subPage >7)
to if (subPage <1 || subPage >8)
. At the end of this function, after the last sub-page (previously 7) we have the following code block around line 522:
if (subPage == 8)
{
sappend('v',"SQ",soundSquelch);
sappend('v',"GN",sampleGain);
}
Here we can see our SQ and GN settings are loaded from EEPROM and filled in to their respective form field using the v case from the sappend()
function.
This file handles storing the settings entered into EEPROM. Similar to xml.cpp, we want to add a settings page so we need to tell WLED there is an additional page in the handleSettingsSet()
function. I changed the following line from if (subPage <1 || subPage >7) return;
to if (subPage <1 || subPage >8) return;
.
Lastly, I added the following code block after the last defined sub-page around line 361:
//SOUND SETTINGS
if (subPage == 8)
{
int t;
t = request->arg("SQ").toInt();
if (t > 0) soundSquelch = t;
t = request->arg("GN").toInt();
if (t > 0) sampleGain = t;
}
This file serves the webpage for the WLED frontend. We want to add a settings page so we will add the following block of code around line 82, using the previous block as an example. Notice the sub-page defined in xml.cpp is referenced as well as the NEW setting page URL defined in settings.htm.
// add sound settings page
server.on("/settings/sound", HTTP_POST, [](AsyncWebServerRequest *request){
handleSettingsSet(request, 8);
serveMessage(request, 200,F("Sound settings saved."),"Redirecting...",1);
});
In the serveSettings()
function around line 383 we need to add else if (url.indexOf("sound")> 0) subPage = 8; // add sound settings page
, so the webserver knows to load those settings.
And finally we need to add a case around line 406 for our new sub-page like this case 8: request->send_P(200, "text/html", PAGE_settings_sound, settingsProcessor); break;
.
Finally, we need to add our new settings page to cdata.js
in the tools folder. This file holds the framework for modifying the compressed *.h
files that serve the WLED frontend. This is the file nodejs looks to when running npm run build
to compress the *.htm
files in the data folder into *.h
files which are compiled with the firmware.
I used the previous entries as an example and added the following code block around line 243:
{
file: "settings_sound.htm",
name: "PAGE_settings_sound",
prepend: "=====(",
append: ")=====",
method: "plaintext",
filter: "html-minify",
mangle: (str) =>
str
.replace(/\<link rel="stylesheet".*\>/gms, "")
.replace(/\<style\>.*\<\/style\>/gms, "%CSS%%SCSS%")
.replace(
/function GetV().*\<\/script\>/gms,
"function GetV() {var d=document;\n"
),
},
Those are the steps I took to modify the WLED settings pages and add a page for the sound reactive related settings in the UI. Once those were completed, I ran npm install
and npm run build
to compress the new UI and include it in the firmware. After compiling the new firmware, I needed to reset the EEPROM via http://WLED/settings/sec?
-> Factory reset.
The following code moves the pixels down the line, but as it gets to the end, the intensity decreases significantly:
setPixelColor(i, getPixelColor(i-1));
getPixelColor()
is lossy, whereas setPixelColor()
perfectly sets the intended color. Unfortunately, the raw pixel memory buffer is also lossy, since it has to save the values scaled by master brightness. And unfortunately, if you do s = x\*b /255
, later doing x = s\*255/b
won't yield exactly the same result (thanks integer division). To solve this problem, we would need a secondary pixel data buffer.
See: https://github.com/Aircoookie/WLED/issues/820
As a workaround, you could allocate memory for each function on the fly as a double buffer and use that, or you could hard code an array. Either way, you need to double up on the memory requirements and that is extremely limited with the ESP8266 and not recommended for that platform.
if (!SEGENV.allocateData(SEGLEN)) return mode_static(); // Allocation failed
byte* myVal = SEGENV.data; // Could also be an int or long or whatever.
In this case, we are using that byte defined array for some function, but NOT to store full color values.
You could then refer to myVal[0]
up through myVal[SEGLEN-1]
within the routine for that function.
You could also define a long
, then allocate the memory for it, and then store your colors in the array until you need to transfer them to the NeoPixel buffer at the end of your routine. See the transfer code below.
One problem with dynamic memory allocation at the firmware level is that it can become segmented and fail.
First off, I would encapsulate ALL of this with #ifndef
statements because you can't guarantee memory available on an ESP8266. In FX.cpp, you would define globally:
#ifndef ESP8266
uint32_t ledData[1500]; // Or whatever value.
#endif
Similarly, you would encapsulate all functions and definitions that support that array. In the (encapsulated) animation, you would do the following:
uint16_t WS2812FX::mode_myMode(void) {
#ifndef ESP8266
uint32_t* leds = ledData;
// PERFORM ANIMATION MAGIC HERE!!
for (int i = SEGLEN; i > 0; i--) { // You can shift LED's the FastLED way.
leds[i] = leds[i-1];
}
for (int i= 0; i < SEGLEN; i++) { // Now send to the NeoPixelBus array
c.h = (leds[i] >> 16) & 0xFF;
c.s = (leds[i] >> 8) &0xFF;
c.v = leds[i] & 0xFF;
color = c; // Implicit conversion to RGB supplied by FastLED
setPixelColor(i, color.red, color.green, color.blue);
}
#else
// DO SOMETHING ELSE IF YOU WANT. Maybe a fade_out(32);
#endif
return FRAMETIME;
} // mode_myMode()
This page provides WLED programmers information on adding another slider to WLED. This information is not yet complete, as it doesn't yet deal with icons, EEPROM or IR. I will also be researching how to programmatically show/hide these sliders.
Please see https://github.com/atuline/WLED/wiki/Modifying-Sound-Reactive-WLED on how to generate html_ui.h since the UI was changed in v0.10.0-alpha-lw.
The information below describes the way html_ui.h was generated before the UI change and is deprecated.
This file is compressed and is taken from data\index.htm. Please see Aircoookie's page on 'adding your own effect:
https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
To serve your changes by the internal webserver, you will need to follow these or similar steps to gzip compress the index.html file:
Here's a link to my Google document containing the changes required:
https://docs.google.com/document/d/1m6dm3O_aXgJLGDJfM6E-4CHzzvU8bsaHqrs7VmisYko/edit
IMPORTANT NOTE:
When testing the UI, make sure to refresh your web browser. It may have cached incorrect information.