rstmt_core/
note.rs

1/*
2    Appellation: aspn <module>
3    Contrib: @FL03
4*/
5mod impl_aspn;
6mod impl_aspn_ext;
7mod impl_note_base;
8mod impl_note_ext;
9mod impl_note_repr;
10
11use crate::octave::Octave;
12use crate::pitch::{self, PitchClass, RawAccidental, RawPitchClass};
13
14/// The [`AsAspn`] trait is used to convert a reference into a [`Aspn`]
15pub trait AsAspn {
16    fn as_aspn(&self) -> Aspn;
17}
18/// A trait for converting a type into a [`Aspn`]
19pub trait IntoAspn {
20    fn into_aspn(self) -> Aspn;
21}
22
23/// An american scientific pitch notation ([`Aspn`]) representation of a musical note; this
24/// standard is used to represent notes in a way that is consistent with the
25/// American scientific pitch notation system, which uses a combination of a pitch class
26/// (represented as an integer) and an octave (represented as an [`Octave`]) to uniquely
27/// identify a musical note. The pitch class is the note's position in the chromatic scale,
28/// while the octave indicates the note's position in the musical range.
29#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
30#[cfg_attr(
31    feature = "serde",
32    derive(serde::Deserialize, serde::Serialize),
33    serde(deny_unknown_fields, default, rename_all = "snake_case")
34)]
35#[repr(C)]
36pub struct Aspn {
37    pub(crate) class: usize,
38    pub(crate) octave: Octave,
39}
40
41/// The [`NoteBase`] is a generic representation of a musical note
42#[derive(Clone, Copy, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
43#[cfg_attr(
44    feature = "serde",
45    derive(serde::Deserialize, serde::Serialize),
46    serde(rename_all = "snake_case")
47)]
48#[repr(C)]
49pub struct NoteBase<P = pitch::CNote, K = <P as RawPitchClass>::Tag>
50where
51    P: RawPitchClass<Tag = K>,
52    K: RawAccidental,
53{
54    pub(crate) class: PitchClass<P, K>,
55    pub(crate) octave: Octave,
56}
57
58/*
59 ************* Implementations *************
60*/
61impl<T> AsAspn for T
62where
63    T: Clone + IntoAspn,
64{
65    fn as_aspn(&self) -> Aspn {
66        self.clone().into_aspn()
67    }
68}
69
70impl<T> IntoAspn for T
71where
72    T: Into<Aspn>,
73{
74    fn into_aspn(self) -> Aspn {
75        self.into()
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use super::NoteBase;
82    use crate::octave::Octave;
83    use crate::pitch::{C, CNote};
84
85    #[test]
86    fn test_note_from_octave() {
87        assert_eq! { NoteBase::<CNote>::from_octave(Octave(4)), "C.4" }
88    }
89    #[test]
90    // #[ignore = "need to fix"]
91    fn test_note_parse() {
92        let exp = NoteBase::new(C::default(), Octave(4));
93        assert_eq! { "C.4".parse::<NoteBase<_, _>>().unwrap(), exp }
94    }
95}