Installing and Compiling

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.

Installing pre-built binaries

Downloading USB Drivers

Download the CH340 drivers at https://www.wemos.cc/en/latest/ch340_driver.html

Flashing From Binary

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

Flashing ESP32 Binaries with esptool

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.

  1. Download esptool.
  2. Download the ESP32 bootloader, such as https://github.com/Aircoookie/WLED/releases/download/v0.13.1/esp32_bootloader_v4.bin
  3. Download the sound reactive binary, such as https://github.com/atuline/WLED/releases
  4. Plug the ESP32 board into your computer.
  5. Optionally determine which Com port it uses. You could use NodeMCU-PyFlasher to do this, but don't flash the binary with it.
  6. Open a Command prompt on your computer.
  7. Assuming you copied esptool and both binaries to the same directory, you could clear the contents of the ESP32 with:

    esptool.exe erase_flash

  8. Then burn the bootloader with:

    esptool.exe write_flash 0x0 esp32_bootloader_v4.bin

  9. Once complete, you can now burn the sound reactive binary with:

    esptool write_flash 0x10000 soundReactive_WLED_0.13.X-bY_ESP32dev.bin

  10. You can optionally add the port, such as '-p COM6'.

  11. In addition, if this is the first time you've used this version, you need to go to the "Security & Updates" settings page and tick the "Factory reset" box, then select "Save & Reboot". Caveat: May not be necessary if you ran 'erase_flash' above.
  12. This will reset the EEPROM and remove any settings or presets you may have saved.

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.

Flashing ESP8266 Binaries

  1. Download for your platform NodeMCU-PyFlasher.
  2. Plug the WeMOS D1 Mini (or other ESP8266 device) into your computer.
  3. Run NodeMCU-PyFlasher.
  4. Load the binary.
  5. Select the Com port.
  6. Select 'yes, wipes all data'.
  7. Press Flash NodeMCU.


unofficial development binaries - here be dragons

You can find some unofficial SR WLED binaries, including intermediate development builds for ESP32, here:

Installation services

Firmware Binaries

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.


Compiling from Platform IO

Getting started

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

Additional Compile Guidelines

  • If you get .py errors, install Python (wait for the VSCode popup to install Python)
  • If you do not install the Arduino IDE (Why should you if you have PlatformIO) and your board is not recognised if you compile to board, install the USB to UART bridge VSP Drivers
  • For the sound reactive ESP32 firmware, the board type should be env:soundreactive_esp32dev. This is because we have modified the build partitions in order to go beyond the original compile size limits of WLED.

Note: We have long since stopped compiling WLED with the Arduino IDE.

Disabled Feature of WLED

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.

How to Shoot Yourself in the Foot

If you're keen to use a disabled WLED feature, in your personal build of SR-WLED:

  1. check if there is a -D DISABLE_... flag in your build environment (platformio.ini, or platformio_override.ini), and comment it out or remove it.
  2. check if the feature is disabled explicitly in wled00/wled.h.
  3. 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.

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

First Time Setup

Introduction

The sound reactive version of WLED provides all of the functionality of WLED with a few caveats:

  • Some of the default services supported by WLED such as IR, Alexa and Blynk are disabled by default. To enable them, update the definitions in wled.h and re-compile.

  • Spurious noise and spikes have been problematic during the development of SR WLED. See 'Noise and Spikes' below for further discussion on this topic.
  • We recommend using SR WLED in STA mode, instead of the standalone AP mode (aka WLED-AP). It generates more noise.
  • If you have problems with the LED's, make sure you can successfully run the latest version of standard WLED.
  • Start out with a small strip of ~30 LED's before setting up a large installation.
  • Grounding may also be a problem. For example, my line-in setup picked up a lot of noise when my ESP32 board was connected to the USB port on my PC, but NO noise when powered by a USB power bank.
  • Connectors!! Dupont connectors are notoriously flaky. I use JST-SM connectors for the LED's and (so far) just soldered the microphones.

First Steps

First Contact (after uploading)

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.

