rill_core/buffer/
delay.rs1use crate::buffer::{AtomicStats, BufferStats, SignalBuffer};
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> SignalBuffer<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 clear(&mut self) {
174 self.clear();
175 }
176 fn stats(&self) -> BufferStats {
177 let mut stats = self.stats.snapshot();
178 stats.fill_level = 1.0;
179 stats
180 }
181 fn reset_stats(&mut self) {
182 self.stats.reset();
183 }
184}
185
186#[cfg(test)]
191mod tests {
192 use super::*;
193
194 #[test]
195 fn test_delay_line_basic() {
196 let mut delay = DelayLine::<f32, 1024>::new(44100.0);
197 delay.set_delay_samples(100);
198 for i in 0..200 {
199 let out = delay.write(i as f32);
200 if i >= 100 {
201 assert_eq!(out, (i - 100) as f32);
202 }
203 }
204 }
205
206 #[test]
207 fn test_delay_line_read_delayed() {
208 let mut delay = DelayLine::<f32, 1024>::new(44100.0);
209 for i in 0..1024 {
210 delay.write(i as f32);
211 }
212 assert_eq!(delay.read_delayed(0), 1023.0);
213 assert_eq!(delay.read_delayed(100), 923.0);
214 }
215
216 #[test]
217 fn test_delay_line_interpolation() {
218 let mut delay = DelayLine::<f32, 1024>::new(44100.0);
219 for i in 0..1024 {
220 delay.write(i as f32);
221 }
222 let val = delay.read_interpolated(100.5);
223 assert!((val - 922.5).abs() < 0.01);
224 }
225}