FastLED 3.9.15
Loading...
Searching...
No Matches
audio_reactive.h
Go to the documentation of this file.
1#pragma once
2
3#include "fl/audio/fft/fft.h"
4#include "fl/stl/int.h"
5#include "fl/audio/audio.h" // IWYU pragma: keep
12#include "fl/stl/array.h"
13#include "fl/stl/span.h"
14#include "fl/stl/shared_ptr.h"
15#include "fl/stl/unique_ptr.h"
17#include "fl/gfx/colorutils.h" // IWYU pragma: keep
18#include "fl/gfx/crgb.h" // for CRGB // IWYU pragma: keep
19#include "fl/stl/vector.h"
20#include "fl/stl/noexcept.h"
21
22namespace fl {
23namespace audio {
24
25class Processor;
26
27// Forward declarations for enhanced beat detection
30namespace detector {
31class MusicalBeat;
32class MultiBandBeat;
33}
34
35// Audio data structure - matches original WLED output with extensions
36struct Data {
37 float volume = 0.0f; // Overall volume level (0.0-1.0, adaptive normalized)
38 float volumeRaw = 0.0f; // Raw volume without smoothing (0.0-1.0)
39 float peak = 0.0f; // Peak level (0.0-1.0)
40 bool beatDetected = false; // Beat detection flag
41 float frequencyBins[16] = {0}; // 16 frequency bins (matches WLED NUM_GEQ_CHANNELS)
42 float dominantFrequency = 0.0f; // Major peak frequency (Hz)
43 float magnitude = 0.0f; // fft::FFT magnitude of dominant frequency
44 fl::u32 timestamp = 0; // millis() when data was captured
45
46 // Enhanced beat detection fields
47 bool bassBeatDetected = false; // Bass-specific beat detection
48 bool midBeatDetected = false; // Mid-range beat detection
49 bool trebleBeatDetected = false; // Treble beat detection
50 float spectralFlux = 0.0f; // Current spectral flux value
51 float bassEnergy = 0.0f; // Energy in bass frequencies (0-1)
52 float midEnergy = 0.0f; // Energy in mid frequencies (6-7)
53 float trebleEnergy = 0.0f; // Energy in treble frequencies (14-15)
54};
55
57 fl::u8 gain = 128; // Input gain (0-255)
58 fl::u8 sensitivity = 128; // AGC sensitivity
59 bool noiseGate = true; // Noise gate
60 fl::u8 attack = 50; // Attack time (ms) - how fast to respond to increases
61 fl::u8 decay = 200; // Decay time (ms) - how slow to respond to decreases
62 u16 sampleRate = 22050; // Sample rate (Hz)
63 fl::u8 scalingMode = 3; // 0=none, 1=log, 2=linear, 3=sqrt
64
65 // Enhanced beat detection configuration
66 bool enableSpectralFlux = true; // Enable spectral flux-based beat detection
67 bool enableMultiBand = true; // Enable multi-band beat detection
68 float spectralFluxThreshold = 0.1f; // Threshold for spectral flux detection
69 float bassThreshold = 0.15f; // Threshold for bass beat detection
70 float midThreshold = 0.12f; // Threshold for mid beat detection
71 float trebleThreshold = 0.08f; // Threshold for treble beat detection
72
73 // Signal conditioning configuration
74 bool enableSignalConditioning = true; // Enable DC removal, spike filter, noise gate
75 bool enableNoiseFloorTracking = true; // Enable noise floor tracking
76
77 // Frequency bin mapping configuration
78 bool enableLogBinSpacing = true; // Use logarithmic frequency bin spacing (vs linear)
79
80 // Spectral equalizer configuration (optional middleware)
81 bool enableSpectralEqualizer = false; // Enable spectral EQ (A-weighting, custom curves)
82
83 // Musical beat detection configuration (Phase 3 middleware)
84 bool enableMusicalBeatDetection = false; // Enable advanced beat tracking with BPM
85 bool enableMultiBandBeats = false; // Enable per-band beat detection
86 float musicalBeatMinBPM = 60.0f; // Minimum BPM for musical beats
87 float musicalBeatMaxBPM = 180.0f; // Maximum BPM for musical beats
88 float musicalBeatConfidence = 0.5f; // Minimum confidence for beat validation
89};
90
91class Reactive {
92public:
95
96 // Setup
97 void begin(const ReactiveConfig& config = ReactiveConfig{});
98 void setConfig(const ReactiveConfig& config);
99
100 // Process audio sample - this does all the work immediately
101 void processSample(const Sample& sample);
102
103 // Optional: update smoothing without new sample data
104 void update(fl::u32 currentTimeMs);
105
106 // Data access
107 const Data& getData() const;
108 const Data& getSmoothedData() const;
109
110 // Convenience accessors
111 float getVolume() const;
112 float getBass() const; // Average of bins 0-1
113 float getMid() const; // Average of bins 6-7
114 float getTreble() const; // Average of bins 14-15
115 bool isBeat() const;
116
117 // Enhanced beat detection accessors
118 bool isBassBeat() const;
119 bool isMidBeat() const;
120 bool isTrebleBeat() const;
121 float getSpectralFlux() const;
122 float getBassEnergy() const;
123 float getMidEnergy() const;
124 float getTrebleEnergy() const;
125
126 // ----- Polling Getters (float 0.0-1.0, bool, or integer) -----
127 // These forward to an internal Processor for detector-based analysis.
128
129 // Vocal Detection
130 float getVocalConfidence();
131
132 // Beat Detection (detector-based)
133 float getBeatConfidence();
134 float getBPM();
135
136 // Energy Analysis
137 float getEnergyLevel();
138 float getPeakLevel();
139
140 // Frequency Bands
141 float getBassLevel();
142 float getMidLevel();
143 float getTrebleLevel();
144
145 // Silence Detection
146 bool isSilent();
147 u32 getSilenceDuration();
148
149 // Transient Detection
150 float getTransientStrength();
151
152 // Dynamics Analysis
153 float getDynamicTrend(); // -1.0 to 1.0
154 bool isCrescendo();
155 bool isDiminuendo();
156
157 // Pitch Detection
158 float getPitchConfidence();
159 float getPitchHz();
160
161 // Tempo Analysis
162 float getTempoConfidence();
163 float getTempoBPM();
164
165 // Buildup Detection
166 float getBuildupIntensity();
167 float getBuildupProgress();
168
169 // Drop Detection
170 float getDropImpact();
171
172 // Percussion Detection
173 bool isKick();
174 bool isSnare();
175 bool isHiHat();
176 bool isTom();
177
178 // Note Detection
180 float getNoteVelocity();
181 float getNoteConfidence();
182
183 // Downbeat Detection
184 float getDownbeatConfidence();
185 float getMeasurePhase();
187
188 // Backbeat Detection
189 float getBackbeatConfidence();
190 float getBackbeatStrength();
191
192 // Chord Detection
193 float getChordConfidence();
194
195 // Key Detection
196 float getKeyConfidence();
197
198 // Mood Analysis
199 float getMoodArousal();
200 float getMoodValence(); // -1.0 to 1.0
201
202 // Gain control - delegates to internal Processor
203 void setGain(float gain);
204 float getGain() const;
205
206 // Effect helpers
207 fl::u8 volumeToScale255() const;
208 CRGB volumeToColor(const CRGBPalette16& palette) const;
209 fl::u8 frequencyToScale255(fl::u8 binIndex) const;
210
211 // Signal conditioning stats
214
215 // Spectral equalizer stats (optional middleware - must be enabled first)
216 bool isSpectralEqualizerEnabled() const;
218
219private:
220 // Internal processing methods
221 void processFFT(const Sample& sample);
223 void updateVolumeAndPeak(const Sample& sample);
224 void detectBeat(fl::u32 currentTimeMs);
225 void smoothResults();
226 void applyScaling();
227 void applyGain();
228
229 // Enhanced beat detection methods
230 void detectEnhancedBeats(fl::u32 currentTimeMs);
232 void updateSpectralFlux();
233 void applyAWeighting();
236
237 // Helper methods
238 float mapFrequencyBin(int fromBin, int toBin);
239 float computeRMS(const fl::vector<fl::i16>& samples);
240
241 // Configuration
243
244 // FFT processing (via shared Context for caching)
247
248 // Audio data
251
252 // Processing state
253 fl::u32 mLastBeatTime = 0;
254 static constexpr fl::u32 BEAT_COOLDOWN = 100; // 100ms minimum between beats
255
256 // Volume tracking for beat detection
257 float mPreviousVolume = 0.0f;
258 float mVolumeThreshold = 0.04f;
259
260 // Pink noise compensation: √(f_center / f_ref) normalized so geometric mean ≈ 1.0.
261 // Compensates for 1/f spectral tilt of natural audio (music, speech).
262 // Computed dynamically from bin centers in begin().
263 float mPinkNoiseGains[16] = {};
264 bool mPinkNoiseComputed = false;
265
266 // Signal conditioning components
270
271 // Enhanced beat detection components
274
275 // Musical beat detection components (Phase 3 middleware)
279
280 // Enhanced beat detection state
282
283 // Silence-gate envelopes for spectral metrics (FastLED#2253).
284 // During silence (Context::isSilent() true), these fast-decay the
285 // dominantFrequency / magnitude / spectralFlux outputs toward zero so
286 // the FFT noise floor does not lock onto arbitrary bins. During audio
287 // they are pass-through. Tau = 0.2 s — spectral metrics are brittle
288 // and should snap to zero quickly.
292
293 // Internal Processor for detector-based polling getters
296};
297
298// Spectral flux-based onset detection for enhanced beat detection
300public:
303
304 void reset();
305 bool detectOnset(span<const float, 16> currentBins);
306 float calculateSpectralFlux(span<const float, 16> currentBins, span<const float, 16> previousBins);
307 void setThreshold(float threshold);
308 float getThreshold() const;
309
310private:
313
314#if SKETCH_HAS_LARGE_MEMORY
315 fl::array<float, 32> mFluxHistory; // For advanced smoothing
316 fl::size mHistoryIndex;
317 float calculateAdaptiveThreshold();
318#endif
319};
320
321// Multi-band beat detection for different frequency ranges
325
326 void reset();
327 void detectBeats(span<const float, 16> frequencyBins, Data& audioData);
328 void setThresholds(float bassThresh, float midThresh, float trebleThresh);
329
330private:
331#if SKETCH_HAS_LARGE_MEMORY
332 SpectralFluxDetector bass; // 20-200 Hz (bins 0-1)
333 SpectralFluxDetector mid; // 200-2000 Hz (bins 6-7)
334 SpectralFluxDetector treble; // 2000-20000 Hz (bins 14-15)
335#else
336 SpectralFluxDetector combined; // Single detector for memory-constrained
337#endif
338
339 // Energy tracking for band-specific thresholds
346};
347
348// Perceptual audio weighting for psychoacoustic processing
350public:
353
354 void applyAWeighting(Data& data) const;
355 void applyLoudnessCompensation(Data& data, float referenceLevel) const;
356
357private:
358 // A-weighting coefficients for 16-bin frequency analysis
359 static constexpr float A_WEIGHTING_COEFFS[16] = {
360 0.5f, 0.6f, 0.8f, 1.0f, 1.2f, 1.3f, 1.4f, 1.4f,
361 1.3f, 1.2f, 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.1f
362 };
363
364#if SKETCH_HAS_LARGE_MEMORY
365 fl::array<float, 16> mLoudnessHistory; // For dynamic compensation
366 fl::size mHistoryIndex;
367#endif
368};
369
370} // namespace audio
371} // namespace fl
UINumberField palette("Palette", 0, 0, 2)
A fixed-size array implementation similar to std::array.
Definition array.h:27
FrequencyBinMapper maps FFT output bins to perceptually-spaced frequency channels.
NoiseFloorTracker maintains an adaptive estimate of the background noise floor for audio signals,...
Get current statistics (for monitoring/debugging)
void applyLoudnessCompensation(Data &data, float referenceLevel) const
static constexpr float A_WEIGHTING_COEFFS[16]
void applyAWeighting(Data &data) const
float mapFrequencyBin(int fromBin, int toBin)
void detectEnhancedBeats(fl::u32 currentTimeMs)
void begin(const ReactiveConfig &config=ReactiveConfig{})
fl::u8 volumeToScale255() const
void update(fl::u32 currentTimeMs)
fl::u8 frequencyToScale255(fl::u8 binIndex) const
const SignalConditioner::Stats & getSignalConditionerStats() const
void detectBeat(fl::u32 currentTimeMs)
void processSample(const Sample &sample)
fl::unique_ptr< SpectralFluxDetector > mSpectralFluxDetector
SilenceEnvelope mDominantFrequencyEnvelope
fl::unique_ptr< SpectralEqualizer > mSpectralEqualizer
CRGB volumeToColor(const CRGBPalette16 &palette) const
fl::unique_ptr< detector::MultiBandBeat > mMultiBandBeatDetector
shared_ptr< Context > mContext
fl::unique_ptr< Processor > mAudioProcessor
bool isSpectralEqualizerEnabled() const
Processor & ensureAudioProcessor()
void processFFT(const Sample &sample)
SilenceEnvelope mMagnitudeEnvelope
ReactiveConfig mConfig
void setConfig(const ReactiveConfig &config)
SignalConditioner mSignalConditioner
NoiseFloorTracker mNoiseFloorTracker
const Data & getSmoothedData() const
fl::unique_ptr< detector::MusicalBeat > mMusicalBeatDetector
const SpectralEqualizer::Stats & getSpectralEqualizerStats() const
fl::unique_ptr< PerceptualWeighting > mPerceptualWeighting
fl::array< float, 16 > mPreviousMagnitudes
const NoiseFloorTracker::Stats & getNoiseFloorStats() const
static constexpr fl::u32 BEAT_COOLDOWN
const Data & getData() const
~Reactive() FL_NOEXCEPT
float computeRMS(const fl::vector< fl::i16 > &samples)
SilenceEnvelope mSpectralFluxEnvelope
FrequencyBinMapper mFrequencyBinMapper
void updateVolumeAndPeak(const Sample &sample)
SignalConditioner performs low-level audio preprocessing to clean raw PCM samples before FFT analysis...
Get current statistics (for debugging/monitoring)
Get statistics (for debugging/monitoring)
float calculateSpectralFlux(span< const float, 16 > currentBins, span< const float, 16 > previousBins)
bool detectOnset(span< const float, 16 > currentBins)
fl::array< float, 16 > mPreviousMagnitudes
MultiBandBeat performs frequency-specific beat detection.
MusicalBeat distinguishes true musical beats from random onset detection.
#define constexpr
Declares that it is possible to evaluate a value at compile time, introduced in C++11.
Definition cpp_compat.h:15
Utility functions for color fill, palettes, blending, and more.
Defines the 8-bit red, green, and blue (RGB) pixel type in the fl namespace.
float frequencyBins[16]
unsigned char u8
Definition s16x16x4.h:132
unsigned char u8
Definition stdint.h:131
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
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT
Representation of an 8-bit RGB pixel (Red, Green, Blue)
Definition crgb.h:38
void setThresholds(float bassThresh, float midThresh, float trebleThresh)
~BeatDetectors() FL_NOEXCEPT
void detectBeats(span< const float, 16 > frequencyBins, Data &audioData)
SpectralFluxDetector combined