use crate::prelude::*;
pub struct DetuneIter {
detune: unt::Interval,
num: u16,
output: unt::Interval,
index: u16,
}
impl DetuneIter {
#[must_use]
pub fn new(detune: unt::Interval, num: u16) -> Self {
let num_i32 = i32::from(num);
let output = if num % 2 == 0 {
detune.sqrt() * detune.powi(num_i32 / 2 - 1)
} else {
detune.powi(num_i32 / 2)
};
Self {
detune,
num,
output,
index: 0,
}
}
#[must_use]
pub fn size(&self) -> u16 {
self.num - self.index
}
}
impl Iterator for DetuneIter {
type Item = unt::Interval;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.num {
None
} else {
let res = self.output;
self.output /= self.detune;
self.index += 1;
Some(res)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.size() as usize;
(size, Some(size))
}
}
pub struct UnisonCurve<C: Map<Input = unt::Val>>
where
C::Output: smp::Sample,
{
map: C,
base: unt::Freq,
val_inters: Vec<(unt::Val, unt::Interval)>,
}
impl<C: Map<Input = unt::Val>> UnisonCurve<C>
where
C::Output: smp::Sample,
{
pub const fn new_curve_phases(
map: C,
base: unt::Freq,
val_inters: Vec<(unt::Val, unt::Interval)>,
) -> Self {
Self {
map,
base,
val_inters,
}
}
pub fn new_curve<I: IntoIterator<Item = unt::Interval>>(
map: C,
base: unt::Freq,
intervals: I,
) -> Self {
Self {
map,
base,
val_inters: intervals.into_iter().map(|x| (unt::Val::ZERO, x)).collect(),
}
}
pub fn detune_curve(map: C, base: unt::Freq, detune: unt::Interval, num: u16) -> Self {
Self::new_curve(map, base, DetuneIter::new(detune, num))
}
pub fn len(&self) -> usize {
self.val_inters.len()
}
pub fn is_empty(&self) -> bool {
self.val_inters.is_empty()
}
pub const fn map(&self) -> &C {
&self.map
}
pub fn map_mut(&mut self) -> &mut C {
&mut self.map
}
pub fn intervals(&self) -> impl Iterator<Item = unt::Interval> + '_ {
self.val_inters.iter().map(|&(_, interval)| interval)
}
pub fn intervals_mut(&mut self) -> impl Iterator<Item = &mut unt::Interval> {
self.val_inters.iter_mut().map(|(_, interval)| interval)
}
pub fn val(&self) -> impl Iterator<Item = unt::Val> + '_ {
self.val_inters.iter().map(|&(val, _)| val)
}
pub fn val_mut(&mut self) -> impl Iterator<Item = &mut unt::Val> {
self.val_inters.iter_mut().map(|(val, _)| val)
}
pub fn get_at(&self, index: u8) -> C::Output {
self.map().eval(self.val_inters[index as usize].0)
}
pub fn randomize_phases(&mut self) {
for val in self.val_mut() {
use rand::Rng;
*val = rand::thread_rng().gen();
}
}
}
impl<C: Map<Input = unt::Val>> Signal for UnisonCurve<C>
where
C::Output: smp::Sample,
{
type Sample = C::Output;
fn get(&self) -> C::Output {
self.val_inters
.iter()
.map(|&(val, _)| self.map().eval(val))
.sum()
}
}
impl<C: Map<Input = unt::Val>> SignalMut for UnisonCurve<C>
where
C::Output: smp::Sample,
{
fn advance(&mut self) {
for (val, interval) in &mut self.val_inters {
val.advance_freq(*interval * self.base);
}
}
fn retrigger(&mut self) {
for vf in &mut self.val_inters {
vf.0 = unt::Val::ZERO;
}
}
}
impl<C: Map<Input = unt::Val>> Base for UnisonCurve<C>
where
C::Output: smp::Sample,
{
impl_base!();
}
impl<C: Map<Input = unt::Val>> Frequency for UnisonCurve<C>
where
C::Output: smp::Sample,
{
fn freq(&self) -> unt::Freq {
self.base
}
fn freq_mut(&mut self) -> &mut unt::Freq {
&mut self.base
}
}
pub type Unison<S, C> = UnisonCurve<gen::CurvePlayer<S, C>>;
impl<S: smp::Sample, C: Map<Input = unt::Val, Output = f64>> Unison<S, C> {
pub fn new_phases<I: IntoIterator<Item = f64>>(
map: C,
base: unt::Freq,
val_inters: Vec<(unt::Val, unt::Interval)>,
) -> Self {
Self::new_curve_phases(gen::CurvePlayer::new(map), base, val_inters)
}
pub fn new<I: IntoIterator<Item = unt::Interval>>(
map: C,
base: unt::Freq,
intervals: I,
) -> Self {
Self::new_curve(gen::CurvePlayer::new(map), base, intervals)
}
pub fn detune(map: C, base: unt::Freq, detune: unt::Interval, num: u16) -> Self {
Self::detune_curve(gen::CurvePlayer::new(map), base, detune, num)
}
}
#[derive(Clone, Copy, Debug, Default)]
pub struct Detune;
impl<C: Map<Input = unt::Val>> Env<UnisonCurve<C>> for Detune
where
C::Output: smp::Sample,
{
fn modify_env(&mut self, sgn: &mut UnisonCurve<C>, val: smp::Env) {
#[allow(clippy::cast_possible_truncation)]
let num = sgn.len() as u16;
for (int, detune) in sgn
.intervals_mut()
.zip(DetuneIter::new(unt::Interval::note(12.0 * val.0), num))
{
*int = detune;
}
}
}
pub type DetuneCurveSgn<C, E> = eff::MutSgn<UnisonCurve<C>, E, Detune>;
pub type DetuneSgn<S, C, E> = eff::MutSgn<Unison<S, C>, E, Detune>;
impl<C: Map<Input = unt::Val>, E: SignalMut<Sample = smp::Env>> DetuneCurveSgn<C, E>
where
C::Output: smp::Sample,
{
pub fn new_detune_curve(map: C, base: unt::Freq, num: u8, env: E) -> Self {
Self::new(
UnisonCurve::new_curve(
map,
base,
std::iter::repeat(unt::Interval::UNISON).take(num as usize),
),
env,
Detune,
)
}
}
impl<S: smp::Sample, C: Map<Input = unt::Val, Output = f64>, E: SignalMut<Sample = smp::Env>>
DetuneSgn<S, C, E>
{
pub fn new_detune(map: C, base: unt::Freq, num: u8, env: E) -> Self {
Self::new_detune_curve(gen::CurvePlayer::new(map), base, num, env)
}
}
pub struct UnisonRef<'a, C: Map<Input = unt::Val>>
where
C::Output: smp::Sample,
{
pub unison: &'a UnisonCurve<C>,
pub index: u8,
}
impl<'a, C: Map<Input = unt::Val>> UnisonRef<'a, C>
where
C::Output: smp::Sample,
{
pub const fn new(unison: &'a UnisonCurve<C>, index: u8) -> Self {
Self { unison, index }
}
}
impl<'a, C: Map<Input = unt::Val>> Signal for UnisonRef<'a, C>
where
C::Output: smp::Sample,
{
type Sample = C::Output;
fn get(&self) -> C::Output {
self.unison.get_at(self.index)
}
}