pub struct AudioTap { /* private fields */ }Expand description
Lock-free single-producer/single-consumer sample tap for the audio → UI analyzer path (audio→UI sample ring).
The audio thread pushes raw samples every
process() call; the UI/editor thread drains them
once per frame. Both sides use plain atomics only - no locks, no
allocation on the producer side - so push is safe to call from a
realtime audio callback (agal/skills/00-core/audio-thread-boundary.md).
Declare with #[skip] like any other DSP↔UI shared field the
derive default-initializes:
#[derive(Params)]
pub struct AnalyzerParams {
#[skip]
pub spectrum_tap: AudioTap,
}The editor reaches it through the concrete Arc<Self::Params>
PluginLogic::editor() already receives (capture it into the
build/sync closures) - not through the dyn Params trait, since a
raw sample ring isn’t part of the host-automatable parameter
surface. FFT / spectrum math stays product-side (lx-analysis,
see G16); this type only moves raw samples across the thread
boundary.
Single-producer / single-consumer is a caller contract, not
enforced by the type: only the audio thread may call push, only
the UI/editor thread may call drain.
On overflow (producer outruns the consumer), the oldest unread
samples are silently overwritten - the tap never blocks and never
grows, matching the audio thread’s no-alloc/no-lock constraint.
Need a non-default capacity? #[skip] fields only require
Default, so wrap in a newtype with its own Default impl calling
AudioTap::new.
Implementations§
Source§impl AudioTap
impl AudioTap
Sourcepub fn new(capacity: usize) -> Self
pub fn new(capacity: usize) -> Self
New tap with the given capacity in samples. 0 is treated as
1 - a zero-length ring can’t hold a sample.