Open-source audio framework for Rust
Tested, not promised.
Manguebyte builds audio plugins and applications in Rust: DSP and instruments, metering, MIDI, files, devices, plugin editors and hosting, and native CLAP, VST 3 and LV2 export from one line each. Its goal is to be for Rust what JUCE is for C++, and then to go further. Every claim on this site links to the test that proves it.
Young project. The API will change before 1.0. Plugin editors open in Win32 windows and are tested in CI, but nobody has opened one in a host by hand yet. See what is missing.
Green on every commit
These are real tests and validator results, not a mock-up. All of them passed in CI at commit c5835bf. Follow any line to the code.
cargo test --workspace
- pluginautomation_
lands_ okon_ its_ exact_ frame_ and_ updates_ the_ parameter - manguebytethe_
song_ okis_ the_ same_ whatever_ the_ block_ size - dspprocessors_
do_ oknot_ use_ the_ heap - pluginchanges_
made_ okoutside_ the_ host_ reach_ the_ plugin_ as_ events - dspexpression_
and_ okmodulation_ reach_ one_ note_ and_ parameters_ reach_ all - paramsstate_
from_ okanother_ version_ loads_ as_ far_ as_ it_ can - clapnumbers_
too_ oksmall_ to_ hear_ are_ zero_ while_ the_ plugin_ runs_ and_ only_ then - hostthe_
hosted_ okplugin_ sounds_ exactly_ as_ the_ plugin_ does_ alone - analysiscases_
1_ okand_ 2_ a_ steady_ tone_ reads_ its_ level_ on_ all_ three_ scales
01
Four things it proves on every commit
Matching JUCE is the baseline. These are places where Manguebyte already does something JUCE 9.0.4 does not, each one backed by a test that runs in CI. The full list has fifteen, with a source for everything said about JUCE and the limit of every claim.
-
Automation lands on the exact sample
Every parameter change arrives with the frame it falls on and is applied on that frame: in the test harness, through CLAP, and through VST 3, where every point of every automation queue is delivered.
- In JUCE 9.0.4
- A processor reads each parameter once per block.
- Limit
- A processor chooses whether to use the timing. Reading a value once per block is still valid, and cheaper.
Proof
-
The same sound at any block size
One song rendered with six block patterns, from a steady 64 frames to an irregular
1, 511, 7, 300, 64, 2, 129, must match bit for bit. The first time this test ran, it failed, and exposed a real bug.- In JUCE 9.0.4
- Whether the sound depends on the host’s buffer size is up to each plugin.
- Limit
- It covers what follows events. A value read once per block changes at block boundaries by definition.
Proof
-
No heap on the audio thread, or CI fails
The tests replace the global allocator with one that counts. If any processor, or the CLAP wrapper, allocates or frees while processing, the build is red. It has already caught a mutex that allocates on macOS.
- In JUCE 9.0.4
- Real-time safety is a rule in the documentation.
- Limit
- A test that runs, not a compile-time proof. It catches heap use on the paths the tests exercise.
Proof
-
CLAP and VST 3 from one line each, checked by their own validators
export_clap!andexport_vst3!turn the same plugin into both formats. CI runs the CLAP project’s validator and Steinberg’s on an instrument and an effect; all 537 VST 3 tests pass on Windows, Linux and macOS. Both were also tested by hand in REAPER, andexport_lv2!adds a third format.- In JUCE 9.0.4
- CLAP export is not available natively.
- Limit
- Editors are tested in CI, not yet opened in a host by hand. LV2 is new: lilv loads it in CI, no host has run it yet. No AU or AAX.
Proof
02
A whole plugin, then one line per format
This is the example effect from the repository: a sidechain ducker. It describes itself, splits each block at its events, and is exported twice. None of the code below was written for this page.
One description
INFOandLAYOUTare constants. The same description becomes the CLAP descriptor, the VST 3 class, whose id is the same on every platform, and the LV2 plugin’s Turtle files.Events on their frame
split_at_eventsrenders up to each event, applies it and carries on, without copying or allocating. That call is all a plugin does to get sample-accurate automation.Three formats, three lines
The macros are the whole integration, and
editorhands the wrappers the plugin’s editor.cargo manguethen builds a.clap, a.vst3and an.lv2bundle in each system’s layout.
impl Plugin for Duck {
const INFO: PluginInfo = PluginInfo {
id: "org.manguebyte.duck",
name: "Mangue Duck",
vendor: "Manguebyte",
version: env!("CARGO_PKG_VERSION"),
description: "A sidechain ducker, as an example of the Manguebyte framework",
kind: PluginKind::Effect,
};
const LAYOUT: AudioLayout = AudioLayout {
inputs: 2,
outputs: 2,
sidechain: 2,
};
type Params = DuckParams;
// ... new, params and prepare are left out here
fn process(&mut self, buffer: &mut AudioBuffer<f32>, context: &ProcessContext<'_, f32>) {
self.cursor = 0;
let sidechain = context.sidechain;
split_at_events(self, buffer, context.events, Self::handle, |duck, piece| {
duck.render(piece, sidechain)
});
self.publish_reduction();
}
// ... reset
fn editor(&self) -> Option<Box<dyn EditorSpec>> {
Some(Box::new(self.editor_spec()))
}
}
manguebyte::clap::export_clap!(Duck);
manguebyte::vst3::export_vst3!(Duck);
manguebyte::lv2::export_lv2!(Duck);
c5835bf. Lines beginning // ... mark what is left out.And a test of it, with no host
Harness plays audio, a sidechain and automation into the plugin inside an ordinary unit test. This one checks that a change of depth lands on frame 1,000 of the block, and not one frame earlier.
#[test]
fn automation_lands_on_its_frame_with_audio_running_through() {
let mut harness = Harness::<Duck>::new(RATE, 256);
let input = steady(1.0, 24_000);
let loud = steady(1.0, 24_000);
// Let the follower settle, then ask for a different depth on one
// particular frame in the middle of a block.
harness.process_with_sidechain(&input, &loud);
harness.automate(24_000 + 1_000, "depth", 24.0);
let output = harness.process_with_sidechain(&input, &loud);
let before = db_to_gain(-12.0) as f32;
let after = db_to_gain(-24.0) as f32;
assert!((output.channel(0)[999] - before).abs() < 1e-4);
assert!((output.channel(0)[1_000] - after).abs() < 1e-4);
}
c5835bf, as it is in the file.03
What you get today
Twenty-three crates that work together, each usable on its own, one of them a command-line tool. manguebyte-core has no dependencies at all.
-
Core
The types everything else is built on. This crate has no dependencies at all.
-
Signal processing
A tuple of processors is a processor: the chain is resolved at compile time, with no virtual calls and no allocation.
-
Instruments
Voices ready to play, each with presets, measured for tuning, decay, velocity and accent, and all at one loudness.
-
Metering and analysis
Meters that run on the audio thread and that any thread reads without waiting.
-
Processing graph
A graph that is rewired while it plays.
-
Parameters
Parameters are atomics in a struct. There are no listeners.
-
Plugins
Write a plugin once. Export it as CLAP, VST 3 and LV2 with one line each, run it as an application, and test it with no host.
manguebyte-pluginmanguebyte-clapmanguebyte-vst3manguebyte-lv2manguebyte-standalone -
Plugin editors
Editors drawn on the CPU and opened in a child of the host’s window, on Win32 so far. Tested in CI; nobody has opened one in a host by hand yet.
manguebyte-gfxmanguebyte-uimanguebyte-windowmanguebyte-gui -
Hosting plugins
Load plugins made by anyone and run them as processors.
-
Sampler
An SFZ player, open so that any program can play the instruments it is given.
-
In the browser
An engine for a browser’s AudioWorklet. Tested natively and in Node.js, not yet in a browser’s audio thread under load.
-
MIDI
MIDI 1.0 and 2.0, with timing kept to the sample.
-
Audio files
Read and write whole files or block by block, from disk to the audio thread.
-
Open Sound Control
Messages from controllers and live-coding programs, on the frame they ask for.
-
Devices
Sound cards and MIDI ports.
-
Command-line tool
From an empty folder to an installed plugin.
04
Where JUCE is ahead
JUCE has more than twenty years of production use behind it, and far more breadth. Today it has, and Manguebyte does not:
- a complete GUI toolkit, with plugin editor windows on every system and in every format (Manguebyte’s editors have windows on Win32 only, and none has been opened in a host by hand yet);
- Audio Unit and AAX plugin formats;
- hosting of AU and LV2 plugins, plugin scanning, and the editors of hosted plugins (Manguebyte hosts CLAP and VST 3 plugins, without their editors);
- more DSP building blocks, and more file formats;
- iOS and Android;
- documentation, tutorials and a large community.
The roadmap says what exists and in what order the gap is being closed.
05
The Manguebyte ecosystem
Two more projects from Recife grow from the same mangue, built to run on Manguebyte.
-

This framework
Manguebyte
The open-source audio framework for Rust, under MIT or Apache-2.0. Aratu already plays on its browser engine; Parabolic is to be built on it.
-

In development
Aratu
A live-coding language that reads like music: measures, beats and note values first, in Portuguese, Spanish and English. Its editor runs in the browser and plays on Manguebyte.
-
Planned
Parabolic
A tool for musicians to record their own instruments and turn them into plugins and samplers without writing code.
06
Crabs with brains
The name comes from Recife, the city in the north-east of Brazil where this project was born. Recife is built on mangroves, mangue in Portuguese.
In the early 1990s a group of local musicians answered the city’s troubles with a manifesto, Caranguejos com Cérebro, “Crabs with Brains”: plug the rich, muddy roots of the region’s culture into the global network of ideas. The image they chose was a satellite dish stuck in the mangrove mud.
Start with one dependency
Manguebyte is not on crates.io yet. Depend on it straight from Git:
[dependencies]
manguebyte = { git = "https://github.com/alessonqueirozdev-hub/manguebyte" }
c5835bf, as it is in the file.