+ DSP primitives: fix a rather stupid bug in clamping functions
[calf.git] / src / modules_dsp.cpp
blob3f6b720a4f4e73f169c1208cb6789581beb838a8
1 /* Calf DSP Library
2 * Example audio modules - DSP code
4 * Copyright (C) 2001-2008 Krzysztof Foltman
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 <config.h>
22 #include <assert.h>
23 #include <limits.h>
24 #include <memory.h>
25 #if USE_JACK
26 #include <jack/jack.h>
27 #endif
28 #include <calf/giface.h>
29 #include <calf/modules.h>
30 #include <calf/modules_dev.h>
32 using namespace dsp;
33 using namespace calf_plugins;
35 /// convert amplitude value to normalized grid-ish value (0dB = 0.5, 30dB = 1.0, -30 dB = 0.0, -60dB = -0.5, -90dB = -1.0)
36 static inline float dB_grid(float amp)
38 return log(amp) * (1.0 / log(256.0)) + 0.4;
41 template<class Fx>
42 static bool get_graph(Fx &fx, int subindex, float *data, int points)
44 for (int i = 0; i < points; i++)
46 typedef std::complex<double> cfloat;
47 double freq = 20.0 * pow (20000.0 / 20.0, i * 1.0 / points);
48 data[i] = dB_grid(fx.freq_gain(subindex, freq, fx.srate));
50 return true;
53 /// convert normalized grid-ish value back to amplitude value
54 static inline float dB_grid_inv(float pos)
56 return pow(256.0, pos - 0.4);
59 static void set_channel_color(cairo_iface *context, int channel)
61 if (channel & 1)
62 context->set_source_rgba(0.35, 0.4, 0.2, 1);
63 else
64 context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
65 context->set_line_width(1.5);
68 static bool get_freq_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context, bool use_frequencies = true)
70 if (subindex < 0 )
71 return false;
72 if (use_frequencies)
74 if (subindex < 28)
76 vertical = true;
77 if (subindex == 9) legend = "100 Hz";
78 if (subindex == 18) legend = "1 kHz";
79 if (subindex == 27) legend = "10 kHz";
80 float freq = 100;
81 if (subindex < 9)
82 freq = 10 * (subindex + 1);
83 else if (subindex < 18)
84 freq = 100 * (subindex - 9 + 1);
85 else if (subindex < 27)
86 freq = 1000 * (subindex - 18 + 1);
87 else
88 freq = 10000 * (subindex - 27 + 1);
89 pos = log(freq / 20.0) / log(1000);
90 if (!legend.empty())
91 context->set_source_rgba(0, 0, 0, 0.2);
92 else
93 context->set_source_rgba(0, 0, 0, 0.1);
94 return true;
96 subindex -= 28;
98 if (subindex >= 32)
99 return false;
100 float gain = 16.0 / (1 << subindex);
101 pos = dB_grid(gain);
102 if (pos < -1)
103 return false;
104 if (subindex != 4)
105 context->set_source_rgba(0, 0, 0, subindex & 1 ? 0.1 : 0.2);
106 if (!(subindex & 1))
108 std::stringstream ss;
109 ss << (24 - 6 * subindex) << " dB";
110 legend = ss.str();
112 vertical = false;
113 return true;
116 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
118 bool frequency_response_line_graph::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
120 return get_freq_gridline(subindex, pos, vertical, legend, context);
123 int frequency_response_line_graph::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
125 subindex_graph = 0;
126 subindex_dot = 0;
127 subindex_gridline = generation ? INT_MAX : 0;
128 return 1;
131 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
133 void flanger_audio_module::activate() {
134 left.reset();
135 right.reset();
136 last_r_phase = *params[par_stereo] * (1.f / 360.f);
137 left.reset_phase(0.f);
138 right.reset_phase(last_r_phase);
139 is_active = true;
142 void flanger_audio_module::set_sample_rate(uint32_t sr) {
143 srate = sr;
144 left.setup(sr);
145 right.setup(sr);
148 void flanger_audio_module::deactivate() {
149 is_active = false;
152 bool flanger_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
154 if (!is_active)
155 return false;
156 if (index == par_delay && subindex < 2)
158 set_channel_color(context, subindex);
159 return ::get_graph(*this, subindex, data, points);
161 return false;
164 float flanger_audio_module::freq_gain(int subindex, float freq, float srate)
166 return (subindex ? right : left).freq_gain(freq, srate);
169 ///////////////////////////////////////////////////////////////////////////////////////////////
171 void phaser_audio_module::set_sample_rate(uint32_t sr)
173 srate = sr;
174 left.setup(sr);
175 right.setup(sr);
178 void phaser_audio_module::activate()
180 is_active = true;
181 left.reset();
182 right.reset();
183 last_r_phase = *params[par_stereo] * (1.f / 360.f);
184 left.reset_phase(0.f);
185 right.reset_phase(last_r_phase);
188 void phaser_audio_module::deactivate()
190 is_active = false;
193 bool phaser_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
195 if (!is_active)
196 return false;
197 if (subindex < 2)
199 set_channel_color(context, subindex);
200 return ::get_graph(*this, subindex, data, points);
202 return false;
205 float phaser_audio_module::freq_gain(int subindex, float freq, float srate)
207 return (subindex ? right : left).freq_gain(freq, srate);
210 bool phaser_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
212 return get_freq_gridline(subindex, pos, vertical, legend, context);
215 ///////////////////////////////////////////////////////////////////////////////////////////////
217 void reverb_audio_module::activate()
219 reverb.reset();
222 void reverb_audio_module::deactivate()
226 void reverb_audio_module::set_sample_rate(uint32_t sr)
228 srate = sr;
229 reverb.setup(sr);
230 amount.set_sample_rate(sr);
233 ///////////////////////////////////////////////////////////////////////////////////////////////
235 bool filter_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
237 if (!is_active)
238 return false;
239 if (index == par_cutoff && !subindex) {
240 context->set_line_width(1.5);
241 return ::get_graph(*this, subindex, data, points);
243 return false;
246 int filter_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
248 if (fabs(inertia_cutoff.get_last() - old_cutoff) + 100 * fabs(inertia_resonance.get_last() - old_resonance) + fabs(*params[par_mode] - old_mode) > 0.1f)
250 old_cutoff = inertia_cutoff.get_last();
251 old_resonance = inertia_resonance.get_last();
252 old_mode = *params[par_mode];
253 last_generation++;
254 subindex_graph = 0;
255 subindex_dot = INT_MAX;
256 subindex_gridline = INT_MAX;
258 else {
259 subindex_graph = 0;
260 subindex_dot = subindex_gridline = generation ? INT_MAX : 0;
262 if (generation == last_calculated_generation)
263 subindex_graph = INT_MAX;
264 return last_generation;
268 ///////////////////////////////////////////////////////////////////////////////////////////////
270 bool filterclavier_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
272 if (!is_active || index != par_mode) {
273 return false;
275 if (!subindex) {
276 context->set_line_width(1.5);
277 return ::get_graph(*this, subindex, data, points);
279 return false;
282 ///////////////////////////////////////////////////////////////////////////////////////////////
284 rotary_speaker_audio_module::rotary_speaker_audio_module()
286 mwhl_value = hold_value = 0.f;
287 phase_h = phase_l = 0.f;
288 aspeed_l = 1.f;
289 aspeed_h = 1.f;
290 dspeed = 0.f;
293 void rotary_speaker_audio_module::set_sample_rate(uint32_t sr)
295 srate = sr;
296 setup();
299 void rotary_speaker_audio_module::setup()
301 crossover1l.set_lp_rbj(800.f, 0.7, (float)srate);
302 crossover1r.set_lp_rbj(800.f, 0.7, (float)srate);
303 crossover2l.set_hp_rbj(800.f, 0.7, (float)srate);
304 crossover2r.set_hp_rbj(800.f, 0.7, (float)srate);
307 void rotary_speaker_audio_module::activate()
309 phase_h = phase_l = 0.f;
310 maspeed_h = maspeed_l = 0.f;
311 setup();
314 void rotary_speaker_audio_module::deactivate()
318 void rotary_speaker_audio_module::control_change(int ctl, int val)
320 if (vibrato_mode == 3 && ctl == 64)
322 hold_value = val / 127.f;
323 set_vibrato();
324 return;
326 if (vibrato_mode == 4 && ctl == 1)
328 mwhl_value = val / 127.f;
329 set_vibrato();
330 return;
334 ///////////////////////////////////////////////////////////////////////////////////////////////
336 void multichorus_audio_module::activate()
338 is_active = true;
339 params_changed();
342 void multichorus_audio_module::deactivate()
344 is_active = false;
347 void multichorus_audio_module::set_sample_rate(uint32_t sr) {
348 srate = sr;
349 left.setup(sr);
350 right.setup(sr);
353 bool multichorus_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
355 if (!is_active)
356 return false;
357 int nvoices = (int)*params[par_voices];
358 if (index == par_delay && subindex < 3)
360 if (subindex < 2)
361 set_channel_color(context, subindex);
362 else {
363 context->set_source_rgba(0.35, 0.4, 0.2);
364 context->set_line_width(1.0);
366 return ::get_graph(*this, subindex, data, points);
368 if (index == par_rate && subindex < nvoices) {
369 sine_multi_lfo<float, 8> &lfo = left.lfo;
370 for (int i = 0; i < points; i++) {
371 float phase = i * 2 * M_PI / points;
372 // original -65536 to 65535 value
373 float orig = subindex * lfo.voice_offset + ((lfo.voice_depth >> (30-13)) * 65536.0 * (0.95 * sin(phase) + 1)/ 8192.0) - 65536;
374 // scale to -1..1
375 data[i] = orig / 65536.0;
377 return true;
379 return false;
382 bool multichorus_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
384 int voice = subindex >> 1;
385 int nvoices = (int)*params[par_voices];
386 if ((index != par_rate && index != par_depth) || voice >= nvoices)
387 return false;
389 float unit = (1 - *params[par_overlap]);
390 float scw = 1 + unit * (nvoices - 1);
391 set_channel_color(context, subindex);
392 sine_multi_lfo<float, 8> &lfo = (subindex & 1 ? right : left).lfo;
393 if (index == par_rate)
395 x = (double)(lfo.phase + lfo.vphase * voice) / 4096.0;
396 y = 0.95 * sin(x * 2 * M_PI);
397 y = (voice * unit + (y + 1) / 2) / scw * 2 - 1;
399 else
401 double ph = (double)(lfo.phase + lfo.vphase * voice) / 4096.0;
402 x = 0.5 + 0.5 * sin(ph * 2 * M_PI);
403 y = subindex & 1 ? -0.75 : 0.75;
404 x = (voice * unit + x) / scw;
406 return true;
409 bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
411 if (index == par_rate && !subindex)
413 pos = 0;
414 vertical = false;
415 return true;
417 if (index == par_delay)
418 return get_freq_gridline(subindex, pos, vertical, legend, context);
419 return false;
422 float multichorus_audio_module::freq_gain(int subindex, float freq, float srate)
424 if (subindex == 2)
425 return *params[par_amount] * left.post.freq_gain(freq, srate);
426 return (subindex ? right : left).freq_gain(freq, srate);
429 ///////////////////////////////////////////////////////////////////////////////////////////////
431 compressor_audio_module::compressor_audio_module()
433 is_active = false;
434 srate = 0;
435 last_generation = 0;
438 void compressor_audio_module::activate()
440 is_active = true;
441 linSlope = 0.f;
442 peak = 0.f;
443 clip = 0.f;
446 void compressor_audio_module::deactivate()
448 is_active = false;
451 void compressor_audio_module::set_sample_rate(uint32_t sr)
453 srate = sr;
454 awL.set(sr);
455 awR.set(sr);
458 bool compressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
460 if (!is_active)
461 return false;
462 if (subindex > 1) // 1
463 return false;
464 for (int i = 0; i < points; i++)
466 float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
467 float output = output_level(input);
468 if (subindex == 0)
469 data[i] = dB_grid(input);
470 else
471 data[i] = dB_grid(output);
473 if (subindex == (*params[param_bypass] > 0.5f ? 1 : 0))
474 context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
475 else {
476 context->set_source_rgba(0.35, 0.4, 0.2, 1);
477 context->set_line_width(2);
479 return true;
482 bool compressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
484 if (!is_active)
485 return false;
486 if (!subindex)
488 bool rms = *params[param_detection] == 0;
489 float det = rms ? sqrt(detected) : detected;
490 x = 0.5 + 0.5 * dB_grid(det);
491 y = dB_grid(*params[param_bypass] > 0.5f ? det : output_level(det));
492 return *params[param_bypass] > 0.5f ? false : true;
494 return false;
497 bool compressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
499 bool tmp;
500 vertical = (subindex & 1) != 0;
501 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
502 if (result && vertical) {
503 if ((subindex & 4) && !legend.empty()) {
504 legend = "";
506 else {
507 size_t pos = legend.find(" dB");
508 if (pos != std::string::npos)
509 legend.erase(pos);
511 pos = 0.5 + 0.5 * pos;
513 return result;
516 // In case of doubt: this function is written by Thor. I just moved it to this file, damaging
517 // the output of "git annotate" in the process.
518 uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
520 bool bypass = *params[param_bypass] > 0.5f;
522 if(bypass) {
523 numsamples += offset;
524 while(offset < numsamples) {
525 outs[0][offset] = ins[0][offset];
526 outs[1][offset] = ins[1][offset];
527 ++offset;
530 if(params[param_compression] != NULL) {
531 *params[param_compression] = 1.f;
534 if(params[param_clip] != NULL) {
535 *params[param_clip] = 0.f;
538 if(params[param_peak] != NULL) {
539 *params[param_peak] = 0.f;
542 return inputs_mask;
545 bool rms = *params[param_detection] == 0;
546 bool average = *params[param_stereo_link] == 0;
547 int aweighting = fastf2i_drm(*params[param_aweighting]);
548 float linThreshold = *params[param_threshold];
549 ratio = *params[param_ratio];
550 float attack = *params[param_attack];
551 float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
552 float release = *params[param_release];
553 float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
554 makeup = *params[param_makeup];
555 knee = *params[param_knee];
557 float linKneeSqrt = sqrt(knee);
558 linKneeStart = linThreshold / linKneeSqrt;
559 adjKneeStart = linKneeStart*linKneeStart;
560 float linKneeStop = linThreshold * linKneeSqrt;
562 threshold = log(linThreshold);
563 kneeStart = log(linKneeStart);
564 kneeStop = log(linKneeStop);
565 compressedKneeStop = (kneeStop - threshold) / ratio + threshold;
567 if (aweighting >= 2)
569 bpL.set_highshelf_rbj(5000, 0.707, 10 << (aweighting - 2), srate);
570 bpR.copy_coeffs(bpL);
571 bpL.sanitize();
572 bpR.sanitize();
575 numsamples += offset;
577 float compression = 1.f;
579 peak -= peak * 5.f * numsamples / srate;
581 clip -= std::min(clip, numsamples);
583 while(offset < numsamples) {
584 float left = ins[0][offset];
585 float right = ins[1][offset];
587 if(aweighting == 1) {
588 left = awL.process(left);
589 right = awR.process(right);
591 else if(aweighting >= 2) {
592 left = bpL.process(left);
593 right = bpR.process(right);
596 float absample = average ? (fabs(left) + fabs(right)) * 0.5f : std::max(fabs(left), fabs(right));
597 if(rms) absample *= absample;
599 linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
601 float gain = 1.f;
603 if(linSlope > 0.f) {
604 gain = output_gain(linSlope, rms);
607 compression = gain;
608 gain *= makeup;
610 float outL = ins[0][offset] * gain;
611 float outR = ins[1][offset] * gain;
613 outs[0][offset] = outL;
614 outs[1][offset] = outR;
616 ++offset;
618 float maxLR = std::max(fabs(outL), fabs(outR));
620 if(maxLR > 1.f) clip = srate >> 3; /* blink clip LED for 125 ms */
622 if(maxLR > peak) {
623 peak = maxLR;
627 detected = linSlope;
629 if(params[param_compression] != NULL) {
630 *params[param_compression] = compression;
633 if(params[param_clip] != NULL) {
634 *params[param_clip] = clip;
637 if(params[param_peak] != NULL) {
638 *params[param_peak] = peak;
641 return inputs_mask;
645 /// Multibandcompressor by Markus Schmidt
647 /// This module splits the signal in four different bands
648 /// and sends them through multiple filters (implemented by
649 /// Krzysztof). They are processed by a compressing routine
650 /// (implemented by Thor) afterwards and summed up to the
651 /// final output again.
652 ///////////////////////////////////////////////////////////////////////////////////////////////
654 multibandcompressor_audio_module::multibandcompressor_audio_module()
656 is_active = false;
657 srate = 0;
658 // zero all displays
659 clip_inL = 0.f;
660 clip_inR = 0.f;
661 clip_outL = 0.f;
662 clip_outR = 0.f;
663 meter_inL = 0.f;
664 meter_inR = 0.f;
665 meter_outL = 0.f;
666 meter_outR = 0.f;
669 void multibandcompressor_audio_module::activate()
671 is_active = true;
672 // set all filters and strips
673 params_changed();
674 // activate all strips
675 for (int j = 0; j < strips; j ++) {
676 strip[j].activate();
677 strip[j].id = j;
681 void multibandcompressor_audio_module::deactivate()
683 is_active = false;
684 // deactivate all strips
685 for (int j = 0; j < strips; j ++) {
686 strip[j].deactivate();
690 void multibandcompressor_audio_module::params_changed()
692 // set the params of all filters
693 if(*params[param_freq0] != freq_old[0] or *params[param_sep0] != sep_old[0] or *params[param_q0] != q_old[0]) {
694 lpL0.set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate);
695 lpR0.set_lp_rbj((float)(*params[param_freq0] * (1 - *params[param_sep0])), *params[param_q0], (float)srate);
696 hpL0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate);
697 hpR0.set_hp_rbj((float)(*params[param_freq0] * (1 + *params[param_sep0])), *params[param_q0], (float)srate);
698 freq_old[0] = *params[param_freq0];
699 sep_old[0] = *params[param_sep2];
700 q_old[0] = *params[param_q2];
702 if(*params[param_freq1] != freq_old[1] or *params[param_sep1] != sep_old[1] or *params[param_q1] != q_old[1]) {
703 lpL1.set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate);
704 lpR1.set_lp_rbj((float)(*params[param_freq1] * (1 - *params[param_sep1])), *params[param_q1], (float)srate);
705 hpL1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate);
706 hpR1.set_hp_rbj((float)(*params[param_freq1] * (1 + *params[param_sep1])), *params[param_q1], (float)srate);
707 freq_old[1] = *params[param_freq1];
708 sep_old[1] = *params[param_sep2];
709 q_old[1] = *params[param_q2];
711 if(*params[param_freq2] != freq_old[2] or *params[param_sep2] != sep_old[2] or *params[param_q2] != q_old[2]) {
712 lpL2.set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate);
713 lpR2.set_lp_rbj((float)(*params[param_freq2] * (1 - *params[param_sep2])), *params[param_q2], (float)srate);
714 hpL2.set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate);
715 hpR2.set_hp_rbj((float)(*params[param_freq2] * (1 + *params[param_sep2])), *params[param_q2], (float)srate);
716 freq_old[2] = *params[param_freq2];
717 sep_old[2] = *params[param_sep2];
718 q_old[2] = *params[param_q2];
720 // set the params of all strips
721 for (int j = 0; j < strips; j ++) {
722 switch (j) {
723 case 0:
724 strip[j].set_params(*params[param_attack0], *params[param_release0], *params[param_threshold0], *params[param_ratio0], *params[param_knee0], *params[param_makeup0], *params[param_detection0], *params[param_bypass0], *params[param_mute0]);
725 break;
726 case 1:
727 strip[j].set_params(*params[param_attack1], *params[param_release1], *params[param_threshold1], *params[param_ratio1], *params[param_knee1], *params[param_makeup1], *params[param_detection1], *params[param_bypass1], *params[param_mute1]);
728 break;
729 case 2:
730 strip[j].set_params(*params[param_attack2], *params[param_release2], *params[param_threshold2], *params[param_ratio2], *params[param_knee2], *params[param_makeup2], *params[param_detection2], *params[param_bypass2], *params[param_mute2]);
731 break;
732 case 3:
733 strip[j].set_params(*params[param_attack3], *params[param_release3], *params[param_threshold3], *params[param_ratio3], *params[param_knee3], *params[param_makeup3], *params[param_detection3], *params[param_bypass3], *params[param_mute3]);
734 break;
739 void multibandcompressor_audio_module::set_sample_rate(uint32_t sr)
741 srate = sr;
742 // set srate of all strips
743 for (int j = 0; j < strips; j ++) {
744 strip[j].set_sample_rate(srate);
748 uint32_t multibandcompressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
750 bool bypass = *params[param_bypass] > 0.5f;
751 numsamples += offset;
752 if(bypass) {
753 // everything bypassed
754 while(offset < numsamples) {
755 outs[0][offset] = ins[0][offset];
756 outs[1][offset] = ins[1][offset];
757 ++offset;
759 // displays, too
760 clip_inL = 0.f;
761 clip_inR = 0.f;
762 clip_outL = 0.f;
763 clip_outR = 0.f;
764 meter_inL = 0.f;
765 meter_inR = 0.f;
766 meter_outL = 0.f;
767 meter_outR = 0.f;
768 } else {
769 // process all strips
771 // determine mute state of strips
772 mute[0] = *params[param_mute0] > 0.f ? true : false;
773 mute[1] = *params[param_mute1] > 0.f ? true : false;
774 mute[2] = *params[param_mute2] > 0.f ? true : false;
775 mute[3] = *params[param_mute3] > 0.f ? true : false;
777 // let meters fall a bit
778 clip_inL -= std::min(clip_inL, numsamples);
779 clip_inR -= std::min(clip_inR, numsamples);
780 clip_outL -= std::min(clip_outL, numsamples);
781 clip_outR -= std::min(clip_outR, numsamples);
782 meter_inL -= meter_inL * 2.5 * numsamples / srate;
783 meter_inR -= meter_inR * 2.5 * numsamples / srate;
784 meter_outL -= meter_outL * 2.5 * numsamples / srate;
785 meter_outR -= meter_outR * 2.5 * numsamples / srate;
787 while(offset < numsamples) {
788 // cycle through samples
789 float inL = ins[0][offset];
790 float inR = ins[1][offset];
791 // in level
792 inR *= *params[param_level_in];
793 inL *= *params[param_level_in];
794 // out vars
795 float outL = 0.f;
796 float outR = 0.f;
797 for (int i = 0; i < strips; i ++) {
798 // cycle trough strips
799 if (!mute[i]) {
800 // strip unmuted
801 float left = inL;
802 float right = inR;
803 // send trough filters
804 switch (i) {
805 case 0:
806 left = lpL0.process(left);
807 right = lpR0.process(right);
808 lpL0.sanitize();
809 lpR0.sanitize();
810 break;
811 case 1:
812 left = lpL1.process(left);
813 right = lpR1.process(right);
814 left = hpL0.process(left);
815 right = hpR0.process(right);
816 lpL1.sanitize();
817 lpR1.sanitize();
818 hpL0.sanitize();
819 hpR0.sanitize();
820 break;
821 case 2:
822 left = lpL2.process(left);
823 right = lpR2.process(right);
824 left = hpL1.process(left);
825 right = hpR1.process(right);
826 lpL2.sanitize();
827 lpR2.sanitize();
828 hpL1.sanitize();
829 hpR1.sanitize();
830 break;
831 case 3:
832 left = hpL2.process(left);
833 right = hpR2.process(right);
834 hpL2.sanitize();
835 hpR2.sanitize();
836 break;
838 // process gain reduction
839 strip[i].process(left, right);
840 // sum up output
841 outL += left;
842 outR += right;
843 } else {
844 // strip muted
849 } // process single strip
851 // even out filters gain reduction
852 // 3dB - levelled manually (based on default sep and q settings)
853 outL *= 1.414213562;
854 outR *= 1.414213562;
856 // out level
857 outL *= *params[param_level_out];
858 outR *= *params[param_level_out];
860 // send to output
861 outs[0][offset] = outL;
862 outs[1][offset] = outR;
864 // clip LED's
865 if(inL > 1.f) {
866 clip_inL = srate >> 3;
868 if(inR > 1.f) {
869 clip_inR = srate >> 3;
871 if(outL > 1.f) {
872 clip_outL = srate >> 3;
874 if(outR > 1.f) {
875 clip_outR = srate >> 3;
877 // rise up in / out meters
878 if(inL > meter_inL) {
879 meter_inL = inL;
881 if(inR > meter_inR) {
882 meter_inR = inR;
884 if(outL > meter_outL) {
885 meter_outL = outL;
887 if(outR > meter_outR) {
888 meter_outR = outR;
890 // next sample
891 ++offset;
892 } // cycle trough samples
894 } // process all strips (no bypass)
896 // draw meters
897 if(params[param_clip_inL] != NULL) {
898 *params[param_clip_inL] = clip_inL;
900 if(params[param_clip_inR] != NULL) {
901 *params[param_clip_inR] = clip_inR;
903 if(params[param_clip_outL] != NULL) {
904 *params[param_clip_outL] = clip_outL;
906 if(params[param_clip_outR] != NULL) {
907 *params[param_clip_outR] = clip_outR;
910 if(params[param_meter_inL] != NULL) {
911 *params[param_meter_inL] = meter_inL;
913 if(params[param_meter_inR] != NULL) {
914 *params[param_meter_inR] = meter_inR;
916 if(params[param_meter_outL] != NULL) {
917 *params[param_meter_outL] = meter_outL;
919 if(params[param_meter_outR] != NULL) {
920 *params[param_meter_outR] = meter_outR;
922 // draw strip meters
923 if(bypass > 0.5f) {
924 if(params[param_compression0] != NULL) {
925 *params[param_compression0] = 1.0f;
927 if(params[param_compression1] != NULL) {
928 *params[param_compression1] = 1.0f;
930 if(params[param_compression2] != NULL) {
931 *params[param_compression2] = 1.0f;
933 if(params[param_compression3] != NULL) {
934 *params[param_compression3] = 1.0f;
937 if(params[param_output0] != NULL) {
938 *params[param_output0] = 0.0f;
940 if(params[param_output1] != NULL) {
941 *params[param_output1] = 0.0f;
943 if(params[param_output2] != NULL) {
944 *params[param_output2] = 0.0f;
946 if(params[param_output3] != NULL) {
947 *params[param_output3] = 0.0f;
949 } else {
950 if(params[param_compression0] != NULL) {
951 *params[param_compression0] = strip[0].get_comp_level();
953 if(params[param_compression1] != NULL) {
954 *params[param_compression1] = strip[1].get_comp_level();
956 if(params[param_compression2] != NULL) {
957 *params[param_compression2] = strip[2].get_comp_level();
959 if(params[param_compression3] != NULL) {
960 *params[param_compression3] = strip[3].get_comp_level();
963 if(params[param_output0] != NULL) {
964 *params[param_output0] = strip[0].get_output_level();
966 if(params[param_output1] != NULL) {
967 *params[param_output1] = strip[1].get_output_level();
969 if(params[param_output2] != NULL) {
970 *params[param_output2] = strip[2].get_output_level();
972 if(params[param_output3] != NULL) {
973 *params[param_output3] = strip[3].get_output_level();
976 // whatever has to be returned x)
977 return outputs_mask;
979 bool multibandcompressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
981 // let's handle by the corresponding strip
982 switch (index) {
983 case param_compression0:
984 return strip[0].get_graph(subindex, data, points, context);
985 break;
986 case param_compression1:
987 return strip[1].get_graph(subindex, data, points, context);
988 break;
989 case param_compression2:
990 return strip[2].get_graph(subindex, data, points, context);
991 break;
992 case param_compression3:
993 return strip[3].get_graph(subindex, data, points, context);
994 break;
996 return false;
999 bool multibandcompressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
1001 // let's handle by the corresponding strip
1002 switch (index) {
1003 case param_compression0:
1004 return strip[0].get_dot(subindex, x, y, size, context);
1005 break;
1006 case param_compression1:
1007 return strip[1].get_dot(subindex, x, y, size, context);
1008 break;
1009 case param_compression2:
1010 return strip[2].get_dot(subindex, x, y, size, context);
1011 break;
1012 case param_compression3:
1013 return strip[3].get_dot(subindex, x, y, size, context);
1014 break;
1016 return false;
1019 bool multibandcompressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
1021 // let's handle by the corresponding strip
1022 switch (index) {
1023 case param_compression0:
1024 return strip[0].get_gridline(subindex, pos, vertical, legend, context);
1025 break;
1026 case param_compression1:
1027 return strip[1].get_gridline(subindex, pos, vertical, legend, context);
1028 break;
1029 case param_compression2:
1030 return strip[2].get_gridline(subindex, pos, vertical, legend, context);
1031 break;
1032 case param_compression3:
1033 return strip[3].get_gridline(subindex, pos, vertical, legend, context);
1034 break;
1036 return false;
1039 int multibandcompressor_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
1041 // let's handle by the corresponding strip
1042 switch (index) {
1043 case param_compression0:
1044 return strip[0].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
1045 break;
1046 case param_compression1:
1047 return strip[1].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
1048 break;
1049 case param_compression2:
1050 return strip[2].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
1051 break;
1052 case param_compression3:
1053 return strip[3].get_changed_offsets(generation, subindex_graph, subindex_dot, subindex_gridline);
1054 break;
1056 return 0;
1058 /// Gain reduction module implemented by Markus Schmidt
1059 /// Nearly all functions of this module are originally written
1060 /// by Thor, while some features have been stripped (mainly stereo linking
1061 /// and frequency correction as implemented in his Compressor above)
1062 /// To save some CPU.
1063 ////////////////////////////////////////////////////////////////////////////////
1064 gain_reduction_audio_module::gain_reduction_audio_module()
1066 is_active = false;
1067 last_generation = 0;
1070 void gain_reduction_audio_module::activate()
1072 is_active = true;
1073 linSlope = 0.f;
1074 meter_out = 0.f;
1075 meter_comp = 1.f;
1076 float l, r;
1077 l = r = 0.f;
1078 float byp = bypass;
1079 bypass = 0.0;
1080 process(l, r);
1081 bypass = byp;
1084 void gain_reduction_audio_module::deactivate()
1086 is_active = false;
1089 void gain_reduction_audio_module::process(float &left, float &right)
1091 float compression = 1.f;
1092 meter_out -= meter_out * 5.f * 1 / srate;
1093 if(bypass < 0.5f) {
1094 // this routine is mainly copied from thor's compressor module
1095 // greatest sounding compressor I've heard!
1096 bool rms = detection == 0;
1097 float linThreshold = threshold;
1098 float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
1099 float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
1100 float linKneeSqrt = sqrt(knee);
1101 linKneeStart = linThreshold / linKneeSqrt;
1102 adjKneeStart = linKneeStart*linKneeStart;
1103 float linKneeStop = linThreshold * linKneeSqrt;
1104 thres = log(linThreshold);
1105 kneeStart = log(linKneeStart);
1106 kneeStop = log(linKneeStop);
1107 compressedKneeStop = (kneeStop - thres) / ratio + thres;
1109 float absample = (fabs(left) + fabs(right)) * 0.5f;
1110 if(rms) absample *= absample;
1112 linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
1114 float gain = 1.f;
1116 if(linSlope > 0.f) {
1117 gain = output_gain(linSlope, rms);
1120 compression = gain;
1121 gain *= makeup;
1123 left *= gain;
1124 right *= gain;
1126 detected = rms ? sqrt(linSlope) : linSlope;
1129 float maxLR = std::max(fabs(left), fabs(right));
1131 if(maxLR > meter_out) {
1132 meter_out = maxLR;
1134 meter_comp = compression;
1137 float gain_reduction_audio_module::output_level(float slope) {
1138 return slope * output_gain(slope, false) * makeup;
1141 float gain_reduction_audio_module::output_gain(float linSlope, bool rms) {
1142 //this calculation is also thor's work
1143 if(linSlope > (rms ? adjKneeStart : linKneeStart)) {
1144 float slope = log(linSlope);
1145 if(rms) slope *= 0.5f;
1147 float gain = 0.f;
1148 float delta = 0.f;
1149 if(IS_FAKE_INFINITY(ratio)) {
1150 gain = thres;
1151 delta = 0.f;
1152 } else {
1153 gain = (slope - thres) / ratio + thres;
1154 delta = 1.f / ratio;
1157 if(knee > 1.f && slope < kneeStop) {
1158 gain = hermite_interpolation(slope, kneeStart, kneeStop, kneeStart, compressedKneeStop, 1.f, delta);
1161 return exp(gain - slope);
1164 return 1.f;
1167 void gain_reduction_audio_module::set_sample_rate(uint32_t sr)
1169 srate = sr;
1171 void gain_reduction_audio_module::set_params(float att, float rel, float thr, float rat, float kn, float mak, float det, float byp, float mu)
1173 // set all params
1174 attack = att;
1175 release = rel;
1176 threshold = thr;
1177 ratio = rat;
1178 knee = kn;
1179 makeup = mak;
1180 detection = det;
1181 bypass = byp;
1182 mute = mu;
1183 if(mute > 0.f) {
1184 meter_out = 0.f;
1185 meter_comp = 1.f;
1188 float gain_reduction_audio_module::get_output_level() {
1189 // returns output level (max(left, right))
1190 return meter_out;
1192 float gain_reduction_audio_module::get_comp_level() {
1193 // returns amount of compression
1194 return meter_comp;
1197 bool gain_reduction_audio_module::get_graph(int subindex, float *data, int points, cairo_iface *context)
1199 if (!is_active)
1200 return false;
1201 if (subindex > 1) // 1
1202 return false;
1203 for (int i = 0; i < points; i++)
1205 float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
1206 if (subindex == 0)
1207 data[i] = dB_grid(input);
1208 else {
1209 float output = output_level(input);
1210 data[i] = dB_grid(output);
1213 if (subindex == (bypass > 0.5f ? 1 : 0) or mute > 0.1f)
1214 context->set_source_rgba(0.35, 0.4, 0.2, 0.3);
1215 else {
1216 context->set_source_rgba(0.35, 0.4, 0.2, 1);
1217 context->set_line_width(1.5);
1219 return true;
1222 bool gain_reduction_audio_module::get_dot(int subindex, float &x, float &y, int &size, cairo_iface *context)
1224 if (!is_active)
1225 return false;
1226 if (!subindex)
1228 if(bypass > 0.5f or mute > 0.f) {
1229 return false;
1230 } else {
1231 bool rms = detection == 0;
1232 float det = rms ? sqrt(detected) : detected;
1233 x = 0.5 + 0.5 * dB_grid(det);
1234 y = dB_grid(bypass > 0.5f or mute > 0.f ? det : output_level(det));
1235 return true;
1238 return false;
1241 bool gain_reduction_audio_module::get_gridline(int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
1243 bool tmp;
1244 vertical = (subindex & 1) != 0;
1245 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
1246 if (result && vertical) {
1247 if ((subindex & 4) && !legend.empty()) {
1248 legend = "";
1250 else {
1251 size_t pos = legend.find(" dB");
1252 if (pos != std::string::npos)
1253 legend.erase(pos);
1255 pos = 0.5 + 0.5 * pos;
1257 return result;
1260 int gain_reduction_audio_module::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
1262 subindex_graph = 0;
1263 subindex_dot = 0;
1264 subindex_gridline = generation ? INT_MAX : 0;
1266 if (fabs(threshold-old_threshold) + fabs(ratio - old_ratio) + fabs(knee - old_knee) + fabs(makeup - old_makeup) + fabs(detection - old_detection) + fabs(bypass - old_bypass) + fabs(mute - old_mute) > 0.000001f)
1268 old_threshold = threshold;
1269 old_ratio = ratio;
1270 old_knee = knee;
1271 old_makeup = makeup;
1272 old_detection = detection;
1273 old_bypass = bypass;
1274 old_mute = mute;
1275 last_generation++;
1278 if (generation == last_generation)
1279 subindex_graph = 2;
1280 return last_generation;