LV2: less heavy-handed approach to lifecycle issues
[calf.git] / src / modules_dist.cpp
blobd69b34840f142447a5a9fac418c52c53e37b39a3
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 lp_pre_freq_old = -1;
40 hp_pre_freq_old = -1;
41 lp_post_freq_old = -1;
42 hp_post_freq_old = -1;
43 p_freq_old = -1;
44 p_level_old = -1;
45 p_q_old = -1;
48 void saturator_audio_module::activate()
50 is_active = true;
51 // set all filters
52 params_changed();
54 void saturator_audio_module::deactivate()
56 is_active = false;
59 void saturator_audio_module::params_changed()
61 // set the params of all filters
62 if(*params[param_lp_pre_freq] != lp_pre_freq_old) {
63 lp[0][0].set_lp_rbj(*params[param_lp_pre_freq], 0.707, (float)srate);
64 if(in_count > 1 && out_count > 1)
65 lp[1][0].copy_coeffs(lp[0][0]);
66 lp[0][1].copy_coeffs(lp[0][0]);
67 if(in_count > 1 && out_count > 1)
68 lp[1][1].copy_coeffs(lp[0][0]);
69 lp_pre_freq_old = *params[param_lp_pre_freq];
71 if(*params[param_hp_pre_freq] != hp_pre_freq_old) {
72 hp[0][0].set_hp_rbj(*params[param_hp_pre_freq], 0.707, (float)srate);
73 if(in_count > 1 && out_count > 1)
74 hp[1][0].copy_coeffs(hp[0][0]);
75 hp[0][1].copy_coeffs(hp[0][0]);
76 if(in_count > 1 && out_count > 1)
77 hp[1][1].copy_coeffs(hp[0][0]);
78 hp_pre_freq_old = *params[param_hp_pre_freq];
80 if(*params[param_lp_post_freq] != lp_post_freq_old) {
81 lp[0][2].set_lp_rbj(*params[param_lp_post_freq], 0.707, (float)srate);
82 if(in_count > 1 && out_count > 1)
83 lp[1][2].copy_coeffs(lp[0][2]);
84 lp[0][3].copy_coeffs(lp[0][2]);
85 if(in_count > 1 && out_count > 1)
86 lp[1][3].copy_coeffs(lp[0][2]);
87 lp_post_freq_old = *params[param_lp_post_freq];
89 if(*params[param_hp_post_freq] != hp_post_freq_old) {
90 hp[0][2].set_hp_rbj(*params[param_hp_post_freq], 0.707, (float)srate);
91 if(in_count > 1 && out_count > 1)
92 hp[1][2].copy_coeffs(hp[0][2]);
93 hp[0][3].copy_coeffs(hp[0][2]);
94 if(in_count > 1 && out_count > 1)
95 hp[1][3].copy_coeffs(hp[0][2]);
96 hp_post_freq_old = *params[param_hp_post_freq];
98 if(*params[param_p_freq] != p_freq_old or *params[param_p_level] != p_level_old or *params[param_p_q] != p_q_old) {
99 p[0].set_peakeq_rbj((float)*params[param_p_freq], (float)*params[param_p_q], (float)*params[param_p_level], (float)srate);
100 if(in_count > 1 && out_count > 1)
101 p[1].copy_coeffs(p[0]);
102 p_freq_old = *params[param_p_freq];
103 p_level_old = *params[param_p_level];
104 p_q_old = *params[param_p_q];
106 // set distortion
107 dist[0].set_params(*params[param_blend], *params[param_drive]);
108 if(in_count > 1 && out_count > 1)
109 dist[1].set_params(*params[param_blend], *params[param_drive]);
112 void saturator_audio_module::set_sample_rate(uint32_t sr)
114 srate = sr;
115 dist[0].set_sample_rate(sr);
116 if(in_count > 1 && out_count > 1)
117 dist[1].set_sample_rate(sr);
118 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
119 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
120 meters.init(params, meter, clip, 4, srate);
123 uint32_t saturator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
125 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
126 numsamples += offset;
127 if(bypassed) {
128 // everything bypassed
129 while(offset < numsamples) {
130 if(in_count > 1 && out_count > 1) {
131 outs[0][offset] = ins[0][offset];
132 outs[1][offset] = ins[1][offset];
133 } else if(in_count > 1) {
134 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
135 } else if(out_count > 1) {
136 outs[0][offset] = ins[0][offset];
137 outs[1][offset] = ins[0][offset];
138 } else {
139 outs[0][offset] = ins[0][offset];
141 float values[] = {0, 0, 0, 0};
142 meters.process(values);
143 ++offset;
145 } else {
146 uint32_t orig_numsamples = numsamples-offset;
147 uint32_t orig_offset = offset;
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 if(in_count > 1 && out_count > 1) {
154 // stereo in/stereo out
155 // handle full stereo
156 in[0] = ins[0][offset];
157 in[1] = ins[1][offset];
158 c = 2;
159 } else {
160 // in and/or out mono
161 // handle mono
162 in[0] = ins[0][offset];
163 in[1] = in[0];
164 c = 1;
167 float proc[2];
168 proc[0] = in[0] * *params[param_level_in];
169 proc[1] = in[1] * *params[param_level_in];
171 float onedivlevelin = 1.0 / *params[param_level_in];
173 for (int i = 0; i < c; ++i) {
174 // all pre filters in chain
175 proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
176 proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
178 // ...saturate...
179 proc[i] = dist[i].process(proc[i]);
181 // tone control
182 proc[i] = p[i].process(proc[i]);
184 // all post filters in chain
185 proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
186 proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
188 //subtract gain
189 proc[i] *= onedivlevelin;
191 if (*params[param_level_in] > 1)
192 proc[i] *= 1 + (*params[param_level_in] - 1) / 32;
195 if(in_count > 1 && out_count > 1) {
196 // full stereo
197 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
198 outs[0][offset] = out[0];
199 out[1] = ((proc[1] * *params[param_mix]) + in[1] * (1 - *params[param_mix])) * *params[param_level_out];
200 outs[1][offset] = out[1];
201 } else if(out_count > 1) {
202 // mono -> pseudo stereo
203 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
204 outs[0][offset] = out[0];
205 out[1] = out[0];
206 outs[1][offset] = out[1];
207 } else {
208 // stereo -> mono
209 // or full mono
210 out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
211 outs[0][offset] = out[0];
213 float values[] = {in[0], in[1], out[0], out[1]};
214 meters.process(values);
216 // next sample
217 ++offset;
218 } // cycle trough samples
220 // clean up
221 lp[0][0].sanitize();
222 lp[1][0].sanitize();
223 lp[0][1].sanitize();
224 lp[1][1].sanitize();
225 lp[0][2].sanitize();
226 lp[1][2].sanitize();
227 lp[0][3].sanitize();
228 lp[1][3].sanitize();
229 hp[0][0].sanitize();
230 hp[1][0].sanitize();
231 hp[0][1].sanitize();
232 hp[1][1].sanitize();
233 hp[0][2].sanitize();
234 hp[1][2].sanitize();
235 hp[0][3].sanitize();
236 hp[1][3].sanitize();
237 p[0].sanitize();
238 p[1].sanitize();
239 bypass.crossfade(ins, outs, 2, orig_offset, orig_numsamples);
241 meters.fall(numsamples);
242 return outputs_mask;
245 /**********************************************************************
246 * EXCITER by Markus Schmidt
247 **********************************************************************/
249 exciter_audio_module::exciter_audio_module()
251 freq_old = 0.f;
252 ceil_old = 0.f;
253 ceil_active_old = false;
254 meter_drive = 0.f;
255 is_active = false;
256 srate = 0;
259 void exciter_audio_module::activate()
261 is_active = true;
262 // set all filters
263 params_changed();
266 void exciter_audio_module::deactivate()
268 is_active = false;
271 void exciter_audio_module::params_changed()
273 // set the params of all filters
274 if(*params[param_freq] != freq_old) {
275 hp[0][0].set_hp_rbj(*params[param_freq], 0.707, (float)srate);
276 hp[0][1].copy_coeffs(hp[0][0]);
277 hp[0][2].copy_coeffs(hp[0][0]);
278 hp[0][3].copy_coeffs(hp[0][0]);
279 if(in_count > 1 && out_count > 1) {
280 hp[1][0].copy_coeffs(hp[0][0]);
281 hp[1][1].copy_coeffs(hp[0][0]);
282 hp[1][2].copy_coeffs(hp[0][0]);
283 hp[1][3].copy_coeffs(hp[0][0]);
285 freq_old = *params[param_freq];
287 // set the params of all filters
288 if(*params[param_ceil] != ceil_old or *params[param_ceil_active] != ceil_active_old) {
289 lp[0][0].set_lp_rbj(*params[param_ceil], 0.707, (float)srate);
290 lp[0][1].copy_coeffs(lp[0][0]);
291 lp[1][0].copy_coeffs(lp[0][0]);
292 lp[1][1].copy_coeffs(lp[0][0]);
293 ceil_old = *params[param_ceil];
294 ceil_active_old = *params[param_ceil_active];
296 // set distortion
297 dist[0].set_params(*params[param_blend], *params[param_drive]);
298 if(in_count > 1 && out_count > 1)
299 dist[1].set_params(*params[param_blend], *params[param_drive]);
302 void exciter_audio_module::set_sample_rate(uint32_t sr)
304 srate = sr;
305 dist[0].set_sample_rate(sr);
306 if(in_count > 1 && out_count > 1)
307 dist[1].set_sample_rate(sr);
308 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
309 int clip[] = {param_clip_in, param_clip_out, -1};
310 meters.init(params, meter, clip, 3, srate);
313 uint32_t exciter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
315 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
316 numsamples += offset;
317 if(bypassed) {
318 // everything bypassed
319 while(offset < numsamples) {
320 if(in_count > 1 && out_count > 1) {
321 outs[0][offset] = ins[0][offset];
322 outs[1][offset] = ins[1][offset];
323 } else if(in_count > 1) {
324 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
325 } else if(out_count > 1) {
326 outs[0][offset] = ins[0][offset];
327 outs[1][offset] = ins[0][offset];
328 } else {
329 outs[0][offset] = ins[0][offset];
331 float values[] = {0, 0, 0, 0, 0};
332 meters.process(values);
333 ++offset;
335 // displays, too
336 meter_drive = 0.f;
337 } else {
338 uint32_t orig_numsamples = numsamples-offset;
339 uint32_t orig_offset = offset;
340 meter_drive = 0.f;
342 float in2out = *params[param_listen] > 0.f ? 0.f : 1.f;
344 // process
345 while(offset < numsamples) {
346 // cycle through samples
347 float out[2], in[2] = {0.f, 0.f};
348 float maxDrive = 0.f;
349 int c = 0;
351 if(in_count > 1 && out_count > 1) {
352 // stereo in/stereo out
353 // handle full stereo
354 in[0] = ins[0][offset];
355 in[0] *= *params[param_level_in];
356 in[1] = ins[1][offset];
357 in[1] *= *params[param_level_in];
358 c = 2;
359 } else {
360 // in and/or out mono
361 // handle mono
362 in[0] = ins[0][offset];
363 in[0] *= *params[param_level_in];
364 in[1] = in[0];
365 c = 1;
368 float proc[2];
369 proc[0] = in[0];
370 proc[1] = in[1];
372 for (int i = 0; i < c; ++i) {
373 // all pre filters in chain
374 proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
376 // saturate
377 proc[i] = dist[i].process(proc[i]);
379 // all post filters in chain
380 proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
382 if(*params[param_ceil_active] > 0.5f) {
383 // all H/P post filters in chain
384 proc[i] = lp[i][0].process(lp[i][1].process(proc[i]));
388 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
390 if(in_count > 1 && out_count > 1) {
391 maxDrive = std::max(maxDrive, dist[1].get_distortion_level() * *params[param_amount]);
392 // full stereo
393 out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
394 out[1] = (proc[1] * *params[param_amount] + in2out * in[1]) * *params[param_level_out];
395 outs[0][offset] = out[0];
396 outs[1][offset] = out[1];
397 } else if(out_count > 1) {
398 // mono -> pseudo stereo
399 out[1] = out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
400 outs[0][offset] = out[0];
401 outs[1][offset] = out[1];
402 } else {
403 // stereo -> mono
404 // or full mono
405 out[0] = (proc[0] * *params[param_amount] + in2out * in[0]) * *params[param_level_out];
406 outs[0][offset] = out[0];
408 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive};
409 meters.process(values);
410 // next sample
411 ++offset;
412 } // cycle trough samples
413 bypass.crossfade(ins, outs, 2, orig_offset, orig_numsamples);
414 // clean up
415 hp[0][0].sanitize();
416 hp[1][0].sanitize();
417 hp[0][1].sanitize();
418 hp[1][1].sanitize();
419 hp[0][2].sanitize();
420 hp[1][2].sanitize();
421 hp[0][3].sanitize();
422 hp[1][3].sanitize();
424 lp[0][0].sanitize();
425 lp[1][0].sanitize();
426 lp[0][1].sanitize();
427 lp[1][1].sanitize();
429 meters.fall(numsamples);
430 return outputs_mask;
433 /**********************************************************************
434 * BASS ENHANCER by Markus Schmidt
435 **********************************************************************/
437 bassenhancer_audio_module::bassenhancer_audio_module()
439 freq_old = 0.f;
440 floor_old = 0.f;
441 floor_active_old = false;
442 meter_drive = 0.f;
443 is_active = false;
444 srate = 0;
447 void bassenhancer_audio_module::activate()
449 is_active = true;
450 // set all filters
451 params_changed();
453 void bassenhancer_audio_module::deactivate()
455 is_active = false;
458 void bassenhancer_audio_module::params_changed()
460 // set the params of all filters
461 if(*params[param_freq] != freq_old) {
462 lp[0][0].set_lp_rbj(*params[param_freq], 0.707, (float)srate);
463 lp[0][1].copy_coeffs(lp[0][0]);
464 lp[0][2].copy_coeffs(lp[0][0]);
465 lp[0][3].copy_coeffs(lp[0][0]);
466 if(in_count > 1 && out_count > 1) {
467 lp[1][0].copy_coeffs(lp[0][0]);
468 lp[1][1].copy_coeffs(lp[0][0]);
469 lp[1][2].copy_coeffs(lp[0][0]);
470 lp[1][3].copy_coeffs(lp[0][0]);
472 freq_old = *params[param_freq];
474 // set the params of all filters
475 if(*params[param_floor] != floor_old or *params[param_floor_active] != floor_active_old) {
476 hp[0][0].set_hp_rbj(*params[param_floor], 0.707, (float)srate);
477 hp[0][1].copy_coeffs(hp[0][0]);
478 hp[1][0].copy_coeffs(hp[0][0]);
479 hp[1][1].copy_coeffs(hp[0][0]);
480 floor_old = *params[param_floor];
481 floor_active_old = *params[param_floor_active];
483 // set distortion
484 dist[0].set_params(*params[param_blend], *params[param_drive]);
485 if(in_count > 1 && out_count > 1)
486 dist[1].set_params(*params[param_blend], *params[param_drive]);
489 void bassenhancer_audio_module::set_sample_rate(uint32_t sr)
491 srate = sr;
492 dist[0].set_sample_rate(sr);
493 if(in_count > 1 && out_count > 1)
494 dist[1].set_sample_rate(sr);
495 int meter[] = {param_meter_in, param_meter_out, param_meter_drive};
496 int clip[] = {param_clip_in, param_clip_out, -1};
497 meters.init(params, meter, clip, 3, srate);
500 uint32_t bassenhancer_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
502 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
503 numsamples += offset;
504 if(bypassed) {
505 // everything bypassed
506 while(offset < numsamples) {
507 if(in_count > 1 && out_count > 1) {
508 outs[0][offset] = ins[0][offset];
509 outs[1][offset] = ins[1][offset];
510 } else if(in_count > 1) {
511 outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
512 } else if(out_count > 1) {
513 outs[0][offset] = ins[0][offset];
514 outs[1][offset] = ins[0][offset];
515 } else {
516 outs[0][offset] = ins[0][offset];
518 float values[] = {0, 0, 0};
519 meters.process(values);
520 ++offset;
522 } else {
523 // process
524 uint32_t orig_numsamples = numsamples-offset;
525 uint32_t orig_offset = offset;
526 while(offset < numsamples) {
527 // cycle through samples
528 float out[2], in[2] = {0.f, 0.f};
529 float maxDrive = 0.f;
530 int c = 0;
532 if(in_count > 1 && out_count > 1) {
533 // stereo in/stereo out
534 // handle full stereo
535 in[0] = ins[0][offset];
536 in[0] *= *params[param_level_in];
537 in[1] = ins[1][offset];
538 in[1] *= *params[param_level_in];
539 c = 2;
540 } else {
541 // in and/or out mono
542 // handle mono
543 in[0] = ins[0][offset];
544 in[0] *= *params[param_level_in];
545 in[1] = in[0];
546 c = 1;
549 float proc[2];
550 proc[0] = in[0];
551 proc[1] = in[1];
553 for (int i = 0; i < c; ++i) {
554 // all pre filters in chain
555 proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
557 // saturate
558 proc[i] = dist[i].process(proc[i]);
560 // all post filters in chain
561 proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
563 if(*params[param_floor_active] > 0.5f) {
564 // all H/P post filters in chain
565 proc[i] = hp[i][0].process(hp[i][1].process(proc[i]));
570 if(in_count > 1 && out_count > 1) {
571 // full stereo
572 if(*params[param_listen] > 0.f)
573 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
574 else
575 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
576 outs[0][offset] = out[0];
577 if(*params[param_listen] > 0.f)
578 out[1] = proc[1] * *params[param_amount] * *params[param_level_out];
579 else
580 out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out];
581 outs[1][offset] = out[1];
582 maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount],
583 dist[1].get_distortion_level() * *params[param_amount]);
584 } else if(out_count > 1) {
585 // mono -> pseudo stereo
586 if(*params[param_listen] > 0.f)
587 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
588 else
589 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
590 outs[0][offset] = out[0];
591 out[1] = out[0];
592 outs[1][offset] = out[1];
593 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
594 } else {
595 // stereo -> mono
596 // or full mono
597 if(*params[param_listen] > 0.f)
598 out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
599 else
600 out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
601 outs[0][offset] = out[0];
602 maxDrive = dist[0].get_distortion_level() * *params[param_amount];
605 float values[] = {(in[0] + in[1]) / 2, (out[0] + out[1]) / 2, maxDrive};
606 meters.process(values);
607 // next sample
608 ++offset;
609 } // cycle trough samples
610 bypass.crossfade(ins, outs, 2, orig_offset, orig_numsamples);
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 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
679 uint32_t orig_offset = offset;
680 for(uint32_t i = offset; i < offset + numsamples; i++) {
681 float L = ins[0][i];
682 float R = ins[1][i];
683 float Lin = ins[0][i];
684 float Rin = ins[1][i];
685 if(bypassed) {
686 outs[0][i] = ins[0][i];
687 outs[1][i] = ins[1][i];
688 float values[] = {0, 0, 0, 0};
689 meters.process(values);
690 } else {
691 // transients
692 float inL = 0;
693 float inR = 0;
694 if(*params[param_magnetical] > 0.5f) {
695 float values[] = {L, R};
696 transients.process(values);
697 L = values[0];
698 R = values[1];
701 // noise
702 if (*params[param_noise]) {
703 float Lnoise = rand() % 2 - 1;
704 float Rnoise = rand() % 2 - 1;
705 Lnoise = noisefilters[0][2].process(noisefilters[0][1].process(noisefilters[0][0].process(Lnoise)));
706 Rnoise = noisefilters[1][2].process(noisefilters[1][1].process(noisefilters[1][0].process(Rnoise)));
707 L += Lnoise * *params[param_noise] / 12.f;
708 R += Rnoise * *params[param_noise] / 12.f;
711 // lfo filters / phasing
712 if (*params[param_mechanical]) {
713 // filtering
714 float freqL1 = *params[param_lp] * (1 - ((lfo1.get_value() + 1) * 0.3 * *params[param_mechanical]));
715 float freqL2 = *params[param_lp] * (1 - ((lfo2.get_value() + 1) * 0.2 * *params[param_mechanical]));
717 float freqR1 = *params[param_lp] * (1 - ((lfo1.get_value() * -1 + 1) * 0.3 * *params[param_mechanical]));
718 float freqR2 = *params[param_lp] * (1 - ((lfo2.get_value() * -1 + 1) * 0.2 * *params[param_mechanical]));
720 lp[0][0].set_lp_rbj(freqL1, 0.707, (float)srate);
721 lp[0][1].set_lp_rbj(freqL2, 0.707, (float)srate);
723 lp[1][0].set_lp_rbj(freqR1, 0.707, (float)srate);
724 lp[1][1].set_lp_rbj(freqR2, 0.707, (float)srate);
726 // phasing
727 float _phase = lfo1.get_value() * *params[param_mechanical] * -36;
729 float _phase_cos_coef = cos(_phase / 180 * M_PI);
730 float _phase_sin_coef = sin(_phase / 180 * M_PI);
732 float _l = L * _phase_cos_coef - R * _phase_sin_coef;
733 float _r = L * _phase_sin_coef + R * _phase_cos_coef;
734 L = _l;
735 R = _r;
738 // gain
739 L *= *params[param_level_in];
740 R *= *params[param_level_in];
742 inL = L;
743 inR = R;
745 // save for drawing input/output curve
746 float Lc = L;
747 float Rc = R;
748 float Lo = L;
749 float Ro = R;
751 // filter
752 if (*params[param_post] < 0.5) {
753 L = lp[0][1].process(lp[0][0].process(L));
754 R = lp[1][1].process(lp[1][0].process(R));
757 // distortion
758 if (L) L = L / fabs(L) * (1 - exp((-1) * 3 * fabs(L)));
759 if (R) R = R / fabs(R) * (1 - exp((-1) * 3 * fabs(R)));
761 if (Lo) Lo = Lo / fabs(Lo) * (1 - exp((-1) * 3 * fabs(Lo)));
762 if (Ro) Ro = Ro / fabs(Ro) * (1 - exp((-1) * 3 * fabs(Ro)));
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 // mix
771 L = L * *params[param_mix] + Lin * (*params[param_mix] * -1 + 1);
772 R = R * *params[param_mix] + Rin * (*params[param_mix] * -1 + 1);
774 // levels out
775 L *= *params[param_level_out];
776 R *= *params[param_level_out];
778 // output
779 outs[0][i] = L;
780 outs[1][i] = R;
782 // sanitize filters
783 lp[0][0].sanitize();
784 lp[1][0].sanitize();
785 lp[0][1].sanitize();
786 lp[1][1].sanitize();
788 // LFO's should go on
789 lfo1.advance(1);
790 lfo2.advance(1);
792 // dot
793 rms = std::max((double)rms, (fabs(Lo) + fabs(Ro)) / 2);
794 input = std::max((double)input, (fabs(Lc) + fabs(Rc)) / 2);
796 float values[] = {inL, inR, outs[0][i], outs[1][i]};
797 meters.process(values);
800 if (bypassed)
801 bypass.crossfade(ins, outs, 2, orig_offset, numsamples);
802 meters.fall(numsamples);
803 return outputs_mask;
806 void tapesimulator_audio_module::set_sample_rate(uint32_t sr)
808 srate = sr;
809 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
810 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
811 meters.init(params, meter, clip, 4, srate);
812 transients.set_sample_rate(srate);
813 noisefilters[0][0].set_hp_rbj(120.f, 0.707, (float)srate);
814 noisefilters[1][0].copy_coeffs(noisefilters[0][0]);
815 noisefilters[0][1].set_lp_rbj(5500.f, 0.707, (float)srate);
816 noisefilters[1][1].copy_coeffs(noisefilters[0][1]);
817 noisefilters[0][2].set_highshelf_rbj(1000.f, 0.707, 0.5, (float)srate);
818 noisefilters[1][2].copy_coeffs(noisefilters[0][2]);
821 bool tapesimulator_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
823 if (subindex > 1)
824 return false;
825 if(index == param_lp and phase) {
826 set_channel_color(context, subindex);
827 return ::get_graph(*this, subindex, data, points);
828 } else if (index == param_level_in and !phase) {
829 if (!subindex) {
830 context->set_source_rgba(0.15, 0.2, 0.0, 0.3);
831 context->set_line_width(1);
833 for (int i = 0; i < points; i++) {
834 if (!subindex) {
835 float input = dB_grid_inv(-1.0 + (float)i * 2.0 / ((float)points - 1.f));
836 data[i] = dB_grid(input);
837 } else {
838 float output = 1 - exp(-3 * (pow(2, -10 + 14 * (float)i / (float) points)));
839 data[i] = dB_grid(output * *params[param_level_out]);
842 return true;
844 return false;
846 float tapesimulator_audio_module::freq_gain(int index, double freq) const
848 return lp[index][0].freq_gain(freq, srate) * lp[index][1].freq_gain(freq, srate);
851 bool tapesimulator_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
853 if(!active or phase)
854 return false;
855 if (index == param_level_in) {
856 bool tmp;
857 vertical = (subindex & 1) != 0;
858 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
859 if (result && vertical) {
860 if ((subindex & 4) && !legend.empty()) {
861 legend = "";
863 else {
864 size_t pos = legend.find(" dB");
865 if (pos != std::string::npos)
866 legend.erase(pos);
868 pos = 0.5 + 0.5 * pos;
870 return result;
871 } else if (index == param_lp) {
872 return get_freq_gridline(subindex, pos, vertical, legend, context);
874 return false;
876 bool tapesimulator_audio_module::get_dot(int index, int subindex, int phase, float &x, float &y, int &size, cairo_iface *context) const
878 if (index == param_level_in and !subindex and phase) {
879 x = log(input) / log(2) / 14.f + 5.f / 7.f;
880 y = dB_grid(rms);
881 rms = 0.f;
882 input = 0.f;
883 return true;
885 return false;
887 bool tapesimulator_audio_module::get_layers(int index, int generation, unsigned int &layers) const
889 layers = 0;
890 // always draw grid on cache if surfaces are new on both widgets
891 if (!generation)
892 layers |= LG_CACHE_GRID;
893 // compression: dot in realtime, graphs as cache on new surfaces
894 if (index == param_level_in and !generation)
895 layers |= LG_CACHE_GRAPH;
896 if (index == param_level_in)
897 layers |= LG_REALTIME_DOT;
898 // frequency: both graphs in realtime
899 if (index == param_lp)
900 layers |= LG_REALTIME_GRAPH;
901 // draw always
902 return true;
907 /**********************************************************************
908 * CRUSHER by Markus Schmidt and Christian Holschuh
909 **********************************************************************/
912 crusher_audio_module::crusher_audio_module()
914 smin = sdiff = 0.f;
917 void crusher_audio_module::activate()
919 lfo.activate();
921 void crusher_audio_module::deactivate()
923 lfo.deactivate();
926 void crusher_audio_module::params_changed()
928 bitreduction.set_params(*params[param_bits],
929 *params[param_morph],
930 *params[param_bypass] > 0.5,
931 *params[param_mode],
932 *params[param_dc],
933 *params[param_aa]);
934 samplereduction[0].set_params(*params[param_samples]);
935 samplereduction[1].set_params(*params[param_samples]);
936 lfo.set_params(*params[param_lforate], 0, 0.f, srate, 0.5f);
937 // calc lfo offsets
938 float rad = *params[param_lforange] / 2.f;
939 smin = std::max(*params[param_samples] - rad, 1.f);
940 float sun = *params[param_samples] - rad - smin;
941 float smax = std::min(*params[param_samples] + rad, 250.f);
942 float sov = *params[param_samples] + rad - smax;
943 smax -= sun;
944 smin -= sov;
945 sdiff = smax - smin;
948 void crusher_audio_module::set_sample_rate(uint32_t sr)
950 srate = sr;
951 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
952 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
953 meters.init(params, meter, clip, 4, srate);
954 bitreduction.set_sample_rate(srate);
957 uint32_t crusher_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
959 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
960 numsamples += offset;
961 if(bypassed) {
962 // everything bypassed
963 while(offset < numsamples) {
964 outs[0][offset] = ins[0][offset];
965 outs[1][offset] = ins[1][offset];
966 float values[] = {0, 0, 0, 0};
967 meters.process(values);
968 ++offset;
970 } else {
971 // process
972 uint32_t orig_numsamples = numsamples-offset;
973 uint32_t orig_offset = offset;
974 while(offset < numsamples) {
975 // cycle through samples
976 if (*params[param_lfo] > 0.5) {
977 samplereduction[0].set_params(smin + sdiff * (lfo.get_value() + 0.5));
978 samplereduction[1].set_params(smin + sdiff * (lfo.get_value() + 0.5));
980 outs[0][offset] = samplereduction[0].process(ins[0][offset] * *params[param_level_in]);
981 outs[1][offset] = samplereduction[1].process(ins[1][offset] * *params[param_level_in]);
982 outs[0][offset] = outs[0][offset] * *params[param_morph] + ins[0][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
983 outs[1][offset] = outs[1][offset] * *params[param_morph] + ins[1][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
984 outs[0][offset] = bitreduction.process(outs[0][offset]) * *params[param_level_out];
985 outs[1][offset] = bitreduction.process(outs[1][offset]) * *params[param_level_out];
986 float values[] = {ins[0][offset], ins[1][offset], outs[0][offset], outs[1][offset]};
987 meters.process(values);
988 // next sample
989 ++offset;
990 if (*params[param_lforate])
991 lfo.advance(1);
992 } // cycle trough samples
993 bypass.crossfade(ins, outs, 2, orig_offset, orig_numsamples);
995 meters.fall(numsamples);
996 return outputs_mask;
998 bool crusher_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
1000 return bitreduction.get_graph(subindex, phase, data, points, context, mode);
1002 bool crusher_audio_module::get_layers(int index, int generation, unsigned int &layers) const
1004 return bitreduction.get_layers(index, generation, layers);
1006 bool crusher_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
1008 return bitreduction.get_gridline(subindex, phase, pos, vertical, legend, context);