Track Similarity Engine
Relevant source files
The following files were used as context for generating this wiki page:The Track Similarity Engine ranks music library tracks based on their mix-compatibility with a specific "seed" track. It operates entirely locally and offline, utilizing metadata stored in the SQLite database to calculate compatibility scores without performing real-time audio analysis or network requests. The engine serves as a core component for the "find similar tracks" feature and provides deterministic ordering for set sequencing.
Sources: crates/core/src/similarity.rs:1-16, README.md:143-149
Core Architecture and Data Flow
The engine follows a multi-tier architecture where the frontend initiates a request, the Tauri IPC layer fetches features from the database, and the Rust core crate executes the scoring logic.
The sequence diagram above illustrates the request-response lifecycle from a user selecting a track to the UI displaying mix-compatible results.
Sources: apps/desktop/src/App.tsx:389-410, apps/desktop/src-tauri/src/commands.rs:360-405, crates/core/src/similarity.rs:149-160
Scoring Logic and Weights
The similarity score is a blended, renormalised weighted sum in the range of 0.0 to 1.0. If metadata is missing for a specific signal on either the seed or candidate track, the engine skips that signal and redistributes the weights among the remaining available signals.
Weight Distribution
| Signal | Weight | Logic Description |
|---|---|---|
| BPM | 45% | Decays from 1.0 (identical) to 0.0 at an 8% relative difference. |
| Key | 35% | Calculated using circular distance on the Camelot wheel (0 to 6). |
| Genre | 10% | Case-insensitive exact string match. |
| Duration | 10% | Decays from 1.0 (identical) to 0.0 at a 25% relative difference. |
Sources: crates/core/src/similarity.rs:8-14, crates/core/src/similarity.rs:113-146
Musical Key Compatibility
Key similarity uses the Camelot wheel to determine harmonic compatibility. The distance is measured between 0 (identical) and 6 (opposite side of the wheel).
- Distance 0: Identical Camelot code (e.g., 8A to 8A).
- Distance 1: Adjacent numbers (8A to 9A) or relative major/minor (8A to 8B).
- Distance 2: Diagonal shift (8A to 9B), often used for energy-boost mixing.
Sources: crates/core/src/similarity.rs:56-83, crates/core/src/similarity.rs:125-135
The flowchart describes the conditional logic applied to each candidate track during the scoring process.
Sources: crates/core/src/similarity.rs:113-146
Data Structures and IPC Models
The engine uses specific structures to pass data across the Rust/TypeScript boundary, ensuring that all UI "reason chips" (e.g., "+1.2% BPM apart") are generated by the core logic for consistency.
Track Features
Used by the core logic to represent the minimum data required for scoring.
pub struct TrackFeatures {
pub id: String,
pub bpm: Option<f64>,
pub key_camelot: Option<String>,
pub genre: Option<String>,
pub duration_ms: i64,
}
Sources: crates/core/src/similarity.rs:20-27
IPC Models
Defined in the Tauri layer to handle communication between the frontend and the core.
| Struct | Field | Type | Description |
|---|---|---|---|
| FindSimilarTracksRequest | track_id | String | The seed track ID. |
limit | Option<i64> | Max results (clamped 1-50). | |
| SimilarTrackResult | track | TrackSummary | The metadata of the similar track. |
score | f64 | 0.0 to 1.0 compatibility score. | |
reasons | Vec<String> | Human-readable chips for the UI. |
Sources: apps/desktop/src-tauri/src/models.rs:188-213
Integration and UI Presentation
The similarity engine is triggered when a user selects a track in the library. Results are displayed in an inspector drawer that provides real-time feedback on why tracks were ranked.
- Selection: When
selectedTrackchanges inApp.tsx, thefindSimilarTracksAPI is called. - Display: Results are rendered as a list showing the title, artist, score percentage, and reason chips.
- Interaction: Users can click a similar track in the drawer to pivot the inspection to that new seed track.
Sources: apps/desktop/src/App.tsx:389-410, apps/desktop/src/App.tsx:825-866
Implementation Details
BPM Decay Calculation
The BPM similarity utilizes a relative difference calculation to ensure that tracks with widely different base tempos (e.g., 70 BPM vs 174 BPM) do not rank together unless their difference is within an 8% mixable range.
pub fn bpm_similarity(a: Option<f64>, b: Option<f64>) -> Option<f64> {
let (a, b) = (a?, b?);
if !a.is_finite() || !b.is_finite() || a <= 0.0 || b <= 0.0 {
return None;
}
let diff = (a - b).abs() / a.max(b);
Some((1.0 - diff / 0.08).clamp(0.0, 1.0))
}
Sources: crates/core/src/similarity.rs:93-100
Deterministic Tie-Breaking
When two tracks result in the same similarity score, the engine uses the track_id as a tie-breaker to ensure the list remains deterministic across refreshes.
scored.sort_by(|a, b| {
b.score
.partial_cmp(&a.score)
.unwrap_or(std::cmp::Ordering::Equal)
.then_with(|| a.track_id.cmp(&b.track_id))
});
Sources: crates/core/src/similarity.rs:168-173
The Track Similarity Engine provides a critical automation layer for DJ set preparation by quantifying harmonic and rhythmic compatibility. By performing these calculations locally on database-resident metadata, it maintains the project's local-first and privacy-focused principles while accelerating the mechanical aspects of music discovery.