mod symbol;
#[cfg(test)]
mod tests;
pub use symbol::{Accidental, NoteLetter};
use crate::{Pitch, PitchyError};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Note {
letter: NoteLetter,
accidental: Accidental,
octave: i8,
}
impl Note {
pub fn new(letter: NoteLetter, accidental: Accidental, octave: i8) -> Self {
Self {
letter,
accidental,
octave,
}
}
pub fn octave(&self) -> i8 {
self.octave
}
pub fn letter(&self) -> NoteLetter {
self.letter
}
pub fn accidental(&self) -> Accidental {
self.accidental
}
#[cfg(feature = "std")]
pub fn name(&self) -> String {
format!("{}{}{}", self.letter, self.accidental, self.octave)
}
}
impl TryFrom<Pitch> for Note {
type Error = PitchyError;
fn try_from(pitch: Pitch) -> Result<Self, Self::Error> {
let midi = pitch.try_midi_number()? as i8;
let octave = midi / 12 - 1;
let semitone = midi % 12;
for accidental in [
Accidental::Natural,
Accidental::Sharp,
Accidental::Flat,
Accidental::DoubleSharp,
Accidental::DoubleFlat,
] {
for letter in NoteLetter::all() {
let base = letter as i8;
if base + accidental as i8 == semitone {
return Ok(Note::new(letter, accidental, octave));
}
}
}
Err(PitchyError::Unspelled)
}
}