eryon_nrt/types/
note.rs

1/*
2    Appellation: note <module>
3    Contrib: @FL03
4*/
5use crate::traits::PitchMod;
6use crate::types::Octave;
7
8#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
9#[cfg_attr(
10    feature = "serde",
11    derive(serde_derive::Deserialize, serde_derive::Serialize)
12)]
13pub struct Note {
14    pub(crate) class: usize,
15    pub(crate) octave: Octave,
16}
17
18impl Note {
19    pub fn new(class: usize, Octave(octave): Octave) -> Self {
20        Self {
21            class,
22            octave: Octave(octave),
23        }
24    }
25    /// returns a new note from a pitch value
26    pub fn from_pitch(pitch: usize) -> Self {
27        Self::new(pitch.pmod(), Octave(4))
28    }
29    /// returns a copy to the index of the note's class
30    pub const fn class(&self) -> usize {
31        self.class
32    }
33    /// returns a mutable reference to the index of the note's class
34    pub fn class_mut(&mut self) -> &mut usize {
35        &mut self.class
36    }
37    /// returns a copy to the octave of the note
38    pub const fn octave(&self) -> Octave {
39        self.octave
40    }
41    /// returns a mutable reference to the current octave
42    pub fn octave_mut(&mut self) -> &mut Octave {
43        &mut self.octave
44    }
45    /// set the pitch class of the note
46    pub fn set_class(&mut self, class: usize) {
47        self.class = class.pmod();
48    }
49    /// set the octave of the note
50    pub fn set_octave(&mut self, octave: Octave) {
51        self.octave = octave;
52    }
53    /// consumes the current instance to create another with the given pitch class
54    pub fn with_class(self, class: usize) -> Self {
55        Self { class, ..self }
56    }
57    /// consumes the current instance to create another with the given octave
58    pub fn with_octave(self, octave: Octave) -> Self {
59        Self { octave, ..self }
60    }
61}
62
63impl core::fmt::Display for Note {
64    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
65        write!(f, "{}.{}", self.class, self.octave)
66    }
67}
68
69impl core::ops::Add<Note> for Note {
70    type Output = Self;
71
72    fn add(self, rhs: Note) -> Self::Output {
73        Self::new(self.class + rhs.class, self.octave + rhs.octave)
74    }
75}
76
77impl core::ops::AddAssign<Note> for Note {
78    fn add_assign(&mut self, rhs: Note) {
79        self.class += rhs.class;
80        self.octave += rhs.octave;
81    }
82}
83
84impl core::ops::Add<usize> for Note {
85    type Output = Self;
86
87    fn add(self, rhs: usize) -> Self::Output {
88        Self::new(self.class + rhs, self.octave)
89    }
90}
91
92impl core::ops::AddAssign<usize> for Note {
93    fn add_assign(&mut self, rhs: usize) {
94        self.class = (self.class + rhs).pmod();
95    }
96}
97
98impl core::ops::Sub<usize> for Note {
99    type Output = Self;
100
101    fn sub(self, rhs: usize) -> Self::Output {
102        let class = self.class as isize - rhs as isize;
103        Self {
104            class: class.pmod() as usize,
105            ..self
106        }
107    }
108}
109
110impl core::ops::SubAssign<usize> for Note {
111    fn sub_assign(&mut self, rhs: usize) {
112        self.class = (self.class as isize - rhs as isize).pmod() as usize;
113    }
114}
115
116macro_rules! impl_note_from {
117    ($($t:ty),*) => {
118        $(
119            impl From<$t> for Note {
120                fn from(class: $t) -> Self {
121                    Note::from_pitch(class.pmod() as usize)
122                }
123            }
124
125            impl From<($t, Octave)> for Note {
126                fn from((class, octave): ($t, Octave)) -> Self {
127                    Note::new(class.pmod() as usize, octave)
128                }
129            }
130        )*
131    };
132}
133
134impl_note_from!(
135    usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128
136);