use crate::{
core::Frequency,
music::{
named_pitch::NamedPitch,
octave::ALL_OCTAVES,
pitch::{ALL_PITCHES, HasPitch, Pitch},
},
};
use paste::paste;
use super::octave::Octave;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug)]
pub struct Note {
named_pitch: NamedPitch,
octave: Octave,
}
impl Note {
pub const fn octave(&self) -> Octave {
self.octave
}
pub fn pitch(&self) -> Pitch {
self.named_pitch.pitch()
}
pub fn frequency(&self) -> Frequency {
let mut octave = self.octave();
let base_frequency = self.pitch().base_frequency();
match self.named_pitch {
NamedPitch::ATripleSharp
| NamedPitch::BTripleSharp
| NamedPitch::BDoubleSharp
| NamedPitch::BSharp => {
octave += 1;
}
NamedPitch::DTripleFlat
| NamedPitch::CTripleFlat
| NamedPitch::CDoubleFlat
| NamedPitch::CFlat => {
octave -= 1;
}
_ => {}
}
base_frequency * 2.0_f32.powf(octave as u8 as f32)
}
}
#[rustfmt::skip]
macro_rules! define_note {
( $name:ident, $named_pitch:expr, $octave_num:ident, $octave:expr) => {
paste! {
pub const [<$name$octave_num>]: Note = Note {
named_pitch: $named_pitch,
octave: $octave,
};
}
};
}
macro_rules! define_octave {
($octave_num:ident, $octave:expr) => {
define_note!(FTripleFlat, NamedPitch::FTripleFlat, $octave_num, $octave);
define_note!(CTripleFlat, NamedPitch::CTripleFlat, $octave_num, $octave);
define_note!(GTripleFlat, NamedPitch::GTripleFlat, $octave_num, $octave);
define_note!(DTripleFlat, NamedPitch::DTripleFlat, $octave_num, $octave);
define_note!(ATripleFlat, NamedPitch::ATripleFlat, $octave_num, $octave);
define_note!(ETripleFlat, NamedPitch::ETripleFlat, $octave_num, $octave);
define_note!(BTripleFlat, NamedPitch::BTripleFlat, $octave_num, $octave);
define_note!(FDoubleFlat, NamedPitch::FDoubleFlat, $octave_num, $octave);
define_note!(CDoubleFlat, NamedPitch::CDoubleFlat, $octave_num, $octave);
define_note!(GDoubleFlat, NamedPitch::GDoubleFlat, $octave_num, $octave);
define_note!(DDoubleFlat, NamedPitch::DDoubleFlat, $octave_num, $octave);
define_note!(ADoubleFlat, NamedPitch::ADoubleFlat, $octave_num, $octave);
define_note!(EDoubleFlat, NamedPitch::EDoubleFlat, $octave_num, $octave);
define_note!(BDoubleFlat, NamedPitch::BDoubleFlat, $octave_num, $octave);
define_note!(FFlat, NamedPitch::FFlat, $octave_num, $octave);
define_note!(CFlat, NamedPitch::CFlat, $octave_num, $octave);
define_note!(GFlat, NamedPitch::GFlat, $octave_num, $octave);
define_note!(DFlat, NamedPitch::DFlat, $octave_num, $octave);
define_note!(AFlat, NamedPitch::AFlat, $octave_num, $octave);
define_note!(EFlat, NamedPitch::EFlat, $octave_num, $octave);
define_note!(BFlat, NamedPitch::BFlat, $octave_num, $octave);
define_note!(F, NamedPitch::F, $octave_num, $octave);
define_note!(C, NamedPitch::C, $octave_num, $octave);
define_note!(G, NamedPitch::G, $octave_num, $octave);
define_note!(D, NamedPitch::D, $octave_num, $octave);
define_note!(A, NamedPitch::A, $octave_num, $octave);
define_note!(E, NamedPitch::E, $octave_num, $octave);
define_note!(B, NamedPitch::B, $octave_num, $octave);
define_note!(FSharp, NamedPitch::FSharp, $octave_num, $octave);
define_note!(CSharp, NamedPitch::CSharp, $octave_num, $octave);
define_note!(GSharp, NamedPitch::GSharp, $octave_num, $octave);
define_note!(DSharp, NamedPitch::DSharp, $octave_num, $octave);
define_note!(ASharp, NamedPitch::ASharp, $octave_num, $octave);
define_note!(ESharp, NamedPitch::ESharp, $octave_num, $octave);
define_note!(BSharp, NamedPitch::BSharp, $octave_num, $octave);
define_note!(FDoubleSharp, NamedPitch::FDoubleSharp, $octave_num, $octave);
define_note!(CDoubleSharp, NamedPitch::CDoubleSharp, $octave_num, $octave);
define_note!(GDoubleSharp, NamedPitch::GDoubleSharp, $octave_num, $octave);
define_note!(DDoubleSharp, NamedPitch::DDoubleSharp, $octave_num, $octave);
define_note!(ADoubleSharp, NamedPitch::ADoubleSharp, $octave_num, $octave);
define_note!(EDoubleSharp, NamedPitch::EDoubleSharp, $octave_num, $octave);
define_note!(BDoubleSharp, NamedPitch::BDoubleSharp, $octave_num, $octave);
define_note!(FTripleSharp, NamedPitch::FTripleSharp, $octave_num, $octave);
define_note!(CTripleSharp, NamedPitch::CTripleSharp, $octave_num, $octave);
define_note!(GTripleSharp, NamedPitch::GTripleSharp, $octave_num, $octave);
define_note!(DTripleSharp, NamedPitch::DTripleSharp, $octave_num, $octave);
define_note!(ATripleSharp, NamedPitch::ATripleSharp, $octave_num, $octave);
define_note!(ETripleSharp, NamedPitch::ETripleSharp, $octave_num, $octave);
define_note!(BTripleSharp, NamedPitch::BTripleSharp, $octave_num, $octave);
};
}
define_octave!(Zero, Octave::Zero);
define_octave!(One, Octave::One);
define_octave!(Two, Octave::Two);
define_octave!(Three, Octave::Three);
define_octave!(Four, Octave::Four);
define_octave!(Five, Octave::Five);
define_octave!(Six, Octave::Six);
define_octave!(Seven, Octave::Seven);
define_octave!(Eight, Octave::Eight);
define_octave!(Nine, Octave::Nine);
define_octave!(Ten, Octave::Ten);
pub const FTripleFlat: Note = FTripleFlatFour;
pub const CTripleFlat: Note = CTripleFlatFour;
pub const GTripleFlat: Note = GTripleFlatFour;
pub const DTripleFlat: Note = DTripleFlatFour;
pub const ATripleFlat: Note = ATripleFlatFour;
pub const ETripleFlat: Note = ETripleFlatFour;
pub const BTripleFlat: Note = BTripleFlatFour;
pub const FDoubleFlat: Note = FDoubleFlatFour;
pub const CDoubleFlat: Note = CDoubleFlatFour;
pub const GDoubleFlat: Note = GDoubleFlatFour;
pub const DDoubleFlat: Note = DDoubleFlatFour;
pub const ADoubleFlat: Note = ADoubleFlatFour;
pub const EDoubleFlat: Note = EDoubleFlatFour;
pub const BDoubleFlat: Note = BDoubleFlatFour;
pub const FFlat: Note = FFlatFour;
pub const CFlat: Note = CFlatFour;
pub const GFlat: Note = GFlatFour;
pub const DFlat: Note = DFlatFour;
pub const AFlat: Note = AFlatFour;
pub const EFlat: Note = EFlatFour;
pub const BFlat: Note = BFlatFour;
pub const F: Note = FFour;
pub const C: Note = CFour;
pub const G: Note = GFour;
pub const D: Note = DFour;
pub const A: Note = AFour;
pub const E: Note = EFour;
pub const B: Note = BFour;
pub const FSharp: Note = FSharpFour;
pub const CSharp: Note = CSharpFour;
pub const GSharp: Note = GSharpFour;
pub const DSharp: Note = DSharpFour;
pub const ASharp: Note = ASharpFour;
pub const ESharp: Note = ESharpFour;
pub const BSharp: Note = BSharpFour;
pub const FDoubleSharp: Note = FDoubleSharpFour;
pub const CDoubleSharp: Note = CDoubleSharpFour;
pub const GDoubleSharp: Note = GDoubleSharpFour;
pub const DDoubleSharp: Note = DDoubleSharpFour;
pub const ADoubleSharp: Note = ADoubleSharpFour;
pub const EDoubleSharp: Note = EDoubleSharpFour;
pub const BDoubleSharp: Note = BDoubleSharpFour;
pub const FTripleSharp: Note = FTripleSharpFour;
pub const CTripleSharp: Note = CTripleSharpFour;
pub const GTripleSharp: Note = GTripleSharpFour;
pub const DTripleSharp: Note = DTripleSharpFour;
pub const ATripleSharp: Note = ATripleSharpFour;
pub const ETripleSharp: Note = ETripleSharpFour;
pub const BTripleSharp: Note = BTripleSharpFour;
#[cfg(feature = "std")]
use std::sync::LazyLock;
#[cfg(feature = "std")]
pub static ALL_PITCH_NOTES: LazyLock<[Note; 192]> = LazyLock::new(|| {
let mut all_notes = Vec::with_capacity(132);
for octave in ALL_OCTAVES.iter() {
for pitch in ALL_PITCHES.iter() {
all_notes.push(Note {
octave: *octave,
named_pitch: pitch.into(),
});
}
}
all_notes.try_into().unwrap()
});