Skip to main content

rill_core/buffer/
ring.rs

1use std::fmt;
2use crate::math::Transcendental;
3
4/// Fixed-size ring buffer (power-of-two size). Single-threaded.
5///
6/// Used inside the signal graph for delay effects and sample buffering.
7/// Size must be a power of two.
8///
9/// # Example
10/// ```
11/// use rill_core::buffer::RingBuffer;
12///
13/// let mut buffer = RingBuffer::<f32, 4>::new();
14/// buffer.write(1.0);
15/// buffer.write(2.0);
16/// assert_eq!(buffer.read_delayed(0), 2.0);
17/// ```
18#[repr(C, align(64))]
19pub struct RingBuffer<T: Transcendental, const N: usize> {
20    data: [T; N],
21    head: usize,
22    tail: usize,
23    mask: usize,
24    full: bool,
25}
26
27impl<T: Transcendental, const N: usize> RingBuffer<T, N> {
28    /// Create a new ring buffer.
29    ///
30    /// # Panics
31    /// Panics if `N` is not a power of two.
32    pub fn new() -> Self {
33        assert!(N.is_power_of_two(), "RingBuffer size must be power of two");
34        Self {
35            data: [T::ZERO; N],
36            head: 0,
37            tail: 0,
38            mask: N - 1,
39            full: false,
40        }
41    }
42
43    /// Write a single sample, advancing the head cursor.
44    pub fn write(&mut self, sample: T) {
45        self.data[self.head] = sample;
46        let next_head = (self.head + 1) & self.mask;
47        self.head = next_head;
48        if next_head == self.tail {
49            self.full = true;
50        }
51    }
52
53    /// Write multiple samples in sequence.
54    pub fn write_slice(&mut self, samples: &[T]) where T: Copy {
55        for &sample in samples {
56            self.write(sample);
57        }
58    }
59
60    /// Read the oldest sample, or `None` if empty.
61    pub fn read(&mut self) -> Option<T> {
62        if self.tail == self.head && !self.full {
63            return None;
64        }
65        let sample = self.data[self.tail];
66        self.tail = (self.tail + 1) & self.mask;
67        self.full = false;
68        Some(sample)
69    }
70
71    /// Read a sample at `delay` samples behind head (0 = most recent).
72    ///
73    /// # Panics
74    /// Panics if `delay >= len()`.
75    pub fn read_delayed(&self, delay: usize) -> T {
76        assert!(delay < self.len(), "Delay must be less than buffer length");
77        let read_pos = (self.head + self.capacity() - delay - 1) & self.mask;
78        self.data[read_pos]
79    }
80
81    /// Read with linear interpolation between samples at fractional delay.
82    pub fn read_interpolated(&self, delay_frac: f32) -> T
83    where
84        T: From<f32> + Into<f32>,
85    {
86        let delay_int = delay_frac.floor() as usize;
87        let frac = delay_frac.fract();
88        if frac == 0.0 {
89            return self.read_delayed(delay_int);
90        }
91        let s1: f32 = self.read_delayed(delay_int).into();
92        let prev = if delay_int == 0 { self.len() - 1 } else { delay_int - 1 };
93        let s2: f32 = self.read_delayed(prev).into();
94        T::from(s1 * (1.0 - frac) + s2 * frac)
95    }
96
97    /// Read a sequence of interpolated samples into the output buffer,
98    /// starting at `start_delay` samples behind head.
99    pub fn read_sequence_interpolated(&self, start_delay: f32, output: &mut [T])
100    where
101        T: From<f32> + Into<f32>,
102    {
103        let len = self.len();
104        for i in 0..output.len() {
105            let delay = start_delay + i as f32;
106            output[i] = if delay < len as f32 {
107                self.read_interpolated(delay)
108            } else {
109                T::ZERO
110            };
111        }
112    }
113
114    /// Number of samples currently stored.
115    pub fn len(&self) -> usize {
116        if self.full { N }
117        else if self.head >= self.tail { self.head - self.tail }
118        else { N - self.tail + self.head }
119    }
120
121    /// Maximum capacity (const generic parameter).
122    pub const fn capacity(&self) -> usize { N }
123    /// Whether the buffer has no samples.
124    pub fn is_empty(&self) -> bool { self.head == self.tail && !self.full }
125    /// Whether the buffer is completely full.
126    pub fn is_full(&self) -> bool { self.full }
127
128    /// Clear all samples and reset cursors.
129    pub fn clear(&mut self) {
130        self.data.fill(T::ZERO);
131        self.head = 0;
132        self.tail = 0;
133        self.full = false;
134    }
135
136    /// Reset cursors without zeroing the data.
137    pub fn reset(&mut self) {
138        self.head = 0;
139        self.tail = 0;
140        self.full = false;
141    }
142}
143
144impl<T: Transcendental, const N: usize> Default for RingBuffer<T, N> {
145    fn default() -> Self { Self::new() }
146}
147
148impl<T: Transcendental + fmt::Debug, const N: usize> fmt::Debug for RingBuffer<T, N> {
149    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150        let mut preview = Vec::with_capacity(4);
151        for i in 0..4.min(N) { preview.push(self.data[i]); }
152        f.debug_struct("RingBuffer")
153            .field("head", &self.head)
154            .field("tail", &self.tail)
155            .field("full", &self.full)
156            .field("len", &self.len())
157            .field("capacity", &N)
158            .field("preview", &preview)
159            .finish()
160    }
161}
162
163// =============================================================================
164// Итератор
165// =============================================================================
166
167/// Iterator over the contents of a [`RingBuffer`], from oldest to newest.
168pub struct RingBufferIter<'a, T: Transcendental, const N: usize> {
169    buffer: &'a RingBuffer<T, N>,
170    pos: usize,
171    end: usize,
172}
173
174impl<'a, T: Transcendental, const N: usize> RingBufferIter<'a, T, N> {
175    fn new(buffer: &'a RingBuffer<T, N>) -> Self {
176        let tail = buffer.tail;
177        let head = buffer.head;
178        let len = if buffer.full { N } else if head >= tail { head - tail } else { N - tail + head };
179        Self { buffer, pos: tail, end: tail + len }
180    }
181}
182
183impl<'a, T: Transcendental, const N: usize> Iterator for RingBufferIter<'a, T, N> {
184    type Item = T;
185    fn next(&mut self) -> Option<Self::Item> {
186        if self.pos >= self.end { None }
187        else {
188            let idx = self.pos & self.buffer.mask;
189            let value = self.buffer.data[idx];
190            self.pos += 1;
191            Some(value)
192        }
193    }
194}
195
196impl<'a, T: Transcendental, const N: usize> ExactSizeIterator for RingBufferIter<'a, T, N> {
197    fn len(&self) -> usize { self.end - self.pos }
198}
199
200impl<T: Transcendental, const N: usize> RingBuffer<T, N> {
201    /// Iterate over buffered samples from oldest to newest.
202    pub fn iter(&self) -> RingBufferIter<'_, T, N> {
203        RingBufferIter::new(self)
204    }
205}
206
207// =============================================================================
208// Тесты
209// =============================================================================
210
211#[cfg(test)]
212mod tests {
213    use super::*;
214
215    #[test]
216    fn test_ring_buffer_basic() {
217        let mut buffer = RingBuffer::<f32, 4>::new();
218        buffer.write(1.0); buffer.write(2.0); buffer.write(3.0); buffer.write(4.0);
219        assert!(buffer.is_full());
220        assert_eq!(buffer.len(), 4);
221        assert_eq!(buffer.read(), Some(1.0));
222        assert_eq!(buffer.read(), Some(2.0));
223        assert_eq!(buffer.read(), Some(3.0));
224        assert_eq!(buffer.read(), Some(4.0));
225        assert_eq!(buffer.read(), None);
226        assert!(buffer.is_empty());
227    }
228
229    #[test]
230    fn test_ring_buffer_wraparound() {
231        let mut buffer = RingBuffer::<f32, 4>::new();
232        for i in 0..10 { buffer.write(i as f32); }
233        assert_eq!(buffer.read_delayed(0), 9.0);
234        assert_eq!(buffer.read_delayed(1), 8.0);
235        assert_eq!(buffer.read_delayed(2), 7.0);
236        assert_eq!(buffer.read_delayed(3), 6.0);
237    }
238
239    #[test]
240    fn test_ring_buffer_interpolated() {
241        let mut buffer = RingBuffer::<f32, 4>::new();
242        buffer.write(1.0); buffer.write(2.0); buffer.write(3.0); buffer.write(4.0);
243        let val = buffer.read_interpolated(1.5);
244        assert!((val - 3.5).abs() < 0.001);
245    }
246
247    #[test]
248    fn test_ring_buffer_clear() {
249        let mut buffer = RingBuffer::<f32, 4>::new();
250        buffer.write(1.0); buffer.write(2.0);
251        assert!(!buffer.is_empty());
252        buffer.clear();
253        assert!(buffer.is_empty());
254    }
255
256    #[test]
257    fn test_ring_buffer_iterator() {
258        let mut buffer = RingBuffer::<f32, 4>::new();
259        buffer.write(1.0); buffer.write(2.0); buffer.write(3.0); buffer.write(4.0);
260        let collected: Vec<f32> = buffer.iter().collect();
261        assert_eq!(collected, vec![1.0, 2.0, 3.0, 4.0]);
262    }
263
264    #[test]
265    fn test_ring_buffer_read_sequence() {
266        let mut buffer = RingBuffer::<f32, 4>::new();
267        buffer.write(1.0); buffer.write(2.0); buffer.write(3.0); buffer.write(4.0);
268        let mut output = [0.0; 4];
269        buffer.read_sequence_interpolated(0.0, &mut output);
270        assert_eq!(output, [4.0, 3.0, 2.0, 1.0]);
271    }
272
273    #[test]
274    #[should_panic(expected = "Delay must be less than buffer length")]
275    fn test_ring_buffer_invalid_delay() {
276        let buffer = RingBuffer::<f32, 4>::new();
277        let _ = buffer.read_delayed(4);
278    }
279
280    #[test]
281    fn test_ring_buffer_write_slice() {
282        let mut buffer = RingBuffer::<f32, 4>::new();
283        buffer.write_slice(&[1.0, 2.0, 3.0, 4.0]);
284        assert_eq!(buffer.read(), Some(1.0));
285        assert_eq!(buffer.read(), Some(2.0));
286        assert_eq!(buffer.read(), Some(3.0));
287        assert_eq!(buffer.read(), Some(4.0));
288    }
289}