euphony 0.1.1

music composition environment for programmers
Documentation
use crate::units::time::Beat;
use core::{
    pin::Pin,
    task::{Context, Poll},
};
use futures::{ready, stream, FutureExt, Stream, StreamExt};

pub use crate::rand::{OneOfExt as RandOneOfExt, TaskExt as RandTaskExt};

pub trait DelayExt {
    fn delay(self) -> crate::time::Timer;
}

impl DelayExt for Beat {
    fn delay(self) -> crate::time::Timer {
        crate::time::delay(self)
    }
}

impl DelayExt for &Beat {
    fn delay(self) -> crate::time::Timer {
        crate::time::delay(*self)
    }
}

impl DelayExt for u64 {
    fn delay(self) -> crate::time::Timer {
        crate::time::delay(Beat(self, 1))
    }
}

impl DelayExt for &u64 {
    fn delay(self) -> crate::time::Timer {
        crate::time::delay(Beat(*self, 1))
    }
}

pub trait DelayStreamExt {
    type Iter;

    fn delays(self) -> DelayStream<Self::Iter>;
}

impl<T> DelayStreamExt for T
where
    T: IntoIterator,
    T::Item: DelayExt,
{
    type Iter = T::IntoIter;

    fn delays(self) -> DelayStream<Self::Iter> {
        DelayStream::new(self.into_iter())
    }
}

pub struct DelayStream<T> {
    items: T,
    timer: Option<crate::time::Timer>,
}

impl<T: Clone> Clone for DelayStream<T> {
    fn clone(&self) -> Self {
        Self {
            items: self.items.clone(),
            timer: None,
        }
    }
}

impl<T> DelayStream<T> {
    pub const fn new(items: T) -> Self {
        Self { items, timer: None }
    }
}

type DelayStreamWith<Stream, IntoIter, Item> =
    stream::Map<stream::Zip<Stream, stream::Iter<IntoIter>>, fn(((), Item)) -> Item>;

impl<T> DelayStream<T>
where
    T: Iterator + Unpin,
    T::Item: DelayExt,
{
    pub fn with<V: IntoIterator>(self, values: V) -> DelayStreamWith<Self, V::IntoIter, V::Item> {
        self.zip(stream::iter(values.into_iter())).map(|(_, v)| v)
    }
}

impl<I> Stream for DelayStream<I>
where
    I: Iterator + Unpin,
    I::Item: DelayExt,
{
    type Item = ();

    fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
        if let Some(timer) = self.timer.as_mut() {
            ready!(timer.poll_unpin(cx));
        }

        let delay = if let Some(delay) = self.items.next() {
            delay
        } else {
            return None.into();
        };

        self.timer = Some(delay.delay());

        Poll::Ready(Some(()))
    }
}

pub trait SpawnExt {
    type Output;

    fn spawn(self) -> crate::runtime::JoinHandle<Self::Output>;
    fn spawn_primary(self) -> crate::runtime::JoinHandle<Self::Output>;
}

impl<F: 'static + core::future::Future + Send> SpawnExt for F
where
    F::Output: 'static + Send,
{
    type Output = F::Output;

    fn spawn(self) -> crate::runtime::JoinHandle<Self::Output> {
        crate::runtime::spawn(self)
    }

    fn spawn_primary(self) -> crate::runtime::JoinHandle<Self::Output> {
        crate::runtime::primary::spawn(self)
    }
}

pub trait EachExt {
    type Item;

    fn each<F: FnMut(&Self::Item) -> T, T>(&self, f: F) -> Vec<T>;
}

impl<U> EachExt for [U] {
    type Item = U;

    fn each<F: FnMut(&U) -> T, T>(&self, f: F) -> Vec<T> {
        self.iter().map(f).collect()
    }
}

impl EachExt for usize {
    type Item = usize;

    fn each<F: FnMut(&Self::Item) -> T, T>(&self, mut f: F) -> Vec<T> {
        (0..*self).map(|v| f(&v)).collect()
    }
}

pub trait MixIterExt {
    fn mix(self) -> crate::node::Node;
}

impl<I: IntoIterator<Item = T>, T: crate::processor::Processor> MixIterExt for I
where
    for<'a> &'a T: Into<crate::value::Parameter>,
{
    fn mix(self) -> crate::node::Node {
        self.into_iter().map(|v| v.node()).sum()
    }
}

impl core::iter::Sum for crate::node::Node {
    fn sum<I: Iterator<Item = Self>>(mut items: I) -> Self {
        use crate::processor::Processor;

        if let Some(acc) = items.next() {
            let mut acc = acc.node();
            for item in items {
                acc = (acc + item).node();
            }
            acc
        } else {
            crate::processors::osc::silence().node()
        }
    }
}

pub trait MixTupleExt {
    fn mix(&self) -> crate::node::Node;
}

macro_rules! sum_tuple {
    () => {};
    ($H:ident $(,$T:ident)* $(,)?) => {
        impl<$H, $($T,)*> MixTupleExt for ($H, $($T,)*)
        where
            $H: crate::processor::Processor,
            for<'a> &'a $H: Into<crate::value::Parameter>,
            $(
                $T: crate::processor::Processor,
                for<'a> &'a $T: Into<crate::value::Parameter>,
            )*
        {
            #[allow(non_snake_case)]
            fn mix(&self) -> crate::node::Node {
                #[allow(unused_imports)]
                use crate::processor::Processor;

                let (
                    $H,
                    $(
                        $T,
                    )*
                ) = self;

                let acc = $H.node();

                $(
                    let acc = (acc + $T).node();
                )*

                acc
            }
        }

        sum_tuple!($($T),*);
    };
}

sum_tuple!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z);

pub trait FreqExt {
    fn freq(&self) -> crate::prelude::Frequency;
}

impl FreqExt for crate::prelude::Interval {
    fn freq(&self) -> crate::prelude::Frequency {
        (crate::pitch::mode() * *self) * crate::pitch::tuning()
    }
}

impl FreqExt for f64 {
    fn freq(&self) -> crate::prelude::Frequency {
        (*self).into()
    }
}