FastLED 3.9.15
Loading...
Searching...
No Matches
Sailboat.ino
// Ported from github.com/zackees/sailboat-lights (FastLED 3.6.0 era).
// The effect logic lives in PerlinParticlePunch (Fx1d); this sketch wires up
// hardware, audio detector callbacks, and color palettes.
// @filter: (mem is large)
#include <FastLED.h>
#if defined(FL_IS_TEENSY)
// Keep fbuild's library scanner aware of PJRC Audio sources for Teensy.
#include <Audio.h>
#endif
#include "fl/ui/ui.h"
// ---------------------------------------------------------------------------
// Configuration
// ---------------------------------------------------------------------------
#define NUM_LEDS 200
#define DATA_PIN 3
#define BRIGHTNESS 255
#define COLOR_ORDER RGB
// I2S pins for INMP441 microphone (adjust for your board)
#define I2S_WS 7
#define I2S_SD 8
#define I2S_CLK 4
// ---------------------------------------------------------------------------
// Globals
// ---------------------------------------------------------------------------
fl::UICheckbox enableAmbient("Ambient Particles", true);
fl::UICheckbox enableMeteors("Beat Meteors", true);
fl::UICheckbox enableTimeWarp("Noise Time-Warp", false);
// Vibe bass is self-normalizing: ~1.0 = song average.
// meteorThreshold: bass must exceed this multiple of average to spawn meteor.
fl::UISlider meteorThreshold("Meteor Threshold", 1.5f, 1.5f, 6.0f, 0.1f);
// ambientThreshold: bass above this spawns ambient particles.
fl::UISlider ambientThreshold("Ambient Threshold", 1.0f, 0.5f, 3.0f, 0.1f);
fl::UISlider dragSlider("Particle Drag", 0.06f, 0.0f, 1.0f, 0.01f);
fl::UISlider speedSlider("Particle Speed", 2.6f, 0.1f, 3.0f, 0.1f);
fl::UISlider ambientTrailSlider("Ambient Trail", 217.0f, 0.0f, 255.0f, 1.0f);
fl::UISlider meteorTrailSlider("Meteor Trail", 171.0f, 0.0f, 255.0f, 1.0f);
fl::UISlider ambientDecaySlider("Ambient Fade", 0.955f, 0.90f, 1.0f, 0.005f);
fl::UISlider minVelocitySlider("Min Velocity", 0.01f, 0.01f, 0.5f, 0.01f);
fl::UISlider debrisDecaySlider("Debris Fade", 0.96f, 0.80f, 1.0f, 0.01f);
fl::UISlider debrisVelDecaySlider("Debris Drag", 0.95f, 0.85f, 1.0f, 0.01f);
// Perlin time-warp state (decays each frame in loop())
float noiseTimeMultiplier = 1.0f;
// Screen map: LEDs follow the main sail hypotenuse with natural sag (catenary)
fl::ScreenMap(NUM_LEDS, 0.15f, [](int index, fl::vec2f &pt_out) {
float t = float(index) / float(NUM_LEDS - 1);
// Straight line: lower-left (15, 5) → upper-right (95, 95)
// Y-up coordinate system: high y = top of screen
pt_out.x = 15.0f + t * 80.0f;
float straight_y = 5.0f + t * 90.0f;
// Sag: catenary droop, subtract to bulge downward visually
float sag = 15.0f * fl::sin(t * FL_M_PI);
pt_out.y = straight_y - sag;
});
// ---------------------------------------------------------------------------
// Arduino setup / loop
// ---------------------------------------------------------------------------
void setup() {
Serial.begin(115200);
//FastLED.setExclusiveDriver(fl::Bus::SPI);
fl::ClocklessChipset chipset(DATA_PIN, timing);
config.setScreenMap(screenMap);
FastLED.add(config);
FastLED.setBrightness(BRIGHTNESS);
// Group UI elements
enableAmbient.setGroup("Features");
enableMeteors.setGroup("Features");
enableTimeWarp.setGroup("Features");
meteorThreshold.setGroup("Audio Detection");
ambientThreshold.setGroup("Audio Detection");
dragSlider.setGroup("Physics");
speedSlider.setGroup("Physics");
minVelocitySlider.setGroup("Physics");
ambientTrailSlider.setGroup("Trails");
meteorTrailSlider.setGroup("Trails");
ambientDecaySlider.setGroup("Trails");
debrisDecaySlider.setGroup("Trails");
debrisVelDecaySlider.setGroup("Trails");
// Blue-white palettes
CRGBPalette16 bluePalette(CRGB(0, 0, 40), CRGB(0, 40, 120),
CRGB(100, 160, 255), CRGB(255, 255, 255));
sailboatFx.setNoisePalette(bluePalette);
sailboatFx.setAmbientPalette(bluePalette);
sailboatFx.setMeteorGradient(CRGB(255, 255, 255), // white-hot head
CRGB(140, 180, 255), // light blue mid
CRGB(0, 40, 120)); // deep blue tail
// Register effect with engine
// --- Wire up audio detector callbacks ---
// Uses the Vibe detector which self-normalizes bass levels:
// getVibeBass() ~1.0 = average for current song
// >1.0 = louder than average, <1.0 = quieter
// This approach works across all music volumes and styles.
auto audio = FastLED.add(audio_ui);
fxEngine.setAudio(audio); // delivers AudioBatch to effects via DrawContext
if (audio) {
// Called every frame with full vibe data — we do threshold
// checks here for both ambient and meteor spawning.
audio->onVibeLevels(
[&](const fl::audio::detector::VibeLevels &levels) {
float bass = levels.bass; // self-normalizing, ~1.0 avg
// Ambient: spawn on bass spikes above ambient threshold
if (enableAmbient && levels.bassSpike &&
bass > ambientThreshold.value()) {
// Scale intensity: map bass from threshold..threshold*2
// to 0.3..1.0
float thresh = ambientThreshold.value();
float intensity =
fl::clamp((bass - thresh) / thresh, 0.3f, 1.0f);
int count = 1 + int(intensity * 2.0f); // 1-3 particles
for (int i = 0; i < count; i++) {
sailboatFx.spawnAmbient(intensity);
}
}
// Meteor: spawn only on very strong bass hits
if (enableMeteors && levels.bassSpike &&
bass > meteorThreshold.value()) {
float thresh = meteorThreshold.value();
// Map bass from threshold..threshold*2 to 0.4..1.0
float intensity =
fl::clamp((bass - thresh) / thresh, 0.4f, 1.0f);
sailboatFx.spawnMeteor(intensity);
noiseTimeMultiplier = 1.0f + intensity * 2.0f;
}
});
// Drop detector: biggest moments (has built-in 2s cooldown)
audio->onDropImpact([&](float impact) {
sailboatFx.spawnMeteor(impact);
noiseTimeMultiplier = 2.0f + impact;
});
}
}
void loop() {
//FL_WARN("Loop");
//delay(10);
// Decay time-warp back to normal
if (noiseTimeMultiplier < 1.01f)
sailboatFx.setTimeMultiplier(noiseTimeMultiplier);
// Update physics params from sliders
float drag = 0.99f - dragSlider.value() * 0.19f;
sailboatFx.setDrag(drag);
sailboatFx.setSpeed(speedSlider.value());
sailboatFx.setAmbientTrailIntensity(u8(ambientTrailSlider));
sailboatFx.setMeteorTrailIntensity(u8(meteorTrailSlider));
sailboatFx.setAmbientBrightnessDecay(ambientDecaySlider.value());
sailboatFx.setMinVelocity(minVelocitySlider.value());
sailboatFx.setDebrisBrightnessDecay(debrisDecaySlider.value());
sailboatFx.setDebrisVelocityDecay(debrisVelDecaySlider.value());
// Draw current effect and show
fxEngine.draw(millis(), leds);
FastLED.show();
//delay(10);
}
void setup()
void loop()
#define COLOR_ORDER
fl::UIAudio audio("Audio Input")
fl::FxEngine fxEngine(NUM_LEDS)
#define NUM_LEDS
fl::CRGB leds[NUM_LEDS]
#define BRIGHTNESS
#define I2S_CLK
#define I2S_SD
#define I2S_WS
#define DATA_PIN
Definition ClientReal.h:82
fl::UIAudio audio_ui("Audio Input")
FL_DISABLE_WARNING_PUSH FL_DISABLE_WARNING_GLOBAL_CONSTRUCTORS CFastLED FastLED
Global LED strip management instance.
fl::UISlider speedSlider("Particle Speed", 2.6f, 0.1f, 3.0f, 0.1f)
fl::UICheckbox enableMeteors("Beat Meteors", true)
fl::UISlider ambientTrailSlider("Ambient Trail", 217.0f, 0.0f, 255.0f, 1.0f)
fl::UISlider minVelocitySlider("Min Velocity", 0.01f, 0.01f, 0.5f, 0.01f)
fl::audio::Config audioConfig
Definition Sailboat.ino:44
fl::UICheckbox enableAmbient("Ambient Particles", true)
fl::UISlider ambientDecaySlider("Ambient Fade", 0.955f, 0.90f, 1.0f, 0.005f)
fl::UICheckbox enableTimeWarp("Noise Time-Warp", false)
fl::UISlider debrisVelDecaySlider("Debris Drag", 0.95f, 0.85f, 1.0f, 0.01f)
float noiseTimeMultiplier
Definition Sailboat.ino:68
fl::UISlider dragSlider("Particle Drag", 0.06f, 0.0f, 1.0f, 0.01f)
fl::UISlider meteorTrailSlider("Meteor Trail", 171.0f, 0.0f, 255.0f, 1.0f)
fl::UISlider debrisDecaySlider("Debris Fade", 0.96f, 0.80f, 1.0f, 0.01f)
fl::UISlider meteorThreshold("Meteor Threshold", 1.5f, 1.5f, 6.0f, 0.1f)
fl::PerlinParticlePunch sailboatFx(NUM_LEDS)
fl::UISlider ambientThreshold("Ambient Threshold", 1.0f, 0.5f, 3.0f, 0.1f)
Runtime chipset timing configuration for clockless LED drivers.
Manages and renders multiple visual effects (Fx) for LED strips.
Definition fx_engine.h:33
static Config CreateInmp441(int pin_ws, int pin_sd, int pin_clk, AudioChannel channel, u16 sample_rate=44100ul, int i2s_num=0) FL_NOEXCEPT
Definition input.h:153
fl::ScreenMap screenMap
Definition Corkscrew.h:101
static uint32_t t
Definition Luminova.h:55
@ TypicalLEDStrip
Typical values for SMD5050 LEDs.
Definition color.h:15
fl::CRGB CRGB
Definition crgb.h:25
unsigned char u8
Definition stdint.h:131
#define FL_M_PI
Definition math.h:34
fl::u32 millis()
Universal millisecond timer - returns milliseconds since system startup.
vec2< float > vec2f
Definition geometry.h:333
constexpr ChipsetTimingConfig makeTimingConfig() FL_NOEXCEPT
Convert compile-time CHIPSET type to runtime timing config.
enable_if< is_fixed_point< T >::value, T >::type sin(T angle) FL_NOEXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type clamp(T x, T lo, T hi) FL_NOEXCEPT
Audio-reactive perlin noise background with ambient particles and beat meteor overlay.
Configuration for a single LED channel.
Definition config.h:163
Optional channel configuration parameters All fields have sensible defaults and can be overridden as ...
Definition options.h:43
Clockless chipset configuration (single data pin)
Definition config.h:32
value_type y
Definition geometry.h:191
value_type x
Definition geometry.h:190
#define Serial
Definition serial.h:304
Aggregator header for the fl/ui/ family of per-element UI types.