bbx_dsp/
buffer.rs

1//! Audio buffer types.
2//!
3//! This module provides the [`Buffer`] trait for generic buffer operations
4//! and [`AudioBuffer`] for storing audio sample data during DSP processing.
5
6use std::ops::{Index, IndexMut};
7
8#[cfg(feature = "simd")]
9use bbx_core::simd::fill as simd_fill;
10
11use crate::sample::Sample;
12
13/// A generic buffer interface for DSP operations.
14///
15/// Provides common operations for buffers used throughout the DSP system.
16/// Implemented by [`AudioBuffer`] for audio sample storage.
17pub trait Buffer<T> {
18    /// Get the length of the `Buffer`.
19    fn len(&self) -> usize;
20
21    /// Check if the `Buffer` is empty.
22    fn is_empty(&self) -> bool;
23
24    /// Get the `Buffer` as a data slice.
25    fn as_slice(&self) -> &[T];
26
27    /// Get the `Buffer` as a mutable data slice.
28    fn as_mut_slice(&mut self) -> &mut [T];
29
30    /// Remove all values from the `Buffer`
31    fn clear(&mut self);
32
33    /// Set all values in the `Buffer` to zero.
34    fn zeroize(&mut self);
35}
36
37/// A buffer for storing audio sample data.
38///
39/// Used internally by the DSP graph for block input/output buffers.
40/// Wraps a `Vec<S>` with convenience methods for audio processing.
41#[derive(Debug, Clone)]
42pub struct AudioBuffer<S: Sample> {
43    data: Vec<S>,
44}
45
46impl<S: Sample> AudioBuffer<S> {
47    /// Create an `AudioBuffer` of a particular capacity,
48    /// automatically filled with zeroes.
49    pub fn new(capacity: usize) -> Self {
50        Self {
51            data: vec![S::ZERO; capacity],
52        }
53    }
54
55    /// Create an `AudioBuffer` initialized with a given set of values.
56    #[inline]
57    pub fn with_data(data: Vec<S>) -> Self {
58        Self { data }
59    }
60
61    /// Get the capacity of the `AudioBuffer`.
62    #[inline]
63    pub fn capacity(&self) -> usize {
64        self.data.capacity()
65    }
66
67    /// Fill the `AudioBuffer` with a particular value.
68    #[inline]
69    pub fn fill(&mut self, value: S) {
70        #[cfg(feature = "simd")]
71        simd_fill(self.data.as_mut_slice(), value);
72
73        #[cfg(not(feature = "simd"))]
74        self.data.fill(value);
75    }
76
77    /// Copy the values from a given source to the `AudioBuffer`.
78    #[inline]
79    pub fn copy_from_slice(&mut self, source: &[S]) {
80        self.data[..source.len()].copy_from_slice(source);
81    }
82
83    /// Copy the `AudioBuffer`'s values to a given slice.
84    #[inline]
85    pub fn copy_to_slice(&self, target: &mut [S]) {
86        let len = self.data.len().min(target.len());
87        target[..len].copy_from_slice(&self.data[..len]);
88    }
89
90    /// Get the `AudioBuffer` as a pointer to its contents.
91    #[inline]
92    pub fn as_ptr(&self) -> *const S {
93        self.data.as_ptr()
94    }
95
96    /// Get the `AudioBuffer` as a mutable pointer to its contents.
97    #[inline]
98    pub fn as_mut_ptr(&mut self) -> *mut S {
99        self.data.as_mut_ptr()
100    }
101
102    /// Append the `AudioBuffer` with data from a given slice.
103    #[inline]
104    pub fn extend_from_slice(&mut self, slice: &[S]) {
105        self.data.extend_from_slice(slice);
106    }
107
108    /// Drain the first `count` values from the `AudioBuffer`.
109    #[inline]
110    pub fn drain_front(&mut self, count: usize) -> std::vec::Drain<'_, S> {
111        let actual_count = count.min(self.data.len());
112        self.data.drain(0..actual_count)
113    }
114}
115
116impl<S: Sample> Buffer<S> for AudioBuffer<S> {
117    #[inline]
118    fn len(&self) -> usize {
119        self.data.len()
120    }
121
122    #[inline]
123    fn is_empty(&self) -> bool {
124        self.data.is_empty()
125    }
126
127    #[inline]
128    fn as_slice(&self) -> &[S] {
129        &self.data
130    }
131
132    #[inline]
133    fn as_mut_slice(&mut self) -> &mut [S] {
134        &mut self.data
135    }
136
137    #[inline]
138    fn clear(&mut self) {
139        self.data.clear();
140    }
141
142    #[inline]
143    fn zeroize(&mut self) {
144        #[cfg(feature = "simd")]
145        simd_fill(self.data.as_mut_slice(), S::ZERO);
146
147        #[cfg(not(feature = "simd"))]
148        self.data.fill(S::ZERO);
149    }
150}
151
152impl<S: Sample> Index<usize> for AudioBuffer<S> {
153    type Output = S;
154
155    fn index(&self, index: usize) -> &Self::Output {
156        &self.data[index]
157    }
158}
159
160impl<S: Sample> IndexMut<usize> for AudioBuffer<S> {
161    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
162        &mut self.data[index]
163    }
164}
165
166impl<S: Sample> Extend<S> for AudioBuffer<S> {
167    fn extend<I: IntoIterator<Item = S>>(&mut self, iter: I) {
168        self.data.extend(iter);
169    }
170}