1use super::Effect;
2use crate::synth::{Duty, NoiseMode, Waveform};
3
4#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
6pub enum Preset {
7 Pickup,
9 Laser,
11 Explosion,
13 PowerUp,
15 Hit,
17 Jump,
19 Blip,
21}
22impl Preset {
23 pub const ALL: [Preset; 7] = [
24 Self::Pickup,
25 Self::Laser,
26 Self::Explosion,
27 Self::PowerUp,
28 Self::Hit,
29 Self::Jump,
30 Self::Blip,
31 ];
32}
33
34struct Rng(u64);
36impl Rng {
37 fn next(&mut self) -> u64 {
38 self.0 = self.0.wrapping_add(0x9e37_79b9_7f4a_7c15);
39 let mut z = self.0;
40 z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
41 z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
42 z ^ (z >> 31)
43 }
44 fn unit(&mut self) -> f64 {
45 (self.next() >> 11) as f64 / (1u64 << 53) as f64
46 }
47 fn range(&mut self, low: f64, high: f64) -> f64 {
49 ((low + (high - low) * self.unit()) * 1000.0).round() / 1000.0
50 }
51 fn chance(&mut self, probability: f64) -> bool {
52 self.unit() < probability
53 }
54 fn pick<T: Copy>(&mut self, items: &[T]) -> T {
55 items[(self.next() % items.len() as u64) as usize]
56 }
57}
58
59pub(super) fn generate(kind: Preset, seed: u64) -> Effect {
60 let index = Preset::ALL.iter().position(|&k| k == kind).unwrap_or(0) as u64;
61 let mut r = Rng(seed ^ index.wrapping_mul(0xd6e8_feb8_6659_fd93));
62 let duties = [Duty::Eighth, Duty::Quarter, Duty::Half];
63 let mut e = Effect::default();
64 match kind {
65 Preset::Pickup => {
66 e.waveform = if r.chance(0.75) {
67 Waveform::Pulse(r.pick(&duties))
68 } else {
69 Waveform::Sawtooth
70 };
71 e.frequency = r.range(700.0, 1700.0);
72 e.sustain = r.range(0.02, 0.1);
73 e.punch = r.range(0.3, 0.7);
74 e.decay = r.range(0.1, 0.35);
75 if r.chance(0.6) {
76 e.arpeggio = r.pick(&[3.0, 4.0, 5.0, 7.0, 12.0]);
77 e.arpeggio_time = r.range(0.03, 0.1);
78 }
79 }
80 Preset::Laser => {
81 let pulse = r.chance(0.6);
82 e.waveform = if pulse {
83 Waveform::Pulse(r.pick(&duties))
84 } else {
85 r.pick(&[Waveform::Sawtooth, Waveform::Triangle])
86 };
87 e.frequency = r.range(500.0, 2000.0);
88 e.slide = r.range(-8.0, -2.5);
89 e.slide_change = if r.chance(0.3) {
90 r.range(0.0, 20.0)
91 } else {
92 0.0
93 };
94 if pulse && r.chance(0.5) {
95 e.duty_sweep = r.range(-2.0, 2.0);
96 }
97 e.sustain = r.range(0.04, 0.15);
98 e.punch = if r.chance(0.5) {
99 r.range(0.0, 0.4)
100 } else {
101 0.0
102 };
103 e.decay = r.range(0.05, 0.2);
104 if r.chance(0.3) {
105 e.high_pass = r.range(100.0, 800.0);
106 }
107 }
108 Preset::Explosion => {
109 e.waveform = Waveform::Noise(NoiseMode::Long);
110 e.frequency = r.range(30.0, 250.0);
111 e.slide = r.range(-2.0, 0.0);
112 e.sustain = r.range(0.08, 0.3);
113 e.punch = r.range(0.2, 0.8);
114 e.decay = r.range(0.3, 0.9);
115 if r.chance(0.6) {
116 e.low_pass = r.range(800.0, 6000.0);
117 e.low_pass_sweep = r.range(-3.0, 0.0);
118 }
119 if r.chance(0.3) {
120 e.vibrato_depth = r.range(0.5, 3.0);
121 e.vibrato_speed = r.range(4.0, 14.0);
122 }
123 e.volume = 0.6;
124 }
125 Preset::PowerUp => {
126 e.waveform = if r.chance(0.6) {
127 Waveform::Pulse(r.pick(&duties))
128 } else {
129 Waveform::Sawtooth
130 };
131 e.frequency = r.range(250.0, 600.0);
132 e.slide = r.range(0.8, 3.0);
133 if r.chance(0.5) {
134 e.repeat = r.range(0.08, 0.2);
135 } else {
136 e.vibrato_depth = r.range(0.2, 1.0);
137 e.vibrato_speed = r.range(8.0, 20.0);
138 }
139 e.sustain = r.range(0.15, 0.4);
140 e.decay = r.range(0.1, 0.4);
141 }
142 Preset::Hit => {
143 let noise = r.chance(0.5);
144 e.waveform = if noise {
145 Waveform::Noise(NoiseMode::Long)
146 } else {
147 r.pick(&[Waveform::Sawtooth, Waveform::Pulse(Duty::Half)])
148 };
149 e.frequency = if noise {
150 r.range(40.0, 200.0)
151 } else {
152 r.range(100.0, 500.0)
153 };
154 e.slide = r.range(-6.0, -1.5);
155 e.sustain = r.range(0.01, 0.05);
156 e.punch = r.range(0.0, 0.5);
157 e.decay = r.range(0.05, 0.2);
158 if r.chance(0.5) {
159 e.high_pass = r.range(80.0, 500.0);
160 }
161 }
162 Preset::Jump => {
163 e.waveform = Waveform::Pulse(r.pick(&[Duty::Quarter, Duty::Half]));
164 e.frequency = r.range(250.0, 600.0);
165 e.slide = r.range(1.0, 3.0);
166 e.sustain = r.range(0.05, 0.15);
167 e.decay = r.range(0.1, 0.25);
168 if r.chance(0.4) {
169 e.low_pass = r.range(2000.0, 8000.0);
170 }
171 if r.chance(0.4) {
172 e.high_pass = r.range(100.0, 400.0);
173 }
174 }
175 Preset::Blip => {
176 e.waveform = if r.chance(0.7) {
177 Waveform::Pulse(r.pick(&[Duty::Quarter, Duty::Half]))
178 } else {
179 Waveform::Triangle
180 };
181 e.frequency = r.range(600.0, 1600.0);
182 e.sustain = r.range(0.02, 0.08);
183 e.decay = r.range(0.01, 0.05);
184 if r.chance(0.3) {
185 e.high_pass = r.range(100.0, 400.0);
186 }
187 e.volume = 0.4;
188 }
189 }
190 e
191}