Wifi and LEDs

  1. On the WiFi Setup page, it is highly recommended that you connect your SR WLED strip to an existing network.
  2. At the bottom of the WiFi Setup page, check on 'Disable WiFi sleep'. This may not be necessary if you're not experiencing noise or UDP Sync lag issues.
  3. On the LED Preferences page, configure the length of your led strip.
  4. On the LED Preference page, configure the 2D matrix size, i.e. 1x30 or 16x16, etc. If you have not configured this, 2D routines may not work.

Sound

  1. On the Sound Setting page, set the Squelch setting to '1', the Gain > 200, and AGC = Off.
  2. On the Effects page, set the animation to 'Gravcenter' or 'Gravimeter'.
  3. Back on the Sound Settings page, increase/save Squelch setting until strip no longer reacts to the ambient noise.
  4. On the Sound Settings page, set the Gain to 40. Then reduce/adjust the Gain setting until the leds react reasonably with your voice.
  5. You might also want to run a Pink Noise video and fine tune the values from there.

Sound Settings: getting started with common microphones

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.

Noise and Spikes

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:

  • Use an I2S microphone, such as the INMP441, SPH0645 or ICS-43434.
  • Use a separate WiFi antenna.
  • Don't use AP mode.
  • Disable the WiFi sleep mode.

  • Use shielded wiring for your analog sampling pin.

  • Isolate the power between the LED strips and the controller.
  • Don't power your LED stripe from the ESP32 3.3v or 5v pins.
  • Don't use USB power from your PC.
  • Some batches of analog microphones are just no good.

2D Support

Introduction

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

2D architecture

WLED SR distinguishes between the following levels

  • 2D Segment (dev)
  • 2D Matrix (dev)
  • 2D Panel (dev)

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

2D Segments

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

Rotation and ReverseX/Y

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

2D Matrices and panels

See Led Preferences

Technical

  • CRGB leds[MAX_LEDS+1]; in FX.cpp defines all leds on the matrix. Multiple segments share this array and effects should only write to leds[] within the boundaries of a segment. This is done by calling leds[XY(x,y)] or leds[realPixelIndex(i)].
  • Functions with leds as parameter should follow above rule and have been refactored for this. E.g. fadeToBlackBy(leds, 32) or fill_solid(leds, 0) otherwise it writes outside the segment boundaries.

2D Segment start stop charts

16x16 matrix

32x32 matrix

(Created by Harry Baas)

Examples

16x16 matrix

To get the (x,y) coordinates from the start and stop led:

  • Segment top left = (start%matrixWidth, start/matrixWidth)
  • Segment bottom right = (stop%matrixWidth, stop/matrixWidth)

Example of 1 segment (default) covering a whole 16x16 matrix:

  • start = 0, stop = 255
  • top left = (0,0)
  • bottom right = (15,15)
  • width = height = 16

Example of a segment covering a middle part rectangle of the 16x16 matrix:

  • start = 20, stop = 235
  • top left = (4,1)
  • bottom right = (10,14)
  • width = 7
  • height = 14

Example of a segment covering the left part of the 16x16 matrix:

  • start = 0, stop = 241
  • top left = (0,0)
  • bottom right = (0,15)
  • width = 1
  • height = 16

16 x 12 matrix

matrixWidth = 16, matrixHeight = 12.

Total led count 192 leds

left and right binmap effect. In the middle noisemove.

  • Segment 0 (middle): start=1, stop=191, effect=noisemove
  • Segment 1 (left): start=0, stop=176, effect=binmap
  • Segment 2 (right): start=15, stop=192, effect=binmap

Api commands for 2D effects

16 segments for 32x32 matrices

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}]}

LED Preferences

LED Preferences for Sound Reactive WLED

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 Matrix

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!

2D Panels

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

2D Panel layout

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.

Example:

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:

Sound Settings

Introduction

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.


Press reset key after changing sound source

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


Analog Input Pins

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.


Squelch

Adjust this value on the Sound Settings page so that the leds are only activated above a certain 'background noise' level.

Gain

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.

How To

