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
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
) * (1.0 / 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 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
];
255 subindex_dot
= INT_MAX
;
256 subindex_gridline
= INT_MAX
;
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
) {
276 context
->set_line_width(1.5);
277 return ::get_graph(*this, subindex
, data
, points
);
282 ///////////////////////////////////////////////////////////////////////////////////////////////
284 rotary_speaker_audio_module::rotary_speaker_audio_module()
286 mwhl_value
= hold_value
= 0.f
;
287 phase_h
= phase_l
= 0.f
;
293 void rotary_speaker_audio_module::set_sample_rate(uint32_t sr
)
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
);
308 void rotary_speaker_audio_module::activate()
310 phase_h
= phase_l
= 0.f
;
311 maspeed_h
= maspeed_l
= 0.f
;
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
;
327 if (vibrato_mode
== 4 && ctl
== 1)
329 mwhl_value
= val
/ 127.f
;
335 ///////////////////////////////////////////////////////////////////////////////////////////////
337 void multichorus_audio_module::activate()
343 void multichorus_audio_module::deactivate()
348 void multichorus_audio_module::set_sample_rate(uint32_t sr
) {
354 bool multichorus_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
358 int nvoices
= (int)*params
[par_voices
];
359 if (index
== par_delay
&& subindex
< 3)
362 set_channel_color(context
, subindex
);
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;
376 data
[i
] = orig
/ 65536.0;
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
)
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;
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
;
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
)
418 if (index
== par_delay
)
419 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
);
423 float multichorus_audio_module::freq_gain(int subindex
, float freq
, float srate
)
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()
439 void compressor_audio_module::activate()
447 void compressor_audio_module::deactivate()
452 void compressor_audio_module::set_sample_rate(uint32_t sr
)
459 bool compressor_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
463 if (subindex
> 1) // 1
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
);
470 data
[i
] = dB_grid(input
);
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);
477 context
->set_source_rgba(0, 1, 0, 1);
478 context
->set_line_width(2);
483 bool compressor_audio_module::get_dot(int index
, int subindex
, float &x
, float &y
, int &size
, cairo_iface
*context
)
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;
498 bool compressor_audio_module::get_gridline(int index
, int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
)
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()) {
508 size_t pos
= legend
.find(" dB");
509 if (pos
!= std::string::npos
)
512 pos
= 0.5 + 0.5 * pos
;
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
;
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
;
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
;
567 bpL
.set_highshelf_rbj(5000, 0.707, 10 << (aweighting
- 2), srate
);
568 bpR
.copy_coeffs(bpL
);
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
);
602 gain
= output_gain(linSlope
, rms
);
608 float outL
= ins
[0][offset
] * gain
;
609 float outR
= ins
[1][offset
] * gain
;
611 outs
[0][offset
] = outL
;
612 outs
[1][offset
] = outR
;
616 float maxLR
= std::max(fabs(outL
), fabs(outR
));
618 if(maxLR
> 1.f
) clip
= srate
>> 3; /* blink clip LED for 125 ms */
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
;