mirror of
https://github.com/alemidev/scope-tui.git
synced 2024-11-23 14:14:48 +01:00
alemi
771987063d
now splitting stream in channels and parsing stream format are separate but handled by the source, so that cpal source can skip format parsing. added some nicer types, and also range now is +-1 because way easier than 32k sorry this is a huge commit, ive been messing with it for a while and changed a lot across whole project, at this point i'm just committing it because it can only get worse ehe
102 lines
2 KiB
Rust
102 lines
2 KiB
Rust
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
|
|
}
|
|
|
|
#[derive(Debug, thiserror::Error, derive_more::Display)]
|
|
pub struct ToneError();
|
|
|
|
#[derive(Debug, PartialEq, Clone)]
|
|
pub struct Note {
|
|
tone: Tone,
|
|
octave: u32,
|
|
}
|
|
|
|
#[derive(Debug, thiserror::Error, derive_more::From, derive_more::Display)]
|
|
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 ),
|
|
_ => Err(ToneError())
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Note {
|
|
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;
|
|
buf.round() as u32
|
|
}
|
|
}
|
|
|
|
impl Tone {
|
|
pub fn freq(&self, octave: u32) -> f32 {
|
|
match octave {
|
|
0 => match self {
|
|
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,
|
|
},
|
|
_ => {
|
|
let mut freq = self.freq(0);
|
|
for _ in 0..octave {
|
|
freq *= 2.0;
|
|
}
|
|
freq
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|