use crate::triad::TriadBase;
use crate::traits::{TriadRepr, TriadReprMut, TriadType};
use crate::types::LPR;
use num_traits::{Float, FromPrimitive, ToPrimitive, Zero};
use rstmt_core::{Octave, PitchMod, Transform};
impl<S, T, K> TriadBase<S, K, T>
where
K: TriadType,
S: TriadRepr<Elem = T>,
{
pub fn new(chord: S, class: K) -> Self
where
T: Zero,
{
Self {
chord,
class,
octave: Octave::zero(),
}
}
pub fn from_root_with_class(root: T, class: K) -> Self
where
T: Copy + FromPrimitive + Zero + PitchMod<Output = T> + core::ops::Add<Output = T>,
{
let chord = [
root,
(root + T::from_usize(class.root()).unwrap()).pmod(),
(root + T::from_usize(class.fifth()).unwrap()).pmod(),
];
Self {
class,
chord: S::from_arr(chord),
octave: Octave::zero(),
}
}
#[inline]
pub fn dynamic(self) -> TriadBase<S, crate::Triads, T> {
TriadBase {
chord: self.chord,
class: crate::Triads::from_class(self.class),
octave: self.octave,
}
}
pub const fn chord(&self) -> &S {
&self.chord
}
pub const fn chord_mut(&mut self) -> &mut S {
&mut self.chord
}
pub const fn class(&self) -> &K {
&self.class
}
pub const fn class_mut(&mut self) -> &mut K {
&mut self.class
}
pub const fn octave(&self) -> &Octave<T> {
&self.octave
}
pub const fn octave_mut(&mut self) -> &mut Octave<T> {
&mut self.octave
}
pub fn root(&self) -> &T
where
S: TriadRepr,
{
self.chord().root()
}
pub fn root_mut(&mut self) -> &mut T
where
S: TriadReprMut,
{
self.chord_mut().root_mut()
}
pub fn third(&self) -> &T
where
S: TriadRepr,
{
self.chord().third()
}
pub fn third_mut(&mut self) -> &mut T
where
S: TriadReprMut,
{
self.chord_mut().third_mut()
}
pub fn fifth(&self) -> &T
where
S: TriadRepr,
{
self.chord().fifth()
}
pub fn fifth_mut(&mut self) -> &mut T
where
S: TriadReprMut,
{
self.chord_mut().fifth_mut()
}
pub fn set_chord(&mut self, chord: S) -> &mut Self {
self.chord = chord;
self
}
pub fn set_class(&mut self, class: K) -> &mut Self {
self.class = class;
self
}
#[inline]
pub fn with_chord<S2>(self, chord: S2) -> TriadBase<S2, K>
where
S2: TriadRepr<Elem = T>,
T: Sized,
{
TriadBase {
chord,
class: self.class,
octave: self.octave,
}
}
#[inline]
pub fn with_class<K2>(self, class: K2) -> TriadBase<S, K2>
where
K2: TriadType,
{
TriadBase {
chord: self.chord,
class,
octave: self.octave,
}
}
#[inline]
pub fn with_octave(self, octave: Octave<T>) -> Self {
Self { octave, ..self }
}
pub fn into_parts(self) -> (S, K) {
(self.chord, self.class)
}
pub fn is_augmented(&self) -> bool {
self.class().is_augmented()
}
pub fn is_diminished(&self) -> bool {
self.class().is_diminished()
}
pub fn is_major(&self) -> bool {
self.class().is_major()
}
pub fn is_minor(&self) -> bool {
self.class().is_minor()
}
pub fn centroid<U>(&self) -> Option<[U; 2]>
where
T: Copy + ToPrimitive,
U: Float + FromPrimitive + ToPrimitive + core::iter::Sum<T>,
S: Clone + IntoIterator<Item = T>,
{
let y = U::from(*self.octave().get())?;
let x = self.chord().clone().into_iter().sum::<U>() / U::from_u8(3)?;
Some([x, y])
}
pub fn contains<Q>(&self, note: &Q) -> bool
where
for<'a> &'a S: IntoIterator<Item = &'a T>,
T: PartialEq,
Q: core::borrow::Borrow<T>,
{
self.chord().into_iter().any(|n| n == note.borrow())
}
#[cfg(feature = "alloc")]
pub fn common_tones(&self, other: &Self) -> alloc::vec::Vec<T>
where
T: Clone + PartialEq,
for<'a> &'a S: IntoIterator<Item = &'a T>,
{
self.chord()
.into_iter()
.filter(|n| other.contains(n))
.cloned()
.collect::<alloc::vec::Vec<_>>()
}
pub fn transform<X, Y>(self, step: X) -> Y
where
Self: Transform<X, Output = Y>,
{
<Self as Transform<X>>::transform(self, step)
}
pub fn leading<Y>(self) -> Y
where
Self: Transform<LPR, Output = Y>,
{
self.transform(LPR::Leading)
}
pub fn parallel<Y>(self) -> Y
where
Self: Transform<LPR, Output = Y>,
{
self.transform(LPR::Parallel)
}
pub fn relative<Y>(self) -> Y
where
Self: Transform<LPR, Output = Y>,
{
self.transform(LPR::Relative)
}
#[cfg(feature = "motion")]
pub fn path_finder(&self) -> crate::motion::PathFinder<'_, S, K, T> {
crate::motion::PathFinder::new(self)
}
}