FastLED 3.9.15
Loading...
Searching...
No Matches

◆ detectDownbeat()

bool fl::audio::detector::Downbeat::detectDownbeat ( u32 timestamp,
float accent )
private

Definition at line 220 of file downbeat.cpp.hpp.

220 {
221 // Downbeat detection strategy:
222 // 1. Check if we're at the expected measure boundary
223 // 2. Check if accent is strong enough
224 // 3. Check if pattern matches metric grouping
225
226 // If we haven't detected any downbeats yet, consider this one
227 if (mLastDownbeatTime == 0) {
228 // Use accent strength for initial confidence instead of fixed 0.5
229 // This provides a better estimate based on actual audio characteristics
230 float meanAccent = 1.0f;
231 if (!mBeatAccents.empty()) {
232 float sum = 0.0f;
233 for (size i = 0; i < mBeatAccents.size(); i++) {
234 sum += mBeatAccents[i];
235 }
236 meanAccent = sum / static_cast<float>(mBeatAccents.size());
237 }
238
239 // Calculate accent-based confidence
240 // If we have accent history, use it; otherwise use raw accent with moderate confidence
241 float accentConfidence = meanAccent > 0.0f
242 ? fl::clamp(accent / (meanAccent * mAccentThreshold), 0.0f, 1.0f)
243 : fl::clamp(accent * 0.5f, 0.3f, 0.7f); // Raw accent scaled to 30-70% range
244
245 mConfidence = accentConfidence;
246 return true;
247 }
248
249 // Calculate expected downbeat position
250 u32 timeSinceDownbeat = timestamp - mLastDownbeatTime;
251 float beatInterval = mBeatDetector->getBPM() > 0.0f
252 ? (60000.0f / mBeatDetector->getBPM())
253 : 500.0f;
254 float expectedMeasureDuration = beatInterval * static_cast<float>(mBeatsPerMeasure);
255
256 // Check if we're near expected measure boundary
257 float timingError = fl::abs(static_cast<float>(timeSinceDownbeat) - expectedMeasureDuration);
258 float maxTimingError = beatInterval * 0.4f; // Allow 40% timing error
259 bool nearMeasureBoundary = (timingError < maxTimingError);
260
261 // Check if accent is strong enough
262 float meanAccent = 1.0f;
263 if (!mBeatAccents.empty()) {
264 float sum = 0.0f;
265 for (size i = 0; i < mBeatAccents.size(); i++) {
266 sum += mBeatAccents[i];
267 }
268 meanAccent = sum / static_cast<float>(mBeatAccents.size());
269 }
270
271 bool strongAccent = (accent > meanAccent * mAccentThreshold);
272
273 // Check if we're at the beat counter boundary
274 bool atBeatCounterBoundary = (mBeatsSinceDownbeat >= mBeatsPerMeasure - 1);
275
276 // Calculate confidence
277 float timingConfidence = 1.0f - (timingError / (beatInterval * 2.0f));
278 timingConfidence = fl::clamp(timingConfidence, 0.0f, 1.0f);
279
280 float accentConfidence = meanAccent > 0.0f
281 ? fl::clamp(accent / (meanAccent * mAccentThreshold), 0.0f, 1.0f)
282 : 0.5f;
283
284 // Adaptive weighting: favor accent when at beat boundary (structural downbeat)
285 // This improves recall for first downbeat after warm-up
286 float accentWeight = atBeatCounterBoundary ? 0.7f : 0.5f;
287 float timingWeight = atBeatCounterBoundary ? 0.3f : 0.5f;
288 mConfidence = (timingConfidence * timingWeight) + (accentConfidence * accentWeight);
289
290 // Additional confidence boost for structural downbeats (at beat boundary)
291 // This compensates for timing uncertainties in the first few measures
292 if (atBeatCounterBoundary && mConfidence < 0.6f) {
293 mConfidence = fl::max(mConfidence, 0.55f); // Ensure minimum confidence at boundaries
294 }
295
296 // Determine if this is a downbeat
297 bool isDownbeat = false;
298
299 if (atBeatCounterBoundary) {
300 // We're at expected measure boundary - high likelihood of downbeat
301 isDownbeat = true;
302 } else if (nearMeasureBoundary && strongAccent) {
303 // Early/late downbeat with strong accent
305 } else if (strongAccent && mBeatsSinceDownbeat == 0) {
306 // Strong accent on first beat (might be downbeat)
308 }
309
310 return isDownbeat;
311}
bool isDownbeat() const
Returns true if downbeat was detected this frame.
Definition downbeat.h:71
deque< float > mBeatAccents
Definition downbeat.h:127
shared_ptr< Beat > mBeatDetector
Definition downbeat.h:104
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
Definition math.h:75
constexpr enable_if< is_fixed_point< T >::value, T >::type abs(T x) FL_NOEXCEPT
constexpr enable_if< is_fixed_point< T >::value, T >::type clamp(T x, T lo, T hi) FL_NOEXCEPT

References fl::abs(), fl::clamp(), isDownbeat(), mAccentThreshold, fl::max(), mBeatAccents, mBeatDetector, mBeatsPerMeasure, mBeatsSinceDownbeat, mConfidence, mConfidenceThreshold, and mLastDownbeatTime.

Referenced by update().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: