beamer_core/buffer.rs
1//! Audio buffer abstractions for plugin processing.
2//!
3//! This module provides [`Buffer`] for main audio I/O and [`AuxiliaryBuffers`]
4//! for sidechain and auxiliary bus access.
5//!
6//! # Architecture
7//!
8//! Audio processing in Beamer uses two separate buffer types:
9//!
10//! - **[`Buffer`]**: Main stereo/surround I/O - used by all plugins
11//! - **[`AuxiliaryBuffers`]**: Sidechain and aux buses - used by multi-bus plugins
12//!
13//! This separation solves Rust's lifetime variance constraints with nested mutable
14//! references while providing a clean, ergonomic API.
15//!
16//! # Real-Time Safety
17//!
18//! All buffer types use fixed-size stack storage with no heap allocations.
19//! This guarantees real-time safety in audio processing callbacks.
20//!
21//! # Generic Sample Type
22//!
23//! All buffer types are generic over `S: Sample`, defaulting to `f32`. This enables
24//! zero-cost generic processing for both 32-bit and 64-bit audio.
25//!
26//! # Example: Simple Gain Plugin
27//!
28//! ```ignore
29//! fn process(&mut self, buffer: &mut Buffer, _aux: &mut AuxiliaryBuffers) {
30//! let gain = self.params.gain();
31//! for (input, output) in buffer.zip_channels() {
32//! for (i, o) in input.iter().zip(output.iter_mut()) {
33//! *o = *i * gain;
34//! }
35//! }
36//! }
37//! ```
38//!
39//! # Example: Sidechain Compressor
40//!
41//! ```ignore
42//! fn process(&mut self, buffer: &mut Buffer, aux: &mut AuxiliaryBuffers) {
43//! // Analyze sidechain input
44//! let key_level = aux.sidechain()
45//! .map(|sc| sc.rms(0)) // RMS of first channel
46//! .unwrap_or(0.0);
47//!
48//! // Apply compression based on sidechain
49//! let reduction = self.compute_gain_reduction(key_level);
50//! for output in buffer.outputs_mut() {
51//! for sample in output {
52//! *sample *= reduction;
53//! }
54//! }
55//! }
56//! ```
57
58use crate::sample::Sample;
59use crate::types::{MAX_AUX_BUSES, MAX_CHANNELS};
60
61// =============================================================================
62// Buffer - Main Audio I/O
63// =============================================================================
64
65/// Main audio buffer for plugin processing.
66///
67/// Contains input and output channel slices for the primary audio bus.
68/// This is what most plugins interact with - simple stereo or surround I/O.
69///
70/// # Type Parameter
71///
72/// `S` is the sample type, defaulting to `f32`. Use `Buffer<f64>` for
73/// 64-bit double precision processing.
74///
75/// # Lifetime
76///
77/// The `'a` lifetime ties the buffer to the host's audio data. Buffers are
78/// only valid within a single `process()` call.
79///
80/// # Channel Layout
81///
82/// Channels are indexed starting from 0:
83/// - Stereo: 0 = Left, 1 = Right
84/// - Surround: 0 = Left, 1 = Right, 2 = Center, etc.
85///
86/// # Real-Time Safety
87///
88/// This struct uses fixed-size stack storage. No heap allocations occur
89/// during construction or use.
90pub struct Buffer<'a, S: Sample = f32> {
91 /// Input channel slices (immutable audio from host)
92 /// Option<&[S]> is Copy, so [None; N] works
93 inputs: [Option<&'a [S]>; MAX_CHANNELS],
94 /// Output channel slices (mutable audio to host)
95 outputs: [Option<&'a mut [S]>; MAX_CHANNELS],
96 /// Number of active input channels
97 num_input_channels: usize,
98 /// Number of active output channels
99 num_output_channels: usize,
100 /// Number of samples in this processing block
101 num_samples: usize,
102}
103
104impl<'a, S: Sample> Buffer<'a, S> {
105 /// Create a new buffer from channel slices.
106 ///
107 /// This is called by the VST3 wrapper, not by plugin code.
108 /// Channels beyond [`MAX_CHANNELS`] are silently ignored.
109 #[inline]
110 pub fn new(
111 inputs: impl IntoIterator<Item = &'a [S]>,
112 outputs: impl IntoIterator<Item = &'a mut [S]>,
113 num_samples: usize,
114 ) -> Self {
115 let mut input_arr: [Option<&'a [S]>; MAX_CHANNELS] = [None; MAX_CHANNELS];
116 let mut num_input_channels = 0;
117 for (i, slice) in inputs.into_iter().take(MAX_CHANNELS).enumerate() {
118 input_arr[i] = Some(slice);
119 num_input_channels = i + 1;
120 }
121
122 // Can't use [None; N] for &mut because it's not Copy
123 let mut output_arr: [Option<&'a mut [S]>; MAX_CHANNELS] = std::array::from_fn(|_| None);
124 let mut num_output_channels = 0;
125 for (i, slice) in outputs.into_iter().take(MAX_CHANNELS).enumerate() {
126 output_arr[i] = Some(slice);
127 num_output_channels = i + 1;
128 }
129
130 Self {
131 inputs: input_arr,
132 outputs: output_arr,
133 num_input_channels,
134 num_output_channels,
135 num_samples,
136 }
137 }
138
139 // =========================================================================
140 // Buffer Info
141 // =========================================================================
142
143 /// Number of samples in this processing block.
144 #[inline]
145 pub fn num_samples(&self) -> usize {
146 self.num_samples
147 }
148
149 /// Number of input channels.
150 #[inline]
151 pub fn num_input_channels(&self) -> usize {
152 self.num_input_channels
153 }
154
155 /// Number of output channels.
156 #[inline]
157 pub fn num_output_channels(&self) -> usize {
158 self.num_output_channels
159 }
160
161 /// Returns true if this is a stereo buffer (2 in, 2 out).
162 #[inline]
163 pub fn is_stereo(&self) -> bool {
164 self.num_input_channels == 2 && self.num_output_channels == 2
165 }
166
167 /// Returns true if this is a mono buffer (1 in, 1 out).
168 #[inline]
169 pub fn is_mono(&self) -> bool {
170 self.num_input_channels == 1 && self.num_output_channels == 1
171 }
172
173 // =========================================================================
174 // Channel Access
175 // =========================================================================
176
177 /// Get an input channel by index.
178 ///
179 /// Returns an empty slice if the channel doesn't exist.
180 #[inline]
181 pub fn input(&self, channel: usize) -> &[S] {
182 self.inputs
183 .get(channel)
184 .and_then(|opt| opt.as_ref())
185 .map(|ch| &ch[..self.num_samples])
186 .unwrap_or(&[])
187 }
188
189 /// Get a mutable output channel by index.
190 ///
191 /// # Panics
192 ///
193 /// Panics if the channel index is out of bounds.
194 #[inline]
195 pub fn output(&mut self, channel: usize) -> &mut [S] {
196 let n = self.num_samples;
197 self.outputs[channel]
198 .as_mut()
199 .map(|ch| &mut ch[..n])
200 .expect("output channel out of bounds")
201 }
202
203 /// Try to get a mutable output channel by index.
204 ///
205 /// Returns `None` if the channel doesn't exist.
206 #[inline]
207 pub fn output_checked(&mut self, channel: usize) -> Option<&mut [S]> {
208 let n = self.num_samples;
209 self.outputs
210 .get_mut(channel)
211 .and_then(|opt| opt.as_mut())
212 .map(|ch| &mut ch[..n])
213 }
214
215 // =========================================================================
216 // Iterators
217 // =========================================================================
218
219 /// Iterate over all input channels.
220 #[inline]
221 pub fn inputs(&self) -> impl Iterator<Item = &[S]> + '_ {
222 let n = self.num_samples;
223 self.inputs[..self.num_input_channels]
224 .iter()
225 .filter_map(move |opt| opt.as_ref().map(|ch| &ch[..n]))
226 }
227
228 /// Iterate over all output channels mutably.
229 #[inline]
230 pub fn outputs_mut(&mut self) -> impl Iterator<Item = &mut [S]> + use<'_, 'a, S> {
231 let n = self.num_samples;
232 self.outputs[..self.num_output_channels]
233 .iter_mut()
234 .filter_map(move |opt| opt.as_mut().map(|ch| &mut ch[..n]))
235 }
236
237 /// Iterate over paired (input, output) channels.
238 ///
239 /// This is the most common pattern for in-place processing.
240 /// Only yields channels that exist in both input and output.
241 ///
242 /// # Example
243 ///
244 /// ```ignore
245 /// for (input, output) in buffer.zip_channels() {
246 /// for (i, o) in input.iter().zip(output.iter_mut()) {
247 /// *o = *i * gain;
248 /// }
249 /// }
250 /// ```
251 #[inline]
252 pub fn zip_channels(&mut self) -> impl Iterator<Item = (&[S], &mut [S])> + use<'_, 'a, S> {
253 let n = self.num_samples;
254 let num_pairs = self.num_input_channels.min(self.num_output_channels);
255 self.inputs[..num_pairs]
256 .iter()
257 .zip(self.outputs[..num_pairs].iter_mut())
258 .filter_map(move |(i_opt, o_opt)| {
259 match (i_opt.as_ref(), o_opt.as_mut()) {
260 (Some(i), Some(o)) => Some((&i[..n], &mut o[..n])),
261 _ => None,
262 }
263 })
264 }
265
266 // =========================================================================
267 // Bulk Operations
268 // =========================================================================
269
270 /// Copy all input channels to output channels.
271 ///
272 /// Useful for bypass or passthrough. Only copies channels that exist
273 /// in both input and output.
274 pub fn copy_to_output(&mut self) {
275 let num_channels = self.num_input_channels.min(self.num_output_channels);
276 let n = self.num_samples;
277 for ch in 0..num_channels {
278 if let (Some(input), Some(output)) = (self.inputs[ch].as_ref(), self.outputs[ch].as_mut()) {
279 output[..n].copy_from_slice(&input[..n]);
280 }
281 }
282 }
283
284 /// Clear all output channels to silence.
285 pub fn clear_outputs(&mut self) {
286 let n = self.num_samples;
287 for opt in self.outputs[..self.num_output_channels].iter_mut() {
288 if let Some(output) = opt.as_mut() {
289 output[..n].fill(S::ZERO);
290 }
291 }
292 }
293
294 /// Apply a gain factor to all output channels.
295 pub fn apply_output_gain(&mut self, gain: S) {
296 let n = self.num_samples;
297 for opt in self.outputs[..self.num_output_channels].iter_mut() {
298 if let Some(output) = opt.as_mut() {
299 for sample in &mut output[..n] {
300 *sample = *sample * gain;
301 }
302 }
303 }
304 }
305}
306
307// =============================================================================
308// AuxiliaryBuffers - Sidechain and Aux Buses
309// =============================================================================
310
311/// Auxiliary audio buffers for sidechain and multi-bus processing.
312///
313/// Contains all non-main audio buses. Most plugins don't need this -
314/// they only use the main [`Buffer`].
315///
316/// # Type Parameter
317///
318/// `S` is the sample type, defaulting to `f32`. Use `AuxiliaryBuffers<f64>` for
319/// 64-bit double precision processing.
320///
321/// # Bus Indexing
322///
323/// Auxiliary buses are indexed starting from 0:
324/// - Bus 0: Sidechain (most common aux use case)
325/// - Bus 1+: Additional auxiliary I/O
326///
327/// # Real-Time Safety
328///
329/// This struct uses fixed-size stack storage. No heap allocations occur
330/// during construction or use.
331///
332/// # Example: Sidechain Access
333///
334/// ```ignore
335/// if let Some(sidechain) = aux.sidechain() {
336/// let key_signal = sidechain.channel(0);
337/// // Use for compression keying, ducking, etc.
338/// }
339/// ```
340pub struct AuxiliaryBuffers<'a, S: Sample = f32> {
341 /// Auxiliary input buses (e.g., sidechain inputs)
342 /// Outer array: buses, Inner array: channels per bus
343 inputs: [[Option<&'a [S]>; MAX_CHANNELS]; MAX_AUX_BUSES],
344 /// Number of channels per input bus
345 input_channel_counts: [usize; MAX_AUX_BUSES],
346 /// Number of active input buses
347 num_input_buses: usize,
348
349 /// Auxiliary output buses (e.g., aux sends)
350 outputs: [[Option<&'a mut [S]>; MAX_CHANNELS]; MAX_AUX_BUSES],
351 /// Number of channels per output bus
352 output_channel_counts: [usize; MAX_AUX_BUSES],
353 /// Number of active output buses
354 num_output_buses: usize,
355
356 /// Number of samples in this processing block
357 num_samples: usize,
358}
359
360impl<'a, S: Sample> AuxiliaryBuffers<'a, S> {
361 /// Create new auxiliary buffers.
362 ///
363 /// This is called by the VST3 wrapper, not by plugin code.
364 /// Buses/channels beyond the limits are silently ignored.
365 #[inline]
366 pub fn new(
367 inputs: impl IntoIterator<Item = impl IntoIterator<Item = &'a [S]>>,
368 outputs: impl IntoIterator<Item = impl IntoIterator<Item = &'a mut [S]>>,
369 num_samples: usize,
370 ) -> Self {
371 // Initialize input buses
372 let mut input_arr: [[Option<&'a [S]>; MAX_CHANNELS]; MAX_AUX_BUSES] =
373 [[None; MAX_CHANNELS]; MAX_AUX_BUSES];
374 let mut input_channel_counts = [0usize; MAX_AUX_BUSES];
375 let mut num_input_buses = 0;
376
377 for (bus_idx, bus) in inputs.into_iter().take(MAX_AUX_BUSES).enumerate() {
378 let mut ch_count = 0;
379 for (ch_idx, slice) in bus.into_iter().take(MAX_CHANNELS).enumerate() {
380 input_arr[bus_idx][ch_idx] = Some(slice);
381 ch_count = ch_idx + 1;
382 }
383 input_channel_counts[bus_idx] = ch_count;
384 if ch_count > 0 {
385 num_input_buses = bus_idx + 1;
386 }
387 }
388
389 // Initialize output buses - need from_fn because &mut is not Copy
390 let mut output_arr: [[Option<&'a mut [S]>; MAX_CHANNELS]; MAX_AUX_BUSES] =
391 std::array::from_fn(|_| std::array::from_fn(|_| None));
392 let mut output_channel_counts = [0usize; MAX_AUX_BUSES];
393 let mut num_output_buses = 0;
394
395 for (bus_idx, bus) in outputs.into_iter().take(MAX_AUX_BUSES).enumerate() {
396 let mut ch_count = 0;
397 for (ch_idx, slice) in bus.into_iter().take(MAX_CHANNELS).enumerate() {
398 output_arr[bus_idx][ch_idx] = Some(slice);
399 ch_count = ch_idx + 1;
400 }
401 output_channel_counts[bus_idx] = ch_count;
402 if ch_count > 0 {
403 num_output_buses = bus_idx + 1;
404 }
405 }
406
407 Self {
408 inputs: input_arr,
409 input_channel_counts,
410 num_input_buses,
411 outputs: output_arr,
412 output_channel_counts,
413 num_output_buses,
414 num_samples,
415 }
416 }
417
418 /// Create empty auxiliary buffers (no aux buses).
419 #[inline]
420 pub fn empty() -> Self {
421 Self {
422 inputs: [[None; MAX_CHANNELS]; MAX_AUX_BUSES],
423 input_channel_counts: [0; MAX_AUX_BUSES],
424 num_input_buses: 0,
425 outputs: std::array::from_fn(|_| std::array::from_fn(|_| None)),
426 output_channel_counts: [0; MAX_AUX_BUSES],
427 num_output_buses: 0,
428 num_samples: 0,
429 }
430 }
431
432 // =========================================================================
433 // Info
434 // =========================================================================
435
436 /// Number of samples in this processing block.
437 #[inline]
438 pub fn num_samples(&self) -> usize {
439 self.num_samples
440 }
441
442 /// Number of auxiliary input buses.
443 #[inline]
444 pub fn num_input_buses(&self) -> usize {
445 self.num_input_buses
446 }
447
448 /// Number of auxiliary output buses.
449 #[inline]
450 pub fn num_output_buses(&self) -> usize {
451 self.num_output_buses
452 }
453
454 /// Returns true if there are no auxiliary buses.
455 #[inline]
456 pub fn is_empty(&self) -> bool {
457 self.num_input_buses == 0 && self.num_output_buses == 0
458 }
459
460 // =========================================================================
461 // Bus Access
462 // =========================================================================
463
464 /// Get the sidechain input bus (auxiliary input bus 0).
465 ///
466 /// This is the most common aux use case. Returns `None` if no
467 /// sidechain is connected.
468 ///
469 /// # Example
470 ///
471 /// ```ignore
472 /// let key_level = aux.sidechain()
473 /// .map(|sc| sc.rms(0))
474 /// .unwrap_or(0.0);
475 /// ```
476 #[inline]
477 pub fn sidechain(&self) -> Option<AuxInput<'_, S>> {
478 self.input(0)
479 }
480
481 /// Get an auxiliary input bus by index.
482 ///
483 /// Returns `None` if the bus doesn't exist or has no channels.
484 #[inline]
485 pub fn input(&self, bus: usize) -> Option<AuxInput<'_, S>> {
486 if bus >= MAX_AUX_BUSES {
487 return None;
488 }
489 let num_channels = self.input_channel_counts[bus];
490 if num_channels == 0 {
491 return None;
492 }
493 Some(AuxInput {
494 channels: &self.inputs[bus][..num_channels],
495 num_samples: self.num_samples,
496 })
497 }
498
499 /// Get a mutable auxiliary output bus by index.
500 ///
501 /// Returns `None` if the bus doesn't exist or has no channels.
502 #[inline]
503 pub fn output(&mut self, bus: usize) -> Option<AuxOutput<'_, 'a, S>> {
504 if bus >= MAX_AUX_BUSES {
505 return None;
506 }
507 let num_channels = self.output_channel_counts[bus];
508 if num_channels == 0 {
509 return None;
510 }
511 let num_samples = self.num_samples;
512 Some(AuxOutput {
513 channels: &mut self.outputs[bus][..num_channels],
514 num_samples,
515 })
516 }
517
518 // =========================================================================
519 // Iterators
520 // =========================================================================
521
522 /// Iterate over all auxiliary input buses.
523 #[inline]
524 pub fn iter_inputs(&self) -> impl Iterator<Item = AuxInput<'_, S>> + '_ {
525 let num_samples = self.num_samples;
526 self.inputs[..self.num_input_buses]
527 .iter()
528 .zip(self.input_channel_counts[..self.num_input_buses].iter())
529 .filter(|(_, &count)| count > 0)
530 .map(move |(channels, &count)| AuxInput {
531 channels: &channels[..count],
532 num_samples,
533 })
534 }
535
536 /// Iterate over all auxiliary output buses mutably.
537 #[inline]
538 pub fn iter_outputs(&mut self) -> impl Iterator<Item = AuxOutput<'_, 'a, S>> + '_ {
539 let num_samples = self.num_samples;
540 let num_buses = self.num_output_buses;
541 self.outputs[..num_buses]
542 .iter_mut()
543 .zip(self.output_channel_counts[..num_buses].iter())
544 .filter(|(_, &count)| count > 0)
545 .map(move |(channels, &count)| AuxOutput {
546 channels: &mut channels[..count],
547 num_samples,
548 })
549 }
550}
551
552// =============================================================================
553// AuxInput - Immutable Auxiliary Input Bus
554// =============================================================================
555
556/// Immutable view of an auxiliary input bus.
557///
558/// Provides access to input channels for a single auxiliary bus
559/// (typically sidechain). Created via [`AuxiliaryBuffers::sidechain()`]
560/// or [`AuxiliaryBuffers::input()`].
561///
562/// # Type Parameter
563///
564/// `S` is the sample type, defaulting to `f32`.
565///
566/// # Example
567///
568/// ```ignore
569/// if let Some(sidechain) = aux.sidechain() {
570/// // Calculate RMS of sidechain for keying
571/// let rms = sidechain.rms(0);
572///
573/// // Or iterate over all channels
574/// for ch in sidechain.iter_channels() {
575/// // Process channel...
576/// }
577/// }
578/// ```
579pub struct AuxInput<'a, S: Sample = f32> {
580 channels: &'a [Option<&'a [S]>],
581 num_samples: usize,
582}
583
584impl<'a, S: Sample> AuxInput<'a, S> {
585 /// Number of samples in each channel.
586 #[inline]
587 pub fn num_samples(&self) -> usize {
588 self.num_samples
589 }
590
591 /// Number of channels in this bus.
592 #[inline]
593 pub fn num_channels(&self) -> usize {
594 self.channels.len()
595 }
596
597 /// Get a channel by index.
598 ///
599 /// Returns an empty slice if the channel doesn't exist.
600 #[inline]
601 pub fn channel(&self, index: usize) -> &[S] {
602 self.channels
603 .get(index)
604 .and_then(|opt| opt.as_ref())
605 .map(|ch| &ch[..self.num_samples])
606 .unwrap_or(&[])
607 }
608
609 /// Iterate over all channel slices.
610 #[inline]
611 pub fn iter_channels(&self) -> impl Iterator<Item = &[S]> + '_ {
612 let n = self.num_samples;
613 self.channels
614 .iter()
615 .filter_map(move |opt| opt.as_ref().map(|ch| &ch[..n]))
616 }
617
618 // =========================================================================
619 // Analysis Utilities
620 // =========================================================================
621
622 /// Calculate the RMS (root mean square) level of a channel.
623 ///
624 /// Returns zero if the channel doesn't exist or is empty.
625 pub fn rms(&self, channel: usize) -> S {
626 let ch = self.channel(channel);
627 if ch.is_empty() {
628 return S::ZERO;
629 }
630 let sum: S = ch.iter().fold(S::ZERO, |acc, &s| acc + s * s);
631 let len = S::from_f32(ch.len() as f32);
632 (sum / len).sqrt()
633 }
634
635 /// Calculate the peak level of a channel.
636 ///
637 /// Returns zero if the channel doesn't exist or is empty.
638 pub fn peak(&self, channel: usize) -> S {
639 self.channel(channel)
640 .iter()
641 .map(|&s| s.abs())
642 .fold(S::ZERO, |a, b| a.max(b))
643 }
644
645 /// Calculate the average absolute level of a channel.
646 ///
647 /// Returns zero if the channel doesn't exist or is empty.
648 pub fn average(&self, channel: usize) -> S {
649 let ch = self.channel(channel);
650 if ch.is_empty() {
651 return S::ZERO;
652 }
653 let sum: S = ch.iter().map(|&s| s.abs()).fold(S::ZERO, |a, b| a + b);
654 let len = S::from_f32(ch.len() as f32);
655 sum / len
656 }
657}
658
659// =============================================================================
660// AuxOutput - Mutable Auxiliary Output Bus
661// =============================================================================
662
663/// Mutable view of an auxiliary output bus.
664///
665/// Provides access to output channels for a single auxiliary bus
666/// (e.g., aux sends, multi-out). Created via [`AuxiliaryBuffers::output()`].
667///
668/// # Type Parameter
669///
670/// `S` is the sample type, defaulting to `f32`.
671///
672/// # Lifetime Parameters
673///
674/// - `'borrow` - The borrow lifetime (from `&mut self` on `AuxiliaryBuffers`)
675/// - `'data` - The underlying audio data lifetime
676///
677/// This separation is required because `&'a mut [&'a mut T]` is invariant
678/// in Rust, which prevents returning borrowed data from methods.
679///
680/// # Example
681///
682/// ```ignore
683/// if let Some(mut aux_out) = aux.output(0) {
684/// // Write to aux output
685/// for sample in aux_out.channel(0) {
686/// *sample = processed_signal;
687/// }
688/// }
689/// ```
690pub struct AuxOutput<'borrow, 'data, S: Sample = f32> {
691 channels: &'borrow mut [Option<&'data mut [S]>],
692 num_samples: usize,
693}
694
695impl<'borrow, 'data, S: Sample> AuxOutput<'borrow, 'data, S> {
696 /// Number of samples in each channel.
697 #[inline]
698 pub fn num_samples(&self) -> usize {
699 self.num_samples
700 }
701
702 /// Number of channels in this bus.
703 #[inline]
704 pub fn num_channels(&self) -> usize {
705 self.channels.len()
706 }
707
708 /// Get a mutable channel by index.
709 ///
710 /// # Panics
711 ///
712 /// Panics if the channel index is out of bounds.
713 #[inline]
714 pub fn channel(&mut self, index: usize) -> &mut [S] {
715 let n = self.num_samples;
716 self.channels[index]
717 .as_mut()
718 .map(|ch| &mut ch[..n])
719 .expect("aux output channel out of bounds")
720 }
721
722 /// Try to get a mutable channel by index.
723 ///
724 /// Returns `None` if the channel doesn't exist.
725 #[inline]
726 pub fn channel_checked(&mut self, index: usize) -> Option<&mut [S]> {
727 let n = self.num_samples;
728 self.channels
729 .get_mut(index)
730 .and_then(|opt| opt.as_mut())
731 .map(|ch| &mut ch[..n])
732 }
733
734 /// Iterate over all channel slices mutably.
735 #[inline]
736 pub fn iter_channels(&mut self) -> impl Iterator<Item = &mut [S]> + use<'_, 'data, S> {
737 let n = self.num_samples;
738 self.channels
739 .iter_mut()
740 .filter_map(move |opt| opt.as_mut().map(|ch| &mut ch[..n]))
741 }
742
743 /// Clear all channels to silence.
744 pub fn clear(&mut self) {
745 let n = self.num_samples;
746 for opt in self.channels.iter_mut() {
747 if let Some(ch) = opt.as_mut() {
748 ch[..n].fill(S::ZERO);
749 }
750 }
751 }
752
753 /// Fill all channels with a constant value.
754 pub fn fill(&mut self, value: S) {
755 let n = self.num_samples;
756 for opt in self.channels.iter_mut() {
757 if let Some(ch) = opt.as_mut() {
758 ch[..n].fill(value);
759 }
760 }
761 }
762}
763
764// =============================================================================
765// Deprecated Compatibility Types
766// =============================================================================
767
768/// DEPRECATED: Use [`Buffer`] and [`AuxiliaryBuffers`] instead.
769///
770/// This type alias exists for migration purposes only.
771#[deprecated(since = "0.2.0", note = "Use Buffer and AuxiliaryBuffers instead")]
772pub type AudioBuffer<'a> = Buffer<'a>;
773
774/// DEPRECATED: Use [`AuxInput`] or [`AuxOutput`] instead.
775///
776/// This type alias exists for migration purposes only.
777#[deprecated(since = "0.2.0", note = "Use AuxInput or AuxOutput instead")]
778pub type Bus<'a> = AuxInput<'a>;