Skip to content

Architecture

This page is the working map of the Rast codebase: the crates, the Tauri command surface, the data flow from import to playback, and where each piece of state lives.

Stack overview

Rast is a Tauri v2 desktop app. The backend is a Rust workspace under rust/ plus the Tauri shell under src-tauri/. The frontend is Svelte 5 + TypeScript built by Vite. Heavy lifting (source separation, chord/beat/note inference) runs on ONNX models via the ort crate; the CLI shells out to ffmpeg for decoding and yt-dlp for YouTube ingest. Persistent state lives in a single SQLite database at ~/Rast/library.db plus a hash-keyed cache directory at ~/Rast/cache/<hash>/.

Workspace layout

The Cargo workspace is declared in rust/Cargo.toml:1. Members:

CratePathResponsibility
rast-theoryrust/rast-theory/Pure music theory: 11 dromoi, chord labels, enharmonic spelling, bar-grid helpers. Zero I/O.
rast-dbrust/rast-db/SQLite schema + queries (rusqlite, bundled). Schema version 7 — rust/rast-db/src/lib.rs:17.
rast-analysisrust/rast-analysis/DSP + ML: CQT, chroma, beat tracking (beat_this), chord inference (CREMA + BTC), Demucs/Spleeter separation, key detection, basic-pitch note transcription.
rast-corerust/rast-core/Pipeline orchestration, ONNX ModelManager, cache I/O, import helpers, default paths.
bench-pipelinerust/bench-pipeline/CLI binary that runs the full end-to-end pipeline against a single audio file.
bench-key-from-chordsrust/bench-key-from-chords/CLI binary that re-runs only detect_key_refined against a precomputed chord JSON, used to iterate on the key-detection algorithm without paying for separation.

Each library crate's public surface is its lib.rs — see rust/rast-theory/src/lib.rs:1, rust/rast-db/src/lib.rs:1, rust/rast-analysis/src/lib.rs:1, rust/rast-core/src/lib.rs:1.

The Tauri shell lives in src-tauri/src/. Its lib.rs registers tracing, opens the library DB on startup to clear stale rows, manages two app states (ActiveJobs, SimilarityCache), and registers all #[tauri::command] handlers — see src-tauri/src/lib.rs:25.

Crate dependency graph

              ┌──────────────────────────────────────┐
              │ src-tauri (binary, Tauri v2 commands) │
              └────────────────┬─────────────────────┘

                    ┌──────────▼──────────┐
                    │      rast-core      │   pipeline, cache, paths,
                    │                     │   ONNX ModelManager, import
                    └─┬─────────┬───────┬─┘
                      │         │       │
        ┌─────────────▼─┐   ┌───▼────┐ ┌▼──────────┐
        │ rast-analysis │   │ rast-db│ │rast-theory│
        │  (ONNX, DSP)  │   │(SQLite)│ │(pure music│
        └────────┬──────┘   └────────┘ │  theory)  │
                 │                     └───────────┘
                 └────────► rast-theory  (chords, scales)

bench-pipeline           ─► rast-core, rast-analysis, rast-theory
bench-key-from-chords    ─► rast-analysis, rast-theory, rast-core (proc only)

rast-theory has no dependencies on the others — it is a pure-data crate. Everything that touches audio buffers, ONNX, or SQLite goes through rast-analysis, rast-db, or rast-core.

Data flow: import → separate → analyse → playback

                ┌──────────┐  ffmpeg                ┌────────────┐
 audio file ───▶│  Decode  │───────────────────────▶│  PCM f64   │
   or URL       │ (44100Hz │                        │ (L, R)     │
                │  stereo) │                        └─────┬──────┘
                └──────────┘                              │
                      │                          ┌───────▼────────┐
              SHA-256 │                          │   ONNX models  │
              (16 hex)│                          │ (beat_this,    │
                      │                          │  CREMA / BTC,  │
                      ▼                          │  Demucs /      │
              ┌───────────────┐                  │  Spleeter,     │
              │  library.db   │                  │  basic_pitch)  │
              │ INSERT songs  │                  └────────┬───────┘
              └───────┬───────┘                           │
                      │                                   │
                      ▼                                   │
            ┌──────────────────────────────────┐          │
            │  AnalysisPipeline.run_analysis   │◀─────────┘
            │  (rast-core::pipeline)           │
            │                                  │
            │  1. separation (Demucs|Spleeter) │
            │  2. beats || chords || notes     │  (parallel, std::thread::scope)
            │  3. key detection (refined)      │
            │  4. chord-snap to beat grid      │
            │  5. beat-synchronous chroma      │
            └──┬───────────────┬───────────────┘
               │               │
               ▼               ▼
        ┌──────────┐    ┌──────────────────┐
        │  cache/  │    │   library.db     │
        │ <hash>/  │    │  UPDATE analysis │
        │  *.flac  │    │  analysis_json,  │
        │ beat_chr │    │  key_*, bpm,     │
        └──────────┘    └─────┬────────────┘


                     ┌────────────────────┐
                     │  Playback (Svelte) │
                     │  WebAudio +        │
                     │  SoundTouch worklet│
                     │  reads vocals.flac │
                     │  + instrumental    │
                     │  via convertFileSrc│
                     └────────────────────┘

