BPM & Beat Grid Analysis
Relevant source files
The following files were used as context for generating this wiki page:
BPM and Beat Grid Analysis identifies the tempo and rhythmic structure of audio tracks to enable professional DJ preparation. The system performs local, on-device computation of Beats Per Minute (BPM), downbeat locations, and a comprehensive beat grid without modifying the source files. This analysis serves as the foundation for downstream features like phrase segmentation and automated cue placement.
Sources: README.md:143-149, crates/analysis/src/bpm.rs:1-12
Analysis Pipeline Architecture
The analysis process follows a deterministic inference path that transforms decoded audio into a structured BeatGrid. The engine uses onset-based tempo induction to establish periodicities.
Core Processing Steps
- Preparation: Decodes audio to mono PCM and resamples to the target analysis rate (default 44.1 kHz).
- Onset Detection: Generates a spectral-flux onset envelope using a Short-Time Fourier Transform (STFT) with a rectangular window.
- Periodicity Search: Performs autocorrelation on the onset envelope to find the dominant beat period.
- Metrical Resolution: Scores candidates (0.5x, 1.0x, 2.0x of the period) against onset alignments to resolve metrical levels.
- Phase Search: Slides the grid to maximize onset alignment, reconstructing the downbeat ($t_0$).
- Result Generation: Produces a
BeatGridcontaining the BPM, timestamps, and confidence scores.
Sources: crates/analysis/src/bpm.rs:12-23, crates/analysis/src/bpm.rs:104-120
Processing Flow Diagram
The following diagram illustrates the data flow from raw audio decoding to the final persistence of analysis results in the local database.
The system is designed for high performance, targeting a processing speed of less than 3 seconds per track.
Sources: crates/analysis/src/bpm.rs:29-33, apps/desktop/src-tauri/src/analysis.rs:104-125
Key Data Structures
BeatGrid
The BeatGrid struct stores the results of the analysis, including timing information and engine metadata.
| Field | Type | Description |
|---|---|---|
bpm | f32 | Detected tempo in beats per minute. |
beats | Vec<f64> | Ascending timestamps of each beat in seconds. |
first_beat_time | f64 | Time of the first beat (downbeat). |
bar_duration | f64 | Duration of one bar in seconds ($240 / BPM$ for 4/4). |
confidence | f32 | Reliability score from 0.0 to 1.0. |
method | BpmMethod | Engine used: OnsetAutocorr or Onnx. |
pipeline_version | &str | Semantic version of the analysis logic. |
Sources: crates/analysis/src/bpm.rs:56-72
BpmOptions
Callers configure the analysis behavior using the BpmOptions structure.
| Option | Default | Description |
|---|---|---|
sample_rate | 44,100 Hz | Rate for mono resampling before STFT. |
frame_size | 1024 | STFT window size (must be power of two). |
hop_size | 512 | STFT hop size (approx. 23ms frames). |
min_bpm | 60.0 | Minimum tempo for search range. |
max_bpm | 200.0 | Maximum tempo for search range. |
target_peak | 0.9 | Peak normalization level before analysis. |
Sources: crates/analysis/src/bpm.rs:43-52, crates/analysis/src/bpm.rs:81-92
Persistence and Status Management
Analysis results are persisted to the tracks table in the local SQLite database. The system uses a composite analysis_version string to track algorithm changes and trigger re-analysis when necessary.
Database Schema (Analysis Fields)
CREATE TABLE tracks (
-- ... other fields ...
bpm REAL,
key_camelot TEXT,
key_classical TEXT,
analysis_status TEXT NOT NULL DEFAULT 'pending',
analysis_version TEXT,
phrase_confidence REAL,
vocal_presence INTEGER DEFAULT 0,
updated_at TEXT NOT NULL DEFAULT (datetime('now'))
);
Sources: apps/desktop/src-tauri/migrations/001_initial_schema.sql:28-40
Status Classification Logic
The classify_analysis_status function determines the state of a track based on the results returned by the engine.
- complete: All signals (BPM, Key, Phrases) are present and confidence is above thresholds.
- needs_review: Analysis succeeded but produced low confidence scores or missing fields.
- pending: The track is newly imported and hasn't been processed.
- failed: A hard error occurred during decoding or inference.
Sources: apps/desktop/src-tauri/src/analysis.rs:24-60, apps/desktop/src-tauri/src/analysis.rs:168-205
Analysis Execution Flow
The analysis is executed via a background job queue to prevent UI blocking.
UI Representation and Formatting
The desktop application formats analysis data for display in the library view using pure TypeScript helpers.
- BPM: Rounded to one decimal place only if the value is not an integer.
- Duration: Formatted as
m:ss(e.g.,3:05). Unknown durations default to--:--. - Status Labels:
complete-> "Analyzed"needs_review-> "Needs review"pending-> "Not analyzed"failed-> "Failed"
Sources: apps/desktop/src/lib/library.ts:54-59, apps/desktop/src/lib/library.ts:167-172, apps/desktop/src/lib/library.ts:182-186
Testing and Golden Fixtures
The system uses a "Golden Fixture" harness for regression testing. Synthetic audio fixtures are generated with specific, known properties to validate the accuracy of the BPM and Key detectors.
Synthesis Parameters for Tests
| Layer | Parameters | Purpose |
|---|---|---|
| BPM Layer | 800 Hz click, 5ms decay, 20ms burst | Dominant spectral-flux for onset detection. |
| Bass Layer | Root note frequency, 0.08 amplitude | Chroma profile for key detection. |
| Noise | $\pm 0.02$ white noise | Rhythmic/spectral richness simulation. |
Sources: scripts/make-analysis-fixtures.py:16-33, fixtures/audio/analysis/analysis_expected.json:1-10
Analysis is considered accurate within a tolerance of 2.0 BPM for the synthetic fixtures.
Sources: fixtures/audio/analysis/analysis_expected.json:7
BPM and Beat Grid Analysis provides the mechanical foundation for automated DJ preparation. By locally extracting rhythmic metadata and establishing a reliable grid, the system enables deterministic phrase detection and non-destructive cue placement while maintaining library integrity through versioned persistence.