bitsy-parser/src/note.rs

110 lines
2.7 KiB
Rust

use core::fmt;
use std::fmt::Formatter;
use crate::Error;
#[derive(Clone, Debug, PartialEq)]
pub enum RelativeNote {
C,
CSharp,
D,
DSharp,
E,
F,
FSharp,
G,
GSharp,
A,
ASharp,
B,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Note {
relative: RelativeNote,
octave: u8, // upper limit? 8?
}
impl Note {
fn from(str: &str) -> Result<Self, Error> {
let mut chars: Vec<char> = str.chars().collect();
// last char may or may not be present / may or may not be an octave number
let octave = chars.pop().unwrap_or('4').to_string().parse().unwrap_or(4);
let chars: String = chars.into_iter().collect();
let relative = match chars.as_ref() {
"C" => RelativeNote::C,
"C#" => RelativeNote::CSharp,
"D" => RelativeNote::D,
"D#" => RelativeNote::DSharp,
"E" => RelativeNote::E,
"F" => RelativeNote::F,
"F#" => RelativeNote::FSharp,
"G" => RelativeNote::G,
"G#" => RelativeNote::GSharp,
"A" => RelativeNote::A,
"A#" => RelativeNote::ASharp,
"B" => RelativeNote::B,
_ => { return Err(Error::RelativeNote); }
};
Ok(Note { relative, octave })
}
}
impl fmt::Display for Note {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(
f,
"{}{}",
match self.relative {
RelativeNote::C => "C",
RelativeNote::CSharp => "C#",
RelativeNote::D => "D",
RelativeNote::DSharp => "D#",
RelativeNote::E => "E",
RelativeNote::F => "F",
RelativeNote::FSharp => "F#",
RelativeNote::G => "G",
RelativeNote::GSharp => "G#",
RelativeNote::A => "A",
RelativeNote::ASharp => "A#",
RelativeNote::B => "B",
},
self.octave
)
}
}
#[cfg(test)]
mod test {
use crate::note::{Note, RelativeNote};
#[test]
fn c4() {
assert_eq!(Note { relative: RelativeNote::C, octave: 4 }.to_string(), "C4");
}
#[test]
fn a_sharp_0() {
assert_eq!(Note { relative: RelativeNote::ASharp, octave: 0 }.to_string(), "A#0");
}
#[test]
fn c_sharp_3_from_str() {
assert_eq!(
Note::from("C#3").unwrap(),
Note { relative: RelativeNote::CSharp, octave: 3 }
);
}
#[test]
fn b_0_from_str() {
assert_eq!(
Note::from("B0").unwrap(),
Note { relative: RelativeNote::B, octave: 0 }
);
}
}