A modular audio synthesis library using Arrow-style combinators and graph-based patching.
- Project Status
- Why Quiver?
- Features
- Architecture
- Quick Start
- Documentation
- Examples
- Development
- Contributing
- License
Quiver is pre-1.0 and under active development. There are no published releases yet β depend on it via git if you want to experiment. The three-layer architecture is in place and the module set is broad, but the public API is still evolving and may change between commits without notice. Expect rough edges; feedback and contributions are very welcome.
Traditional audio synthesis libraries often force you to choose between:
- Low-level control with verbose, error-prone code
- High-level convenience that hides the signal flow
Quiver gives you both. Inspired by category theory and modular synthesizers, it provides:
| Approach | Benefit |
|---|---|
| π Arrow Combinators | Compose modules like functions with type-safe operators |
| ποΈ Patch Graph | Visual, intuitive signal routing like hardware modular synths |
| ποΈ Analog Modeling | Authentic warmth with component drift and saturation |
| β‘ Zero Allocation | Real-time safe with predictable performance |
// Compose modules functionally with Arrow-style combinators
let synth = oscillator >>> filter >>> amplifier;
// Or patch them like hardware, jack to jack
patch.connect(vco.out("saw"), vcf.in_("in")).unwrap();Quiver's niche is an embeddable, Rust-first modular-synth graph with hardware-style
semantics β a no_std core plus first-class WebAssembly bindings.
| Quiver | FunDSP | VCV Rack | Glicol / Web Audio | |
|---|---|---|---|---|
| Form | Rust library | Rust library | Desktop application | DSL / browser graph |
| Model | Modular graph + Arrow combinators | Combinator DSP graphs | Patchable rack of plugins | Live-coding / node graph |
| Semantics | Hardware-style ports (V/Oct, gate, CV, normalled jacks) | Signal-flow operators | Eurorack-style modules | Audio nodes / DSL |
no_std core |
β | partial | β | β |
| WASM bindings | β (first-class) | via wasm-pack | β | β (browser-native) |
| Zero-alloc audio path | β | β | n/a | n/a |
If you want a signal-flow combinator DSP library, FunDSP is excellent and an inspiration. If you want a finished desktop instrument, use VCV Rack. Quiver is for building modular instruments and tools β in native apps, plugins, or the browser β from Rust.
- π Typed Combinators: Compose audio modules using category-theory-inspired operators (
>>>,***,&&&) - ποΈ Graph-Based Patching: Build complex synthesizer patches with a flexible node/cable system
- ποΈ Analog Modeling: Realistic VCO drift, filter saturation, and component tolerances
- πΉ Polyphony: Built-in voice allocation with multiple algorithms
- β‘ SIMD Optimization: Optional vectorized processing for performance-critical applications
- πΎ Serialization: Save and load patches as JSON
- π§
no_stdSupport: Run on embedded systems and WebAssembly targets
Quiver is built in three composable layers:
graph TD
subgraph "Layer 3: Patch Graph"
VCO[VCO] --> VCF[VCF]
VCF --> VCA[VCA]
VCA --> Output[Output]
VCO --> LFO[LFO]
LFO --> VCF
ADSR[ADSR] --> VCA
end
subgraph "Layer 2: Port System"
Ports["SignalKind: Audio | V/Oct | Gate | Trigger | CV<br/>ModulatedParam: Linear | Exponential | V/Oct ranges"]
end
subgraph "Layer 1: Typed Combinators"
Combinators["Chain (>>>) | Parallel (***) | Fanout (&&&) | Feedback"]
end
Output ~~~ Ports
Ports ~~~ Combinators
Layer 1 - Combinators: Functional composition with type-safe signal flow Layer 2 - Ports: Rich metadata for inputs/outputs with modulation support Layer 3 - Graph: Visual patching with cables, mixing, and normalled connections
Add Quiver to your Cargo.toml (the package is published as quiver-dsp
because the bare name quiver was taken on crates.io; the library name is
still quiver, so imports are use quiver::...):
[dependencies]
quiver-dsp = "0.2"| Feature | Default | Description |
|---|---|---|
std |
Yes | Full functionality including OSC, plugins, visualization (implies alloc) |
alloc |
No | Serialization, presets, and I/O for no_std + heap environments |
simd |
No | SIMD vectorization for block processing (works with any tier) |
wasm |
No | WebAssembly bindings (wasm-bindgen) + TypeScript types (tsify); implies alloc. Powers packages/@quiver-dsp/wasm and the browser synth demo |
Quiver supports three tiers for different environments. All tiers are no_std
but require a global allocator β the core graph uses Box/Vec/String, so
there is no allocator-free tier:
# Tier 1: Core DSP only (no_std, heap required β bring your own #[global_allocator])
quiver-dsp = { version = "0.2", default-features = false }
# Tier 2: With serialization & presets (WASM web apps)
quiver-dsp = { version = "0.2", default-features = false, features = ["alloc"] }
# Tier 3: Full std (desktop apps, default)
quiver-dsp = "0.2"| Tier | DSP | Serialize | Presets | I/O | OSC/Plugins | Visual |
|---|---|---|---|---|---|---|
| Core | β | |||||
alloc |
β | β | β | β | ||
std |
β | β | β | β | β | β |
Build a subtractive synthesizer voice β VCO β VCF β VCA, shaped by an ADSR envelope:
use quiver::prelude::*;
fn main() {
// Create a patch at CD-quality sample rate.
let sr = 44_100.0;
let mut patch = Patch::new(sr);
// Add modules β each `add` takes a name and returns a `NodeHandle`
// used to reference that module's ports.
let vco = patch.add("vco", Vco::new(sr));
let vcf = patch.add("vcf", Svf::new(sr));
let vca = patch.add("vca", Vca::new());
let env = patch.add("env", Adsr::new(sr));
let out = patch.add("out", StereoOutput::new());
// Patch cables jack-to-jack: VCO β VCF β VCA β stereo out.
// `in_()` is spelled with a trailing underscore because `in` is a Rust keyword.
patch.connect(vco.out("saw"), vcf.in_("in")).unwrap();
patch.connect(vcf.out("lp"), vca.in_("in")).unwrap();
patch.connect(vca.out("out"), out.in_("left")).unwrap();
patch.connect(vca.out("out"), out.in_("right")).unwrap();
// The envelope modulates both the filter cutoff and the amplitude.
patch.connect(env.out("env"), vcf.in_("cutoff")).unwrap();
patch.connect(env.out("env"), vca.in_("cv")).unwrap();
// Select the output module, then compile before processing (required).
patch.set_output(out.id());
patch.compile().unwrap();
// Advance the patch one sample at a time; each `tick()` returns stereo audio.
let (left, right) = patch.tick();
println!("first sample: {left}, {right}");
}| Resource | Description |
|---|---|
| π User Guide | Comprehensive tutorials and concepts |
| ποΈ Live Playground | The full synth engine (WASM) playable in your browser |
| π API Reference | Rustdoc documentation |
| π‘ Examples | Runnable example patches |
| πΊοΈ DEVELOPMENT.md | Architecture decisions and roadmap |
Run the examples to hear Quiver in action:
# Simple patch demo
cargo run --example simple_patch
# FM synthesis tutorial
cargo run --example tutorial_fm
# Polyphonic synth
cargo run --example tutorial_polyphony
# See all examples
cargo run --example| Example | Description |
|---|---|
simple_patch |
Basic VCO β VCF β VCA signal chain |
tutorial_fm |
FM synthesis with modulator/carrier |
tutorial_polyphony |
Polyphonic voice allocation |
tutorial_subtractive |
Classic subtractive synthesis |
howto_midi |
MIDI input handling |
# Setup development environment (installs tools and git hooks)
make setup
# Run all checks (format, lint, test)
make check
# Run tests with coverage (80% threshold)
make coverage
# Format and lint
make fmt lint
# Generate changelog
make changelog
# See all available commands
make helpSee DEVELOPMENT.md for the development roadmap and architecture decisions.
Contributions are welcome! Please read our Contributing Guidelines before submitting a PR.
| Area | Examples |
|---|---|
| π DSP Algorithms | Filter models, oscillator antialiasing, effects |
| π§ͺ Testing | Audio comparison tests, performance benchmarks |
| π Documentation | Tutorials, examples, API docs |
| ποΈ Modules | Classic hardware module implementations |
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-filter) - Make your changes
- Run checks (
make check) - Commit with conventional commits
- Open a Pull Request
Look for issues labeled good first issue to get started!
This project is licensed under the MIT License - see the LICENSE file for details.