Here's a method to setup squelch and gain for your SR WLED Device.

  1. Start out with the routine '*Gravimeter' with default sliders in the middle.
  2. Go to the sound settings configuration page.
  3. Increase gain to a high value, let's say 234 (or higher) and set the squelch to '1', AGC off, then save.
  4. Depending on your input, you should now see the led's flashing, even when the wind blows.
  5. In a quiet environment, increase and occasionally save the "squelch" incrementally until the led's are no longer flashing.
  6. Once that's done, set "gain" to 40. Make noise appropriate to your 'noisy' environment and number of led's. Then adjust/save the gain so that the led's are responding appropriately.
  7. Note that some of the animations allow further sensitivity adjustment with the 'Intensity' setting.
  8. Check out the 'Sound Reactive Animations' page to see what controls are available for each animation.

Voltage Fluctuation

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.

I2S Digital Input

Currently the following I2S options are available:

Some more information can be found on our I2S digital microphones page.

to be extended soon

I2S Line-in

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.

AGC - improved Autonomous Gain Control

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:

  • Off - AGC off. WLED will strictly use the Gain value from sound input settings, without any adjustments.
  • Normal - AGC tries to smoothly follow changes in sound input volume. Recommended as a balanced option for general use.
  • Vivid - AGC will quickly adjust to changes in sound input volume. Recommended in case you want "more blinken from your LEDs".
  • Lazy - AGC will take some more time before internal gain is adjusted. Recommended for GEQ effects, or when listening to music that features strong "dynamics".

to be extended soon

Running Sound Reactive WLED

Captive Portal

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.

Initial Sound Reactive Settings

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.

Initial 2D Settings - ESP32 Only

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.

Initial UDP Sync Settings

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.

Connect to WLED

  1. Open up settings on your phone or computer.
  2. Navigate to your Wi-Fi settings.
  3. Look for the WLED SSID, default is "WLED-AP".
  4. Enter the password, the default is "wled1234".
  5. Once connected, you should automatically be re-directed to your LED strip.
  6. This gets you to the limited captive portal 'browser'.
  7. If not, open up a browser and navigate to 4.3.2.1.

Configure a bootup effects sequence

  1. From the main screen, click on "TO THE CONTROLS!"
  2. Select the "Effects" tab.
  3. Select an effect mode, i.e. "Bpm".
  4. Adjust overall brightness, speed, and intensity/fade rate.
  5. Select the "Colors" tab.
  6. Select one of the palettes, such as "Beach".
  7. Select the "Favorites" tab.
  8. Select the "Saving mode" checkbox.
  9. Save to slot "1".
  10. Check the "Preset" cycle.
  11. Select the Config cog at the top right of the application display.
  12. Select "LED Preference".
  13. Check "Set current preset cycle setting as boot default" checkbox.
  14. Click on "Save" at the bottom of the screen.

Reset the device

  1. Log in to the device. If you cannot log in, then you need to Reflash the device, which may default to AP mode.
  2. Select the Config cog at the top right of the application display.
  3. Select "Security and Updates".
  4. Check "Factory reset".
  5. Click on "Save & reboot".
  6. Reverts to the initial AP Mode and all other settings are gone.

Sound Reactive Animations

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

Slider Usage

Please see the brief slider descripion for each effect in the rightmost column above.

Speed/Intensity

These typically reflect the value of their namesake. Intensity would typically be number of LED's lit, or brightness of the LED's

FFT Sliders

These may get renamed in the future and could be used for FFT routines OR for additional effect adjustments.

Peak Detection

This is NOT beat detection, but rather samples that are louder than a the current average plus a slider adjustable value.

Automatic Gain Control

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.

FFT Routines

Additional effect notes

Freqmatrix

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:

  1. Speed: This determines the time delay before each pixel is moved down the line.
  2. Intensity: This determines how MUCH the sound input affects the selected effect.
  3. FFT Low: Can be an additional adjustment. Can also select low end of frequency bins if used by that effect.
  4. FFT High: Can be an additional adjustment. Can also select high end of frequency bins if used by that effect.
  5. FFT Custom: Can be an addiitional adjustment.

