rust_synth/math/
genetic.rs1use fundsp::hacker::Shared;
10
11use super::harmony::{golden_pentatonic, rand_f32, rand_u32};
12
13pub struct Genome<'a> {
16 pub freq: &'a Shared,
17 pub cutoff: &'a Shared,
18 pub resonance: &'a Shared,
19 pub reverb_mix: &'a Shared,
20 pub pulse_depth: &'a Shared,
21 pub pattern_hits: &'a Shared,
22 pub pattern_rotation: &'a Shared,
23 pub character: &'a Shared,
24}
25
26pub fn mutate(g: &Genome, seed: &mut u64, strength: f32) {
34 let s = strength.clamp(0.0, 1.0);
35
36 let cur = g.freq.value();
38 let scale = golden_pentatonic(cur);
39 let idx = rand_u32(seed, scale.len() as u32) as usize;
40 g.freq.set_value(scale[idx]);
41
42 let cut_factor = (1.0 + s * 0.8 * rand_f32(seed)).clamp(0.25, 4.0);
44 g.cutoff
45 .set_value((g.cutoff.value() * cut_factor).clamp(40.0, 12000.0));
46
47 let res = (g.resonance.value() + s * 0.15 * rand_f32(seed)).clamp(0.0, 0.55);
50 g.resonance.set_value(res);
51
52 let rev = (g.reverb_mix.value() + s * 0.25 * rand_f32(seed)).clamp(0.0, 1.0);
53 g.reverb_mix.set_value(rev);
54
55 let pulse = (g.pulse_depth.value() + s * 0.2 * rand_f32(seed)).clamp(0.0, 1.0);
56 g.pulse_depth.set_value(pulse);
57
58 let hits = (g.pattern_hits.value() + s * 3.0 * rand_f32(seed)).clamp(1.0, 11.0);
62 g.pattern_hits.set_value(hits);
63 let rot = (g.pattern_rotation.value() + s * 4.0 * rand_f32(seed)).rem_euclid(16.0);
64 g.pattern_rotation.set_value(rot);
65
66 let ch = (g.character.value() + s * 0.35 * rand_f32(seed)).clamp(0.0, 1.0);
69 g.character.set_value(ch);
70}
71
72pub fn crossover(a: &Genome, b: &Genome, seed: &mut u64) {
75 if rand_u32(seed, 2) == 0 {
76 a.freq.set_value(b.freq.value());
77 }
78 if rand_u32(seed, 2) == 0 {
79 a.cutoff.set_value(b.cutoff.value());
80 }
81 if rand_u32(seed, 2) == 0 {
82 a.resonance.set_value(b.resonance.value());
83 }
84 if rand_u32(seed, 2) == 0 {
85 a.reverb_mix.set_value(b.reverb_mix.value());
86 }
87 if rand_u32(seed, 2) == 0 {
88 a.pulse_depth.set_value(b.pulse_depth.value());
89 }
90 if rand_u32(seed, 2) == 0 {
91 a.pattern_hits.set_value(b.pattern_hits.value());
92 }
93 if rand_u32(seed, 2) == 0 {
94 a.pattern_rotation.set_value(b.pattern_rotation.value());
95 }
96 if rand_u32(seed, 2) == 0 {
97 a.character.set_value(b.character.value());
98 }
99 let cur = a.freq.value();
101 let scale = golden_pentatonic(cur);
102 let idx = rand_u32(seed, scale.len() as u32) as usize;
103 a.freq.set_value(scale[idx]);
104}