FastLED 3.9.15
Loading...
Searching...
No Matches
Animartrix.ino

This sketch is fully compatible with the FastLED web compiler.

This sketch is fully compatible with the FastLED web compiler. To use it do the following:

  1. Install Fastled: pip install fastled
  2. cd into this examples page.
  3. Run the FastLED web compiler at root: fastled
  4. When the compiler is done a web page will open.
Author
Stefan Petrick
Zach Vorhies (FastLED adaptation)
// @filter: (memory is large)
/*
This demo is best viewed using the FastLED compiler.
Windows/MacOS binaries: https://github.com/FastLED/FastLED/releases
Python
Install: pip install fastled
Run: fastled <this sketch directory>
This will compile and preview the sketch in the browser, and enable
all the UI elements you see below.
OVERVIEW:
This is the famouse Animartrix demo by Stefan Petrick. The effects are generated
using polor polar coordinates. The effects are very complex and powerful.
*/
#define FL_ANIMARTRIX_USES_FAST_MATH 1
/*
Performence notes @64x64:
* ESP32-S3:
* FL_ANIMARTRIX_USES_FAST_MATH 0: 143ms
* FL_ANIMARTRIX_USES_FAST_MATH 1: 90ms
*/
#include "FastLED.h"
#if defined(FL_IS_TEENSY)
// Keep fbuild's library scanner aware of PJRC Audio sources for Teensy.
#include <Audio.h>
#endif
// DRAW TIME: 7ms
#include <FastLED.h>
#include "fl/stl/json.h"
#include "fl/stl/span.h"
#include "fl/ui/ui.h"
#ifndef PIN_DATA
#define PIN_DATA 3
#endif // PIN_DATA
#ifndef LED_PIN
#define LED_PIN PIN_DATA
#endif // LED_PIN
#define BRIGHTNESS 32
#define COLOR_ORDER GRB
#define MATRIX_WIDTH 64
#define MATRIX_HEIGHT 64
#define NUM_LEDS (MATRIX_WIDTH * MATRIX_HEIGHT)
#define FIRST_ANIMATION fl::AnimartrixAnim::POLAR_WAVES
// This is purely use for the web compiler to display the animartrix effects.
// This small led was chosen because otherwise the bloom effect is too strong.
#define LED_DIAMETER 0.15 // .15 cm or 1.5mm
#define POWER_LIMITER_ACTIVE
#define POWER_VOLTS 5
#define POWER_MILLIAMPS 2000
fl::UITitle title("Animartrix");
fl::UIDescription description("Demo of the Animatrix effects. @author of fx is StefanPetrick");
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255);
fl::UIDropdown fxIndex("Animartrix - index", {
"RGB_BLOBS5", "RGB_BLOBS4", "RGB_BLOBS3", "RGB_BLOBS2", "RGB_BLOBS",
"POLAR_WAVES", "SLOW_FADE", "ZOOM2", "ZOOM", "HOT_BLOB",
"SPIRALUS2", "SPIRALUS", "YVES", "SCALEDEMO1", "LAVA1",
"CALEIDO3", "CALEIDO2", "CALEIDO1", "DISTANCE_EXPERIMENT", "CENTER_FIELD",
"WAVES", "CHASING_SPIRALS", "ROTATING_BLOB", "RINGS", "COMPLEX_KALEIDO",
"COMPLEX_KALEIDO_2", "COMPLEX_KALEIDO_3", "COMPLEX_KALEIDO_4", "COMPLEX_KALEIDO_5", "COMPLEX_KALEIDO_6",
"WATER", "PARAMETRIC_WATER", "MODULE_EXPERIMENT1", "MODULE_EXPERIMENT2", "MODULE_EXPERIMENT3",
"MODULE_EXPERIMENT4", "MODULE_EXPERIMENT5", "MODULE_EXPERIMENT6", "MODULE_EXPERIMENT7", "MODULE_EXPERIMENT8",
"MODULE_EXPERIMENT9", "MODULE_EXPERIMENT10", "MODULE_EXPERIMENT_SM1", "MODULE_EXPERIMENT_SM2", "MODULE_EXPERIMENT_SM3",
"MODULE_EXPERIMENT_SM4", "MODULE_EXPERIMENT_SM5", "MODULE_EXPERIMENT_SM6", "MODULE_EXPERIMENT_SM8", "MODULE_EXPERIMENT_SM9",
"MODULE_EXPERIMENT_SM10", "FLUFFY_BLOBS"
});
fl::UIDropdown colorOrder("Color Order", {"RGB", "RBG", "GRB", "GBR", "BRG", "BGR"});
fl::UISlider timeSpeed("Time Speed", 1, -10, 10, .1);
// Audio UI controls
fl::UIAudio audio("Audio Input");
fl::UICheckbox enableVibeReactive("Enable Vibe Reactive", false);
fl::UISlider vibeSpeedMultiplier("Vibe Speed Multiplier", 3.0, 0.0, 10.0, 0.1);
fl::UISlider vibeBaseSpeed("Vibe Base Speed", 1.0, 0.0, 5.0, 0.1);
// Processor with Vibe
const bool kPowerLimiterActive = false;
FastLED.setMaxPowerInVoltsAndMilliamps(POWER_VOLTS, POWER_MILLIAMPS); // Set max power to 2 amps
}
}
void setup() {
Serial.begin(115200);
FL_WARN("*** SETUP ***");
auto screen_map = xyMap.toScreenMap();
screen_map.setDiameter(LED_DIAMETER);
.setCorrection(TypicalLEDStrip)
.setScreenMap(screen_map);
FastLED.setBrightness(brightness);
colorOrder.onChanged([](fl::UIDropdown &dropdown) {
int value = dropdown.as_int();
switch(value) {
case 0: value = static_cast<int>(RGB); break;
case 1: value = static_cast<int>(RBG); break;
case 2: value = static_cast<int>(GRB); break;
case 3: value = static_cast<int>(GBR); break;
case 4: value = static_cast<int>(BRG); break;
case 5: value = static_cast<int>(BGR); break;
}
animartrix.setColorOrder(static_cast<fl::EOrder>(value));
});
// Hook Vibe bass level to FxEngine timewarp.
// onVibeLevels fires every frame with self-normalizing levels:
// bass ~1.0 = average, >1.0 = louder than normal, <1.0 = quieter
// We map bass level directly to animation speed so beats accelerate
// the animation.
audioProcessor.onVibeLevels([](const fl::audio::detector::VibeLevels &vibe) {
if (!enableVibeReactive.value()) {
return;
}
// Print beat/mid/treble levels and spike flags each frame
FL_WARN("Vibe: bass=" << vibe.bass << " mid=" << vibe.mid << " treb=" << vibe.treb
<< " | spikes: bass=" << vibe.bassSpike << " mid=" << vibe.midSpike << " treb=" << vibe.trebSpike);
float bassBoost = (vibe.bass - 1.0f) * vibeSpeedMultiplier.value();
float speed = vibeBaseSpeed.value() + bassBoost;
speed *= timeSpeed.value();
fxEngine.setSpeed(speed);
});
// Log spike events
audioProcessor.onVibeBassSpike([]() {
FL_WARN(">>> BASS SPIKE!");
});
audioProcessor.onVibeMidSpike([]() {
FL_WARN(">>> MID SPIKE!");
});
audioProcessor.onVibeTrebSpike([]() {
FL_WARN(">>> TREB SPIKE!");
});
}
void loop() {
FL_WARN("*** LOOP ***");
uint32_t start = fl::millis();
FastLED.setBrightness(brightness);
// Always drain audio samples from the ring buffer to prevent overflow,
// and process them when vibe reactive is enabled.
{
if (sample.isValid()) {
static uint32_t sAudioSamples = 0;
sAudioSamples++;
if (sAudioSamples == 1) {
FL_WARN("Animartrix: First audio sample received! enableVibeReactive=" << (int)enableVibeReactive.value());
} else if (sAudioSamples % 172 == 0) {
FL_WARN("Animartrix: " << sAudioSamples << " audio samples processed, enableVibeReactive=" << (int)enableVibeReactive.value());
}
if (enableVibeReactive.value()) {
audioProcessor.update(sample);
}
}
if (!enableVibeReactive.value()) {
fxEngine.setSpeed(timeSpeed);
}
}
static int lastFxIndex = -1;
if (fxIndex.as_int() != lastFxIndex) {
lastFxIndex = fxIndex.as_int();
animartrix.fxSet(fxIndex.as_int());
}
FL_WARN("*** DRAW TIME: " << int(end - start) << "ms");
FastLED.show();
uint32_t end2 = fl::millis();
FL_WARN("*** SHOW + DRAW TIME: " << int(end2 - start) << "ms");
}
void setup()
void loop()
#define COLOR_ORDER
fl::UIAudio audio("Audio Input")
#define MATRIX_HEIGHT
fl::UISlider vibeSpeedMultiplier("Vibe Speed Multiplier", 3.0, 0.0, 10.0, 0.1)
fl::XYMap xyMap
fl::audio::Processor audioProcessor
fl::UICheckbox enableVibeReactive("Enable Vibe Reactive", false)
fl::FxEngine fxEngine(NUM_LEDS)
#define NUM_LEDS
fl::UIDescription description("Demo of the Animatrix effects. @author of fx is StefanPetrick")
fl::Animartrix animartrix(xyMap, FIRST_ANIMATION)
#define PIN_DATA
fl::UITitle title("Animartrix")
#define LED_DIAMETER
#define POWER_MILLIAMPS
#define POWER_VOLTS
fl::CRGB leds[NUM_LEDS]
const bool kPowerLimiterActive
fl::UIDropdown fxIndex("Animartrix - index", { "RGB_BLOBS5", "RGB_BLOBS4", "RGB_BLOBS3", "RGB_BLOBS2", "RGB_BLOBS", "POLAR_WAVES", "SLOW_FADE", "ZOOM2", "ZOOM", "HOT_BLOB", "SPIRALUS2", "SPIRALUS", "YVES", "SCALEDEMO1", "LAVA1", "CALEIDO3", "CALEIDO2", "CALEIDO1", "DISTANCE_EXPERIMENT", "CENTER_FIELD", "WAVES", "CHASING_SPIRALS", "ROTATING_BLOB", "RINGS", "COMPLEX_KALEIDO", "COMPLEX_KALEIDO_2", "COMPLEX_KALEIDO_3", "COMPLEX_KALEIDO_4", "COMPLEX_KALEIDO_5", "COMPLEX_KALEIDO_6", "WATER", "PARAMETRIC_WATER", "MODULE_EXPERIMENT1", "MODULE_EXPERIMENT2", "MODULE_EXPERIMENT3", "MODULE_EXPERIMENT4", "MODULE_EXPERIMENT5", "MODULE_EXPERIMENT6", "MODULE_EXPERIMENT7", "MODULE_EXPERIMENT8", "MODULE_EXPERIMENT9", "MODULE_EXPERIMENT10", "MODULE_EXPERIMENT_SM1", "MODULE_EXPERIMENT_SM2", "MODULE_EXPERIMENT_SM3", "MODULE_EXPERIMENT_SM4", "MODULE_EXPERIMENT_SM5", "MODULE_EXPERIMENT_SM6", "MODULE_EXPERIMENT_SM8", "MODULE_EXPERIMENT_SM9", "MODULE_EXPERIMENT_SM10", "FLUFFY_BLOBS" })
fl::UISlider timeSpeed("Time Speed", 1, -10, 10,.1)
fl::UISlider brightness("Brightness", BRIGHTNESS, 0, 255)
fl::UIDropdown colorOrder("Color Order", {"RGB", "RBG", "GRB", "GBR", "BRG", "BGR"})
#define BRIGHTNESS
#define FIRST_ANIMATION
void setup_max_power()
#define MATRIX_WIDTH
fl::UISlider vibeBaseSpeed("Vibe Base Speed", 1.0, 0.0, 5.0, 0.1)
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
uint16_t speed
Definition Noise.ino:66
Manages and renders multiple visual effects (Fx) for LED strips.
Definition fx_engine.h:33
int as_int() const FL_NOEXCEPT
Definition dropdown.h:127
static XYMap constructRectangularGrid(u16 width, u16 height, u16 offset=0) FL_NOEXCEPT
Definition xymap.cpp.hpp:35
constexpr EOrder BGR
Definition eorder.h:22
constexpr EOrder RBG
Definition eorder.h:18
constexpr EOrder BRG
Definition eorder.h:21
constexpr EOrder GRB
Definition eorder.h:19
constexpr EOrder RGB
Definition eorder.h:17
constexpr EOrder GBR
Definition eorder.h:20
@ TypicalLEDStrip
Typical values for SMD5050 LEDs.
Definition color.h:15
FastLED's Elegant JSON Library: fl::json
#define FL_WARN(X)
Definition log.h:276
fl::u32 uint32_t
Definition s16x16x4.h:219
fl::u32 millis()
Universal millisecond timer - returns milliseconds since system startup.
constexpr T * end(T(&array)[N]) FL_NOEXCEPT
CRGB sample(const CRGB *grid, const XYMap &xyMap, float x, float y, SampleMode mode)
Sample a pixel from a 2D CRGB grid at floating-point coordinates.
Definition sample.cpp.hpp:9
EOrder
RGB color channel orderings, used when instantiating controllers to determine what order the controll...
Definition eorder.h:13
Representation of an 8-bit RGB pixel (Red, Green, Blue)
Definition crgb.h:38
#define Serial
Definition serial.h:304
Aggregator header for the fl/ui/ family of per-element UI types.