firefly_rust/audio/
freq.rs

1pub const SAMPLE_RATE: u32 = 44_100;
2
3#[derive(Copy, Clone)]
4pub enum Pitch {
5    C,
6    Cs,
7    D,
8    Ds,
9    E,
10    F,
11    Fs,
12    G,
13    Gs,
14    A,
15    As,
16    B,
17}
18
19impl TryFrom<char> for Pitch {
20    type Error = ();
21
22    fn try_from(value: char) -> Result<Self, Self::Error> {
23        match value {
24            'A' => Ok(Self::A),
25            'B' => Ok(Self::B),
26            'C' => Ok(Self::C),
27            'D' => Ok(Self::D),
28            'E' => Ok(Self::E),
29            'F' => Ok(Self::F),
30            'G' => Ok(Self::G),
31            _ => Err(()),
32        }
33    }
34}
35
36#[derive(Copy, Clone)]
37pub struct Freq(pub(super) f32);
38
39impl Freq {
40    pub const ZERO: Self = Self(0.);
41
42    // https://www.liutaiomottola.com/formulae/freqtab.htm
43
44    /// C0, MIDI note #12
45    pub const C0: Self = Self(16.351);
46    pub const CS0: Self = Self(17.324);
47    pub const D0: Self = Self(18.354);
48    pub const DS0: Self = Self(19.445);
49    pub const E0: Self = Self(20.601);
50    pub const F0: Self = Self(21.827);
51    pub const FS0: Self = Self(23.124);
52    pub const G0: Self = Self(24.499);
53    pub const GS0: Self = Self(25.956);
54    /// A0, the lowest note of a piano
55    pub const A0: Self = Self(27.5);
56    pub const AS0: Self = Self(29.135);
57    /// B0, the lowest note of a 5 string bass
58    pub const B0: Self = Self(30.868);
59    /// C1, the lowest note of double bass with C extension
60    pub const C1: Self = Self(32.703);
61    pub const CS1: Self = Self(34.648);
62    pub const D1: Self = Self(36.708);
63    pub const DS1: Self = Self(38.891);
64    /// E1, the lowest note of a bass
65    pub const E1: Self = Self(41.203);
66    pub const F1: Self = Self(43.654);
67    pub const FS1: Self = Self(46.249);
68    pub const G1: Self = Self(48.999);
69    pub const GS1: Self = Self(51.913);
70    pub const A1: Self = Self(55.);
71    pub const AS1: Self = Self(58.27);
72    pub const B1: Self = Self(61.735);
73    pub const C2: Self = Self(65.406);
74    pub const CS2: Self = Self(69.296);
75    pub const D2: Self = Self(73.416);
76    pub const DS2: Self = Self(77.782);
77    /// E2, the lowest note of a guitar.
78    pub const E2: Self = Self(82.407);
79    pub const F2: Self = Self(87.307);
80    pub const FS2: Self = Self(92.499);
81    pub const G2: Self = Self(97.999);
82    pub const GS2: Self = Self(103.826);
83    pub const A2: Self = Self(110.);
84    pub const AS2: Self = Self(116.541);
85    pub const B2: Self = Self(123.471);
86    pub const C3: Self = Self(130.813);
87    pub const CS3: Self = Self(138.591);
88    pub const D3: Self = Self(146.832);
89    pub const DS3: Self = Self(155.563);
90    pub const E3: Self = Self(164.814);
91    pub const F3: Self = Self(174.614);
92    pub const FS3: Self = Self(184.997);
93    /// G3, the lowest note of a violin.
94    pub const G3: Self = Self(195.998);
95    pub const GS3: Self = Self(207.652);
96    pub const A3: Self = Self(220.);
97    pub const AS3: Self = Self(233.082);
98    pub const B3: Self = Self(246.942);
99    /// C4, the "middle C".
100    pub const C4: Self = Self(261.626);
101    pub const CS4: Self = Self(277.183);
102    pub const D4: Self = Self(293.665);
103    pub const DS4: Self = Self(311.127);
104    pub const E4: Self = Self(329.628);
105    pub const F4: Self = Self(349.228);
106    pub const FS4: Self = Self(369.994);
107    pub const G4: Self = Self(391.995);
108    pub const GS4: Self = Self(415.305);
109    /// A4, the tuning reference note.
110    pub const A4: Self = Self(440.);
111    pub const AS4: Self = Self(466.164);
112    pub const B4: Self = Self(493.883);
113    pub const C5: Self = Self(523.251);
114    pub const CS5: Self = Self(554.365);
115    pub const D5: Self = Self(587.33);
116    pub const DS5: Self = Self(622.254);
117    pub const E5: Self = Self(659.255);
118    pub const F5: Self = Self(698.456);
119    pub const FS5: Self = Self(739.989);
120    pub const G5: Self = Self(783.991);
121    pub const GS5: Self = Self(830.609);
122    pub const A5: Self = Self(880.);
123    pub const AS5: Self = Self(932.328);
124    pub const B5: Self = Self(987.767);
125    pub const C6: Self = Self(1046.502);
126    pub const CS6: Self = Self(1108.731);
127    pub const D6: Self = Self(1174.659);
128    pub const DS6: Self = Self(1244.508);
129    pub const E6: Self = Self(1318.51);
130    pub const F6: Self = Self(1396.913);
131    pub const FS6: Self = Self(1479.978);
132    pub const G6: Self = Self(1567.982);
133    pub const GS6: Self = Self(1661.219);
134    pub const A6: Self = Self(1760.);
135    pub const AS6: Self = Self(1864.655);
136    pub const B6: Self = Self(1975.533);
137    pub const C7: Self = Self(2093.005);
138    pub const CS7: Self = Self(2217.461);
139    pub const D7: Self = Self(2349.318);
140    pub const DS7: Self = Self(2489.016);
141    pub const E7: Self = Self(2637.021);
142    pub const F7: Self = Self(2793.826);
143    pub const FS7: Self = Self(2959.955);
144    pub const G7: Self = Self(3135.964);
145    pub const GS7: Self = Self(3322.438);
146    pub const A7: Self = Self(3520.);
147    pub const AS7: Self = Self(3729.31);
148    pub const B7: Self = Self(3951.066);
149    /// C8, the highest note of a piano.
150    pub const C8: Self = Self(4186.009);
151    pub const CS8: Self = Self(4434.922);
152    pub const D8: Self = Self(4698.636);
153    pub const DS8: Self = Self(4978.032);
154    pub const E8: Self = Self(5274.042);
155    pub const F8: Self = Self(5587.652);
156    pub const FS8: Self = Self(5919.91);
157    pub const G8: Self = Self(6271.928);
158    pub const GS8: Self = Self(6644.876);
159    pub const A8: Self = Self(7040.);
160    pub const AS8: Self = Self(7458.62);
161    pub const B8: Self = Self(7902.132);
162    pub const C9: Self = Self(8372.018);
163    pub const CS9: Self = Self(8869.844);
164    pub const D9: Self = Self(9397.272);
165    pub const DS9: Self = Self(9956.064);
166    pub const E9: Self = Self(10548.084);
167    pub const F9: Self = Self(11175.304);
168    pub const FS9: Self = Self(11839.82);
169    pub const G9: Self = Self(12543.856);
170    /// G#9, MIDI note #128, the top of the MIDI tuning range.
171    pub const GS9: Self = Self(13289.752);
172    pub const A9: Self = Self(14080.);
173    pub const AS9: Self = Self(14917.24);
174    /// B9. For most of adults, it is already beyond the hearing range.
175    pub const B9: Self = Self(15804.264);
176
177    #[must_use]
178    pub fn hz(hz: f32) -> Self {
179        Self(hz)
180    }
181
182    #[must_use]
183    #[expect(clippy::cast_precision_loss)]
184    pub fn midi(note: u8) -> Self {
185        // https://inspiredacoustics.com/en/MIDI_note_numbers_and_center_frequencies
186        // https://en.wikipedia.org/wiki/Musical_note#MIDI
187        let mut f: f32 = match note % 12 {
188            0 => 8.1758,
189            1 => 8.66,
190            2 => 9.18,
191            3 => 9.72,
192            4 => 10.30,
193            5 => 10.91,
194            6 => 11.56,
195            7 => 12.25,
196            8 => 12.98,
197            9 => 13.75,
198            10 => 14.57,
199            _ => 15.43,
200        };
201        let oct = note / 12;
202        f *= (1 << oct) as f32;
203        Self(f)
204    }
205
206    #[must_use]
207    #[expect(clippy::cast_precision_loss)]
208    pub fn note(pitch: Pitch, octave: u8) -> Self {
209        // https://github.com/crbulakites/hum/blob/master/src/hum_process/hum_math.rs
210        // https://en.wikipedia.org/wiki/Musical_note#Pitch_frequency_in_hertz
211        let mut f: f32 = match pitch {
212            Pitch::C => 16.351,
213            Pitch::Cs => 17.324,
214            Pitch::D => 18.354,
215            Pitch::Ds => 19.445,
216            Pitch::E => 20.601,
217            Pitch::F => 21.827,
218            Pitch::Fs => 23.124,
219            Pitch::G => 24.499,
220            Pitch::Gs => 25.956,
221            Pitch::A => 27.5,
222            Pitch::As => 29.135,
223            Pitch::B => 30.868,
224        };
225        f *= (1 << octave) as f32;
226        Freq(f)
227    }
228}
229
230impl From<f32> for Freq {
231    fn from(value: f32) -> Self {
232        Self(value)
233    }
234}