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.
26 #include <jack/jack.h>
28 #include <calf/giface.h>
29 #include <calf/modules.h>
30 #include <calf/modules_dev.h>
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;
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
));
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
)
62 context
->set_source_rgba(0.75, 1, 0);
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)
77 if (subindex
== 9) legend
= "100 Hz";
78 if (subindex
== 18) legend
= "1 kHz";
79 if (subindex
== 27) legend
= "10 kHz";
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);
88 freq
= 10000 * (subindex
- 27 + 1);
89 pos
= log(freq
/ 20.0) / log(1000);
91 context
->set_source_rgba(0.25, 0.25, 0.25, 0.75);
93 context
->set_source_rgba(0.25, 0.25, 0.25, 0.5);
100 float gain
= 16.0 / (1 << subindex
);
105 context
->set_source_rgba(0.25, 0.25, 0.25, subindex
& 1 ? 0.5 : 0.75);
108 std::stringstream ss
;
109 ss
<< (24 - 6 * subindex
) << " dB";
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
)
127 subindex_gridline
= generation
? INT_MAX
: 0;
131 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
133 void flanger_audio_module::activate() {
136 last_r_phase
= *params
[par_stereo
] * (1.f
/ 360.f
);
137 left
.reset_phase(0.f
);
138 right
.reset_phase(last_r_phase
);
142 void flanger_audio_module::set_sample_rate(uint32_t sr
) {
148 void flanger_audio_module::deactivate() {
152 bool flanger_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
156 if (index
== par_delay
&& subindex
< 2)
158 set_channel_color(context
, subindex
);
159 return ::get_graph(*this, subindex
, data
, points
);
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
)
178 void phaser_audio_module::activate()
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()
193 bool phaser_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
199 set_channel_color(context
, subindex
);
200 return ::get_graph(*this, subindex
, data
, points
);
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()
222 void reverb_audio_module::deactivate()
226 void reverb_audio_module::set_sample_rate(uint32_t 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
)
239 if (index
== par_cutoff
&& !subindex
) {
240 context
->set_line_width(1.5);
241 return ::get_graph(*this, subindex
, data
, points
);
246 ///////////////////////////////////////////////////////////////////////////////////////////////
248 bool filterclavier_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
250 if (!is_active
|| index
!= par_mode
) {
254 context
->set_line_width(1.5);
255 return ::get_graph(*this, subindex
, data
, points
);
260 ///////////////////////////////////////////////////////////////////////////////////////////////
262 rotary_speaker_audio_module::rotary_speaker_audio_module()
264 mwhl_value
= hold_value
= 0.f
;
265 phase_h
= phase_l
= 0.f
;
271 void rotary_speaker_audio_module::set_sample_rate(uint32_t sr
)
277 void rotary_speaker_audio_module::setup()
279 crossover1l
.set_lp_rbj(800.f
, 0.7, (float)srate
);
280 crossover1r
.set_lp_rbj(800.f
, 0.7, (float)srate
);
281 crossover2l
.set_hp_rbj(800.f
, 0.7, (float)srate
);
282 crossover2r
.set_hp_rbj(800.f
, 0.7, (float)srate
);
286 void rotary_speaker_audio_module::activate()
288 phase_h
= phase_l
= 0.f
;
289 maspeed_h
= maspeed_l
= 0.f
;
293 void rotary_speaker_audio_module::deactivate()
297 void rotary_speaker_audio_module::control_change(int ctl
, int val
)
299 if (vibrato_mode
== 3 && ctl
== 64)
301 hold_value
= val
/ 127.f
;
305 if (vibrato_mode
== 4 && ctl
== 1)
307 mwhl_value
= val
/ 127.f
;
313 ///////////////////////////////////////////////////////////////////////////////////////////////
315 void multichorus_audio_module::activate()
321 void multichorus_audio_module::deactivate()
326 void multichorus_audio_module::set_sample_rate(uint32_t sr
) {
332 bool multichorus_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
336 if (index
== par_delay
&& subindex
< 3)
339 set_channel_color(context
, subindex
);
341 context
->set_source_rgba(0, 1, 0);
342 context
->set_line_width(1.0);
344 return ::get_graph(*this, subindex
, data
, points
);
346 if (index
== par_rate
&& !subindex
) {
347 for (int i
= 0; i
< points
; i
++)
348 data
[i
] = 0.95 * sin(i
* 2 * M_PI
/ points
);
354 bool multichorus_audio_module::get_dot(int index
, int subindex
, float &x
, float &y
, int &size
, cairo_iface
*context
)
356 if ((index
!= par_rate
&& index
!= par_depth
) || subindex
>= 2 * (int)*params
[par_voices
])
359 set_channel_color(context
, subindex
);
360 sine_multi_lfo
<float, 8> &lfo
= (subindex
& 1 ? right
: left
).lfo
;
361 if (index
== par_rate
)
363 x
= (double)(lfo
.phase
+ lfo
.vphase
* (subindex
>> 1)) / 4096.0;
364 y
= 0.95 * sin(x
* 2 * M_PI
);
368 double ph
= (double)(lfo
.phase
+ lfo
.vphase
* (subindex
>> 1)) / 4096.0;
369 x
= 0.5 + 0.5 * sin(ph
* 2 * M_PI
);
370 y
= subindex
& 1 ? -0.75 : 0.75;
375 bool multichorus_audio_module::get_gridline(int index
, int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
)
377 if (index
== par_rate
&& !subindex
)
383 if (index
== par_delay
)
384 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
);
388 float multichorus_audio_module::freq_gain(int subindex
, float freq
, float srate
)
391 return *params
[par_amount
] * left
.post
.freq_gain(freq
, srate
);
392 return (subindex
? right
: left
).freq_gain(freq
, srate
);
395 ///////////////////////////////////////////////////////////////////////////////////////////////
397 compressor_audio_module::compressor_audio_module()
403 void compressor_audio_module::activate()
411 void compressor_audio_module::deactivate()
416 void compressor_audio_module::set_sample_rate(uint32_t sr
)
423 bool compressor_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
427 if (subindex
> 1) // 1
429 for (int i
= 0; i
< points
; i
++)
431 float input
= dB_grid_inv(-1.0 + i
* 2.0 / (points
- 1));
432 float output
= output_level(input
);
434 data
[i
] = dB_grid(input
);
436 data
[i
] = dB_grid(output
);
438 if (subindex
== (*params
[param_bypass
] > 0.5f
? 1 : 0))
439 context
->set_source_rgba(0.5, 0.5, 0.5, 0.5);
441 context
->set_source_rgba(0, 1, 0, 1);
442 context
->set_line_width(2);
447 bool compressor_audio_module::get_dot(int index
, int subindex
, float &x
, float &y
, int &size
, cairo_iface
*context
)
453 x
= 0.5 + 0.5 * dB_grid(detected
);
454 y
= dB_grid(*params
[param_bypass
] > 0.5f
? detected
: output_level(detected
));
455 return *params
[param_bypass
] > 0.5f
? false : true;
460 bool compressor_audio_module::get_gridline(int index
, int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
)
463 vertical
= (subindex
& 1) != 0;
464 bool result
= get_freq_gridline(subindex
>> 1, pos
, tmp
, legend
, context
, false);
465 if (result
&& vertical
) {
466 if ((subindex
& 4) && !legend
.empty()) {
470 size_t pos
= legend
.find(" dB");
471 if (pos
!= std::string::npos
)
474 pos
= 0.5 + 0.5 * pos
;
479 // In case of doubt: this function is written by Thor. I just moved it to this file, damaging
480 // the output of "git annotate" in the process.
481 uint32_t compressor_audio_module::process(uint32_t offset
, uint32_t numsamples
, uint32_t inputs_mask
, uint32_t outputs_mask
)
483 bool bypass
= *params
[param_bypass
] > 0.5f
;
486 int count
= numsamples
* sizeof(float);
487 memcpy(outs
[0], ins
[0], count
);
488 memcpy(outs
[1], ins
[1], count
);
490 if(params
[param_compression
] != NULL
) {
491 *params
[param_compression
] = 1.f
;
494 if(params
[param_clip
] != NULL
) {
495 *params
[param_clip
] = 0.f
;
498 if(params
[param_peak
] != NULL
) {
499 *params
[param_peak
] = 0.f
;
505 bool rms
= *params
[param_detection
] == 0;
506 bool average
= *params
[param_stereo_link
] == 0;
507 bool aweighting
= *params
[param_aweighting
] > 0.5f
;
508 float linThreshold
= *params
[param_threshold
];
509 ratio
= *params
[param_ratio
];
510 float attack
= *params
[param_attack
];
511 float attack_coeff
= std::min(1.f
, 1.f
/ (attack
* srate
/ 4000.f
));
512 float release
= *params
[param_release
];
513 float release_coeff
= std::min(1.f
, 1.f
/ (release
* srate
/ 4000.f
));
514 makeup
= *params
[param_makeup
];
515 knee
= *params
[param_knee
];
517 float linKneeSqrt
= sqrt(knee
);
518 linKneeStart
= linThreshold
/ linKneeSqrt
;
519 adjKneeStart
= linKneeStart
*linKneeStart
;
520 float linKneeStop
= linThreshold
* linKneeSqrt
;
522 threshold
= log(linThreshold
);
523 kneeStart
= log(linKneeStart
);
524 kneeStop
= log(linKneeStop
);
525 compressedKneeStop
= (kneeStop
- threshold
) / ratio
+ threshold
;
527 numsamples
+= offset
;
529 float compression
= 1.f
;
531 peak
-= peak
* 5.f
* numsamples
/ srate
;
533 clip
-= std::min(clip
, numsamples
);
535 while(offset
< numsamples
) {
536 float left
= ins
[0][offset
];
537 float right
= ins
[1][offset
];
540 left
= awL
.process(left
);
541 right
= awR
.process(right
);
544 float absample
= average
? (fabs(left
) + fabs(right
)) * 0.5f
: std::max(fabs(left
), fabs(right
));
545 if(rms
) absample
*= absample
;
547 linSlope
+= (absample
- linSlope
) * (absample
> linSlope
? attack_coeff
: release_coeff
);
552 gain
= output_gain(linSlope
, rms
);
558 float outL
= ins
[0][offset
] * gain
;
559 float outR
= ins
[1][offset
] * gain
;
561 outs
[0][offset
] = outL
;
562 outs
[1][offset
] = outR
;
566 float maxLR
= std::max(fabs(outL
), fabs(outR
));
568 if(maxLR
> 1.f
) clip
= srate
>> 3; /* blink clip LED for 125 ms */
575 detected
= rms
? sqrt(linSlope
) : linSlope
;
577 if(params
[param_compression
] != NULL
) {
578 *params
[param_compression
] = compression
;
581 if(params
[param_clip
] != NULL
) {
582 *params
[param_clip
] = clip
;
585 if(params
[param_peak
] != NULL
) {
586 *params
[param_peak
] = peak
;