+ GUI: remove more unused control pointers
[calf.git] / src / modules_dsp.cpp
blob98d4a25211b7411be7c81172ce5715edbeb438fd
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., 59 Temple Place, Suite 330,
19 * Boston, MA 02111-1307, 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.75, 1, 0);
63 else
64 context->set_source_rgba(0, 1, 0.75);
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.25, 0.25, 0.25, 0.75);
92 else
93 context->set_source_rgba(0.25, 0.25, 0.25, 0.5);
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.25, 0.25, 0.25, subindex & 1 ? 0.5 : 0.75);
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 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 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);
305 set_vibrato();
308 void rotary_speaker_audio_module::activate()
310 phase_h = phase_l = 0.f;
311 maspeed_h = maspeed_l = 0.f;
312 setup();
315 void rotary_speaker_audio_module::deactivate()
319 void rotary_speaker_audio_module::control_change(int ctl, int val)
321 if (vibrato_mode == 3 && ctl == 64)
323 hold_value = val / 127.f;
324 set_vibrato();
325 return;
327 if (vibrato_mode == 4 && ctl == 1)
329 mwhl_value = val / 127.f;
330 set_vibrato();
331 return;
335 ///////////////////////////////////////////////////////////////////////////////////////////////
337 void multichorus_audio_module::activate()
339 is_active = true;
340 params_changed();
343 void multichorus_audio_module::deactivate()
345 is_active = false;
348 void multichorus_audio_module::set_sample_rate(uint32_t sr) {
349 srate = sr;
350 left.setup(sr);
351 right.setup(sr);
354 bool multichorus_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
356 if (!is_active)
357 return false;
358 int nvoices = (int)*params[par_voices];
359 if (index == par_delay && subindex < 3)
361 if (subindex < 2)
362 set_channel_color(context, subindex);
363 else {
364 context->set_source_rgba(0, 1, 0);
365 context->set_line_width(1.0);
367 return ::get_graph(*this, subindex, data, points);
369 if (index == par_rate && subindex < nvoices) {
370 sine_multi_lfo<float, 8> &lfo = left.lfo;
371 for (int i = 0; i < points; i++) {
372 float phase = i * 2 * M_PI / points;
373 // original -65536 to 65535 value
374 float orig = subindex * lfo.voice_offset + ((lfo.voice_depth >> (30-13)) * 65536.0 * (0.95 * sin(phase) + 1)/ 8192.0) - 65536;
375 // scale to -1..1
376 data[i] = orig / 65536.0;
378 return true;
380 return false;
383 bool multichorus_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
385 int voice = subindex >> 1;
386 int nvoices = (int)*params[par_voices];
387 if ((index != par_rate && index != par_depth) || voice >= nvoices)
388 return false;
390 float unit = (1 - *params[par_overlap]);
391 float scw = 1 + unit * (nvoices - 1);
392 set_channel_color(context, subindex);
393 sine_multi_lfo<float, 8> &lfo = (subindex & 1 ? right : left).lfo;
394 if (index == par_rate)
396 x = (double)(lfo.phase + lfo.vphase * voice) / 4096.0;
397 y = 0.95 * sin(x * 2 * M_PI);
398 y = (voice * unit + (y + 1) / 2) / scw * 2 - 1;
400 else
402 double ph = (double)(lfo.phase + lfo.vphase * voice) / 4096.0;
403 x = 0.5 + 0.5 * sin(ph * 2 * M_PI);
404 y = subindex & 1 ? -0.75 : 0.75;
405 x = (voice * unit + x) / scw;
407 return true;
410 bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
412 if (index == par_rate && !subindex)
414 pos = 0;
415 vertical = false;
416 return true;
418 if (index == par_delay)
419 return get_freq_gridline(subindex, pos, vertical, legend, context);
420 return false;
423 float multichorus_audio_module::freq_gain(int subindex, float freq, float srate)
425 if (subindex == 2)
426 return *params[par_amount] * left.post.freq_gain(freq, srate);
427 return (subindex ? right : left).freq_gain(freq, srate);
430 ///////////////////////////////////////////////////////////////////////////////////////////////
432 compressor_audio_module::compressor_audio_module()
434 is_active = false;
435 srate = 0;
436 last_generation = 0;
439 void compressor_audio_module::activate()
441 is_active = true;
442 linSlope = 0.f;
443 peak = 0.f;
444 clip = 0.f;
447 void compressor_audio_module::deactivate()
449 is_active = false;
452 void compressor_audio_module::set_sample_rate(uint32_t sr)
454 srate = sr;
455 awL.set(sr);
456 awR.set(sr);
459 bool compressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
461 if (!is_active)
462 return false;
463 if (subindex > 1) // 1
464 return false;
465 for (int i = 0; i < points; i++)
467 float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
468 float output = output_level(input);
469 if (subindex == 0)
470 data[i] = dB_grid(input);
471 else
472 data[i] = dB_grid(output);
474 if (subindex == (*params[param_bypass] > 0.5f ? 1 : 0))
475 context->set_source_rgba(0.5, 0.5, 0.5, 0.5);
476 else {
477 context->set_source_rgba(0, 1, 0, 1);
478 context->set_line_width(2);
480 return true;
483 bool compressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
485 if (!is_active)
486 return false;
487 if (!subindex)
489 bool rms = *params[param_detection] == 0;
490 float det = rms ? sqrt(detected) : detected;
491 x = 0.5 + 0.5 * dB_grid(det);
492 y = dB_grid(*params[param_bypass] > 0.5f ? det : output_level(det));
493 return *params[param_bypass] > 0.5f ? false : true;
495 return false;
498 bool compressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
500 bool tmp;
501 vertical = (subindex & 1) != 0;
502 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
503 if (result && vertical) {
504 if ((subindex & 4) && !legend.empty()) {
505 legend = "";
507 else {
508 size_t pos = legend.find(" dB");
509 if (pos != std::string::npos)
510 legend.erase(pos);
512 pos = 0.5 + 0.5 * pos;
514 return result;
517 // In case of doubt: this function is written by Thor. I just moved it to this file, damaging
518 // the output of "git annotate" in the process.
519 uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
521 bool bypass = *params[param_bypass] > 0.5f;
523 if(bypass) {
524 int count = numsamples * sizeof(float);
525 memcpy(outs[0], ins[0], count);
526 memcpy(outs[1], ins[1], count);
528 if(params[param_compression] != NULL) {
529 *params[param_compression] = 1.f;
532 if(params[param_clip] != NULL) {
533 *params[param_clip] = 0.f;
536 if(params[param_peak] != NULL) {
537 *params[param_peak] = 0.f;
540 return inputs_mask;
543 bool rms = *params[param_detection] == 0;
544 bool average = *params[param_stereo_link] == 0;
545 int aweighting = fastf2i_drm(*params[param_aweighting]);
546 float linThreshold = *params[param_threshold];
547 ratio = *params[param_ratio];
548 float attack = *params[param_attack];
549 float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
550 float release = *params[param_release];
551 float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
552 makeup = *params[param_makeup];
553 knee = *params[param_knee];
555 float linKneeSqrt = sqrt(knee);
556 linKneeStart = linThreshold / linKneeSqrt;
557 adjKneeStart = linKneeStart*linKneeStart;
558 float linKneeStop = linThreshold * linKneeSqrt;
560 threshold = log(linThreshold);
561 kneeStart = log(linKneeStart);
562 kneeStop = log(linKneeStop);
563 compressedKneeStop = (kneeStop - threshold) / ratio + threshold;
565 if (aweighting >= 2)
567 bpL.set_highshelf_rbj(5000, 0.707, 10 << (aweighting - 2), srate);
568 bpR.copy_coeffs(bpL);
569 bpL.sanitize();
570 bpR.sanitize();
573 numsamples += offset;
575 float compression = 1.f;
577 peak -= peak * 5.f * numsamples / srate;
579 clip -= std::min(clip, numsamples);
581 while(offset < numsamples) {
582 float left = ins[0][offset];
583 float right = ins[1][offset];
585 if(aweighting == 1) {
586 left = awL.process(left);
587 right = awR.process(right);
589 else if(aweighting >= 2) {
590 left = bpL.process(left);
591 right = bpR.process(right);
594 float absample = average ? (fabs(left) + fabs(right)) * 0.5f : std::max(fabs(left), fabs(right));
595 if(rms) absample *= absample;
597 linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
599 float gain = 1.f;
601 if(linSlope > 0.f) {
602 gain = output_gain(linSlope, rms);
605 compression = gain;
606 gain *= makeup;
608 float outL = ins[0][offset] * gain;
609 float outR = ins[1][offset] * gain;
611 outs[0][offset] = outL;
612 outs[1][offset] = outR;
614 ++offset;
616 float maxLR = std::max(fabs(outL), fabs(outR));
618 if(maxLR > 1.f) clip = srate >> 3; /* blink clip LED for 125 ms */
620 if(maxLR > peak) {
621 peak = maxLR;
625 detected = linSlope;
627 if(params[param_compression] != NULL) {
628 *params[param_compression] = compression;
631 if(params[param_clip] != NULL) {
632 *params[param_clip] = clip;
635 if(params[param_peak] != NULL) {
636 *params[param_peak] = peak;
639 return inputs_mask;