oscillation 0.1.1

Oscillators and a collection of waveforms for real-time usage.
Documentation
use num_traits::{Float, FloatConst};

use crate::{waveform::Waveform, Wavetable, WavetableView};

use super::{Direct, DirectDTC, OscillatorState, Wave};

#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
pub struct WaveDTC<F, W, const N: usize>
where
    F: Float + FloatConst,
    W: Waveform<F>
{
    pub waveform: W,
    pub duty_cycle: F,
    #[serde(skip)]
    wavetable: Option<Option<Wavetable<F, N>>>
}

impl<F, W, const N: usize> From<W> for WaveDTC<F, W, N>
where
    F: Float + FloatConst,
    W: Waveform<F>
{
    fn from(waveform: W) -> Self
    {
        Direct::from(waveform).into()
    }
}
impl<F, W, const N: usize> From<Direct<W>> for WaveDTC<F, W, N>
where
    F: Float + FloatConst,
    W: Waveform<F>
{
    fn from(value: Direct<W>) -> Self
    {
        DirectDTC::from(value).into()
    }
}
impl<F, W, const N: usize> From<DirectDTC<F, W>> for WaveDTC<F, W, N>
where
    F: Float + FloatConst,
    W: Waveform<F>
{
    fn from(value: DirectDTC<F, W>) -> Self
    {
        let DirectDTC {waveform, duty_cycle} = value;
        Self {
            waveform,
            duty_cycle,
            wavetable: None
        }
    }
}
impl<F, W, const N: usize> From<Wave<F, W, N>> for WaveDTC<F, W, N>
where
    F: Float + FloatConst,
    W: Waveform<F>
{
    fn from(value: Wave<F, W, N>) -> Self
    {
        value.with_dtc(crate::duty_cycle_default())
    }
}

impl<F, W, const N: usize> OscillatorState<F> for WaveDTC<F, W, N>
where
    F: Float + FloatConst,
    W: Waveform<F>
{
    type Waveform = W;

    type WithDTC = WaveDTC<F, W, N>;
    type WithoutDTC = Wave<F, W, N>;

    type WithWavetable<const NN: usize> = WaveDTC<F, W, NN>;
    type WithoutWavetable = DirectDTC<F, W>;

    type WithWaveform<WW> = WaveDTC<F, WW, N>
    where
        WW: Waveform<F>;

    fn next(&mut self, theta: F, omega: F, rate: F) -> F
    {
        let zero = F::zero();
        let pi = F::PI();
        let nyq = pi*rate;
        if nyq <= omega
        {
            return zero
        }

        if N != 0
            && let up_to = (nyq/omega).abs().to_usize().unwrap_or(N)
            && up_to <= N
            && let Some(wavetable) = self.wavetable.get_or_insert_with(|| self.waveform.wavetable_with_dtc(self.duty_cycle))
            && let Some(y) = wavetable.waveform(theta, up_to)
        {
            y
        }
        else
        {
            self.waveform.waveform_with_dtc(theta, self.duty_cycle)
        }
    }

    fn duty_cycle(&self) -> F
    {
        self.duty_cycle
    }

    fn wavetable(&self) -> Option<WavetableView<'_, F>>
    {
        self.wavetable.as_ref().and_then(|w| w.as_ref().map(Wavetable::view))
    }

    fn waveform(&self) -> &Self::Waveform
    {
        &self.waveform
    }
    fn waveform_mut(&mut self) -> &mut Self::Waveform
    {
        &mut self.waveform
    }

    fn with_dtc(self, duty_cycle: F) -> Self::WithDTC
    {
        self.without_wavetable().with_dtc(duty_cycle).with_wavetable()
    }
    fn without_dtc(self) -> Self::WithoutDTC
    {
        self.without_wavetable().without_dtc().with_wavetable()
    }

    fn with_wavetable<const NN: usize>(self) -> Self::WithWavetable<NN>
    {
        let Self {waveform, duty_cycle, wavetable} = self;
        WaveDTC {
            waveform,
            duty_cycle,
            wavetable: wavetable.map(|w| w.and_then(Wavetable::truncate))
        }
    }
    fn without_wavetable(self) -> Self::WithoutWavetable
    {
        let Self {waveform, duty_cycle, wavetable: _} = self;
        DirectDTC {
            waveform,
            duty_cycle
        }
    }

    fn map_waveform<WW>(self, waveform: impl FnOnce(Self::Waveform) -> WW) -> Self::WithWaveform<WW>
    where
        WW: Waveform<F>
    {
        self.without_wavetable().map_waveform(waveform).with_wavetable()
    }
}