1use super::{EffectTime, finite, within};
3use crate::Result;
4use crate::math::{cos_turns, db_to_gain, exp2, sin_turns};
5
6#[derive(Clone, Copy, Debug, PartialEq)]
10pub enum ModulationRate {
11 Hertz(f64),
13 Beats {
14 beats: f64,
15 bpm: f64,
16 },
17}
18impl ModulationRate {
19 fn hz(self) -> Result<f64> {
20 let hz = match self {
21 Self::Hertz(hz) => hz,
22 Self::Beats { beats, bpm } => 1.0 / EffectTime::Beats { beats, bpm }.seconds()?,
23 };
24 within(hz, 0.0, 20.0)?;
25 Ok(hz)
26 }
27}
28
29#[derive(Clone, Copy, Debug, PartialEq)]
33pub struct Chorus {
34 pub rate: ModulationRate,
35 pub delay_ms: f32,
36 pub depth_ms: f32,
37 pub feedback: f32,
39 pub stereo_phase: f32,
41 pub mix: f32,
43}
44impl Default for Chorus {
45 fn default() -> Self {
46 Self {
47 rate: ModulationRate::Hertz(0.8),
48 delay_ms: 18.0,
49 depth_ms: 6.0,
50 feedback: 0.0,
51 stereo_phase: 0.5,
52 mix: 0.35,
53 }
54 }
55}
56impl Chorus {
57 pub(super) fn values(self, rate: u32) -> Result<[f64; 6]> {
58 modulation(
59 self.rate,
60 self.delay_ms,
61 self.depth_ms,
62 self.feedback,
63 self.stereo_phase,
64 self.mix,
65 0.08,
66 rate,
67 )
68 }
69}
70
71#[derive(Clone, Copy, Debug, PartialEq)]
75pub struct Flanger {
76 pub rate: ModulationRate,
77 pub delay_ms: f32,
78 pub depth_ms: f32,
79 pub feedback: f32,
81 pub stereo_phase: f32,
83 pub mix: f32,
85}
86impl Default for Flanger {
87 fn default() -> Self {
88 Self {
89 rate: ModulationRate::Hertz(0.25),
90 delay_ms: 2.0,
91 depth_ms: 1.5,
92 feedback: 0.5,
93 stereo_phase: 0.0,
94 mix: 0.5,
95 }
96 }
97}
98impl Flanger {
99 pub(super) fn values(self, rate: u32) -> Result<[f64; 6]> {
100 modulation(
101 self.rate,
102 self.delay_ms,
103 self.depth_ms,
104 self.feedback,
105 self.stereo_phase,
106 self.mix,
107 0.02,
108 rate,
109 )
110 }
111}
112#[allow(clippy::too_many_arguments)]
113fn modulation(
114 speed: ModulationRate,
115 delay: f32,
116 depth: f32,
117 feedback: f32,
118 spread: f32,
119 mix: f32,
120 maximum: f64,
121 rate: u32,
122) -> Result<[f64; 6]> {
123 let delay = delay as f64 * rate as f64 / 1000.0;
124 let depth = depth as f64 * rate as f64 / 1000.0;
125 within(depth, 0.0, maximum * rate as f64)?;
126 within(delay - depth, 1.0, maximum * rate as f64)?;
127 within(delay + depth, 1.0, maximum * rate as f64)?;
128 feedback_range(feedback)?;
129 within(spread as f64, 0.0, 1.0)?;
130 within(mix as f64, 0.0, 1.0)?;
131 Ok([
132 speed.hz()?,
133 delay,
134 depth,
135 feedback as f64,
136 spread as f64,
137 mix as f64,
138 ])
139}
140fn feedback_range(feedback: f32) -> Result<()> {
141 within(feedback as f64, -(0.95f32 as f64), 0.95f32 as f64)
142}
143
144#[derive(Clone, Copy, Debug, PartialEq)]
148pub struct Phaser {
149 pub rate: ModulationRate,
150 pub centre_hz: f32,
152 pub depth_octaves: f32,
155 pub feedback: f32,
157 pub stereo_phase: f32,
159 pub mix: f32,
161}
162impl Default for Phaser {
163 fn default() -> Self {
164 Self {
165 rate: ModulationRate::Hertz(0.4),
166 centre_hz: 800.0,
167 depth_octaves: 2.0,
168 feedback: 0.2,
169 stereo_phase: 0.5,
170 mix: 0.5,
171 }
172 }
173}
174impl Phaser {
175 pub(super) fn values(self, rate: u32) -> Result<[f64; 6]> {
176 within(self.centre_hz as f64, 1.0, rate as f64 * 0.45)?;
177 within(self.depth_octaves as f64, 0.0, 4.0)?;
178 feedback_range(self.feedback)?;
179 within(self.stereo_phase as f64, 0.0, 1.0)?;
180 within(self.mix as f64, 0.0, 1.0)?;
181 Ok([
182 self.rate.hz()?,
183 self.centre_hz as f64,
184 self.depth_octaves as f64,
185 self.feedback as f64,
186 self.stereo_phase as f64,
187 self.mix as f64,
188 ])
189 }
190}
191
192#[derive(Clone, Copy, Debug, PartialEq)]
198pub struct Bitcrusher {
199 pub bits: f32,
201 pub rate_ratio: f32,
203 pub mix: f32,
205}
206impl Default for Bitcrusher {
207 fn default() -> Self {
208 Self {
209 bits: 8.0,
210 rate_ratio: 0.25,
211 mix: 1.0,
212 }
213 }
214}
215impl Bitcrusher {
216 pub(super) fn values(self) -> Result<[f64; 6]> {
217 within(self.bits as f64, 2.0, 24.0)?;
218 within(self.rate_ratio as f64, 0.001f32 as f64, 1.0)?;
219 within(self.mix as f64, 0.0, 1.0)?;
220 Ok([
221 self.bits as f64,
222 self.rate_ratio as f64,
223 self.mix as f64,
224 0.0,
225 0.0,
226 0.0,
227 ])
228 }
229}
230
231#[derive(Clone, Copy, Debug, PartialEq)]
235pub struct Saturation {
236 pub drive_db: f32,
238 pub output_db: f32,
240 pub mix: f32,
242}
243impl Default for Saturation {
244 fn default() -> Self {
245 Self {
246 drive_db: 6.0,
247 output_db: 0.0,
248 mix: 1.0,
249 }
250 }
251}
252impl Saturation {
253 pub(super) fn values(self) -> Result<[f64; 6]> {
254 within(self.drive_db as f64, 0.0, 36.0)?;
255 within(self.output_db as f64, -24.0, 24.0)?;
256 within(self.mix as f64, 0.0, 1.0)?;
257 Ok([
258 self.drive_db as f64,
259 self.output_db as f64,
260 self.mix as f64,
261 0.0,
262 0.0,
263 0.0,
264 ])
265 }
266}
267
268pub(super) enum Processor {
269 ModDelay {
270 ring: Vec<f64>,
271 at: usize,
272 phase: f64,
273 chorus: bool,
274 },
275 Phaser {
276 memory: Box<[[f64; 4]]>,
277 feedback: [f64; 8],
278 phase: f64,
279 },
280 Crusher {
281 held: [f64; 8],
282 phase: f64,
283 },
284 Saturation,
285}
286impl Processor {
287 pub(super) fn new(kind: u8, rate: u32, channels: usize) -> Self {
288 match kind {
289 5 | 6 => Self::ModDelay {
290 ring: vec![
291 0.0;
292 ((rate as f64 * if kind == 5 { 0.08 } else { 0.02 }).ceil() as usize + 2)
293 * channels
294 ],
295 at: 0,
296 phase: 0.0,
297 chorus: kind == 5,
298 },
299 7 => Self::Phaser {
300 memory: vec![[0.0; 4]; channels].into_boxed_slice(),
301 feedback: [0.0; 8],
302 phase: 0.0,
303 },
304 8 => Self::Crusher {
305 held: [0.0; 8],
306 phase: 1.0,
307 },
308 _ => Self::Saturation,
309 }
310 }
311 pub(super) fn process(&mut self, x: &mut [f64; 8], p: [f64; 6], rate: u32, channels: usize) {
312 match self {
313 Self::ModDelay {
314 ring,
315 at,
316 phase,
317 chorus,
318 } => {
319 let max = rate as f64 * if *chorus { 0.08 } else { 0.02 };
321 for c in 0..channels {
322 let phase = *phase + c as f64 * p[4];
323 let delay = (p[1] + p[2] * sin_turns(phase)).clamp(1.0, max);
324 let mut wet = read(ring, *at, delay, c, channels);
325 if *chorus {
326 let delay = (p[1] + p[2] * sin_turns(phase + 0.25)).clamp(1.0, max);
327 wet = (wet + read(ring, *at, delay, c, channels)) * 0.5;
328 }
329 ring[*at * channels + c] = finite(x[c] + wet * p[3]);
330 x[c] = x[c] * (1.0 - p[5]) + wet * p[5];
331 }
332 *at = (*at + 1) % (ring.len() / channels);
333 advance(phase, p[0] / rate as f64);
334 }
335 Self::Phaser {
336 memory,
337 feedback,
338 phase,
339 } => {
340 for c in 0..channels {
341 let hz = (p[1] * exp2(p[2] * sin_turns(*phase + c as f64 * p[4])))
342 .clamp(1.0, rate as f64 * 0.45);
343 let turns = hz / (2.0 * rate as f64);
344 let g = sin_turns(turns) / cos_turns(turns);
345 let a = (g - 1.0) / (g + 1.0);
346 let mut wet = finite(x[c] + feedback[c] * p[3]);
347 for state in &mut memory[c] {
348 let output = a * wet + *state;
349 *state = finite(wet - a * output);
350 wet = finite(output);
351 }
352 feedback[c] = wet;
353 x[c] = x[c] * (1.0 - p[5]) + wet * p[5];
354 }
355 advance(phase, p[0] / rate as f64);
356 }
357 Self::Crusher { held, phase } => {
358 if *phase >= 1.0 {
359 *held = *x;
360 *phase -= phase.floor();
361 }
362 *phase += p[1];
363 let bits = p[0].floor() as u32;
364 let fraction = p[0] - bits as f64;
365 for c in 0..channels {
366 let low = quantize(held[c], bits);
367 let high = quantize(held[c], (bits + 1).min(24));
368 let wet = low + (high - low) * fraction;
369 x[c] = x[c] * (1.0 - p[2]) + wet * p[2];
370 }
371 }
372 Self::Saturation => {
373 let drive = db_to_gain(p[0]);
374 let gain = db_to_gain(p[1]);
375 for sample in &mut x[..channels] {
376 let v = *sample * drive;
377 let wet = if v.abs() >= 1.0 {
378 v.signum() * (2.0 / 3.0)
379 } else {
380 v - v * v * v / 3.0
381 } * gain;
382 *sample = *sample * (1.0 - p[2]) + wet * p[2];
383 }
384 }
385 }
386 }
387}
388fn read(ring: &[f64], at: usize, delay: f64, channel: usize, channels: usize) -> f64 {
389 let frames = ring.len() / channels;
390 let mut pos = at as f64 - delay;
391 if pos < 0.0 {
392 pos += frames as f64;
393 }
394 let a = pos.floor() as usize;
395 let fraction = pos - a as f64;
396 ring[a * channels + channel] * (1.0 - fraction)
397 + ring[((a + 1) % frames) * channels + channel] * fraction
398}
399fn advance(phase: &mut f64, step: f64) {
400 *phase += step;
401 *phase -= phase.floor();
402}
403fn quantize(value: f64, bits: u32) -> f64 {
404 let scale = (1u64 << (bits - 1)) as f64;
405 (value.clamp(-1.0, 1.0) * scale)
406 .round()
407 .clamp(-scale, scale - 1.0)
408 / scale
409}