1 /* Calf DSP plugin pack
2  * Equalization related plugins
3  *
4  * Copyright (C) 2001-2010 Krzysztof Foltman, Markus Schmidt, Thor Harald Johansen and others
5  *
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.
10  *
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.
15  *
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 02111-1307, USA.
20  */
21 #ifndef CALF_MODULES_FILTER_H
22 #define CALF_MODULES_FILTER_H
23 
24 #include <assert.h>
25 #include <limits.h>
26 #include "biquad.h"
27 #include "inertia.h"
28 #include "audio_fx.h"
29 #include "giface.h"
30 #include "metadata.h"
31 #include "plugin_tools.h"
32 #include "loudness.h"
33 #include "analyzer.h"
34 #include "bypass.h"
35 #include "orfanidis_eq.h"
36 
37 namespace calf_plugins {
38 
39 /**********************************************************************
40  * EQUALIZER N BAND by Markus Schmidt and Krzysztof Foltman
41 **********************************************************************/
42 
43 template<class BaseClass, bool has_lphp>
44 class equalizerNband_audio_module: public audio_module<BaseClass>, public frequency_response_line_graph {
45 public:
46     typedef audio_module<BaseClass> AM;
47     using AM::ins;
48     using AM::outs;
49     using AM::params;
50     using AM::in_count;
51     using AM::out_count;
52     using AM::param_count;
53     using AM::PeakBands;
54 private:
55     analyzer _analyzer;
56     enum { graph_param_count = BaseClass::last_graph_param - BaseClass::first_graph_param + 1, params_per_band = AM::param_p2_active - AM::param_p1_active };
57     float hp_mode_old, hp_freq_old, hp_q_old;
58     float lp_mode_old, lp_freq_old, lp_q_old;
59     float ls_level_old, ls_freq_old, ls_q_old;
60     float hs_level_old, hs_freq_old, hs_q_old;
61     int indiv_old;
62     bool analyzer_old;
63     float p_level_old[PeakBands], p_freq_old[PeakBands], p_q_old[PeakBands];
64     mutable float old_params_for_graph[graph_param_count];
65     vumeters meters;
66     CalfEqMode hp_mode, lp_mode;
67     dsp::biquad_d2 hp[3][2], lp[3][2];
68     dsp::biquad_d2 lsL, lsR, hsL, hsR;
69     dsp::biquad_d2 pL[PeakBands], pR[PeakBands];
70     dsp::bypass bypass;
71     int keep_gliding;
72     mutable int last_peak;
73     inline void process_hplp(float &left, float &right);
74 public:
75     typedef std::complex<double> cfloat;
76     uint32_t srate;
77     bool is_active;
78     mutable volatile int last_generation, last_calculated_generation;
79     equalizerNband_audio_module();
80     void activate();
81     void deactivate();
82 
83     void params_changed();
84     bool get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
85     bool get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const;
86     bool get_layers(int index, int generation, unsigned int &layers) const;
87     float freq_gain(int index, double freq) const;
88     std::string get_crosshair_label(int x, int y, int sx, int sy, float q, int dB, int name, int note, int cents) const;
89 
set_sample_rate(uint32_t sr)90     void set_sample_rate(uint32_t sr)
91     {
92         srate = sr;
93         _analyzer.set_sample_rate(sr);
94         int meter[] = {AM::param_meter_inL, AM::param_meter_inR,  AM::param_meter_outL, AM::param_meter_outR};
95         int clip[] = {AM::param_clip_inL, AM::param_clip_inR, AM::param_clip_outL, AM::param_clip_outR};
96         meters.init(params, meter, clip, 4, sr);
97     }
98     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
99 };
100 
101 typedef equalizerNband_audio_module<equalizer5band_metadata,  false> equalizer5band_audio_module;
102 typedef equalizerNband_audio_module<equalizer8band_metadata,  true>  equalizer8band_audio_module;
103 typedef equalizerNband_audio_module<equalizer12band_metadata, true>  equalizer12band_audio_module;
104 
105 /**********************************************************************
106  * EQUALIZER 30 BAND
107 **********************************************************************/
108 
109 class equalizer30band_audio_module: public audio_module<equalizer30band_metadata> {
110     OrfanidisEq::Conversions conv;
111     OrfanidisEq::FrequencyGrid fg;
112     std::vector<OrfanidisEq::Eq*> eq_arrL;
113     std::vector<OrfanidisEq::Eq*> eq_arrR;
114 
115     OrfanidisEq::filter_type flt_type;
116     OrfanidisEq::filter_type flt_type_old;
117 
118     dsp::switcher<OrfanidisEq::filter_type> swL;
119     dsp::switcher<OrfanidisEq::filter_type> swR;
120 
121 public:
122     uint32_t srate;
123     bool is_active;
124     dsp::bypass bypass;
125     dsp::bypass eq_switch;
126     vumeters meters;
127     equalizer30band_audio_module();
128     ~equalizer30band_audio_module();
129 
130     void activate();
131     void deactivate();
132     void params_changed();
133     void set_sample_rate(uint32_t sr);
134     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
135 };
136 
137 /**********************************************************************
138  * FILTER MODULE by Krzysztof Foltman
139 **********************************************************************/
140 
141 template<typename FilterClass, typename Metadata>
142 class filter_module_with_inertia: public audio_module<Metadata>, public FilterClass,
143 public frequency_response_line_graph
144 {
145     using FilterClass::calculate_filter;
146     using FilterClass::freq_gain;
147 public:
148     /// These are pointers to the ins, outs, params arrays in the main class
149     typedef filter_module_with_inertia inertia_filter_module;
150     using audio_module<Metadata>::ins;
151     using audio_module<Metadata>::outs;
152     using audio_module<Metadata>::params;
153 
154     dsp::inertia<dsp::exponential_ramp> inertia_cutoff, inertia_resonance, inertia_gain;
155     dsp::once_per_n timer;
156     bool is_active;
157     mutable volatile int last_generation, last_calculated_generation;
158 
159     dsp::bypass bypass;
160     vumeters meters;
161 
filter_module_with_inertia()162     filter_module_with_inertia()
163     : inertia_cutoff(dsp::exponential_ramp(128), 20)
164     , inertia_resonance(dsp::exponential_ramp(128), 20)
165     , inertia_gain(dsp::exponential_ramp(128), 1.0)
166     , timer(128)
167     , is_active(false)
168     , last_generation(-1)
169     , last_calculated_generation(-2)
170     {}
171 
calculate_filter()172     void calculate_filter()
173     {
174         float freq = inertia_cutoff.get_last();
175         // printf("freq=%g inr.cnt=%d timer.left=%d\n", freq, inertia_cutoff.count, timer.left);
176         // XXXKF this is resonance of a single stage, obviously for three stages, resonant gain will be different
177         float q    = inertia_resonance.get_last();
178         int   mode = dsp::fastf2i_drm(*params[Metadata::par_mode]);
179         // printf("freq = %f q = %f mode = %d\n", freq, q, mode);
180 
181         int inertia = dsp::fastf2i_drm(*params[Metadata::par_inertia]);
182         if (inertia != inertia_cutoff.ramp.length()) {
183             inertia_cutoff.ramp.set_length(inertia);
184             inertia_resonance.ramp.set_length(inertia);
185             inertia_gain.ramp.set_length(inertia);
186         }
187 
188         FilterClass::calculate_filter(freq, q, mode, inertia_gain.get_last());
189     }
190 
params_changed()191     virtual void params_changed()
192     {
193         calculate_filter();
194     }
195 
on_timer()196     void on_timer()
197     {
198         int gen = last_generation;
199         inertia_cutoff.step();
200         inertia_resonance.step();
201         inertia_gain.step();
202         calculate_filter();
203         last_calculated_generation = gen;
204     }
205 
activate()206     void activate()
207     {
208         params_changed();
209         FilterClass::filter_activate();
210         timer = dsp::once_per_n(FilterClass::srate / 1000);
211         timer.start();
212         is_active = true;
213     }
214 
set_sample_rate(uint32_t sr)215     void set_sample_rate(uint32_t sr)
216     {
217         FilterClass::srate = sr;
218         int meter[] = {Metadata::param_meter_inL,  Metadata::param_meter_inR, Metadata::param_meter_outL, Metadata::param_meter_outR};
219         int clip[]  = {Metadata::param_clip_inL, Metadata::param_clip_inR, Metadata::param_clip_outL, Metadata::param_clip_outR};
220         meters.init(params, meter, clip, 4, sr);
221     }
222 
223 
deactivate()224     void deactivate()
225     {
226         is_active = false;
227     }
228 
process(uint32_t offset,uint32_t numsamples,uint32_t inputs_mask,uint32_t outputs_mask)229     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask) {
230 //        printf("sr=%d cutoff=%f res=%f mode=%f\n", FilterClass::srate, *params[Metadata::par_cutoff], *params[Metadata::par_resonance], *params[Metadata::par_mode]);
231         uint32_t ostate = 0;
232         uint32_t orig_offset = offset, orig_numsamples = numsamples;
233         bool bypassed = bypass.update(*params[Metadata::param_bypass] > 0.5f, numsamples);
234         if (bypassed) {
235             float values[] = {0,0,0,0};
236             for (uint32_t i = offset; i < offset + numsamples; i++) {
237                 outs[0][i] = ins[0][i];
238                 outs[1][i] = ins[1][i];
239                 //float values[] = {ins[0][i],ins[1][i],outs[0][i],outs[1][i]};
240                 meters.process(values);
241                 ostate = -1;
242             }
243         } else {
244             numsamples += offset;
245             while(offset < numsamples) {
246                 uint32_t numnow = numsamples - offset;
247                 // if inertia's inactive, we can calculate the whole buffer at once
248                 if (inertia_cutoff.active() || inertia_resonance.active() || inertia_gain.active())
249                     numnow = timer.get(numnow);
250                 if (outputs_mask & 1) {
251                     ostate |= FilterClass::process_channel(0, ins[0] + offset, outs[0] + offset, numnow, inputs_mask & 1, *params[Metadata::param_level_in], *params[Metadata::param_level_out]);
252                 }
253                 if (outputs_mask & 2) {
254                     ostate |= FilterClass::process_channel(1, ins[1] + offset, outs[1] + offset, numnow, inputs_mask & 2, *params[Metadata::param_level_in], *params[Metadata::param_level_out]);
255                 }
256                 if (timer.elapsed()) {
257                     on_timer();
258                 }
259                 for (uint32_t i = offset; i < offset + numnow; i++) {
260                     float values[] = {ins[0][i] * *params[Metadata::param_level_in], ins[1][i] * *params[Metadata::param_level_in], outs[0][i], outs[1][i]};
261                     meters.process(values);
262                 }
263                 offset += numnow;
264             }
265             bypass.crossfade(ins, outs, 2, orig_offset, orig_numsamples);
266         }
267         meters.fall(orig_numsamples);
268         return ostate;
269     }
freq_gain(int index,double freq)270     float freq_gain(int index, double freq) const {
271         return FilterClass::freq_gain(index, (float)freq, (float)FilterClass::srate);
272     }
273 };
274 
275 /**********************************************************************
276  * FILTER by Krzysztof Foltman
277 **********************************************************************/
278 
279 class filter_audio_module:
280     public filter_module_with_inertia<dsp::biquad_filter_module, filter_metadata>
281 {
282     mutable float old_cutoff, old_resonance, old_mode;
283 public:
filter_audio_module()284     filter_audio_module()
285     {
286         last_generation = 0;
287         old_mode = old_resonance = old_cutoff = -1;
288         redraw_graph = true;
289     }
params_changed()290     void params_changed()
291     {
292         inertia_cutoff.set_inertia(*params[par_cutoff]);
293         inertia_resonance.set_inertia(*params[par_resonance]);
294         inertia_filter_module::params_changed();
295         redraw_graph = true;
296     }
297 };
298 
299 /**********************************************************************
300  * FILTERKLAVIER by Hans Baier
301 **********************************************************************/
302 
303 class filterclavier_audio_module:
304         public filter_module_with_inertia<dsp::biquad_filter_module, filterclavier_metadata>
305 {
306     using audio_module<filterclavier_metadata>::ins;
307     using audio_module<filterclavier_metadata>::outs;
308     using audio_module<filterclavier_metadata>::params;
309 
310     const float min_gain;
311     const float max_gain;
312 
313     int last_note;
314     int last_velocity;
315 public:
316     filterclavier_audio_module();
317     void params_changed();
318     void activate();
319     void set_sample_rate(uint32_t sr);
320     void deactivate();
321 
322     /// MIDI control
323     virtual void note_on(int channel, int note, int vel);
324     virtual void note_off(int channel, int note, int vel);
325 private:
326     void adjust_gain_according_to_filter_mode(int velocity);
327 };
328 
329 /**********************************************************************
330  * EMPHASIS by Damien Zammit
331 **********************************************************************/
332 
333 class emphasis_audio_module: public audio_module<emphasis_metadata>, public frequency_response_line_graph {
334 public:
335     dsp::riaacurve riaacurvL, riaacurvR;
336     dsp::bypass bypass;
337     int mode, type, bypass_;
338     typedef std::complex<double> cfloat;
339     uint32_t srate;
340     bool is_active;
341     vumeters meters;
342     emphasis_audio_module();
343     void activate();
344     void deactivate();
345     void params_changed();
set_sample_rate(uint32_t sr)346     void set_sample_rate(uint32_t sr)
347     {
348         srate = sr;
349         int meter[] = {param_meter_inL, param_meter_inR,  param_meter_outL, param_meter_outR};
350         int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
351         meters.init(params, meter, clip, 4, sr);
352     }
freq_gain(int index,double freq)353     virtual float freq_gain(int index, double freq) const {
354         return riaacurvL.freq_gain(freq, (float)srate);
355     }
356     virtual bool get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const;
357     virtual bool get_gridline(int index, int subindex, int phase, float &pos, bool &vertical, std::string &legend, cairo_iface *context) const;
358     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
359 };
360 
361 /**********************************************************************
362  * CROSSOVER MODULES by Markus Schmidt
363 **********************************************************************/
364 
365 template<class XoverBaseClass>
366 class xover_audio_module: public audio_module<XoverBaseClass>, public frequency_response_line_graph {
367 public:
368     typedef audio_module<XoverBaseClass> AM;
369     using AM::ins;
370     using AM::outs;
371     using AM::params;
372     using AM::in_count;
373     using AM::out_count;
374     using AM::param_count;
375     using AM::bands;
376     using AM::channels;
377     enum { params_per_band = AM::param_level2 - AM::param_level1 };
378     uint32_t srate;
379     bool is_active;
380     float * buffer;
381     float in[channels];
382     unsigned int pos;
383     unsigned int buffer_size;
384     int last_peak;
sign(float x)385     static inline float sign(float x) {
386         if(x < 0) return -1.f;
387         if(x > 0) return 1.f;
388         return 0.f;
389     }
390     vumeters meters;
391     dsp::crossover crossover;
392     xover_audio_module();
393     ~xover_audio_module();
394     void activate();
395     void deactivate();
396     void params_changed();
397     void set_sample_rate(uint32_t sr);
398     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
399     bool get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const;
400     bool get_layers(int index, int generation, unsigned int &layers) const;
401 };
402 
403 typedef xover_audio_module<xover2_metadata> xover2_audio_module;
404 typedef xover_audio_module<xover3_metadata> xover3_audio_module;
405 typedef xover_audio_module<xover4_metadata> xover4_audio_module;
406 
407 /**********************************************************************
408  * VOCODER by Markus Schmidt & Christian Holschuh
409 **********************************************************************/
410 
411 class vocoder_audio_module: public audio_module<vocoder_metadata>, public frequency_response_line_graph {
412 public:
413     int bands, bands_old, order, hiq_old;
414     float order_old, lower_old, upper_old, tilt_old;
415     float q_old[32];
416     float bandfreq[32];
417     uint32_t srate;
418     bool is_active;
419     static const int maxorder = 8;
420     dsp::biquad_d2 detector[2][maxorder][32], modulator[2][maxorder][32];
421     dsp::bypass bypass;
422     double env_mods[2][32];
423     vumeters meters;
424     analyzer _analyzer;
425     double attack, release, fcoeff, log2_;
426     vocoder_audio_module();
427     void activate();
428     void deactivate();
429     void params_changed();
430     int get_solo() const;
set_sample_rate(uint32_t sr)431     void set_sample_rate(uint32_t sr)
432     {
433         srate = sr;
434         _analyzer.set_sample_rate(sr);
435         int meter[] = {param_carrier_inL, param_carrier_inR,  param_mod_inL, param_mod_inR, param_outL, param_outR};
436         int clip[] = {param_carrier_clip_inL, param_carrier_clip_inR, param_mod_clip_inL, param_mod_clip_inR, param_clip_outL, param_clip_outR};
437         meters.init(params, meter, clip, 6, sr);
438     }
439     virtual bool get_graph(int index, int subindex, int phase, float *data, int points, cairo_iface *context, int *mode) const;
440     virtual bool get_layers(int index, int generation, unsigned int &layers) const;
441     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
442 };
443 
444 /**********************************************************************
445  * ENVELOPE FILTER by Markus Schmidt
446 **********************************************************************/
447 
448 class envelopefilter_audio_module: public audio_module<envelopefilter_metadata>, public dsp::biquad_filter_module,
449 public frequency_response_line_graph
450 {
451     using dsp::biquad_filter_module::freq_gain;
452 public:
453     uint32_t srate;
454     bool is_active;
455 
456     dsp::bypass bypass;
457     vumeters meters;
458 
459     float envelope, attack, release, envelope_old, attack_old, release_old, q_old;
460     float gain, gain_old, upper, upper_old, lower, lower_old;
461     float coefa, coefb, coefz;
462     int mode, mode_old;
463 
envelopefilter_audio_module()464     envelopefilter_audio_module()
465     {
466         envelope = envelope_old = 0;
467         lower = 10; lower_old = 0;
468         upper = 10; upper_old = 0;
469         gain  = 1;  gain_old  = 0;
470         attack = release = attack_old = release_old = -1;
471         mode = mode_old = q_old = 0;
472         coefa = coefb = 0;
473         coefz = 2;
474     }
475 
activate()476     void activate()
477     {
478         params_changed();
479         filter_activate();
480         is_active = true;
481     }
482 
deactivate()483     void deactivate()
484     {
485         is_active = false;
486     }
487 
set_sample_rate(uint32_t sr)488     void set_sample_rate(uint32_t sr)
489     {
490         srate = sr;
491         dsp::biquad_filter_module::srate = sr;
492         int meter[] = {param_meter_inL, param_meter_inR, param_meter_outL, param_meter_outR};
493         int clip[] = {param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR};
494         meters.init(params, meter, clip, 4, sr);
495     }
496 
params_changed()497     void params_changed()
498     {
499         if (*params[param_attack] != attack_old) {
500             attack_old = *params[param_attack];
501             attack     = exp(log(0.01)/( attack_old * srate * 0.001));
502         }
503         if (*params[param_release] != release_old) {
504             release_old = *params[param_release];
505             release     = exp(log(0.01)/( release_old * srate * 0.001));
506         }
507         if (*params[param_mode] != mode_old) {
508             mode = dsp::fastf2i_drm(*params[param_mode]);
509             mode_old = *params[param_mode];
510             calc_filter();
511         }
512         if (*params[param_q] != q_old) {
513             q_old = *params[param_q];
514             calc_filter();
515         }
516         if (*params[param_upper] != upper_old) {
517             upper = *params[param_upper];
518             upper_old = *params[param_upper];
519             calc_coef();
520             calc_filter();
521         }
522         if (*params[param_lower] != lower_old) {
523             lower = *params[param_lower];
524             lower_old = *params[param_lower];
525             calc_coef();
526             calc_filter();
527         }
528         if (*params[param_gain] != gain_old) {
529             gain = *params[param_gain];
530             gain_old = *params[param_gain];
531             calc_filter();
532         }
533     }
534 
process(uint32_t offset,uint32_t numsamples,uint32_t inputs_mask,uint32_t outputs_mask)535     uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
536     {
537         bool bypassed = bypass.update(*params[param_bypass] > 0.5f, numsamples);
538         uint32_t end = numsamples + offset;
539         while(offset < end) {
540             float D;
541             if (*params[param_sidechain] > 0.5)
542                 D = std::max(fabs(ins[2][offset]), fabs(ins[3][offset])) * *params[param_gain];
543             else
544                 D = std::max(fabs(ins[0][offset]), fabs(ins[1][offset])) * *params[param_gain];
545 
546             // advance envelope
547             envelope = std::min(1.f, (D > envelope ? attack : release) * (envelope - D) + D);
548             if (envelope != envelope_old) {
549                 envelope_old = envelope;
550                 redraw_graph = true;
551                 dsp::biquad_filter_module::calculate_filter(get_freq(envelope), *params[param_q], mode, 1.0);
552             }
553 
554             if(bypassed) {
555                 outs[0][offset]  = ins[0][offset];
556                 outs[1][offset]  = ins[1][offset];
557                 float values[] = {0, 0, 0, 0};
558                 meters.process(values);
559             } else {
560                 const float inL  = ins[0][offset] * *params[param_level_in];
561                 const float inR  = ins[1][offset] * *params[param_level_in];
562                 float outL = outs[0][offset];
563                 float outR = outs[1][offset];
564 
565                 // process filters
566                 dsp::biquad_filter_module::process_channel(0, &inL, &outL, 1, inputs_mask & 1);
567                 dsp::biquad_filter_module::process_channel(1, &inR, &outR, 1, inputs_mask & 2);
568 
569                 // mix and out level
570                 outs[0][offset] = (outL * *params[param_mix] + inL * (*params[param_mix] * -1 + 1)) * *params[param_level_out];
571                 outs[1][offset] = (outR * *params[param_mix] + inR * (*params[param_mix] * -1 + 1)) * *params[param_level_out];
572 
573                 // meters
574                 float values[] = {inL, inR, outs[0][offset], outs[1][offset]};
575                 meters.process(values);
576             }
577             // step on
578             offset += 1;
579         }
580         if (bypassed)
581             bypass.crossfade(ins, outs, 2, offset - numsamples, numsamples);
582         meters.fall(numsamples);
583         return outputs_mask;
584     }
585 
freq_gain(int index,double freq)586     float freq_gain(int index, double freq) const {
587         return dsp::biquad_filter_module::freq_gain(index, (float)freq, (float)srate);
588     }
589 
calc_filter()590     void calc_filter ()
591     {
592         redraw_graph = true;
593         dsp::biquad_filter_module::calculate_filter(get_freq(envelope), *params[param_q], mode, 1.0);
594     }
595 
calc_coef()596     void calc_coef ()
597     {
598         coefa = log10(upper) - log10(lower);
599         coefb = log10(lower);
600     }
601 
get_freq(float envelope)602     float get_freq(float envelope) const {
603         float diff = upper - lower;
604         float env  = pow(envelope, pow(2, *params[param_response] * -2));
605         float freq = pow(10, coefa * env + coefb);
606         if (diff < 0)
607             return  std::max(upper, std::min(lower, freq));
608         return std::min(upper, std::max(lower, freq));
609     }
610 
611 };
612 
613 };
614 
615 #endif
616