scope/
music.rs

1use std::{str::FromStr, num::ParseIntError};
2
3#[derive(Debug, PartialEq, Clone)]
4pub enum Tone {
5	C, Db, D, Eb, E, F, Gb, G, Ab, A, Bb, B
6}
7
8#[derive(Debug, thiserror::Error, derive_more::Display)]
9pub struct ToneError();
10
11#[derive(Debug, PartialEq, Clone)]
12pub struct Note {
13	tone: Tone,
14	octave: u32,
15}
16
17#[derive(Debug, thiserror::Error, derive_more::From, derive_more::Display)]
18pub enum NoteError {
19	InvalidOctave(ParseIntError),
20	InalidNote(ToneError),
21}
22
23impl FromStr for Note {
24	type Err = NoteError;
25
26	fn from_str(txt: &str) -> Result<Self, Self::Err> {
27		let trimmed = txt.trim();
28		let mut split = 0;
29		for c in trimmed.chars() {
30			if !c.is_ascii_digit() {
31				split += 1;
32			} else {
33				break;
34			}
35		}
36		Ok(
37			Note {
38				tone: trimmed[..split].parse::<Tone>()?,
39				octave: trimmed[split..].parse::<u32>().unwrap_or(0),
40			}
41		)
42	}
43}
44
45impl FromStr for Tone {
46	type Err = ToneError;
47
48	fn from_str(txt: &str) -> Result<Self, Self::Err> {
49		match txt {
50			"C"         => Ok(Tone::C ),
51			"C#" | "Db" => Ok(Tone::Db),
52			"D"         => Ok(Tone::D ),
53			"D#" | "Eb" => Ok(Tone::Eb),
54			"E"         => Ok(Tone::E ),
55			"F"         => Ok(Tone::F ),
56			"F#" | "Gb" => Ok(Tone::Gb),
57			"G"         => Ok(Tone::G ),
58			"G#" | "Ab" => Ok(Tone::Ab),
59			"A"         => Ok(Tone::A ),
60			"A#" | "Bb" => Ok(Tone::Bb),
61			"B"         => Ok(Tone::B ),
62			_           => Err(ToneError())
63		}
64	}
65}
66
67impl Note {
68	pub fn tune_buffer_size(&self, sample_rate: u32) -> u32 {
69		let t = 1.0 / self.tone.freq(self.octave); // periodo ?
70		let buf = (sample_rate as f32) * t;
71		buf.round() as u32
72	}
73}
74
75impl Tone {
76	pub fn freq(&self, octave: u32) -> f32 {
77		match octave {
78			0 => match self {
79				Tone::C  => 16.35,
80				Tone::Db => 17.32,
81				Tone::D  => 18.35,
82				Tone::Eb => 19.45,
83				Tone::E  => 20.60,
84				Tone::F  => 21.83,
85				Tone::Gb => 23.12,
86				Tone::G  => 24.50,
87				Tone::Ab => 25.96,
88				Tone::A  => 27.50,
89				Tone::Bb => 29.14,
90				Tone::B  => 30.87,
91			},
92			_ => {
93				let mut freq = self.freq(0);
94				for _ in 0..octave {
95					freq *= 2.0;
96				}
97				freq
98			}
99		}
100	}
101}
102