Skip to main content

rill_core/buffer/
ring.rs

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