Skip to main content

RealtimePluginRunner

Struct RealtimePluginRunner 

Source
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 AudioBuffers sized 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

Source

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).

Source

pub fn start(&mut self) -> Result<()>

Begin processing. Call once before the first process.

Source

pub fn stop(&mut self) -> Result<()>

Stop processing.

Source

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.

Source

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.

Source

pub fn into_plugin(self) -> Plugin

Recover the owned plugin, consuming the runner.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<S> FromSample<S> for S

Source§

fn from_sample_(s: S) -> S

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

Source§

fn to_sample_(self) -> U

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.