Hass Enhancer: Cleanup, added enhanced metering, added seamless bypass
[calf.git] / src / modules_dist.cpp
blobd1dfac21834a0d6f38da81c1e1d79366c89b3a98
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 bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
321 numsamples += offset;
322 if(bypassed) {
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 {
343 uint32_t orig_offset = offset;
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 bypass.crossfade(ins, outs, 2, orig_offset, numsamples);
418 // clean up
419 hp[0][0].sanitize();
420 hp[1][0].sanitize();
421 hp[0][1].sanitize();
422 hp[1][1].sanitize();
423 hp[0][2].sanitize();
424 hp[1][2].sanitize();
425 hp[0][3].sanitize();
426 hp[1][3].sanitize();
428 lp[0][0].sanitize();
429 lp[1][0].sanitize();
430 lp[0][1].sanitize();
431 lp[1][1].sanitize();
433 meters.fall(numsamples);
434 return outputs_mask;
437 /**********************************************************************
438 * BASS ENHANCER by Markus Schmidt
439 **********************************************************************/
441 bassenhancer_audio_module::bassenhancer_audio_module()
443 freq_old = 0.f;
444 floor_old = 0.f;
445 floor_active_old = false;
446 meter_drive = 0.f;
447 is_active = false;
448 srate = 0;
451 void bassenhancer_audio_module::activate()
453 is_active = true;
454 // set all filters
455 params_changed();
457 void bassenhancer_audio_module::deactivate()
459 is_active = false;
462 void bassenhancer_audio_module::params_changed()
464 // set the params of all filters
465 if(*params[param_freq] != freq_old) {
466 lp[0][0].set_lp_rbj(*params[param_freq], 0.707, (float)srate);
467 lp[0][1].copy_coeffs(lp[0][0]);
468 lp[0][2].copy_coeffs(lp[0][0]);
469 lp[0][3].copy_coeffs(lp[0][0]);
470 if(in_count > 1 && out_count > 1) {
471 lp[1][0].copy_coeffs(lp[0][0]);
472 lp[1][1].copy_coeffs(lp[0][0]);
473 lp[1][2].copy_coeffs(lp[0][0]);
474 lp[1][3].copy_coeffs(lp[0][0]);
476 freq_old = *params[param_freq];
478 // set the params of all filters
479 if(*params[param_floor] != floor_old or *params[param_floor_active] != floor_active_old) {
480 hp[0][0].set_hp_rbj(*params[param_floor], 0.707, (float)srate);
481 hp[0][1].copy_coeffs(hp[0][0]);
482 hp[1][0].copy_coeffs(hp[0][0]);
483 hp[1][1].copy_coeffs(hp[0][0]);
484 floor_old = *params[param_floor];
485 floor_active_old = *params[param_floor_active];
487 // set distortion
488 dist[0].set_params(*params[param_blend], *params[param_drive]);
489 if(in_count > 1 && out_count > 1)
490 dist[1].set_params(*params[param_blend], *params[param_drive]);
493 void bassenhancer_audio_module::set_sample_rate(uint32_t sr)
495 srate = sr;
496 dist[0].set_sample_rate(sr);
497 if(in_count > 1 && out_count > 1)
498 dist[1].set_sample_rate(sr);
499 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
500 int clip[] = {param_clip_in, param_clip_out, -1};
501 meters.init(params, meter, clip, 3, srate);
504 uint32_t bassenhancer_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
506 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
507 numsamples += offset;
508 if(bypassed) {
509 // everything bypassed
510 while(offset < numsamples) {
511 if(in_count > 1 && out_count > 1) {
512 outs[0][offset] = ins[0][offset];
513 outs[1][offset] = ins[1][offset];
514 } else if(in_count > 1) {
515 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
516 } else if(out_count > 1) {
517 outs[0][offset] = ins[0][offset];
518 outs[1][offset] = ins[0][offset];
519 } else {
520 outs[0][offset] = ins[0][offset];
522 float values[] = {0, 0, 0};
523 meters.process(values);
524 ++offset;
526 } else {
527 // process
528 uint32_t orig_offset = offset;
529 while(offset < numsamples) {
530 // cycle through samples
531 float out[2], in[2] = {0.f, 0.f};
532 float maxDrive = 0.f;
533 int c = 0;
535 if(in_count > 1 && out_count > 1) {
536 // stereo in/stereo out
537 // handle full stereo
538 in[0] = ins[0][offset];
539 in[0] *= *params[param_level_in];
540 in[1] = ins[1][offset];
541 in[1] *= *params[param_level_in];
542 c = 2;
543 } else {
544 // in and/or out mono
545 // handle mono
546 in[0] = ins[0][offset];
547 in[0] *= *params[param_level_in];
548 in[1] = in[0];
549 c = 1;
552 float proc[2];
553 proc[0] = in[0];
554 proc[1] = in[1];
556 for (int i = 0; i < c; ++i) {
557 // all pre filters in chain
558 proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
560 // saturate
561 proc[i] = dist[i].process(proc[i]);
563 // all post filters in chain
564 proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
566 if(*params[param_floor_active] > 0.5f) {
567 // all H/P post filters in chain
568 proc[i] = hp[i][0].process(hp[i][1].process(proc[i]));
573 if(in_count > 1 && out_count > 1) {
574 // full stereo
575 if(*params[param_listen] > 0.f)
576 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
577 else
578 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
579 outs[0][offset] = out[0];
580 if(*params[param_listen] > 0.f)
581 out[1] = proc[1] * *params[param_amount] * *params[param_level_out];
582 else
583 out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out];
584 outs[1][offset] = out[1];
585 maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount],
586 dist[1].get_distortion_level() * *params[param_amount]);
587 } else if(out_count > 1) {
588 // mono -> pseudo stereo
589 if(*params[param_listen] > 0.f)
590 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
591 else
592 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
593 outs[0][offset] = out[0];
594 out[1] = out[0];
595 outs[1][offset] = out[1];
596 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
597 } else {
598 // stereo -> mono
599 // or full mono
600 if(*params[param_listen] > 0.f)
601 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
602 else
603 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
604 outs[0][offset] = out[0];
605 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
608 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive};
609 meters.process(values);
610 // next sample
611 ++offset;
612 } // cycle trough samples
613 bypass.crossfade(ins, outs, 2, orig_offset, numsamples);
614 // clean up
615 lp[0][0].sanitize();
616 lp[1][0].sanitize();
617 lp[0][1].sanitize();
618 lp[1][1].sanitize();
619 lp[0][2].sanitize();
620 lp[1][2].sanitize();
621 lp[0][3].sanitize();
622 lp[1][3].sanitize();
623 hp[0][0].sanitize();
624 hp[1][0].sanitize();
625 hp[0][1].sanitize();
626 hp[1][1].sanitize();
628 meters.fall(numsamples);
629 return outputs_mask;
632 /**********************************************************************
633 * TAPESIMULATOR by Markus Schmidt
634 **********************************************************************/
636 tapesimulator_audio_module::tapesimulator_audio_module() {
637 active = false;
638 clip_inL = 0.f;
639 clip_inR = 0.f;
640 clip_outL = 0.f;
641 clip_outR = 0.f;
642 meter_inL = 0.f;
643 meter_inR = 0.f;
644 meter_outL = 0.f;
645 meter_outR = 0.f;
646 lp_old = -1.f;
647 rms = 0.f;
648 mech_old = false;
649 transients.set_channels(channels);
652 void tapesimulator_audio_module::activate() {
653 active = true;
656 void tapesimulator_audio_module::deactivate() {
657 active = false;
660 void tapesimulator_audio_module::params_changed() {
661 if(*params[param_lp] != lp_old or *params[param_mechanical] != mech_old) {
662 lp[0][0].set_lp_rbj(*params[param_lp], 0.707, (float)srate);
663 lp[0][1].copy_coeffs(lp[0][0]);
664 lp[1][0].copy_coeffs(lp[0][0]);
665 lp[1][1].copy_coeffs(lp[0][0]);
666 lp_old = *params[param_lp];
667 mech_old = *params[param_mechanical] > 0.5;
669 transients.set_params(50.f / (*params[param_speed] + 1),
670 -0.05f / (*params[param_speed] + 1),
671 100.f,
672 0.f,
673 1.f,
676 lfo1.set_params((*params[param_speed] + 1) / 2, 0, 0.f, srate, 1.f);
677 lfo2.set_params((*params[param_speed] + 1) / 9.38, 0, 0.f, srate, 1.f);
680 uint32_t tapesimulator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
681 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
682 uint32_t orig_offset = offset;
683 for(uint32_t i = offset; i < offset + numsamples; i++) {
684 float L = ins[0][i];
685 float R = ins[1][i];
686 float Lin = ins[0][i];
687 float Rin = ins[1][i];
688 if(bypassed) {
689 outs[0][i] = ins[0][i];
690 outs[1][i] = ins[1][i];
691 float values[] = {0, 0, 0, 0};
692 meters.process(values);
693 } else {
694 // transients
695 float inL = 0;
696 float inR = 0;
697 if(*params[param_magnetical] > 0.5f) {
698 float values[] = {L, R};
699 transients.process(values);
700 L = values[0];
701 R = values[1];
704 // noise
705 if (*params[param_noise]) {
706 float Lnoise = rand() % 2 - 1;
707 float Rnoise = rand() % 2 - 1;
708 Lnoise = noisefilters[0][2].process(noisefilters[0][1].process(noisefilters[0][0].process(Lnoise)));
709 Rnoise = noisefilters[1][2].process(noisefilters[1][1].process(noisefilters[1][0].process(Rnoise)));
710 L += Lnoise * *params[param_noise] / 12.f;
711 R += Rnoise * *params[param_noise] / 12.f;
714 // lfo filters / phasing
715 if (*params[param_mechanical]) {
716 // filtering
717 float freqL1 = *params[param_lp] * (1 - ((lfo1.get_value() + 1) * 0.3 * *params[param_mechanical]));
718 float freqL2 = *params[param_lp] * (1 - ((lfo2.get_value() + 1) * 0.2 * *params[param_mechanical]));
720 float freqR1 = *params[param_lp] * (1 - ((lfo1.get_value() * -1 + 1) * 0.3 * *params[param_mechanical]));
721 float freqR2 = *params[param_lp] * (1 - ((lfo2.get_value() * -1 + 1) * 0.2 * *params[param_mechanical]));
723 lp[0][0].set_lp_rbj(freqL1, 0.707, (float)srate);
724 lp[0][1].set_lp_rbj(freqL2, 0.707, (float)srate);
726 lp[1][0].set_lp_rbj(freqR1, 0.707, (float)srate);
727 lp[1][1].set_lp_rbj(freqR2, 0.707, (float)srate);
729 // phasing
730 float _phase = lfo1.get_value() * *params[param_mechanical] * -36;
732 float _phase_cos_coef = cos(_phase / 180 * M_PI);
733 float _phase_sin_coef = sin(_phase / 180 * M_PI);
735 float _l = L * _phase_cos_coef - R * _phase_sin_coef;
736 float _r = L * _phase_sin_coef + R * _phase_cos_coef;
737 L = _l;
738 R = _r;
741 // gain
742 L *= *params[param_level_in];
743 R *= *params[param_level_in];
745 inL = L;
746 inR = R;
748 // save for drawing input/output curve
749 float Lc = L;
750 float Rc = R;
751 float Lo = L;
752 float Ro = R;
754 // filter
755 if (*params[param_post] < 0.5) {
756 L = lp[0][1].process(lp[0][0].process(L));
757 R = lp[1][1].process(lp[1][0].process(R));
760 // distortion
761 if (L) L = L / fabs(L) * (1 - exp((-1) * 3 * fabs(L)));
762 if (R) R = R / fabs(R) * (1 - exp((-1) * 3 * fabs(R)));
764 if (Lo) Lo = Lo / fabs(Lo) * (1 - exp((-1) * 3 * fabs(Lo)));
765 if (Ro) Ro = Ro / fabs(Ro) * (1 - exp((-1) * 3 * fabs(Ro)));
767 // filter
768 if (*params[param_post] >= 0.5) {
769 L = lp[0][1].process(lp[0][0].process(L));
770 R = lp[1][1].process(lp[1][0].process(R));
773 // mix
774 L = L * *params[param_mix] + Lin * (*params[param_mix] * -1 + 1);
775 R = R * *params[param_mix] + Rin * (*params[param_mix] * -1 + 1);
777 // levels out
778 L *= *params[param_level_out];
779 R *= *params[param_level_out];
781 // output
782 outs[0][i] = L;
783 outs[1][i] = R;
785 // sanitize filters
786 lp[0][0].sanitize();
787 lp[1][0].sanitize();
788 lp[0][1].sanitize();
789 lp[1][1].sanitize();
791 // LFO's should go on
792 lfo1.advance(1);
793 lfo2.advance(1);
795 // dot
796 rms = std::max((double)rms, (fabs(Lo) + fabs(Ro)) / 2);
797 input = std::max((double)input, (fabs(Lc) + fabs(Rc)) / 2);
799 float values[] = {inL, inR, outs[0][i], outs[1][i]};
800 meters.process(values);
803 if (bypassed)
804 bypass.crossfade(ins, outs, 2, orig_offset, numsamples);
805 meters.fall(numsamples);
806 return outputs_mask;
809 void tapesimulator_audio_module::set_sample_rate(uint32_t sr)
811 srate = sr;
812 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
813 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
814 meters.init(params, meter, clip, 4, srate);
815 transients.set_sample_rate(srate);
816 noisefilters[0][0].set_hp_rbj(120.f, 0.707, (float)srate);
817 noisefilters[1][0].copy_coeffs(noisefilters[0][0]);
818 noisefilters[0][1].set_lp_rbj(5500.f, 0.707, (float)srate);
819 noisefilters[1][1].copy_coeffs(noisefilters[0][1]);
820 noisefilters[0][2].set_highshelf_rbj(1000.f, 0.707, 0.5, (float)srate);
821 noisefilters[1][2].copy_coeffs(noisefilters[0][2]);
824 bool tapesimulator_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
826 if (subindex > 1)
827 return false;
828 if(index == param_lp and phase) {
829 set_channel_color(context, subindex);
830 return ::get_graph(*this, subindex, data, points);
831 } else if (index == param_level_in and !phase) {
832 if (!subindex) {
833 context->set_source_rgba(0.15, 0.2, 0.0, 0.3);
834 context->set_line_width(1);
836 for (int i = 0; i < points; i++) {
837 if (!subindex) {
838 float input = dB_grid_inv(-1.0 + (float)i * 2.0 / ((float)points - 1.f));
839 data[i] = dB_grid(input);
840 } else {
841 float output = 1 - exp(-3 * (pow(2, -10 + 14 * (float)i / (float) points)));
842 data[i] = dB_grid(output * *params[param_level_out]);
845 return true;
847 return false;
849 float tapesimulator_audio_module::freq_gain(int index, double freq) const
851 return lp[index][0].freq_gain(freq, srate) * lp[index][1].freq_gain(freq, srate);
854 bool tapesimulator_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
856 if(!active or phase)
857 return false;
858 if (index == param_level_in) {
859 bool tmp;
860 vertical = (subindex & 1) != 0;
861 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
862 if (result && vertical) {
863 if ((subindex & 4) && !legend.empty()) {
864 legend = "";
866 else {
867 size_t pos = legend.find(" dB");
868 if (pos != std::string::npos)
869 legend.erase(pos);
871 pos = 0.5 + 0.5 * pos;
873 return result;
874 } else if (index == param_lp) {
875 return get_freq_gridline(subindex, pos, vertical, legend, context);
877 return false;
879 bool tapesimulator_audio_module::get_dot(int index, int subindex, int phase, float &x, float &y, int &size, cairo_iface *context) const
881 if (index == param_level_in and !subindex and phase) {
882 x = log(input) / log(2) / 14.f + 5.f / 7.f;
883 y = dB_grid(rms);
884 rms = 0.f;
885 input = 0.f;
886 return true;
888 return false;
890 bool tapesimulator_audio_module::get_layers(int index, int generation, unsigned int &layers) const
892 layers = 0;
893 // always draw grid on cache if surfaces are new on both widgets
894 if (!generation)
895 layers |= LG_CACHE_GRID;
896 // compression: dot in realtime, graphs as cache on new surfaces
897 if (index == param_level_in and !generation)
898 layers |= LG_CACHE_GRAPH;
899 if (index == param_level_in)
900 layers |= LG_REALTIME_DOT;
901 // frequency: both graphs in realtime
902 if (index == param_lp)
903 layers |= LG_REALTIME_GRAPH;
904 // draw always
905 return true;
910 /**********************************************************************
911 * CRUSHER by Markus Schmidt and Christian Holschuh
912 **********************************************************************/
915 crusher_audio_module::crusher_audio_module()
917 smin = sdiff = 0.f;
920 void crusher_audio_module::activate()
922 lfo.activate();
924 void crusher_audio_module::deactivate()
926 lfo.deactivate();
929 void crusher_audio_module::params_changed()
931 bitreduction.set_params(*params[param_bits],
932 *params[param_morph],
933 *params[param_bypass] > 0.5,
934 *params[param_mode],
935 *params[param_dc],
936 *params[param_aa]);
937 samplereduction[0].set_params(*params[param_samples]);
938 samplereduction[1].set_params(*params[param_samples]);
939 lfo.set_params(*params[param_lforate], 0, 0.f, srate, 0.5f);
940 // calc lfo offsets
941 float rad = *params[param_lforange] / 2.f;
942 smin = std::max(*params[param_samples] - rad, 1.f);
943 float sun = *params[param_samples] - rad - smin;
944 float smax = std::min(*params[param_samples] + rad, 250.f);
945 float sov = *params[param_samples] + rad - smax;
946 smax -= sun;
947 smin -= sov;
948 sdiff = smax - smin;
951 void crusher_audio_module::set_sample_rate(uint32_t sr)
953 srate = sr;
954 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
955 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
956 meters.init(params, meter, clip, 4, srate);
957 bitreduction.set_sample_rate(srate);
960 uint32_t crusher_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
962 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
963 numsamples += offset;
964 if(bypassed) {
965 // everything bypassed
966 while(offset < numsamples) {
967 outs[0][offset] = ins[0][offset];
968 outs[1][offset] = ins[1][offset];
969 float values[] = {0, 0, 0, 0};
970 meters.process(values);
971 ++offset;
973 } else {
974 // process
975 uint32_t orig_offset = offset;
976 while(offset < numsamples) {
977 // cycle through samples
978 if (*params[param_lfo] > 0.5) {
979 samplereduction[0].set_params(smin + sdiff * (lfo.get_value() + 0.5));
980 samplereduction[1].set_params(smin + sdiff * (lfo.get_value() + 0.5));
982 outs[0][offset] = samplereduction[0].process(ins[0][offset] * *params[param_level_in]);
983 outs[1][offset] = samplereduction[1].process(ins[1][offset] * *params[param_level_in]);
984 outs[0][offset] = outs[0][offset] * *params[param_morph] + ins[0][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
985 outs[1][offset] = outs[1][offset] * *params[param_morph] + ins[1][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
986 outs[0][offset] = bitreduction.process(outs[0][offset]) * *params[param_level_out];
987 outs[1][offset] = bitreduction.process(outs[1][offset]) * *params[param_level_out];
988 float values[] = {ins[0][offset], ins[1][offset], outs[0][offset], outs[1][offset]};
989 meters.process(values);
990 // next sample
991 ++offset;
992 if (*params[param_lforate])
993 lfo.advance(1);
994 } // cycle trough samples
995 bypass.crossfade(ins, outs, 2, orig_offset, numsamples);
997 meters.fall(numsamples);
998 return outputs_mask;
1000 bool crusher_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
1002 return bitreduction.get_graph(subindex, phase, data, points, context, mode);
1004 bool crusher_audio_module::get_layers(int index, int generation, unsigned int &layers) const
1006 return bitreduction.get_layers(index, generation, layers);
1008 bool crusher_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
1010 return bitreduction.get_gridline(subindex, phase, pos, vertical, legend, context);