Vocoder: toggle switch for detection LEDs
[calf.git] / src / modules_dist.cpp
blob017a48f430dddc3e52363aae75e0ca66ca6a7f94
1 /* Calf DSP plugin pack
2 * Distortion related plugins
4 * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #include <limits.h>
22 #include <memory.h>
23 #include <calf/giface.h>
24 #include <calf/modules_dist.h>
26 using namespace dsp;
27 using namespace calf_plugins;
29 #define SET_IF_CONNECTED(name) if (params[AM::param_##name] != NULL) *params[AM::param_##name] = name;
31 /**********************************************************************
32 * SATURATOR by Markus Schmidt
33 **********************************************************************/
35 saturator_audio_module::saturator_audio_module()
37 is_active = false;
38 srate = 0;
39 meter_drive = 0.f;
40 lp_pre_freq_old = -1;
41 hp_pre_freq_old = -1;
42 lp_post_freq_old = -1;
43 hp_post_freq_old = -1;
44 p_freq_old = -1;
45 p_level_old = -1;
46 p_q_old = -1;
49 void saturator_audio_module::activate()
51 is_active = true;
52 // set all filters
53 params_changed();
54 meter_drive = 0.f;
56 void saturator_audio_module::deactivate()
58 is_active = false;
61 void saturator_audio_module::params_changed()
63 // set the params of all filters
64 if(*params[param_lp_pre_freq] != lp_pre_freq_old) {
65 lp[0][0].set_lp_rbj(*params[param_lp_pre_freq], 0.707, (float)srate);
66 if(in_count > 1 && out_count > 1)
67 lp[1][0].copy_coeffs(lp[0][0]);
68 lp[0][1].copy_coeffs(lp[0][0]);
69 if(in_count > 1 && out_count > 1)
70 lp[1][1].copy_coeffs(lp[0][0]);
71 lp_pre_freq_old = *params[param_lp_pre_freq];
73 if(*params[param_hp_pre_freq] != hp_pre_freq_old) {
74 hp[0][0].set_hp_rbj(*params[param_hp_pre_freq], 0.707, (float)srate);
75 if(in_count > 1 && out_count > 1)
76 hp[1][0].copy_coeffs(hp[0][0]);
77 hp[0][1].copy_coeffs(hp[0][0]);
78 if(in_count > 1 && out_count > 1)
79 hp[1][1].copy_coeffs(hp[0][0]);
80 hp_pre_freq_old = *params[param_hp_pre_freq];
82 if(*params[param_lp_post_freq] != lp_post_freq_old) {
83 lp[0][2].set_lp_rbj(*params[param_lp_post_freq], 0.707, (float)srate);
84 if(in_count > 1 && out_count > 1)
85 lp[1][2].copy_coeffs(lp[0][2]);
86 lp[0][3].copy_coeffs(lp[0][2]);
87 if(in_count > 1 && out_count > 1)
88 lp[1][3].copy_coeffs(lp[0][2]);
89 lp_post_freq_old = *params[param_lp_post_freq];
91 if(*params[param_hp_post_freq] != hp_post_freq_old) {
92 hp[0][2].set_hp_rbj(*params[param_hp_post_freq], 0.707, (float)srate);
93 if(in_count > 1 && out_count > 1)
94 hp[1][2].copy_coeffs(hp[0][2]);
95 hp[0][3].copy_coeffs(hp[0][2]);
96 if(in_count > 1 && out_count > 1)
97 hp[1][3].copy_coeffs(hp[0][2]);
98 hp_post_freq_old = *params[param_hp_post_freq];
100 if(*params[param_p_freq] != p_freq_old or *params[param_p_level] != p_level_old or *params[param_p_q] != p_q_old) {
101 p[0].set_peakeq_rbj((float)*params[param_p_freq], (float)*params[param_p_q], (float)*params[param_p_level], (float)srate);
102 if(in_count > 1 && out_count > 1)
103 p[1].copy_coeffs(p[0]);
104 p_freq_old = *params[param_p_freq];
105 p_level_old = *params[param_p_level];
106 p_q_old = *params[param_p_q];
108 // set distortion
109 dist[0].set_params(*params[param_blend], *params[param_drive]);
110 if(in_count > 1 && out_count > 1)
111 dist[1].set_params(*params[param_blend], *params[param_drive]);
114 void saturator_audio_module::set_sample_rate(uint32_t sr)
116 srate = sr;
117 dist[0].set_sample_rate(sr);
118 if(in_count > 1 && out_count > 1)
119 dist[1].set_sample_rate(sr);
120 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
121 int clip[] = {param_clip_in, param_clip_out, -1};
122 meters.init(params, meter, clip, 3, srate);
125 uint32_t saturator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
127 bool bypass = *params[param_bypass] > 0.5f;
128 numsamples += offset;
129 if(bypass) {
130 // everything bypassed
131 while(offset < numsamples) {
132 if(in_count > 1 && out_count > 1) {
133 outs[0][offset] = ins[0][offset];
134 outs[1][offset] = ins[1][offset];
135 } else if(in_count > 1) {
136 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
137 } else if(out_count > 1) {
138 outs[0][offset] = ins[0][offset];
139 outs[1][offset] = ins[0][offset];
140 } else {
141 outs[0][offset] = ins[0][offset];
143 float values[] = {0, 0, 0};
144 meters.process(values);
145 ++offset;
147 } else {
148 // process
149 while(offset < numsamples) {
150 // cycle through samples
151 float out[2], in[2] = {0.f, 0.f};
152 int c = 0;
153 float maxDrive = 0.f;
154 if(in_count > 1 && out_count > 1) {
155 // stereo in/stereo out
156 // handle full stereo
157 in[0] = ins[0][offset];
158 in[1] = ins[1][offset];
159 c = 2;
160 } else {
161 // in and/or out mono
162 // handle mono
163 in[0] = ins[0][offset];
164 in[1] = in[0];
165 c = 1;
168 float proc[2];
169 proc[0] = in[0] * *params[param_level_in];
170 proc[1] = in[1] * *params[param_level_in];
172 float onedivlevelin = 1.0 / *params[param_level_in];
174 for (int i = 0; i < c; ++i) {
175 // all pre filters in chain
176 proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
177 proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
179 // ...saturate...
180 proc[i] = dist[i].process(proc[i]);
182 // tone control
183 proc[i] = p[i].process(proc[i]);
185 // all post filters in chain
186 proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
187 proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
189 //subtract gain
190 proc[i] *= onedivlevelin;
192 if (*params[param_level_in] > 1)
193 proc[i] *= 1 + (*params[param_level_in] - 1) / 32;
196 maxDrive = dist[0].get_distortion_level() * *params[param_blend];
198 if(in_count > 1 && out_count > 1) {
199 maxDrive = dist[1].get_distortion_level() * *params[param_blend];
200 // full stereo
201 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
202 outs[0][offset] = out[0];
203 out[1] = ((proc[1] * *params[param_mix]) + in[1] * (1 - *params[param_mix])) * *params[param_level_out];
204 outs[1][offset] = out[1];
205 } else if(out_count > 1) {
206 // mono -> pseudo stereo
207 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
208 outs[0][offset] = out[0];
209 out[1] = out[0];
210 outs[1][offset] = out[1];
211 } else {
212 // stereo -> mono
213 // or full mono
214 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
215 outs[0][offset] = out[0];
217 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive / 20};
218 meters.process(values);
220 // next sample
221 ++offset;
222 } // cycle trough samples
224 // clean up
225 lp[0][0].sanitize();
226 lp[1][0].sanitize();
227 lp[0][1].sanitize();
228 lp[1][1].sanitize();
229 lp[0][2].sanitize();
230 lp[1][2].sanitize();
231 lp[0][3].sanitize();
232 lp[1][3].sanitize();
233 hp[0][0].sanitize();
234 hp[1][0].sanitize();
235 hp[0][1].sanitize();
236 hp[1][1].sanitize();
237 hp[0][2].sanitize();
238 hp[1][2].sanitize();
239 hp[0][3].sanitize();
240 hp[1][3].sanitize();
241 p[0].sanitize();
242 p[1].sanitize();
244 meters.fall(numsamples);
245 return outputs_mask;
248 /**********************************************************************
249 * EXCITER by Markus Schmidt
250 **********************************************************************/
252 exciter_audio_module::exciter_audio_module()
254 freq_old = 0.f;
255 ceil_old = 0.f;
256 ceil_active_old = false;
257 meter_drive = 0.f;
258 is_active = false;
259 srate = 0;
262 void exciter_audio_module::activate()
264 is_active = true;
265 // set all filters
266 params_changed();
269 void exciter_audio_module::deactivate()
271 is_active = false;
274 void exciter_audio_module::params_changed()
276 // set the params of all filters
277 if(*params[param_freq] != freq_old) {
278 hp[0][0].set_hp_rbj(*params[param_freq], 0.707, (float)srate);
279 hp[0][1].copy_coeffs(hp[0][0]);
280 hp[0][2].copy_coeffs(hp[0][0]);
281 hp[0][3].copy_coeffs(hp[0][0]);
282 if(in_count > 1 && out_count > 1) {
283 hp[1][0].copy_coeffs(hp[0][0]);
284 hp[1][1].copy_coeffs(hp[0][0]);
285 hp[1][2].copy_coeffs(hp[0][0]);
286 hp[1][3].copy_coeffs(hp[0][0]);
288 freq_old = *params[param_freq];
290 // set the params of all filters
291 if(*params[param_ceil] != ceil_old or *params[param_ceil_active] != ceil_active_old) {
292 lp[0][0].set_lp_rbj(*params[param_ceil], 0.707, (float)srate);
293 lp[0][1].copy_coeffs(lp[0][0]);
294 lp[1][0].copy_coeffs(lp[0][0]);
295 lp[1][1].copy_coeffs(lp[0][0]);
296 ceil_old = *params[param_ceil];
297 ceil_active_old = *params[param_ceil_active];
299 // set distortion
300 dist[0].set_params(*params[param_blend], *params[param_drive]);
301 if(in_count > 1 && out_count > 1)
302 dist[1].set_params(*params[param_blend], *params[param_drive]);
305 void exciter_audio_module::set_sample_rate(uint32_t sr)
307 srate = sr;
308 dist[0].set_sample_rate(sr);
309 if(in_count > 1 && out_count > 1)
310 dist[1].set_sample_rate(sr);
311 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
312 int clip[] = {param_clip_in, param_clip_out, -1};
313 meters.init(params, meter, clip, 3, srate);
316 uint32_t exciter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
318 bool bypass = *params[param_bypass] > 0.5f;
319 numsamples += offset;
320 if(bypass) {
321 // everything bypassed
322 while(offset < numsamples) {
323 if(in_count > 1 && out_count > 1) {
324 outs[0][offset] = ins[0][offset];
325 outs[1][offset] = ins[1][offset];
326 } else if(in_count > 1) {
327 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
328 } else if(out_count > 1) {
329 outs[0][offset] = ins[0][offset];
330 outs[1][offset] = ins[0][offset];
331 } else {
332 outs[0][offset] = ins[0][offset];
334 float values[] = {0, 0, 0, 0, 0};
335 meters.process(values);
336 ++offset;
338 // displays, too
339 meter_drive = 0.f;
340 } else {
342 meter_drive = 0.f;
344 float in2out = *params[param_listen] > 0.f ? 0.f : 1.f;
346 // process
347 while(offset < numsamples) {
348 // cycle through samples
349 float out[2], in[2] = {0.f, 0.f};
350 float maxDrive = 0.f;
351 int c = 0;
353 if(in_count > 1 && out_count > 1) {
354 // stereo in/stereo out
355 // handle full stereo
356 in[0] = ins[0][offset];
357 in[0] *= *params[param_level_in];
358 in[1] = ins[1][offset];
359 in[1] *= *params[param_level_in];
360 c = 2;
361 } else {
362 // in and/or out mono
363 // handle mono
364 in[0] = ins[0][offset];
365 in[0] *= *params[param_level_in];
366 in[1] = in[0];
367 c = 1;
370 float proc[2];
371 proc[0] = in[0];
372 proc[1] = in[1];
374 for (int i = 0; i < c; ++i) {
375 // all pre filters in chain
376 proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
378 // saturate
379 proc[i] = dist[i].process(proc[i]);
381 // all post filters in chain
382 proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
384 if(*params[param_ceil_active] > 0.5f) {
385 // all H/P post filters in chain
386 proc[i] = lp[i][0].process(lp[i][1].process(proc[i]));
390 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
392 if(in_count > 1 && out_count > 1) {
393 maxDrive = std::max(maxDrive, dist[1].get_distortion_level() * *params[param_amount]);
394 // full stereo
395 out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
396 out[1] = (proc[1] * *params[param_amount] + in2out * in[1]) * *params[param_level_out];
397 outs[0][offset] = out[0];
398 outs[1][offset] = out[1];
399 } else if(out_count > 1) {
400 // mono -> pseudo stereo
401 out[1] = out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
402 outs[0][offset] = out[0];
403 outs[1][offset] = out[1];
404 } else {
405 // stereo -> mono
406 // or full mono
407 out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
408 outs[0][offset] = out[0];
410 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive};
411 meters.process(values);
412 // next sample
413 ++offset;
414 } // cycle trough samples
415 // clean up
416 hp[0][0].sanitize();
417 hp[1][0].sanitize();
418 hp[0][1].sanitize();
419 hp[1][1].sanitize();
420 hp[0][2].sanitize();
421 hp[1][2].sanitize();
422 hp[0][3].sanitize();
423 hp[1][3].sanitize();
425 lp[0][0].sanitize();
426 lp[1][0].sanitize();
427 lp[0][1].sanitize();
428 lp[1][1].sanitize();
430 meters.fall(numsamples);
431 return outputs_mask;
434 /**********************************************************************
435 * BASS ENHANCER by Markus Schmidt
436 **********************************************************************/
438 bassenhancer_audio_module::bassenhancer_audio_module()
440 freq_old = 0.f;
441 floor_old = 0.f;
442 floor_active_old = false;
443 meter_drive = 0.f;
444 is_active = false;
445 srate = 0;
448 void bassenhancer_audio_module::activate()
450 is_active = true;
451 // set all filters
452 params_changed();
454 void bassenhancer_audio_module::deactivate()
456 is_active = false;
459 void bassenhancer_audio_module::params_changed()
461 // set the params of all filters
462 if(*params[param_freq] != freq_old) {
463 lp[0][0].set_lp_rbj(*params[param_freq], 0.707, (float)srate);
464 lp[0][1].copy_coeffs(lp[0][0]);
465 lp[0][2].copy_coeffs(lp[0][0]);
466 lp[0][3].copy_coeffs(lp[0][0]);
467 if(in_count > 1 && out_count > 1) {
468 lp[1][0].copy_coeffs(lp[0][0]);
469 lp[1][1].copy_coeffs(lp[0][0]);
470 lp[1][2].copy_coeffs(lp[0][0]);
471 lp[1][3].copy_coeffs(lp[0][0]);
473 freq_old = *params[param_freq];
475 // set the params of all filters
476 if(*params[param_floor] != floor_old or *params[param_floor_active] != floor_active_old) {
477 hp[0][0].set_hp_rbj(*params[param_floor], 0.707, (float)srate);
478 hp[0][1].copy_coeffs(hp[0][0]);
479 hp[1][0].copy_coeffs(hp[0][0]);
480 hp[1][1].copy_coeffs(hp[0][0]);
481 floor_old = *params[param_floor];
482 floor_active_old = *params[param_floor_active];
484 // set distortion
485 dist[0].set_params(*params[param_blend], *params[param_drive]);
486 if(in_count > 1 && out_count > 1)
487 dist[1].set_params(*params[param_blend], *params[param_drive]);
490 void bassenhancer_audio_module::set_sample_rate(uint32_t sr)
492 srate = sr;
493 dist[0].set_sample_rate(sr);
494 if(in_count > 1 && out_count > 1)
495 dist[1].set_sample_rate(sr);
496 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
497 int clip[] = {param_clip_in, param_clip_out, -1};
498 meters.init(params, meter, clip, 3, srate);
501 uint32_t bassenhancer_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
503 bool bypass = *params[param_bypass] > 0.5f;
504 numsamples += offset;
505 if(bypass) {
506 // everything bypassed
507 while(offset < numsamples) {
508 if(in_count > 1 && out_count > 1) {
509 outs[0][offset] = ins[0][offset];
510 outs[1][offset] = ins[1][offset];
511 } else if(in_count > 1) {
512 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
513 } else if(out_count > 1) {
514 outs[0][offset] = ins[0][offset];
515 outs[1][offset] = ins[0][offset];
516 } else {
517 outs[0][offset] = ins[0][offset];
519 float values[] = {0, 0, 0};
520 meters.process(values);
521 ++offset;
523 } else {
524 // process
525 while(offset < numsamples) {
526 // cycle through samples
527 float out[2], in[2] = {0.f, 0.f};
528 float maxDrive = 0.f;
529 int c = 0;
531 if(in_count > 1 && out_count > 1) {
532 // stereo in/stereo out
533 // handle full stereo
534 in[0] = ins[0][offset];
535 in[0] *= *params[param_level_in];
536 in[1] = ins[1][offset];
537 in[1] *= *params[param_level_in];
538 c = 2;
539 } else {
540 // in and/or out mono
541 // handle mono
542 in[0] = ins[0][offset];
543 in[0] *= *params[param_level_in];
544 in[1] = in[0];
545 c = 1;
548 float proc[2];
549 proc[0] = in[0];
550 proc[1] = in[1];
552 for (int i = 0; i < c; ++i) {
553 // all pre filters in chain
554 proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
556 // saturate
557 proc[i] = dist[i].process(proc[i]);
559 // all post filters in chain
560 proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
562 if(*params[param_floor_active] > 0.5f) {
563 // all H/P post filters in chain
564 proc[i] = hp[i][0].process(hp[i][1].process(proc[i]));
569 if(in_count > 1 && out_count > 1) {
570 // full stereo
571 if(*params[param_listen] > 0.f)
572 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
573 else
574 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
575 outs[0][offset] = out[0];
576 if(*params[param_listen] > 0.f)
577 out[1] = proc[1] * *params[param_amount] * *params[param_level_out];
578 else
579 out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out];
580 outs[1][offset] = out[1];
581 maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount],
582 dist[1].get_distortion_level() * *params[param_amount]);
583 } else if(out_count > 1) {
584 // mono -> pseudo stereo
585 if(*params[param_listen] > 0.f)
586 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
587 else
588 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
589 outs[0][offset] = out[0];
590 out[1] = out[0];
591 outs[1][offset] = out[1];
592 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
593 } else {
594 // stereo -> mono
595 // or full mono
596 if(*params[param_listen] > 0.f)
597 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
598 else
599 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
600 outs[0][offset] = out[0];
601 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
604 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive};
605 meters.process(values);
606 // next sample
607 ++offset;
608 } // cycle trough samples
609 // clean up
610 lp[0][0].sanitize();
611 lp[1][0].sanitize();
612 lp[0][1].sanitize();
613 lp[1][1].sanitize();
614 lp[0][2].sanitize();
615 lp[1][2].sanitize();
616 lp[0][3].sanitize();
617 lp[1][3].sanitize();
618 hp[0][0].sanitize();
619 hp[1][0].sanitize();
620 hp[0][1].sanitize();
621 hp[1][1].sanitize();
623 meters.fall(numsamples);
624 return outputs_mask;
627 /**********************************************************************
628 * TAPESIMULATOR by Markus Schmidt
629 **********************************************************************/
631 tapesimulator_audio_module::tapesimulator_audio_module() {
632 active = false;
633 clip_inL = 0.f;
634 clip_inR = 0.f;
635 clip_outL = 0.f;
636 clip_outR = 0.f;
637 meter_inL = 0.f;
638 meter_inR = 0.f;
639 meter_outL = 0.f;
640 meter_outR = 0.f;
641 lp_old = -1.f;
642 rms = 0.f;
643 mech_old = false;
644 transients.set_channels(channels);
647 void tapesimulator_audio_module::activate() {
648 active = true;
651 void tapesimulator_audio_module::deactivate() {
652 active = false;
655 void tapesimulator_audio_module::params_changed() {
656 if(*params[param_lp] != lp_old or *params[param_mechanical] != mech_old) {
657 lp[0][0].set_lp_rbj(*params[param_lp], 0.707, (float)srate);
658 lp[0][1].copy_coeffs(lp[0][0]);
659 lp[1][0].copy_coeffs(lp[0][0]);
660 lp[1][1].copy_coeffs(lp[0][0]);
661 lp_old = *params[param_lp];
662 mech_old = *params[param_mechanical] > 0.5;
664 transients.set_params(50.f / (*params[param_speed] + 1),
665 -0.05f / (*params[param_speed] + 1),
666 100.f,
667 0.f,
668 1.f,
671 lfo1.set_params((*params[param_speed] + 1) / 2, 0, 0.f, srate, 1.f);
672 lfo2.set_params((*params[param_speed] + 1) / 9.38, 0, 0.f, srate, 1.f);
675 uint32_t tapesimulator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
676 for(uint32_t i = offset; i < offset + numsamples; i++) {
677 float L = ins[0][i];
678 float R = ins[1][i];
679 float Lin = ins[0][i];
680 float Rin = ins[1][i];
681 if(*params[param_bypass] > 0.5) {
682 outs[0][i] = ins[0][i];
683 outs[1][i] = ins[1][i];
684 clip_inL = 0.f;
685 clip_inR = 0.f;
686 clip_outL = 0.f;
687 clip_outR = 0.f;
688 meter_inL = 0.f;
689 meter_inR = 0.f;
690 meter_outL = 0.f;
691 meter_outR = 0.f;
692 } else {
693 // let meters fall a bit
694 clip_inL -= std::min(clip_inL, numsamples);
695 clip_inR -= std::min(clip_inR, numsamples);
696 clip_outL -= std::min(clip_outL, numsamples);
697 clip_outR -= std::min(clip_outR, numsamples);
698 meter_inL = 0.f;
699 meter_inR = 0.f;
700 meter_outL = 0.f;
701 meter_outR = 0.f;
703 // GUI stuff
704 if(L > meter_inL) meter_inL = L;
705 if(R > meter_inR) meter_inR = R;
706 if(L > 1.f) clip_inL = srate >> 3;
707 if(R > 1.f) clip_inR = srate >> 3;
709 // transients
710 if(*params[param_magnetical] > 0.5f) {
711 float values[] = {L, R};
712 transients.process(values);
713 L = values[0];
714 R = values[1];
717 // noise
718 if (*params[param_noise]) {
719 float Lnoise = rand() % 2 - 1;
720 float Rnoise = rand() % 2 - 1;
721 Lnoise = noisefilters[0][2].process(noisefilters[0][1].process(noisefilters[0][0].process(Lnoise)));
722 Rnoise = noisefilters[1][2].process(noisefilters[1][1].process(noisefilters[1][0].process(Rnoise)));
723 L += Lnoise * *params[param_noise] / 12.f;
724 R += Rnoise * *params[param_noise] / 12.f;
727 // lfo filters / phasing
728 if (*params[param_mechanical]) {
729 // filtering
730 float freqL1 = *params[param_lp] * (1 - ((lfo1.get_value() + 1) * 0.3 * *params[param_mechanical]));
731 float freqL2 = *params[param_lp] * (1 - ((lfo2.get_value() + 1) * 0.2 * *params[param_mechanical]));
733 float freqR1 = *params[param_lp] * (1 - ((lfo1.get_value() * -1 + 1) * 0.3 * *params[param_mechanical]));
734 float freqR2 = *params[param_lp] * (1 - ((lfo2.get_value() * -1 + 1) * 0.2 * *params[param_mechanical]));
736 lp[0][0].set_lp_rbj(freqL1, 0.707, (float)srate);
737 lp[0][1].set_lp_rbj(freqL2, 0.707, (float)srate);
739 lp[1][0].set_lp_rbj(freqR1, 0.707, (float)srate);
740 lp[1][1].set_lp_rbj(freqR2, 0.707, (float)srate);
742 // phasing
743 float _phase = lfo1.get_value() * *params[param_mechanical] * -36;
745 float _phase_cos_coef = cos(_phase / 180 * M_PI);
746 float _phase_sin_coef = sin(_phase / 180 * M_PI);
748 float _l = L * _phase_cos_coef - R * _phase_sin_coef;
749 float _r = L * _phase_sin_coef + R * _phase_cos_coef;
750 L = _l;
751 R = _r;
754 // gain
755 L *= *params[param_level_in];
756 R *= *params[param_level_in];
758 // save for drawing input/output curve
759 float Lc = L;
760 float Rc = R;
761 float Lo = L;
762 float Ro = R;
764 // filter
765 if (*params[param_post] < 0.5) {
766 L = lp[0][1].process(lp[0][0].process(L));
767 R = lp[1][1].process(lp[1][0].process(R));
770 // distortion
771 if (L) L = L / fabs(L) * (1 - exp((-1) * 3 * fabs(L)));
772 if (R) R = R / fabs(R) * (1 - exp((-1) * 3 * fabs(R)));
774 if (Lo) Lo = Lo / fabs(Lo) * (1 - exp((-1) * 3 * fabs(Lo)));
775 if (Ro) Ro = Ro / fabs(Ro) * (1 - exp((-1) * 3 * fabs(Ro)));
777 // filter
778 if (*params[param_post] >= 0.5) {
779 L = lp[0][1].process(lp[0][0].process(L));
780 R = lp[1][1].process(lp[1][0].process(R));
783 // mix
784 L = L * *params[param_mix] + Lin * (*params[param_mix] * -1 + 1);
785 R = R * *params[param_mix] + Rin * (*params[param_mix] * -1 + 1);
787 // levels out
788 L *= *params[param_level_out];
789 R *= *params[param_level_out];
791 // output
792 outs[0][i] = L;
793 outs[1][i] = R;
795 // clip LED's
796 if(L > 1.f) clip_outL = srate >> 3;
797 if(R > 1.f) clip_outR = srate >> 3;
798 if(L > meter_outL) meter_outL = L;
799 if(R > meter_outR) meter_outR = R;
801 // sanitize filters
802 lp[0][0].sanitize();
803 lp[1][0].sanitize();
804 lp[0][1].sanitize();
805 lp[1][1].sanitize();
807 // LFO's should go on
808 lfo1.advance(1);
809 lfo2.advance(1);
811 float s = (fabs(Lo) + fabs(Ro)) / 2;
812 if (s > rms) {
813 rms = s;
815 float in = (fabs(Lc) + fabs(Rc)) / 2;
816 if (in > input) {
817 input = in;
821 // draw meters
822 SET_IF_CONNECTED(clip_inL);
823 SET_IF_CONNECTED(clip_inR);
824 SET_IF_CONNECTED(clip_outL);
825 SET_IF_CONNECTED(clip_outR);
826 SET_IF_CONNECTED(meter_inL);
827 SET_IF_CONNECTED(meter_inR);
828 SET_IF_CONNECTED(meter_outL);
829 SET_IF_CONNECTED(meter_outR);
830 return outputs_mask;
833 void tapesimulator_audio_module::set_sample_rate(uint32_t sr)
835 srate = sr;
836 transients.set_sample_rate(srate);
837 noisefilters[0][0].set_hp_rbj(120.f, 0.707, (float)srate);
838 noisefilters[1][0].copy_coeffs(noisefilters[0][0]);
839 noisefilters[0][1].set_lp_rbj(5500.f, 0.707, (float)srate);
840 noisefilters[1][1].copy_coeffs(noisefilters[0][1]);
841 noisefilters[0][2].set_highshelf_rbj(1000.f, 0.707, 0.5, (float)srate);
842 noisefilters[1][2].copy_coeffs(noisefilters[0][2]);
845 bool tapesimulator_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
847 if (subindex > 1)
848 return false;
849 if(index == param_lp and phase) {
850 set_channel_color(context, subindex);
851 return ::get_graph(*this, subindex, data, points);
852 } else if (index == param_level_in and !phase) {
853 if (!subindex) {
854 context->set_source_rgba(0.15, 0.2, 0.0, 0.3);
855 context->set_line_width(1);
857 for (int i = 0; i < points; i++) {
858 if (!subindex) {
859 float input = dB_grid_inv(-1.0 + (float)i * 2.0 / ((float)points - 1.f));
860 data[i] = dB_grid(input);
861 } else {
862 float output = 1 - exp(-3 * (pow(2, -10 + 14 * (float)i / (float) points)));
863 data[i] = dB_grid(output * *params[param_level_out]);
866 return true;
868 return false;
870 float tapesimulator_audio_module::freq_gain(int index, double freq) const
872 return lp[index][0].freq_gain(freq, srate) * lp[index][1].freq_gain(freq, srate);
875 bool tapesimulator_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
877 if(!active or phase)
878 return false;
879 if (index == param_level_in) {
880 bool tmp;
881 vertical = (subindex & 1) != 0;
882 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
883 if (result && vertical) {
884 if ((subindex & 4) && !legend.empty()) {
885 legend = "";
887 else {
888 size_t pos = legend.find(" dB");
889 if (pos != std::string::npos)
890 legend.erase(pos);
892 pos = 0.5 + 0.5 * pos;
894 return result;
895 } else if (index == param_lp) {
896 return get_freq_gridline(subindex, pos, vertical, legend, context);
898 return false;
900 bool tapesimulator_audio_module::get_dot(int index, int subindex, int phase, float &x, float &y, int &size, cairo_iface *context) const
902 if (index == param_level_in and !subindex and phase) {
903 x = log(input) / log(2) / 14.f + 5.f / 7.f;
904 y = dB_grid(rms);
905 rms = 0.f;
906 input = 0.f;
907 return true;
909 return false;
911 bool tapesimulator_audio_module::get_layers(int index, int generation, unsigned int &layers) const
913 layers = 0;
914 // always draw grid on cache if surfaces are new on both widgets
915 if (!generation)
916 layers |= LG_CACHE_GRID;
917 // compression: dot in realtime, graphs as cache on new surfaces
918 if (index == param_level_in and !generation)
919 layers |= LG_CACHE_GRAPH;
920 if (index == param_level_in)
921 layers |= LG_REALTIME_DOT;
922 // frequency: both graphs in realtime
923 if (index == param_lp)
924 layers |= LG_REALTIME_GRAPH;
925 // draw always
926 return true;
931 /**********************************************************************
932 * CRUSHER by Markus Schmidt and Christian Holschuh
933 **********************************************************************/
936 crusher_audio_module::crusher_audio_module()
938 smin = sdiff = 0.f;
941 void crusher_audio_module::activate()
943 lfo.activate();
945 void crusher_audio_module::deactivate()
947 lfo.deactivate();
950 void crusher_audio_module::params_changed()
952 bitreduction.set_params(*params[param_bits],
953 *params[param_morph],
954 *params[param_bypass] > 0.5,
955 *params[param_mode],
956 *params[param_dc],
957 *params[param_aa]);
958 samplereduction[0].set_params(*params[param_samples]);
959 samplereduction[1].set_params(*params[param_samples]);
960 lfo.set_params(*params[param_lforate], 0, 0.f, srate, 0.5f);
961 // calc lfo offsets
962 float rad = *params[param_lforange] / 2.f;
963 smin = std::max(*params[param_samples] - rad, 1.f);
964 float sun = *params[param_samples] - rad - smin;
965 float smax = std::min(*params[param_samples] + rad, 250.f);
966 float sov = *params[param_samples] + rad - smax;
967 smax -= sun;
968 smin -= sov;
969 sdiff = smax - smin;
972 void crusher_audio_module::set_sample_rate(uint32_t sr)
974 srate = sr;
975 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
976 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
977 meters.init(params, meter, clip, 4, srate);
978 bitreduction.set_sample_rate(srate);
981 uint32_t crusher_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
983 bool bypass = *params[param_bypass] > 0.5f;
984 numsamples += offset;
985 if(bypass) {
986 // everything bypassed
987 while(offset < numsamples) {
988 outs[0][offset] = ins[0][offset];
989 outs[1][offset] = ins[1][offset];
990 float values[] = {0, 0, 0, 0};
991 meters.process(values);
992 ++offset;
994 } else {
995 // process
996 while(offset < numsamples) {
997 // cycle through samples
998 if (*params[param_lfo] > 0.5) {
999 samplereduction[0].set_params(smin + sdiff * (lfo.get_value() + 0.5));
1000 samplereduction[1].set_params(smin + sdiff * (lfo.get_value() + 0.5));
1002 outs[0][offset] = samplereduction[0].process(ins[0][offset] * *params[param_level_in]);
1003 outs[1][offset] = samplereduction[1].process(ins[1][offset] * *params[param_level_in]);
1004 outs[0][offset] = outs[0][offset] * *params[param_morph] + ins[0][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
1005 outs[1][offset] = outs[1][offset] * *params[param_morph] + ins[1][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
1006 outs[0][offset] = bitreduction.process(outs[0][offset]) * *params[param_level_out];
1007 outs[1][offset] = bitreduction.process(outs[1][offset]) * *params[param_level_out];
1008 float values[] = {ins[0][offset], ins[1][offset], outs[0][offset], outs[1][offset]};
1009 meters.process(values);
1010 // next sample
1011 ++offset;
1012 if (*params[param_lforate])
1013 lfo.advance(1);
1014 } // cycle trough samples
1016 meters.fall(numsamples);
1017 return outputs_mask;
1019 bool crusher_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
1021 return bitreduction.get_graph(subindex, phase, data, points, context, mode);
1023 bool crusher_audio_module::get_layers(int index, int generation, unsigned int &layers) const
1025 return bitreduction.get_layers(index, generation, layers);
1027 bool crusher_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
1029 return bitreduction.get_gridline(subindex, phase, pos, vertical, legend, context);