// ZPWR-CRATE — SHARED SAMPLE-LIBRARY CRATE BROWSER

private internal library · rlib + staticlib + cdylib · 19 crate_* C ABI exports · native rlib for Audio-Haxor · C ABI for zpwr-daw · one SQLite/FTS5 schema

Report GitHub
// Color scheme

>_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

Scanparallel 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
IndexSQLite 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')
Browsecrate_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_freeopen a database handle; release it
crate_string_freefree any char* a crate_* function returned
crate_scanscan + index a JSON array of sample root paths
crate_scan_unifiedunified incremental scan driver across domains
crate_scan_pluginsscan installed audio plugins into the library
crate_scan_midiscan MIDI files into the library
crate_scan_videoscan video assets into the library
crate_queryfaceted browse — JSON params in, JSON result out
crate_browse_queryunified-browser query across domains, as JSON
crate_browse_facetsunified-browser facets as JSON
crate_facetsfilter-bar facets (packs, manufacturers, keys) as JSON
crate_category_countscategory histogram as JSON
crate_genre_rules_reportgenre-rules report as JSON
crate_favorite_list / crate_favorite_toggleread / toggle favorited pack ids
crate_waveform_peaksmin/max peak envelope for a sample at a given width, as JSON
crate_loop_region_get / crate_loop_region_setread / store a sample's loop region

Storage & schema

WAL + read poolDatabase::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 trigramaudio_samples_fts is a contentless FTS5 virtual table with the trigram tokenizer (substring search); its rowid links to audio_samples.id
REGEXPa SQLite user function backed by a cached regex::Regex map, matching name/path like JS new RegExp(pat, 'i')
IncrementalIncrementalDirState records a per-directory mtime snapshot under the "unified" domain so rescans skip unchanged trees
Migrations15 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.rsschema migrations, pool, insert_audio_batch, crate_* queries, incremental state
src/audio_scanner.rsaudio header decode + metadata extraction (verbatim)
src/unified_walker.rsIncrementalDirState + walk helpers
src/audio_extensions.rs / src/scanner_skip_dirs.rs / src/path_norm.rsextension set, build/cache skip dirs, path normalization (verbatim)
src/ffi.rsthe C ABI (crate_* exports)
include/zpwr_crate.hhand-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