1use crate::bridge::cs_format_parameter;
2use num_enum::{IntoPrimitive, TryFromPrimitive};
3
4pub fn format_parameter_value(param_id: ParamId, value: f32) -> String {
6 let id: u8 = param_id.into();
7 cs_format_parameter(id as u32, value)
8}
9
10#[repr(u8)]
12#[derive(Copy, Clone, Eq, PartialEq, Debug, IntoPrimitive, TryFromPrimitive)]
13pub enum ParamId {
14 Interpolation = 0,
15 LowCutEnabled = 1,
16 HighCutEnabled = 2,
17 InputMix = 3,
18 LowCut = 4,
19 HighCut = 5,
20 DryOut = 6,
21 EarlyOut = 7,
22 LateOut = 8,
23
24 TapEnabled = 9,
25 TapCount = 10,
26 TapDecay = 11,
27 TapPredelay = 12,
28 TapLength = 13,
29
30 EarlyDiffuseEnabled = 14,
31 EarlyDiffuseCount = 15,
32 EarlyDiffuseDelay = 16,
33 EarlyDiffuseModAmount = 17,
34 EarlyDiffuseFeedback = 18,
35 EarlyDiffuseModRate = 19,
36
37 LateMode = 20,
38 LateLineCount = 21,
39 LateDiffuseEnabled = 22,
40 LateDiffuseCount = 23,
41 LateLineSize = 24,
42 LateLineModAmount = 25,
43 LateDiffuseDelay = 26,
44 LateDiffuseModAmount = 27,
45 LateLineDecay = 28,
46 LateLineModRate = 29,
47 LateDiffuseFeedback = 30,
48 LateDiffuseModRate = 31,
49
50 EqLowShelfEnabled = 32,
51 EqHighShelfEnabled = 33,
52 EqLowpassEnabled = 34,
53 EqLowFreq = 35,
54 EqHighFreq = 36,
55 EqCutoff = 37,
56 EqLowGain = 38,
57 EqHighGain = 39,
58 EqCrossSeed = 40,
59
60 SeedTap = 41,
61 SeedDiffusion = 42,
62 SeedDelay = 43,
63 SeedPostDiffusion = 44,
64}
65
66#[derive(Clone, Copy, Debug, PartialEq)]
67pub enum LateMode {
68 Pre = 0,
69 Post = 1,
70}
71
72#[derive(Clone, Copy, Debug, PartialEq)]
75pub struct Program {
76 pub interpolation: bool,
78 pub low_cut_enabled: bool,
79 pub high_cut_enabled: bool,
80 pub input_mix: f32,
81 pub low_cut: f32,
82 pub high_cut: f32,
83 pub dry_out: f32,
84 pub early_out: f32,
85 pub late_out: f32,
86
87 pub tap_enabled: bool,
89 pub tap_count: f32,
90 pub tap_decay: f32,
91 pub tap_predelay: f32,
92 pub tap_length: f32,
93
94 pub early_diffuse_enabled: bool,
96 pub early_diffuse_count: f32,
97 pub early_diffuse_delay: f32,
98 pub early_diffuse_mod_amount: f32,
99 pub early_diffuse_feedback: f32,
100 pub early_diffuse_mod_rate: f32,
101
102 pub late_mode: LateMode,
104 pub late_line_count: f32,
105 pub late_diffuse_enabled: bool,
106 pub late_diffuse_count: f32,
107 pub late_line_size: f32,
108 pub late_line_mod_amount: f32,
109 pub late_diffuse_delay: f32,
110 pub late_diffuse_mod_amount: f32,
111 pub late_line_decay: f32,
112 pub late_line_mod_rate: f32,
113 pub late_diffuse_feedback: f32,
114 pub late_diffuse_mod_rate: f32,
115
116 pub eq_low_shelf_enabled: bool,
118 pub eq_high_shelf_enabled: bool,
119 pub eq_lowpass_enabled: bool,
120 pub eq_low_freq: f32,
121 pub eq_high_freq: f32,
122 pub eq_cutoff: f32,
123 pub eq_low_gain: f32,
124 pub eq_high_gain: f32,
125 pub eq_cross_seed: f32,
126
127 pub seed_tap: f32,
129 pub seed_diffusion: f32,
130 pub seed_delay: f32,
131 pub seed_post_diffusion: f32,
132}
133
134impl Program {
136 pub fn to_array(&self) -> [f32; 45] {
139 [
140 bool_to_param(self.interpolation),
141 bool_to_param(self.low_cut_enabled),
142 bool_to_param(self.high_cut_enabled),
143 self.input_mix,
144 self.low_cut,
145 self.high_cut,
146 self.dry_out,
147 self.early_out,
148 self.late_out,
149 bool_to_param(self.tap_enabled),
150 self.tap_count,
151 self.tap_decay,
152 self.tap_predelay,
153 self.tap_length,
154 bool_to_param(self.early_diffuse_enabled),
155 self.early_diffuse_count,
156 self.early_diffuse_delay,
157 self.early_diffuse_mod_amount,
158 self.early_diffuse_feedback,
159 self.early_diffuse_mod_rate,
160 match self.late_mode {
161 LateMode::Pre => 0.0,
162 LateMode::Post => 1.0,
163 },
164 self.late_line_count,
165 bool_to_param(self.late_diffuse_enabled),
166 self.late_diffuse_count,
167 self.late_line_size,
168 self.late_line_mod_amount,
169 self.late_diffuse_delay,
170 self.late_diffuse_mod_amount,
171 self.late_line_decay,
172 self.late_line_mod_rate,
173 self.late_diffuse_feedback,
174 self.late_diffuse_mod_rate,
175 bool_to_param(self.eq_low_shelf_enabled),
176 bool_to_param(self.eq_high_shelf_enabled),
177 bool_to_param(self.eq_lowpass_enabled),
178 self.eq_low_freq,
179 self.eq_high_freq,
180 self.eq_cutoff,
181 self.eq_low_gain,
182 self.eq_high_gain,
183 self.eq_cross_seed,
184 self.seed_tap,
185 self.seed_diffusion,
186 self.seed_delay,
187 self.seed_post_diffusion,
188 ]
189 }
190
191 pub fn from_array(a: [f32; 45]) -> Self {
194 Self {
195 interpolation: param_to_bool(a[0]),
196 low_cut_enabled: param_to_bool(a[1]),
197 high_cut_enabled: param_to_bool(a[2]),
198 input_mix: a[3],
199 low_cut: a[4],
200 high_cut: a[5],
201 dry_out: a[6],
202 early_out: a[7],
203 late_out: a[8],
204 tap_enabled: param_to_bool(a[9]),
205 tap_count: a[10],
206 tap_decay: a[11],
207 tap_predelay: a[12],
208 tap_length: a[13],
209 early_diffuse_enabled: param_to_bool(a[14]),
210 early_diffuse_count: a[15],
211 early_diffuse_delay: a[16],
212 early_diffuse_mod_amount: a[17],
213 early_diffuse_feedback: a[18],
214 early_diffuse_mod_rate: a[19],
215 late_mode: if a[20] >= 0.5 {
216 LateMode::Post
217 } else {
218 LateMode::Pre
219 },
220 late_line_count: a[21],
221 late_diffuse_enabled: param_to_bool(a[22]),
222 late_diffuse_count: a[23],
223 late_line_size: a[24],
224 late_line_mod_amount: a[25],
225 late_diffuse_delay: a[26],
226 late_diffuse_mod_amount: a[27],
227 late_line_decay: a[28],
228 late_line_mod_rate: a[29],
229 late_diffuse_feedback: a[30],
230 late_diffuse_mod_rate: a[31],
231 eq_low_shelf_enabled: param_to_bool(a[32]),
232 eq_high_shelf_enabled: param_to_bool(a[33]),
233 eq_lowpass_enabled: param_to_bool(a[34]),
234 eq_low_freq: a[35],
235 eq_high_freq: a[36],
236 eq_cutoff: a[37],
237 eq_low_gain: a[38],
238 eq_high_gain: a[39],
239 eq_cross_seed: a[40],
240 seed_tap: a[41],
241 seed_diffusion: a[42],
242 seed_delay: a[43],
243 seed_post_diffusion: a[44],
244 }
245 }
246
247 pub fn from_slice(slice: &[f32]) -> Option<Self> {
250 if slice.len() == 45 {
251 let mut a = [0.0f32; 45];
252 a.copy_from_slice(slice);
253 Some(Self::from_array(a))
254 } else {
255 None
256 }
257 }
258}
259
260impl Program {
262 pub fn get(&self, id: ParamId) -> f32 {
264 match id {
265 ParamId::Interpolation => bool_to_param(self.interpolation),
266 ParamId::LowCutEnabled => bool_to_param(self.low_cut_enabled),
267 ParamId::HighCutEnabled => bool_to_param(self.high_cut_enabled),
268 ParamId::InputMix => self.input_mix,
269 ParamId::LowCut => self.low_cut,
270 ParamId::HighCut => self.high_cut,
271 ParamId::DryOut => self.dry_out,
272 ParamId::EarlyOut => self.early_out,
273 ParamId::LateOut => self.late_out,
274
275 ParamId::TapEnabled => bool_to_param(self.tap_enabled),
276 ParamId::TapCount => self.tap_count,
277 ParamId::TapDecay => self.tap_decay,
278 ParamId::TapPredelay => self.tap_predelay,
279 ParamId::TapLength => self.tap_length,
280
281 ParamId::EarlyDiffuseEnabled => bool_to_param(self.early_diffuse_enabled),
282 ParamId::EarlyDiffuseCount => self.early_diffuse_count,
283 ParamId::EarlyDiffuseDelay => self.early_diffuse_delay,
284 ParamId::EarlyDiffuseModAmount => self.early_diffuse_mod_amount,
285 ParamId::EarlyDiffuseFeedback => self.early_diffuse_feedback,
286 ParamId::EarlyDiffuseModRate => self.early_diffuse_mod_rate,
287
288 ParamId::LateMode => match self.late_mode {
289 LateMode::Pre => 0.0,
290 LateMode::Post => 1.0,
291 },
292 ParamId::LateLineCount => self.late_line_count,
293 ParamId::LateDiffuseEnabled => bool_to_param(self.late_diffuse_enabled),
294 ParamId::LateDiffuseCount => self.late_diffuse_count,
295 ParamId::LateLineSize => self.late_line_size,
296 ParamId::LateLineModAmount => self.late_line_mod_amount,
297 ParamId::LateDiffuseDelay => self.late_diffuse_delay,
298 ParamId::LateDiffuseModAmount => self.late_diffuse_mod_amount,
299 ParamId::LateLineDecay => self.late_line_decay,
300 ParamId::LateLineModRate => self.late_line_mod_rate,
301 ParamId::LateDiffuseFeedback => self.late_diffuse_feedback,
302 ParamId::LateDiffuseModRate => self.late_diffuse_mod_rate,
303
304 ParamId::EqLowShelfEnabled => bool_to_param(self.eq_low_shelf_enabled),
305 ParamId::EqHighShelfEnabled => bool_to_param(self.eq_high_shelf_enabled),
306 ParamId::EqLowpassEnabled => bool_to_param(self.eq_lowpass_enabled),
307
308 ParamId::EqLowFreq => self.eq_low_freq,
309 ParamId::EqHighFreq => self.eq_high_freq,
310 ParamId::EqCutoff => self.eq_cutoff,
311 ParamId::EqLowGain => self.eq_low_gain,
312 ParamId::EqHighGain => self.eq_high_gain,
313 ParamId::EqCrossSeed => self.eq_cross_seed,
314
315 ParamId::SeedTap => self.seed_tap,
316 ParamId::SeedDiffusion => self.seed_diffusion,
317 ParamId::SeedDelay => self.seed_delay,
318 ParamId::SeedPostDiffusion => self.seed_post_diffusion,
319 }
320 }
321
322 pub fn set(&mut self, id: ParamId, value: f32) {
324 match id {
325 ParamId::Interpolation => {
326 self.interpolation = param_to_bool(value);
327 }
328 ParamId::LowCutEnabled => {
329 self.low_cut_enabled = param_to_bool(value);
330 }
331 ParamId::HighCutEnabled => {
332 self.high_cut_enabled = param_to_bool(value);
333 }
334 ParamId::InputMix => {
335 self.input_mix = value;
336 }
337 ParamId::LowCut => {
338 self.low_cut = value;
339 }
340 ParamId::HighCut => {
341 self.high_cut = value;
342 }
343 ParamId::DryOut => {
344 self.dry_out = value;
345 }
346 ParamId::EarlyOut => {
347 self.early_out = value;
348 }
349 ParamId::LateOut => {
350 self.late_out = value;
351 }
352 ParamId::TapEnabled => {
353 self.tap_enabled = param_to_bool(value);
354 }
355 ParamId::TapCount => {
356 self.tap_count = value;
357 }
358 ParamId::TapDecay => {
359 self.tap_decay = value;
360 }
361 ParamId::TapPredelay => {
362 self.tap_predelay = value;
363 }
364 ParamId::TapLength => {
365 self.tap_length = value;
366 }
367 ParamId::EarlyDiffuseEnabled => {
368 self.early_diffuse_enabled = param_to_bool(value);
369 }
370 ParamId::EarlyDiffuseCount => {
371 self.early_diffuse_count = value;
372 }
373 ParamId::EarlyDiffuseDelay => {
374 self.early_diffuse_delay = value;
375 }
376 ParamId::EarlyDiffuseModAmount => {
377 self.early_diffuse_mod_amount = value;
378 }
379 ParamId::EarlyDiffuseFeedback => {
380 self.early_diffuse_feedback = value;
381 }
382 ParamId::EarlyDiffuseModRate => {
383 self.early_diffuse_mod_rate = value;
384 }
385 ParamId::LateMode => {
386 self.late_mode = if value >= 0.5 {
387 LateMode::Post
388 } else {
389 LateMode::Pre
390 };
391 }
392 ParamId::LateLineCount => {
393 self.late_line_count = value;
394 }
395 ParamId::LateDiffuseEnabled => {
396 self.late_diffuse_enabled = param_to_bool(value);
397 }
398 ParamId::LateDiffuseCount => {
399 self.late_diffuse_count = value;
400 }
401 ParamId::LateLineSize => {
402 self.late_line_size = value;
403 }
404 ParamId::LateLineModAmount => {
405 self.late_line_mod_amount = value;
406 }
407 ParamId::LateDiffuseDelay => {
408 self.late_diffuse_delay = value;
409 }
410 ParamId::LateDiffuseModAmount => {
411 self.late_diffuse_mod_amount = value;
412 }
413 ParamId::LateLineDecay => {
414 self.late_line_decay = value;
415 }
416 ParamId::LateLineModRate => {
417 self.late_line_mod_rate = value;
418 }
419 ParamId::LateDiffuseFeedback => {
420 self.late_diffuse_feedback = value;
421 }
422 ParamId::LateDiffuseModRate => {
423 self.late_diffuse_mod_rate = value;
424 }
425 ParamId::EqLowShelfEnabled => {
426 self.eq_low_shelf_enabled = param_to_bool(value);
427 }
428 ParamId::EqHighShelfEnabled => {
429 self.eq_high_shelf_enabled = param_to_bool(value);
430 }
431 ParamId::EqLowpassEnabled => {
432 self.eq_lowpass_enabled = param_to_bool(value);
433 }
434 ParamId::EqLowFreq => {
435 self.eq_low_freq = value;
436 }
437 ParamId::EqHighFreq => {
438 self.eq_high_freq = value;
439 }
440 ParamId::EqCutoff => {
441 self.eq_cutoff = value;
442 }
443 ParamId::EqLowGain => {
444 self.eq_low_gain = value;
445 }
446 ParamId::EqHighGain => {
447 self.eq_high_gain = value;
448 }
449 ParamId::EqCrossSeed => {
450 self.eq_cross_seed = value;
451 }
452 ParamId::SeedTap => {
453 self.seed_tap = value;
454 }
455 ParamId::SeedDiffusion => {
456 self.seed_diffusion = value;
457 }
458 ParamId::SeedDelay => {
459 self.seed_delay = value;
460 }
461 ParamId::SeedPostDiffusion => {
462 self.seed_post_diffusion = value;
463 }
464 }
465 }
466}
467
468fn param_to_bool(value: f32) -> bool {
469 value >= 0.5
470}
471
472fn bool_to_param(value: bool) -> f32 {
473 if value {
474 1.0
475 } else {
476 0.0
477 }
478}
479
480pub static DARK_PLATE: Program = Program {
482 interpolation: true,
484 low_cut_enabled: false,
485 high_cut_enabled: false,
486 input_mix: 0.23469999,
487 low_cut: 0.63999999,
488 high_cut: 0.29330000,
489 dry_out: 0.8706000,
490 early_out: 0.0,
491 late_out: 0.66139996,
492
493 tap_enabled: false,
495 tap_count: 0.19599999,
496 tap_decay: 1.0,
497 tap_predelay: 0.0,
498 tap_length: 0.98670000,
499
500 early_diffuse_enabled: false,
502 early_diffuse_count: 0.29600000,
503 early_diffuse_delay: 0.30669999,
504 early_diffuse_mod_amount: 0.14389999,
505 early_diffuse_feedback: 0.77069998,
506 early_diffuse_mod_rate: 0.24669999,
507
508 late_mode: LateMode::Post,
510 late_line_count: 1.0,
511 late_diffuse_enabled: true,
512 late_diffuse_count: 0.48799998,
513 late_line_size: 0.46939999,
514 late_line_mod_amount: 0.27199998,
515 late_diffuse_delay: 0.23999999,
516 late_diffuse_mod_amount: 0.14680000,
517 late_line_decay: 0.63460000,
518 late_line_mod_rate: 0.22929999,
519 late_diffuse_feedback: 0.85069996,
520 late_diffuse_mod_rate: 0.16669999,
521
522 eq_low_shelf_enabled: false,
524 eq_high_shelf_enabled: true,
525 eq_lowpass_enabled: false,
526 eq_low_freq: 0.38799998,
527 eq_high_freq: 0.51339996,
528 eq_cutoff: 0.97599995,
529 eq_low_gain: 0.55599999,
530 eq_high_gain: 0.76800001,
531 eq_cross_seed: 0.0,
532
533 seed_tap: 0.33399999,
535 seed_diffusion: 0.18500000,
536 seed_delay: 0.21810000,
537 seed_post_diffusion: 0.36530000,
538};