spectrusty_audio/
music.rs1use core::convert::TryInto;
10pub fn equal_tempered_scale_note_freqs(hz: f32, n0: i16, steps: i16)
16 -> impl IntoIterator<Item=f32> + Clone + ExactSizeIterator
17{
18 (0..steps).map(move |n| {
19 hz * (2.0f32).powf( (n + n0) as f32 / steps as f32 )
20 })
21}
22
23pub fn render_equal_tempered_scale_note_freqs(hz: f32, n0: i16, target: &mut [f32]) {
29 let steps = target.len().try_into().expect("target is too large");
30 for (t, hz) in target.iter_mut()
31 .zip(equal_tempered_scale_note_freqs(hz, n0, steps)) {
32 *t = hz
33 }
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 fn nearly_equal(a: f32, b: f32, epsilon: f32) -> bool {
41 let abs_a = a.abs();
42 let abs_b = b.abs();
43 let diff = (a - b).abs();
44 if a == b {
45 true
46 }
47 else if a == 0.0 || b == 0.0 || (abs_a + abs_b < f32::MIN_POSITIVE) {
48 diff < epsilon * f32::MIN_POSITIVE
49 }
50 else {
51 diff / (abs_a + abs_b).min(f32::MAX) < epsilon
52 }
53 }
54
55 #[test]
56 fn music_works() {
57 let mut freqs = vec![0.0f32;12];
58 render_equal_tempered_scale_note_freqs(440.0, 0, &mut freqs);
59 let freqs0 = vec![440.0, 466.1638, 493.8833, 523.2511, 554.3653, 587.3295,
60 622.25397, 659.2551, 698.4565, 739.98883, 783.99084, 830.6094];
61 for (freq1, freq0) in freqs.into_iter().zip(freqs0.into_iter()) {
62 assert!(nearly_equal(freq1, freq0, f32::EPSILON));
63 }
64 }
65}