Skip to main content

max / audiofiles

Update path deps for ~/Code directory layout, add Linux drag stub Move project docs into repo. Update Cargo.toml path dependencies for new Shared/ location. Add Linux fallback in begin_drag. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-03-30 02:26 UTC
Commit: 547ecd721af21ea0a1d95f6b9cda98a13c492027
Parent: c565538
8 files changed, +1224 insertions, -3 deletions
M Cargo.toml +2 -2
@@ -44,5 +44,5 @@ reqwest = { version = "0.12", default-features = false, features = ["json", "nat
44 44 semver = "1"
45 45 open = "5"
46 46 rayon = "1.10"
47 - docengine = { path = "../docengine" }
48 - tagtree = { path = "../tagtree" }
47 + docengine = { path = "../../Shared/docengine" }
48 + tagtree = { path = "../../Shared/tagtree" }
@@ -138,4 +138,9 @@ pub fn begin_drag(files: &[DragFile]) -> bool {
138 138 DRAG_ACTIVE.store(false, Ordering::Release);
139 139 result
140 140 }
141 + #[cfg(not(any(target_os = "macos", target_os = "windows")))]
142 + {
143 + DRAG_ACTIVE.store(false, Ordering::Release);
144 + false
145 + }
141 146 }
@@ -5,7 +5,7 @@ edition.workspace = true
5 5
6 6 [dependencies]
7 7 audiofiles-core = { workspace = true }
8 - synckit-client = { path = "../../../synckit-client" }
8 + synckit-client = { path = "../../../../Shared/synckit-client" }
9 9 rusqlite = { workspace = true }
10 10 parking_lot = { workspace = true }
11 11 tokio = { workspace = true }
@@ -0,0 +1,158 @@
1 + # audiofiles Architecture
2 +
3 + ## System Overview
4 +
5 + audiofiles is a standalone desktop sample manager built with egui. Samples are stored in a content-addressed blob store keyed by SHA-256 hash, and organized through a virtual filesystem (VFS) that maps user-visible directory trees to underlying content hashes. The database (SQLite) tracks metadata, analysis results, tags, collections, and VFS structure. The app provides cpal audio output, system tray integration, and cloud sync via SyncKit.
6 +
7 + ## Workspace Layout
8 +
9 + The project is a 5-crate Rust workspace (plus an optional training binary):
10 +
11 + ### audiofiles-core
12 +
13 + Pure data layer with no UI or async dependencies. Owns the SQLite database schema (versioned migrations), content-addressed `SampleStore`, VFS tree operations, tag management, search/filter, smart folders, audio analysis pipeline (BPM, key, loudness, spectral, classification, loop detection), fingerprinting for duplicate detection, similarity search, instrument zone definitions, and export logic including device profile support. All operations are synchronous. This crate is the single source of truth for business logic.
14 +
15 + ### audiofiles-browser
16 +
17 + Shared egui UI. Contains the `Backend` trait abstraction, `BrowserState` (the central state machine), the `editor` module (top-level draw dispatch), and all UI panels: file list, detail pane, filter sidebar, toolbar, footer, waveform display, import/export workflow screens, instrument panel, sync panel, overlays, and the theme system. Also owns the `PreviewPlayback` shared audio state and the background import worker.
18 +
19 + ### audiofiles-app
20 +
21 + Desktop binary. Launches an eframe window with the browser UI and a cpal audio output stream for preview playback. Adds a system tray icon, drag-and-drop file import, CLI argument import, and optional SyncKit cloud sync (configured via environment variables). Owns a tokio runtime for async sync operations.
22 +
23 + ### audiofiles-sync
24 +
25 + SyncKit integration layer. Wraps the `synckit-client` SDK to provide `SyncManager`, which the standalone app owns and the browser UI reads for status display. Handles OAuth2 PKCE authentication, E2E encryption setup (ChaCha20-Poly1305 + Argon2), session restore from keychain, push/pull changelog sync, and a background scheduler that runs periodic sync cycles on a tokio runtime.
26 +
27 + ### audiofiles-rhai
28 +
29 + Device plugin runtime. Loads TOML manifests (bundled at compile time and user-supplied from `~/.config/audiofiles/plugins/user/`) describing hardware sampler constraints (supported formats, sample rates, bit depths, channel counts, naming rules). Optionally runs sandboxed Rhai scripts for custom export hooks: `validate_sample`, `transform_filename`, `pre_export`, and `post_export`. The plugin registry resolves device profiles for export configuration.
30 +
31 + ## Backend Trait Abstraction
32 +
33 + The `Backend` trait in `audiofiles-browser::backend` defines every operation that `BrowserState` needs from the data layer: VFS CRUD, tag management, search, smart folders, analysis, similarity, store operations, export, device profiles, config, and long-running background operations (import, analysis, export) with event polling.
34 +
35 + One implementation exists:
36 +
37 + - **DirectBackend** -- wraps `Mutex<Database>` + `SampleStore`, calls core functions directly. Used in the app and tests.
38 +
39 + This trait boundary keeps the browser UI decoupled from the data layer.
40 +
41 + ## Content-Addressed Storage
42 +
43 + Every imported audio file is hashed with SHA-256 and stored at `<data_dir>/samples/<hash>.<ext>`. The `SampleStore` handles:
44 +
45 + 1. **Import**: Stream file through SHA-256 hasher, copy to content-addressed path if not already present, insert metadata row (original name, extension, file size, timestamps) into the `samples` table with `INSERT OR IGNORE` for deduplication.
46 + 2. **Lookup**: Given a hash and extension, resolve to a filesystem path. Hash validation (64 lowercase hex characters) prevents directory traversal.
47 + 3. **Verification**: Re-hash a stored file and compare against the expected hash to detect corruption.
48 + 4. **Removal**: Delete the on-disk blob and the database row (CASCADE handles VFS nodes, tags, analysis, etc.).
49 +
50 + The VFS layer maps user-visible paths to content hashes. A single sample blob can appear in multiple VFS locations without duplication. VFS nodes are either directories (no hash) or sample links (referencing a hash in the `samples` table).
51 +
52 + ## Database Schema
53 +
54 + SQLite with 11 versioned migrations:
55 +
56 + | Table | Purpose |
57 + |-------|---------|
58 + | `samples` | Content-addressed sample metadata (hash PK, original name, extension, size, timestamps) |
59 + | `audio_analysis` | Per-sample analysis results (BPM, key, duration, sample rate, channels, loudness, spectral features, classification) |
60 + | `vfs` | Virtual filesystem roots (name, timestamps, sync_files flag) |
61 + | `vfs_nodes` | Tree nodes (directory or sample link, parent reference, unique name per parent) |
62 + | `tags` | Flat tag strings per sample hash (simplified from original name/value model) |
63 + | `collections` / `collection_members` | Named sample playlists |
64 + | `smart_folders` | Saved search queries (JSON filter per VFS) |
65 + | `waveform_data` | Pre-computed waveform display data (bucketed peaks) |
66 + | `fingerprints` | Audio envelope fingerprints for duplicate detection |
67 + | `user_config` | Key-value user preferences |
68 + | `sync_state` | SyncKit metadata (device ID, cursors, settings) |
69 + | `sync_changelog` | Local change log for push/pull sync, populated by triggers |
70 +
71 + Foreign keys with CASCADE ensure referential integrity. Triggers on `samples`, `vfs`, `vfs_nodes`, `tags`, `audio_analysis`, `collections`, `collection_members`, `smart_folders`, and `user_config` record changes to `sync_changelog` for sync, gated by the `applying_remote` flag to avoid echoing pulled changes back.
72 +
73 + ## Analysis Pipeline
74 +
75 + The analysis system in `audiofiles-core::analysis` decodes audio to mono f32 via Symphonia, then runs configurable stages:
76 +
77 + - **Basic**: Duration, sample rate, channel count -- always computed.
78 + - **Loudness**: Peak dBFS, RMS dB, integrated LUFS (via bs1770).
79 + - **Spectral**: Centroid, flatness, rolloff, zero-crossing rate, bandwidth, centroid variance (via FFT with realfft).
80 + - **Waveform**: Crest factor (peak/RMS ratio), attack time (seconds to 90% of peak via 1ms RMS envelope).
81 + - **BPM**: Onset-based tempo estimation using spectral flux and autocorrelation.
82 + - **Key**: Musical key detection from chroma features.
83 + - **MFCC**: Mel-Frequency Cepstral Coefficients computed from existing STFT magnitudes (26-band mel filterbank, log energy, DCT-II, 13 coefficients). Aggregated as mean + variance across frames (26 features total).
84 + - **Classification**: Two-layer ML system mapping 35-feature vectors (9 spectral/waveform + 26 MFCC) to 16 sample categories (kick, snare, hihat, cymbal, percussion, bass, vocal, synth, pad, fx, noise, music, ambience, impact, foley, texture). Layer 1: rule-based broad classifier detects drums vs non-drum categories. Layer 2: 200-tree Random Forest (7.4MB, embedded via `include_bytes!`, `OnceLock` lazy init) for drum sub-classification (kick/snare/hihat/cymbal/percussion). Confidence scores from RF vote fraction. 94.4% strict accuracy on 4343 labeled drum samples. Training binary in `audiofiles-train` crate (not built by default).
85 + - **Loop detection**: Identifies whether a sample is a seamless loop.
86 + - **Fingerprinting**: Computes an amplitude envelope fingerprint for near-duplicate detection across the library.
87 + - **Tag suggestion**: Generates tag suggestions from analysis results (classification, BPM range, key, duration bracket) with confidence scores and human-readable reasons.
88 +
89 + Analysis runs in a background worker thread using rayon for parallel processing. A configurable analysis cap (`max_analysis_seconds`, default 30s) limits expensive operations (STFT, BPM/key) to the first N seconds of audio while cheap operations (peak/RMS, fingerprint) use the full signal. An `AtomicBool` cancel flag allows interrupting in-flight parallel work.
90 +
91 + ## Export System
92 +
93 + Export converts VFS subtrees into standalone file hierarchies on disk. The pipeline:
94 +
95 + 1. **Collect items**: Walk the VFS subtree, resolving each sample link to its content-addressed blob path and enriching with tags.
96 + 2. **Configure**: User selects format (original, WAV, AIFF), sample rate, bit depth, channel configuration, structure (preserve tree or flatten), naming pattern (with tokens like `{name}`, `{bpm}`, `{key}`, `{class}`), metadata sidecar, and destination directory.
97 + 3. **Device profiles**: Optionally select a hardware sampler profile (from the Rhai plugin registry) which pre-fills format constraints and may run custom hook scripts during export.
98 + 4. **Execute**: Background worker copies or transcodes each file, applying format conversion (via hound + rubato for resampling), channel conversion (mono/stereo), and naming rules. Progress is reported per file.
99 +
100 + ## Instrument Engine
101 +
102 + audiofiles includes a polyphonic sampler instrument for keyboard-driven sample playback. The instrument system spans two crates:
103 +
104 + - **audiofiles-core::instrument** defines `InstrumentConfig` and `AdsrEnvelope` (attack, decay, sustain, release parameters).
105 + - **audiofiles-browser::instrument** owns the runtime state: `InstrumentPlayback` (voice pool, loaded zones, sample rate), `Voice` (per-voice ADSR tracking, fractional position for pitch interpolation), and `LoadedZone` (decoded buffer with root note, key range, velocity range).
106 +
107 + Pitch shifting uses semitone-based ratio calculation: `2^(semitone_offset / 12) * (source_rate / host_rate)`. The fractional sample position advances by this ratio per output sample, with linear interpolation between adjacent source samples.
108 +
109 + ## Theme System
110 +
111 + The browser supports multiple color themes via a 14-slot palette (4 background, 3 foreground, 6 accent, 1 border). Themes are defined as TOML files with `[meta]`, `[background]`, `[foreground]`, `[accent]`, and `[border]` sections. Nine themes are bundled at compile time (Tokyo Night, Catppuccin Mocha/Latte, Dracula, Nord, Ayu Light, Flatwhite, Neobrute, High Contrast). Users can add custom themes to `<config>/audiofiles/themes/` which override bundled themes by ID.
112 +
113 + The active theme is stored in a global `RwLock<ThemeColors>`. Public accessor functions (e.g., `bg_primary()`, `text_secondary()`, `accent_blue()`) read through the lock. Derived colors (row stripes, selection highlights, hover states) are computed by linear interpolation between base palette slots.
114 +
115 + Sample classification colors are hardcoded (not theme-driven) so that semantic categories maintain consistent visual identity across themes.
116 +
117 + ## Audio Thread Model
118 +
119 + The cpal audio output callback runs on a real-time thread where blocking should be avoided. The design uses `parking_lot::Mutex` with `try_lock`:
120 +
121 + - **Preview playback**: The GUI thread decodes audio and writes the buffer into `PreviewPlayback` behind a mutex. The cpal callback calls `try_lock()` -- if the GUI holds the lock (decoding), the callback outputs silence instead of blocking.
122 +
123 + Voice stealing in the instrument engine uses a monotonic age counter to find the oldest voice without sorting.
124 +
125 + ## Sync Integration
126 +
127 + The app optionally connects to MakeNotWork's SyncKit service for cloud sync of sample metadata. `SyncManager` coordinates:
128 +
129 + 1. **Authentication**: OAuth2 PKCE flow via browser redirect.
130 + 2. **Encryption**: E2E encryption with ChaCha20-Poly1305; key derived from user password via Argon2, stored in OS keychain, encrypted copy on server for cross-device setup.
131 + 3. **Push/pull**: Local changes are recorded by SQLite triggers into `sync_changelog`. Push sends unpushed entries to the server; pull applies remote changes with `applying_remote` flag set to suppress trigger re-recording. FK-safe ordering ensures parents are created before children and children are deleted before parents.
132 + 4. **Scheduler**: Background tokio task runs periodic sync cycles (configurable interval, default 15 minutes).
133 +
134 + Synced tables: `vfs`, `samples`, `vfs_nodes`, `audio_analysis`, `tags`, `collections`, `collection_members`, `smart_folders`, `user_config`. Audio file blobs can optionally sync per-VFS (controlled by `vfs.sync_files` flag); metadata always syncs.
135 +
136 + ## Import Pipeline
137 +
138 + Folder import runs in a background thread with its own database connection:
139 +
140 + 1. **Walk**: Recursively scan the source directory, collecting paths with recognized audio extensions (wav, aiff, mp3, flac, ogg).
141 + 2. **Strategy selection**: User chooses flat (all links in current directory), new VFS (preserve directory structure), or merge into existing VFS.
142 + 3. **Import loop**: For each file -- hash, copy to store, create VFS node. Duplicates (name conflicts) are counted but not errors. Progress and errors are reported back to the GUI via channel events.
143 + 4. **Folder tagging**: After import completes, the user can assign comma-separated tags to each imported top-level folder, applied to all samples within.
144 + 5. **Analysis**: Optionally run configurable analysis (loudness, BPM, key, spectral, classification, loop detection, fingerprint, auto-suggest tags) on imported samples.
145 + 6. **Tag review**: If auto-suggest was enabled, the user reviews suggested tags with accept/reject per suggestion before committing.
146 +
147 + Cancellation is checked between files, keeping the UI responsive during large imports.
148 +
149 + ## Key Design Decisions
150 +
151 + - **Content-addressed storage** prevents duplicate blobs regardless of how many VFS locations reference the same sample. SHA-256 provides collision resistance and integrity verification.
152 + - **VFS abstraction** decouples user-visible organization from on-disk storage. Users can create multiple independent directory trees, rename and restructure freely, without moving files.
153 + - **Backend trait** keeps the browser UI decoupled from the data layer, making it testable with mock backends.
154 + - **Synchronous core** keeps the data layer simple and predictable. Async is confined to the sync layer (tokio) and the app.
155 + - **try_lock on audio thread** guarantees real-time safety. The cpal callback never blocks -- it either gets the lock and produces audio, or outputs silence.
156 + - **Strongly-typed IDs** (VfsId, NodeId, SmartFolderId, SampleHash) prevent accidental mixups at compile time. Integer IDs use a macro-generated newtype; SampleHash wraps a hex string.
157 + - **Device plugin system** with Rhai scripting allows hardware sampler export profiles to be extended by users without recompiling, while keeping the sandbox constrained.
158 + - **Trigger-based sync changelog** captures all local mutations automatically without requiring callers to manually record changes, making sync integration transparent to the rest of the codebase.
@@ -0,0 +1,333 @@
1 + # audiofiles -- Code Audit Review
2 +
3 + **Last audited:** 2026-03-28 (sixteenth audit, Run 12 cross-project)
4 + **Previous audit:** 2026-03-26 (fifteenth audit, ML classifier)
5 +
6 + ## Overall Grade: A
7 +
8 + Run 12 cross-project audit. 611 tests. 0 clippy warnings. v0.3.0. Grade A (maintained). ML classifier well-designed (two-layer, 94.4% accuracy). New dependency advisory: rustls-webpki (RUSTSEC-2026-0049).
9 +
10 + ## Scorecard
11 +
12 + | Dimension | Grade | Notes |
13 + |-----------|:-----:|-------|
14 + | Code Quality | A | Clippy clean (0 warnings). No raw SQL in UI layer. Consistent error types. Zero production unwraps in sync/service.rs and theme.rs (verified). 2 guarded unwraps in sidebar.rs (safe but redundant). Disciplined `?` propagation. |
15 + | Architecture | A | 5-crate workspace: core (sync DB/store), browser (state + UI + backend trait), app, sync, rhai. Backend trait cleanly abstracts data access. Core crate has zero UI/async dependencies. |
16 + | Testing | A | 585 tests, all passing. Core: 316+3 e2e, browser: 183, app: 22, sync: 27, rhai: 34. VP-tree: 10 tests (incl. brute-force correctness). FingerprintIndex: 4 tests (incl. index-vs-linear parity). SimilarityIndex: 5 tests (incl. ranking-matches-linear, sorted output). App: updater state machine (8), API key persistence (7), tray icon (2), audio (5). drag_out/ has no tests (platform FFI, manual testing). |
17 + | Security | A | All SQL parameterized. LIKE wildcards escaped. Hash validated. Column whitelists in sync. 17 unsafe blocks in drag_out/ (all platform FFI: objc2 macOS, COM Windows). Drag-out filenames sanitized (path separators + traversal rejected). OTA updater HTTPS-only endpoint but trusts server-provided download URL (opens in browser, no auto-install). applying_remote cleared on startup. |
18 + | Performance | A | try_lock on cpal audio callback. LEFT JOIN enriched queries (no N+1). 7+ indexes. WAL mode. Background workers for import/analysis/export. Pre-computed waveforms. VP-tree indexes for both similarity (O(log n), fixed normalization) and fingerprint search (O(log n) + NCC verification). Sub-millisecond queries at 100K samples. |
19 + | Documentation | A | Every module has //! docs. Public functions have /// docs. SAFETY comments on unsafe blocks. architecture.md and README created. All pub functions now have /// doc comments. |
20 + | Dependencies | A | nih-plug removed (was the only git-pinned dep). All remaining deps use semver. No unused deps. |
21 + | Frontend | A | egui patterns clean. TOML theme system with 17 bundled themes (audiofiles default) + custom loading. "af/" logo in Recursive Mono Bold via embedded font. Waveform painter with click-to-seek. Keyboard shortcuts. try_lock from GUI thread. import_screens split into directory module. file_list.rs (689 LOC, high branch density) is the largest UI file. |
22 + | Type Safety | A | `VfsId`, `NodeId`, `SmartFolderId`, `CollectionId` i64 newtypes via `define_i64_id!` macro. `SampleHash(String)` validated newtype. `NodeType::parse()` returns explicit error. Good domain enums. Typed error hierarchy. |
23 + | Observability | A | `tracing` in all crates with EnvFilter subscriber (env-configurable log levels). 115 `#[instrument(skip_all)]` annotations across 50+ files. Core, rhai, sync, browser all instrumented. Density on par with GO/BB/PoM/MT. |
24 + | Concurrency | A | Correct `try_lock()` on audio thread with silence fallback. Workers in own threads with separate DB connections. `Mutex<Database>` in DirectBackend. `spawn_blocking` for sync DB ops. Single-lock .take() pattern in cancel operations (eliminates double-lock TOCTOU). |
25 + | Resilience | A | Worker Drop with clean Shutdown+join. Per-file error reporting during import. Audio stream failure non-fatal. Sync optional. Tray failure non-fatal. Atomic migrations. CASCADE foreign keys. `applying_remote` cleared on startup (`service.rs:102-110`). |
26 + | API Consistency | A | 47-method Backend trait with uniform `BackendResult<T>`. Consistent naming (list_*, create_*, delete_*, get_*, start_*, cancel_*). Core functions follow consistent patterns. |
27 + | Codebase Size | A | ~23K LOC across 5 crates for ~18 major features + cloud sync + Rhai scripting + native drag-out. Lean with excellent feature density. No dead code. Largest files: sync/service.rs (1,437), browser/backend/direct.rs (983), browser/state/mod.rs (968). |
28 +
29 + ## Module Heatmap
30 +
31 + | Module | Code | Arch | Test | Security | Perf | Docs | Frontend |
32 + |--------|:----:|:----:|:----:|:--------:|:----:|:----:|:--------:|
33 + | audiofiles-core | A | A | A | A | A- | A | n/a |
34 + | audiofiles-browser | A | A | A- | A- | A- | A | A |
35 + | audiofiles-app | A | A- | A- | A- | n/a | A | n/a |
36 + | audiofiles-sync | A | A | A- | A | n/a | A | n/a |
37 + | audiofiles-rhai | A | A | A- | A | n/a | A | n/a |
38 +
39 + ### Cold Spots
40 +
41 + All previous cold spots resolved. Two new LOW findings:
42 +
43 + 1. ~~**applying_remote crash recovery**~~ -- RESOLVED (cleared at top of perform_sync())
44 + 2. ~~**eprintln! in browser crate**~~ -- RESOLVED (migrated to tracing)
45 + 3. ~~**import_screens.rs (668 LOC)**~~ -- RESOLVED (split into directory module)
46 + 4. ~~**No E2E integration tests**~~ -- RESOLVED (3 e2e tests added)
47 + 5. ~~**Theme include_str! paths**~~ -- RESOLVED (themes moved into crate, paths fixed)
48 + 6. **sidebar.rs unwraps (LOW)** -- Lines 133, 135: `.unwrap()` on `collection_rename_target` inside an `if let Some()` guard. Safe (guard ensures value exists) but stylistically redundant. Could use the bound variable directly.
49 + 7. **updater.rs URL trust (LOW)** -- OTA updater stores `update.url` from server response without validation and passes it to `open::that()`. The updater only opens URLs in the browser (no auto-download/install), so risk is limited to the MNW server being compromised. Acceptable for alpha.
50 +
51 + ## Mandatory Surprise
52 +
53 + ### Finding (this audit): sync/service.rs has zero production unwraps
54 +
55 + **Impressive.**
56 +
57 + Previous audit agents flagged sync/service.rs (1,437 lines) as having "15+ unwraps in critical paths." Line-by-line verification found zero production `.unwrap()` calls. All uses are in the `#[cfg(test)]` module (line 806+). Production code consistently uses `?` operator, `unwrap_or()`, `unwrap_or_else()`, and explicit match/if-let patterns. The same verification on theme.rs (877 lines) also found zero production unwraps.
58 +
59 + **Verdict:** Impressive. Error handling discipline across the largest files is exemplary.
60 +
61 + ### Finding (previous): applying_remote flag stuck after crash silently drops changes
62 +
63 + **Resolved.** Flag cleared at top of `perform_sync()` (`service.rs:102-110`).
64 +
65 + ## Strengths
66 +
67 + - **Content-addressed storage is elegant.** SHA-256 dedup, CASCADE deletes, recursive CTE queries. SampleStore + VFS separation enables unlimited virtual hierarchies over one flat blob store.
68 +
69 + - **Backend trait abstraction is well-designed.** 47-method trait surface that maps 1:1 to what BrowserState needs. DirectBackend wraps Mutex<Database> + SampleStore + worker handles. No leaked abstractions.
70 +
71 + - **SyncKit integration is clean.** FK-safe ordering, column whitelists, changelog triggers, blob sync scaffolding. OAuth2 PKCE auth flow properly separated. Scheduler with exponential backoff.
72 +
73 + - **Audio thread safety is correct.** The cpal audio callback uses `try_lock()` on `Mutex<PreviewPlayback>` and falls back to silence. No heap allocations on audio thread.
74 +
75 + - **Rhai scripting is well-sandboxed.** No filesystem access from scripts. Host API exposes only sample metadata. User plugins can override bundled ones. Four hook points with clean compilation/execution.
76 +
77 + - **Core functions live in core.** Sync-only, no async, no UI dependencies. All database queries, analysis, search, export -- everything computation-heavy is in core. Browser delegates through Backend trait.
78 +
79 + ## Weaknesses
80 +
81 + - **drag_out/ has no automated tests** -- Platform FFI code (macOS objc2, Windows COM) is tested manually only. Hard to unit test (requires windowed app context), but integration test coverage is zero.
82 + - **17 unsafe blocks in drag_out/** -- All justified (platform FFI). Each has SAFETY comments.
83 + - **file_list.rs branch density** -- 689 lines with high branching (egui immediate-mode). Could benefit from extracting row rendering into a helper.
84 +
85 + ## Action Items
86 +
87 + No new action items filed — all findings are LOW severity (acceptable for alpha).
88 +
89 + Previously resolved:
90 + - ~~CRITICAL: applying_remote crash recovery~~ -- RESOLVED
91 + - ~~Migrate browser eprintln! to tracing~~ -- RESOLVED
92 + - ~~Split import_screens.rs~~ -- RESOLVED
93 + - ~~Fix theme include_str! paths~~ -- RESOLVED
94 + - ~~Add E2E integration tests~~ -- RESOLVED
95 +
96 + ## Metrics Over Time
97 +
98 + | Metric | 6th (03-11) | 7th (03-13) | Adversarial (03-13) | 11th (03-18) | 12th (03-19) | 13th (03-19) | 14th (03-22) | ML (03-26) | Run 12 (03-28) |
99 + |--------|:-----------:|:-----------:|:-------------------:|:------------:|:------------:|:------------:|:------------:|:----------:|:--------------:|
100 + | Overall | A- | A- | A- | A- | A | A | A | A | A |
101 + | LOC | 25.6K | 25.6K | 25.6K | ~25K | ~23K | ~23.5K | ~23.5K | ~24.5K | ~24.5K |
102 + | Tests | 518 | 532 | 557 | 566 | 535 | 560 | 585 | 610 | 611 |
103 + | Crates | 7 + xtask | 7 + xtask | 7 + xtask | 7 + xtask | 5 | 5 | 5 | 5 + train | 5 + train |
104 + | Clippy | 2 (trivial) | 2 (trivial) | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
105 + | Unwrap (prod) | ~1 | 7 (all init) | 7 (all init) | 2 (sidebar, guarded) | 2 (sidebar, guarded) | 2 (sidebar) | 2 (sidebar) | 2 (sidebar) | 2 (sidebar) |
106 + | Unsafe | 2 (test) | 2 (test) | 2 (test) | 2 (test) | 17 (FFI) | 17 (FFI) | 17 (FFI) | 17 (FFI) | 17 (FFI) |
107 +
108 + ## Changes Since Last Audit
109 +
110 + ### Sixteenth audit (2026-03-28, Run 12 cross-project)
111 + - **Test count:** 611. 0 clippy warnings. 0 failures.
112 + - **Grade:** A (maintained). v0.3.0.
113 + - **No code changes since ML classifier (2026-03-26).**
114 + - **New dependency advisory:** rustls-webpki 0.103.9 (RUSTSEC-2026-0049) — upgrade to 0.103.10 via `cargo update -p rustls-webpki`.
115 + - **Mandatory surprise:** None. Previous surprises (sync/service.rs zero production unwraps, applying_remote crash recovery) all resolved.
116 + - **No new code findings.** All previous items remain resolved.
117 +
118 + ### Two-Layer ML Classifier (2026-03-26)
119 + - **Test count:** 585 -> 610 (+25). 0 clippy warnings.
120 + - **DB version:** v10 -> v11 (migration 011: `classification_confidence REAL` column on `audio_analysis`, sync triggers updated).
121 + - **New module:** `analysis/mfcc.rs` — MFCC feature extraction from existing STFT magnitudes. 26-band mel filterbank, DCT-II, 13 coefficients aggregated as mean+variance. 7 unit tests.
122 + - **Rewritten:** `analysis/classify.rs` — Two-layer ML classifier replacing rule-based `classify_full()`. Layer 1: rule-based broad classifier (Drum/Bass/Vocal/Synth/Pad/Fx/Noise/Music/Ambience/Impact/Foley/Texture). Layer 2: 200-tree Random Forest for drum sub-classification. New types: `BroadClass`, `ClassificationResult`, `TreeNode`, `RandomForestModel`. 35-feature vector (9 scalar + 26 MFCC). Model embedded via `include_bytes!` (7.4MB), lazy init via `OnceLock`. 5 new tests.
123 + - **New crate:** `audiofiles-train` — RF training binary (excluded from default-members). Custom implementation (no linfa dependency). Stratified 5-fold CV, rayon parallel training, JSON serialization.
124 + - **Modified:** `analysis/spectral.rs` — Added `compute_spectral_features_with_frames()` returning magnitude vectors alongside features. Original function delegates and discards frames.
125 + - **Modified:** `analysis/mod.rs` — Pipeline now computes MFCCs from STFT frames, builds extended ClassifyInput, calls `classify_ml()`. `AnalysisResult` gains `classification_confidence: Option<f64>`.
126 + - **Modified:** `analysis/suggest.rs` — Confidence-gated tag suggestions (only suggest if ML confidence >= 0.5). Reason string includes ML confidence percentage.
127 + - **Modified:** `classify_validation.rs` — Reports per-class confidence stats (mean/median/P10) and precision/recall/F1.
128 + - **Accuracy:** 94.4% strict / 95.6% lenient on 4343 labeled drum samples (was 36%/61% rule-based).
129 + - **Model file:** `crates/audiofiles-core/models/layer2_drum.json` (7.4MB, 200 trees, max_depth=25).
130 + - **No grade change expected** — all new code follows existing patterns, clippy clean, comprehensive tests.
131 +
132 + ### Fourteenth audit (2026-03-22, app test coverage)
133 + - **Test count:** 560 -> 585 (+25). 0 clippy warnings.
134 + - **Grade:** A (maintained). audiofiles-app Test B -> A-.
135 + - **updater.rs:** 8 new tests — UpdateStatus default, dismiss/should_show state machine (4 states), UpdateResponse deserialization, CURRENT_VERSION semver validation.
136 + - **main.rs:** 7 new tests — load_api_key (from file, trims whitespace, empty/whitespace-only/missing file), save_api_key, save-and-load roundtrip.
137 + - **tray.rs:** 2 new tests — build_icon produces valid 18x18 RGBA, icon buffer dimensions and pixel content verification. `build_icon` changed from `fn` to `pub(crate) fn` for testability.
138 + - **Still open (audiofiles-app):** eframe UI update loop, start_output_stream, AppTray::new/poll — all platform-dependent, inherently hard to unit test.
139 +
140 + ### Thirteenth audit (2026-03-19, VP-tree addition)
141 + - **Test count:** 560 (+25). 0 clippy warnings.
142 + - **Grade:** A (maintained). Performance A- -> A. v0.3.0.
143 + - **VP-tree module:** New `vp_tree.rs` — generic `VpTree<T>` with `build()`, `find_nearest()`, `find_within()`. 10 tests including brute-force correctness check.
144 + - **FingerprintIndex:** Two-phase near-duplicate search. Phase 1: VP-tree on 16-bin compact Euclidean features (proper metric, O(log n)). Phase 2: full NCC verification on candidates. Build < 1s for 100K. Query ~3ms at 100K (was 2.7s linear scan — ~900x speedup). 4 tests.
145 + - **SimilarityIndex:** VP-tree on fixed-normalization Euclidean features. Ranges computed once from dataset (not per-query). Minor semantic change: single new sample no longer shifts normalization of all others. Sub-ms queries at 100K (was 26ms linear scan). 5 tests.
146 + - **DirectBackend integration:** Both indexes cached as `Mutex<Option<...>>`, lazy build on first query, auto-invalidation on `save_analysis`.
147 +
148 + ### Twelfth audit (2026-03-19, AF-focused)
149 + - **Test count:** 535. 0 clippy warnings.
150 + - **Grade:** A- -> A. v0.3.0.
151 + - **Major additions:** Native macOS drag-out (drag_out/ module: mod.rs, macos.rs, windows.rs), brand refresh (audiofiles theme, af/ logo in Recursive font, app icon with squircle), description.md rewrite.
152 + - **Crate removal:** audiofiles-plugin, audiofiles-ipc, and xtask removed (standalone-only). 7 crates -> 5. nih-plug workspace deps removed.
153 + - **Unsafe surface change:** 17 platform FFI in drag_out/. All justified: objc2 NSDraggingSession on macOS, COM IDataObject on Windows. No production unsafe outside FFI.
154 + - **Verification results:** sync/service.rs has zero production unwraps (all in #[cfg(test)]). theme.rs has zero production unwraps. Rhai engine has 100K ops + 32 call levels limits. note_counter is u64 (no overflow risk). DRAG_ACTIVE is in-memory AtomicBool (resets on restart, no persistence issue).
155 + - **New LOW findings:** sidebar.rs has 2 guarded unwraps (style nit). updater.rs trusts server-provided download URL (acceptable — opens in browser, no auto-install).
156 + - **Mandatory surprise:** sync/service.rs zero production unwraps — Impressive (see above).
157 +
158 + ### Eleventh audit (2026-03-18, Run 9 cross-project)
159 + - **Test count:** 566 (up from 557). 0 clippy warnings.
160 + - **Grade:** A- (maintained). v0.3.0.
161 + - **Clippy fixes:** 3 warnings resolved pre-release build: collapsible `if` in `file_list.rs` and `sidebar.rs`, derivable `Default` impl in `updater.rs`.
162 + - **Release build:** Standalone app + CLAP + VST3 all signed+notarized.
163 + - **OTA updater verified:** `updater.rs` (148 LOC) — proper error handling (15s timeout, version parsing fallback, target/arch detection), Arc-wrapped UpdateStatus for thread safety, 10s initial delay + 6h polling.
164 + - **No new findings.** All previous cold spots remain resolved.
165 + - **Mandatory surprise:** None. Previous surprises (applying_remote crash recovery, find_nodes_by_hashes column mismatch) all resolved.
166 +
167 + ### Concurrency Upgrade (2026-03-13)
168 + - **Concurrency:** A- -> A
169 + - Eliminated double-lock TOCTOU in cancel_import/cancel_analysis/cancel_export -- now uses single lock with .take() pattern (6 lock acquisitions reduced to 3).
170 +
171 + ### Observability Upgrade (2026-03-13)
172 + - **Observability:** A- -> A
173 + - Upgraded tracing subscriber from bare `fmt::init()` to `registry() + EnvFilter + fmt layer` with env-configurable log levels (RUST_LOG)
174 + - Added `features = ["env-filter"]` to `tracing-subscriber` workspace dependency
175 + - Added 12 `#[instrument(skip_all)]` annotations across 6 files: scheduler.rs (2), service.rs (6), auth.rs (1), audio.rs (1), import.rs (1), export.rs (1)
176 + - `cargo check --workspace` passes clean
177 +
178 + ### Adversarial Test Audit (2026-03-13)
179 +
180 + Targeted adversarial testing after seventh audit remediation. Test count: 532 → 546 (+14 tests). 4 critical bugs found and fixed:
181 +
182 + **CRITICAL: `find_nodes_by_hashes` SELECT had wrong column count**
183 + - Missing `s.cloud_only` column and `LEFT JOIN samples` in query
184 + - Query returned 4 columns but code expected 5, causing panic on result extraction
185 + - Fixed: Added missing column and join to match schema
186 + - Added 3 adversarial tests: non-existent hash, mismatched hash count, partial hash set
187 +
188 + **HIGH: `move_node` allowed circular parent chains**
189 + - No cycle detection before UPDATE — could create infinite loops
190 + - Fixed: Added ancestor chain walk with HashSet cycle detection before UPDATE
191 + - Added 3 tests: direct self-parent, indirect circular chain, valid deep move
192 +
193 + **HIGH: Zero-byte files accepted into content store**
194 + - No validation on file size before hashing and import
195 + - Fixed: Reject zero-byte files before hashing
196 + - Added 2 tests: zero-byte rejection, valid non-empty file acceptance
197 +
198 + **HIGH: Non-atomic remove ordered file deletion before DB**
199 + - Deleted file from disk first, then updated DB — crash between steps left orphan DB row
200 + - Fixed: Reversed order to DB first, then file (matches content store pattern)
201 + - Added 3 tests: remove_by_hash atomicity, remove_sample atomicity, remove rollback leaves file intact
202 +
203 + **Security & correctness improvements:**
204 + - All 4 findings had genuine data corruption or crash potential
205 + - Adversarial tests now cover: malformed queries, cycle creation, zero-byte edge case, crash-during-delete atomicity
206 + - DB version unchanged: v8 (hash re-verification migration from earlier audit still current)
207 +
208 + **Test breakdown:**
209 + - Core: 179 → 190 (+11 tests for the 4 fixes above)
210 + - Sync: 21 → 24 (+3 tests for edge cases)
211 +
212 + ### Eighth audit (2026-03-16, Run 6 cross-project)
213 + - **Test count:** 546 -> 557 (+11 tests)
214 + - **Grade:** A- (maintained).
215 + - **New findings (LOW):** unix_now().expect() in error.rs:134 could crash DAW host (should use non-panicking fallback). Only 12 #[instrument] annotations on 86 files — observability density gap.
216 + - **Mandatory surprise:** unix_now().expect() in CLAP/VST3 plugin context — Genuine issue (panic = DAW crash).
217 + - **Previous items verified:** All previous remediated items confirmed intact (applying_remote, browser tracing, import_screens split, theme paths).
218 +
219 + ### Seventh audit (2026-03-13, pre-launch skeptical lens)
220 +
221 + Grade holds at A-. 528 tests (was 518). Audio thread safety confirmed excellent. New minor findings:
222 + - Vec allocation in audio path for MIDI events (should be SmallVec/pre-allocated)
223 + - query_sample_field uses string interpolation for SQL column name (safe — values from match arms, not user input — but fragile if pattern copied)
224 + - No hash re-verification on read from content store (import validates, but read path trusts stored hash)
225 +
226 + Previous applying_remote crash recovery issue remains open (CRITICAL).
227 +
228 + **Post-audit remediation (2026-03-13):**
229 + - All 3 seventh-audit findings resolved: SmallVec for MIDI events, query_sample_field allowlist, hash re-verification
230 + - All 5 prior cold spots resolved: applying_remote cleared on startup, browser tracing migration, import_screens split, E2E tests (3), theme paths fixed
231 + - Test count: 528 -> 532 (+4 tests)
232 + - DB version: v7 -> v8
233 + - Documentation upgraded to A: SpectralFeatures fields documented with units, SampleStore struct doc added, architecture.md created (168 lines), README created (58 lines). All pub functions now have /// doc comments.
234 +
235 + ### Sixth-run full audit (2026-03-11)
236 +
237 + Fresh audit of entire codebase per audit.md. Test count: 518 (was 429). 2 trivial clippy warnings. Near-zero `.unwrap()` in production code. 2 `unsafe` blocks (both in test helpers, test-only). 7 crates (was 5).
238 +
239 + ### Major changes since fifth audit
240 +
241 + - **New crate: audiofiles-sync (1,838 LOC)** -- Full SyncKit integration: push/pull sync engine, OAuth2 PKCE auth, background scheduler, changelog triggers across 9 tables. 21 tests.
242 + - **New crate: audiofiles-rhai (1,462 LOC)** -- Rhai scripting for hardware sampler export profiles. Sandboxed engine, plugin discovery/loading, 4 hook points, bundled device plugins. 33 tests.
243 + - **Test count: 429 -> 518** -- New tests across sync (21), rhai (33), plus additional core/browser tests.
244 + - **LOC: ~22K -> 25.6K** -- Growth from sync and rhai crates.
245 + - **DB version: v6 -> v7** -- Migration 007 adds sync_state table, sync_changelog table, 27 changelog triggers.
246 + - **Backend trait: 42 -> 47 methods** -- Added sync-related methods (get/set VFS sync_files, sync manager integration).
247 + - **Alpha polish** -- VFS management UI (context menus, create/rename modals), directory management.
248 +
249 + ### Grades changed
250 +
251 + | Dimension | Previous | Current | Change |
252 + |-----------|:--------:|:-------:|--------|
253 + | Security | A | A- | applying_remote crash recovery gap |
254 + | Resilience | B+ | A- | Worker Drop cleanup improved, but applying_remote is new concern |
255 +
256 + ### Mandatory surprise assessment
257 +
258 + - **applying_remote flag stuck after crash**: Genuine issue. Silent data loss vector in sync system. Filed as CRITICAL action item.
259 +
260 + ### Audit Grade Corrections (2026-03-13)
261 +
262 + Corrected stale grades where the auditor missed existing code:
263 + - **Resilience:** A- → A. `applying_remote` cleared on startup (`service.rs:102-110`). All other resilience items confirmed working (Worker Drop, per-file error reporting, audio stream failure non-fatal, atomic migrations, CASCADE FKs).
264 + - **Frontend:** A- → A. import_screens split into directory module (configure.rs 229, progress.rs 177, tagging.rs 267). No single UI file exceeds 300 LOC.
265 +
266 + ### Security Deep Dive (2026-03-13) — Complete (2/2)
267 +
268 + - **Extension validation:** `store.rs` — `validate_extension()` function added, only allows alphanumeric characters, dots, and hyphens; prevents path traversal via crafted extensions. 3 new tests (path traversal, path separator, common extensions).
269 + - **OAuth callback safe slicing:** `auth.rs` — OAuth callback parser uses `.get(after_q..end)` for safe slicing instead of direct indexing; `saturating_sub` for fallback calculation; graceful break with `tracing::warn!` on malformed requests.
270 +
271 + ### Still open (5 items)
272 +
273 + - Add `updated_at` columns for sync (Phase 9 prerequisite)
274 + - Consider BrowserState decomposition (40+ field god object)
275 + - app crate: 22 tests now cover updater, key management, icon, audio; remaining gaps are platform-dependent (eframe, cpal, tray)
276 + - Add tests for remaining UI modules (file_list.rs, widgets.rs)
277 + - drag_out/ has no automated tests (platform FFI, manual testing only)
278 +
279 + ## Resolved Items (Previous Audits)
280 +
281 + - [x] state.rs split into directory module (state/mod.rs, navigation.rs, import_workflow.rs, bulk_ops.rs, tests.rs)
282 + - [x] 132 integration tests for state.rs orchestration
283 + - [x] LIKE wildcards escaped via `escape_like()` in search.rs and tags.rs
284 + - [x] DB migrations wrapped in transactions
285 + - [x] Hash validation in store.rs (validate_hash checks 64-char lowercase hex)
286 + - [x] `Result<_, String>` in app/audio.rs replaced with typed AudioError enum
287 + - [x] contents.clone() in file_list.rs confirmed as Arc clone (not deep copy)
288 + - [x] All clippy lints resolved (items_after_test_module, io_other_error, identity_op)
289 + - [x] Moved load_analysis to core (was raw SQL in DirectBackend)
290 + - [x] Moved sample_extension/original_name to core
291 + - [x] Replaced manual transactions with Database::transaction()
292 + - [x] Cleaned up find_nodes_by_hashes
293 + - [x] `export/mod.rs` split (extracted resolve.rs, runner.rs)
294 + - [x] SAFETY comments on unsafe blocks (preview.rs, instrument.rs)
295 + - [x] Scalability notes on fingerprint.rs and similarity.rs (O(n) documented; fingerprint now VP-tree indexed)
296 + - [x] Tag validation docs enhanced
297 + - [x] Theme tests: 44 tests for ui/theme.rs pure functions
298 + - [x] `split_name_ext` centralized into util.rs (3 tests)
299 + - [x] Smart folder error handling: CoreError::Serialization variant
300 + - [x] Entity ID newtypes (VfsId, NodeId, SmartFolderId, CollectionId)
301 + - [x] SampleHash validated newtype with new() returning Result
302 + - [x] NodeType::parse() wildcard fallback replaced with explicit error
303 + - [x] SampleHash consistency fix (ExportItem, ReviewItem)
304 +
305 + ---
306 +
307 + ## Documentation Review
308 +
309 + **Last reviewed:** 2026-03-04 (first doc audit)
310 +
311 + ### Overall Grade: A
312 +
313 + Minimal but appropriate doc set for the project's current stage. No inaccuracies found. description.md is an intentional placeholder. Documentation is proportional to the project's development status.
314 +
315 + ### Document Heatmap
316 +
317 + | Document | Status | Last Verified | Notes |
318 + |----------|:------:|:-------------:|-------|
319 + | docs/todo.md | Current | 2026-03-04 | Active task list |
320 + | docs/todo_done.md | Current | 2026-03-04 | Completed items archive |
321 + | docs/description.md | Current | 2026-03-04 | Project overview + technical reference |
322 + | docs/competition.md | Current | 2026-03-04 | Competitive analysis |
323 + | docs/description.md | Placeholder | 2026-03-04 | Intentional placeholder |
324 + | docs/human_testing.md | Current | 2026-03-04 | Manual QA checklist |
325 + | docs/audit_review.md | Current | 2026-03-04 | Code audit history |
326 +
327 + ### Stale References Found (This Audit)
328 +
329 + None.
330 +
331 + ### Action Items
332 +
333 + - None. Clean doc set for project's current stage.
@@ -0,0 +1,290 @@
1 + # audiofiles -- Competitive Analysis
2 +
3 + Last updated: 2026-03-18
4 +
5 + ## Positioning
6 +
7 + audiofiles is the only sample manager with content-addressed storage, multiple virtual file systems, and hardware sampler export profiles. It runs as a standalone desktop app. Built in Rust with egui, it provides audio analysis, intelligent tagging, similarity search, native drag-to-DAW, MIDI instrument mode, cloud sync, and device-specific export for 14 hardware samplers.
8 +
9 + ## Pricing Comparison
10 +
11 + | App | Price | Model |
12 + |-----|-------|-------|
13 + | **audiofiles** | **Free (alpha)** | Source-available |
14 + | ADSR Sample Manager | Free | Free + marketplace |
15 + | Argotlunar | Free | Free |
16 + | Sononym | $99 once | Standalone only |
17 + | Atlas 2 | $99 once | Plugin + standalone |
18 + | AudioFinder | $70 once | macOS only |
19 + | XO | $180 once | Plugin + standalone |
20 + | Splice | $13-40/mo | Subscription |
21 + | Loopcloud | $8-22/mo | Subscription |
22 +
23 + ## Feature Matrix
24 +
25 + | Feature | AF | Splice | ADSR | Loopcloud | XO | Atlas 2 | Sononym | AudioFinder |
26 + |---------|:--:|:------:|:----:|:---------:|:--:|:-------:|:-------:|:-----------:|
27 + | **Content-addressed store** | Yes | No | No | No | No | No | No | No |
28 + | **VFS (multiple hierarchies)** | Yes | No | No | No | No | No | No | No |
29 + | **Hardware export profiles** | Yes (14) | No | No | No | No | No | No | No |
30 + | **Rhai scripting** | Yes | No | No | No | No | No | No | No |
31 + | **CLAP plugin** | Yes | No | No | No | No | No | No | No |
32 + | **VST3 plugin** | Yes | Yes | Yes | No | Yes | Yes | No | No |
33 + | **Standalone** | Yes | App | Yes | App | Yes | Yes | Yes | Yes |
34 + | **Source-available** | Yes | No | No | No | No | No | No | No |
35 + | **Local-first** | Yes | No | Partial | No | Yes | Yes | Yes | Yes |
36 + | **Cross-platform** | Yes | Mac/Win | Mac/Win | Mac/Win | Mac/Win | Mac/Win/Linux | Mac/Win/Linux | macOS only |
37 + | **BPM detection** | Yes | Metadata | No | Metadata | No | No | Yes | Yes |
38 + | **Key detection** | Yes | Metadata | No | Metadata | No | No | Yes | Yes |
39 + | **LUFS loudness** | Yes | No | No | No | No | No | No | No |
40 + | **Spectral analysis** | Yes | No | No | No | No | No | Yes | No |
41 + | **Classification (12-class)** | Yes | No | No | No | No | No | Yes | Separate ($10) |
42 + | **Loop detection** | Yes | No | No | No | No | No | No | No |
43 + | **Tag suggestions** | Yes | No | Smart tags | No | No | No | Yes (v1.6) | No |
44 + | **Bulk ops with undo** | Yes | No | No | No | No | No | No | Yes (rename) |
45 + | **Similarity search** | Yes | Yes (ML) | No | Yes (ML) | Yes (2D map) | Yes (timbre) | Yes (tunable) | No |
46 + | **Drag-to-DAW** | Yes | Yes | Yes | Yes | Yes | Yes | No | No |
47 + | **Auto tempo/key match** | No | Yes | Via Link | Yes | No | No | Pitch ctrl | No |
48 + | **Sample marketplace** | No | 4M+ | Yes | 4M+ | No | No | No | No |
49 + | **Preview effects** | No | No | Yes (HP/LP/gain) | Yes (10 FX) | No | No | No | Yes (AU hosting) |
50 + | **Built-in sequencer** | No | No | No | 8-track | Yes | Yes | No | No |
51 + | **Mobile app** | No | Yes | No | No | No | No | No | No |
52 + | **Cloud storage** | No | Yes | No | Yes | No | No | No | No |
53 +
54 + ## Competitor Deep Dives
55 +
56 + ### Splice
57 +
58 + Sample marketplace + cloud library with DAW integration plugin and AI-powered discovery tools.
59 +
60 + **Pricing:** Subscription. Sounds+ $12.99/mo (100 credits), Creator $19.99/mo (200 credits), Creator+ $39.99/mo (500 credits). Annual plans at ~17% discount. Rent-to-own plugin marketplace is separate.
61 +
62 + | Feature | Notes | Tag |
63 + |---------|-------|-----|
64 + | 4M+ royalty-free sample marketplace | Credit-based download from curated cloud catalog | |
65 + | Bridge plugin (in-DAW BPM/key-matched preview) | Preview Splice samples in-context inside DAW, auto tempo/key sync | |
66 + | Create mode / Stacks (AI sample layering) | AI selects up to 8 compatible layers matched by key/tempo/genre | |
67 + | Similar Sounds (AI audio fingerprint search) | ML-based sonic similarity across their catalog, not tag-based | |
68 + | Search with Sound (upload audio to find matches) | Drag audio from DAW or upload loop, AI finds complementary samples | |
69 + | Mobile app (iOS/Android) | Browse catalog, Create mode, Splice Mic for vocal recording on phone | |
70 + | Splice Instrument (sample-based virtual instrument) | Play downloaded samples chromatically via plugin keyboard | |
71 + | Collections (shareable playlists) | Curate sample groups, share via URL, accessible on web/desktop/mobile | |
72 + | Rent-to-own plugin marketplace | Pay monthly toward owning third-party plugins (Serum, Arturia, etc.) | [BLOAT] |
73 + | Community Discord + remix contests | Social engagement layer | [BLOAT] |
74 + | CoSo social sharing (video export of Stacks) | Record mute/unmute performances, share to social media | [BLOAT] [DATA-HUNGRY] |
75 + | DAW project file export (Ableton/Studio One) | Export Stacks as full DAW project with warped samples | |
76 + | Companion mode (mini floating browser) | Condensed desktop app for quick browsing alongside DAW | |
77 + | User analytics and listening behavior tracking | Splice tracks usage patterns to personalize recommendations | [INVASIVE] [DATA-HUNGRY] |
78 +
79 + **Key takeaway:** Splice is a marketplace first, manager second. Its strength is the massive catalog and AI discovery. audiofiles competes on the management side -- Splice does not offer content-addressed storage, deduplication, VFS, hardware sampler export, or local-first analysis. Splice requires an internet connection and subscription for core value.
80 +
81 + ---
82 +
83 + ### ADSR Sample Manager
84 +
85 + Free sample browser/manager with cloud marketplace integration and DAW plugin.
86 +
87 + **Pricing:** Free (standalone + plugin). ADSR marketplace uses credit bundles starting at $5. Earn credits from ADSR store purchases.
88 +
89 + | Feature | Notes | Tag |
90 + |---------|-------|-----|
91 + | HP/LP filter on preview | Shape sound before auditioning with highpass/lowpass filters | |
92 + | Fade in/out on preview | Apply fades during preview, render to DAW with settings applied | |
93 + | Gain + normalize on preview | Adjust and normalize volume before dragging to DAW | |
94 + | Ableton Link sync | Sync loop preview playback across devices and Link-enabled apps | |
95 + | True drag-and-drop to DAW (rendered with settings) | Drag applies preview settings (filter, fade, gain) to rendered output | |
96 + | Cloud sample browsing (ADSR marketplace) | Browse and preview purchased ADSR samples from within the manager | [DATA-HUNGRY] |
97 + | Smart tags (auto-generated from filename/path) | Automatic tag generation from folder structure and filename parsing | |
98 + | Looped preview with quantized start points | Loops restart at beat-quantized positions for musical auditioning | |
99 + | Resizable waveform display with zoom | Drag to resize waveform, zoom with snapping to zero crossings and note divisions | |
100 + | Effective length column | Shows actual audio duration excluding silence | |
101 +
102 + **Key takeaway:** ADSR competes on price (free) and workflow convenience (preview manipulation before drag-to-DAW). audiofiles already has stronger analysis, VFS, and deduplication. The preview manipulation features (HP/LP filter, fade, gain, normalize on preview) are genuinely useful workflow additions worth noting.
103 +
104 + ---
105 +
106 + ### Loopcloud
107 +
108 + Sample marketplace + DAW plugin with built-in editor, effects, and cloud storage.
109 +
110 + **Pricing:** Subscription. Artist $7.99/mo (100 sounds, 5GB cloud), Studio $11.99/mo (300 sounds, 50GB cloud), Professional $21.99/mo (600 sounds, 250GB cloud). Annual plans at ~17% discount.
111 +
112 + | Feature | Notes | Tag |
113 + |---------|-------|-----|
114 + | 4M+ royalty-free cloud sample library | Subscription access to Loopmasters catalog | |
115 + | 8-track editor with slice/rearrange | Multi-track sample editor for building loops from sliced parts | |
116 + | 10 built-in effects (reverb, delay, EQ, compressor, grain stretch, tonebox) | FX chain on samples before export, like a mini DAW | [BLOAT] |
117 + | Flip Sample (1000+ pattern transforms) | One-click sample transformation: slice, pitch, sequence, apply effects patterns | |
118 + | Auto time-stretch to project BPM | Samples automatically stretch to match DAW tempo | |
119 + | Auto key transpose (Key Lock) | Samples auto-transpose to match project key | |
120 + | Cloud sample storage (5-250GB by tier) | Store your own samples in the cloud, tagged and organized | |
121 + | Favourites and Collections | Organize samples into playlists across cloud and local libraries | |
122 + | Sample similarity search within catalog | Find similar sounds in the Loopcloud library | |
123 + | In-app sample purchasing | Browse, preview, buy samples without leaving the app | [DATA-HUNGRY] |
124 +
125 + **Key takeaway:** Loopcloud is a marketplace-first tool with a surprisingly capable editor. The Flip Sample feature (pattern-based sample transformation) is creative but moves into sound design territory, not management. audiofiles differentiates with local-first architecture, deduplication, VFS, and hardware export. Loopcloud has no deduplication, no hardware sampler awareness, and requires subscription for core features.
126 +
127 + ---
128 +
129 + ### XO by XLN Audio
130 +
131 + Drum sample organizer with AI similarity mapping and built-in sequencer.
132 +
133 + **Pricing:** One-time $179.95. VST/AU/AAX plugin + standalone.
134 +
135 + | Feature | Notes | Tag |
136 + |---------|-------|-----|
137 + | XO Space (visual similarity map) | 2D point cloud visualization of entire drum library by sonic similarity | |
138 + | Similarity List (nearest-neighbor suggestions) | Click any sample, see ranked list of most similar sounds | |
139 + | 8-track drum sequencer (32-step) | Pattern editor with A/B patterns, groove templates, velocity control | |
140 + | Playground Mode (randomize patterns/sounds) | Non-destructive random exploration of beat and sound combinations | |
141 + | 8700+ bundled one-shot drum samples | Factory content covering all drum categories and genres | |
142 + | 240+ beat presets | Pre-built patterns across genres | |
143 + | Per-channel groove presets (14 templates) | Swing/groove quantization per sequencer channel | |
144 + | Nudge per channel (up to 16th note) | Micro-timing offset per drum channel for humanization | |
145 + | Rolls (up to 4x repeats) | Drum roll effect on sequencer steps | |
146 + | WAV stem export + MIDI export | Export individual channel stems or full beat as audio/MIDI | |
147 + | Drag-and-drop individual sounds or full kit | Export raw or processed sounds to DAW via drag | |
148 + | Duplicate detection and sorting | Identifies and sorts duplicate samples across folders | |
149 +
150 + **Key takeaway:** XO is the closest competitor in the "make sense of a chaotic sample library" space. Its visual similarity map (XO Space) is a genuinely innovative interface that audiofiles lacks. However, XO is drum-only, has no VFS, no content-addressed storage, no tagging system, no hardware sampler export, and no general-purpose sample management. audiofiles covers all sample types and has deeper organizational tools.
151 +
152 + ---
153 +
154 + ### Sononym
155 +
156 + AI-powered sample browser with similarity search and automatic categorization.
157 +
158 + **Pricing:** One-time $99 (or 89 EUR). 30-day free trial. Windows/macOS/Linux.
159 +
160 + | Feature | Notes | Tag |
161 + |---------|-------|-----|
162 + | ML similarity search (multi-aspect) | Find similar sounds using tunable aspects: spectrum, timbre, pitch, amplitude | |
163 + | Aspects Dial (tunable similarity weighting) | Adjust which sonic dimensions matter most in similarity results | |
164 + | Live recording input for similarity search | Record audio live, use recording as similarity search query | |
165 + | Near-duplicate detection (fuzzy matching) | Finds not just exact duplicates but near-identical sounds | |
166 + | Spectrogram visualization | Visual frequency-over-time display for each sample | |
167 + | ML-based automatic categorization | Machine learning groups samples into categories (kick, snare, pad, etc.) | |
168 + | Offline-first, no internet required | Fully functional without network access | |
169 +
170 + **Key takeaway:** Sononym is the most directly comparable competitor in philosophy: local-first, analysis-driven, no subscription. Its ML similarity search with tunable aspects is more sophisticated than audiofiles' weighted Euclidean similarity search. The Aspects Dial (weight different sonic dimensions) is a compelling UX pattern. However, Sononym has no VFS, no content-addressed storage, no deduplication, no DAW plugin mode, no tagging system, and no hardware sampler export. audiofiles has a much broader feature surface.
171 +
172 + ---
173 +
174 + ### Atlas 2 by Algonaut
175 +
176 + AI-driven drum sample organizer with visual map and drum sequencer.
177 +
178 + **Pricing:** One-time $99 (upgrade from v1: $19). Free trial. VST3/AU plugin + standalone. Windows/macOS/Linux.
179 +
180 + | Feature | Notes | Tag |
181 + |---------|-------|-----|
182 + | AI timbre map (point cloud clusters) | Visual 2D map grouping samples by instrument type and timbre | |
183 + | Drum sequencer (step + piano roll hybrid) | Fast step entry with piano-roll flexibility for detailed editing | |
184 + | Variation Engine (humanization/randomization) | Randomize velocity, timing, sample start per trigger for organic feel | |
185 + | 8/16/64 channel drum kits | Scalable kit sizes from minimal to massive | |
186 + | MIDI import | Load MIDI patterns to trigger kit sounds | |
187 + | MIDI export (single file or per-channel) | Export patterns for use in DAW, with or without groove baked in | |
188 + | Mirror edit, rotate notes, nudge | Pattern manipulation tools for creative sequencing | |
189 + | Polyrhythm support | Different time divisions per channel | |
190 + | Record-in mode | Real-time recording of drum patterns | |
191 +
192 + **Key takeaway:** Atlas 2 is very similar to XO in concept (drum-focused, visual map, sequencer) but adds a more flexible sequencer with humanization. Like XO, it is drum-only and lacks general-purpose sample management, VFS, tagging, or hardware export. Not a direct competitor to audiofiles' core value proposition.
193 +
194 + ---
195 +
196 + ### AudioFinder (Iced Audio)
197 +
198 + Veteran macOS sample manager with editing, batch processing, and AudioUnit hosting.
199 +
200 + **Pricing:** One-time ~$69.95 with lifetime updates. macOS only.
201 +
202 + | Feature | Notes | Tag |
203 + |---------|-------|-----|
204 + | Sample Extractor (auto-split by volume threshold) | Split a single audio file into multiple samples at transients | |
205 + | Built-in sample editor (trim, loop, fade, gain, beat slice) | Destructive audio editing within the manager | |
206 + | AudioUnit plugin hosting | Preview samples through AudioUnit effects chains | |
207 + | Batch processing with DSP routines | Apply processing to many files at once | |
208 + | Beat detection | Detect and slice on beat boundaries | |
209 + | MIDI preview keyboard | Play samples at different pitches via built-in keyboard or MIDI input | |
210 + | Apple Loop / BWF / ACID WAV metadata display | Read and display industry-standard metadata formats | |
211 + | Power Rename (batch renaming) | Pattern-based bulk renaming with preview | |
212 + | AudioCortex 2.0 (separate AI product) | ML-based auto-categorization into 443+ categories, sound stacking tool | |
213 + | REX/RX2 file support | Read Propellerhead REX loop format | |
214 + | SYX/MID file support | Browse MIDI and SysEx files alongside audio | |
215 + | Bookmarks, history, favorites | Navigation aids for large libraries | |
216 + | Multi-channel playback and display | Preview and visualize surround/multi-channel audio files | |
217 + | Rating system (star ratings per sample) | Rate samples for quality-based filtering | |
218 +
219 + **Key takeaway:** AudioFinder is the most mature pure sample manager in this list, with deep editing and batch processing features that audiofiles lacks. Its Sample Extractor (auto-split audio into individual hits) is a genuinely useful tool for sample pack creation. However, it is macOS-only, has no DAW plugin mode, no content-addressed storage, no VFS, and no hardware sampler export. AudioCortex (AI categorization) is a separate paid product. The codebase appears to be aging (Objective-C era tooling).
220 +
221 + ## Closed Gaps (since initial analysis)
222 +
223 + Features that were previously missing and are now implemented:
224 +
225 + - **True drag-and-drop to DAW** -- macOS NSDraggingSession, Windows OLE DoDragDrop. Multi-file, friendly filenames via temp symlinks. [Done]
226 + - **Waveform display** -- Custom egui painter with click-to-seek, rendered from pre-generated peak data. [Done]
227 + - **Collections / favorites / playlists** -- Cross-VFS groupings with full CRUD. [Done]
228 + - **Similarity search** -- Weighted Euclidean distance on analysis feature vectors. "Find Similar" context menu. [Done]
229 + - **Near-duplicate detection** -- Peak envelope fingerprint comparison. "Find Duplicates" context menu. [Done]
230 + - **Cloud sync** -- E2E encrypted push/pull via MNW SyncKit, per-VFS file sync toggle, cloud-only browsing. [Done]
231 + - **MIDI instrument mode** -- Chromatic + multi-sample, ADSR, 8-voice polyphony, drag-to-keyboard zone assignment. [Done]
232 +
233 + ## Remaining Gaps
234 +
235 + Features present in multiple competitors that audiofiles still lacks, grouped by priority.
236 +
237 + ### Worth Adding
238 +
239 + - **Auto tempo/key-matched preview** -- Splice Bridge and Loopcloud auto-stretch to project BPM/key. Requires time-stretch library.
240 + - **Preview effects (filter, pitch)** -- ADSR has HP/LP filter, fade, gain, normalize baked into drag-to-DAW output. Loopcloud has 10 built-in effects. HP/LP filter on preview would be a small, useful addition. Full FX chains are bloat.
241 + - **Visual similarity map (2D point cloud)** -- XO, Atlas 2, Sononym. Visually compelling for exploration. Non-trivial in egui but high wow-factor.
242 + - **ML-based categorization** -- Sononym, XO, Atlas 2, AudioFinder/AudioCortex. Rule-based classification covers 12 categories today. ML would improve accuracy and expand categories.
243 + - **Spectrogram visualization** -- Sononym, AudioFinder. Frequency-over-time display per sample.
244 +
245 + ### Low Priority / Out of Scope
246 +
247 + - **Built-in sequencer / pattern editor** -- XO and Atlas 2 have drum sequencers. DAW territory; not in AF's scope.
248 + - **Cloud sample marketplace / storefront** -- Splice and Loopcloud each have 4M+ royalty-free samples. Requires massive catalog licensing, content moderation, and ongoing operational cost. Contradicts audiofiles' local-first philosophy. The planned community sharing feature (deferred) is a lighter alternative.
249 + - **Cloud storage** -- Splice and Loopcloud sync samples to cloud. AF has its own optional sync tier planned, but cloud-as-primary contradicts local-first philosophy.
250 + - **Mobile app** -- Splice has iOS/Android. Out of scope until core desktop/plugin experience is complete. Mobile tagging has niche value for field recording workflows. [Planned, Deferred]
251 + - **Sample editing (trim, loop, fade, slice)** -- AudioFinder, Loopcloud. DAW territory. AF should remain non-destructive and metadata-focused. Export-time transformations (device profiles) are the right approach.
252 + - **Batch processing / DSP** -- AudioFinder, Loopcloud. Same reasoning as sample editing. Batch format conversion is already covered by device export profiles.
253 + - **Full effects chain on preview** -- Bloat for a manager.
254 + - **AAX format** -- ADSR and AudioFinder support it. Low priority vs CLAP/VST3.
255 + - **Social features / sharing / community** -- Premature, low signal.
256 +
257 + ## What We Offer That Competitors Don't
258 +
259 + - **Content-addressed storage with SHA-256 deduplication** -- Samples stored by hash, never duplicated regardless of how many VFS trees reference them. No other tool does this.
260 + - **Multiple Virtual File Systems** -- Organize the same samples into unlimited hierarchies without copying files. All operations are metadata-only (instant moves, renames, multi-tree views).
261 + - **Hardware sampler export profiles** -- Rhai-scripted export to 10+ devices (M8, Digitakt, Digitakt II, SP-404 MKII, MPC, Polyend Tracker, Deluge, Blackbox, Volca Sample 2, OP-1) with proper sample rate conversion, bit depth dithering, and filename sanitization. No competitor offers this.
262 + - **7 local analysis types** -- BPM, key, LUFS, spectral (centroid/flatness/rolloff/ZCR), classification, loop detection, tag suggestions. Splice and Loopcloud rely on catalog metadata; Sononym has ML similarity but fewer distinct analysis types.
263 + - **Tag suggestion engine with confidence scores** -- Analyzes audio characteristics and suggests tags with reasoning. Sononym v1.6 added tagging but without confidence scoring.
264 + - **Bulk operations with 50-deep undo** -- Delete, move, rename, tag operations all undoable. No competitor has this depth of undo.
265 + - **Rhai scripting for extensibility** -- Export profiles, future import adapters. Community-extensible via plugin.toml manifests + optional scripts in a sandboxed runtime. No other sample manager has a scripting runtime.
266 + - **Built entirely in Rust** -- Memory-safe, no garbage collector pauses, real-time audio thread safety via try_lock.
267 + - **Sync-only core library (no async runtime)** -- Simple, predictable data layer with no async complexity.
268 + - **SQLite-backed metadata** -- Single-file database, no server, portable, fast.
269 + - **Source-available** -- Unique among all competitors.
270 +
271 + ## Key Dynamics
272 +
273 + - Splice's native DAW integrations (embedded in Pro Tools, Studio One, Ableton without a plugin) represent a shift in the market. AF's plugin approach is the standard; direct DAW embedding is the future for marketplace products.
274 + - Sononym v1.6 (2025) added tagging and UCS integration, closing the gap on AF's tag system, but AF's confidence-scored suggestion engine and content-addressed storage remain unique.
275 + - The drag-and-drop blocker is the most impactful missing feature. Copy-path-to-clipboard is a friction point that every competitor has solved.
276 + - The most important gaps to close (in priority order):
277 + 1. Waveform display -- table stakes, already planned
278 + 2. Collections -- already planned, high usability impact
279 + 3. Similarity search -- already planned, major discovery feature
280 + 4. True drag-and-drop to DAW -- already planned (blocked on baseview)
281 + 5. Preview pitch/tempo matching -- not yet planned, high value in plugin mode
282 + 6. Near-duplicate detection -- extends existing exact dedup with fuzzy matching
283 +
284 + ## Target Users
285 +
286 + - Music producers who accumulate large sample libraries and need to organize, search, and preview them efficiently
287 + - Hardware sampler owners (Digitakt, SP-404, MPC, OP-1, M8, etc.) who need to format and export samples to device-specific constraints
288 + - Sound designers who need content-addressed deduplication across projects
289 + - Sample pack creators who need bulk tagging, renaming, and export tools
290 +
@@ -0,0 +1,312 @@
1 + # audiofiles
2 +
3 + > Manage your sample library without the waits.
4 +
5 + ## What It Is
6 +
7 + audiofiles is a standalone desktop sample manager. It stores samples by content hash so nothing is ever duplicated, organizes them in virtual file systems that don't touch your disk, and exports them formatted for 14 hardware samplers. Built entirely in Rust.
8 +
9 + ## Design
10 +
11 + - **Brand:** "audiofiles/" in Recursive Mono Bold. Short form: "af/"
12 + - **Default theme:** Bold black and white (pure #000000 background, #ffffff text, sharp system accent colors). 17 bundled themes including dark, light, and high-contrast variants.
13 + - **Typography:** Recursive Mono Bold for the logo; egui system font for all UI text.
14 +
15 + ## Features
16 +
17 + ### Sample Import
18 + - Import folders of audio samples (WAV, FLAC, MP3, OGG, AIFF)
19 + - Three import strategies: flat, new VFS, or merge into existing VFS
20 + - Content-addressed storage (SHA-256) with automatic deduplication
21 + - Progress display with cancel support; partial imports remain valid
22 + - Drag-and-drop import (standalone app)
23 + - CLI argument import (`audiofiles-app /path/to/folder`)
24 + - Post-import folder tagging prompt
25 +
26 + ### Virtual File System (VFS)
27 + - Organize samples in virtual directories independent of disk location
28 + - Multiple VFS roots (switch between collections via sidebar or dropdown)
29 + - Create, rename, delete VFS roots and directories
30 + - Move and rename sample links (instant, metadata-only operations)
31 + - Breadcrumb navigation with clickable path segments
32 + - Keyboard nav: j/k or arrows, Enter to open, Backspace to go up
33 + - Directories always sort before files
34 + - Cascade delete (deleting a VFS removes all its nodes)
35 + - Background right-click context menu: New Folder, Import Folder, Deselect
36 +
37 + ### Audio Analysis
38 + - Configurable analysis pipeline (enable/disable each type):
39 + - Loudness: peak dB, RMS dB, LUFS (bs1770 ITU-R BS.1770-4)
40 + - BPM detection (stratum-dsp, requires 2+ seconds of audio)
41 + - Musical key detection
42 + - Spectral: centroid, flatness, rolloff, zero-crossing rate, onset strength
43 + - Loop detection: cross-correlation + beat alignment
44 + - Classification: rule-based into 12 categories
45 + - Waveform generation: downsampled peak pairs for display
46 + - Background worker thread (non-blocking UI)
47 + - Progress bar with cancel support
48 + - Re-analyze previously analyzed samples
49 +
50 + ### Classification (12 Categories)
51 + Kick, Snare, HiHat, Cymbal, Percussion, Bass, Vocal, Synth, Pad, FX, Noise, Music
52 +
53 + ### Tag System
54 + - Hierarchical dot-notation tags (e.g., `genre.electronic.house`, `instrument.drum.kick`)
55 + - Auto-suggested tags from analysis with confidence scores and reasoning:
56 + - Classification, BPM, genre hint, key, loop/oneshot, loudness character
57 + - Review suggestions screen: accept/reject per-suggestion with Accept All / Reject All
58 + - Tag entire folders during import
59 + - Add/remove tags manually in detail panel
60 + - Bulk tagging across multi-selection (Cmd+T)
61 +
62 + ### Collections
63 + - Cross-VFS sample groupings for quick access
64 + - Create, rename, delete collections
65 + - Add/remove samples from any VFS
66 +
67 + ### Smart Folders
68 + - Saved filter queries stored as JSON in the database
69 + - Sidebar section with collapsible list
70 + - Click to apply saved filter instantly
71 +
72 + ### Search + Filtering
73 + - Text search by sample name (folder or global scope, 500 result limit)
74 + - Filter panel: BPM range, duration range, key selector (with compatibility mode), classification checkboxes, tag prefix filter
75 + - Filters combine with AND logic
76 + - `/` to focus search bar
77 + - Similarity search: weighted Euclidean distance on analysis vectors ("Find Similar" in context menu)
78 + - Near-duplicate detection: VP-tree indexed peak envelope fingerprint comparison ("Find Duplicates" in context menu)
79 +
80 + ### Preview Playback
81 + - Double-click or Space to play/pause
82 + - Plays through system audio via cpal
83 + - Selecting a different sample switches playback
84 + - Status footer shows currently playing filename
85 +
86 + ### MIDI Instrument Mode
87 + - Chromatic mode: play any sample across the keyboard with pitch shifting
88 + - Multi-sample mode: assign samples to key zones with velocity layers
89 + - ADSR envelope (per-sample linear ramps)
90 + - 8-voice polyphony with oldest-note stealing
91 + - 3-octave piano keyboard UI with click-to-set root note
92 + - Drag samples from file list to keyboard to create zones
93 + - Toggle with I key; panel appears below file list
94 +
95 + ### Native Drag-Out
96 + - Drag samples from the file list to Finder, Desktop, or DAW (REAPER, Ableton, Logic, etc.)
97 + - macOS: NSDraggingSession via AppKit (deferred to run loop, session lifecycle callbacks)
98 + - Windows: OLE DoDragDrop with CF_HDROP (blocking modal)
99 + - Temporary symlinks provide friendly filenames (content store uses hash names)
100 + - Multi-file drag (all selected samples)
101 + - 4-pixel dead zone prevents accidental drags during clicks
102 +
103 + ### Export
104 + - Export VFS subtree to filesystem (preserving directory structure or flattened)
105 + - Device export with 14 bundled hardware sampler profiles:
106 + - Dirtywave M8, Elektron Digitakt, Digitakt II, Octatrack, Model:Samples
107 + - Roland SP-404 MKII, Akai MPC, Polyend Tracker, Synthstrom Deluge
108 + - 1010music Blackbox, Korg Volca Sample 2, TE OP-1
109 + - Novation Circuit Rhythm, NI Maschine+
110 + - Profiles handle sample rate conversion, bit depth, channel count, filename sanitization, file size limits
111 + - Rhai scripting engine for custom/community export profiles
112 + - Export dialog with device picker, destination, preview, progress
113 + - Metadata sidecar option (.audiofiles.json per sample)
114 +
115 + ### Cloud Sync (MNW SyncKit)
116 + - Optional cloud sync via Makenotwork accounts
117 + - E2E encrypted (ChaCha20-Poly1305 + Argon2)
118 + - Push/pull changelog sync with conflict resolution
119 + - Per-VFS toggle for syncing audio files vs metadata-only
120 + - Cloud-only samples: visible with cloud icon, metadata searchable, no local blob required
121 + - Auto-sync scheduler (configurable interval: 5/15/30/60 min)
122 + - PKCE OAuth authentication flow
123 +
124 + ### OTA Updates
125 + - Background update checker (custom reqwest-based, not Tauri)
126 + - Consent dialog: Download (opens browser) or Not Now
127 + - Non-intrusive bottom-right overlay notification
128 +
129 + ### File List + Sorting
130 + - Multi-column table: Name, BPM, Key, Duration, Classification (configurable)
131 + - Click column header to sort (ascending, descending, reset)
132 + - Directories always first regardless of sort
133 +
134 + ### Selection
135 + - Single-click, Cmd+Click (toggle), Shift+Click (range)
136 + - Shift+Arrow to extend selection
137 + - Cmd+A to select all
138 + - Keyboard navigation: j/k or arrow keys
139 +
140 + ### Bulk Operations
141 + - Bulk delete, move, rename, tag (add/remove) across multi-selection
142 + - 50-deep undo stack (Cmd+Z)
143 + - Rename pattern engine: {name}, {ext}, {bpm}, {key}, {class}, {duration}, {n}/{nn}/{nnn} tokens
144 + - Live preview of rename results before applying
145 + - Bulk modal UIs: tag editor (Cmd+T), directory picker, pattern builder (F2)
146 +
147 + ### Detail Panel
148 + - Waveform display with click-to-seek (rendered from pre-generated peak data)
149 + - Metadata: duration, sample rate, channels, peak dB, RMS dB, LUFS, BPM, key, classification
150 + - Tag editor (add/remove chips)
151 + - Auto-hides when window is narrow (< 700px)
152 + - Resizable (200-400px)
153 +
154 + ### Context Menus
155 + - Sample: Preview, Find Similar, Find Duplicates, Play as Instrument, Copy Path, Export, Delete
156 + - Folder: Open, Rename, Export, Delete
157 + - Multi-select: Tag, Move to, Rename, Copy Paths, Delete
158 + - Background (empty space): New Folder, Import Folder, Deselect
159 +
160 + ### Keyboard Shortcuts
161 + - j/k or arrows: navigate
162 + - Enter or Right: open directory / preview sample
163 + - Backspace or Left: go up
164 + - Space: play/pause
165 + - /: focus search
166 + - I: toggle instrument panel
167 + - S: toggle sidebar
168 + - D: toggle detail panel
169 + - Cmd+A: select all
170 + - Cmd+Z: undo
171 + - Cmd+T: bulk tag
172 + - F1: help overlay
173 + - F2: bulk rename
174 + - Delete: delete (with confirmation)
175 + - Escape: close dialog / clear search
176 +
177 + ### Themes
178 + - 17 bundled themes (audiofiles default + 16 community themes)
179 + - Dark: audiofiles, Tokyo Night, Catppuccin Mocha, Dracula, Nord, Gruvbox Dark, Rose Pine, Everforest, Solarized Dark, Kanagawa
180 + - Light: Catppuccin Latte, Ayu Light, Flatwhite, Neobrute, Gruvbox Light, Rose Pine Dawn
181 + - High Contrast: High Contrast
182 + - Custom themes: drop .toml files into `~/.config/audiofiles/themes/`
183 + - Theme selector in toolbar
184 +
185 + ### Standalone App
186 + - Native desktop window (eframe, 900x600 default, 600x400 minimum)
187 + - System audio output via cpal
188 + - Drag-and-drop files and folders (import)
189 + - Native drag-out to Finder/DAW (export)
190 + - CLI argument import
191 + - macOS app bundle with squircle icon, file associations (.wav, .flac, .mp3, .ogg, .aiff)
192 + - System tray icon with Show Window / Toggle Playback / Quit
193 + - OTA update notifications
194 +
195 + ### Data Storage
196 + - SQLite database (schema v8, 11 tables, migrations)
197 + - Content-addressed sample store (files named by SHA-256 hash)
198 + - Waveform data cached in database
199 + - Database local to the app
200 +
201 + ### Platforms
202 + - macOS (primary, signed + notarized)
203 + - Windows, Linux
204 +
205 + ## Price
206 +
207 + Free (alpha). Source-available (PolyForm Noncommercial 1.0.0).
208 +
209 + ## Tags
210 +
211 + Music Production, Samples, Audio, DAW Plugin, Sample Manager, Hardware Sampler, Rust
212 +
213 + ---
214 +
215 + ## Technical Reference
216 +
217 + ### Tech Stack
218 +
219 + - **Language:** Rust (2021 edition), pure Rust with zero `unsafe` in production code
220 + - **Audio Decoding:** Symphonia 0.5.5
221 + - **Analysis:** stratum-dsp 1.0 (BPM/key), bs1770 (LUFS), realfft 3.5 (spectral)
222 + - **Database:** SQLite via rusqlite 0.31 (bundled, schema v8)
223 + - **Hashing:** SHA-256 (content-addressed storage)
224 + - **GUI:** eframe (egui windowed) + cpal 0.15 (audio output)
225 + - **Export Scripting:** Rhai 1.21 (sandboxed: 100K ops, 32-level calls)
226 + - **Sync:** synckit-client (ChaCha20-Poly1305, Argon2, reqwest)
227 + - **Font:** Recursive Mono Linear Bold (logo)
228 +
229 + **Workspace:** 5 crates — `audiofiles-core` (sync-only library), `audiofiles-browser` (egui UI), `audiofiles-app` (standalone desktop), `audiofiles-sync` (cloud sync), `audiofiles-rhai` (export scripting)
230 +
231 + ### Testing
232 +
233 + - **560 tests** across the workspace
234 + - Core (audiofiles-core): database, store, VFS, tags, analysis, search, export, instrument, smart folders, rename, fingerprint, similarity
235 + - Browser (audiofiles-browser): state orchestration (selection, bulk ops, import/analysis, navigation, rename, column config), theme parsing, preview decoding, export pipeline
236 + - Integration: full pipeline (import, analyze, search, tag, export), analysis roundtrip, combined filter search
237 +
238 + ### Status
239 +
240 + All pre-beta phases complete (0-9F). 560 tests. Grade A (all dimensions). Ready for private alpha testing.
241 +
242 + ---
243 +
244 + ## Appendix: Building from Source on Linux
245 +
246 + audiofiles is built entirely in Rust and compiles on Linux without modification. The source is available on sourcehut.
247 +
248 + ### Prerequisites
249 +
250 + - Rust toolchain (stable, 1.75+): https://rustup.rs
251 + - System packages for audio and graphics (package names for Debian/Ubuntu):
252 +
253 + ```
254 + sudo apt install build-essential pkg-config libasound2-dev libgtk-3-dev \
255 + libxcb-render0-dev libxcb-shape0-dev libxcb-xfixes0-dev libxkbcommon-dev \
256 + libssl-dev libfontconfig1-dev
257 + ```
258 +
259 + For Fedora/RHEL:
260 +
261 + ```
262 + sudo dnf install gcc pkg-config alsa-lib-devel gtk3-devel \
263 + libxcb-devel libxkbcommon-devel openssl-devel fontconfig-devel
264 + ```
265 +
266 + For Arch:
267 +
268 + ```
269 + sudo pacman -S base-devel alsa-lib gtk3 libxcb libxkbcommon openssl fontconfig
270 + ```
271 +
272 + ### Clone
273 +
274 + audiofiles depends on the `synckit-client` crate via a relative path. Clone both repositories side by side:
275 +
276 + ```
277 + git clone https://git.sr.ht/~maxmj/synckit-client
278 + git clone https://git.sr.ht/~maxmj/audiofiles
279 + ```
280 +
281 + Your directory should look like:
282 +
283 + ```
284 + parent/
285 + synckit-client/
286 + audiofiles/
287 + ```
288 +
289 + ### Build the Standalone App
290 +
291 + ```
292 + cd audiofiles
293 + cargo build --release -p audiofiles-app
294 + ```
295 +
296 + The binary is at `target/release/audiofiles-app`. Run it directly or copy it to a location in your `$PATH`.
297 +
298 + ### Run Tests
299 +
300 + ```
301 + cargo test --workspace
302 + ```
303 +
304 + ### Sync (Optional)
305 +
306 + Cloud sync requires a Makenotwork account. Set the environment variables before launching:
307 +
308 + ```
309 + AF_SYNC_SERVER_URL=https://makenot.work AF_SYNC_API_KEY=your-key audiofiles-app
310 + ```
311 +
312 + Without these variables, the app runs fully offline with all features except sync.
A docs/todo.md +123
@@ -0,0 +1,123 @@
1 + # audiofiles TODO
2 +
3 + ## Status
4 + Done: All pre-beta phases (0-8 incl. system tray, UX Overhaul, 7B MIDI instrument, 9A-9F Cloud Sync, Collections). Two-layer ML classifier deployed. 610 tests. DB v11. All audit items resolved. Theme audit complete (17 themes bundled). Native drag-out implemented (macOS/Windows). VFS symlink mirror. OTA updater. Brand rename complete. Standalone-only (plugin/IPC/xtask removed). VP-tree indexes for similarity and fingerprint search. Tag tree sidebar (dot-separated tags as collapsible folders). Zero audit cold spots. Analysis engine overhauled: rayon parallel worker, 30s analysis cap, 16-class classifier (added Ambience/Impact/Foley/Texture), MFCC feature extraction, 35-feature vector. Two-layer ML classification: Layer 1 rule-based broad classifier (Drum/Bass/Vocal/Synth/etc.), Layer 2 Random Forest (200 trees, 7.4MB embedded model) for drum sub-classification. 94.4% strict / 95.6% lenient on 4343 labeled drum samples.
5 +
6 + **Scope:** Pre-beta coding complete. ML classifier done. Sample forge features next.
7 +
8 + Completed work archived in `docs/archive/af_todo_done.md`.
9 +
10 + ---
11 +
12 + ## Architecture
13 + - Standalone desktop app (eframe + egui + cpal)
14 + - Core library sync-only (no tokio), SQLite via rusqlite
15 + - Content-addressed flat store (SHA-256), multiple VFS trees
16 + - Audio: symphonia, stratum-dsp (BPM/key), bs1770 (LUFS), realfft (spectral)
17 + - Rhai scripting for export/import plugins
18 +
19 + ## Phase 7: Export — Device Reference
20 +
21 + | Device | Rate | Depth | Channels | Format |
22 + |--------|------|-------|----------|--------|
23 + | Dirtywave M8 | 44.1kHz | 8/16/24 | Mono | WAV |
24 + | Elektron Digitakt | 48kHz | 16-bit | Mono | WAV |
25 + | Elektron Digitakt II | 48kHz | 16-bit | Mono/Stereo | WAV |
26 + | Roland SP-404 MKII | 44.1kHz | 16-bit | Mono/Stereo | WAV |
27 + | Akai MPC | 44.1kHz | 16/24-bit | Mono/Stereo | WAV |
28 + | Polyend Tracker | 44.1kHz | 16/24/32 | Mono | WAV |
29 + | Synthstrom Deluge | 44.1kHz | 16/24-bit | Mono/Stereo | WAV/AIFF |
30 + | 1010music Blackbox | 48kHz | 16/24/32 | Mono/Stereo | WAV |
31 + | Korg Volca Sample 2 | 31.25kHz | 16-bit | Mono | WAV |
32 + | TE OP-1 | 44.1kHz | 16/24-bit | Mono/Stereo | AIFF/WAV |
33 +
34 + ## Phase 8: Remaining
35 + - [ ] Windows standalone installer (Inno Setup or WiX)
36 + - [ ] Code-sign Windows binaries
37 + - [ ] Test standalone on Windows
38 + - [ ] Linux AppImage packaging
39 +
40 + ## Phase 10: Plugin Processing
41 + Apply CLAP plugins to samples as a lightweight host. Destructive or render-to-new-file workflow.
42 +
43 + Research complete (CLAP via clack-host, VST3 deferred).
44 +
45 + ### Implementation
46 + - [ ] Add `clack-host` + `clack-extensions` git dependencies (pin commit hash)
47 + - [ ] Plugin scanner: walk standard CLAP paths, cache descriptors in SQLite
48 + - [ ] Plugin host engine: load → init → activate → process chunks → deactivate → destroy
49 + - [ ] Parameter discovery: query plugin params, render as egui sliders/knobs
50 + - [ ] Render workflow: process sample → save as new sample in content-addressed store
51 + - [ ] Plugin state save/load: store state blobs in SQLite for preset recall
52 + - [ ] Chain support: multiple plugins in series
53 + - [ ] Wet/dry mix control + A/B preview (original vs processed)
54 +
55 + ## Phase 11: Destructive Edits
56 + Built-in sample transformations without external plugins.
57 +
58 + - [ ] Trim (set start/end points, render to new sample)
59 + - [ ] Fade in/out (linear, logarithmic, S-curve)
60 + - [ ] Normalize (peak or LUFS target)
61 + - [ ] Reverse
62 + - [ ] Gain adjust (dB slider)
63 + - [ ] DC offset removal
64 + - [ ] Silence insert/remove
65 + - [ ] Mono-to-stereo / stereo-to-mono conversion
66 +
67 + ## Phase 12: Chop Engine
68 + Slice samples into pieces for drum kits and one-shots.
69 +
70 + - [ ] Waveform view with draggable slice markers
71 + - [ ] Auto-chop by transient detection (reuse existing onset analysis)
72 + - [ ] Auto-chop by equal divisions (2, 4, 8, 16, 32 slices)
73 + - [ ] Auto-chop by BPM grid (reuse stratum-dsp BPM detection)
74 + - [ ] Export slices as individual samples into VFS folder
75 + - [ ] Batch chop: apply same slice template to multiple samples
76 +
77 + ## Phase 13: Resample and Time-Stretch
78 + Sample rate conversion and time/pitch manipulation.
79 +
80 + - [ ] Resample to target rate (rubato already in deps — 22.05, 44.1, 48, 96 kHz)
81 + - [ ] Bit-depth conversion (8, 16, 24, 32-bit)
82 + - [ ] Time-stretch without pitch change (rubato or new algorithm)
83 + - [ ] Pitch-shift without time change
84 + - [ ] Varispeed (pitch + time together, tape-style)
85 +
86 + ## Phase 14: Layer and Stack
87 + Combine multiple samples into composites.
88 +
89 + - [ ] Layer: mix N samples with per-layer gain/pan, render to new sample
90 + - [ ] Concatenate: join samples end-to-end with crossfade options
91 + - [ ] Round-robin export: distribute layers into numbered one-shots for sampler instruments
92 +
93 + ## Phase 15: Batch Forge
94 + Apply operations to multiple samples at once.
95 +
96 + - [ ] Batch normalize (peak or LUFS target across selection)
97 + - [ ] Batch resample (convert selection to target rate/depth)
98 + - [ ] Batch trim silence (auto-detect and trim leading/trailing silence)
99 + - [ ] Batch apply plugin chain (run same plugin + params across selection)
100 + - [ ] Batch rename (pattern-based: prefix, suffix, numbering)
101 +
102 + ## Phase 16: Snapshot History
103 + Non-destructive processing history per sample.
104 +
105 + - [ ] Store processing chain as metadata (operations + parameters)
106 + - [ ] Undo to any previous snapshot (content-addressed store makes this free — originals never deleted)
107 + - [ ] Compare snapshots side-by-side (A/B waveform + playback)
108 + - [ ] Fork: branch from any snapshot to try different processing paths
109 +
110 + ## Shared Code Extraction (Cross-Project)
111 + - [ ] Theme loading: deduplicate TOML theme parser across GO/BB/AF
112 + - [ ] Rhai host functions: deduplicate plugin runtime setup across GO/BB/AF
113 + - [ ] FTS5 query building: extract shared SQLite full-text search utilities
114 +
115 + ## Key Paths
116 + ```
117 + crates/audiofiles-core/ Core library (store, VFS, DB, analysis, search)
118 + crates/audiofiles-browser/ egui browser UI
119 + crates/audiofiles-app/ Desktop app (eframe + cpal)
120 + crates/audiofiles-core/src/export/ Export engine
121 + crates/audiofiles-rhai/ Rhai plugin runtime
122 + plugins/bundled/ Device export plugins
123 + ```