rstmt_core/pitch/
kinds.rs

1/*
2    Appellation: pitches <module>
3    Contrib: FL03 <jo3mccain@icloud.com>
4*/
5use super::{PitchClass, PitchTy};
6
7pitch_class! {
8    #[default(C)]
9    pub enum Natural {
10        C = 0,
11        D = 2,
12        E = 4,
13        F = 5,
14        G = 7,
15        A = 9,
16        B = 11,
17    }
18}
19
20pitch_class! {
21    #[default(C)]
22    pub enum Sharp {
23        C = 1,
24        D = 3,
25        F = 6,
26        G = 8,
27        A = 10,
28    }
29}
30
31pitch_class! {
32    #[default(D)]
33    pub enum Flat {
34        D = 1,
35        E = 3,
36        G = 6,
37        A = 8,
38        B = 10,
39    }
40}
41
42#[derive(
43    Clone,
44    Copy,
45    Eq,
46    Hash,
47    Ord,
48    PartialEq,
49    PartialOrd,
50    smart_default::SmartDefault,
51    strum::AsRefStr,
52    strum::EnumCount,
53    strum::EnumIs,
54    strum::VariantNames,
55)]
56#[cfg_attr(
57    feature = "serde",
58    derive(serde::Deserialize, serde::Serialize),
59    serde(rename_all = "lowercase")
60)]
61#[repr(i8)]
62#[strum(serialize_all = "lowercase")]
63pub enum Pitches {
64    Flat(Flat),
65    #[default]
66    Natural(Natural),
67    Sharp(Sharp),
68}
69
70impl Pitches {
71    pub fn try_from_value(value: PitchTy) -> Result<Self, crate::Error> {
72        if let Ok(n) = Natural::try_from_value(value) {
73            Ok(n.as_class())
74        } else if let Ok(s) = Sharp::try_from_value(value) {
75            Ok(s.as_class())
76        } else if let Ok(f) = Flat::try_from_value(value) {
77            Ok(f.as_class())
78        } else {
79            Err(crate::Error::music_error("Invalid pitch value."))
80        }
81    }
82
83    pub fn value(&self) -> PitchTy {
84        match self {
85            Pitches::Flat(f) => f.pitch(),
86            Pitches::Natural(n) => n.pitch(),
87            Pitches::Sharp(s) => s.pitch(),
88        }
89    }
90}
91
92impl core::fmt::Debug for Pitches {
93    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
94        use Pitches::*;
95        match self {
96            Flat(cls) => write!(f, "{}♭", cls.as_ref()),
97            Natural(cls) => write!(f, "{}", cls.as_ref()),
98            Sharp(cls) => write!(f, "{}#", cls.as_ref()),
99        }
100    }
101}
102
103impl core::fmt::Display for Pitches {
104    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
105        use Pitches::*;
106        match self {
107            Flat(cls) => write!(f, "{}♭", cls.as_ref()),
108            Natural(cls) => write!(f, "{}", cls.as_ref()),
109            Sharp(cls) => write!(f, "{}#", cls.as_ref()),
110        }
111    }
112}
113
114impl PitchClass for Pitches {
115    seal!();
116
117    fn pitch(&self) -> PitchTy {
118        self.value()
119    }
120}
121
122impl From<Pitches> for PitchTy {
123    fn from(pitch: Pitches) -> PitchTy {
124        pitch.value()
125    }
126}
127
128impl From<PitchTy> for Pitches {
129    fn from(value: PitchTy) -> Pitches {
130        Self::try_from_value(value).unwrap_or_default()
131    }
132}