caw_modules/
envelope_follower.rs1use crate::low_pass_butterworth::{self, LowPassButterworth};
2use caw_builder_proc_macros::builder;
3use caw_core::{Buf, Filter, Sig, SigAbs, SigCtx, SigT};
4
5pub const DEFAULT_SENSITIVITY_HZ: f32 = 60.0;
6
7builder! {
8 #[constructor = "envelope_follower"]
9 #[constructor_doc = "Approximates the loudness of its input signal"]
10 #[generic_setter_type_name = "X"]
11 pub struct Props {
12 #[generic_with_constraint = "SigT<Item = f32>"]
13 #[generic_name = "S"]
14 #[default = DEFAULT_SENSITIVITY_HZ]
15 sensitivity_hz: f32,
16 }
17}
18
19impl<S> Filter for Props<S>
20where
21 S: SigT<Item = f32>,
22{
23 type ItemIn = f32;
24
25 type Out<I>
26 = EnvelopeFollower<I, S>
27 where
28 I: SigT<Item = Self::ItemIn>;
29
30 fn into_sig<I>(self, sig: I) -> Self::Out<I>
31 where
32 I: SigT<Item = Self::ItemIn>,
33 {
34 let low_pass_filter =
35 low_pass_butterworth::low_pass_butterworth(self.sensitivity_hz)
36 .into_sig(Sig(sig).abs().0);
37 EnvelopeFollower { low_pass_filter }
38 }
39}
40
41pub struct EnvelopeFollower<I, S>
42where
43 I: SigT<Item = f32>,
44 S: SigT<Item = f32>,
45{
46 low_pass_filter: LowPassButterworth<SigAbs<I>, S>,
48}
49
50impl<I, S> SigT for EnvelopeFollower<I, S>
51where
52 I: SigT<Item = f32>,
53 S: SigT<Item = f32>,
54{
55 type Item = f32;
56
57 fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
58 self.low_pass_filter.sample(ctx)
59 }
60}