hz_to_note as primitive; line graph cross hair with much more information; new labels...
[calf.git] / src / modules_dist.cpp
blob9e0a1ab15ce8d625f04c4f36c73fe3c2a3ecf3a8
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 output_old = -1.f;
645 rms = 0.f;
646 mech_old = false;
647 transients.set_channels(channels);
650 void tapesimulator_audio_module::activate() {
651 active = true;
654 void tapesimulator_audio_module::deactivate() {
655 active = false;
658 void tapesimulator_audio_module::params_changed() {
659 if(*params[param_lp] != lp_old or *params[param_mechanical] != mech_old) {
660 lp[0][0].set_lp_rbj(*params[param_lp], 0.707, (float)srate);
661 lp[0][1].copy_coeffs(lp[0][0]);
662 lp[1][0].copy_coeffs(lp[0][0]);
663 lp[1][1].copy_coeffs(lp[0][0]);
664 lp_old = *params[param_lp];
665 mech_old = *params[param_mechanical] > 0.5;
667 transients.set_params(50.f / (*params[param_speed] + 1),
668 -0.05f / (*params[param_speed] + 1),
669 100.f,
670 0.f,
671 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);
675 if (*params[param_level_out] != output_old) {
676 output_old = *params[param_level_out];
677 redraw_output = true;
681 uint32_t tapesimulator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
682 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
683 uint32_t orig_offset = offset;
684 for(uint32_t i = offset; i < offset + numsamples; i++) {
685 float L = ins[0][i];
686 float R = ins[1][i];
687 float Lin = ins[0][i];
688 float Rin = ins[1][i];
689 if(bypassed) {
690 outs[0][i] = ins[0][i];
691 outs[1][i] = ins[1][i];
692 float values[] = {0, 0, 0, 0};
693 meters.process(values);
694 } else {
695 // transients
696 float inL = 0;
697 float inR = 0;
698 if(*params[param_magnetical] > 0.5f) {
699 float values[] = {L, R};
700 transients.process(values, (L + R) / 2.f);
701 L = values[0];
702 R = values[1];
705 // noise
706 if (*params[param_noise]) {
707 float Lnoise = rand() % 2 - 1;
708 float Rnoise = rand() % 2 - 1;
709 Lnoise = noisefilters[0][2].process(noisefilters[0][1].process(noisefilters[0][0].process(Lnoise)));
710 Rnoise = noisefilters[1][2].process(noisefilters[1][1].process(noisefilters[1][0].process(Rnoise)));
711 L += Lnoise * *params[param_noise] / 12.f;
712 R += Rnoise * *params[param_noise] / 12.f;
715 // lfo filters / phasing
716 if (*params[param_mechanical]) {
717 // filtering
718 float freqL1 = *params[param_lp] * (1 - ((lfo1.get_value() + 1) * 0.3 * *params[param_mechanical]));
719 float freqL2 = *params[param_lp] * (1 - ((lfo2.get_value() + 1) * 0.2 * *params[param_mechanical]));
721 float freqR1 = *params[param_lp] * (1 - ((lfo1.get_value() * -1 + 1) * 0.3 * *params[param_mechanical]));
722 float freqR2 = *params[param_lp] * (1 - ((lfo2.get_value() * -1 + 1) * 0.2 * *params[param_mechanical]));
724 lp[0][0].set_lp_rbj(freqL1, 0.707, (float)srate);
725 lp[0][1].set_lp_rbj(freqL2, 0.707, (float)srate);
727 lp[1][0].set_lp_rbj(freqR1, 0.707, (float)srate);
728 lp[1][1].set_lp_rbj(freqR2, 0.707, (float)srate);
730 // phasing
731 float _phase = lfo1.get_value() * *params[param_mechanical] * -36;
733 float _phase_cos_coef = cos(_phase / 180 * M_PI);
734 float _phase_sin_coef = sin(_phase / 180 * M_PI);
736 float _l = L * _phase_cos_coef - R * _phase_sin_coef;
737 float _r = L * _phase_sin_coef + R * _phase_cos_coef;
738 L = _l;
739 R = _r;
742 // gain
743 L *= *params[param_level_in];
744 R *= *params[param_level_in];
746 inL = L;
747 inR = R;
749 // save for drawing input/output curve
750 float Lc = L;
751 float Rc = R;
752 float Lo = L;
753 float Ro = R;
755 // filter
756 if (*params[param_post] < 0.5) {
757 L = lp[0][1].process(lp[0][0].process(L));
758 R = lp[1][1].process(lp[1][0].process(R));
761 // distortion
762 if (L) L = L / fabs(L) * (1 - exp((-1) * 3 * fabs(L)));
763 if (R) R = R / fabs(R) * (1 - exp((-1) * 3 * fabs(R)));
765 if (Lo) Lo = Lo / fabs(Lo) * (1 - exp((-1) * 3 * fabs(Lo)));
766 if (Ro) Ro = Ro / fabs(Ro) * (1 - exp((-1) * 3 * fabs(Ro)));
768 // filter
769 if (*params[param_post] >= 0.5) {
770 L = lp[0][1].process(lp[0][0].process(L));
771 R = lp[1][1].process(lp[1][0].process(R));
774 // mix
775 L = L * *params[param_mix] + Lin * (*params[param_mix] * -1 + 1);
776 R = R * *params[param_mix] + Rin * (*params[param_mix] * -1 + 1);
778 // levels out
779 L *= *params[param_level_out];
780 R *= *params[param_level_out];
782 // output
783 outs[0][i] = L;
784 outs[1][i] = R;
786 // sanitize filters
787 lp[0][0].sanitize();
788 lp[1][0].sanitize();
789 lp[0][1].sanitize();
790 lp[1][1].sanitize();
792 // LFO's should go on
793 lfo1.advance(1);
794 lfo2.advance(1);
796 // dot
797 rms = std::max((double)rms, (fabs(Lo) + fabs(Ro)) / 2);
798 input = std::max((double)input, (fabs(Lc) + fabs(Rc)) / 2);
800 float values[] = {inL, inR, outs[0][i], outs[1][i]};
801 meters.process(values);
804 if (bypassed)
805 bypass.crossfade(ins, outs, 2, orig_offset, numsamples);
806 meters.fall(numsamples);
807 return outputs_mask;
810 void tapesimulator_audio_module::set_sample_rate(uint32_t sr)
812 srate = sr;
813 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
814 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
815 meters.init(params, meter, clip, 4, srate);
816 transients.set_sample_rate(srate);
817 noisefilters[0][0].set_hp_rbj(120.f, 0.707, (float)srate);
818 noisefilters[1][0].copy_coeffs(noisefilters[0][0]);
819 noisefilters[0][1].set_lp_rbj(5500.f, 0.707, (float)srate);
820 noisefilters[1][1].copy_coeffs(noisefilters[0][1]);
821 noisefilters[0][2].set_highshelf_rbj(1000.f, 0.707, 0.5, (float)srate);
822 noisefilters[1][2].copy_coeffs(noisefilters[0][2]);
825 bool tapesimulator_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
827 if (subindex > 1)
828 return false;
829 if(index == param_lp and phase) {
830 set_channel_color(context, subindex);
831 return ::get_graph(*this, subindex, data, points);
832 } else if (index == param_level_in and !phase) {
833 if (!subindex) {
834 context->set_source_rgba(0.15, 0.2, 0.0, 0.3);
835 context->set_line_width(1);
837 for (int i = 0; i < points; i++) {
838 if (!subindex) {
839 float input = dB_grid_inv(-1.0 + (float)i * 2.0 / ((float)points - 1.f));
840 printf("%d %.4f\n", i,input);
841 data[i] = dB_grid(input);
842 } else {
843 float output = 1 - exp(-3 * (pow(2, -10 + 14 * (float)i / (float) points)));
844 data[i] = dB_grid(output * *params[param_level_out]);
847 return true;
849 return false;
851 float tapesimulator_audio_module::freq_gain(int index, double freq) const
853 return lp[index][0].freq_gain(freq, srate) * lp[index][1].freq_gain(freq, srate);
856 bool tapesimulator_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
858 if(!active or phase)
859 return false;
860 if (index == param_level_in) {
861 bool tmp;
862 vertical = (subindex & 1) != 0;
863 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
864 if (result && vertical) {
865 if ((subindex & 4) && !legend.empty()) {
866 legend = "";
868 else {
869 size_t pos = legend.find(" dB");
870 if (pos != std::string::npos)
871 legend.erase(pos);
873 pos = 0.5 + 0.5 * pos;
875 return result;
876 } else if (index == param_lp) {
877 return get_freq_gridline(subindex, pos, vertical, legend, context);
879 return false;
881 bool tapesimulator_audio_module::get_dot(int index, int subindex, int phase, float &x, float &y, int &size, cairo_iface *context) const
883 if (index == param_level_in and !subindex and phase) {
884 x = log(input) / log(2) / 14.f + 5.f / 7.f;
885 y = dB_grid(rms * *params[param_level_out]);
886 rms = 0.f;
887 input = 0.f;
888 return true;
890 return false;
892 bool tapesimulator_audio_module::get_layers(int index, int generation, unsigned int &layers) const
894 layers = 0;
895 // always draw grid on cache if surfaces are new on both widgets
896 if (!generation)
897 layers |= LG_CACHE_GRID;
898 // compression: dot in realtime, graphs as cache on new surfaces
899 if (index == param_level_in and (!generation or redraw_output)) {
900 layers |= LG_CACHE_GRAPH;
901 redraw_output = false;
903 if (index == param_level_in)
904 layers |= LG_REALTIME_DOT;
905 // frequency: both graphs in realtime
906 if (index == param_lp)
907 layers |= LG_REALTIME_GRAPH;
908 // draw always
909 return true;
914 /**********************************************************************
915 * CRUSHER by Markus Schmidt and Christian Holschuh
916 **********************************************************************/
919 crusher_audio_module::crusher_audio_module()
921 smin = sdiff = 0.f;
924 void crusher_audio_module::activate()
926 lfo.activate();
928 void crusher_audio_module::deactivate()
930 lfo.deactivate();
933 void crusher_audio_module::params_changed()
935 bitreduction.set_params(*params[param_bits],
936 *params[param_morph],
937 *params[param_bypass] > 0.5,
938 *params[param_mode],
939 *params[param_dc],
940 *params[param_aa]);
941 samplereduction[0].set_params(*params[param_samples]);
942 samplereduction[1].set_params(*params[param_samples]);
943 lfo.set_params(*params[param_lforate], 0, 0.f, srate, 0.5f);
944 // calc lfo offsets
945 float rad = *params[param_lforange] / 2.f;
946 smin = std::max(*params[param_samples] - rad, 1.f);
947 float sun = *params[param_samples] - rad - smin;
948 float smax = std::min(*params[param_samples] + rad, 250.f);
949 float sov = *params[param_samples] + rad - smax;
950 smax -= sun;
951 smin -= sov;
952 sdiff = smax - smin;
955 void crusher_audio_module::set_sample_rate(uint32_t sr)
957 srate = sr;
958 int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
959 int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
960 meters.init(params, meter, clip, 4, srate);
961 bitreduction.set_sample_rate(srate);
964 uint32_t crusher_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
966 bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
967 numsamples += offset;
968 if(bypassed) {
969 // everything bypassed
970 while(offset < numsamples) {
971 outs[0][offset] = ins[0][offset];
972 outs[1][offset] = ins[1][offset];
973 float values[] = {0, 0, 0, 0};
974 meters.process(values);
975 ++offset;
977 } else {
978 // process
979 uint32_t orig_numsamples = numsamples-offset;
980 uint32_t orig_offset = offset;
981 while(offset < numsamples) {
982 // cycle through samples
983 if (*params[param_lfo] > 0.5) {
984 samplereduction[0].set_params(smin + sdiff * (lfo.get_value() + 0.5));
985 samplereduction[1].set_params(smin + sdiff * (lfo.get_value() + 0.5));
987 outs[0][offset] = samplereduction[0].process(ins[0][offset] * *params[param_level_in]);
988 outs[1][offset] = samplereduction[1].process(ins[1][offset] * *params[param_level_in]);
989 outs[0][offset] = outs[0][offset] * *params[param_morph] + ins[0][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
990 outs[1][offset] = outs[1][offset] * *params[param_morph] + ins[1][offset] * (*params[param_morph] * -1 + 1) * *params[param_level_in];
991 outs[0][offset] = bitreduction.process(outs[0][offset]) * *params[param_level_out];
992 outs[1][offset] = bitreduction.process(outs[1][offset]) * *params[param_level_out];
993 float values[] = {ins[0][offset], ins[1][offset], outs[0][offset], outs[1][offset]};
994 meters.process(values);
995 // next sample
996 ++offset;
997 if (*params[param_lforate])
998 lfo.advance(1);
999 } // cycle trough samples
1000 bypass.crossfade(ins, outs, 2, orig_offset, orig_numsamples);
1002 meters.fall(numsamples);
1003 return outputs_mask;
1005 bool crusher_audio_module::get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const
1007 return bitreduction.get_graph(subindex, phase, data, points, context, mode);
1009 bool crusher_audio_module::get_layers(int index, int generation, unsigned int &layers) const
1011 return bitreduction.get_layers(index, generation, layers);
1013 bool crusher_audio_module::get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const
1015 return bitreduction.get_gridline(subindex, phase, pos, vertical, legend, context);