Freqwave

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:

  1. Speed: This determines the time delay before each pixel is moved down the line.
  2. Intensity: This determines how MUCH the sound input affects the selected effect.
  3. FFT Low: The low cut off for the FFT bins. Values range from 0-100. Good values are from 0 to 10
  4. FFT High: High cut off for the FFT bins. Values range from 0-100. This is important because every type of music is different and what is considered a high note in one type of music is not the case in others.
  5. FFT Custom: This slider works similarly to a "pre-amp" for the input signal. The possible values for this slider are 1-10. A good starting point for this is around 2-3.

Non-Reactive Animations

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

2D Clock Overlay

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

2D Animations

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.

Custom Effects

Table of contents generated with markdown-toc

Custom effects

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.

Quick start

To get your first Custom Effect running, perform the following steps

  • In tab effects, select 'βš™οΈ Custom Effect'

  • In tab Segments, give the segment a name, this will be the name of the Custom Effect

  • Click on Custom Effect Editor

  • Click on Download wled.json to enable Custom Effects for WLED (needed each time a new version of CE is published)
  • Click on Load template to get a 'hello world' example
  • Press save and the template will be executed

Running examples

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.

Create your own Custom Effects

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.

Components

  • 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

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.

WLED general

"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"},

WLED SR

"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"},

Custom Effects

"counter": {"return": "uint32"},

"shift": {"delta": "int"},
"circle2D": {"degrees": "int"}, 

Math

"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"},

Time

"hour": {"return":"uint8"},
"minute": {"return":"uint8"},
"second": {"return":"uint8"},
"millis": {"return": "uint32"},

Pixelblase support

"time": {"inVal":"double", "return": "double"},
"triangle": {"t":"double", "return": "double"},
"wave": {"v":"double", "return": "double"},
"square": {"v":"double", "t":"double", "return": "double"},

Serial output

"printf": {"args": "__VA_ARGS__"}

Details

  • ledcount: number of leds within(!) a segment
  • setpixelColor: currently the second parameter is color from palette!
  • leds: one or 2 dimensional array: One index for led strips and 2 indexes for panels. If the leds variable is used an implicit setPixels(leds) will be done each frame!
  • shift: shift all leds left or right (using delta)
  • circle2D: puts a dot on a circle using the angle. Used to show a 2D clock, see clock2D.wled
  • random: 16 bit random nr
  • sin/cos: value between -1 and 1
  • hour/minute/second: current time (set in time preferences)
  • printf: currently no real printf: prints numbers, max 3

Implementation of variables and functions

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:

Current limitations

  • Only 1 segment
  • no unary operators like - (use 0-1) and ++, --
  • no strings

trouble shooting

  • effect crashes: most likely too deeply nested commands (e.g. pixbri = (sin(startVal + millis()/(255- freq)) + 1) * 128), try to split up in more lines.

UDP Sound Sync

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.

Setup

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.

Technical

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

What else ?

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

Analog Audio Input Options

Microphone Input

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.


The following schematics are provided as an example only. There are many ways to achieve the same results. These are only a few of those ways.

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.

Dual Input Wiring

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.

Pins Used

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.

Squelch

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.

Gain

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.

Problems Encountered

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.

Digital Microphone Hookup

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


Some I2S audio modules and boards

IMNP441

This is the IMNP441; you can find it in many shops including Amazon and Aliexpress. It works very well with SR WLED.

 

 

ICS-43434

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/

 

I2S ADC for Line-In

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.

 

ES7243 based boards

 

ES8388 based boards

with I2S on-board microphone and I2S Line-In (SR WLED support not available yet, but being developed)

Using my PC for the Sound

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.

News

What's possibly on the horizon (no dates given):

  • Add 2D orientation settings, but no multi-SEGMENT 2D orientation support.
  • Yes, we'd love dynamic controls for each animation, but we think that may interfere with future releases from Aircoookie.
  • We are working on adding multiple panels.
  • Automatic gain control. It's a challenge because each animation uses sound variables differently. And yes, it will be there πŸ‘ in the upcoming release.
  • Improvements to our audio processing algorithms. More awesomeness for your LEDs.
  • More and improved sound reactive effects.

May 15, 2021

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.

