caw_modules/
down_sample.rs1use caw_builder_proc_macros::builder;
2use caw_core::{Buf, Filter, SigCtx, SigT};
3use itertools::izip;
4
5builder! {
6 #[constructor = "down_sample"]
7 #[constructor_doc = "Artificially reduce the sample rate of a signal"]
8 #[generic_setter_type_name = "X"]
9 pub struct Props {
10 #[generic_with_constraint = "SigT<Item = f32>"]
12 #[generic_name = "C"]
13 scale: _,
14 }
15}
16
17impl<C> Filter for Props<C>
18where
19 C: SigT<Item = f32>,
20{
21 type ItemIn = f32;
22
23 type Out<S>
24 = Downsample<C, S>
25 where
26 S: SigT<Item = Self::ItemIn>;
27
28 fn into_sig<S>(self, sig: S) -> Self::Out<S>
29 where
30 S: SigT<Item = Self::ItemIn>,
31 {
32 Downsample {
33 props: self,
34 sig,
35 buf: Vec::new(),
36 prev_input_sample: 0.0,
37 prev_output_sample: 0.0,
38 remaining_samples: 0.0,
39 }
40 }
41}
42
43pub struct Downsample<C, S>
44where
45 C: SigT<Item = f32>,
46 S: SigT<Item = f32>,
47{
48 props: Props<C>,
49 sig: S,
50 buf: Vec<f32>,
51 prev_input_sample: f32,
52 prev_output_sample: f32,
53 remaining_samples: f32,
54}
55
56impl<C, S> SigT for Downsample<C, S>
57where
58 C: SigT<Item = f32>,
59 S: SigT<Item = f32>,
60{
61 type Item = f32;
62
63 fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
64 self.buf.resize(ctx.num_samples, 0.0);
65 let sig = self.sig.sample(ctx);
66 let scale = self.props.scale.sample(ctx);
67 for (out, sample, scale) in izip! {
68 self.buf.iter_mut(),
69 sig.iter(),
70 scale.iter(),
71 } {
72 let scale = scale.max(1.0);
73 if self.remaining_samples < 1.0 {
74 self.remaining_samples = self.remaining_samples.max(0.0);
75 self.prev_output_sample = (self.prev_input_sample
76 * self.remaining_samples)
77 + (sample * (1.0 - self.remaining_samples));
78 *out = self.prev_output_sample;
80 self.remaining_samples = scale;
81 } else {
82 *out = self.prev_output_sample;
83 self.remaining_samples -= 1.0;
84 }
85 self.prev_input_sample = sample;
86 }
87 &self.buf
88 }
89}