Rust Core (dj-assistant-core)
Relevant source files
The following files were used as context for generating this wiki page:
Rust Core (dj-assistant-core) serves as the performance-critical engine for the DJ Assistant application. It operates as a Tauri-free library to ensure high testability across different toolchains without requiring a graphical environment or WebView2 dependencies. The core manages library scanning, file fingerprinting, metadata extraction, and local data persistence via SQLite.
Rust Core coordinates the transformation of raw audio files into structured library records. It handles I/O operations, utilizes BLAKE3 for content-addressed deduplication, and implements custom parsers for audio containers that lack standard metadata support in high-level libraries. It acts as the bridge between the high-level UI commands and the low-level audio analysis engine.
Sources: README.md:214-230, CHANGELOG.md:129-134, apps/desktop/src-tauri/Cargo.toml:16-18
Core Architecture and Components
The architecture follows a modular design where library management is decoupled from audio signal processing. The dj-assistant-core crate focuses on library integrity and metadata, while dj-assistant-analysis handles DSP and ONNX inference.
Component Responsibilities
| Component | Responsibility | Primary Files/Modules |
|---|---|---|
| Scanner | Discovers audio files and manages the import pipeline. | scanner.rs, dedup.rs |
| Metadata Engine | Extracts tags, handles fallbacks, and manages artwork. | metadata.rs |
| Container Parsers | Custom logic for RIFF (WAV), AIFF, and MP3 headers. | riff.rs, mp3.rs, aiff.rs |
| Data Layer | Manages SQLite connection, WAL mode, and migrations. | db.rs |
| Fingerprinter | Computes BLAKE3 hashes for content-based deduplication. | blake3 (dependency) |
Sources: CHANGELOG.md:129-134, apps/desktop/src-tauri/src/lib.rs:1-10, README.md:237-250
Library Scan Pipeline
The scanner executes a multi-stage pipeline to ingest tracks. It first discovers files, computes a hash to prevent duplicates, extracts embedded metadata, and finally commits the record to the database.
The diagram above shows the sequential logic of the file ingestion process within the core.
Sources: README.md:144-180, CHANGELOG.md:139-142, crates/core/src/metadata.rs:163-180
Metadata Extraction and Normalization
The metadata engine provides a forgiving extraction process. If tag parsing fails, the system defaults to filename-based titles and "Unknown Artist" labels to prevent scan interruptions. It utilizes audiotags as a primary backend with custom fallbacks for specific frames and containers.
Extraction Logic
Metadata extraction follows a tiered approach to ensure maximum data recovery:
- Primary Reader: Attempts to read tags using the
audiotagslibrary. - Fallback Reader: consults specific container parsers (e.g.,
id3for AIFF/WAV) if the primary reader fails. - Extras Processor: Extracts non-standard tags like BPM, Camelot keys, and star ratings that high-level libraries often omit.
Sources: crates/core/src/metadata.rs:10-18, crates/core/src/metadata.rs:163-230
Camelot Key Mapping
The core includes a deterministic mapping system to convert classical key names (e.g., "A minor") into Camelot codes (e.g., "8A"). This supports harmonic mixing by standardizing various tagging conventions.
This flow illustrates how raw textual key data is converted into the Camelot notation used for DJ sequencing.
Sources: crates/core/src/metadata.rs:434-480
Embedded Artwork Management
Rust Core handles embedded cover art by caching it on disk. To optimize storage, it uses content-addressed hashing.
- Hash Generation: Computes a BLAKE3 digest of the raw image bytes.
- Deduplication: Identical images across multiple tracks share a single cache file.
- Format Normalization: Maps MIME types (e.g.,
image/jpeg) to standard extensions for local file storage.
Sources: crates/core/src/metadata.rs:485-515
Container and Duration Parsing
Because standard libraries often fail to report accurate durations for WAV and MP3 files, Rust Core implements custom header parsers.
RIFF/WAVE Duration
The riff.rs module calculates duration by walking the RIFF chunk tree. It avoids loading the full audio payload by identifying the fmt chunk for the byte rate and the data chunk for the total byte size.
- Calculation:
duration_ms = (data_size * 1000) / byte_rate - Validation: Verifies chunk sizes against actual file length to handle corrupt or truncated files gracefully.
Sources: crates/core/src/riff.rs:1-80
MP3 and AIFF Support
- MP3: Reads duration from Xing, Info, or VBRI headers. It falls back to a CBR (Constant Bit Rate) estimate if headers are missing.
- AIFF: Extracted via a custom parser that reads
numSampleFramesand the 80-bit extendedsampleRatefrom theCOMMchunk.
Sources: CHANGELOG.md:143-145, CHANGELOG.md:220-230
Data Persistence
The core utilizes SQLite in Write-Ahead Logging (WAL) mode for high-performance local storage. The schema ensures data integrity through strict foreign key enforcement and unique constraints on workspace/hash pairs.
Database Interaction Flow
Tauri commands interact with the core's database layer to retrieve and filter track data.
This diagram demonstrates the flow of data from the persistence layer to the user interface.
Sources: apps/desktop/src-tauri/src/lib.rs:25-50, CHANGELOG.md:12-20, CHANGELOG.md:246-250
Summary of Key Features
| Feature | Technical Implementation |
|---|---|
| Deduplication | Content-based hashing using BLAKE3. |
| Tagging | Forgiving extraction with standard and "Extra" tag support. |
| Performance | Multi-threaded scanning and SQLite WAL mode. |
| Portability | Tauri-free crates/core for CLI and desktop use. |
| Integrity | Deterministic duration parsing for WAV/AIFF/MP3. |
Sources: README.md:214-230, CHANGELOG.md:129-150, crates/core/src/metadata.rs:163-180
The Rust Core provides a stable, high-performance foundation for the DJ Assistant project. By centralizing library management and metadata logic in a standalone crate, it ensures that the critical path of file ingestion remains reliable and platform-independent.