reverb/
delay_line.rs

1/// Delay-line whose maximum size is fixed
2/// The advantage of using a static versus dynamic array is that its elements
3/// can be laid out in a predicatable location in memeory. This can improve
4/// access speeds if many delay-lines are used within another object, like a
5/// reverb
6#[derive(PartialEq, Eq)]
7pub struct DelayLine<B> {
8    pos: usize,
9    buffer: B,
10}
11
12impl<B> DelayLine<B>
13where
14    B: Buffer,
15{
16    /// Default constructor for a delay line
17    pub fn new() -> DelayLine<B> {
18        DelayLine {
19            pos: 0,
20            buffer: B::zeroed(),
21        }
22    }
23
24    /// Get size of delay-line
25    pub fn reset(&mut self) {
26        self.pos = 0;
27        self.buffer = B::zeroed();
28    }
29
30    /// Get size of delay-line
31    pub fn size(&self) -> usize {
32        self.buffer.len()
33    }
34
35    /// Get element at back
36    pub fn back(&self) -> f32 {
37        let idx = self.index_back();
38        *self.buffer.index(idx)
39    }
40
41    /// Get index of back element.
42    pub fn index_back(&self) -> usize {
43        let i = self.pos + 1;
44        if i < self.size() {
45            i
46        } else {
47            0
48        }
49    }
50
51    /// Read value at delay i
52    pub fn read(&self, i: i32) -> &f32 {
53        let mut idx = self.pos as i32 - i;
54        if idx < 0 {
55            idx += self.size() as i32;
56        }
57        self.buffer.index(idx as usize)
58    }
59
60    /// Write value to delay
61    pub fn write(&mut self, value: f32) {
62        *self.buffer.index_mut(self.pos) = value;
63        self.pos += 1;
64        if self.pos >= self.size() {
65            self.pos = 0;
66        }
67    }
68
69    /// Write new value and return oldest value
70    pub fn get_write_and_step(&mut self, value: f32) -> f32 {
71        let r = *self.buffer.index(self.pos);
72        self.write(value);
73        r
74    }
75
76    /// Comb filter input using a delay time equal to the maximum size of the delay-line
77    pub fn comb(&mut self, value: f32, feed_fwd: f32, feed_bck: f32) -> f32 {
78        let d = *self.buffer.index(self.pos);
79        let r = value + d * feed_bck;
80        self.write(r);
81        d + r * feed_fwd
82    }
83
84    /// Allpass filter input using a delay time equal to the maximum size of the delay-line
85    pub fn allpass(&mut self, value: f32, feed_fwd: f32) -> f32 {
86        self.comb(value, feed_fwd, -feed_fwd)
87    }
88}
89
90impl<B> Clone for DelayLine<B>
91where
92    B: Buffer,
93{
94    fn clone(&self) -> Self {
95        DelayLine {
96            pos: self.pos,
97            buffer: Buffer::clone(&self.buffer),
98        }
99    }
100}
101
102impl<B> ::std::fmt::Debug for DelayLine<B>
103where
104    B: Buffer,
105{
106    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
107        write!(
108            f,
109            "pos: {:?}, buffer: [f32; {:?}]",
110            self.pos,
111            self.buffer.len()
112        )
113    }
114}
115
116/// Some buffer of Float values that is compatible with the delay-line
117pub trait Buffer {
118    fn zeroed() -> Self;
119    fn clone(&self) -> Self;
120    fn len(&self) -> usize;
121    fn index(&self, idx: usize) -> &f32;
122    fn index_mut(&mut self, idx: usize) -> &mut f32;
123}