>_ZPWR-CRATE
One source of truth for the sample library. The shared crate browser behind the MenkeTechnologies audio stack — filesystem + SQLite/FTS5 sample scanning and the faceted "crate" query layer. The scanner, schema and query code are lifted verbatim from the Audio-Haxor backend (src-tauri/src/) with the Tauri glue stripped, so both front ends run byte-for-byte identical indexing and browsing against the same database.
Two consumers, one library
| Audio-Haxor (Tauri / Rust) | links it natively as an rlib and calls the API directly |
| zpwr-daw (JUCE / C++) | links libzpwr_crate.a (or the cdylib) over the C ABI in include/zpwr_crate.h |
Schema versions match Audio-Haxor's migration numbers, so opening an existing Audio-Haxor database is a no-op — it is already past those versions.
Scan · Index · Browse
| Scan | parallel rayon walk for audio samples (.wav .mp3 .aiff .flac .ogg .m4a .aac .opus .rex .rx2 .sf2 .sfz); duration / channels / sample-rate / bit-depth via header parse + symphonia; symlink + firmlink dedup; incremental rescans from a per-directory mtime snapshot |
| Index | SQLite with a contentless FTS5 (trigram) table + a canonical audio_library row per path; WAL journal, a writer + round-robin read pool, and a REGEXP user function matching JS new RegExp(pat, 'i') |
| Browse | crate_query filters by category (incl. parent node), pack, manufacturer, BPM range, key, loop/one-shot, favorite packs, name/path search (LIKE or regex), with pagination — plus crate_facets, crate_category_counts, and favorite-pack toggling |
Native (Rust) usage
Audio-Haxor links the rlib and calls the API directly. scan drives the walk + index; Database::crate_query serves the browse side.
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use zpwr_crate::{Database, CrateQueryParams, scan};
let db = Database::open(std::path::Path::new("/path/to/crate.db"))?;
let roots = vec![std::path::PathBuf::from("/Users/me/Samples")];
let n = scan(&db, &roots, Arc::new(AtomicBool::new(false)), None, |total| {
println!("inserted {total}");
})?;
let res = db.crate_query(&CrateQueryParams {
category: Some("Drums".into()),
bpm_min: Some(120),
bpm_max: Some(130),
limit: 200,
..Default::default()
})?;
println!("{} of {}", res.rows.len(), res.total);
CrateQueryParams::limit defaults to 200 only when deserialized from JSON (the FFI path); native callers constructing the struct should set limit themselves.
C ABI usage (zpwr-daw)
zpwr-daw links libzpwr_crate.a (or the cdylib) and includes include/zpwr_crate.h — hand-written, no cbindgen. Structured data crosses as UTF-8 JSON.
#include "zpwr_crate.h"
CrateHandle *h = crate_open("/path/to/crate.db");
crate_scan(h, "[\"/Users/me/Samples\"]", NULL, NULL);
char *json = crate_query(h, "{\"category\":\"Drums\",\"limit\":200}");
/* ... parse json ... */
crate_string_free(json);
crate_free(h);
Every returned char* is owned by Rust — release it with crate_string_free. Release the handle with crate_free.
C ABI surface
crate_open / crate_free | open a database handle; release it |
crate_string_free | free any char* a crate_* function returned |
crate_scan | scan + index a JSON array of sample root paths |
crate_scan_unified | unified incremental scan driver across domains |
crate_scan_plugins | scan installed audio plugins into the library |
crate_scan_midi | scan MIDI files into the library |
crate_scan_video | scan video assets into the library |
crate_query | faceted browse — JSON params in, JSON result out |
crate_browse_query | unified-browser query across domains, as JSON |
crate_browse_facets | unified-browser facets as JSON |
crate_facets | filter-bar facets (packs, manufacturers, keys) as JSON |
crate_category_counts | category histogram as JSON |
crate_genre_rules_report | genre-rules report as JSON |
crate_favorite_list / crate_favorite_toggle | read / toggle favorited pack ids |
crate_waveform_peaks | min/max peak envelope for a sample at a given width, as JSON |
crate_loop_region_get / crate_loop_region_set | read / store a sample's loop region |
Storage & schema
| WAL + read pool | Database::open keeps one primary writer (Mutex<Connection>) plus a round-robin pool of read-only handles sized from num_cpus (min 2); the writer is reserved for migrations + cache writes so reads never block on it |
| FTS5 trigram | audio_samples_fts is a contentless FTS5 virtual table with the trigram tokenizer (substring search); its rowid links to audio_samples.id |
| REGEXP | a SQLite user function backed by a cached regex::Regex map, matching name/path like JS new RegExp(pat, 'i') |
| Incremental | IncrementalDirState records a per-directory mtime snapshot under the "unified" domain so rescans skip unchanged trees |
| Migrations | 15 versioned migrations v1 / v2 / v6 / v8 / v9 / v10 / v12 / v14 / v15 / v16 / v17 / v20 / v24 / v27 / v28; the subset v1 / v9 / v10 / v12 / v14 / v24 / v27 is aligned with Audio-Haxor; the sample_analysis pipeline is separate — this crate owns the schema + read side and creates the analysis tables so browser joins resolve |
Build & test
cargo build # produces rlib + staticlib + cdylib cargo test # headless; scans temp dirs, exercises the query layer cargo fmt --all --check cargo clippy --all-targets -- -D warnings
Builds and tests on Linux x86_64 and macOS aarch64 (CI covers both). rusqlite is bundled, so no system SQLite is required.
Source layout
src/db.rs | schema migrations, pool, insert_audio_batch, crate_* queries, incremental state |
src/audio_scanner.rs | audio header decode + metadata extraction (verbatim) |
src/unified_walker.rs | IncrementalDirState + walk helpers |
src/audio_extensions.rs / src/scanner_skip_dirs.rs / src/path_norm.rs | extension set, build/cache skip dirs, path normalization (verbatim) |
src/ffi.rs | the C ABI (crate_* exports) |
include/zpwr_crate.h | hand-written C header (no cbindgen) |
The audio stack
zpwr-crate is the shared data layer of the MenkeTechnologies audio applications. Browse the rest via the MenkeTechnologiesMeta umbrella repo:
- Audio-Haxor — Tauri v2 desktop app; links zpwr-crate as an rlib
- zpwr-daw — DAW arranger + the 4th patch-graph plugin; links the C ABI
- zpwr-synth — JUCE modular patch-graph synthesizer
- zpwr-fx — JUCE modular multi-effects plugin
- zpwr-midi-fx — JUCE modular MIDI-effects plugin
- zpwr-patch-core — signal-agnostic modular patch graph