pub struct RealtimePluginRunner { /* private fields */ }Expand description
Owns a Plugin on the audio thread and applies queued control commands before each
process block. Pair with an RtControl (returned from Self::new) to drive it from
other threads.
§Real-time safety
In steady state process is allocation-free and Drop-free: once
warmed up it performs no heap allocation, reallocation, or free per block, even while
parameter changes and MIDI (in and out) are flowing. This holds under two conditions:
- Fixed buffer size — pass an
AudioBufferssized to the configured block size and don’t resize it between calls (a smaller block is fine; growth reallocates). - In-process — the runner hosts the plugin in-process; the process-isolation path marshals audio over IPC and is not allocation-free.
This is verified by tests/alloc_tests.rs (a counting global allocator asserts zero
alloc/realloc/free over a steady-state run driving parameters and MIDI). The host cannot
guarantee the plugin’s own process() is allocation-free — that is the plugin’s
responsibility; the guarantee is about the host code around it.
It is not yet fully lock-free: process still takes a few short, uncontended mutexes
per block (the parameter-change and event queues, and the level meter). They are uncontended
while the runner owns the plugin, but a hard-real-time deployment should treat lock removal
as pending work. Output MIDI is already lock-free, though: take a
OutputMidiConsumer via
Plugin::output_midi_handle before moving the plugin
into the runner, then drain emitted events from your UI thread while the audio thread pushes.
Implementations§
Source§impl RealtimePluginRunner
impl RealtimePluginRunner
Sourcepub fn new(plugin: Plugin, command_capacity: usize) -> (Self, RtControl)
pub fn new(plugin: Plugin, command_capacity: usize) -> (Self, RtControl)
Build a runner that owns plugin, plus the RtControl handle to drive it.
command_capacity is the maximum number of MIDI/parameter commands that can be
queued between two process calls; pushes beyond it are dropped
(reported by the RtControl methods returning false). Size it for your block rate
and worst-case control burst (e.g. 1024).
Sourcepub fn process(&mut self, buffers: &mut AudioBuffers) -> Result<()>
pub fn process(&mut self, buffers: &mut AudioBuffers) -> Result<()>
Drain all queued control commands and render one block.
Call this from the audio thread (e.g. inside your device callback). It performs only the lock-free queue drain plus the plugin’s own processing — it never blocks on a lock a control thread could hold.
Sourcepub fn plugin(&self) -> &Plugin
pub fn plugin(&self) -> &Plugin
Borrow the underlying plugin (e.g. to read parameters or info). Do not call this from the audio thread while another thread might also touch the plugin.
Sourcepub fn into_plugin(self) -> Plugin
pub fn into_plugin(self) -> Plugin
Recover the owned plugin, consuming the runner.