FastLED 3.9.15
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) override;
21 void fireCallbacks() override;
22 bool needsFFT() const override { return true; }
23 bool needsFFTHistory() const override { return true; }
24 const char* getName() const override { return "TempoAnalyzer"; }
25 void reset() 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 { return mCurrentBPM; }
36 float getConfidence() const { return mConfidence; }
37 bool isStable() const { return mIsStable; }
38 float getStability() const { return mStability; }
39
40 // Configuration
41 void setMinBPM(float minBPM) { mMinBPM = minBPM; }
42 void setMaxBPM(float maxBPM) { mMaxBPM = maxBPM; }
43 void setStabilityThreshold(float threshold) { mStabilityThreshold = threshold; }
44
45 // Scoring (public for testability)
46 float calculateIntervalScore(u32 interval);
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
108 float calculateSpectralFlux(const fft::Bins& fft);
110 bool detectOnset(u32 timestamp);
111 void updateHypotheses(u32 timestamp);
112 void pruneHypotheses();
113 void updateCurrentTempo();
114 void updateStability();
116};
117
118} // namespace detector
119} // namespace audio
120} // namespace fl
void bpm()
void setStabilityThreshold(float threshold)
function_list< void()> onTempoUnstable
static constexpr size FLUX_HISTORY_SIZE
vector< TempoHypothesis > mHypotheses
function_list< void()> onTempoStable
function_list< void(float bpm, float confidence)> onTempoWithConfidence
float calculateSpectralFlux(const fft::Bins &fft)
const char * getName() const override
static constexpr size BPM_HISTORY_SIZE
bool needsFFTHistory() const override
static constexpr size MAX_ONSET_HISTORY
static constexpr u32 MIN_BEAT_INTERVAL_MS
static constexpr u32 MAX_BEAT_INTERVAL_MS
void update(shared_ptr< Context > context) override
float calculateTempoConfidence(const TempoHypothesis &hyp)
function_list< void(float bpm)> onTempoChange
MovingAverage< float, 43 > mFluxAvg
MedianFilter< float, 21 > mBPMMedian
~TempoAnalyzer() FL_NOEXCEPT override
shared_ptr< const fft::Bins > mRetainedFFT
function_list< void(float bpm)> onTempo
static constexpr u32 STABLE_FRAMES_REQUIRED
static constexpr size MAX_HYPOTHESES
Base definition for an LED controller.
Definition crgb.hpp:179
#define FL_NOEXCEPT