use crate::consts::A4_FREQUENCY;
use crate::freq::frequency::Frequency;
use crate::freq::{RawFrequency, classify_freq_with_scale, get_frequency_of_pitch};
use crate::pitch::{Accidental, PitchClass, RawPitchClass};
use num_traits::{Float, FromPrimitive, ToPrimitive};
use rstmt_traits::ClassifyBy;
impl<T> Frequency<T>
where
T: RawFrequency,
{
pub const fn new(index: T) -> Self {
Frequency(index)
}
pub fn from_class_with_scale<N>(note: N, root: T) -> Self
where
N: ToPrimitive,
T: Float + FromPrimitive,
{
let class = note.to_isize().unwrap();
Self(get_frequency_of_pitch(class, root))
}
pub fn from_class_on_a4<N>(note: N) -> Self
where
N: ToPrimitive,
T: Float + FromPrimitive,
{
let root = <T>::from_f64(A4_FREQUENCY).unwrap();
Self::from_class_with_scale(note, root)
}
pub fn from_pitch_class<P, K>(class: PitchClass<P, K>, root: T) -> Self
where
P: RawPitchClass<Tag = K>,
K: Accidental,
T: RawFrequency + Float + FromPrimitive,
{
let semitones = class.get().index();
Self::from_class_with_scale(semitones, root)
}
pub fn init<F>(f: F) -> Self
where
F: FnOnce() -> T,
{
Frequency(f())
}
pub fn one() -> Self
where
T: num_traits::One,
{
Frequency::init(T::one)
}
pub fn zero() -> Self
where
T: num_traits::Zero,
{
Frequency::init(T::zero)
}
pub const fn as_ptr(&self) -> *const T {
core::ptr::from_ref(self.get())
}
pub const fn as_mut_ptr(&mut self) -> *mut T {
core::ptr::from_mut(self.get_mut())
}
#[inline]
pub fn value(self) -> T {
self.0
}
pub const fn get(&self) -> &T {
&self.0
}
pub const fn get_mut(&mut self) -> &mut T {
&mut self.0
}
#[inline]
pub fn map<U, F>(self, f: F) -> Frequency<U>
where
F: FnOnce(T) -> U,
{
Frequency(f(self.value()))
}
#[inline]
pub fn apply<U, F>(&self, f: F) -> Frequency<U>
where
F: FnOnce(&T) -> U,
{
Frequency(f(self.get()))
}
pub fn apply_inplace<F>(&mut self, f: F) -> &mut Self
where
F: FnOnce(&mut T),
{
f(self.get_mut());
self
}
pub const fn replace(&mut self, index: T) -> T {
core::mem::replace(self.get_mut(), index)
}
#[inline]
pub fn set(&mut self, index: T) {
*self.get_mut() = index
}
pub const fn swap(&mut self, other: &mut Self) {
core::mem::swap(self.get_mut(), other.get_mut());
}
#[inline]
pub fn take(&mut self) -> T
where
T: Default,
{
core::mem::take(self.get_mut())
}
#[inline]
pub fn with<U>(self, other: U) -> Frequency<U> {
Frequency(other)
}
pub const fn view(&self) -> Frequency<&T> {
Frequency(self.get())
}
pub const fn view_mut(&mut self) -> Frequency<&mut T> {
Frequency(self.get_mut())
}
pub fn classify_by<Z>(&self, base: T) -> Z
where
Self: ClassifyBy<T, Output = Z>,
{
ClassifyBy::classify_by(self, base)
}
pub fn get_octave_with(&self, base: T) -> isize
where
T: Float + FromPrimitive,
{
self.classify_by(base) / 12
}
pub fn get_octave(&self) -> isize
where
T: Float + FromPrimitive,
{
let root = <T>::from_f64(A4_FREQUENCY).unwrap();
self.get_octave_with(root)
}
}
impl<T> ClassifyBy<T> for Frequency<T>
where
T: RawFrequency + Float + FromPrimitive,
{
type Output = isize;
fn classify_by(&self, base: T) -> Self::Output {
classify_freq_with_scale(self.value(), base).expect("failed to classify frequency")
}
}