caw_modules 0.5.0

Collection of synthesizer modules for the caw synthesizer framework
Documentation
use caw_builder_proc_macros::builder;
use caw_core::{sig_ops::sig_div, Buf, Sig, SigCtx, SigT};
use itertools::izip;

pub struct PeriodicTrig<P>
where
    P: SigT<Item = f32>,
{
    period_s: P,
    remaining_s: f32,
    buf: Vec<bool>,
}

impl<P> SigT for PeriodicTrig<P>
where
    P: SigT<Item = f32>,
{
    type Item = bool;

    fn sample(&mut self, ctx: &SigCtx) -> impl caw_core::Buf<Self::Item> {
        self.buf.resize(ctx.num_samples, false);
        let sample_period_s = 1.0 / ctx.sample_rate_hz;
        let period_s = self.period_s.sample(ctx);
        for (out, period_s) in izip! {
            self.buf.iter_mut(),
            period_s.iter(),
        } {
            self.remaining_s =
                (self.remaining_s - sample_period_s).min(period_s);
            *out = if self.remaining_s < 0.0 {
                self.remaining_s = period_s;
                true
            } else {
                false
            };
        }
        &self.buf
    }
}

impl<P> PeriodicTrig<P>
where
    P: SigT<Item = f32>,
{
    fn new_s(period_s: P) -> Sig<Self> {
        Sig(Self {
            period_s,
            remaining_s: 0.0,
            buf: Vec::new(),
        })
    }
}

impl<P> PeriodicTrig<Sig<sig_div::OpScalarSig<f32, P>>>
where
    P: SigT<Item = f32>,
{
    fn new_hz(freq_hz: P) -> Sig<Self> {
        let period_s = 1.0 / Sig(freq_hz);
        Sig(Self {
            period_s,
            remaining_s: 0.0,
            buf: Vec::new(),
        })
    }
}

builder! {
    #[constructor = "periodic_trig_s"]
    #[constructor_doc = "A periodic trigger defined in terms of its period in seconds"]
    #[build_fn = "PeriodicTrig::new_s"]
    #[build_ty = "Sig<PeriodicTrig<P>>"]
    #[generic_setter_type_name = "X"]
    pub struct PropsBuilderS {
        #[generic_with_constraint = "SigT<Item = f32>"]
        #[generic_name = "P"]
        period_s: _,
    }
}

builder! {
    #[constructor = "periodic_trig_hz"]
    #[constructor_doc = "A periodic trigger defined in terms of its frequency in Hertz"]
    #[build_fn = "PeriodicTrig::new_hz"]
    #[build_ty = "Sig<PeriodicTrig<Sig<sig_div::OpScalarSig<f32, P>>>>"]
    #[generic_setter_type_name = "X"]
    pub struct PropsBuilderHz {
        #[generic_with_constraint = "SigT<Item = f32>"]
        #[generic_name = "P"]
        freq_hz: _,
    }
}