FastLED 3.10.8
Loading...
Searching...
No Matches
tempo_analyzer.h
Go to the documentation of this file.
1#pragma once
2
6#include "fl/stl/function.h"
7#include "fl/stl/vector.h"
8#include "fl/stl/deque.h"
9#include "fl/stl/noexcept.h"
10
11namespace fl {
12namespace audio {
13namespace detector {
14
15class TempoAnalyzer : public Detector {
16public:
19
20 void update(shared_ptr<Context> context) FL_NO_EXCEPT override;
21 void fireCallbacks() FL_NO_EXCEPT override;
22 bool needsFFT() const FL_NO_EXCEPT override { return true; }
23 bool needsFFTHistory() const FL_NO_EXCEPT override { return true; }
24 const char* getName() const FL_NO_EXCEPT override { return "TempoAnalyzer"; }
25 void reset() FL_NO_EXCEPT override;
26
27 // Callbacks (multiple listeners supported)
28 function_list<void(float bpm)> onTempo;
29 function_list<void(float bpm, float confidence)> onTempoWithConfidence;
30 function_list<void(float bpm)> onTempoChange;
31 function_list<void()> onTempoStable;
32 function_list<void()> onTempoUnstable;
33
34 // State access
35 float getBPM() const FL_NO_EXCEPT { return mCurrentBPM; }
36 float getConfidence() const FL_NO_EXCEPT { return mConfidence; }
37 bool isStable() const FL_NO_EXCEPT { return mIsStable; }
38 float getStability() const FL_NO_EXCEPT { return mStability; }
39
40 // Configuration
41 void setMinBPM(float minBPM) FL_NO_EXCEPT { mMinBPM = minBPM; }
42 void setMaxBPM(float maxBPM) FL_NO_EXCEPT { mMaxBPM = maxBPM; }
43 void setStabilityThreshold(float threshold) FL_NO_EXCEPT { mStabilityThreshold = threshold; }
44
45 // Scoring (public for testability)
46 float calculateIntervalScore(u32 interval) FL_NO_EXCEPT;
47
48private:
49 // Current tempo state
54 float mMinBPM;
55 float mMaxBPM;
57
58 // Tempo hypothesis tracking
60 float bpm;
61 float score;
64 };
66 static constexpr size MAX_HYPOTHESES = 5;
67
68 // Onset detection state
70 static constexpr size MAX_ONSET_HISTORY = 50;
71 vector<float> mPreviousMagnitudes; // Per-bin magnitudes for spectral flux
72 float mPreviousFlux; // Previous frame's total flux (for threshold)
75 static constexpr size FLUX_HISTORY_SIZE = 43; // ~1 second at 43fps
76
77 // Callback state tracking
78 bool mWasStable = false;
79 bool mBpmChanged = false;
80 float mPreviousBPM = 120.0f;
81
82 // Stability tracking (MedianFilter rejects half/double-tempo outliers)
85 static constexpr size BPM_HISTORY_SIZE = 20;
87 static constexpr u32 STABLE_FRAMES_REQUIRED = 10;
88
89 // Tempo range constraints
90 static constexpr u32 MIN_BEAT_INTERVAL_MS = 250; // Max 240 BPM
91 static constexpr u32 MAX_BEAT_INTERVAL_MS = 2000; // Min 30 BPM
92
94
95 // Silence gate for confidence. Decays confidence (not BPM) toward 0 with
96 // tau ~2s during silence; the BPM estimate itself is preserved so that
97 // when audio returns, beat sync resumes from the same tempo. Musical tempo
98 // has natural persistence — snapping too fast feels wrong to users.
100
101 // Timestamp of the previous update() call, used to compute dt for the
102 // envelope. Zero means "no previous frame" and the envelope skips decay
103 // for that one-off call.
105 bool mHasPrevTimestamp = false;
106
107 // Internal methods
110 bool detectOnset(u32 timestamp) FL_NO_EXCEPT;
111 void updateHypotheses(u32 timestamp) FL_NO_EXCEPT;
116};
117
118} // namespace detector
119} // namespace audio
120} // namespace fl
void bpm()
void updateHypotheses(u32 timestamp) FL_NO_EXCEPT
float getBPM() const FL_NO_EXCEPT
void setStabilityThreshold(float threshold) FL_NO_EXCEPT
function_list< void()> onTempoUnstable
static constexpr size FLUX_HISTORY_SIZE
vector< TempoHypothesis > mHypotheses
function_list< void()> onTempoStable
float getConfidence() const FL_NO_EXCEPT
bool needsFFTHistory() const FL_NO_EXCEPT override
function_list< void(float bpm, float confidence)> onTempoWithConfidence
float getStability() const FL_NO_EXCEPT
bool isStable() const FL_NO_EXCEPT
static constexpr size BPM_HISTORY_SIZE
void setMinBPM(float minBPM) FL_NO_EXCEPT
void update(shared_ptr< Context > context) FL_NO_EXCEPT override
static constexpr size MAX_ONSET_HISTORY
~TempoAnalyzer() FL_NO_EXCEPT override
void setMaxBPM(float maxBPM) FL_NO_EXCEPT
static constexpr u32 MIN_BEAT_INTERVAL_MS
static constexpr u32 MAX_BEAT_INTERVAL_MS
void fireCallbacks() FL_NO_EXCEPT override
function_list< void(float bpm)> onTempoChange
float calculateSpectralFlux(const fft::Bins &fft) FL_NO_EXCEPT
void reset() FL_NO_EXCEPT override
float calculateIntervalScore(u32 interval) FL_NO_EXCEPT
MovingAverage< float, 43 > mFluxAvg
const char * getName() const FL_NO_EXCEPT override
MedianFilter< float, 21 > mBPMMedian
float calculateTempoConfidence(const TempoHypothesis &hyp) FL_NO_EXCEPT
bool detectOnset(u32 timestamp) FL_NO_EXCEPT
bool needsFFT() const FL_NO_EXCEPT override
shared_ptr< const fft::Bins > mRetainedFFT
function_list< void(float bpm)> onTempo
static constexpr u32 STABLE_FRAMES_REQUIRED
static constexpr size MAX_HYPOTHESES
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
Base definition for an LED controller.
Definition crgb.hpp:179