Skip to main content

AudioHandle

Struct AudioHandle 

Source
pub struct AudioHandle { /* private fields */ }
Expand description

A running audio stream driving a Plugin.

Dropping the handle stops playback (the underlying device stream is released). While it lives, the plugin keeps running on the audio thread; use Self::lock to send MIDI or change parameters from your control thread.

§Thread affinity

AudioHandle owns the device stream, which backends make thread-affine (cpal’s Stream is !Send for exactly this reason: open, control and drop must happen on one thread). So the handle is !Send and has to stay on the thread that started playback:

fn assert_send<T: Send>() {}
assert_send::<vst3_host::AudioHandle>(); // AudioHandle is deliberately not Send

To drive the plugin from another thread, move a MidiSink (Self::midi_sink) or the shared Arc<Mutex<Plugin>> (Self::plugin) there instead — both are Send.

Implementations§

Source§

impl AudioHandle

Source

pub fn lock(&self) -> MutexGuard<'_, Plugin>

Lock the running plugin to send MIDI, change parameters, etc.

Recovers automatically if the audio thread previously panicked while holding the lock (poisoned mutex), so control calls keep working.

Source

pub fn try_lock(&self) -> Option<MutexGuard<'_, Plugin>>

Try to lock the plugin without blocking, returning None if the audio callback currently holds the lock (it is held for the duration of each process_audio call).

Use this on a UI/render thread for best-effort, per-frame reads (VU meters, output-MIDI drain, parameter sync): skipping a frame when the audio thread is mid-block is invisible, and it keeps the UI thread from stalling on the (unfair) mutex — which otherwise shows up as input lag.

Source

pub fn send_midi(&self, event: MidiEvent) -> bool

Queue a MIDI event for the plugin without locking the audio thread.

The event is pushed onto a lock-free ring and applied at the start of the next audio block. Prefer this over lock().send_midi_event(..) on a UI thread — it never blocks on the audio mutex. Returns false if the ring is full (the event is dropped).

Source

pub fn send_midi_at(&self, event: MidiEvent, sample_offset: i32) -> bool

Queue a MIDI event scheduled at sample_offset samples into the next block, for sample-accurate sequencing, without locking the audio thread. A negative offset is floored to 0. Returns false if the ring is full.

Source

pub fn midi_sink(&self) -> MidiSink

Obtain a MidiSink: a cheap, cloneable, Send handle that can queue MIDI to this running plugin from another thread.

Unlike AudioHandle itself (which is not Send, as it owns the device stream), the sink can be moved into a background thread or callback — e.g. a MIDI input device callback (see crate::midi_input). It shares the same lock-free command ring as Self::send_midi.

Source

pub fn set_parameter(&self, id: u32, value: f64) -> bool

Queue a normalized parameter change without locking the audio thread; applied at the start of the next block. value must be finite and within 0.0..=1.0 — an invalid value is rejected here (returns false) rather than queued, so the caller learns about it instead of the audio thread silently discarding it. Returns false if the ring is full.

§The editor catches up later

The audio thread applies the value to the plugin’s DSP, but IEditController belongs to the main-thread domain, so the plugin’s own editor (and Plugin::get_parameter, format_parameter and saved state) is updated from the control thread instead. That happens the next time the control thread touches the plugin — reading a parameter, draining Plugin::get_parameter_changes, or calling Plugin::service_host_requests. A host that polls the plugin every UI frame (the usual editor loop) never notices the gap; a host that never calls back in will see a stale editor. The queue is bounded and drops its oldest entry when full, so the newest value for a parameter always wins.

Source

pub fn set_tempo(&self, bpm: f64) -> bool

Queue a transport tempo change (BPM) without locking the audio thread; applied at the start of the next block. bpm must be finite and greater than 0 (an invalid value is rejected, returning false). Returns false if the ring is full.

Source

pub fn set_time_signature(&self, numerator: i32, denominator: i32) -> bool

Queue a transport time-signature change without locking the audio thread; applied at the start of the next block. denominator must be one of 1, 2, 4, 8, 16 and numerator must be positive (an invalid value is rejected, returning false). Returns false if the ring is full.

Source

pub fn set_playing(&self, playing: bool) -> bool

Queue a transport playing-state toggle without locking the audio thread; applied at the start of the next block. Returns false if the ring is full.

Source

pub fn midi_panic(&self) -> bool

Queue an all-notes-off “panic” (CC 123/120/121 on every channel) without locking the audio thread. Returns false if the ring is full.

Source

pub fn output_levels(&self) -> AudioLevels

Read the latest per-channel output peak levels without locking the audio thread.

Each channel reports the maximum peak observed since the previous call (the read resets the accumulator), so polling at UI frame rate never misses a transient between frames. rms is not tracked on this path and is reported as 0; peak_hold mirrors peak (drive your own ballistics, e.g. crate::audio::PeakMeter, from the peak).

Source

pub fn drain_output_midi(&self) -> Vec<MidiEvent>

Drain MIDI the plugin emitted during processing (arpeggiators, MPE, …) without locking the audio thread. Returns the events queued since the last call.

Source

pub fn drain_parameter_changes(&self) -> Vec<(u32, f64)>

Drain parameter changes the plugin made through its own editor without locking the audio thread. Returns (id, normalized_value) pairs queued since the last call.

Source

pub fn plugin(&self) -> Arc<Mutex<Plugin>>

A shared handle to the plugin, e.g. to move into another thread.

Source

pub fn stop(self)

Stop playback now (equivalent to dropping the handle).

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.