rill_core/buffer/
delay.rs1use crate::buffer::{AtomicStats, Buffer, BufferStats};
2use crate::math::Transcendental;
3use core::marker::PhantomData;
4use core::ops::{Index, IndexMut};
5
6#[repr(align(64))]
17pub struct DelayLine<T: Transcendental, const MAX_DELAY: usize> {
18 buffer: [T; MAX_DELAY],
19 write_pos: usize,
20 delay_samples: usize,
21 sample_rate: f32,
22 stats: AtomicStats,
23 _phantom: PhantomData<T>,
24}
25
26impl<T: Transcendental, const MAX_DELAY: usize> DelayLine<T, MAX_DELAY> {
27 pub fn new(sample_rate: f32) -> Self {
32 assert!(MAX_DELAY > 0, "DelayLine must have MAX_DELAY > 0");
33 Self {
34 buffer: [T::ZERO; MAX_DELAY],
35 write_pos: 0,
36 delay_samples: 0,
37 sample_rate,
38 stats: AtomicStats::new(),
39 _phantom: PhantomData,
40 }
41 }
42
43 pub fn set_delay(&mut self, delay_sec: f32) {
45 let samples = (delay_sec * self.sample_rate) as usize;
46 self.delay_samples = samples.min(MAX_DELAY - 1);
47 }
48
49 pub fn set_delay_samples(&mut self, samples: usize) {
51 self.delay_samples = samples.min(MAX_DELAY - 1);
52 }
53
54 pub fn delay_samples(&self) -> usize {
56 self.delay_samples
57 }
58 pub const fn max_delay(&self) -> usize {
60 MAX_DELAY
61 }
62 pub fn sample_rate(&self) -> f32 {
64 self.sample_rate
65 }
66
67 #[inline(always)]
69 pub fn write(&mut self, input: T) -> T {
70 self.buffer[self.write_pos] = input;
71 let read_pos = if self.write_pos >= self.delay_samples {
72 self.write_pos - self.delay_samples
73 } else {
74 MAX_DELAY + self.write_pos - self.delay_samples
75 };
76 let output = self.buffer[read_pos];
77 self.write_pos = (self.write_pos + 1) % MAX_DELAY;
78 self.stats.record_write();
79 self.stats.record_read();
80 self.stats.update_peak(MAX_DELAY);
81 output
82 }
83
84 #[inline(always)]
86 pub fn read(&self) -> T {
87 let read_pos = if self.write_pos >= self.delay_samples {
88 self.write_pos - self.delay_samples
89 } else {
90 MAX_DELAY + self.write_pos - self.delay_samples
91 };
92 self.buffer[read_pos]
93 }
94
95 #[inline(always)]
97 pub fn read_delayed(&self, delay: usize) -> T {
98 debug_assert!(
99 delay < MAX_DELAY,
100 "Delay {} out of range (max {})",
101 delay,
102 MAX_DELAY
103 );
104 let read_pos = if self.write_pos > delay {
105 self.write_pos - 1 - delay
106 } else {
107 MAX_DELAY + self.write_pos - 1 - delay
108 };
109 self.buffer[read_pos]
110 }
111
112 #[inline(always)]
114 pub fn read_interpolated(&self, delay_frac: f32) -> T {
115 let delay_int = delay_frac.floor() as usize;
116 let frac = T::from_f32(delay_frac.fract());
117 let s1 = self.read_delayed(delay_int);
118 if delay_int == MAX_DELAY - 1 {
119 s1
120 } else {
121 let s2 = self.read_delayed(delay_int + 1);
122 s1 + (s2 - s1) * frac
123 }
124 }
125
126 pub fn clear(&mut self) {
128 self.buffer.fill(T::ZERO);
129 self.write_pos = 0;
130 self.stats.reset();
131 }
132
133 pub fn write_position(&self) -> usize {
135 self.write_pos
136 }
137}
138
139impl<T: Transcendental, const MAX_DELAY: usize> Index<usize> for DelayLine<T, MAX_DELAY> {
144 type Output = T;
145 fn index(&self, index: usize) -> &Self::Output {
146 &self.buffer[index]
147 }
148}
149
150impl<T: Transcendental, const MAX_DELAY: usize> IndexMut<usize> for DelayLine<T, MAX_DELAY> {
151 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
152 &mut self.buffer[index]
153 }
154}
155
156impl<T: Transcendental, const MAX_DELAY: usize> Buffer<T> for DelayLine<T, MAX_DELAY> {
161 fn capacity(&self) -> usize {
162 MAX_DELAY
163 }
164 fn len(&self) -> usize {
165 MAX_DELAY
166 }
167 fn is_empty(&self) -> bool {
168 false
169 }
170 fn is_full(&self) -> bool {
171 true
172 }
173 fn as_slice(&self) -> &[T] {
174 &self.buffer
175 }
176 fn as_mut_slice(&mut self) -> &mut [T] {
177 &mut self.buffer
178 }
179 fn fill(&mut self, value: T) {
180 self.buffer.fill(value);
181 }
182 fn copy_from(&mut self, src: &[T]) {
183 let len = src.len().min(MAX_DELAY);
184 self.buffer[..len].copy_from_slice(&src[..len]);
185 }
186 fn clear(&mut self) {
187 self.buffer.fill(T::ZERO);
188 self.write_pos = 0;
189 self.stats.reset();
190 }
191 fn stats(&self) -> BufferStats {
192 let mut stats = self.stats.snapshot();
193 stats.fill_level = 1.0;
194 stats
195 }
196 fn reset_stats(&mut self) {
197 self.stats.reset();
198 }
199}
200
201#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn test_delay_line_basic() {
211 let mut delay = DelayLine::<f32, 1024>::new(44100.0);
212 delay.set_delay_samples(100);
213 for i in 0..200 {
214 let out = delay.write(i as f32);
215 if i >= 100 {
216 assert_eq!(out, (i - 100) as f32);
217 }
218 }
219 }
220
221 #[test]
222 fn test_delay_line_read_delayed() {
223 let mut delay = DelayLine::<f32, 1024>::new(44100.0);
224 for i in 0..1024 {
225 delay.write(i as f32);
226 }
227 assert_eq!(delay.read_delayed(0), 1023.0);
228 assert_eq!(delay.read_delayed(100), 923.0);
229 }
230
231 #[test]
232 fn test_delay_line_interpolation() {
233 let mut delay = DelayLine::<f32, 1024>::new(44100.0);
234 for i in 0..1024 {
235 delay.write(i as f32);
236 }
237 let val = delay.read_interpolated(100.5);
238 assert!((val - 922.5).abs() < 0.01);
239 }
240}