caw_modules 0.5.0

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

builder! {
    #[constructor = "sample_and_hold"]
    #[constructor_doc = "Always yields the value of its input signal when the trigger was last true"]
    #[generic_setter_type_name = "X"]
    pub struct Props {
        #[generic_with_constraint = "SigT<Item = bool>"]
        #[generic_name = "T"]
        trigger: _,
        #[generic_with_constraint = "Default"]
        #[generic_name = "V"]
        #[default = 0.0]
        initial_value: f32,
    }
}

impl<T, V> Filter for Props<T, V>
where
    T: SigT<Item = bool>,
    V: Default + Clone,
{
    type ItemIn = V;

    type Out<S>
        = SampleAndHold<S, T>
    where
        S: SigT<Item = Self::ItemIn>;

    fn into_sig<S>(self, sig: S) -> Self::Out<S>
    where
        S: SigT<Item = Self::ItemIn>,
    {
        let Props {
            trigger,
            initial_value,
        } = self;
        SampleAndHold {
            trigger,
            sig,
            value: initial_value,
            buf: Vec::new(),
        }
    }
}

pub struct SampleAndHold<S, T>
where
    S: SigT,
    S::Item: Clone + Default,
    T: SigT<Item = bool>,
{
    trigger: T,
    sig: S,
    value: S::Item,
    buf: Vec<S::Item>,
}

impl<S, T> SigT for SampleAndHold<S, T>
where
    S: SigT,
    S::Item: Clone + Default,
    T: SigT<Item = bool>,
{
    type Item = S::Item;

    fn sample(&mut self, ctx: &SigCtx) -> impl Buf<Self::Item> {
        self.buf.resize_with(ctx.num_samples, Default::default);
        let sig = self.sig.sample(ctx);
        let trigger = self.trigger.sample(ctx);
        for (out, sample, trigger) in izip! {
            self.buf.iter_mut(),
            sig.iter(),
            trigger.iter(),
        } {
            if trigger {
                self.value = sample;
            }
            *out = self.value.clone();
        }
        &self.buf
    }
}