at least make freqgridline return false when the gridline subindex is below zero.
[calf.git] / src / modules_dsp.cpp
blob2cdc390a6a8414b9bf713316b1641837d69a08ab
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 float gain = 16.0 / (1 << subindex);
99 pos = dB_grid(gain);
100 if (pos < -1)
101 return false;
102 if (subindex != 4)
103 context->set_source_rgba(0.25, 0.25, 0.25, subindex & 1 ? 0.5 : 0.75);
104 if (!(subindex & 1))
106 std::stringstream ss;
107 ss << (24 - 6 * subindex) << " dB";
108 legend = ss.str();
110 vertical = false;
111 return true;
114 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
116 bool frequency_response_line_graph::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
118 return get_freq_gridline(subindex, pos, vertical, legend, context);
121 int frequency_response_line_graph::get_changed_offsets(int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
123 subindex_graph = 0;
124 subindex_dot = 0;
125 subindex_gridline = generation ? INT_MAX : 0;
126 return 1;
129 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
131 void flanger_audio_module::activate() {
132 left.reset();
133 right.reset();
134 last_r_phase = *params[par_stereo] * (1.f / 360.f);
135 left.reset_phase(0.f);
136 right.reset_phase(last_r_phase);
137 is_active = true;
140 void flanger_audio_module::set_sample_rate(uint32_t sr) {
141 srate = sr;
142 left.setup(sr);
143 right.setup(sr);
146 void flanger_audio_module::deactivate() {
147 is_active = false;
150 bool flanger_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
152 if (!is_active)
153 return false;
154 if (index == par_delay && subindex < 2)
156 set_channel_color(context, subindex);
157 return ::get_graph(*this, subindex, data, points);
159 return false;
162 float flanger_audio_module::freq_gain(int subindex, float freq, float srate)
164 return (subindex ? right : left).freq_gain(freq, srate);
167 ///////////////////////////////////////////////////////////////////////////////////////////////
169 void phaser_audio_module::set_sample_rate(uint32_t sr)
171 srate = sr;
172 left.setup(sr);
173 right.setup(sr);
176 void phaser_audio_module::activate()
178 is_active = true;
179 left.reset();
180 right.reset();
181 last_r_phase = *params[par_stereo] * (1.f / 360.f);
182 left.reset_phase(0.f);
183 right.reset_phase(last_r_phase);
186 void phaser_audio_module::deactivate()
188 is_active = false;
191 bool phaser_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
193 if (!is_active)
194 return false;
195 if (subindex < 2)
197 set_channel_color(context, subindex);
198 return ::get_graph(*this, subindex, data, points);
200 return false;
203 float phaser_audio_module::freq_gain(int subindex, float freq, float srate)
205 return (subindex ? right : left).freq_gain(freq, srate);
208 bool phaser_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
210 return get_freq_gridline(subindex, pos, vertical, legend, context);
213 ///////////////////////////////////////////////////////////////////////////////////////////////
215 void reverb_audio_module::activate()
217 reverb.reset();
220 void reverb_audio_module::deactivate()
224 void reverb_audio_module::set_sample_rate(uint32_t sr)
226 srate = sr;
227 reverb.setup(sr);
228 amount.set_sample_rate(sr);
231 ///////////////////////////////////////////////////////////////////////////////////////////////
233 bool filter_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
235 if (!is_active)
236 return false;
237 if (index == par_cutoff && !subindex) {
238 context->set_line_width(1.5);
239 return ::get_graph(*this, subindex, data, points);
241 return false;
244 ///////////////////////////////////////////////////////////////////////////////////////////////
246 bool filterclavier_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
248 if (!is_active || index != par_mode) {
249 return false;
251 if (!subindex) {
252 context->set_line_width(1.5);
253 return ::get_graph(*this, subindex, data, points);
255 return false;
258 ///////////////////////////////////////////////////////////////////////////////////////////////
260 rotary_speaker_audio_module::rotary_speaker_audio_module()
262 mwhl_value = hold_value = 0.f;
263 phase_h = phase_l = 0.f;
264 aspeed_l = 1.f;
265 aspeed_h = 1.f;
266 dspeed = 0.f;
269 void rotary_speaker_audio_module::set_sample_rate(uint32_t sr)
271 srate = sr;
272 setup();
275 void rotary_speaker_audio_module::setup()
277 crossover1l.set_lp_rbj(800.f, 0.7, (float)srate);
278 crossover1r.set_lp_rbj(800.f, 0.7, (float)srate);
279 crossover2l.set_hp_rbj(800.f, 0.7, (float)srate);
280 crossover2r.set_hp_rbj(800.f, 0.7, (float)srate);
281 set_vibrato();
284 void rotary_speaker_audio_module::activate()
286 phase_h = phase_l = 0.f;
287 maspeed_h = maspeed_l = 0.f;
288 setup();
291 void rotary_speaker_audio_module::deactivate()
295 void rotary_speaker_audio_module::control_change(int ctl, int val)
297 if (vibrato_mode == 3 && ctl == 64)
299 hold_value = val / 127.f;
300 set_vibrato();
301 return;
303 if (vibrato_mode == 4 && ctl == 1)
305 mwhl_value = val / 127.f;
306 set_vibrato();
307 return;
311 ///////////////////////////////////////////////////////////////////////////////////////////////
313 void multichorus_audio_module::activate()
315 is_active = true;
316 params_changed();
319 void multichorus_audio_module::deactivate()
321 is_active = false;
324 void multichorus_audio_module::set_sample_rate(uint32_t sr) {
325 srate = sr;
326 left.setup(sr);
327 right.setup(sr);
330 bool multichorus_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
332 if (!is_active)
333 return false;
334 if (index == par_delay && subindex < 3)
336 if (subindex < 2)
337 set_channel_color(context, subindex);
338 else {
339 context->set_source_rgba(0, 1, 0);
340 context->set_line_width(1.0);
342 return ::get_graph(*this, subindex, data, points);
344 if (index == par_rate && !subindex) {
345 for (int i = 0; i < points; i++)
346 data[i] = 0.95 * sin(i * 2 * M_PI / points);
347 return true;
349 return false;
352 bool multichorus_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
354 if ((index != par_rate && index != par_depth) || subindex >= 2 * (int)*params[par_voices])
355 return false;
357 set_channel_color(context, subindex);
358 sine_multi_lfo<float, 8> &lfo = (subindex & 1 ? right : left).lfo;
359 if (index == par_rate)
361 x = (double)(lfo.phase + lfo.vphase * (subindex >> 1)) / 4096.0;
362 y = 0.95 * sin(x * 2 * M_PI);
364 else
366 double ph = (double)(lfo.phase + lfo.vphase * (subindex >> 1)) / 4096.0;
367 x = 0.5 + 0.5 * sin(ph * 2 * M_PI);
368 y = subindex & 1 ? -0.75 : 0.75;
370 return true;
373 bool multichorus_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
375 if (index == par_rate && !subindex)
377 pos = 0;
378 vertical = false;
379 return true;
381 if (index == par_delay)
382 return get_freq_gridline(subindex, pos, vertical, legend, context);
383 return false;
386 float multichorus_audio_module::freq_gain(int subindex, float freq, float srate)
388 if (subindex == 2)
389 return *params[par_amount] * left.post.freq_gain(freq, srate);
390 return (subindex ? right : left).freq_gain(freq, srate);
393 ///////////////////////////////////////////////////////////////////////////////////////////////
395 compressor_audio_module::compressor_audio_module()
397 is_active = false;
398 srate = 0;
401 void compressor_audio_module::activate()
403 is_active = true;
404 linSlope = 0.f;
405 peak = 0.f;
406 clip = 0.f;
409 void compressor_audio_module::deactivate()
411 is_active = false;
414 void compressor_audio_module::set_sample_rate(uint32_t sr)
416 srate = sr;
417 awL.set(sr);
418 awR.set(sr);
421 bool compressor_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
423 if (!is_active)
424 return false;
425 if (subindex > 1) // 1
426 return false;
427 for (int i = 0; i < points; i++)
429 float input = dB_grid_inv(-1.0 + i * 2.0 / (points - 1));
430 float output = output_level(input);
431 if (subindex == 0)
432 data[i] = dB_grid(input);
433 else
434 data[i] = dB_grid(output);
436 if (subindex == (*params[param_bypass] > 0.5f ? 1 : 0))
437 context->set_source_rgba(0.5, 0.5, 0.5, 0.5);
438 else {
439 context->set_source_rgba(0, 1, 0, 1);
440 context->set_line_width(2);
442 return true;
445 bool compressor_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
447 if (!is_active)
448 return false;
449 if (!subindex)
451 x = 0.5 + 0.5 * dB_grid(detected);
452 y = dB_grid(*params[param_bypass] > 0.5f ? detected : output_level(detected));
453 return *params[param_bypass] > 0.5f ? false : true;
455 return false;
458 bool compressor_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
460 bool tmp;
461 vertical = (subindex & 1) != 0;
462 bool result = get_freq_gridline(subindex >> 1, pos, tmp, legend, context, false);
463 if (result && vertical) {
464 if ((subindex & 4) && !legend.empty()) {
465 legend = "";
467 else {
468 size_t pos = legend.find(" dB");
469 if (pos != std::string::npos)
470 legend.erase(pos);
472 pos = 0.5 + 0.5 * pos;
474 return result;
477 // In case of doubt: this function is written by Thor. I just moved it to this file, damaging
478 // the output of "git annotate" in the process.
479 uint32_t compressor_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
481 bool bypass = *params[param_bypass] > 0.5f;
483 if(bypass) {
484 int count = numsamples * sizeof(float);
485 memcpy(outs[0], ins[0], count);
486 memcpy(outs[1], ins[1], count);
488 if(params[param_compression] != NULL) {
489 *params[param_compression] = 1.f;
492 if(params[param_clip] != NULL) {
493 *params[param_clip] = 0.f;
496 if(params[param_peak] != NULL) {
497 *params[param_peak] = 0.f;
500 return inputs_mask;
503 bool rms = *params[param_detection] == 0;
504 bool average = *params[param_stereo_link] == 0;
505 bool aweighting = *params[param_aweighting] > 0.5f;
506 float linThreshold = *params[param_threshold];
507 ratio = *params[param_ratio];
508 float attack = *params[param_attack];
509 float attack_coeff = std::min(1.f, 1.f / (attack * srate / 4000.f));
510 float release = *params[param_release];
511 float release_coeff = std::min(1.f, 1.f / (release * srate / 4000.f));
512 makeup = *params[param_makeup];
513 knee = *params[param_knee];
515 float linKneeSqrt = sqrt(knee);
516 linKneeStart = linThreshold / linKneeSqrt;
517 adjKneeStart = linKneeStart*linKneeStart;
518 float linKneeStop = linThreshold * linKneeSqrt;
520 threshold = log(linThreshold);
521 kneeStart = log(linKneeStart);
522 kneeStop = log(linKneeStop);
523 compressedKneeStop = (kneeStop - threshold) / ratio + threshold;
525 numsamples += offset;
527 float compression = 1.f;
529 peak -= peak * 5.f * numsamples / srate;
531 clip -= std::min(clip, numsamples);
533 while(offset < numsamples) {
534 float left = ins[0][offset];
535 float right = ins[1][offset];
537 if(aweighting) {
538 left = awL.process(left);
539 right = awR.process(right);
542 float absample = average ? (fabs(left) + fabs(right)) * 0.5f : std::max(fabs(left), fabs(right));
543 if(rms) absample *= absample;
545 linSlope += (absample - linSlope) * (absample > linSlope ? attack_coeff : release_coeff);
547 float gain = 1.f;
549 if(linSlope > 0.f) {
550 gain = output_gain(linSlope, rms);
553 compression = gain;
554 gain *= makeup;
556 float outL = ins[0][offset] * gain;
557 float outR = ins[1][offset] * gain;
559 outs[0][offset] = outL;
560 outs[1][offset] = outR;
562 ++offset;
564 float maxLR = std::max(fabs(outL), fabs(outR));
566 if(maxLR > 1.f) clip = srate >> 3; /* blink clip LED for 125 ms */
568 if(maxLR > peak) {
569 peak = maxLR;
573 detected = rms ? sqrt(linSlope) : linSlope;
575 if(params[param_compression] != NULL) {
576 *params[param_compression] = compression;
579 if(params[param_clip] != NULL) {
580 *params[param_clip] = clip;
583 if(params[param_peak] != NULL) {
584 *params[param_peak] = peak;
587 return inputs_mask;