1use crate::{f, fclampc, Flt};
8
9#[derive(Debug, Clone, Copy)]
16pub struct TriSawLFO<F: Flt> {
17 israte: F,
19 phase: F,
21 rev: F,
23 freq: F,
25 rise_r: F,
27 fall_r: F,
28 init_phase: F,
30}
31
32impl<F: Flt> TriSawLFO<F> {
33 pub fn new() -> Self {
34 let mut this = Self {
35 israte: f(1.0 / 44100.0),
36 phase: f(0.0),
37 rev: f(0.5),
38 freq: f(1.0),
39 fall_r: f(0.0),
40 rise_r: f(0.0),
41 init_phase: f(0.0),
42 };
43 this.recalc();
44 this
45 }
46
47 pub fn set_phase_offs(&mut self, phase: F) {
48 self.init_phase = phase;
49 self.phase = phase;
50 }
51
52 #[inline]
53 fn recalc(&mut self) {
54 self.rev = fclampc(self.rev, 0.0001, 0.999);
55 self.rise_r = f::<F>(1.0) / self.rev;
56 self.fall_r = f::<F>(-1.0) / (f::<F>(1.0) - self.rev);
57 }
58
59 pub fn set_sample_rate(&mut self, srate: F) {
60 self.israte = f::<F>(1.0) / (srate as F);
61 self.recalc();
62 }
63
64 pub fn reset(&mut self) {
65 self.phase = self.init_phase;
66 self.rev = f(0.5);
67 }
68
69 #[inline]
70 pub fn set(&mut self, freq: F, rev: F) {
71 self.freq = freq as F;
72 self.rev = rev as F;
73 self.recalc();
74 }
75
76 #[inline]
77 pub fn next_unipolar(&mut self) -> F {
78 if self.phase >= f(1.0) {
79 self.phase = self.phase - f(1.0);
80 }
81
82 let s = if self.phase < self.rev {
83 self.phase * self.rise_r
84 } else {
85 self.phase * self.fall_r - self.fall_r
86 };
87
88 self.phase = self.phase + self.freq * self.israte;
89
90 s
91 }
92
93 #[inline]
94 pub fn next_bipolar(&mut self) -> F {
95 (self.next_unipolar() * f(2.0)) - f(1.0)
96 }
97}
98
99#[derive(Debug, Clone, Copy)]
101pub struct SlewValue<F: Flt> {
102 current: F,
103 slew_per_ms: F,
104}
105
106impl<F: Flt> SlewValue<F> {
107 pub fn new() -> Self {
108 Self { current: f(0.0), slew_per_ms: f(1000.0 / 44100.0) }
109 }
110
111 pub fn reset(&mut self) {
112 self.current = f(0.0);
113 }
114
115 pub fn set_sample_rate(&mut self, srate: F) {
116 self.slew_per_ms = f::<F>(1000.0) / srate;
117 }
118
119 #[inline]
120 pub fn value(&self) -> F {
121 self.current
122 }
123
124 #[inline]
127 pub fn next(&mut self, target: F, slew_ms_per_1: F) -> F {
128 if slew_ms_per_1 < f(0.11) {
130 self.current = target;
131 } else {
132 let max_delta = self.slew_per_ms / slew_ms_per_1;
133 self.current = target.min(self.current + max_delta).max(self.current - max_delta);
134 }
135
136 self.current
137 }
138}
139
140#[derive(Debug, Clone, Copy)]
142pub struct RampValue<F: Flt> {
143 slew_count: u64,
144 current: F,
145 target: F,
146 inc: F,
147 sr_ms: F,
148}
149
150impl<F: Flt> RampValue<F> {
151 pub fn new() -> Self {
152 Self {
153 slew_count: 0,
154 current: f(0.0),
155 target: f(0.0),
156 inc: f(0.0),
157 sr_ms: f(44100.0 / 1000.0),
158 }
159 }
160
161 pub fn reset(&mut self) {
162 self.slew_count = 0;
163 self.current = f(0.0);
164 self.target = f(0.0);
165 self.inc = f(0.0);
166 }
167
168 pub fn set_sample_rate(&mut self, srate: F) {
169 self.sr_ms = srate / f(1000.0);
170 }
171
172 #[inline]
173 pub fn set_target(&mut self, target: F, slew_time_ms: F) {
174 self.target = target;
175
176 if slew_time_ms < f(0.02) {
178 self.current = self.target;
179 self.slew_count = 0;
180 } else {
181 let slew_samples = slew_time_ms * self.sr_ms;
182 self.slew_count = slew_samples.to_u64().unwrap_or(0);
183 self.inc = (self.target - self.current) / slew_samples;
184 }
185 }
186
187 #[inline]
188 pub fn value(&self) -> F {
189 self.current
190 }
191
192 #[inline]
193 pub fn next(&mut self) -> F {
194 if self.slew_count > 0 {
195 self.current = self.current + self.inc;
196 self.slew_count -= 1;
197 } else {
198 self.current = self.target;
199 }
200
201 self.current
202 }
203}
204
205#[derive(Debug, Clone)]
206pub struct Quantizer {
207 old_mask: i64,
208 lkup_tbl: [(f32, f32); 24],
209 last_key: f32,
210}
211
212impl Quantizer {
213 pub fn new() -> Self {
214 Self { old_mask: 0xFFFF_FFFF, lkup_tbl: [(0.0, 0.0); 24], last_key: 0.0 }
215 }
216
217 #[inline]
218 pub fn set_keys(&mut self, keys_mask: i64) {
219 if keys_mask == self.old_mask {
220 return;
221 }
222 self.old_mask = keys_mask;
223
224 self.setup_lookup_table();
225 }
226
227 #[inline]
228 fn setup_lookup_table(&mut self) {
229 let mask = self.old_mask;
230 let any_enabled = mask > 0x0;
231
232 for i in 0..24 {
233 let mut min_d_note_idx = 0;
234 let mut min_dist = 1000000000;
235
236 for note in -12..=24 {
237 let dist = ((i + 1_i64) / 2 - note).abs();
238 let note_idx = note.rem_euclid(12);
239
240 if any_enabled && (mask & (0x1 << ((note_idx + 9) % 12))) == 0x0 {
244 continue;
245 }
246
247 if dist < min_dist {
253 min_d_note_idx = note;
254 min_dist = dist;
255 } else {
256 break;
257 }
258 }
259
260 self.lkup_tbl[i as usize] = (
261 (min_d_note_idx + 9).rem_euclid(12) as f32 * (0.1 / 12.0),
262 min_d_note_idx.rem_euclid(12) as f32 * (0.1 / 12.0)
263 + (if min_d_note_idx < 0 {
264 -0.1
265 } else if min_d_note_idx > 11 {
266 0.1
267 } else {
268 0.0
269 }),
270 );
271 }
272 }
274
275 #[inline]
276 pub fn last_key_pitch(&self) -> f32 {
277 self.last_key
278 }
279
280 #[inline]
281 pub fn process(&mut self, inp: f32) -> f32 {
282 let note_num = (inp * 240.0).round() as i64;
283 let octave = note_num.div_euclid(24);
284 let note_idx = note_num - octave * 24;
285
286 let (ui_key_pitch, note_pitch) = self.lkup_tbl[note_idx as usize % 24];
292 self.last_key = ui_key_pitch;
293 note_pitch + octave as f32 * 0.1
294 }
295}
296
297#[derive(Debug, Clone)]
298pub struct CtrlPitchQuantizer {
299 keys: Vec<f32>,
301 used_keys: [f32; 12],
303 input_params: u64,
305 mask_key_count: u16,
307 last_key: u8,
309}
310
311const QUANT_TUNE_TO_A4: f32 = (9.0 / 12.0) * 0.1;
312
313impl CtrlPitchQuantizer {
314 pub fn new() -> Self {
315 Self {
316 keys: vec![0.0; 12 * 10],
317 used_keys: [0.0; 12],
318 mask_key_count: 0,
319 input_params: 0xFFFFFFFFFF,
320 last_key: 0,
321 }
322 }
323
324 #[inline]
325 pub fn last_key_pitch(&self) -> f32 {
326 self.used_keys[self.last_key as usize % (self.mask_key_count as usize)] + QUANT_TUNE_TO_A4
327 }
328
329 #[inline]
330 pub fn update_keys(&mut self, mut mask: i64, min_oct: i64, max_oct: i64) {
331 let inp_params = (mask as u64) | ((min_oct as u64) << 12) | ((max_oct as u64) << 20);
332
333 if self.input_params == inp_params {
334 return;
335 }
336
337 self.input_params = inp_params;
338
339 let mut mask_count = 0;
340
341 if mask == 0x0 {
343 mask = 0xFFFF;
344 }
345
346 for i in 0..12 {
347 if mask & (0x1 << i) > 0 {
348 self.used_keys[mask_count] = (i as f32 / 12.0) * 0.1 - QUANT_TUNE_TO_A4;
349 mask_count += 1;
350 }
351 }
352
353 self.keys.clear();
354
355 let min_oct = min_oct as usize;
356 for o in 0..min_oct {
357 let o = min_oct - o;
358
359 for i in 0..mask_count {
360 self.keys.push(self.used_keys[i] - (o as f32) * 0.1);
361 }
362 }
363
364 for i in 0..mask_count {
365 self.keys.push(self.used_keys[i]);
366 }
367
368 let max_oct = max_oct as usize;
369 for o in 1..=max_oct {
370 for i in 0..mask_count {
371 self.keys.push(self.used_keys[i] + (o as f32) * 0.1);
372 }
373 }
374
375 self.mask_key_count = mask_count as u16;
376 }
377
378 #[inline]
379 pub fn signal_to_pitch(&mut self, inp: f32) -> f32 {
380 let len = self.keys.len();
381 let key = (inp.clamp(0.0, 0.9999) * (len as f32)).floor();
382 let key = key as usize % len;
383 self.last_key = key as u8;
384 self.keys[key]
385 }
386}