const WELL_C_MINUS_1: f32 = 8.20354352009375;
const STANDARD_C: f32 = 8.18;
pub fn just_intonation(midi_pitch: f32) -> f32 {
let midi_pitch = midi_pitch as u8;
let octave = (midi_pitch / 12) as f32;
2.0_f32.powf(octave)
* STANDARD_C
* match midi_pitch % 12 {
0 => 1.0,
1 => 1.06666667, 2 => 1.125, 3 => 1.2, 4 => 1.28, 5 => 1.3333333333333333, 6 => 1.4222222222222223, 7 => 1.5, 8 => 1.6, 9 => 1.6666666666666667, 10 => 1.7777777777777777, 11 => 1.875, _ => panic!("Unreachable"),
}
}
pub fn well_temperament(midi_pitch: f32) -> f32 {
let midi_pitch = midi_pitch as u8;
let octave = (midi_pitch / 12) as f32;
2.0_f32.powf(octave)
* WELL_C_MINUS_1
* match midi_pitch % 12 {
0 => 1.0,
1 => 1.058267369,
2 => 1.119929822,
3 => 1.187864957,
4 => 1.254242807,
5 => 1.3363480780010195,
6 => 1.411023157998401,
7 => 1.4966160640051305,
8 => 1.5856094859970158,
9 => 1.6761049619985275,
10 => 1.7797864719968166,
11 => 1.8813642110048348,
_ => panic!("Unreachable"),
}
}
#[cfg(test)]
mod tests {
use crate::tunings::{STANDARD_C, just_intonation, well_temperament};
use float_eq::assert_float_eq;
#[test]
fn test_well() {
for (midi, hz) in [
(53.0, 175.404633854),
(54.0, 185.206238152),
(55.0, 196.440880223),
(56.0, 208.121862788),
(57.0, 220.000000000),
(58.0, 233.608892472),
(59.0, 246.941650914),
(60.0, 262.513392643),
(61.0, 277.809357360),
(62.0, 293.996156549),
(63.0, 311.830459864),
(64.0, 329.255534464),
] {
assert_float_eq!(well_temperament(midi), hz, abs <= 1e-3);
}
}
#[test]
fn test_just_intonation_multipliers_relative_to_c4() {
let expected_ratios = [
1.0, 16.0 / 15.0, 9.0 / 8.0, 6.0 / 5.0, 5.0 / 4.0, 4.0 / 3.0, 64.0 / 45.0, 3.0 / 2.0, 8.0 / 5.0, 5.0 / 3.0, 16.0 / 9.0, 15.0 / 8.0, ];
let c4_freq = just_intonation(60.0);
assert_float_eq!(c4_freq, 2.0_f32.powf(5.0) * STANDARD_C, abs <= 1e-3);
for (pitch_class, expected_ratio) in expected_ratios.iter().enumerate() {
let midi = 60.0 + pitch_class as f32;
let freq = just_intonation(midi);
let actual_multiplier = freq / c4_freq;
assert_float_eq!(
actual_multiplier,
*expected_ratio,
abs <= 0.035,
"Multiplier for note {} (MIDI {}) does not match expected",
pitch_class,
midi
);
}
}
}