caw_modules/
delay_s.rs

1use crate::low_level::linearly_interpolating_ring_buffer::LinearlyInterpolatingRingBuffer;
2use caw_builder_proc_macros::builder;
3use caw_core::{Buf, Filter, SigCtx, SigT};
4use itertools::izip;
5
6builder! {
7    #[constructor = "delay_s"]
8    #[constructor_doc = "Delay module where the delay is a configurable period"]
9    #[generic_setter_type_name = "X"]
10    pub struct Props {
11        #[generic_with_constraint = "SigT<Item = f32>"]
12        #[generic_name = "P"]
13        period_s: _,
14        // 0 is dry signal, 1 is all delay
15        #[generic_with_constraint = "SigT<Item = f32>"]
16        #[generic_name = "M"]
17        #[default = 0.5]
18        mix_01: f32,
19        // ratio of output fed back into the input
20        #[generic_with_constraint = "SigT<Item = f32>"]
21        #[generic_name = "F"]
22        #[default = 0.5]
23        feedback_ratio: f32,
24    }
25}
26
27pub struct DelayS<S, P, M, F>
28where
29    S: SigT<Item = f32>,
30    P: SigT<Item = f32>,
31    M: SigT<Item = f32>,
32    F: SigT<Item = f32>,
33{
34    props: Props<P, M, F>,
35    sig: S,
36    ring: LinearlyInterpolatingRingBuffer,
37    buf: Vec<f32>,
38}
39
40impl<P, M, F> Filter for Props<P, M, F>
41where
42    P: SigT<Item = f32>,
43    M: SigT<Item = f32>,
44    F: SigT<Item = f32>,
45{
46    type ItemIn = f32;
47
48    type Out<S>
49        = DelayS<S, P, M, F>
50    where
51        S: SigT<Item = Self::ItemIn>;
52
53    fn into_sig<S>(self, sig: S) -> Self::Out<S>
54    where
55        S: SigT<Item = f32>,
56    {
57        DelayS {
58            props: self,
59            sig,
60            ring: LinearlyInterpolatingRingBuffer::new(44100),
61            buf: Vec::new(),
62        }
63    }
64}
65
66impl<S, P, M, F> SigT for DelayS<S, P, M, F>
67where
68    S: SigT<Item = f32>,
69    P: SigT<Item = f32>,
70    M: SigT<Item = f32>,
71    F: SigT<Item = f32>,
72{
73    type Item = f32;
74
75    fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
76        self.buf.resize_with(ctx.num_samples, Default::default);
77        let sig = self.sig.sample(ctx);
78        let period_s = self.props.period_s.sample(ctx);
79        let mix_01 = self.props.mix_01.sample(ctx);
80        let feedback_ratio = self.props.feedback_ratio.sample(ctx);
81        for (out, sample, period_s, mix_01, feedback_ratio) in izip! {
82            self.buf.iter_mut(),
83            sig.iter(),
84            period_s.iter(),
85            mix_01.iter(),
86            feedback_ratio.iter(),
87        } {
88            let index = period_s * ctx.sample_rate_hz;
89            let output = self.ring.query_resizing(index);
90            self.ring
91                .insert((sample * mix_01) + (output * feedback_ratio));
92            *out = output + (sample * (1.0 - mix_01));
93        }
94        &self.buf
95    }
96}