rust_synth/math/
harmony.rs1pub const PHI: f32 = 1.618_034;
4
5pub fn golden_freq(base: f32, step: i32) -> f32 {
6 let raw = base * PHI.powi(step);
7 fold_octave(raw, base)
8}
9
10pub fn fold_octave(mut f: f32, base: f32) -> f32 {
11 let lo = base * 0.5;
12 let hi = base * 2.0;
13 while f < lo {
14 f *= 2.0;
15 }
16 while f > hi {
17 f *= 0.5;
18 }
19 f
20}
21
22pub fn golden_pentatonic(base: f32) -> [f32; 5] {
23 [
24 base,
25 fold_octave(base / PHI, base),
26 fold_octave(base * PHI, base),
27 fold_octave(base / (PHI * PHI), base),
28 fold_octave(base * PHI * PHI, base),
29 ]
30}
31
32pub fn rand_f32(seed: &mut u64) -> f32 {
33 *seed ^= *seed << 13;
34 *seed ^= *seed >> 7;
35 *seed ^= *seed << 17;
36 let h = seed.wrapping_mul(0x2545_F491_4F6C_DD1D);
37 ((h >> 40) as i32 as f32) / ((1i32 << 23) as f32)
38}
39
40pub fn rand_u32(seed: &mut u64, n: u32) -> u32 {
41 *seed ^= *seed << 13;
42 *seed ^= *seed >> 7;
43 *seed ^= *seed << 17;
44 let h = seed.wrapping_mul(0x2545_F491_4F6C_DD1D);
45 (h >> 32) as u32 % n.max(1)
46}
47
48#[cfg(test)]
49mod tests {
50 use super::*;
51 use approx::assert_relative_eq;
52
53 #[test]
54 fn fold_keeps_octave() {
55 let f = fold_octave(55.0 * 16.0, 55.0);
56 assert!((27.5..=110.0).contains(&f));
57 }
58
59 #[test]
60 fn golden_step_zero_is_base() {
61 assert_relative_eq!(golden_freq(55.0, 0), 55.0, epsilon = 1e-4);
62 }
63
64 #[test]
65 fn rand_is_deterministic() {
66 let mut a = 42;
67 let mut b = 42;
68 assert_eq!(rand_f32(&mut a), rand_f32(&mut b));
69 }
70}