January 13, 2021

  • Well that was a year, only for 2021 to say 'hold my beer'.
  • We've been working on fixing bugs, including UDP sync issues among others.
  • Normalizing frequency and volume response for different microphones.
  • Testing/updating various routines to work with the above changes.
  • Modified routines to better support the 'FastLED' way of doing things, specifically for leds[i+1] = leds[i] and vice versa.
  • Dealing with platform related noise and spikes. Had to add an exponential filter combined with the squelch control.
  • Added a few more animations, and took out one or two.

November 5, 2020

  • The ESP8266 branch continues to be reliable for that platform, but NOT reliable for the regular build. Would love to know why. Update: It was probably RAM usage.
  • Have fixed issues around SEGMENTS for various sound reactive animations. Ths issue was SEGMENT specific 'persistent' variables. Use the uint16_t SEGENV.aux0 or SEGENV.aux1 variables if you need those.
  • That was updated for both the dev and ESP8266 branches.
  • We now have a dedicated Sound Settings page.

August 22, 2020

  • Our dev build now has INMP441 (digital microphone) support for the ESP32.
  • Our dev build also now has a Gain settings control for volume reactive or '*' routines.
  • Neither update has been rolled up into our main branch.
  • We've had a lot of issues with AP mode and ESP8266's, so Andrew created an ESP8266 branch, downloaded the latest version of WLED and added just the volume reactive functionality to that branch.
  • We'll be removing ESP8266 support from our dev and main branches over time. That will simplify coding significantly.
  • apleschu is still busy with his cross continental move.

It's Not Working

If you'd like some help with your device, these are the types of things we would be asking:

  • If you require support, please engage the Discord community as linked to in the readme.md. Github issues are more for actual bugs in the firmware.
  • When asking for support on Discord or on another forum, please provide details up front and not way down a threaded list of messages. Edit your original question if you have more information to provide.
  • The latest version of SR WLED for the ESP32 has a sound pin configurator. Please review yours.
  • Don't forget to check the pin on the LED settings page.
  • Please provide a comprehensive, but clear and concise description of the symptoms and your environment.
  • That includes things like exactly what board you're using, how many led's, are you using a level shifter
  • Also, the exact steps you took to flash a binary and the steps you took after doing so.
  • How about posting a crystal clear close-up photo of your wiring, or better yet, a block diagram.
  • If something doesn't work as a result of an upgrade, did you roll back to ensure it still works?
  • Don't just reboot the device. Actually, cycle the power (reference: IT Crowd).
  • If you change the microphone pin/type, you need to reboot. If using an I2S microphone, you need to cycle the power on the device.
  • You may need to re-flash/clear the device completely especially after a major update.
  • SR WLED had to change from the default 'partition size' because we outgrew the default 1MB. As a result, you need to perform a 'Factory reset' after flashing it.
  • Does the regular version of WLED work, while this one doesn't?
  • 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 it just sound reactivity that doesn't work? Is there a specific animation?
  • Is it an ESP32? An ESP8266? Please provide the link that you downloaded the files from.
  • How exactly did you flash the device? See https://github.com/atuline/WLED/wiki/Installing-and-Compiling
  • Are you compiling from IDE? We are no longer supporting the Arduino IDE.
  • Make sure your microphone is powered by the 3V pin and NOT Vin or 5V . . and that your LED's are NOT connected to that 3V pin either (source: experience).
  • If you had previously used a 5V pin for your microphone, you may have blown that analog pin.
  • Have you gone through initial settings?
  • Is your audio all wired up OK? See here.
  • Which microphone/input are you using and how is it configured?
  • Leave the MAX4466 gain untouched. It works fine out of the box.
  • Have you tested that microphone with a basic analog sound sampling sketch?
  • You have an INMP441 or ICS-43434? Try the basic digital sound sampling sketch.
  • What are the results of that sketch? Does it respond to your speech? A MAX4466 and INMP401 should average about 1875 on an ESP32, a MAX9814 about 1350 for all gain settings.
  • Try a different pin when using that sketch if you're still not seeing good results.
  • Have spares of everything. They're cheap and they break. (source: experience)
  • How about power? Lots of LED's require lots of power and a common ground for everything.
  • Does the latest release from WLED work?
  • Are you using our most recent 'MASTER' release?
  • Have you tried flashing our latest release?
  • Is your device working in AP mode?

  • Got too much noise? Try lowering the current draw/brightness and clean up the wiring.

  • If it's a compile error, can you provide the errors?
  • Have you made any changes to the source?
  • UDP Sync not working? Have you tested WLED's built-in sync? Do you need to enable multicast on your network equipment?
  • If your bootloader is broken, the binary may not load. Try the one from wled.me first.
  • Can you document the steps to re-create that error?
  • Make sure your grounds are all connected together.
  • If you're using our 'dev' branch, don't forget to make a fresh 'pull'.
  • See my FastLED support FAQ.

