atagen

headroom

public
Star0
Watch0
c454b10854660e0f55220e43b21a60913b505716
1
ssh://brewery@pls.lobotomise.me:33/atagen/headroom.git
crates/headroom-dsp/src/delay.rsRust66 lines1.5 KB
1
//! fixed-length fifo sample delay.
2
3
pub struct DelayLine {
4
    buf: Vec<f32>,
5
    write_idx: usize,
6
}
7
8
impl DelayLine {
9
    /// 0 clamps to 1 (one-sample identity minimum).
10
    #[must_use]
11
    pub fn new(samples: usize) -> Self {
12
        Self {
13
            buf: vec![0.0; samples.max(1)],
14
            write_idx: 0,
15
        }
16
    }
17
18
    #[must_use]
19
    pub fn len(&self) -> usize {
20
        self.buf.len()
21
    }
22
23
    #[must_use]
24
    pub fn is_empty(&self) -> bool {
25
        false
26
    }
27
28
    /// write `x`, return the sample written `len` calls ago.
29
    pub fn push_pop(&mut self, x: f32) -> f32 {
30
        let out = self.buf[self.write_idx];
31
        self.buf[self.write_idx] = x;
32
        self.write_idx = (self.write_idx + 1) % self.buf.len();
33
        out
34
    }
35
36
    pub fn reset(&mut self) {
37
        for v in &mut self.buf {
38
            *v = 0.0;
39
        }
40
        self.write_idx = 0;
41
    }
42
}
43
44
#[cfg(test)]
45
mod tests {
46
    use super::*;
47
48
    #[test]
49
    fn delays_exactly_n_samples() {
50
        let mut d = DelayLine::new(4);
51
        let expected = [0.0, 0.0, 0.0, 0.0, 1.0, 2.0, 3.0, 4.0];
52
        let inputs = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0];
53
        for (i, &x) in inputs.iter().enumerate() {
54
            let y = d.push_pop(x);
55
            assert!((y - expected[i]).abs() < 1e-9, "i={i} y={y}");
56
        }
57
    }
58
59
    #[test]
60
    fn zero_length_clamps_to_one() {
61
        let mut d = DelayLine::new(0);
62
        assert_eq!(d.len(), 1);
63
        assert_eq!(d.push_pop(1.0), 0.0);
64
        assert_eq!(d.push_pop(2.0), 1.0);
65
    }
66
}