The pipeline structure and parallel scope are in rust/rast-core/src/pipeline.rs:316. Stage weights (used to map per-stage progress onto a 0..1 overall percent the frontend renders) live at rust/rast-core/src/pipeline.rs:111. The Tauri asset-protocol scope $HOME/Rast/cache/** is whitelisted in src-tauri/tauri.conf.json so the WebView can fetch vocals.flac / instrumental.flac directly without a Rust streaming server.

Tauri command surface

All commands are registered in the invoke_handler! block at src-tauri/src/lib.rs:106. Grouped by file:

library.rs — library CRUD

CommandWhat it does
list_songsReturns all songs joined with their analysis row, newest first. src-tauri/src/library.rs:23.
delete_songRefuses if a job is active or status is processing; otherwise removes the row and the cache dir. src-tauri/src/library.rs:60.
rename_songTrims, rejects empty, updates songs.title. src-tauri/src/library.rs:109.

analysis.rs — per-song analysis DTOs and chord edits

CommandWhat it does
get_song_analysisReads analysis_json, snaps chords to the beat grid (idempotent on already-snapped data), returns an AnalysisDto. src-tauri/src/analysis.rs:72.
update_chordEdits a single chord cell; snapshots original_chords_json on first edit. src-tauri/src/analysis.rs:221.
revert_chordRestores one cell from the original snapshot. src-tauri/src/analysis.rs:294.
save_chordsReplaces the full chord array. src-tauri/src/analysis.rs:345.
restore_original_chordsFull revert from the snapshot. src-tauri/src/analysis.rs:383.
save_count_inPersists count-in bars (0..=8). src-tauri/src/analysis.rs:157.
save_pitchPersists per-song pitch shift (-24..=24 semitones). src-tauri/src/analysis.rs:172.

import.rs — ingest

CommandWhat it does
import_fileHash → ffmpeg decode → run AnalysisPipeline → write cache + DB row. Emits import://progress, import://done, import://error. src-tauri/src/import.rs:231.
import_youtubeDetects yt-dlp (standalone or python -m yt_dlp), downloads as mp3, then takes the file-import path. UTF-8-safe for Greek titles. src-tauri/src/import.rs:590.

reprocess.rs — re-run separation/analysis on imported songs

CommandWhat it does
reprocess_songscope = "analysis" reuses cached stems; scope = "stems" invalidates and rebuilds them. Emits `reprocess://progress
get_backend_availabilityProbes installed ONNX files; returns { demucs, spleeter, btc_chord }. Used by the frontend to hide unavailable options. src-tauri/src/reprocess.rs:521.

playback.rs — stem URL resolution

CommandWhat it does
get_stem_urlsReturns absolute paths to vocals.flac and instrumental.flac for the song's hash. The frontend wraps these with convertFileSrc to get an asset-protocol URL the WebView can stream. src-tauri/src/playback.rs:16.

similarity.rs — beat-synchronous chroma similarity

CommandWhat it does
compute_beat_chromaLazy-loads the on-disk beat_chroma.bin for a song into the in-memory SimilarityCache. src-tauri/src/similarity.rs:35.
find_similar_rangesQueries the cached matrix for ranges similar to a beat range. src-tauri/src/similarity.rs:84.

log_bridge.rs

CommandWhat it does
log_from_frontendRoutes Svelte logger lines (level, target, message) into the shared tracing subscriber so frontend events land in the same log file as backend events. src-tauri/src/log_bridge.rs:7.

State storage

WhereWhatNotes
~/Rast/library.db (songs table)id, hash, title, source_type/path/url, duration_seconds, status, error_message, imported_atSchema in rust/rast-db/src/lib.rs:106. Status sweep on startup at src-tauri/src/lib.rs:92.
~/Rast/library.db (analysis table)key_primary, key_root_pc, key_scale, key_confidence, bpm, analysis_json, user_chords_json, count_in_bars, original_chords_json, pitch_semitonesSchema in rust/rast-db/src/lib.rs:119. Includes legacy-column purge (rebuilds the table when stale columns are present) — rust/rast-db/src/lib.rs:184.
analysis_json (TEXT blob inside analysis)full AnalysisOutput: chords, beat_times, downbeat_times, key result, stage timingsType at rust/rast-core/src/pipeline.rs:58. The beat_chroma field is #[serde(skip)]'d out of this blob and persisted separately to disk.
~/Rast/cache/<hash>/original.flacLossless stereo mix, ffmpeg-converted from sourceRequired precondition for any reprocess. src-tauri/src/reprocess.rs:264.
~/Rast/cache/<hash>/vocals.flac, instrumental.flacSeparation outputsBoth must be present for Scope::Analysis reprocess. Tauri asset-protocol scope $HOME/Rast/cache/** makes them addressable from the WebView.
~/Rast/cache/<hash>/beat_chroma.binPer-beat chroma matrix for similarity searchLazy-loaded into SimilarityCache (src-tauri/src/similarity.rs:23).
~/Rast/logs/rast.logSingle per-run log, truncated on startupPath at rust/rast-core/src/paths.rs:26.
In-memory: ActiveJobs (Tauri state)Per-song reprocess locksrc-tauri/src/jobs.rs:163.
In-memory: SimilarityCache (Tauri state)HashMap<song_id, Vec<[f64; 12]>> of beat-chroma matricessrc-tauri/src/similarity.rs:23.
Svelte stores (browser memory)UI stateSee below.

Frontend structure

src/main.ts mounts App.svelte which composes the high-level layout. Top of src/App.svelte:1 shows the card composition — Titlebar, Sidebar (library), SongInfo, TimelineCard, ChordGridCard, TransportBar, ControlsPanel, plus dialogs (Toast, ImportCard, ShortcutsDialog).

Cards (src/lib/)

ComponentRole
Titlebar.svelteCustom frameless-window titlebar (the Tauri window has decorations: false).
Sidebar.svelteLibrary list and search; emits song selection.
SongInfo.svelteTitle, key, BPM, status badge for the selected song.
TimelineCard.svelteBeat-aligned waveform + chord blocks + similarity highlights.
ChordGridCard.svelteBar-grid chord editor; the primary surface for edit-mode actions.
ChordPicker.svelteModal/popover for picking a new chord during edits.
ControlsPanel.svelteVocal/instrumental volume, pitch shift, speed, metronome.
TransportBar.sveltePlay/pause/seek + position display.
ImportCard.svelteFile-picker / YouTube URL form, listens to import://* events.
Toast.svelte, ShortcutsDialog.svelte, SongActionsMenu.svelte, Titlebar.svelteAuxiliary surfaces.

Stores (src/lib/stores/)

StoreHoldsNotes
selection.tsselectedSongId, the analysis readable derived from itSingle source of truth for which song is loaded. src/lib/stores/selection.ts:34.
transport.tsisPlaying, positionSec, durationSec, loading, errorDrives a requestAnimationFrame loop while playing. src/lib/stores/transport.ts:29.
controls.tsvocal/instrumental volume, pitch (persisted), speed, metronomeSubscribes to its own changes to push values into the audio engine, and persists pitch via save_pitch. src/lib/stores/controls.ts:32.
editMode.tseditMode: boolean toggleGates Ctrl+Z / Ctrl+C / split / paste shortcuts in App.svelte.
chordHistory.ts, chordMutations.ts, chordSelection.ts, chordClipboard.tsUndo/redo stack, range selection, copy/cut/paste of chord cellsPure-TS music ops live next door in src/lib/music/.
viewMode.tsGrid vs timeline view
metronome.ts, simplify.tsMetronome tick rate, opt-in dromos-aware chord simplificationThe simplification toggle is intentionally client-side — see the comment at rust/rast-core/src/pipeline.rs:903.
import.ts, reprocess.rs (sic)Active job state for the import / reprocess UIListens for import://progress and reprocess://progress events.

Audio engine

src/lib/audio/engine.ts is a singleton AudioContext with a SoundTouchNode worklet for pitch/speed and a separate click-scheduler for the metronome. Stems load via convertFileSrc(...) against the asset-protocol scope, never via a Rust HTTP server. The worklet has a measured 100 ms latency; the click track is shifted forward by SOUNDTOUCH_LATENCY_SEC to keep clicks aligned with what the user hears — see src/lib/audio/engine.ts:35.

See also