MAX4466/ESP32 Sampling results - Quiet room

MAX4466/ESP32 Sampling results - Talking

The other analog input options should provide something similar.

UDP Sound Sync Issues

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.

Noise and Spikes

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.

ESP8266

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.

ESP32

Although the ESP32 did lose connection with the web server, it was nowhere near as bad as the ESP8266.

Both platforms

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.

Connectivity Issues

We've sometimes been unable to connect to one or more of our WLED enabled devices. Here are some things to try:

  • Wipe (using pyflasher or esptool.py) and re-flash your device.
    • NOTE: For ESP32 you must write flash at 0x10000. There are great instructions here.
  • For more reliable connectivity on Android, go into WiFi advanced settings (press the 3 dots at the top right of the WiFi page) and disable 'Switch to mobile data' as well as 'Wi-Fi power saving mode'.
  • In the WIFI Setup settings page of WLED, uncheck 'Disable WiFi sleep'.
  • Ensure you have a strong signal to the device.
  • When compiling, make sure you have selected Flash Size as 4MB (FS:2MB OTA:~1019KB)

Note: This page has been brought to you by our Discord friend @tuantrung2905. Thanks for your continued and persistent testing efforts!

WLED Programming Notes

Introduction

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.

Updating FX.h (line numbers will vary)

  • Line 105 – Update the mode count.
  • Line 250 - Added extern variables around line 250 of FX.h. These are defined in audio_reactive.h.
  • Line 214 – Update the defines.
  • Line 456 – Update the _mode.
  • Line 697 – Update the mode definition and don’t forget , and ;
  • Line 816 – Update the JSON entry. Can add an extra entry. No Spaces, 10 per line!!

Updating FX.cpp

Append the new function(s) and use current functions as templates. Cannot add any functions without accompanying index entry.

WLED Support Functions

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

Important WLED variables

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

Important Structures

  • FX.h:267 - Segment aka SEGMENT
  • FX.h:318 - Segment runtime.value> aka SEGENV
  • FX.h:66 - Other stuff

Delays

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
  }
}

Displaying the LED's.

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.

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:

  • FastLED Math and trigonometry
  • Noise
  • Palettes
  • Palette transitioning (use your own palette variables though)
  • EVERY_N_MILLIS

What is NOT included:

  • FastLED.show()
  • FastLED pixel setup
  • FastLED power management
  • Working directly with the leds[x] array
  • fill_rainbow and related routines that directly affect the array
  • fade/nscale, you need to use the WLED equivalent

On Variable Length Arrays

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

Using CRGB Color Space

  CRGB *leds = (CRGB *)ledData;     // Define the pointer and override the default data type.
  leds[0] = CRGB::Red;
  leds[1] = ColorFromPalette(currentPalette, index, bright, LINEARBLEND);

Display the CRGB Array

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.

Proposed - Using CHSV Colour Space

   CHSV *leds = (CHSV *)ledData;
   leds[i]  = CHSV(25, 255,255);

Proposed - Display the CHSV Colour Space

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);
    }

Current Use of the CHSV Colour Space

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 );

Current Display of CHSV array

    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);
    }

How to use a non-dynamically created variable array

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

2D Changes

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

Sound Reactive EEPROM Layout

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

Presets in EEPROM

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)

On Frame Rates

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;

  • Frametime is a constant, which is 1000/42. In order to increase the FPS, instead of return frametime, we can write a smaller value than that and for max speed simply go for return(0), which is the smallest.

On Segments

