rill_core_dsp/generators/
reader.rs1use rill_core::interpolate::Interpolate;
8use rill_core::math::vector::scalar::ScalarVector4;
9use rill_core::math::vector::traits::Vector as VecTrait;
10use rill_core::Transcendental;
11
12fn len_remainder(pos: f64, len: f64) -> f64 {
13 let r = pos % len;
14 if r < 0.0 {
15 r + len
16 } else {
17 r
18 }
19}
20
21pub struct InterpolatedReader<T> {
26 buffer: Box<[T]>,
27 position: f64,
28 rate: f64,
29 cubic: bool,
30 wrap: bool,
31}
32
33impl<T: Transcendental + Copy> InterpolatedReader<T> {
34 pub fn new(buffer: Vec<T>) -> Self {
38 Self {
39 buffer: buffer.into_boxed_slice(),
40 position: 0.0,
41 rate: 1.0,
42 cubic: false,
43 wrap: false,
44 }
45 }
46
47 pub fn from_boxed(buffer: Box<[T]>) -> Self {
49 Self {
50 buffer,
51 position: 0.0,
52 rate: 1.0,
53 cubic: false,
54 wrap: false,
55 }
56 }
57
58 #[inline(always)]
60 pub fn len(&self) -> usize {
61 self.buffer.len()
62 }
63
64 #[inline(always)]
66 pub fn is_empty(&self) -> bool {
67 self.buffer.is_empty()
68 }
69
70 #[inline(always)]
72 pub fn position(&self) -> f64 {
73 self.position
74 }
75
76 #[inline(always)]
78 pub fn set_position(&mut self, pos: f64) {
79 self.position = pos;
80 }
81
82 #[inline(always)]
84 pub fn rate(&self) -> f64 {
85 self.rate
86 }
87
88 #[inline(always)]
90 pub fn set_rate(&mut self, rate: f64) {
91 self.rate = rate;
92 }
93
94 #[inline(always)]
96 pub fn is_cubic(&self) -> bool {
97 self.cubic
98 }
99
100 #[inline(always)]
102 pub fn set_cubic(&mut self, cubic: bool) {
103 self.cubic = cubic;
104 }
105
106 #[inline(always)]
108 pub fn is_wrap(&self) -> bool {
109 self.wrap
110 }
111
112 #[inline(always)]
114 pub fn set_wrap(&mut self, wrap: bool) {
115 self.wrap = wrap;
116 }
117
118 pub fn set_buffer(&mut self, buffer: Vec<T>) {
120 self.buffer = buffer.into_boxed_slice();
121 self.position = 0.0;
122 }
123
124 #[inline(always)]
126 pub fn as_slice(&self) -> &[T] {
127 &self.buffer
128 }
129
130 fn read_wrap_linear(&self, pos: f64) -> T {
132 let len = self.len();
133 let i0 = pos.floor() as usize % len;
134 let i1 = (i0 + 1) % len;
135 let frac = T::from_f64(pos.fract());
136 let a = self.buffer[i0];
137 let b = self.buffer[i1];
138 a + (b - a) * frac
139 }
140
141 fn read_wrap_cubic(&self, pos: f64) -> T {
143 let len = self.len();
144 let i = pos.floor() as usize;
145 let i0 = (i + len - 1) % len;
146 let i1 = i % len;
147 let i2 = (i + 1) % len;
148 let i3 = (i + 2) % len;
149 let frac = T::from_f64(pos.fract());
150
151 let c0 = self.buffer[i1];
152 let c1 = (self.buffer[i2] - self.buffer[i0]) * T::from_f32(0.5);
153 let c2 = self.buffer[i0] * T::from_f32(-1.5)
154 + self.buffer[i1] * T::from_f32(2.0)
155 + self.buffer[i2] * T::from_f32(-0.5);
156 let c3 = self.buffer[i0] * T::from_f32(-0.5)
157 + self.buffer[i1] * T::from_f32(1.5)
158 + self.buffer[i2] * T::from_f32(-1.5)
159 + self.buffer[i3] * T::from_f32(0.5);
160
161 let f2 = frac * frac;
162 let f3 = f2 * frac;
163 c0 + c1 * frac + c2 * f2 + c3 * f3
164 }
165
166 #[inline(always)]
168 pub fn read_one(&self) -> T {
169 if self.is_empty() {
170 return T::ZERO;
171 }
172 let pos = if self.wrap {
173 len_remainder(self.position, self.len() as f64)
174 } else {
175 self.position
176 };
177 if self.cubic && self.len() >= 4 {
178 if self.wrap {
179 self.read_wrap_cubic(pos)
180 } else {
181 self.buffer.interpolate_cubic(pos)
182 }
183 } else if self.wrap {
184 self.read_wrap_linear(pos)
185 } else {
186 self.buffer.interpolate_linear(pos)
187 }
188 }
189
190 #[inline(always)]
192 pub fn advance(&mut self) {
193 self.position += self.rate;
194 }
195
196 pub fn render_block(&mut self, output: &mut [T]) {
198 if self.is_empty() {
199 for s in output.iter_mut() {
200 *s = T::ZERO;
201 }
202 return;
203 }
204 self.render_block_simd(output);
205 }
206
207 fn render_block_simd(&mut self, output: &mut [T]) {
209 let chunks = output.len() / 4;
210 let mut pos = self.position;
211 let rate = self.rate;
212
213 if self.wrap {
214 let len_f = self.len() as f64;
215 if self.cubic && self.len() >= 4 {
216 for chunk in 0..chunks {
217 let offset = chunk * 4;
218 let _p0 = pos;
219 let _p1 = pos + rate;
220 let _p2 = pos + rate * 2.0;
221 let _p3 = pos + rate * 3.0;
222 pos += rate * 4.0;
223
224 self.render_scalar_range(output, offset, 4, self.wrap, self.cubic);
227 }
230 } else {
231 for chunk in 0..chunks {
232 let offset = chunk * 4;
233 let p0 = len_remainder(pos, len_f);
235 let p1 = len_remainder(pos + rate, len_f);
236 let p2 = len_remainder(pos + rate * 2.0, len_f);
237 let p3 = len_remainder(pos + rate * 3.0, len_f);
238 pos += rate * 4.0;
239
240 let i0 = p0 as usize;
241 let i1 = p1 as usize;
242 let i2 = p2 as usize;
243 let i3 = p3 as usize;
244
245 let j0 = (i0 + 1) % self.len();
246 let j1 = (i1 + 1) % self.len();
247 let j2 = (i2 + 1) % self.len();
248 let j3 = (i3 + 1) % self.len();
249
250 let f0 = T::from_f64(p0.fract());
251 let f1 = T::from_f64(p1.fract());
252 let f2 = T::from_f64(p2.fract());
253 let f3 = T::from_f64(p3.fract());
254
255 let a0 = self.buffer[i0];
256 let a1 = self.buffer[i1];
257 let a2 = self.buffer[i2];
258 let a3 = self.buffer[i3];
259 let b0 = self.buffer[j0];
260 let b1 = self.buffer[j1];
261 let b2 = self.buffer[j2];
262 let b3 = self.buffer[j3];
263
264 let a_v = ScalarVector4::load(&[a0, a1, a2, a3]);
265 let b_v = ScalarVector4::load(&[b0, b1, b2, b3]);
266 let f_v = ScalarVector4::load(&[f0, f1, f2, f3]);
267
268 let result = a_v.add(&b_v.sub(&a_v).mul(&f_v));
270 result.store(&mut output[offset..offset + 4]);
271 }
272 }
273 } else if self.cubic {
274 self.render_scalar_block(output);
276 return;
277 } else {
278 for chunk in 0..chunks {
279 let offset = chunk * 4;
280 let p0 = pos;
281 let p1 = pos + rate;
282 let p2 = pos + rate * 2.0;
283 let p3 = pos + rate * 3.0;
284 pos += rate * 4.0;
285
286 let last_idx = self.len() - 1;
287 let i0 = (p0 as usize).min(last_idx);
288 let i1 = (p1 as usize).min(last_idx);
289 let i2 = (p2 as usize).min(last_idx);
290 let i3 = (p3 as usize).min(last_idx);
291
292 let j0 = (i0 + 1).min(last_idx);
293 let j1 = (i1 + 1).min(last_idx);
294 let j2 = (i2 + 1).min(last_idx);
295 let j3 = (i3 + 1).min(last_idx);
296
297 let f0 = T::from_f64(p0.fract());
298 let f1 = T::from_f64(p1.fract());
299 let f2 = T::from_f64(p2.fract());
300 let f3 = T::from_f64(p3.fract());
301
302 let a_v = ScalarVector4::load(&[
303 self.buffer[i0],
304 self.buffer[i1],
305 self.buffer[i2],
306 self.buffer[i3],
307 ]);
308 let b_v = ScalarVector4::load(&[
309 self.buffer[j0],
310 self.buffer[j1],
311 self.buffer[j2],
312 self.buffer[j3],
313 ]);
314 let f_v = ScalarVector4::load(&[f0, f1, f2, f3]);
315
316 let result = a_v.add(&b_v.sub(&a_v).mul(&f_v));
317 result.store(&mut output[offset..offset + 4]);
318 }
319 }
320
321 self.position = pos;
322
323 for out in output[chunks * 4..].iter_mut() {
325 *out = self.read_one();
326 self.advance();
327 }
328 }
329
330 fn render_scalar_block(&mut self, output: &mut [T]) {
332 if self.is_empty() {
333 for s in output.iter_mut() {
334 *s = T::ZERO;
335 }
336 return;
337 }
338 if self.wrap {
339 let len_f = self.len() as f64;
340 for s in output.iter_mut() {
341 *s = self.read_wrap_linear(len_remainder(self.position, len_f));
342 self.position += self.rate;
343 }
344 } else {
345 for s in output.iter_mut() {
346 *s = self.buffer.interpolate_linear(self.position);
347 self.position += self.rate;
348 }
349 }
350 }
351
352 #[allow(dead_code)]
354 fn render_scalar_range(
355 &mut self,
356 output: &mut [T],
357 start: usize,
358 count: usize,
359 wrap: bool,
360 _cubic: bool,
361 ) {
362 for out in output[start..start + count].iter_mut() {
363 *out = if wrap {
364 let len = self.len() as f64;
365 self.read_wrap_linear(len_remainder(self.position, len))
366 } else {
367 self.buffer.interpolate_linear(self.position)
368 };
369 self.position += self.rate;
370 }
371 }
372}
373
374#[cfg(test)]
375mod tests {
376 use super::*;
377
378 #[test]
379 fn test_basic_read() {
380 let buf = vec![0.0, 1.0, 2.0, 3.0, 4.0];
381 let mut reader = InterpolatedReader::new(buf);
382 let mut out = [0.0f64; 4];
383 reader.render_block(&mut out);
384 assert_eq!(out, [0.0, 1.0, 2.0, 3.0]);
385 assert!((reader.position() - 4.0).abs() < 1e-10);
386 }
387
388 #[test]
389 fn test_rate_half() {
390 let buf = vec![0.0, 2.0, 4.0, 6.0, 8.0];
391 let mut reader = InterpolatedReader::new(buf);
392 reader.set_rate(0.5);
393 let mut out = [0.0f64; 4];
394 reader.render_block(&mut out);
395 assert!((out[0] - 0.0).abs() < 1e-10);
396 assert!((out[1] - 1.0).abs() < 1e-10);
397 assert!((out[2] - 2.0).abs() < 1e-10);
398 assert!((out[3] - 3.0).abs() < 1e-10);
399 assert!((reader.position() - 2.0).abs() < 1e-10);
400 }
401
402 #[test]
403 fn test_empty_buffer() {
404 let buf: Vec<f64> = vec![];
405 let mut reader = InterpolatedReader::new(buf);
406 let mut out = [1.0f64; 4];
407 reader.render_block(&mut out);
408 assert_eq!(out, [0.0; 4]);
409 }
410
411 #[test]
412 fn test_set_buffer() {
413 let buf = vec![0.0, 0.0];
414 let mut reader = InterpolatedReader::new(buf);
415 reader.set_position(10.0);
416 reader.set_buffer(vec![10.0, 20.0, 30.0]);
417 assert_eq!(reader.position(), 0.0);
418 assert_eq!(reader.len(), 3);
419 }
420
421 #[test]
422 fn test_wrap_linear() {
423 let buf = vec![0.0, 1.0, 2.0, 3.0];
424 let mut reader = InterpolatedReader::new(buf);
425 reader.set_wrap(true);
426 reader.set_position(3.5);
427 let mut out = [0.0f64; 2];
428 reader.render_block(&mut out);
429 assert!(
430 (out[0] - 1.5).abs() < 1e-10,
431 "wrap 3.5 -> 1.5, got {}",
432 out[0]
433 );
434 assert!(
435 (out[1] - 0.5).abs() < 1e-10,
436 "wrap 4.5 -> 0.5, got {}",
437 out[1]
438 );
439 }
440
441 #[test]
442 fn test_wrap_cubic_at_boundary() {
443 let buf = vec![0.0, 1.0, 2.0, 3.0];
444 let mut reader = InterpolatedReader::new(buf);
445 reader.set_wrap(true);
446 reader.set_cubic(true);
447 reader.set_position(0.0);
448 let mut out = [0.0f64; 1];
449 reader.render_block(&mut out);
450 assert!(
451 (out[0] - 0.0).abs() < 1e-10,
452 "cubic wrap at 0 -> 0, got {}",
453 out[0]
454 );
455 }
456
457 #[test]
458 fn test_clamp_at_end() {
459 let buf = vec![10.0, 20.0];
460 let mut reader = InterpolatedReader::new(buf);
461 reader.set_position(5.0);
462 let mut out = [0.0f64; 3];
463 reader.render_block(&mut out);
464 assert_eq!(out, [20.0, 20.0, 20.0]);
465 }
466}