rstmt_core/pitch/
pbase.rs

1/*
2    Appellation: aspn <module>
3    Contrib: @FL03
4*/
5use crate::PitchMod;
6use crate::freq::{Frequency, RawFrequency};
7
8/// A discrete pitch with a class and frequency.
9#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
10#[cfg_attr(
11    feature = "serde",
12    derive(serde::Deserialize, serde::Serialize),
13    serde(deny_unknown_fields, rename_all = "snake_case")
14)]
15#[repr(C)]
16pub struct Pitch<T = f32> {
17    pub(crate) class: usize,
18    pub(crate) freq: Frequency<T>,
19}
20
21impl<T> Pitch<T>
22where
23    T: RawFrequency,
24{
25    pub fn new(class: usize, freq: Frequency<T>) -> Self {
26        Self { class, freq }
27    }
28    /// returns a copy to the index of the note's class
29    pub const fn class(&self) -> usize {
30        self.class
31    }
32    /// returns a mutable reference to the index of the note's class
33    pub fn class_mut(&mut self) -> &mut usize {
34        &mut self.class
35    }
36    /// returns a reference to the frequency of the pitch
37    pub const fn frequency(&self) -> &Frequency<T> {
38        &self.freq
39    }
40    /// returns a mutable reference to the current octave
41    pub const fn frequency_mut(&mut self) -> &mut Frequency<T> {
42        &mut self.freq
43    }
44    /// set the pitch class and return a mutable reference to the current instance
45    pub fn set_class(&mut self, class: usize) -> &mut Self {
46        self.class = class.pmod();
47        self
48    }
49    /// set the frequency and return a mutable reference to the current instance
50    pub fn set_frequency(&mut self, freq: Frequency<T>) -> &mut Self {
51        self.freq = freq;
52        self
53    }
54    /// consumes the current instance to create another with the given pitch class
55    pub fn with_class(self, class: usize) -> Self {
56        Self { class, ..self }
57    }
58    /// consumes the current instance to create another with the given frequency
59    pub fn with_frequency<T2>(self, freq: Frequency<T2>) -> Pitch<T2>
60    where
61        T2: RawFrequency,
62    {
63        Pitch {
64            class: self.class,
65            freq,
66        }
67    }
68}
69
70impl<T> Default for Pitch<T>
71where
72    T: Default,
73{
74    fn default() -> Self {
75        Pitch {
76            class: 0,
77            freq: Frequency::default(),
78        }
79    }
80}
81
82impl<T> core::fmt::Display for Pitch<T>
83where
84    T: RawFrequency,
85{
86    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
87        write!(f, "{}.{}", self.class, self.freq)
88    }
89}
90
91impl<T> PartialEq<Frequency<T>> for Pitch<T>
92where
93    T: RawFrequency + PartialEq,
94{
95    fn eq(&self, other: &Frequency<T>) -> bool {
96        self.frequency() == other
97    }
98}
99
100impl<T> PartialEq<usize> for Pitch<T>
101where
102    T: RawFrequency,
103{
104    fn eq(&self, other: &usize) -> bool {
105        self.class() == *other
106    }
107}
108
109impl<T> PartialEq<Pitch<T>> for usize
110where
111    T: RawFrequency,
112{
113    fn eq(&self, other: &Pitch<T>) -> bool {
114        *self == other.class()
115    }
116}
117
118impl<T> PartialOrd<usize> for Pitch<T>
119where
120    T: RawFrequency,
121{
122    fn partial_cmp(&self, other: &usize) -> Option<core::cmp::Ordering> {
123        self.class().partial_cmp(other)
124    }
125}
126
127impl<T> PartialOrd<Pitch<T>> for usize
128where
129    T: RawFrequency,
130{
131    fn partial_cmp(&self, other: &Pitch<T>) -> Option<core::cmp::Ordering> {
132        self.partial_cmp(&other.class())
133    }
134}