Some animations may break when the users start implementing SEGMENTS. Issues encountered were:

  • Triggers. A triggered event, which was reset by the animation. This does not work with SEGMENTS. One workaround is knowing that the MIN_SHOW_DELAY is 15, and then determine if now-original_event > MIN_SHOW_DELAY in order to reset the animation.
  • To get the current segment being displayed, try Serial.println(_segment_index);
  • To use persistent variable across SEGMENTS, don't use 'static', but rather use the existing uint16_t defined SEGENV.aux0 and SEGENV.aux1 variables. Too bad they're not uint32_t.
  • For further reading on persistent variables, see this page https://github.com/atuline/WLED/wiki/Persistent-Variables-and-WLED

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>
  }

getPixel and setPixel

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.

Modifying Sound Reactive WLED

Changing Web UI

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.

Future Directions

We've had a lot of fun creating our audio reactive fork of WLED, and we've got more to come.

Wish List

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.

Outstanding Issues

Issue Notes

Adding a new Settings Page

Introduction

This page outlines the methods we used and the files that must be modified to add a Sound Settings page to the WLED UI.

NEW settings_sound.htm

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.

  • At the top, we have our standard HTML beginning lines with the TITLE of the page between the <title> tags.
  • Inside of the <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.
  • Inside the <style> tag we @import the relevant style.css file. This closes our <head> tag.
  • When the body of the page is loaded, function GetV() is called. This can vary depending on the functions that need to be called when the page loads.
  • Inside the <body> tag we have our form. This form holds the layout for the settings page.
    • Our squelch and gain settings have the names "SQ" and "GN" respectively. These names refer to the name given to the setting in xml.cpp and are used to retrieve and save these settings from/to EEPROM.

Modify settings.htm

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.

Modify xml.cpp

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:
    • 'c', a check box
    • 'v', a numeric value
    • 'i', the selected index
  • sappends() takes a string setting and appends it to the string buffer. Valid cases for this function are:
    • 's', a string setting
    • 'm', a message to be displayed

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.

Modify set.cpp

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;
}

Modify wled_server.cpp

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

Modify cdata.js

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.

On Lossy Colours

Issue

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));

Explanation

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

Workarounds

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.

Allocate memory

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.

Hard-coded array

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()

Sliders in WLED

Introduction

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.

Updating html_ui.h

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:

  1. Gzip compress the file. I use this online converter, use setting Compress this file, output – gz
  2. Rename file to xxx.gz.png (change file type to image)
  3. Convert it to a C-style byte/char array. I use this converter, intended for image sprites. Therefore, the previous step of changing the file format was neccessary. Select Raw as Color format.
  4. Open the downloaded .c file in a text editor, e. g. Notepad++. Select the contents of the array and replace the array contents in html_ui.h with them.
  5. Update PAGE_index_L to the binary size stated in the bottom of the downloaded .c file Recompile and flash WLED!

Here's a link to my Google document containing the changes required:

https://docs.google.com/document/d/1m6dm3O_aXgJLGDJfM6E-4CHzzvU8bsaHqrs7VmisYko/edit

Testing

IMPORTANT NOTE:

When testing the UI, make sure to refresh your web browser. It may have cached incorrect information.

Compile

  • Compile/run on ESP32.
  • Compile/run on ESP8266.

Network

  • Configure/test for AP mode.
  • Configure/test for STA mode.

Colors

  • Test Default palette as well as defined palettes.
  • Test RGBW.
  • Test with various effects.

Effects

  • Test each effect with/without palette.
  • Ensure they are all present and line-up.

Segments

  • Configure multiple segments.
  • Configure multiple groups.
  • Segment options.

Sound

  • Configure squelch setting.
  • Reboot.
  • Microphone input sensitivity.

2D

  • Test different sizes, i.e. 1x32, 16x16, etc.
  • Serpentine/linear.
  • Single/multi-panels.
  • Layouts

UDP Sound Sync

  • Test ESP32 to ESP8266 sync.
  • Test ESP32 to ESP32 sync.
  • Test all modes.

EEPROM

  • Ensure EEPROM changes survive reboot.
  • Test with ESP32.
  • Test with ESP8266.
  • (Ensure EEPROM default is not 255 or 65535 - Not done yet).
  • OTA updates.