+ Organ: add pitch bend inertia
[calf.git] / src / modules_dsp.cpp
blob5ee5bfae38a776e2a5cfc04b5f2bb50d7773107f
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) / 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 if (index == par_delay && subindex < 3)
360 if (subindex < 2)
361 set_channel_color(context, subindex);
362 else {
363 context->set_source_rgba(0, 1, 0);
364 context->set_line_width(1.0);
366 return ::get_graph(*this, subindex, data, points);
368 if (index == par_rate && !subindex) {
369 for (int i = 0; i < points; i++)
370 data[i] = 0.95 * sin(i * 2 * M_PI / points);
371 return true;
373 return false;
376 bool multichorus_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
378 if ((index != par_rate && index != par_depth) || subindex >= 2 * (int)*params[par_voices])
379 return false;
381 set_channel_color(context, subindex);
382 sine_multi_lfo<float, 8> &lfo = (subindex & 1 ? right : left).lfo;
383 if (index == par_rate)
385 x = (double)(lfo.phase + lfo.vphase * (subindex >> 1)) / 4096.0;
386 y = 0.95 * sin(x * 2 * M_PI);
388 else
390 double ph = (double)(lfo.phase + lfo.vphase * (subindex >> 1)) / 4096.0;
391 x = 0.5 + 0.5 * sin(ph * 2 * M_PI);
392 y = subindex & 1 ? -0.75 : 0.75;
394 return true;
397 bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
399 if (index == par_rate && !subindex)
401 pos = 0;
402 vertical = false;
403 return true;
405 if (index == par_delay)
406 return get_freq_gridline(subindex, pos, vertical, legend, context);
407 return false;
410 float multichorus_audio_module::freq_gain(int subindex, float freq, float srate)
412 if (subindex == 2)
413 return *params[par_amount] * left.post.freq_gain(freq, srate);
414 return (subindex ? right : left).freq_gain(freq, srate);
417 ///////////////////////////////////////////////////////////////////////////////////////////////
419 compressor_audio_module::compressor_audio_module()
421 is_active = false;
422 srate = 0;
423 last_generation = 0;
426 void compressor_audio_module::activate()
428 is_active = true;
429 linSlope = 0.f;
430 peak = 0.f;
431 clip = 0.f;
434 void compressor_audio_module::deactivate()
436 is_active = false;
439 void compressor_audio_module::set_sample_rate(uint32_t sr)
441 srate = sr;
442 awL.set(sr);
443 awR.set(sr);
446 bool compressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
448 if (!is_active)
449 return false;
450 if (subindex > 1) // 1
451 return false;
452 for (int i = 0; i < points; i++)
454 float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
455 float output = output_level(input);
456 if (subindex == 0)
457 data[i] = dB_grid(input);
458 else
459 data[i] = dB_grid(output);
461 if (subindex == (*params[param_bypass] > 0.5f ? 1 : 0))
462 context->set_source_rgba(0.5, 0.5, 0.5, 0.5);
463 else {
464 context->set_source_rgba(0, 1, 0, 1);
465 context->set_line_width(2);
467 return true;
470 bool compressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
472 if (!is_active)
473 return false;
474 if (!subindex)
476 x = 0.5 + 0.5 * dB_grid(detected);
477 y = dB_grid(*params[param_bypass] > 0.5f ? detected : output_level(detected));
478 return *params[param_bypass] > 0.5f ? false : true;
480 return false;
483 bool compressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
485 bool tmp;
486 vertical = (subindex & 1) != 0;
487 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
488 if (result && vertical) {
489 if ((subindex & 4) && !legend.empty()) {
490 legend = "";
492 else {
493 size_t pos = legend.find(" dB");
494 if (pos != std::string::npos)
495 legend.erase(pos);
497 pos = 0.5 + 0.5 * pos;
499 return result;
502 // In case of doubt: this function is written by Thor. I just moved it to this file, damaging
503 // the output of "git annotate" in the process.
504 uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
506 bool bypass = *params[param_bypass] > 0.5f;
508 if(bypass) {
509 int count = numsamples * sizeof(float);
510 memcpy(outs[0], ins[0], count);
511 memcpy(outs[1], ins[1], count);
513 if(params[param_compression] != NULL) {
514 *params[param_compression] = 1.f;
517 if(params[param_clip] != NULL) {
518 *params[param_clip] = 0.f;
521 if(params[param_peak] != NULL) {
522 *params[param_peak] = 0.f;
525 return inputs_mask;
528 bool rms = *params[param_detection] == 0;
529 bool average = *params[param_stereo_link] == 0;
530 bool aweighting = *params[param_aweighting] > 0.5f;
531 float linThreshold = *params[param_threshold];
532 ratio = *params[param_ratio];
533 float attack = *params[param_attack];
534 float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
535 float release = *params[param_release];
536 float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
537 makeup = *params[param_makeup];
538 knee = *params[param_knee];
540 float linKneeSqrt = sqrt(knee);
541 linKneeStart = linThreshold / linKneeSqrt;
542 adjKneeStart = linKneeStart*linKneeStart;
543 float linKneeStop = linThreshold * linKneeSqrt;
545 threshold = log(linThreshold);
546 kneeStart = log(linKneeStart);
547 kneeStop = log(linKneeStop);
548 compressedKneeStop = (kneeStop - threshold) / ratio + threshold;
550 numsamples += offset;
552 float compression = 1.f;
554 peak -= peak * 5.f * numsamples / srate;
556 clip -= std::min(clip, numsamples);
558 while(offset < numsamples) {
559 float left = ins[0][offset];
560 float right = ins[1][offset];
562 if(aweighting) {
563 left = awL.process(left);
564 right = awR.process(right);
567 float absample = average ? (fabs(left) + fabs(right)) * 0.5f : std::max(fabs(left), fabs(right));
568 if(rms) absample *= absample;
570 linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
572 float gain = 1.f;
574 if(linSlope > 0.f) {
575 gain = output_gain(linSlope, rms);
578 compression = gain;
579 gain *= makeup;
581 float outL = ins[0][offset] * gain;
582 float outR = ins[1][offset] * gain;
584 outs[0][offset] = outL;
585 outs[1][offset] = outR;
587 ++offset;
589 float maxLR = std::max(fabs(outL), fabs(outR));
591 if(maxLR > 1.f) clip = srate >> 3; /* blink clip LED for 125 ms */
593 if(maxLR > peak) {
594 peak = maxLR;
598 detected = rms ? sqrt(linSlope) : linSlope;
600 if(params[param_compression] != NULL) {
601 *params[param_compression] = compression;
604 if(params[param_clip] != NULL) {
605 *params[param_clip] = clip;
608 if(params[param_peak] != NULL) {
609 *params[param_peak] = peak;
612 return inputs_mask;