2022-12-27 19:02:52 +01:00
|
|
|
use std::{str::FromStr, num::ParseIntError};
|
|
|
|
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
|
|
pub enum Tone {
|
|
|
|
C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B
|
|
|
|
}
|
|
|
|
|
2023-09-17 03:51:44 +02:00
|
|
|
#[derive(Debug, thiserror::Error, derive_more::Display)]
|
|
|
|
pub struct ToneError();
|
2022-12-27 19:02:52 +01:00
|
|
|
|
2022-12-26 02:18:52 +01:00
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
2022-12-27 19:02:52 +01:00
|
|
|
pub struct Note {
|
|
|
|
tone: Tone,
|
|
|
|
octave: u32,
|
|
|
|
}
|
|
|
|
|
2023-09-17 03:51:44 +02:00
|
|
|
#[derive(Debug, thiserror::Error, derive_more::From, derive_more::Display)]
|
2022-12-27 19:02:52 +01:00
|
|
|
pub enum NoteError {
|
|
|
|
InvalidOctave(ParseIntError),
|
|
|
|
InalidNote(ToneError),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Note {
|
|
|
|
type Err = NoteError;
|
|
|
|
|
|
|
|
fn from_str(txt: &str) -> Result<Self, Self::Err> {
|
|
|
|
let trimmed = txt.trim();
|
|
|
|
let mut split = 0;
|
|
|
|
for c in trimmed.chars() {
|
|
|
|
if !c.is_ascii_digit() {
|
|
|
|
split += 1;
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(
|
|
|
|
Note {
|
|
|
|
tone: trimmed[..split].parse::<Tone>()?,
|
|
|
|
octave: trimmed[split..].parse::<u32>().unwrap_or(0),
|
|
|
|
}
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Tone {
|
|
|
|
type Err = ToneError;
|
|
|
|
|
|
|
|
fn from_str(txt: &str) -> Result<Self, Self::Err> {
|
|
|
|
match txt {
|
|
|
|
"C" => Ok(Tone::C ),
|
|
|
|
"C#" | "Db" => Ok(Tone::Db),
|
|
|
|
"D" => Ok(Tone::D ),
|
|
|
|
"D#" | "Eb" => Ok(Tone::Eb),
|
|
|
|
"E" => Ok(Tone::E ),
|
|
|
|
"F" => Ok(Tone::F ),
|
|
|
|
"F#" | "Gb" => Ok(Tone::Gb),
|
|
|
|
"G" => Ok(Tone::G ),
|
|
|
|
"G#" | "Ab" => Ok(Tone::Ab),
|
|
|
|
"A" => Ok(Tone::A ),
|
|
|
|
"A#" | "Bb" => Ok(Tone::Bb),
|
|
|
|
"B" => Ok(Tone::B ),
|
2023-09-17 03:51:44 +02:00
|
|
|
_ => Err(ToneError())
|
2022-12-26 02:18:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Note {
|
2022-12-27 19:02:52 +01:00
|
|
|
pub fn tune_buffer_size(&self, sample_rate: u32) -> u32 {
|
|
|
|
let t = 1.0 / self.tone.freq(self.octave); // periodo ?
|
|
|
|
let buf = (sample_rate as f32) * t;
|
2023-09-17 03:51:44 +02:00
|
|
|
(buf * 4.0).round() as u32
|
2022-12-27 19:02:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Tone {
|
2022-12-26 02:18:52 +01:00
|
|
|
pub fn freq(&self, octave: u32) -> f32 {
|
|
|
|
match octave {
|
|
|
|
0 => match self {
|
2022-12-27 19:02:52 +01:00
|
|
|
Tone::C => 16.35,
|
|
|
|
Tone::Db => 17.32,
|
|
|
|
Tone::D => 18.35,
|
|
|
|
Tone::Eb => 19.45,
|
|
|
|
Tone::E => 20.60,
|
|
|
|
Tone::F => 21.83,
|
|
|
|
Tone::Gb => 23.12,
|
|
|
|
Tone::G => 24.50,
|
|
|
|
Tone::Ab => 25.96,
|
|
|
|
Tone::A => 27.50,
|
|
|
|
Tone::Bb => 29.14,
|
|
|
|
Tone::B => 30.87,
|
2022-12-26 02:18:52 +01:00
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
let mut freq = self.freq(0);
|
|
|
|
for _ in 0..octave {
|
|
|
|
freq *= 2.0;
|
|
|
|
}
|
|
|
|
freq
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|