use crate::triad::TriadBase;
use crate::traits::TriadRepr;
use crate::types::{LPR, Triads};
use num_traits::{Float, FromPrimitive, Num, ToPrimitive, Zero};
use rstmt_core::traits::{PitchMod, Transform};
use rstmt_core::{Augmented, Diminished, Major, Minor};
impl<S, T> TriadBase<S, Augmented, T>
where
S: TriadRepr<Elem = T>,
{
pub fn augmented(root: T) -> Self
where
T: Copy + FromPrimitive + Zero + PitchMod<Output = T> + core::ops::Add<Output = T>,
{
TriadBase::from_root_with_class(root, Augmented)
}
}
impl<S, T> TriadBase<S, Diminished, T>
where
S: TriadRepr<Elem = T>,
{
pub fn diminished(root: T) -> Self
where
T: Copy + FromPrimitive + Zero + PitchMod<Output = T> + core::ops::Add<Output = T>,
{
TriadBase::from_root_with_class(root, Diminished)
}
}
impl<S, T> TriadBase<S, Major, T>
where
S: TriadRepr<Elem = T>,
{
pub fn major(root: T) -> Self
where
T: Copy + FromPrimitive + Zero + PitchMod<Output = T> + core::ops::Add<Output = T>,
{
TriadBase::from_root_with_class(root, Major)
}
}
impl<S, T> TriadBase<S, Minor, T>
where
S: TriadRepr<Elem = T>,
{
pub fn minor(root: T) -> Self
where
T: Copy + FromPrimitive + Zero + PitchMod<Output = T> + core::ops::Add<Output = T>,
{
TriadBase::from_root_with_class(root, Minor)
}
}
impl<T> TriadBase<[T; 3], Triads, T>
where
T: Copy + ToPrimitive + FromPrimitive + PitchMod<Output = T> + core::ops::Add<Output = T>,
{
pub fn barycentric<N, U>(&self, p: N) -> [U; 3]
where
T: Copy + ToPrimitive,
N: rstmt_core::IntoAspn,
U: Float + FromPrimitive,
{
let note = p.into_aspn();
let px = U::from_usize(note.class().pmod()).unwrap();
let py = U::from_isize(*note.octave()).unwrap();
let y = U::from(*self.octave).unwrap();
let [v0, v1, v2] = self.chord().map(|n| U::from(n).unwrap());
let d00 = v0 * v0 + y * y;
let d01 = v0 * v1 + y * y;
let d11 = v1 * v1 + y * y;
let d20 = v2 * px + y * py;
let d21 = v2 * v1 + y * y;
let denom = d00 * d11 - d01 * d01;
let a = (d11 * d20 - d01 * d21) / denom;
let b = (d00 * d21 - d01 * d20) / denom;
let c = U::one() - a - b;
[a, b, c]
}
pub fn is_valid(&self) -> bool
where
T: Copy
+ PartialEq
+ FromPrimitive
+ ToPrimitive
+ PitchMod<Output = T>
+ core::ops::Sub<Output = T>,
{
self.class().validate(self.chord())
}
pub fn is_neighbor(&self, other: &Self) -> Option<LPR>
where
Self: Transform<LPR, Output = Self>,
T: PartialEq,
{
LPR::iter().find(|&dirac| self.transform(dirac) == *other)
}
}
impl<T> TriadBase<[T; 3], Triads, T>
where
T: Copy + ToPrimitive + FromPrimitive + Num + PitchMod<Output = T>,
{
pub fn walk<I>(&self, path: I) -> Self
where
I: IntoIterator<Item = LPR>,
{
path.into_iter()
.fold(*self, |triad, dirac| dirac.apply(triad))
}
pub fn walk_inplace<I>(&mut self, path: I)
where
I: IntoIterator<Item = LPR>,
{
*self = self.walk(path);
}
}
impl TriadBase<[usize; 3], Triads> {
pub fn transform_inplace(&mut self, transform: LPR) {
*self = self.transform(transform);
}
}