Skip to main content

scope/
music.rs

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