use std::fmt::Display;
use serde::{Deserialize, Serialize};
use crate::prelude::{Key, Semitones};
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)]
pub enum PitchName {
C,
D,
E,
F,
G,
A,
B,
}
impl Display for PitchName {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)]
pub enum PitchSign {
DoubleFlat,
Flat,
Natural,
Sharp,
DoubleSharp,
}
impl Display for PitchSign {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", match self {
PitchSign::Natural => "",
PitchSign::Sharp => "#",
PitchSign::Flat => "b",
PitchSign::DoubleSharp => "##",
PitchSign::DoubleFlat => "bb",
})
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Debug)]
pub struct Pitch {
pub name: PitchName,
pub sign: PitchSign,
}
impl Display for Pitch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{}", self.name, self.sign)
}
}
impl Pitch {
pub const C: Pitch = Self {
name: PitchName::C,
sign: PitchSign::Natural,
};
pub const D: Pitch = Self {
name: PitchName::D,
sign: PitchSign::Natural,
};
pub const E: Pitch = Self {
name: PitchName::E,
sign: PitchSign::Natural,
};
pub const F: Pitch = Self {
name: PitchName::F,
sign: PitchSign::Natural,
};
pub const G: Pitch = Self {
name: PitchName::G,
sign: PitchSign::Natural,
};
pub const A: Pitch = Self {
name: PitchName::A,
sign: PitchSign::Natural,
};
pub const B: Pitch = Self {
name: PitchName::B,
sign: PitchSign::Natural,
};
pub const C_SHARP: Pitch = Self {
name: PitchName::C,
sign: PitchSign::Sharp,
};
pub const D_SHARP: Pitch = Self {
name: PitchName::D,
sign: PitchSign::Sharp,
};
pub const E_SHARP: Pitch = Self {
name: PitchName::E,
sign: PitchSign::Sharp,
};
pub const F_SHARP: Pitch = Self {
name: PitchName::F,
sign: PitchSign::Sharp,
};
pub const G_SHARP: Pitch = Self {
name: PitchName::G,
sign: PitchSign::Sharp,
};
pub const A_SHARP: Pitch = Self {
name: PitchName::A,
sign: PitchSign::Sharp,
};
pub const B_SHARP: Pitch = Self {
name: PitchName::B,
sign: PitchSign::Sharp,
};
pub const C_FLAT: Pitch = Self {
name: PitchName::C,
sign: PitchSign::Flat,
};
pub const D_FLAT: Pitch = Self {
name: PitchName::D,
sign: PitchSign::Flat,
};
pub const E_FLAT: Pitch = Self {
name: PitchName::E,
sign: PitchSign::Flat,
};
pub const F_FLAT: Pitch = Self {
name: PitchName::F,
sign: PitchSign::Flat,
};
pub const G_FLAT: Pitch = Self {
name: PitchName::G,
sign: PitchSign::Flat,
};
pub const A_FLAT: Pitch = Self {
name: PitchName::A,
sign: PitchSign::Flat,
};
pub const B_FLAT: Pitch = Self {
name: PitchName::B,
sign: PitchSign::Flat,
};
pub const C_DOUBLE_SHARP: Pitch = Self {
name: PitchName::C,
sign: PitchSign::DoubleSharp,
};
pub const D_DOUBLE_SHARP: Pitch = Self {
name: PitchName::D,
sign: PitchSign::DoubleSharp,
};
pub const E_DOUBLE_SHARP: Pitch = Self {
name: PitchName::E,
sign: PitchSign::DoubleSharp,
};
pub const F_DOUBLE_SHARP: Pitch = Self {
name: PitchName::F,
sign: PitchSign::DoubleSharp,
};
pub const G_DOUBLE_SHARP: Pitch = Self {
name: PitchName::G,
sign: PitchSign::DoubleSharp,
};
pub const A_DOUBLE_SHARP: Pitch = Self {
name: PitchName::A,
sign: PitchSign::DoubleSharp,
};
pub const B_DOUBLE_SHARP: Pitch = Self {
name: PitchName::B,
sign: PitchSign::DoubleSharp,
};
pub const C_DOUBLE_FLAT: Pitch = Self {
name: PitchName::C,
sign: PitchSign::DoubleFlat,
};
pub const D_DOUBLE_FLAT: Pitch = Self {
name: PitchName::D,
sign: PitchSign::DoubleFlat,
};
pub const E_DOUBLE_FLAT: Pitch = Self {
name: PitchName::E,
sign: PitchSign::DoubleFlat,
};
pub const F_DOUBLE_FLAT: Pitch = Self {
name: PitchName::F,
sign: PitchSign::DoubleFlat,
};
pub const G_DOUBLE_FLAT: Pitch = Self {
name: PitchName::G,
sign: PitchSign::DoubleFlat,
};
pub const A_DOUBLE_FLAT: Pitch = Self {
name: PitchName::A,
sign: PitchSign::DoubleFlat,
};
pub const B_DOUBLE_FLAT: Pitch = Self {
name: PitchName::B,
sign: PitchSign::DoubleFlat,
};
}
impl Pitch {
pub fn new(name: PitchName, sign: PitchSign) -> Self {
Self { name, sign }
}
}
impl From<PitchName> for Semitones {
fn from(v: PitchName) -> Self {
let v = match v {
PitchName::C => 0,
PitchName::D => 2,
PitchName::E => 4,
PitchName::F => 5,
PitchName::G => 7,
PitchName::A => 9,
PitchName::B => 11,
};
Self::from(v)
}
}
impl From<PitchSign> for Semitones {
fn from(v: PitchSign) -> Self {
let v = match v {
PitchSign::Natural => 0,
PitchSign::Sharp => 1,
PitchSign::Flat => -1,
PitchSign::DoubleSharp => 2,
PitchSign::DoubleFlat => -2,
};
Self::from(v)
}
}
impl From<Pitch> for Semitones {
fn from(v: Pitch) -> Self {
let name_val = Semitones::from(v.name).0;
let sign_val = Semitones::from(v.sign).0;
Self::from(name_val + sign_val)
}
}
impl From<Semitones> for PitchSign {
fn from(v: Semitones) -> Self {
match v.0 {
0 => Self::Natural,
1 => Self::Sharp,
-1 => Self::Flat,
2 => Self::DoubleSharp,
-2 => Self::DoubleFlat,
_ => Self::Natural,
}
}
}
impl From<Semitones> for Pitch {
fn from(v: Semitones) -> Self {
let pos_val = if v.0 >= 0 { v.0 % 12 } else { v.0 % 12 + 12 };
match pos_val {
0 => Pitch::C,
1 => Pitch::C_SHARP,
2 => Pitch::D,
3 => Pitch::D_SHARP,
4 => Pitch::E,
5 => Pitch::F,
6 => Pitch::F_SHARP,
7 => Pitch::G,
8 => Pitch::G_SHARP,
9 => Pitch::A,
10 => Pitch::A_SHARP,
11 => Pitch::B,
_ => Pitch::C,
}
}
}
impl From<Key> for Pitch {
fn from(v: Key) -> Self {
match v {
Key::Natural(name) => Self::new(name, PitchSign::Natural),
Key::Sharp(name) => Self::new(name, PitchSign::Sharp),
Key::Flat(name) => Self::new(name, PitchSign::Flat),
}
}
}
impl Pitch {
pub fn to_text(&self) -> String {
format!("{}", self)
}
pub fn from_text(text: &str) -> Self {
match text {
"C" => Pitch::C,
"D" => Pitch::D,
"E" => Pitch::E,
"F" => Pitch::F,
"G" => Pitch::G,
"A" => Pitch::A,
"B" => Pitch::B,
"C#" => Pitch::C_SHARP,
"D#" => Pitch::D_SHARP,
"E#" => Pitch::E_SHARP,
"F#" => Pitch::F_SHARP,
"G#" => Pitch::G_SHARP,
"A#" => Pitch::A_SHARP,
"B#" => Pitch::B_SHARP,
"Cb" => Pitch::C_FLAT,
"Db" => Pitch::D_FLAT,
"Eb" => Pitch::E_FLAT,
"Fb" => Pitch::F_FLAT,
"Gb" => Pitch::G_FLAT,
"Ab" => Pitch::A_FLAT,
"Bb" => Pitch::B_FLAT,
"C##" => Pitch::C_DOUBLE_SHARP,
"D##" => Pitch::D_DOUBLE_SHARP,
"E##" => Pitch::E_DOUBLE_SHARP,
"F##" => Pitch::F_DOUBLE_SHARP,
"G##" => Pitch::G_DOUBLE_SHARP,
"A##" => Pitch::A_DOUBLE_SHARP,
"B##" => Pitch::B_DOUBLE_SHARP,
"Cbb" => Pitch::C_DOUBLE_FLAT,
"Dbb" => Pitch::D_DOUBLE_FLAT,
"Ebb" => Pitch::E_DOUBLE_FLAT,
"Fbb" => Pitch::F_DOUBLE_FLAT,
"Gbb" => Pitch::G_DOUBLE_FLAT,
"Abb" => Pitch::A_DOUBLE_FLAT,
"Bbb" => Pitch::B_DOUBLE_FLAT,
_ => Pitch::C,
}
}
}