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>;