Saturator: example use of seamless bypass
[calf.git] / src / modules_dist.cpp
blob0d3feb356e5ecd45ff31469e85b233c64c42b2bc
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 bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
128 numsamples += offset;
129 if(bypassed) {
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 uint32_t orig_offset = offset;
149 // process
150 while(offset < numsamples) {
151 // cycle through samples
152 float out[2], in[2] = {0.f, 0.f};
153 int c = 0;
154 float maxDrive = 0.f;
155 if(in_count > 1 && out_count > 1) {
156 // stereo in/stereo out
157 // handle full stereo
158 in[0] = ins[0][offset];
159 in[1] = ins[1][offset];
160 c = 2;
161 } else {
162 // in and/or out mono
163 // handle mono
164 in[0] = ins[0][offset];
165 in[1] = in[0];
166 c = 1;
169 float proc[2];
170 proc[0] = in[0] * *params[param_level_in];
171 proc[1] = in[1] * *params[param_level_in];
173 float onedivlevelin = 1.0 / *params[param_level_in];
175 for (int i = 0; i < c; ++i) {
176 // all pre filters in chain
177 proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
178 proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
180 // ...saturate...
181 proc[i] = dist[i].process(proc[i]);
183 // tone control
184 proc[i] = p[i].process(proc[i]);
186 // all post filters in chain
187 proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
188 proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
190 //subtract gain
191 proc[i] *= onedivlevelin;
193 if (*params[param_level_in] > 1)
194 proc[i] *= 1 + (*params[param_level_in] - 1) / 32;
197 maxDrive = dist[0].get_distortion_level() * *params[param_blend];
199 if(in_count > 1 && out_count > 1) {
200 maxDrive = dist[1].get_distortion_level() * *params[param_blend];
201 // full stereo
202 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
203 outs[0][offset] = out[0];
204 out[1] = ((proc[1] * *params[param_mix]) + in[1] * (1 - *params[param_mix])) * *params[param_level_out];
205 outs[1][offset] = out[1];
206 } else if(out_count > 1) {
207 // mono -> pseudo stereo
208 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
209 outs[0][offset] = out[0];
210 out[1] = out[0];
211 outs[1][offset] = out[1];
212 } else {
213 // stereo -> mono
214 // or full mono
215 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
216 outs[0][offset] = out[0];
218 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive / 20};
219 meters.process(values);
221 // next sample
222 ++offset;
223 } // cycle trough samples
225 // clean up
226 lp[0][0].sanitize();
227 lp[1][0].sanitize();
228 lp[0][1].sanitize();
229 lp[1][1].sanitize();
230 lp[0][2].sanitize();
231 lp[1][2].sanitize();
232 lp[0][3].sanitize();
233 lp[1][3].sanitize();
234 hp[0][0].sanitize();
235 hp[1][0].sanitize();
236 hp[0][1].sanitize();
237 hp[1][1].sanitize();
238 hp[0][2].sanitize();
239 hp[1][2].sanitize();
240 hp[0][3].sanitize();
241 hp[1][3].sanitize();
242 p[0].sanitize();
243 p[1].sanitize();
244 bypass.crossfade(ins, outs, 2, orig_offset, numsamples);
246 meters.fall(numsamples);
247 return outputs_mask;
250 /**********************************************************************
251 * EXCITER by Markus Schmidt
252 **********************************************************************/
254 exciter_audio_module::exciter_audio_module()
256 freq_old = 0.f;
257 ceil_old = 0.f;
258 ceil_active_old = false;
259 meter_drive = 0.f;
260 is_active = false;
261 srate = 0;
264 void exciter_audio_module::activate()
266 is_active = true;
267 // set all filters
268 params_changed();
271 void exciter_audio_module::deactivate()
273 is_active = false;
276 void exciter_audio_module::params_changed()
278 // set the params of all filters
279 if(*params[param_freq] != freq_old) {
280 hp[0][0].set_hp_rbj(*params[param_freq], 0.707, (float)srate);
281 hp[0][1].copy_coeffs(hp[0][0]);
282 hp[0][2].copy_coeffs(hp[0][0]);
283 hp[0][3].copy_coeffs(hp[0][0]);
284 if(in_count > 1 && out_count > 1) {
285 hp[1][0].copy_coeffs(hp[0][0]);
286 hp[1][1].copy_coeffs(hp[0][0]);
287 hp[1][2].copy_coeffs(hp[0][0]);
288 hp[1][3].copy_coeffs(hp[0][0]);
290 freq_old = *params[param_freq];
292 // set the params of all filters
293 if(*params[param_ceil] != ceil_old or *params[param_ceil_active] != ceil_active_old) {
294 lp[0][0].set_lp_rbj(*params[param_ceil], 0.707, (float)srate);
295 lp[0][1].copy_coeffs(lp[0][0]);
296 lp[1][0].copy_coeffs(lp[0][0]);
297 lp[1][1].copy_coeffs(lp[0][0]);
298 ceil_old = *params[param_ceil];
299 ceil_active_old = *params[param_ceil_active];
301 // set distortion
302 dist[0].set_params(*params[param_blend], *params[param_drive]);
303 if(in_count > 1 && out_count > 1)
304 dist[1].set_params(*params[param_blend], *params[param_drive]);
307 void exciter_audio_module::set_sample_rate(uint32_t sr)
309 srate = sr;
310 dist[0].set_sample_rate(sr);
311 if(in_count > 1 && out_count > 1)
312 dist[1].set_sample_rate(sr);
313 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
314 int clip[] = {param_clip_in, param_clip_out, -1};
315 meters.init(params, meter, clip, 3, srate);
318 uint32_t exciter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
320 bool bypass = *params[param_bypass] > 0.5f;
321 numsamples += offset;
322 if(bypass) {
323 // everything bypassed
324 while(offset < numsamples) {
325 if(in_count > 1 && out_count > 1) {
326 outs[0][offset] = ins[0][offset];
327 outs[1][offset] = ins[1][offset];
328 } else if(in_count > 1) {
329 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
330 } else if(out_count > 1) {
331 outs[0][offset] = ins[0][offset];
332 outs[1][offset] = ins[0][offset];
333 } else {
334 outs[0][offset] = ins[0][offset];
336 float values[] = {0, 0, 0, 0, 0};
337 meters.process(values);
338 ++offset;
340 // displays, too
341 meter_drive = 0.f;
342 } else {
344 meter_drive = 0.f;
346 float in2out = *params[param_listen] > 0.f ? 0.f : 1.f;
348 // process
349 while(offset < numsamples) {
350 // cycle through samples
351 float out[2], in[2] = {0.f, 0.f};
352 float maxDrive = 0.f;
353 int c = 0;
355 if(in_count > 1 && out_count > 1) {
356 // stereo in/stereo out
357 // handle full stereo
358 in[0] = ins[0][offset];
359 in[0] *= *params[param_level_in];
360 in[1] = ins[1][offset];
361 in[1] *= *params[param_level_in];
362 c = 2;
363 } else {
364 // in and/or out mono
365 // handle mono
366 in[0] = ins[0][offset];
367 in[0] *= *params[param_level_in];
368 in[1] = in[0];
369 c = 1;
372 float proc[2];
373 proc[0] = in[0];
374 proc[1] = in[1];
376 for (int i = 0; i < c; ++i) {
377 // all pre filters in chain
378 proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
380 // saturate
381 proc[i] = dist[i].process(proc[i]);
383 // all post filters in chain
384 proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
386 if(*params[param_ceil_active] > 0.5f) {
387 // all H/P post filters in chain
388 proc[i] = lp[i][0].process(lp[i][1].process(proc[i]));
392 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
394 if(in_count > 1 && out_count > 1) {
395 maxDrive = std::max(maxDrive, dist[1].get_distortion_level() * *params[param_amount]);
396 // full stereo
397 out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
398 out[1] = (proc[1] * *params[param_amount] + in2out * in[1]) * *params[param_level_out];
399 outs[0][offset] = out[0];
400 outs[1][offset] = out[1];
401 } else if(out_count > 1) {
402 // mono -> pseudo stereo
403 out[1] = out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
404 outs[0][offset] = out[0];
405 outs[1][offset] = out[1];
406 } else {
407 // stereo -> mono
408 // or full mono
409 out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
410 outs[0][offset] = out[0];
412 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive};
413 meters.process(values);
414 // next sample
415 ++offset;
416 } // cycle trough samples
417 // clean up
418 hp[0][0].sanitize();
419 hp[1][0].sanitize();
420 hp[0][1].sanitize();
421 hp[1][1].sanitize();
422 hp[0][2].sanitize();
423 hp[1][2].sanitize();
424 hp[0][3].sanitize();
425 hp[1][3].sanitize();
427 lp[0][0].sanitize();
428 lp[1][0].sanitize();
429 lp[0][1].sanitize();
430 lp[1][1].sanitize();
432 meters.fall(numsamples);
433 return outputs_mask;
436 /**********************************************************************
437 * BASS ENHANCER by Markus Schmidt
438 **********************************************************************/
440 bassenhancer_audio_module::bassenhancer_audio_module()
442 freq_old = 0.f;
443 floor_old = 0.f;
444 floor_active_old = false;
445 meter_drive = 0.f;
446 is_active = false;
447 srate = 0;
450 void bassenhancer_audio_module::activate()
452 is_active = true;
453 // set all filters
454 params_changed();
456 void bassenhancer_audio_module::deactivate()
458 is_active = false;
461 void bassenhancer_audio_module::params_changed()
463 // set the params of all filters
464 if(*params[param_freq] != freq_old) {
465 lp[0][0].set_lp_rbj(*params[param_freq], 0.707, (float)srate);
466 lp[0][1].copy_coeffs(lp[0][0]);
467 lp[0][2].copy_coeffs(lp[0][0]);
468 lp[0][3].copy_coeffs(lp[0][0]);
469 if(in_count > 1 && out_count > 1) {
470 lp[1][0].copy_coeffs(lp[0][0]);
471 lp[1][1].copy_coeffs(lp[0][0]);
472 lp[1][2].copy_coeffs(lp[0][0]);
473 lp[1][3].copy_coeffs(lp[0][0]);
475 freq_old = *params[param_freq];
477 // set the params of all filters
478 if(*params[param_floor] != floor_old or *params[param_floor_active] != floor_active_old) {
479 hp[0][0].set_hp_rbj(*params[param_floor], 0.707, (float)srate);
480 hp[0][1].copy_coeffs(hp[0][0]);
481 hp[1][0].copy_coeffs(hp[0][0]);
482 hp[1][1].copy_coeffs(hp[0][0]);
483 floor_old = *params[param_floor];
484 floor_active_old = *params[param_floor_active];
486 // set distortion
487 dist[0].set_params(*params[param_blend], *params[param_drive]);
488 if(in_count > 1 && out_count > 1)
489 dist[1].set_params(*params[param_blend], *params[param_drive]);
492 void bassenhancer_audio_module::set_sample_rate(uint32_t sr)
494 srate = sr;
495 dist[0].set_sample_rate(sr);
496 if(in_count > 1 && out_count > 1)
497 dist[1].set_sample_rate(sr);
498 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
499 int clip[] = {param_clip_in, param_clip_out, -1};
500 meters.init(params, meter, clip, 3, srate);
503 uint32_t bassenhancer_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
505 bool bypass = *params[param_bypass] > 0.5f;
506 numsamples += offset;
507 if(bypass) {
508 // everything bypassed
509 while(offset < numsamples) {
510 if(in_count > 1 && out_count > 1) {
511 outs[0][offset] = ins[0][offset];
512 outs[1][offset] = ins[1][offset];
513 } else if(in_count > 1) {
514 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
515 } else if(out_count > 1) {
516 outs[0][offset] = ins[0][offset];
517 outs[1][offset] = ins[0][offset];
518 } else {
519 outs[0][offset] = ins[0][offset];
521 float values[] = {0, 0, 0};
522 meters.process(values);
523 ++offset;
525 } else {
526 // process
527 while(offset < numsamples) {
528 // cycle through samples
529 float out[2], in[2] = {0.f, 0.f};
530 float maxDrive = 0.f;
531 int c = 0;
533 if(in_count > 1 && out_count > 1) {
534 // stereo in/stereo out
535 // handle full stereo
536 in[0] = ins[0][offset];
537 in[0] *= *params[param_level_in];
538 in[1] = ins[1][offset];
539 in[1] *= *params[param_level_in];
540 c = 2;
541 } else {
542 // in and/or out mono
543 // handle mono
544 in[0] = ins[0][offset];
545 in[0] *= *params[param_level_in];
546 in[1] = in[0];
547 c = 1;
550 float proc[2];
551 proc[0] = in[0];
552 proc[1] = in[1];
554 for (int i = 0; i < c; ++i) {
555 // all pre filters in chain
556 proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
558 // saturate
559 proc[i] = dist[i].process(proc[i]);
561 // all post filters in chain
562 proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
564 if(*params[param_floor_active] > 0.5f) {
565 // all H/P post filters in chain
566 proc[i] = hp[i][0].process(hp[i][1].process(proc[i]));
571 if(in_count > 1 && out_count > 1) {
572 // full stereo
573 if(*params[param_listen] > 0.f)
574 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
575 else
576 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
577 outs[0][offset] = out[0];
578 if(*params[param_listen] > 0.f)
579 out[1] = proc[1] * *params[param_amount] * *params[param_level_out];
580 else
581 out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out];
582 outs[1][offset] = out[1];
583 maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount],
584 dist[1].get_distortion_level() * *params[param_amount]);
585 } else if(out_count > 1) {
586 // mono -> pseudo stereo
587 if(*params[param_listen] > 0.f)
588 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
589 else
590 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
591 outs[0][offset] = out[0];
592 out[1] = out[0];
593 outs[1][offset] = out[1];
594 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
595 } else {
596 // stereo -> mono
597 // or full mono
598 if(*params[param_listen] > 0.f)
599 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
600 else
601 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
602 outs[0][offset] = out[0];
603 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
606 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive};
607 meters.process(values);
608 // next sample
609 ++offset;
610 } // cycle trough samples
611 // clean up
612 lp[0][0].sanitize();
613 lp[1][0].sanitize();
614 lp[0][1].sanitize();
615 lp[1][1].sanitize();
616 lp[0][2].sanitize();
617 lp[1][2].sanitize();
618 lp[0][3].sanitize();
619 lp[1][3].sanitize();
620 hp[0][0].sanitize();
621 hp[1][0].sanitize();
622 hp[0][1].sanitize();
623 hp[1][1].sanitize();
625 meters.fall(numsamples);
626 return outputs_mask;
629 /**********************************************************************
630 * TAPESIMULATOR by Markus Schmidt
631 **********************************************************************/
633 tapesimulator_audio_module::tapesimulator_audio_module() {
634 active = false;
635 clip_inL = 0.f;
636 clip_inR = 0.f;
637 clip_outL = 0.f;
638 clip_outR = 0.f;
639 meter_inL = 0.f;
640 meter_inR = 0.f;
641 meter_outL = 0.f;
642 meter_outR = 0.f;
643 lp_old = -1.f;
644 rms = 0.f;
645 mech_old = false;
646 transients.set_channels(channels);
649 void tapesimulator_audio_module::activate() {
650 active = true;
653 void tapesimulator_audio_module::deactivate() {
654 active = false;
657 void tapesimulator_audio_module::params_changed() {
658 if(*params[param_lp] != lp_old or *params[param_mechanical] != mech_old) {
659 lp[0][0].set_lp_rbj(*params[param_lp], 0.707, (float)srate);
660 lp[0][1].copy_coeffs(lp[0][0]);
661 lp[1][0].copy_coeffs(lp[0][0]);
662 lp[1][1].copy_coeffs(lp[0][0]);
663 lp_old = *params[param_lp];
664 mech_old = *params[param_mechanical] > 0.5;
666 transients.set_params(50.f / (*params[param_speed] + 1),
667 -0.05f / (*params[param_speed] + 1),
668 100.f,
669 0.f,
670 1.f,
673 lfo1.set_params((*params[param_speed] + 1) / 2, 0, 0.f, srate, 1.f);
674 lfo2.set_params((*params[param_speed] + 1) / 9.38, 0, 0.f, srate, 1.f);
677 uint32_t tapesimulator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
678 for(uint32_t i = offset; i < offset + numsamples; i++) {
679 float L = ins[0][i];
680 float R = ins[1][i];
681 float Lin = ins[0][i];
682 float Rin = ins[1][i];
683 if(*params[param_bypass] > 0.5) {
684 outs[0][i] = ins[0][i];
685 outs[1][i] = ins[1][i];
686 clip_inL = 0.f;
687 clip_inR = 0.f;
688 clip_outL = 0.f;
689 clip_outR = 0.f;
690 meter_inL = 0.f;
691 meter_inR = 0.f;
692 meter_outL = 0.f;
693 meter_outR = 0.f;
694 } else {
695 // let meters fall a bit
696 clip_inL -= std::min(clip_inL, numsamples);
697 clip_inR -= std::min(clip_inR, numsamples);
698 clip_outL -= std::min(clip_outL, numsamples);
699 clip_outR -= std::min(clip_outR, numsamples);
700 meter_inL = 0.f;
701 meter_inR = 0.f;
702 meter_outL = 0.f;
703 meter_outR = 0.f;
705 // GUI stuff
706 if(L > meter_inL) meter_inL = L;
707 if(R > meter_inR) meter_inR = R;
708 if(L > 1.f) clip_inL = srate >> 3;
709 if(R > 1.f) clip_inR = srate >> 3;
711 // transients
712 if(*params[param_magnetical] > 0.5f) {
713 float values[] = {L, R};
714 transients.process(values);
715 L = values[0];
716 R = values[1];
719 // noise
720 if (*params[param_noise]) {
721 float Lnoise = rand() % 2 - 1;
722 float Rnoise = rand() % 2 - 1;
723 Lnoise = noisefilters[0][2].process(noisefilters[0][1].process(noisefilters[0][0].process(Lnoise)));
724 Rnoise = noisefilters[1][2].process(noisefilters[1][1].process(noisefilters[1][0].process(Rnoise)));
725 L += Lnoise * *params[param_noise] / 12.f;
726 R += Rnoise * *params[param_noise] / 12.f;
729 // lfo filters / phasing
730 if (*params[param_mechanical]) {
731 // filtering
732 float freqL1 = *params[param_lp] * (1 - ((lfo1.get_value() + 1) * 0.3 * *params[param_mechanical]));
733 float freqL2 = *params[param_lp] * (1 - ((lfo2.get_value() + 1) * 0.2 * *params[param_mechanical]));
735 float freqR1 = *params[param_lp] * (1 - ((lfo1.get_value() * -1 + 1) * 0.3 * *params[param_mechanical]));
736 float freqR2 = *params[param_lp] * (1 - ((lfo2.get_value() * -1 + 1) * 0.2 * *params[param_mechanical]));
738 lp[0][0].set_lp_rbj(freqL1, 0.707, (float)srate);
739 lp[0][1].set_lp_rbj(freqL2, 0.707, (float)srate);
741 lp[1][0].set_lp_rbj(freqR1, 0.707, (float)srate);
742 lp[1][1].set_lp_rbj(freqR2, 0.707, (float)srate);
744 // phasing
745 float _phase = lfo1.get_value() * *params[param_mechanical] * -36;
747 float _phase_cos_coef = cos(_phase / 180 * M_PI);
748 float _phase_sin_coef = sin(_phase / 180 * M_PI);
750 float _l = L * _phase_cos_coef - R * _phase_sin_coef;
751 float _r = L * _phase_sin_coef + R * _phase_cos_coef;
752 L = _l;
753 R = _r;
756 // gain
757 L *= *params[param_level_in];
758 R *= *params[param_level_in];
760 // save for drawing input/output curve
761 float Lc = L;
762 float Rc = R;
763 float Lo = L;
764 float Ro = R;
766 // filter
767 if (*params[param_post] < 0.5) {
768 L = lp[0][1].process(lp[0][0].process(L));
769 R = lp[1][1].process(lp[1][0].process(R));
772 // distortion
773 if (L) L = L / fabs(L) * (1 - exp((-1) * 3 * fabs(L)));
774 if (R) R = R / fabs(R) * (1 - exp((-1) * 3 * fabs(R)));
776 if (Lo) Lo = Lo / fabs(Lo) * (1 - exp((-1) * 3 * fabs(Lo)));
777 if (Ro) Ro = Ro / fabs(Ro) * (1 - exp((-1) * 3 * fabs(Ro)));
779 // filter
780 if (*params[param_post] >= 0.5) {
781 L = lp[0][1].process(lp[0][0].process(L));
782 R = lp[1][1].process(lp[1][0].process(R));
785 // mix
786 L = L * *params[param_mix] + Lin * (*params[param_mix] * -1 + 1);
787 R = R * *params[param_mix] + Rin * (*params[param_mix] * -1 + 1);
789 // levels out
790 L *= *params[param_level_out];
791 R *= *params[param_level_out];
793 // output
794 outs[0][i] = L;
795 outs[1][i] = R;
797 // clip LED's
798 if(L > 1.f) clip_outL = srate >> 3;
799 if(R > 1.f) clip_outR = srate >> 3;
800 if(L > meter_outL) meter_outL = L;
801 if(R > meter_outR) meter_outR = R;
803 // sanitize filters
804 lp[0][0].sanitize();
805 lp[1][0].sanitize();
806 lp[0][1].sanitize();
807 lp[1][1].sanitize();
809 // LFO's should go on
810 lfo1.advance(1);
811 lfo2.advance(1);
813 float s = (fabs(Lo) + fabs(Ro)) / 2;
814 if (s > rms) {
815 rms = s;
817 float in = (fabs(Lc) + fabs(Rc)) / 2;
818 if (in > input) {
819 input = in;
823 // draw meters
824 SET_IF_CONNECTED(clip_inL);
825 SET_IF_CONNECTED(clip_inR);
826 SET_IF_CONNECTED(clip_outL);
827 SET_IF_CONNECTED(clip_outR);
828 SET_IF_CONNECTED(meter_inL);
829 SET_IF_CONNECTED(meter_inR);
830 SET_IF_CONNECTED(meter_outL);
831 SET_IF_CONNECTED(meter_outR);
832 return outputs_mask;
835 void tapesimulator_audio_module::set_sample_rate(uint32_t sr)
837 srate = sr;
838 transients.set_sample_rate(srate);
839 noisefilters[0][0].set_hp_rbj(120.f, 0.707, (float)srate);
840 noisefilters[1][0].copy_coeffs(noisefilters[0][0]);
841 noisefilters[0][1].set_lp_rbj(5500.f, 0.707, (float)srate);
842 noisefilters[1][1].copy_coeffs(noisefilters[0][1]);
843 noisefilters[0][2].set_highshelf_rbj(1000.f, 0.707, 0.5, (float)srate);
844 noisefilters[1][2].copy_coeffs(noisefilters[0][2]);
847 bool tapesimulator_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
849 if (subindex > 1)
850 return false;
851 if(index == param_lp and phase) {
852 set_channel_color(context, subindex);
853 return ::get_graph(*this, subindex, data, points);
854 } else if (index == param_level_in and !phase) {
855 if (!subindex) {
856 context->set_source_rgba(0.15, 0.2, 0.0, 0.3);
857 context->set_line_width(1);
859 for (int i = 0; i < points; i++) {
860 if (!subindex) {
861 float input = dB_grid_inv(-1.0 + (float)i * 2.0 / ((float)points - 1.f));
862 data[i] = dB_grid(input);
863 } else {
864 float output = 1 - exp(-3 * (pow(2, -10 + 14 * (float)i / (float) points)));
865 data[i] = dB_grid(output * *params[param_level_out]);
868 return true;
870 return false;
872 float tapesimulator_audio_module::freq_gain(int index, double freq) const
874 return lp[index][0].freq_gain(freq, srate) * lp[index][1].freq_gain(freq, srate);
877 bool tapesimulator_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
879 if(!active or phase)
880 return false;
881 if (index == param_level_in) {
882 bool tmp;
883 vertical = (subindex & 1) != 0;
884 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
885 if (result && vertical) {
886 if ((subindex & 4) && !legend.empty()) {
887 legend = "";
889 else {
890 size_t pos = legend.find(" dB");
891 if (pos != std::string::npos)
892 legend.erase(pos);
894 pos = 0.5 + 0.5 * pos;
896 return result;
897 } else if (index == param_lp) {
898 return get_freq_gridline(subindex, pos, vertical, legend, context);
900 return false;
902 bool tapesimulator_audio_module::get_dot(int index, int subindex, int phase, float &x, float &y, int &size, cairo_iface *context) const
904 if (index == param_level_in and !subindex and phase) {
905 x = log(input) / log(2) / 14.f + 5.f / 7.f;
906 y = dB_grid(rms);
907 rms = 0.f;
908 input = 0.f;
909 return true;
911 return false;
913 bool tapesimulator_audio_module::get_layers(int index, int generation, unsigned int &layers) const
915 layers = 0;
916 // always draw grid on cache if surfaces are new on both widgets
917 if (!generation)
918 layers |= LG_CACHE_GRID;
919 // compression: dot in realtime, graphs as cache on new surfaces
920 if (index == param_level_in and !generation)
921 layers |= LG_CACHE_GRAPH;
922 if (index == param_level_in)
923 layers |= LG_REALTIME_DOT;
924 // frequency: both graphs in realtime
925 if (index == param_lp)
926 layers |= LG_REALTIME_GRAPH;
927 // draw always
928 return true;
933 /**********************************************************************
934 * CRUSHER by Markus Schmidt and Christian Holschuh
935 **********************************************************************/
938 crusher_audio_module::crusher_audio_module()
940 smin = sdiff = 0.f;
943 void crusher_audio_module::activate()
945 lfo.activate();
947 void crusher_audio_module::deactivate()
949 lfo.deactivate();
952 void crusher_audio_module::params_changed()
954 bitreduction.set_params(*params[param_bits],
955 *params[param_morph],
956 *params[param_bypass] > 0.5,
957 *params[param_mode],
958 *params[param_dc],
959 *params[param_aa]);
960 samplereduction[0].set_params(*params[param_samples]);
961 samplereduction[1].set_params(*params[param_samples]);
962 lfo.set_params(*params[param_lforate], 0, 0.f, srate, 0.5f);
963 // calc lfo offsets
964 float rad = *params[param_lforange] / 2.f;
965 smin = std::max(*params[param_samples] - rad, 1.f);
966 float sun = *params[param_samples] - rad - smin;
967 float smax = std::min(*params[param_samples] + rad, 250.f);
968 float sov = *params[param_samples] + rad - smax;
969 smax -= sun;
970 smin -= sov;
971 sdiff = smax - smin;
974 void crusher_audio_module::set_sample_rate(uint32_t sr)
976 srate = sr;
977 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
978 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
979 meters.init(params, meter, clip, 4, srate);
980 bitreduction.set_sample_rate(srate);
983 uint32_t crusher_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
985 bool bypass = *params[param_bypass] > 0.5f;
986 numsamples += offset;
987 if(bypass) {
988 // everything bypassed
989 while(offset < numsamples) {
990 outs[0][offset] = ins[0][offset];
991 outs[1][offset] = ins[1][offset];
992 float values[] = {0, 0, 0, 0};
993 meters.process(values);
994 ++offset;
996 } else {
997 // process
998 while(offset < numsamples) {
999 // cycle through samples
1000 if (*params[param_lfo] > 0.5) {
1001 samplereduction[0].set_params(smin + sdiff * (lfo.get_value() + 0.5));
1002 samplereduction[1].set_params(smin + sdiff * (lfo.get_value() + 0.5));
1004 outs[0][offset] = samplereduction[0].process(ins[0][offset] * *params[param_level_in]);
1005 outs[1][offset] = samplereduction[1].process(ins[1][offset] * *params[param_level_in]);
1006 outs[0][offset] = outs[0][offset] * *params[param_morph] + ins[0][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
1007 outs[1][offset] = outs[1][offset] * *params[param_morph] + ins[1][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
1008 outs[0][offset] = bitreduction.process(outs[0][offset]) * *params[param_level_out];
1009 outs[1][offset] = bitreduction.process(outs[1][offset]) * *params[param_level_out];
1010 float values[] = {ins[0][offset], ins[1][offset], outs[0][offset], outs[1][offset]};
1011 meters.process(values);
1012 // next sample
1013 ++offset;
1014 if (*params[param_lforate])
1015 lfo.advance(1);
1016 } // cycle trough samples
1018 meters.fall(numsamples);
1019 return outputs_mask;
1021 bool crusher_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
1023 return bitreduction.get_graph(subindex, phase, data, points, context, mode);
1025 bool crusher_audio_module::get_layers(int index, int generation, unsigned int &layers) const
1027 return bitreduction.get_layers(index, generation, layers);
1029 bool crusher_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
1031 return bitreduction.get_gridline(subindex, phase, pos, vertical, legend, context);