1use crate::math::Transcendental;
2use crate::buffer::Buffer;
3
4#[derive(Debug)]
26pub struct TapeLoop<T> {
27 buffer: Box<[T]>,
28 capacity: usize,
29 write_pos: usize,
30}
31
32impl<T: Transcendental> TapeLoop<T> {
33 pub fn new(capacity: usize) -> Option<Self> {
35 if capacity == 0 {
36 return None;
37 }
38 let mut vec = Vec::with_capacity(capacity);
39 for _ in 0..capacity {
40 vec.push(T::ZERO);
41 }
42 Some(Self {
43 buffer: vec.into_boxed_slice(),
44 capacity,
45 write_pos: 0,
46 })
47 }
48
49 pub fn capacity(&self) -> usize { self.capacity }
51 pub fn write_pos(&self) -> usize { self.write_pos }
53
54 #[inline(always)]
56 pub fn write(&mut self, sample: T) {
57 self.buffer[self.write_pos] = sample;
58 self.write_pos = (self.write_pos + 1) % self.capacity;
59 }
60
61 #[inline(always)]
63 pub fn read(&self, delay: usize) -> T {
64 let d = delay.min(self.capacity - 1);
65 let read_pos = if self.write_pos > d {
66 self.write_pos - 1 - d
67 } else {
68 self.capacity + self.write_pos - 1 - d
69 };
70 self.buffer[read_pos]
71 }
72
73 #[inline(always)]
75 pub fn read_interpolated(&self, delay: f64) -> T {
76 let d = delay as usize;
77 let frac = T::from_f64(delay.fract());
78 let s1 = self.read(d);
79 let s2 = self.read(d + 1);
80 s1 + (s2 - s1) * frac
81 }
82
83 #[inline(always)]
85 pub fn write_block(&mut self, block: &[T]) {
86 let len = block.len().min(self.capacity);
87 for i in 0..len {
88 self.buffer[(self.write_pos + i) % self.capacity] = block[i];
89 }
90 self.write_pos = (self.write_pos + len) % self.capacity;
91 }
92
93 #[inline(always)]
95 pub fn read_block(&self, delay: usize, output: &mut [T]) {
96 let len = output.len().min(self.capacity);
97 let d = delay.min(self.capacity - 1);
98 for i in 0..len {
99 output[i] = self.read(d + len - 1 - i);
100 }
101 }
102
103 pub fn fill(&mut self, value: T) {
105 for slot in self.buffer.iter_mut() {
106 *slot = value;
107 }
108 }
109
110 pub fn clear(&mut self) {
112 for slot in self.buffer.iter_mut() {
113 *slot = T::ZERO;
114 }
115 self.write_pos = 0;
116 }
117}
118
119impl<T: Transcendental> Buffer<T> for TapeLoop<T> {
122 fn len(&self) -> usize {
123 self.capacity
124 }
125
126 fn as_slice(&self) -> &[T] {
127 &self.buffer
128 }
129
130 fn as_mut_slice(&mut self) -> &mut [T] {
131 &mut self.buffer
132 }
133
134 fn fill(&mut self, value: T)
135 where
136 T: Copy,
137 {
138 for slot in self.buffer.iter_mut() {
139 *slot = value;
140 }
141 }
142
143 fn copy_from(&mut self, src: &[T])
144 where
145 T: Copy,
146 {
147 let len = src.len().min(self.capacity);
148 self.buffer[..len].copy_from_slice(&src[..len]);
149 }
150}
151
152#[cfg(test)]
153mod tests {
154 use super::*;
155
156 #[test]
157 fn test_tape_basic_write_read() {
158 let mut tape = TapeLoop::<f32>::new(1024).unwrap();
159 tape.write(1.0);
160 tape.write(2.0);
161 tape.write(3.0);
162 assert_eq!(tape.read(0), 3.0);
163 assert_eq!(tape.read(1), 2.0);
164 assert_eq!(tape.read(2), 1.0);
165 }
166
167 #[test]
168 fn test_tape_wraparound() {
169 let mut tape = TapeLoop::<f32>::new(4).unwrap();
170 for i in 0..10 { tape.write(i as f32); }
171 assert_eq!(tape.read(0), 9.0);
172 assert_eq!(tape.read(1), 8.0);
173 assert_eq!(tape.read(2), 7.0);
174 assert_eq!(tape.read(3), 6.0);
175 }
176
177 #[test]
178 fn test_tape_block_ops() {
179 let mut tape = TapeLoop::<f32>::new(64).unwrap();
180 let block = [1.0f32; 64];
181 tape.write_block(&block);
182 let mut out = [0.0f32; 64];
183 tape.read_block(63, &mut out);
184 assert_eq!(out[0], 1.0);
185 }
186
187 #[test]
188 fn test_tape_large_capacity() {
189 let tape = TapeLoop::<f32>::new(1_000_000).unwrap();
190 assert_eq!(tape.capacity(), 1_000_000);
191 }
192
193 #[test]
194 fn test_tape_zero_capacity() {
195 assert!(TapeLoop::<f32>::new(0).is_none());
196 }
197
198 #[test]
199 fn test_read_interpolated() {
200 let mut tape = TapeLoop::<f32>::new(1024).unwrap();
201 tape.write(0.0);
202 tape.write(1.0);
203 let v = tape.read_interpolated(0.5);
204 assert!((v - 0.5).abs() < 0.01);
205 }
206}