1
0
Fork 0
mirror of https://github.com/alemidev/scope-tui.git synced 2024-11-23 14:14:48 +01:00
scope-tui/src/music.rs
alemi 771987063d
feat: add cpal source, refactor sources
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
2024-03-18 03:39:49 +01:00

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
}
}
}
}