1use crate::buffer::Buffer;
2use crate::math::Transcendental;
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 {
51 self.capacity
52 }
53 pub fn write_pos(&self) -> usize {
55 self.write_pos
56 }
57
58 #[inline(always)]
60 pub fn write(&mut self, sample: T) {
61 self.buffer[self.write_pos] = sample;
62 self.write_pos = (self.write_pos + 1) % self.capacity;
63 }
64
65 #[inline(always)]
67 pub fn read(&self, delay: usize) -> T {
68 let d = delay.min(self.capacity - 1);
69 let read_pos = if self.write_pos > d {
70 self.write_pos - 1 - d
71 } else {
72 self.capacity + self.write_pos - 1 - d
73 };
74 self.buffer[read_pos]
75 }
76
77 #[inline(always)]
79 pub fn read_interpolated(&self, delay: f64) -> T {
80 let d = delay as usize;
81 let frac = T::from_f64(delay.fract());
82 let s1 = self.read(d);
83 let s2 = self.read(d + 1);
84 s1 + (s2 - s1) * frac
85 }
86
87 #[inline(always)]
89 pub fn write_block(&mut self, block: &[T]) {
90 let len = block.len().min(self.capacity);
91 for (i, &b) in block.iter().enumerate().take(len) {
92 self.buffer[(self.write_pos + i) % self.capacity] = b;
93 }
94 self.write_pos = (self.write_pos + len) % self.capacity;
95 }
96
97 #[inline(always)]
99 pub fn read_block(&self, delay: usize, output: &mut [T]) {
100 let len = output.len().min(self.capacity);
101 let d = delay.min(self.capacity - 1);
102 for (i, out) in output.iter_mut().enumerate().take(len) {
103 *out = self.read(d + len - 1 - i);
104 }
105 }
106
107 pub fn fill(&mut self, value: T) {
109 for slot in self.buffer.iter_mut() {
110 *slot = value;
111 }
112 }
113
114 pub fn clear(&mut self) {
116 for slot in self.buffer.iter_mut() {
117 *slot = T::ZERO;
118 }
119 self.write_pos = 0;
120 }
121}
122
123impl<T: Transcendental> Buffer<T> for TapeLoop<T> {
126 fn capacity(&self) -> usize {
127 self.capacity
128 }
129
130 fn len(&self) -> usize {
131 self.capacity
132 }
133
134 fn as_slice(&self) -> &[T] {
135 &self.buffer
136 }
137
138 fn as_mut_slice(&mut self) -> &mut [T] {
139 &mut self.buffer
140 }
141
142 fn fill(&mut self, value: T) {
143 for slot in self.buffer.iter_mut() {
144 *slot = value;
145 }
146 }
147
148 fn copy_from(&mut self, src: &[T]) {
149 let len = src.len().min(self.capacity);
150 self.buffer[..len].copy_from_slice(&src[..len]);
151 }
152
153 fn clear(&mut self) {
154 for slot in self.buffer.iter_mut() {
155 *slot = T::ZERO;
156 }
157 self.write_pos = 0;
158 }
159}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn test_tape_basic_write_read() {
167 let mut tape = TapeLoop::<f32>::new(1024).unwrap();
168 tape.write(1.0);
169 tape.write(2.0);
170 tape.write(3.0);
171 assert_eq!(tape.read(0), 3.0);
172 assert_eq!(tape.read(1), 2.0);
173 assert_eq!(tape.read(2), 1.0);
174 }
175
176 #[test]
177 fn test_tape_wraparound() {
178 let mut tape = TapeLoop::<f32>::new(4).unwrap();
179 for i in 0..10 {
180 tape.write(i as f32);
181 }
182 assert_eq!(tape.read(0), 9.0);
183 assert_eq!(tape.read(1), 8.0);
184 assert_eq!(tape.read(2), 7.0);
185 assert_eq!(tape.read(3), 6.0);
186 }
187
188 #[test]
189 fn test_tape_block_ops() {
190 let mut tape = TapeLoop::<f32>::new(64).unwrap();
191 let block = [1.0f32; 64];
192 tape.write_block(&block);
193 let mut out = [0.0f32; 64];
194 tape.read_block(63, &mut out);
195 assert_eq!(out[0], 1.0);
196 }
197
198 #[test]
199 fn test_tape_large_capacity() {
200 let tape = TapeLoop::<f32>::new(1_000_000).unwrap();
201 assert_eq!(tape.capacity(), 1_000_000);
202 }
203
204 #[test]
205 fn test_tape_zero_capacity() {
206 assert!(TapeLoop::<f32>::new(0).is_none());
207 }
208
209 #[test]
210 fn test_read_interpolated() {
211 let mut tape = TapeLoop::<f32>::new(1024).unwrap();
212 tape.write(0.0);
213 tape.write(1.0);
214 let v = tape.read_interpolated(0.5);
215 assert!((v - 0.5).abs() < 0.01);
216 }
217}