FastLED 3.9.15
Loading...
Searching...
No Matches
Sailboat.ino
Go to the documentation of this file.
1
5
6// Ported from github.com/zackees/sailboat-lights (FastLED 3.6.0 era).
7// The effect logic lives in PerlinParticlePunch (Fx1d); this sketch wires up
8// hardware, audio detector callbacks, and color palettes.
9
10// @filter: (mem is large)
11
12#include <FastLED.h>
13
14#if defined(FL_IS_TEENSY)
15// Keep fbuild's library scanner aware of PJRC Audio sources for Teensy.
16#include <Audio.h>
17#endif
18
19#include "fl/channels/config.h"
22#include "fl/fx/fx_engine.h"
23#include "fl/ui/ui.h"
24
25
26// ---------------------------------------------------------------------------
27// Configuration
28// ---------------------------------------------------------------------------
29#define NUM_LEDS 200
30#define DATA_PIN 3
31
32#define BRIGHTNESS 255
33#define COLOR_ORDER RGB
34
35// I2S pins for INMP441 microphone (adjust for your board)
36#define I2S_WS 7
37#define I2S_SD 8
38#define I2S_CLK 4
39
40// ---------------------------------------------------------------------------
41// Globals
42// ---------------------------------------------------------------------------
47fl::UICheckbox enableAmbient("Ambient Particles", true);
48fl::UICheckbox enableMeteors("Beat Meteors", true);
49fl::UICheckbox enableTimeWarp("Noise Time-Warp", false);
50// Vibe bass is self-normalizing: ~1.0 = song average.
51// meteorThreshold: bass must exceed this multiple of average to spawn meteor.
52fl::UISlider meteorThreshold("Meteor Threshold", 1.5f, 1.5f, 6.0f, 0.1f);
53// ambientThreshold: bass above this spawns ambient particles.
54fl::UISlider ambientThreshold("Ambient Threshold", 1.0f, 0.5f, 3.0f, 0.1f);
55fl::UISlider dragSlider("Particle Drag", 0.06f, 0.0f, 1.0f, 0.01f);
56fl::UISlider speedSlider("Particle Speed", 2.6f, 0.1f, 3.0f, 0.1f);
57fl::UISlider ambientTrailSlider("Ambient Trail", 217.0f, 0.0f, 255.0f, 1.0f);
58fl::UISlider meteorTrailSlider("Meteor Trail", 171.0f, 0.0f, 255.0f, 1.0f);
59fl::UISlider ambientDecaySlider("Ambient Fade", 0.955f, 0.90f, 1.0f, 0.005f);
60fl::UISlider minVelocitySlider("Min Velocity", 0.01f, 0.01f, 0.5f, 0.01f);
61fl::UISlider debrisDecaySlider("Debris Fade", 0.96f, 0.80f, 1.0f, 0.01f);
62fl::UISlider debrisVelDecaySlider("Debris Drag", 0.95f, 0.85f, 1.0f, 0.01f);
64
66
67// Perlin time-warp state (decays each frame in loop())
69
70// Screen map: LEDs follow the main sail hypotenuse with natural sag (catenary)
72 fl::ScreenMap(NUM_LEDS, 0.15f, [](int index, fl::vec2f &pt_out) {
73 float t = float(index) / float(NUM_LEDS - 1);
74 // Straight line: lower-left (15, 5) → upper-right (95, 95)
75 // Y-up coordinate system: high y = top of screen
76 pt_out.x = 15.0f + t * 80.0f;
77 float straight_y = 5.0f + t * 90.0f;
78 // Sag: catenary droop, subtract to bulge downward visually
79 float sag = 15.0f * fl::sin(t * FL_M_PI);
80 pt_out.y = straight_y - sag;
81 });
82
83// ---------------------------------------------------------------------------
84// Arduino setup / loop
85// ---------------------------------------------------------------------------
86void setup() {
87 Serial.begin(115200);
88 //FastLED.setExclusiveDriver(fl::Bus::SPI);
92 fl::ClocklessChipset chipset(DATA_PIN, timing);
94 config.setScreenMap(screenMap);
95 FastLED.add(config);
96 FastLED.setBrightness(BRIGHTNESS);
97
98 // Group UI elements
99 enableAmbient.setGroup("Features");
100 enableMeteors.setGroup("Features");
101 enableTimeWarp.setGroup("Features");
102
103 meteorThreshold.setGroup("Audio Detection");
104 ambientThreshold.setGroup("Audio Detection");
105
106 dragSlider.setGroup("Physics");
107 speedSlider.setGroup("Physics");
108 minVelocitySlider.setGroup("Physics");
109
110 ambientTrailSlider.setGroup("Trails");
111 meteorTrailSlider.setGroup("Trails");
112 ambientDecaySlider.setGroup("Trails");
113 debrisDecaySlider.setGroup("Trails");
114 debrisVelDecaySlider.setGroup("Trails");
115
116 // Blue-white palettes
117 CRGBPalette16 bluePalette(CRGB(0, 0, 40), CRGB(0, 40, 120),
118 CRGB(100, 160, 255), CRGB(255, 255, 255));
119 sailboatFx.setNoisePalette(bluePalette);
120 sailboatFx.setAmbientPalette(bluePalette);
121 sailboatFx.setMeteorGradient(CRGB(255, 255, 255), // white-hot head
122 CRGB(140, 180, 255), // light blue mid
123 CRGB(0, 40, 120)); // deep blue tail
124
125 // Register effect with engine
126 fxEngine.addFx(sailboatFx);
127
128 // --- Wire up audio detector callbacks ---
129 // Uses the Vibe detector which self-normalizes bass levels:
130 // getVibeBass() ~1.0 = average for current song
131 // >1.0 = louder than average, <1.0 = quieter
132 // This approach works across all music volumes and styles.
133 auto audio = FastLED.add(audio_ui);
134 fxEngine.setAudio(audio); // delivers AudioBatch to effects via DrawContext
135 if (audio) {
136 // Called every frame with full vibe data — we do threshold
137 // checks here for both ambient and meteor spawning.
138 audio->onVibeLevels(
139 [&](const fl::audio::detector::VibeLevels &levels) {
140 float bass = levels.bass; // self-normalizing, ~1.0 avg
141
142 // Ambient: spawn on bass spikes above ambient threshold
143 if (enableAmbient && levels.bassSpike &&
144 bass > ambientThreshold.value()) {
145 // Scale intensity: map bass from threshold..threshold*2
146 // to 0.3..1.0
147 float thresh = ambientThreshold.value();
148 float intensity =
149 fl::clamp((bass - thresh) / thresh, 0.3f, 1.0f);
150 int count = 1 + int(intensity * 2.0f); // 1-3 particles
151 for (int i = 0; i < count; i++) {
152 sailboatFx.spawnAmbient(intensity);
153 }
154 }
155
156 // Meteor: spawn only on very strong bass hits
157 if (enableMeteors && levels.bassSpike &&
158 bass > meteorThreshold.value()) {
159 float thresh = meteorThreshold.value();
160 // Map bass from threshold..threshold*2 to 0.4..1.0
161 float intensity =
162 fl::clamp((bass - thresh) / thresh, 0.4f, 1.0f);
163 sailboatFx.spawnMeteor(intensity);
164 if (enableTimeWarp)
165 noiseTimeMultiplier = 1.0f + intensity * 2.0f;
166 }
167 });
168
169 // Drop detector: biggest moments (has built-in 2s cooldown)
170 audio->onDropImpact([&](float impact) {
171 if (enableMeteors)
172 sailboatFx.spawnMeteor(impact);
173 if (enableTimeWarp)
174 noiseTimeMultiplier = 2.0f + impact;
175 });
176 }
177}
178
179void loop() {
180 //FL_WARN("Loop");
181 //delay(10);
182 // Decay time-warp back to normal
183 noiseTimeMultiplier *= 0.95f;
184 if (noiseTimeMultiplier < 1.01f)
185 noiseTimeMultiplier = 1.0f;
186 sailboatFx.setTimeMultiplier(noiseTimeMultiplier);
187
188 // Update physics params from sliders
189 float drag = 0.99f - dragSlider.value() * 0.19f;
190 sailboatFx.setDrag(drag);
191 sailboatFx.setSpeed(speedSlider.value());
192 sailboatFx.setAmbientTrailIntensity(u8(ambientTrailSlider));
193 sailboatFx.setMeteorTrailIntensity(u8(meteorTrailSlider));
194 sailboatFx.setAmbientBrightnessDecay(ambientDecaySlider.value());
195 sailboatFx.setMinVelocity(minVelocitySlider.value());
196 sailboatFx.setDebrisBrightnessDecay(debrisDecaySlider.value());
197 sailboatFx.setDebrisVelocityDecay(debrisVelDecaySlider.value());
198
199 // Draw current effect and show
200 fxEngine.draw(millis(), leds);
201 FastLED.show();
202 //delay(10);
203}
#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::FxEngine fxEngine(NUM_LEDS)
fl::audio::Config audioConfig
Definition Sailboat.ino:44
fl::UICheckbox enableAmbient("Ambient Particles", true)
void setup()
Definition Sailboat.ino:86
fl::UISlider ambientDecaySlider("Ambient Fade", 0.955f, 0.90f, 1.0f, 0.005f)
fl::UICheckbox enableTimeWarp("Noise Time-Warp", false)
fl::UIAudio audio_ui("Audio Input", audioConfig)
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)
void loop()
Definition Sailboat.ino:179
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
#define FL_M_PI
Definition math.h:34
unsigned char u8
Definition stdint.h:131
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.
void setScreenMap(const fl::ScreenMap &map) FL_NOEXCEPT
Set screen map for JS canvas visualization.
Definition config.h:251
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.