BPM Detection
Tempo (BPM) detection for audio tracks.
This module provides tempo estimation using librosa’s beat tracking algorithms, with genre-aware corrections for electronic music production.
Example
>>> import numpy as np
>>> from mixref.detective.tempo import detect_bpm
>>>
>>> # Generate 120 BPM test signal
>>> sr = 44100
>>> audio = np.random.randn(2, sr * 10) # 10 seconds stereo
>>>
>>> result = detect_bpm(audio, sr)
>>> print(f"BPM: {result.bpm:.1f} (confidence: {result.confidence:.2f})")
BPM: 120.0 (confidence: 0.95)
- class mixref.detective.tempo.TempoResult[source]
Bases:
objectResult of tempo detection.
- confidence
Confidence score from 0.0 to 1.0. Higher values indicate more reliable detection.
- Type:
- onset_strength
Raw onset strength envelope used for detection. Useful for debugging or visualization.
- Type:
Any | None
- __init__(bpm, confidence, onset_strength=None)
- mixref.detective.tempo.detect_bpm(audio, sample_rate, start_bpm=120.0, include_onset_strength=False)[source]
Detect tempo (BPM) of an audio signal.
Uses librosa’s beat tracking algorithm with onset detection. Returns BPM and confidence score.
- Parameters:
audio (Any) – Audio signal as numpy array. Shape: (samples,) for mono or (samples, channels) for multi-channel. Also accepts (channels, samples) format. Multi-channel audio will be converted to mono for analysis.
sample_rate (int) – Sample rate in Hz (e.g., 44100).
start_bpm (float) – Initial tempo estimate in BPM for the algorithm. Default: 120.0 (common for electronic music).
include_onset_strength (bool) – If True, include onset strength envelope in result. Useful for visualization or debugging. Default: False to save memory.
- Returns:
TempoResult with detected BPM, confidence score, and optionally onset data.
- Raises:
ValueError – If audio is empty or invalid.
- Return type:
Example
>>> import numpy as np >>> from mixref.detective.tempo import detect_bpm >>> >>> # Synthetic 140 BPM techno kick pattern >>> sr = 44100 >>> duration = 8 # seconds >>> audio = np.zeros(sr * duration) >>> >>> # Add kicks every 0.428 seconds (140 BPM) >>> kick_interval = int(60 / 140 * sr) >>> for i in range(0, len(audio), kick_interval): ... if i + 100 < len(audio): ... audio[i:i+100] = 0.8 >>> >>> result = detect_bpm(audio, sr) >>> assert 135 < result.bpm < 145 # Should be near 140