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.35, 0.4, 0.2, 1);
64 context
->set_source_rgba(0.35, 0.4, 0.2, 0.5);
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, 0, 0, 0.2);
93 context
->set_source_rgba(0, 0, 0, 0.1);
100 float gain
= 16.0 / (1 << subindex
);
105 context
->set_source_rgba(0, 0, 0, subindex
& 1 ? 0.1 : 0.2);
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 index
, 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 index
, 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
);
307 void rotary_speaker_audio_module::activate()
309 phase_h
= phase_l
= 0.f
;
310 maspeed_h
= maspeed_l
= 0.f
;
314 void rotary_speaker_audio_module::deactivate()
318 void rotary_speaker_audio_module::control_change(int ctl
, int val
)
320 if (vibrato_mode
== 3 && ctl
== 64)
322 hold_value
= val
/ 127.f
;
326 if (vibrato_mode
== 4 && ctl
== 1)
328 mwhl_value
= val
/ 127.f
;
334 ///////////////////////////////////////////////////////////////////////////////////////////////
336 void multichorus_audio_module::activate()
342 void multichorus_audio_module::deactivate()
347 void multichorus_audio_module::set_sample_rate(uint32_t sr
) {
353 bool multichorus_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
357 int nvoices
= (int)*params
[par_voices
];
358 if (index
== par_delay
&& subindex
< 3)
361 set_channel_color(context
, subindex
);
363 context
->set_source_rgba(0.35, 0.4, 0.2);
364 context
->set_line_width(1.0);
366 return ::get_graph(*this, subindex
, data
, points
);
368 if (index
== par_rate
&& subindex
< nvoices
) {
369 sine_multi_lfo
<float, 8> &lfo
= left
.lfo
;
370 for (int i
= 0; i
< points
; i
++) {
371 float phase
= i
* 2 * M_PI
/ points
;
372 // original -65536 to 65535 value
373 float orig
= subindex
* lfo
.voice_offset
+ ((lfo
.voice_depth
>> (30-13)) * 65536.0 * (0.95 * sin(phase
) + 1)/ 8192.0) - 65536;
375 data
[i
] = orig
/ 65536.0;
382 bool multichorus_audio_module::get_dot(int index
, int subindex
, float &x
, float &y
, int &size
, cairo_iface
*context
)
384 int voice
= subindex
>> 1;
385 int nvoices
= (int)*params
[par_voices
];
386 if ((index
!= par_rate
&& index
!= par_depth
) || voice
>= nvoices
)
389 float unit
= (1 - *params
[par_overlap
]);
390 float scw
= 1 + unit
* (nvoices
- 1);
391 set_channel_color(context
, subindex
);
392 sine_multi_lfo
<float, 8> &lfo
= (subindex
& 1 ? right
: left
).lfo
;
393 if (index
== par_rate
)
395 x
= (double)(lfo
.phase
+ lfo
.vphase
* voice
) / 4096.0;
396 y
= 0.95 * sin(x
* 2 * M_PI
);
397 y
= (voice
* unit
+ (y
+ 1) / 2) / scw
* 2 - 1;
401 double ph
= (double)(lfo
.phase
+ lfo
.vphase
* voice
) / 4096.0;
402 x
= 0.5 + 0.5 * sin(ph
* 2 * M_PI
);
403 y
= subindex
& 1 ? -0.75 : 0.75;
404 x
= (voice
* unit
+ x
) / scw
;
409 bool multichorus_audio_module::get_gridline(int index
, int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
)
411 if (index
== par_rate
&& !subindex
)
417 if (index
== par_delay
)
418 return get_freq_gridline(subindex
, pos
, vertical
, legend
, context
);
422 float multichorus_audio_module::freq_gain(int subindex
, float freq
, float srate
)
425 return *params
[par_amount
] * left
.post
.freq_gain(freq
, srate
);
426 return (subindex
? right
: left
).freq_gain(freq
, srate
);
429 ///////////////////////////////////////////////////////////////////////////////////////////////
431 compressor_audio_module::compressor_audio_module()
438 void compressor_audio_module::activate()
446 void compressor_audio_module::deactivate()
451 void compressor_audio_module::set_sample_rate(uint32_t sr
)
458 bool compressor_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
462 if (subindex
> 1) // 1
464 for (int i
= 0; i
< points
; i
++)
466 float input
= dB_grid_inv(-1.0 + i
* 2.0 / (points
- 1));
467 float output
= output_level(input
);
469 data
[i
] = dB_grid(input
);
471 data
[i
] = dB_grid(output
);
473 if (subindex
== (*params
[param_bypass
] > 0.5f
? 1 : 0))
474 context
->set_source_rgba(0.35, 0.4, 0.2, 0.3);
476 context
->set_source_rgba(0.35, 0.4, 0.2, 1);
477 context
->set_line_width(2);
482 bool compressor_audio_module::get_dot(int index
, int subindex
, float &x
, float &y
, int &size
, cairo_iface
*context
)
488 bool rms
= *params
[param_detection
] == 0;
489 float det
= rms
? sqrt(detected
) : detected
;
490 x
= 0.5 + 0.5 * dB_grid(det
);
491 y
= dB_grid(*params
[param_bypass
] > 0.5f
? det
: output_level(det
));
492 return *params
[param_bypass
] > 0.5f
? false : true;
497 bool compressor_audio_module::get_gridline(int index
, int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
)
500 vertical
= (subindex
& 1) != 0;
501 bool result
= get_freq_gridline(subindex
>> 1, pos
, tmp
, legend
, context
, false);
502 if (result
&& vertical
) {
503 if ((subindex
& 4) && !legend
.empty()) {
507 size_t pos
= legend
.find(" dB");
508 if (pos
!= std::string::npos
)
511 pos
= 0.5 + 0.5 * pos
;
516 // In case of doubt: this function is written by Thor. I just moved it to this file, damaging
517 // the output of "git annotate" in the process.
518 uint32_t compressor_audio_module::process(uint32_t offset
, uint32_t numsamples
, uint32_t inputs_mask
, uint32_t outputs_mask
)
520 bool bypass
= *params
[param_bypass
] > 0.5f
;
523 numsamples
+= offset
;
524 while(offset
< numsamples
) {
525 outs
[0][offset
] = ins
[0][offset
];
526 outs
[1][offset
] = ins
[1][offset
];
530 if(params
[param_compression
] != NULL
) {
531 *params
[param_compression
] = 1.f
;
534 if(params
[param_clip
] != NULL
) {
535 *params
[param_clip
] = 0.f
;
538 if(params
[param_peak
] != NULL
) {
539 *params
[param_peak
] = 0.f
;
545 bool rms
= *params
[param_detection
] == 0;
546 bool average
= *params
[param_stereo_link
] == 0;
547 int aweighting
= fastf2i_drm(*params
[param_aweighting
]);
548 float linThreshold
= *params
[param_threshold
];
549 ratio
= *params
[param_ratio
];
550 float attack
= *params
[param_attack
];
551 float attack_coeff
= std::min(1.f
, 1.f
/ (attack
* srate
/ 4000.f
));
552 float release
= *params
[param_release
];
553 float release_coeff
= std::min(1.f
, 1.f
/ (release
* srate
/ 4000.f
));
554 makeup
= *params
[param_makeup
];
555 knee
= *params
[param_knee
];
557 float linKneeSqrt
= sqrt(knee
);
558 linKneeStart
= linThreshold
/ linKneeSqrt
;
559 adjKneeStart
= linKneeStart
*linKneeStart
;
560 float linKneeStop
= linThreshold
* linKneeSqrt
;
562 threshold
= log(linThreshold
);
563 kneeStart
= log(linKneeStart
);
564 kneeStop
= log(linKneeStop
);
565 compressedKneeStop
= (kneeStop
- threshold
) / ratio
+ threshold
;
569 bpL
.set_highshelf_rbj(5000, 0.707, 10 << (aweighting
- 2), srate
);
570 bpR
.copy_coeffs(bpL
);
575 numsamples
+= offset
;
577 float compression
= 1.f
;
579 peak
-= peak
* 5.f
* numsamples
/ srate
;
581 clip
-= std::min(clip
, numsamples
);
583 while(offset
< numsamples
) {
584 float left
= ins
[0][offset
];
585 float right
= ins
[1][offset
];
587 if(aweighting
== 1) {
588 left
= awL
.process(left
);
589 right
= awR
.process(right
);
591 else if(aweighting
>= 2) {
592 left
= bpL
.process(left
);
593 right
= bpR
.process(right
);
596 float absample
= average
? (fabs(left
) + fabs(right
)) * 0.5f
: std::max(fabs(left
), fabs(right
));
597 if(rms
) absample
*= absample
;
599 linSlope
+= (absample
- linSlope
) * (absample
> linSlope
? attack_coeff
: release_coeff
);
604 gain
= output_gain(linSlope
, rms
);
610 float outL
= ins
[0][offset
] * gain
;
611 float outR
= ins
[1][offset
] * gain
;
613 outs
[0][offset
] = outL
;
614 outs
[1][offset
] = outR
;
618 float maxLR
= std::max(fabs(outL
), fabs(outR
));
620 if(maxLR
> 1.f
) clip
= srate
>> 3; /* blink clip LED for 125 ms */
629 if(params
[param_compression
] != NULL
) {
630 *params
[param_compression
] = compression
;
633 if(params
[param_clip
] != NULL
) {
634 *params
[param_clip
] = clip
;
637 if(params
[param_peak
] != NULL
) {
638 *params
[param_peak
] = peak
;
645 /// Multibandcompressor by Markus Schmidt
647 /// This module splits the signal in four different bands
648 /// and sends them through multiple filters (implemented by
649 /// Krzysztof). They are processed by a compressing routine
650 /// (implemented by Thor) afterwards and summed up to the
651 /// final output again.
652 ///////////////////////////////////////////////////////////////////////////////////////////////
654 multibandcompressor_audio_module::multibandcompressor_audio_module()
669 void multibandcompressor_audio_module::activate()
672 // set all filters and strips
674 // activate all strips
675 for (int j
= 0; j
< strips
; j
++) {
681 void multibandcompressor_audio_module::deactivate()
684 // deactivate all strips
685 for (int j
= 0; j
< strips
; j
++) {
686 strip
[j
].deactivate();
690 void multibandcompressor_audio_module::params_changed()
692 // set the params of all filters
693 if(*params
[param_freq0
] != freq_old
[0] or *params
[param_sep0
] != sep_old
[0] or *params
[param_q0
] != q_old
[0]) {
694 lpL0
.set_lp_rbj((float)(*params
[param_freq0
] * (1 - *params
[param_sep0
])), *params
[param_q0
], (float)srate
);
695 lpR0
.set_lp_rbj((float)(*params
[param_freq0
] * (1 - *params
[param_sep0
])), *params
[param_q0
], (float)srate
);
696 hpL0
.set_hp_rbj((float)(*params
[param_freq0
] * (1 + *params
[param_sep0
])), *params
[param_q0
], (float)srate
);
697 hpR0
.set_hp_rbj((float)(*params
[param_freq0
] * (1 + *params
[param_sep0
])), *params
[param_q0
], (float)srate
);
698 freq_old
[0] = *params
[param_freq0
];
699 sep_old
[0] = *params
[param_sep2
];
700 q_old
[0] = *params
[param_q2
];
702 if(*params
[param_freq1
] != freq_old
[1] or *params
[param_sep1
] != sep_old
[1] or *params
[param_q1
] != q_old
[1]) {
703 lpL1
.set_lp_rbj((float)(*params
[param_freq1
] * (1 - *params
[param_sep1
])), *params
[param_q1
], (float)srate
);
704 lpR1
.set_lp_rbj((float)(*params
[param_freq1
] * (1 - *params
[param_sep1
])), *params
[param_q1
], (float)srate
);
705 hpL1
.set_hp_rbj((float)(*params
[param_freq1
] * (1 + *params
[param_sep1
])), *params
[param_q1
], (float)srate
);
706 hpR1
.set_hp_rbj((float)(*params
[param_freq1
] * (1 + *params
[param_sep1
])), *params
[param_q1
], (float)srate
);
707 freq_old
[1] = *params
[param_freq1
];
708 sep_old
[1] = *params
[param_sep2
];
709 q_old
[1] = *params
[param_q2
];
711 if(*params
[param_freq2
] != freq_old
[2] or *params
[param_sep2
] != sep_old
[2] or *params
[param_q2
] != q_old
[2]) {
712 lpL2
.set_lp_rbj((float)(*params
[param_freq2
] * (1 - *params
[param_sep2
])), *params
[param_q2
], (float)srate
);
713 lpR2
.set_lp_rbj((float)(*params
[param_freq2
] * (1 - *params
[param_sep2
])), *params
[param_q2
], (float)srate
);
714 hpL2
.set_hp_rbj((float)(*params
[param_freq2
] * (1 + *params
[param_sep2
])), *params
[param_q2
], (float)srate
);
715 hpR2
.set_hp_rbj((float)(*params
[param_freq2
] * (1 + *params
[param_sep2
])), *params
[param_q2
], (float)srate
);
716 freq_old
[2] = *params
[param_freq2
];
717 sep_old
[2] = *params
[param_sep2
];
718 q_old
[2] = *params
[param_q2
];
720 // set the params of all strips
721 for (int j
= 0; j
< strips
; j
++) {
724 strip
[j
].set_params(*params
[param_attack0
], *params
[param_release0
], *params
[param_threshold0
], *params
[param_ratio0
], *params
[param_knee0
], *params
[param_makeup0
], *params
[param_detection0
], *params
[param_bypass0
], *params
[param_mute0
]);
727 strip
[j
].set_params(*params
[param_attack1
], *params
[param_release1
], *params
[param_threshold1
], *params
[param_ratio1
], *params
[param_knee1
], *params
[param_makeup1
], *params
[param_detection1
], *params
[param_bypass1
], *params
[param_mute1
]);
730 strip
[j
].set_params(*params
[param_attack2
], *params
[param_release2
], *params
[param_threshold2
], *params
[param_ratio2
], *params
[param_knee2
], *params
[param_makeup2
], *params
[param_detection2
], *params
[param_bypass2
], *params
[param_mute2
]);
733 strip
[j
].set_params(*params
[param_attack3
], *params
[param_release3
], *params
[param_threshold3
], *params
[param_ratio3
], *params
[param_knee3
], *params
[param_makeup3
], *params
[param_detection3
], *params
[param_bypass3
], *params
[param_mute3
]);
739 void multibandcompressor_audio_module::set_sample_rate(uint32_t sr
)
742 // set srate of all strips
743 for (int j
= 0; j
< strips
; j
++) {
744 strip
[j
].set_sample_rate(srate
);
748 uint32_t multibandcompressor_audio_module::process(uint32_t offset
, uint32_t numsamples
, uint32_t inputs_mask
, uint32_t outputs_mask
)
750 bool bypass
= *params
[param_bypass
] > 0.5f
;
751 numsamples
+= offset
;
753 // everything bypassed
754 while(offset
< numsamples
) {
755 outs
[0][offset
] = ins
[0][offset
];
756 outs
[1][offset
] = ins
[1][offset
];
769 // process all strips
771 // determine mute state of strips
772 mute
[0] = *params
[param_mute0
] > 0.f
? true : false;
773 mute
[1] = *params
[param_mute1
] > 0.f
? true : false;
774 mute
[2] = *params
[param_mute2
] > 0.f
? true : false;
775 mute
[3] = *params
[param_mute3
] > 0.f
? true : false;
777 // let meters fall a bit
778 clip_inL
-= std::min(clip_inL
, numsamples
);
779 clip_inR
-= std::min(clip_inR
, numsamples
);
780 clip_outL
-= std::min(clip_outL
, numsamples
);
781 clip_outR
-= std::min(clip_outR
, numsamples
);
782 meter_inL
-= meter_inL
* 2.5 * numsamples
/ srate
;
783 meter_inR
-= meter_inR
* 2.5 * numsamples
/ srate
;
784 meter_outL
-= meter_outL
* 2.5 * numsamples
/ srate
;
785 meter_outR
-= meter_outR
* 2.5 * numsamples
/ srate
;
787 while(offset
< numsamples
) {
788 // cycle through samples
789 float inL
= ins
[0][offset
];
790 float inR
= ins
[1][offset
];
792 inR
*= *params
[param_level_in
];
793 inL
*= *params
[param_level_in
];
797 for (int i
= 0; i
< strips
; i
++) {
798 // cycle trough strips
803 // send trough filters
806 left
= lpL0
.process(left
);
807 right
= lpR0
.process(right
);
812 left
= lpL1
.process(left
);
813 right
= lpR1
.process(right
);
814 left
= hpL0
.process(left
);
815 right
= hpR0
.process(right
);
822 left
= lpL2
.process(left
);
823 right
= lpR2
.process(right
);
824 left
= hpL1
.process(left
);
825 right
= hpR1
.process(right
);
832 left
= hpL2
.process(left
);
833 right
= hpR2
.process(right
);
838 // process gain reduction
839 strip
[i
].process(left
, right
);
849 } // process single strip
851 // even out filters gain reduction
852 // 3dB - levelled manually (based on default sep and q settings)
857 outL
*= *params
[param_level_out
];
858 outR
*= *params
[param_level_out
];
861 outs
[0][offset
] = outL
;
862 outs
[1][offset
] = outR
;
866 clip_inL
= srate
>> 3;
869 clip_inR
= srate
>> 3;
872 clip_outL
= srate
>> 3;
875 clip_outR
= srate
>> 3;
877 // rise up in / out meters
878 if(inL
> meter_inL
) {
881 if(inR
> meter_inR
) {
884 if(outL
> meter_outL
) {
887 if(outR
> meter_outR
) {
892 } // cycle trough samples
894 } // process all strips (no bypass)
897 if(params
[param_clip_inL
] != NULL
) {
898 *params
[param_clip_inL
] = clip_inL
;
900 if(params
[param_clip_inR
] != NULL
) {
901 *params
[param_clip_inR
] = clip_inR
;
903 if(params
[param_clip_outL
] != NULL
) {
904 *params
[param_clip_outL
] = clip_outL
;
906 if(params
[param_clip_outR
] != NULL
) {
907 *params
[param_clip_outR
] = clip_outR
;
910 if(params
[param_meter_inL
] != NULL
) {
911 *params
[param_meter_inL
] = meter_inL
;
913 if(params
[param_meter_inR
] != NULL
) {
914 *params
[param_meter_inR
] = meter_inR
;
916 if(params
[param_meter_outL
] != NULL
) {
917 *params
[param_meter_outL
] = meter_outL
;
919 if(params
[param_meter_outR
] != NULL
) {
920 *params
[param_meter_outR
] = meter_outR
;
924 if(params
[param_compression0
] != NULL
) {
925 *params
[param_compression0
] = 1.0f
;
927 if(params
[param_compression1
] != NULL
) {
928 *params
[param_compression1
] = 1.0f
;
930 if(params
[param_compression2
] != NULL
) {
931 *params
[param_compression2
] = 1.0f
;
933 if(params
[param_compression3
] != NULL
) {
934 *params
[param_compression3
] = 1.0f
;
937 if(params
[param_output0
] != NULL
) {
938 *params
[param_output0
] = 0.0f
;
940 if(params
[param_output1
] != NULL
) {
941 *params
[param_output1
] = 0.0f
;
943 if(params
[param_output2
] != NULL
) {
944 *params
[param_output2
] = 0.0f
;
946 if(params
[param_output3
] != NULL
) {
947 *params
[param_output3
] = 0.0f
;
950 if(params
[param_compression0
] != NULL
) {
951 *params
[param_compression0
] = strip
[0].get_comp_level();
953 if(params
[param_compression1
] != NULL
) {
954 *params
[param_compression1
] = strip
[1].get_comp_level();
956 if(params
[param_compression2
] != NULL
) {
957 *params
[param_compression2
] = strip
[2].get_comp_level();
959 if(params
[param_compression3
] != NULL
) {
960 *params
[param_compression3
] = strip
[3].get_comp_level();
963 if(params
[param_output0
] != NULL
) {
964 *params
[param_output0
] = strip
[0].get_output_level();
966 if(params
[param_output1
] != NULL
) {
967 *params
[param_output1
] = strip
[1].get_output_level();
969 if(params
[param_output2
] != NULL
) {
970 *params
[param_output2
] = strip
[2].get_output_level();
972 if(params
[param_output3
] != NULL
) {
973 *params
[param_output3
] = strip
[3].get_output_level();
976 // whatever has to be returned x)
979 bool multibandcompressor_audio_module::get_graph(int index
, int subindex
, float *data
, int points
, cairo_iface
*context
)
981 // let's handle by the corresponding strip
983 case param_compression0
:
984 return strip
[0].get_graph(subindex
, data
, points
, context
);
986 case param_compression1
:
987 return strip
[1].get_graph(subindex
, data
, points
, context
);
989 case param_compression2
:
990 return strip
[2].get_graph(subindex
, data
, points
, context
);
992 case param_compression3
:
993 return strip
[3].get_graph(subindex
, data
, points
, context
);
999 bool multibandcompressor_audio_module::get_dot(int index
, int subindex
, float &x
, float &y
, int &size
, cairo_iface
*context
)
1001 // let's handle by the corresponding strip
1003 case param_compression0
:
1004 return strip
[0].get_dot(subindex
, x
, y
, size
, context
);
1006 case param_compression1
:
1007 return strip
[1].get_dot(subindex
, x
, y
, size
, context
);
1009 case param_compression2
:
1010 return strip
[2].get_dot(subindex
, x
, y
, size
, context
);
1012 case param_compression3
:
1013 return strip
[3].get_dot(subindex
, x
, y
, size
, context
);
1019 bool multibandcompressor_audio_module::get_gridline(int index
, int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
)
1021 // let's handle by the corresponding strip
1023 case param_compression0
:
1024 return strip
[0].get_gridline(subindex
, pos
, vertical
, legend
, context
);
1026 case param_compression1
:
1027 return strip
[1].get_gridline(subindex
, pos
, vertical
, legend
, context
);
1029 case param_compression2
:
1030 return strip
[2].get_gridline(subindex
, pos
, vertical
, legend
, context
);
1032 case param_compression3
:
1033 return strip
[3].get_gridline(subindex
, pos
, vertical
, legend
, context
);
1039 int multibandcompressor_audio_module::get_changed_offsets(int index
, int generation
, int &subindex_graph
, int &subindex_dot
, int &subindex_gridline
)
1041 // let's handle by the corresponding strip
1043 case param_compression0
:
1044 return strip
[0].get_changed_offsets(generation
, subindex_graph
, subindex_dot
, subindex_gridline
);
1046 case param_compression1
:
1047 return strip
[1].get_changed_offsets(generation
, subindex_graph
, subindex_dot
, subindex_gridline
);
1049 case param_compression2
:
1050 return strip
[2].get_changed_offsets(generation
, subindex_graph
, subindex_dot
, subindex_gridline
);
1052 case param_compression3
:
1053 return strip
[3].get_changed_offsets(generation
, subindex_graph
, subindex_dot
, subindex_gridline
);
1058 /// Gain reduction module implemented by Markus Schmidt
1059 /// Nearly all functions of this module are originally written
1060 /// by Thor, while some features have been stripped (mainly stereo linking
1061 /// and frequency correction as implemented in his Compressor above)
1062 /// To save some CPU.
1063 ////////////////////////////////////////////////////////////////////////////////
1064 gain_reduction_audio_module::gain_reduction_audio_module()
1067 last_generation
= 0;
1070 void gain_reduction_audio_module::activate()
1084 void gain_reduction_audio_module::deactivate()
1089 void gain_reduction_audio_module::process(float &left
, float &right
)
1091 float compression
= 1.f
;
1092 meter_out
-= meter_out
* 5.f
* 1 / srate
;
1094 // this routine is mainly copied from thor's compressor module
1095 // greatest sounding compressor I've heard!
1096 bool rms
= detection
== 0;
1097 float linThreshold
= threshold
;
1098 float attack_coeff
= std::min(1.f
, 1.f
/ (attack
* srate
/ 4000.f
));
1099 float release_coeff
= std::min(1.f
, 1.f
/ (release
* srate
/ 4000.f
));
1100 float linKneeSqrt
= sqrt(knee
);
1101 linKneeStart
= linThreshold
/ linKneeSqrt
;
1102 adjKneeStart
= linKneeStart
*linKneeStart
;
1103 float linKneeStop
= linThreshold
* linKneeSqrt
;
1104 thres
= log(linThreshold
);
1105 kneeStart
= log(linKneeStart
);
1106 kneeStop
= log(linKneeStop
);
1107 compressedKneeStop
= (kneeStop
- thres
) / ratio
+ thres
;
1109 float absample
= (fabs(left
) + fabs(right
)) * 0.5f
;
1110 if(rms
) absample
*= absample
;
1112 linSlope
+= (absample
- linSlope
) * (absample
> linSlope
? attack_coeff
: release_coeff
);
1116 if(linSlope
> 0.f
) {
1117 gain
= output_gain(linSlope
, rms
);
1126 detected
= rms
? sqrt(linSlope
) : linSlope
;
1129 float maxLR
= std::max(fabs(left
), fabs(right
));
1131 if(maxLR
> meter_out
) {
1134 meter_comp
= compression
;
1137 float gain_reduction_audio_module::output_level(float slope
) {
1138 return slope
* output_gain(slope
, false) * makeup
;
1141 float gain_reduction_audio_module::output_gain(float linSlope
, bool rms
) {
1142 //this calculation is also thor's work
1143 if(linSlope
> (rms
? adjKneeStart
: linKneeStart
)) {
1144 float slope
= log(linSlope
);
1145 if(rms
) slope
*= 0.5f
;
1149 if(IS_FAKE_INFINITY(ratio
)) {
1153 gain
= (slope
- thres
) / ratio
+ thres
;
1154 delta
= 1.f
/ ratio
;
1157 if(knee
> 1.f
&& slope
< kneeStop
) {
1158 gain
= hermite_interpolation(slope
, kneeStart
, kneeStop
, kneeStart
, compressedKneeStop
, 1.f
, delta
);
1161 return exp(gain
- slope
);
1167 void gain_reduction_audio_module::set_sample_rate(uint32_t sr
)
1171 void gain_reduction_audio_module::set_params(float att
, float rel
, float thr
, float rat
, float kn
, float mak
, float det
, float byp
, float mu
)
1188 float gain_reduction_audio_module::get_output_level() {
1189 // returns output level (max(left, right))
1192 float gain_reduction_audio_module::get_comp_level() {
1193 // returns amount of compression
1197 bool gain_reduction_audio_module::get_graph(int subindex
, float *data
, int points
, cairo_iface
*context
)
1201 if (subindex
> 1) // 1
1203 for (int i
= 0; i
< points
; i
++)
1205 float input
= dB_grid_inv(-1.0 + i
* 2.0 / (points
- 1));
1207 data
[i
] = dB_grid(input
);
1209 float output
= output_level(input
);
1210 data
[i
] = dB_grid(output
);
1213 if (subindex
== (bypass
> 0.5f
? 1 : 0) or mute
> 0.1f
)
1214 context
->set_source_rgba(0.35, 0.4, 0.2, 0.3);
1216 context
->set_source_rgba(0.35, 0.4, 0.2, 1);
1217 context
->set_line_width(1.5);
1222 bool gain_reduction_audio_module::get_dot(int subindex
, float &x
, float &y
, int &size
, cairo_iface
*context
)
1228 if(bypass
> 0.5f
or mute
> 0.f
) {
1231 bool rms
= detection
== 0;
1232 float det
= rms
? sqrt(detected
) : detected
;
1233 x
= 0.5 + 0.5 * dB_grid(det
);
1234 y
= dB_grid(bypass
> 0.5f
or mute
> 0.f
? det
: output_level(det
));
1241 bool gain_reduction_audio_module::get_gridline(int subindex
, float &pos
, bool &vertical
, std::string
&legend
, cairo_iface
*context
)
1244 vertical
= (subindex
& 1) != 0;
1245 bool result
= get_freq_gridline(subindex
>> 1, pos
, tmp
, legend
, context
, false);
1246 if (result
&& vertical
) {
1247 if ((subindex
& 4) && !legend
.empty()) {
1251 size_t pos
= legend
.find(" dB");
1252 if (pos
!= std::string::npos
)
1255 pos
= 0.5 + 0.5 * pos
;
1260 int gain_reduction_audio_module::get_changed_offsets(int generation
, int &subindex_graph
, int &subindex_dot
, int &subindex_gridline
)
1264 subindex_gridline
= generation
? INT_MAX
: 0;
1266 if (fabs(threshold
-old_threshold
) + fabs(ratio
- old_ratio
) + fabs(knee
- old_knee
) + fabs(makeup
- old_makeup
) + fabs(detection
- old_detection
) + fabs(bypass
- old_bypass
) + fabs(mute
- old_mute
) > 0.000001f
)
1268 old_threshold
= threshold
;
1271 old_makeup
= makeup
;
1272 old_detection
= detection
;
1273 old_bypass
= bypass
;
1278 if (generation
== last_generation
)
1280 return last_generation
;