use crate::{cent::Cent, frequency::Frequency, offsets::OctaveOffsets, Result};
#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]
#[repr(u8)]
pub enum Pitch {
C0,
Cs0,
D0,
Eb0,
E0,
F0,
Fs0,
G0,
Ab0,
A0,
Bb0,
B0,
C1,
Cs1,
D1,
Eb1,
E1,
F1,
Fs1,
G1,
Ab1,
A1,
Bb1,
B1,
C2,
Cs2,
D2,
Eb2,
E2,
F2,
Fs2,
G2,
Ab2,
A2,
Bb2,
B2,
C3,
Cs3,
D3,
Eb3,
E3,
F3,
Fs3,
G3,
Ab3,
A3,
Bb3,
B3,
C4,
Cs4,
D4,
Eb4,
E4,
F4,
Fs4,
G4,
Ab4,
A4,
Bb4,
B4,
C5,
Cs5,
D5,
Eb5,
E5,
F5,
Fs5,
G5,
Ab5,
A5,
Bb5,
B5,
C6,
Cs6,
D6,
Eb6,
E6,
F6,
Fs6,
G6,
Ab6,
A6,
Bb6,
B6,
C7,
Cs7,
D7,
Eb7,
E7,
F7,
Fs7,
G7,
Ab7,
A7,
Bb7,
B7,
C8,
Cs8,
D8,
Eb8,
E8,
F8,
Fs8,
G8,
Ab8,
A8,
Bb8,
B8,
C9,
}
impl Pitch {
pub fn frequency_based_on(
&self,
reference_pitch: Pitch,
reference_ferquency: Frequency,
offsets: &OctaveOffsets,
) -> Result<Frequency> {
let num_of_half_steps: i32 = (*self) as i32 - reference_pitch as i32;
let equal_temperament_frequency =
reference_ferquency.adding(Cent(100.0 * num_of_half_steps as f64))?;
let offset = offsets.offset_for(*self) - offsets.offset_for(reference_pitch).0;
equal_temperament_frequency.adding(offset)
}
pub fn name(&self) -> &str {
match self {
Pitch::C0 => "C0",
Pitch::Cs0 => "C♯0",
Pitch::D0 => "D0",
Pitch::Eb0 => "E♭0",
Pitch::E0 => "E0",
Pitch::F0 => "F0",
Pitch::Fs0 => "F♯0",
Pitch::G0 => "G0",
Pitch::Ab0 => "A♭0",
Pitch::A0 => "A0",
Pitch::Bb0 => "B♭0",
Pitch::B0 => "B0",
Pitch::C1 => "C1",
Pitch::Cs1 => "C♯1",
Pitch::D1 => "D1",
Pitch::Eb1 => "E♭1",
Pitch::E1 => "E1",
Pitch::F1 => "F1",
Pitch::Fs1 => "F♯1",
Pitch::G1 => "G1",
Pitch::Ab1 => "A♭1",
Pitch::A1 => "A1",
Pitch::Bb1 => "B♭1",
Pitch::B1 => "B1",
Pitch::C2 => "C2",
Pitch::Cs2 => "C♯2",
Pitch::D2 => "D2",
Pitch::Eb2 => "E♭2",
Pitch::E2 => "E2",
Pitch::F2 => "F2",
Pitch::Fs2 => "F♯2",
Pitch::G2 => "G2",
Pitch::Ab2 => "A♭2",
Pitch::A2 => "A2",
Pitch::Bb2 => "B♭2",
Pitch::B2 => "B2",
Pitch::C3 => "C3",
Pitch::Cs3 => "C♯3",
Pitch::D3 => "D3",
Pitch::Eb3 => "E♭3",
Pitch::E3 => "E3",
Pitch::F3 => "F3",
Pitch::Fs3 => "F♯3",
Pitch::G3 => "G3",
Pitch::Ab3 => "A♭3",
Pitch::A3 => "A3",
Pitch::Bb3 => "B♭3",
Pitch::B3 => "B3",
Pitch::C4 => "C4",
Pitch::Cs4 => "C♯4",
Pitch::D4 => "D4",
Pitch::Eb4 => "E♭4",
Pitch::E4 => "E4",
Pitch::F4 => "F4",
Pitch::Fs4 => "F♯4",
Pitch::G4 => "G4",
Pitch::Ab4 => "A♭4",
Pitch::A4 => "A4",
Pitch::Bb4 => "B♭4",
Pitch::B4 => "B4",
Pitch::C5 => "C5",
Pitch::Cs5 => "C♯5",
Pitch::D5 => "D5",
Pitch::Eb5 => "E♭5",
Pitch::E5 => "E5",
Pitch::F5 => "F5",
Pitch::Fs5 => "F♯5",
Pitch::G5 => "G5",
Pitch::Ab5 => "A♭5",
Pitch::A5 => "A5",
Pitch::Bb5 => "B♭5",
Pitch::B5 => "B5",
Pitch::C6 => "C6",
Pitch::Cs6 => "C♯6",
Pitch::D6 => "D6",
Pitch::Eb6 => "E♭6",
Pitch::E6 => "E6",
Pitch::F6 => "F6",
Pitch::Fs6 => "F♯6",
Pitch::G6 => "G6",
Pitch::Ab6 => "A♭6",
Pitch::A6 => "A6",
Pitch::Bb6 => "B♭6",
Pitch::B6 => "B6",
Pitch::C7 => "C7",
Pitch::Cs7 => "C♯7",
Pitch::D7 => "D7",
Pitch::Eb7 => "E♭7",
Pitch::E7 => "E7",
Pitch::F7 => "F7",
Pitch::Fs7 => "F♯7",
Pitch::G7 => "G7",
Pitch::Ab7 => "A♭7",
Pitch::A7 => "A7",
Pitch::Bb7 => "B♭7",
Pitch::B7 => "B7",
Pitch::C8 => "C8",
Pitch::Cs8 => "C♯8",
Pitch::D8 => "D8",
Pitch::Eb8 => "E♭8",
Pitch::E8 => "E8",
Pitch::F8 => "F8",
Pitch::Fs8 => "F♯8",
Pitch::G8 => "G8",
Pitch::Ab8 => "A♭8",
Pitch::A8 => "A8",
Pitch::Bb8 => "B♭8",
Pitch::B8 => "B8",
Pitch::C9 => "C9",
}
}
}
impl From<Pitch> for PitchClass {
fn from(val: Pitch) -> Self {
match val {
Pitch::A0
| Pitch::A1
| Pitch::A2
| Pitch::A3
| Pitch::A4
| Pitch::A5
| Pitch::A6
| Pitch::A7
| Pitch::A8 => PitchClass::A,
Pitch::Ab0
| Pitch::Ab1
| Pitch::Ab2
| Pitch::Ab3
| Pitch::Ab4
| Pitch::Ab5
| Pitch::Ab6
| Pitch::Ab7
| Pitch::Ab8 => PitchClass::Ab,
Pitch::B0
| Pitch::B1
| Pitch::B2
| Pitch::B3
| Pitch::B4
| Pitch::B5
| Pitch::B6
| Pitch::B7
| Pitch::B8 => PitchClass::B,
Pitch::Bb0
| Pitch::Bb1
| Pitch::Bb2
| Pitch::Bb3
| Pitch::Bb4
| Pitch::Bb5
| Pitch::Bb6
| Pitch::Bb7
| Pitch::Bb8 => PitchClass::Bb,
Pitch::C0
| Pitch::C1
| Pitch::C2
| Pitch::C3
| Pitch::C4
| Pitch::C5
| Pitch::C6
| Pitch::C7
| Pitch::C8
| Pitch::C9 => PitchClass::C,
Pitch::Cs0
| Pitch::Cs1
| Pitch::Cs2
| Pitch::Cs3
| Pitch::Cs4
| Pitch::Cs5
| Pitch::Cs6
| Pitch::Cs7
| Pitch::Cs8 => PitchClass::Cs,
Pitch::D0
| Pitch::D1
| Pitch::D2
| Pitch::D3
| Pitch::D4
| Pitch::D5
| Pitch::D6
| Pitch::D7
| Pitch::D8 => PitchClass::D,
Pitch::E0
| Pitch::E1
| Pitch::E2
| Pitch::E3
| Pitch::E4
| Pitch::E5
| Pitch::E6
| Pitch::E7
| Pitch::E8 => PitchClass::E,
Pitch::Eb0
| Pitch::Eb1
| Pitch::Eb2
| Pitch::Eb3
| Pitch::Eb4
| Pitch::Eb5
| Pitch::Eb6
| Pitch::Eb7
| Pitch::Eb8 => PitchClass::Eb,
Pitch::F0
| Pitch::F1
| Pitch::F2
| Pitch::F3
| Pitch::F4
| Pitch::F5
| Pitch::F6
| Pitch::F7
| Pitch::F8 => PitchClass::F,
Pitch::Fs0
| Pitch::Fs1
| Pitch::Fs2
| Pitch::Fs3
| Pitch::Fs4
| Pitch::Fs5
| Pitch::Fs6
| Pitch::Fs7
| Pitch::Fs8 => PitchClass::Fs,
Pitch::G0
| Pitch::G1
| Pitch::G2
| Pitch::G3
| Pitch::G4
| Pitch::G5
| Pitch::G6
| Pitch::G7
| Pitch::G8 => PitchClass::G,
}
}
}
impl From<Pitch> for i32 {
fn from(val: Pitch) -> Self {
val as u8 as i32
}
}
#[derive(Debug, serde::Serialize, serde::Deserialize)]
pub enum PitchClass {
C,
Cs,
D,
Eb,
E,
F,
Fs,
G,
Ab,
A,
Bb,
B,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn check_note_names() {
let name = Pitch::Fs4.name();
assert_eq!(name, "F♯4");
}
}