[SCM] calf/master: Merge branch 'master' into saturators

js at users.alioth.debian.org js at users.alioth.debian.org
Tue May 7 15:39:54 UTC 2013


+ EQ: Fix adding EQ plugin using menu in calfjackhost
new backgrounds for rack
Entry/spinbutton fixed
Some changes in style, smaller h/v-scale added
Complete RC rewrite (in progress)
+ VU meter: move to separate header to enable reuse, modify falloff behaviour, add clipping detection
+ LADSPA: make plugin IDs unique across Calf plugins, add an install-time check
GUI: Set plugin GUI window's role to plugin_ui (for WM kludges etc).
+ GUI: add missing pixmaps
+ Pulsator: labelling change
+ EQ-5: refactoring to eliminate code duplication, side effect: stereo meters
Merge commit 'origin/pulsator'
Merged with master
Merge branch 'master' into style
Merge branch 'master' into pulsator
Merge branch 'master' into style
Bypass should leave LFO alone
Pulsator process and GUI, slight changes in other GUI's
LFO module, Pulsator (GUI missing)
Mistakes in button images, higher contrast on tubes, pixel accuracy for toggle buttons
Buttons with better response, pixel accurate, light border
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
X-Git-Refname: refs/heads/master
X-Git-Reftype: branch
X-Git-Oldrev: d6a3c1a63a147948535a50da009275278ad5e6a3
X-Git-Newrev: 34569260c452f0fa4c543155ebba174a42a343dc

The following commit has been merged in the master branch:
commit bfe620f99aed1c6585a33e1d9ab143f9941c232d
Merge: f6c43f7f0d2e66e63676224ae3332c318d7b781d d8ad25e069267e409f9a43943a1b861c1c5ee2e4
Author: Markus Schmidt <schmidt at boomshop.net>
Date:   Sun Dec 13 14:23:02 2009 +0100

    Merge branch 'master' into saturators

diff --combined src/calf/metadata.h
index 4dd2275,22d9f22..63788fe
--- a/src/calf/metadata.h
+++ b/src/calf/metadata.h
@@@ -192,15 -192,19 +192,19 @@@ struct deesser_metadata: public plugin_
  struct equalizer5band_metadata: public plugin_metadata<equalizer5band_metadata>
  {
      enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
-     enum { param_bypass, param_level_in, param_level_out, param_meter_in,
-            param_meter_out, param_clip_in, param_clip_out,
+     enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
+            param_meter_outL, param_meter_outR, param_clip_inL, param_clip_outL, param_clip_inR, param_clip_outR,
             param_ls_active, param_ls_level, param_ls_freq,
             param_hs_active, param_hs_level, param_hs_freq,
             param_p1_active, param_p1_level, param_p1_freq, param_p1_q,
             param_p2_active, param_p2_level, param_p2_freq, param_p2_q,
             param_p3_active, param_p3_level, param_p3_freq, param_p3_q,
             param_count };
-     PLUGIN_NAME_ID_LABEL("equalizer5band", "equalizer5band", "Equalizer 5 Band")
+     // dummy parameter numbers, shouldn't be used EVER, they're only there to avoid pushing LP/HP filters to a separate class
+     // and potentially making inlining and optimization harder for the compiler
+     enum { param_lp_active = 0xDEADBEEF, param_hp_active, param_hp_mode, param_lp_mode, param_hp_freq, param_lp_freq };
+     enum { PeakBands = 3, first_graph_param = param_ls_active, last_graph_param = param_p3_q };
+     PLUGIN_NAME_ID_LABEL("equalizer5band", "eq5", "Equalizer 5 Band")
  };
  /// Markus's 8-band EQ - metadata
  struct equalizer8band_metadata: public plugin_metadata<equalizer8band_metadata>
@@@ -218,7 -222,7 +222,7 @@@
             param_p4_active, param_p4_level, param_p4_freq, param_p4_q,
             param_count };
      enum { PeakBands = 4, first_graph_param = param_hp_active, last_graph_param = param_p4_q };
-     PLUGIN_NAME_ID_LABEL("equalizer8band", "equalizer8band", "Equalizer 8 Band")
+     PLUGIN_NAME_ID_LABEL("equalizer8band", "eq8", "Equalizer 8 Band")
  };
  /// Markus's 12-band EQ - metadata
  struct equalizer12band_metadata: public plugin_metadata<equalizer12band_metadata>
@@@ -240,37 -244,19 +244,47 @@@
             param_p8_active, param_p8_level, param_p8_freq, param_p8_q,
             param_count };
      enum { PeakBands = 8, first_graph_param = param_hp_active, last_graph_param = param_p8_q };
-     PLUGIN_NAME_ID_LABEL("equalizer12band", "equalizer12band", "Equalizer 12 Band")
+     PLUGIN_NAME_ID_LABEL("equalizer12band", "eq12", "Equalizer 12 Band")
+ };
+ 
+ /// Markus's Pulsator - metadata
+ struct pulsator_metadata: public plugin_metadata<pulsator_metadata>
+ {
+     enum { in_count = 2, out_count = 2, ins_optional = 0, outs_optional = 0, support_midi = false, require_midi = false, rt_capable = true };
+     enum { param_bypass, param_level_in, param_level_out, param_meter_inL, param_meter_inR,
+            param_meter_outL, param_meter_outR, param_clip_inL, param_clip_inR, param_clip_outL, param_clip_outR,
+            param_mode, param_freq, param_amount, param_offset, param_mono, param_reset, param_count };
+     PLUGIN_NAME_ID_LABEL("pulsator", "pulsator", "Pulsator")
  };
  
 +/// Markus's Saturator - metadata
 +struct saturator_metadata: public plugin_metadata<saturator_metadata>
 +{
 +    enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
 +    enum { param_bypass, param_level_in, param_level_out, param_mix, param_meter_in,
 +           param_meter_out, param_clip_in, param_clip_out, param_drive, param_blend, param_meter_drive,
 +           param_lp_pre_freq, param_hp_pre_freq, param_lp_post_freq, param_hp_post_freq,
 +           param_p_freq, param_p_level, param_p_q, param_count };
 +    PLUGIN_NAME_ID_LABEL("saturator", "saturator", "Saturator")
 +};
 +/// Markus's Exciter - metadata
 +struct exciter_metadata: public plugin_metadata<exciter_metadata>
 +{
 +    enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
 +    enum { param_bypass, param_level_in, param_level_out, param_amount, param_meter_in,
 +           param_meter_out, param_clip_in, param_clip_out, param_drive, param_blend, param_meter_drive,
 +           param_freq, param_listen, param_count };
 +    PLUGIN_NAME_ID_LABEL("exciter", "exciter", "Exciter")
 +};
 +/// Markus's Bass Enhancer - metadata
 +struct bassenhancer_metadata: public plugin_metadata<bassenhancer_metadata>
 +{
 +    enum { in_count = 2, out_count = 2, ins_optional = 1, outs_optional = 1, support_midi = false, require_midi = false, rt_capable = true };
 +    enum { param_bypass, param_level_in, param_level_out, param_amount, param_meter_in,
 +           param_meter_out, param_clip_in, param_clip_out, param_drive, param_blend, param_meter_drive,
 +           param_freq, param_listen, param_count };
 +    PLUGIN_NAME_ID_LABEL("bassenhancer", "bassenhancer", "Bass Enhancer")
 +};
  /// Organ - enums for parameter IDs etc. (this mess is caused by organ split between plugin and generic class - which was
  /// a bad design decision and should be sorted out some day) XXXKF @todo
  struct organ_enums
diff --combined src/calf/modulelist.h
index 02e947a,fd1531f..0fc6a9c
--- a/src/calf/modulelist.h
+++ b/src/calf/modulelist.h
@@@ -13,12 -13,10 +13,13 @@@
      PER_MODULE_ITEM(sidechaincompressor, false, "sidechaincompressor")
      PER_MODULE_ITEM(multibandcompressor, false, "multibandcompressor")
      PER_MODULE_ITEM(deesser, false, "deesser")
+     PER_MODULE_ITEM(pulsator, false, "pulsator")
      PER_MODULE_ITEM(equalizer5band, false, "eq5")
      PER_MODULE_ITEM(equalizer8band, false, "eq8")
      PER_MODULE_ITEM(equalizer12band, false, "eq12")
 +    PER_MODULE_ITEM(saturator, false, "saturator")
 +    PER_MODULE_ITEM(exciter, false, "exciter")
 +    PER_MODULE_ITEM(bassenhancer, false, "bassenhancer")
  #ifdef ENABLE_EXPERIMENTAL
      PER_MODULE_ITEM(fluidsynth, true, "fluidsynth")
      PER_MODULE_ITEM(wavetable, true, "wavetable")
diff --combined src/calf/modules.h
index b46ddf3,ee89067..d0c9ea0
--- a/src/calf/modules.h
+++ b/src/calf/modules.h
@@@ -1039,7 -1039,7 +1039,7 @@@ public
  };
  
  /// Equalizer N Band by Markus Schmidt (based on Krzysztof's filters)
- template<class BaseClass>
+ template<class BaseClass, bool has_lphp>
  class equalizerNband_audio_module: public audio_module<BaseClass>, public frequency_response_line_graph {
  public:
      typedef audio_module<BaseClass> AM;
@@@ -1057,9 -1057,12 +1057,12 @@@ private
      float old_params_for_graph[graph_param_count];
      uint32_t clip_inL, clip_outL, clip_inR, clip_outR;
      float meter_inL, meter_outL, meter_inR, meter_outR;
+     CalfEqMode hp_mode, lp_mode;
      biquad_d2<float> hp[3][2], lp[3][2];
      biquad_d2<float> lsL, lsR, hsL, hsR;
      biquad_d2<float> pL[PeakBands], pR[PeakBands];
+     
+     inline void process_hplp(float &left, float &right);
  public:
      typedef std::complex<double> cfloat;
      float *ins[in_count];
@@@ -1071,6 -1074,7 +1074,7 @@@
      equalizerNband_audio_module();
      void activate();
      void deactivate();
+ 
      void params_changed();
      float freq_gain(int index, double freq, uint32_t sr);
      void set_sample_rate(uint32_t sr)
@@@ -1083,160 -1087,63 +1087,172 @@@
      int  get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
  };
  
- typedef equalizerNband_audio_module<equalizer8band_metadata> equalizer8band_audio_module;
- typedef equalizerNband_audio_module<equalizer12band_metadata> equalizer12band_audio_module;
+ typedef equalizerNband_audio_module<equalizer5band_metadata, false> equalizer5band_audio_module;
+ typedef equalizerNband_audio_module<equalizer8band_metadata, true> equalizer8band_audio_module;
+ typedef equalizerNband_audio_module<equalizer12band_metadata, true> equalizer12band_audio_module;
  
- /// Equalizer 5 Band by Markus Schmidt (based on Krzysztof's filters)
- class equalizer5band_audio_module: public audio_module<equalizer5band_metadata>, public frequency_response_line_graph  {
+ /// LFO by Markus
+ class lfo_audio_module {
  private:
-     float ls_level_old, ls_freq_old;
-     float hs_level_old, hs_freq_old;
-     float p_level_old[3], p_freq_old[3], p_q_old[3];
-     float ls_level_old1, ls_freq_old1, ls_active_old1;
-     float hs_level_old1, hs_freq_old1, hs_active_old1;
-     float p_level_old1[3], p_freq_old1[3], p_q_old1[3], p_active_old1[3];
-     uint32_t clip_in, clip_out;
-     float meter_in, meter_out;
-     biquad_d2<float> lsL, lsR, hsL, hsR;
-     biquad_d2<float> pL[3], pR[3];
+     float phase, freq, offset, amount;
+     int mode;
+     uint32_t srate;
+     bool is_active;
+ public:
+     lfo_audio_module();
+     void set_params(float f, int m, float o, uint32_t sr, float amount = 1.f);
+     float get_value();
+     void advance(uint32_t count);
+     void set_phase(float ph);
+     void activate();
+     void deactivate();
+     float get_value_from_phase(float ph, float off);
+     virtual bool get_graph(float *data, int points, cairo_iface *context);
+     virtual bool get_dot(float &x, float &y, int &size, cairo_iface *context);
+ };
+ 
+ /// Pulsator by Markus Schmidt
+ class pulsator_audio_module: public audio_module<pulsator_metadata>, public frequency_response_line_graph  {
+ private:
+     uint32_t clip_inL, clip_inR, clip_outL, clip_outR;
+     float meter_inL, meter_inR, meter_outL, meter_outR;
+     float offset_old;
+     int mode_old;
+     bool clear_reset;
+     lfo_audio_module lfoL, lfoR;
  public:
-     typedef std::complex<double> cfloat;
      float *ins[in_count];
      float *outs[out_count];
      float *params[param_count];
      uint32_t srate;
      bool is_active;
-     volatile int last_generation, last_calculated_generation;
-     equalizer5band_audio_module();
+     pulsator_audio_module();
      void activate();
      void deactivate();
      void params_changed();
-     float freq_gain(int index, double freq, uint32_t sr)
+     void set_sample_rate(uint32_t sr);
+     void params_reset()
      {
-         float ret = 1.f;
-         ret *= (*params[param_ls_active] > 0.f) ? lsL.freq_gain(freq, sr) : 1;
-         ret *= (*params[param_hs_active] > 0.f) ? hsL.freq_gain(freq, sr) : 1;
-         ret *= (*params[param_p1_active] > 0.f) ? pL[0].freq_gain(freq, sr) : 1;
-         ret *= (*params[param_p2_active] > 0.f) ? pL[1].freq_gain(freq, sr) : 1;
-         ret *= (*params[param_p3_active] > 0.f) ? pL[2].freq_gain(freq, sr) : 1;
-         return ret;
+         if (clear_reset) {
+             *params[param_reset] = 0.f;
+             clear_reset = false;
+         }
      }
-     void set_sample_rate(uint32_t sr);
      uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
      bool get_graph(int index, int subindex, float *data, int points, cairo_iface *context);
+     bool get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context);
      bool get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context);
-     int  get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline);
  };
  
 +class distortion_audio_module {
 +private:
 +    float blend_old, drive_old;
 +    float meter;
 +    float rdrive, rbdr, kpa, kpb, kna, knb, ap, an, imr, kc, srct, sq, pwrq;
 +    float prev_med, prev_out;
 +public:
 +    uint32_t srate;
 +    bool is_active;
 +    distortion_audio_module();
 +    void activate();
 +    void deactivate();
 +    void set_params(float blend, float drive);
 +    void set_sample_rate(uint32_t sr);
 +    float process(float in);
 +    float get_distortion_level();
 +    static inline float
 +    // NOTICE!! These routines are implemented for testing purposes only!
 +    // They're taken from TAP Plugins and will act as a placeholder until
 +    // Krzysztof's distrotion routine is ready!
 +    M(float x) {
 +
 +        if ((x > 0.000000001f) || (x < -0.000000001f))
 +            return x;
 +        else
 +            return 0.0f;
 +    }
 +
 +    static inline float
 +    D(float x) {
 +
 +        if (x > 0.000000001f)
 +            return sqrt(x);
 +        else if (x < -0.000000001f)
 +            return sqrt(-x);
 +        else
 +            return 0.0f;
 +    }
 +};
 +
 +/// Saturator by Markus Schmidt (based on Krzysztof's filters and distortion algorythm)
 +class saturator_audio_module: public audio_module<saturator_metadata> {
 +private:
 +    float hp_pre_freq_old, lp_pre_freq_old;
 +    float hp_post_freq_old, lp_post_freq_old;
 +    float p_level_old, p_freq_old, p_q_old;
 +    uint32_t clip_in, clip_out;
 +    float meter_in, meter_out, meter_drive;
 +    biquad_d2<float> lp[2][4], hp[2][4];
 +    biquad_d2<float> p[2];
 +    distortion_audio_module dist[2];
 +public:
 +    float *ins[in_count];
 +    float *outs[out_count];
 +    float *params[param_count];
 +    uint32_t srate;
 +    bool is_active;
 +    saturator_audio_module();
 +    void activate();
 +    void deactivate();
 +    void params_changed();
 +    void set_sample_rate(uint32_t sr);
 +    uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
 +};
 +
 +/// Exciter by Markus Schmidt (based on Krzysztof's filters and distortion algorythm)
 +class exciter_audio_module: public audio_module<exciter_metadata> {
 +private:
 +    float freq_old;
 +    uint32_t clip_in, clip_out;
 +    float meter_in, meter_out, meter_drive;
 +    biquad_d2<float> hp[2][4];
 +    distortion_audio_module dist[2];
 +public:
 +    float *ins[in_count];
 +    float *outs[out_count];
 +    float *params[param_count];
 +    uint32_t srate;
 +    bool is_active;
 +    exciter_audio_module();
 +    void activate();
 +    void deactivate();
 +    void params_changed();
 +    void set_sample_rate(uint32_t sr);
 +    uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
 +};
 +
 +/// Bass Enhancer by Markus Schmidt (based on Krzysztof's filters and distortion algorythm)
 +class bassenhancer_audio_module: public audio_module<bassenhancer_metadata> {
 +private:
 +    float freq_old;
 +    uint32_t clip_in, clip_out;
 +    float meter_in, meter_out, meter_drive;
 +    biquad_d2<float> lp[2][4];
 +    distortion_audio_module dist[2];
 +public:
 +    float *ins[in_count];
 +    float *outs[out_count];
 +    float *params[param_count];
 +    uint32_t srate;
 +    bool is_active;
 +    bassenhancer_audio_module();
 +    void activate();
 +    void deactivate();
 +    void params_changed();
 +    void set_sample_rate(uint32_t sr);
 +    uint32_t process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask);
 +};
 +
  /// Filterclavier --- MIDI controlled filter by Hans Baier
  class filterclavier_audio_module: 
          public audio_module<filterclavier_metadata>, 
diff --combined src/modules.cpp
index 14f27d8,b9bc039..b2e3727
--- a/src/modules.cpp
+++ b/src/modules.cpp
@@@ -282,7 -282,7 +282,7 @@@ CALF_PORT_PROPS(sidechaincompressor) = 
      { 0,      0,  1,    0, PF_BOOL | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "f2_active", "F2 Active" },
  };
  
- CALF_PLUGIN_INFO(sidechaincompressor) = { 0x8502, "Sidechaincompressor", "Calf Sidechain Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
+ CALF_PLUGIN_INFO(sidechaincompressor) = { 0x8517, "Sidechaincompressor", "Calf Sidechain Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
  
  ////////////////////////////////////////////////////////////////////////////
  
@@@ -307,13 -307,13 +307,13 @@@ CALF_PORT_PROPS(multibandcompressor) = 
      { 1000,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq1", "Split 2/3" },
      { 6000,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "freq2", "Split 3/4" },
      
-     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep0", "S0" },
-     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep1", "S1" },
-     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep2", "S2" },
+     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep0", "S1" },
+     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep1", "S2" },
+     { -0.17,      -0.5,         0.5,   0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_GRAPH, NULL, "sep2", "S3" },
      
-     { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q0" },
-     { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q1" },
-     { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q2" },
+     { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q0", "Q1" },
+     { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q1", "Q2" },
+     { 0.895025,    0.25,        4,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_GRAPH, NULL, "q2", "Q3" },
      
      
      { 0.0625,      0.000976563, 1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "threshold0", "Threshold 1" },
@@@ -368,7 -368,7 +368,7 @@@
      { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "mute3", "Mute 4" },
  };
  
- CALF_PLUGIN_INFO(multibandcompressor) = { 0x8502, "Multibandcompressor", "Calf Multiband Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
+ CALF_PLUGIN_INFO(multibandcompressor) = { 0x8516, "Multibandcompressor", "Calf Multiband Compressor", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
  
  ////////////////////////////////////////////////////////////////////////////
  
@@@ -399,46 -399,41 +399,41 @@@ CALF_PORT_PROPS(deesser) = 
      { 0,      0,  1,    0, PF_BOOL | PF_CTL_TOGGLE, NULL, "sc_listen", "S/C-Listen" },
  };
  
- CALF_PLUGIN_INFO(deesser) = { 0x8502, "Deesser", "Calf Deesser", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
+ CALF_PLUGIN_INFO(deesser) = { 0x8515, "Deesser", "Calf Deesser", "Markus Schmidt / Thor Harald Johansen", calf_plugins::calf_copyright_info, "CompressorPlugin" };
  
  ////////////////////////////////////////////////////////////////////////////
+ // A few macros to make 
  
- CALF_PORT_NAMES(equalizer5band) = {"In L", "In R", "Out L", "Out R"};
- 
- CALF_PORT_PROPS(equalizer5band) = {
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
-     { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input Gain" },
+ #define BYPASS_AND_LEVEL_PARAMS \
+     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" }, \
+     { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input Gain" }, \
      { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output Gain" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input Level" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output Level" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB-In" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB-Out" },
- 
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "ls_active", "LS Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "ls_level", "Level L" },
-     { 200,         10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "ls_freq", "Freq L" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "hs_active", "HS Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "hs_level", "Level H" },
-     { 4000,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hs_freq", "Freq H" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "p1_active", "F1 Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "p1_level", "Level 1" },
-     { 250,         10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "p1_freq", "Freq 1" },
-     { 1,           0.1,         100,   1,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p1_q", "Q 1" },
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "p2_active", "F2 Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "p2_level", "Level 2" },
-     { 1000,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "p2_freq", "Freq 2" },
-     { 1,           0.1,         100,   1,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p2_q", "Q 2" },
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "p3_active", "F3 Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "p3_level", "Level 3" },
-     { 2500,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "p3_freq", "Freq 3" },
-     { 1,           0.1,         100,   1,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p3_q", "Q 3" },
- };
  
- CALF_PLUGIN_INFO(equalizer5band) = { 0x8501, "Equalizer5Band", "Calf Equalizer 5 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" };
+ #define METERING_PARAMS \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inL", "Meter-InL" }, \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inR", "Meter-InR" }, \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outL", "Meter-OutL" }, \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outR", "Meter-OutR" }, \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB-InL" }, \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB-InR" }, \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" }, \
+     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" },
  
- //////////////////////////////////////////////////////////////////////////////
+ #define LPHP_PARAMS \
+     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "hp_active", "HP Active" }, \
+     { 30,          10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_freq", "HP Freq" }, \
+     { 1,           0,           2,     0,  PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "hp_mode", "HP Mode" }, \
+     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "lp_active", "LP Active" }, \
+     { 18000,       10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_freq", "LP Freq" }, \
+     { 1,           0,           2,     0,  PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "lp_mode", "LP Mode" }, \
+ 
+ #define SHELF_PARAMS \
+     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "ls_active", "LS Active" }, \
+     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "ls_level", "Level L" }, \
+     { 200,         10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "ls_freq", "Freq L" }, \
+     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "hs_active", "HS Active" }, \
+     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "hs_level", "Level H" }, \
+     { 4000,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hs_freq", "Freq H" },
  
  #define EQ_BAND_PARAMS(band, frequency) \
      { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "p" #band "_active", "F" #band " Active" }, \
@@@ -446,79 -441,49 +441,49 @@@
      { frequency,   10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ | PF_PROP_GRAPH, NULL, "p" #band "_freq", "Freq " #band }, \
      { 1,           0.1,         100,   1,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p" #band "_q", "Q " #band },
  
+ ////////////////////////////////////////////////////////////////////////////
+ 
+ CALF_PORT_NAMES(equalizer5band) = {"In L", "In R", "Out L", "Out R"};
+ 
+ CALF_PORT_PROPS(equalizer5band) = {
+     BYPASS_AND_LEVEL_PARAMS
+     METERING_PARAMS
+     SHELF_PARAMS
+     EQ_BAND_PARAMS(1, 250)
+     EQ_BAND_PARAMS(2, 1000)
+     EQ_BAND_PARAMS(3, 2500)
+ };
+ 
+ CALF_PLUGIN_INFO(equalizer5band) = { 0x8511, "Equalizer5Band", "Calf Equalizer 5 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" };
+ 
+ //////////////////////////////////////////////////////////////////////////////
+ 
+ 
  CALF_PORT_NAMES(equalizer8band) = {"In L", "In R", "Out L", "Out R"};
  const char *rolloff_mode_names[] = {"12dB/oct", "24dB/oct", "36dB/oct"};
  
  CALF_PORT_PROPS(equalizer8band) = {
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
-     { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input Gain" },
-     { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output Gain" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inL", "Meter-InL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inR", "Meter-InR" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outL", "Meter-OutL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outR", "Meter-OutR" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB-InL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB-InR" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" },
- 
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "hp_active", "HP Active" },
-     { 30,          10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_freq", "HP Freq" },
-     { 1,           0,           2,     0,  PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "hp_mode", "HP Mode" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "lp_active", "LP Active" },
-     { 18000,       10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_freq", "LP Freq" },
-     { 1,           0,           2,     0,  PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "lp_mode", "LP Mode" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "ls_active", "LS Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "ls_level", "LS Level" },
-     { 200,         10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "ls_freq", "LS Freq" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "hs_active", "HS Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "hs_level", "HS Level" },
-     { 4000,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hs_freq", "HS Freq" },
-     
+     BYPASS_AND_LEVEL_PARAMS
+     METERING_PARAMS
+     LPHP_PARAMS
+     SHELF_PARAMS
      EQ_BAND_PARAMS(1, 250)
      EQ_BAND_PARAMS(2, 1000)
      EQ_BAND_PARAMS(3, 2500)
      EQ_BAND_PARAMS(4, 5000)
  };
  
- CALF_PLUGIN_INFO(equalizer8band) = { 0x8501, "Equalizer8Band", "Calf Equalizer 8 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" };
+ CALF_PLUGIN_INFO(equalizer8band) = { 0x8512, "Equalizer8Band", "Calf Equalizer 8 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" };
  
  ////////////////////////////////////////////////////////////////////////////
  
  CALF_PORT_NAMES(equalizer12band) = {"In L", "In R", "Out L", "Out R"};
  
  CALF_PORT_PROPS(equalizer12band) = {
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
-     { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" },
-     { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inL", "InL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_inR", "InR" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outL", "OutL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_outR", "OutR" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inL", "0dB-InL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_inR", "0dB-InR" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outL", "0dB-OutL" },
-     { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_outR", "0dB-OutR" },
- 
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "hp_active", "HP Active" },
-     { 30,          10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_freq", "Freq HP" },
-     { 1,           0,           2,     0,  PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "hp_mode", "Mode HP" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "lp_active", "LP Active" },
-     { 18000,       10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_freq", "Freq LP" },
-     { 1,           0,           2,     0,  PF_ENUM | PF_CTL_COMBO, rolloff_mode_names, "lp_mode", "Mode LP" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "ls_active", "LS Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "ls_level", "Level LS" },
-     { 200,         10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "ls_freq", "Freq LS" },
-     
-     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "hs_active", "LS Active" },
-     { 1,           0.015625,    64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "hs_level", "Level HS" },
-     { 4000,        10,          20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hs_freq", "Freq HS" },
-     
+     BYPASS_AND_LEVEL_PARAMS
+     METERING_PARAMS
+     LPHP_PARAMS
+     SHELF_PARAMS
      EQ_BAND_PARAMS(1, 60)
      EQ_BAND_PARAMS(2, 120)
      EQ_BAND_PARAMS(3, 250)
@@@ -529,87 -494,29 +494,106 @@@
      EQ_BAND_PARAMS(8, 6000)
  };
  
- CALF_PLUGIN_INFO(equalizer12band) = { 0x8501, "Equalizer12Band", "Calf Equalizer 12 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" };
+ CALF_PLUGIN_INFO(equalizer12band) = { 0x8513, "Equalizer12Band", "Calf Equalizer 12 Band", "Markus Schmidt", calf_plugins::calf_copyright_info, "EqualizerPlugin" };
+ 
+ ////////////////////////////////////////////////////////////////////////////
+ 
+ CALF_PORT_NAMES(pulsator) = {"In L", "In R", "Out L", "Out R"};
+ 
+ const char *pulsator_mode_names[] = { "Sine", "Triangle", "Square", "Saw up", "Saw down" };
+ 
+ CALF_PORT_PROPS(pulsator) = {
+     BYPASS_AND_LEVEL_PARAMS
+     METERING_PARAMS
+     { 0,           0,           4,     0,  PF_ENUM | PF_CTL_COMBO, pulsator_mode_names, "mode", "Mode" },
+     { 1,           0.01,        100,   0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Frequency" },
+     { 1,           0,           1,     0,  PF_FLOAT | PF_SCALE_PERC, NULL, "amount", "Modulation" },
+     { 0.5,         0,           1,     0,  PF_FLOAT | PF_SCALE_PERC, NULL, "offset", "Offset L/R" },
+     { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "mono", "Mono-in" },
+     { 0,           0,           1,     2,  PF_BOOL | PF_CTL_BUTTON , NULL, "reset", "Reset" },
+ };
+ 
+ CALF_PLUGIN_INFO(pulsator) = { 0x8514, "Pulsator", "Calf Pulsator", "Markus Schmidt", calf_plugins::calf_copyright_info, "ModulationPlugin" };
  
  ////////////////////////////////////////////////////////////////////////////
  
 +CALF_PORT_NAMES(saturator) = {"In L", "In R", "Out L", "Out R"};
 +
 +CALF_PORT_PROPS(saturator) = {
 +    { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Gain" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Master" },
 +    { 0.5,         0,           1,     0,  PF_FLOAT | PF_SCALE_PERC | PF_CTL_KNOB , NULL, "mix", "Mix" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" },
 +    
 +    { 2,           0.1,         10,    0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "drive", "Drive" },
 +    { 10,         -10,          10,    0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_COEF, NULL, "blend", "Blend" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_drive", "Drive" },
 +    
 +    { 20000,      10,           20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_pre_freq", "Lowpass" },
 +    { 10,         10,           20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_pre_freq", "Highpass" },
 +
 +    { 20000,      10,           20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "lp_post_freq", "Lowpass" },
 +    { 10,         10,           20000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "hp_post_freq", "Highpass" },
 +    
 +    { 2000,       80,           8000,  0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "p_freq", "Tone" },
 +    { 1,          0.0625,       16,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB, NULL, "p_level", "Amount" },
 +    { 1,          0.1,          10,    1,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "p_q", "Gradient" },
 +};
 +
 +CALF_PLUGIN_INFO(saturator) = { 0x8502, "Saturator", "Calf Saturator", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" };
 +
 +////////////////////////////////////////////////////////////////////////////
 +
 +CALF_PORT_NAMES(exciter) = {"In L", "In R", "Out L", "Out R"};
 +
 +CALF_PORT_PROPS(exciter) = {
 +    { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" },
 +    
 +    { 8.5,         0.1,         10,    0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "drive", "Harmonics" },
 +    { 0,          -10,          10,    0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_COEF, NULL, "blend", "Blend harmonics" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_drive", "Harmonics level" },
 +    
 +    { 6000,       2000,         12000, 0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Scope" },
 +    { 0,          0,            1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "listen", "Listen" },
 +};
 +
 +CALF_PLUGIN_INFO(exciter) = { 0x8502, "Exciter", "Calf Exciter", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" };
 +
 +////////////////////////////////////////////////////////////////////////////
 +
 +CALF_PORT_NAMES(bassenhancer) = {"In L", "In R", "Out L", "Out R"};
 +
 +CALF_PORT_PROPS(bassenhancer) = {
 +    { 0,           0,           1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "bypass", "Bypass" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_in", "Input" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_COEF | PF_PROP_NOBOUNDS, NULL, "level_out", "Output" },
 +    { 1,           0,           64,    0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_KNOB | PF_UNIT_DB | PF_PROP_NOBOUNDS, NULL, "amount", "Amount" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_in", "Input" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_out", "Output" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_in", "0dB" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_CTL_LED | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "clip_out", "0dB" },
 +    
 +    { 8.5,         0.1,         10,    0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_KNOB | PF_UNIT_COEF, NULL, "drive", "Harmonics" },
 +    { 0,          -10,          10,    0,  PF_FLOAT | PF_SCALE_LINEAR | PF_CTL_FADER | PF_UNIT_COEF, NULL, "blend", "Blend harmonics" },
 +    { 0,           0,           1,     0,  PF_FLOAT | PF_SCALE_GAIN | PF_CTL_METER | PF_CTLO_LABEL | PF_UNIT_DB | PF_PROP_OUTPUT | PF_PROP_OPTIONAL, NULL, "meter_drive", "Harmonics level" },
 +    
 +    { 120,        10,           250,   0,  PF_FLOAT | PF_SCALE_LOG | PF_CTL_KNOB | PF_UNIT_HZ, NULL, "freq", "Scope" },
 +    { 0,          0,            1,     0,  PF_BOOL | PF_CTL_TOGGLE, NULL, "listen", "Listen" },
 +};
 +
 +CALF_PLUGIN_INFO(bassenhancer) = { 0x8502, "BassEnhancer", "Calf Bass Enhancer", "Markus Schmidt / Krzysztof Foltman", calf_plugins::calf_copyright_info, "DistortionPlugin" };
 +
  ////////////////////////////////////////////////////////////////////////////
  
  CALF_PORT_NAMES(monosynth) = {
diff --combined src/modules_dsp.cpp
index 95105f3,d7afa93..3347c8d
--- a/src/modules_dsp.cpp
+++ b/src/modules_dsp.cpp
@@@ -1730,8 -1730,8 +1730,8 @@@ int gain_reduction_audio_module::get_ch
  /// of different chained filters.
  ///////////////////////////////////////////////////////////////////////////////////////////////
  
- template<class BaseClass>
- equalizerNband_audio_module<BaseClass>::equalizerNband_audio_module()
+ template<class BaseClass, bool has_lphp>
+ equalizerNband_audio_module<BaseClass, has_lphp>::equalizerNband_audio_module()
  {
      is_active = false;
      srate = 0;
@@@ -1740,16 -1740,16 +1740,16 @@@
      meter_inL = meter_inR = meter_outL = meter_outR = 0.f;
  }
  
- template<class BaseClass>
- void equalizerNband_audio_module<BaseClass>::activate()
+ template<class BaseClass, bool has_lphp>
+ void equalizerNband_audio_module<BaseClass, has_lphp>::activate()
  {
      is_active = true;
      // set all filters
      params_changed();
  }
  
- template<class BaseClass>
- void equalizerNband_audio_module<BaseClass>::deactivate()
+ template<class BaseClass, bool has_lphp>
+ void equalizerNband_audio_module<BaseClass, has_lphp>::deactivate()
  {
      is_active = false;
  }
@@@ -1762,26 -1762,31 +1762,31 @@@ static inline void copy_lphp(biquad_d2<
                  filters[i][j].copy_coeffs(filters[0][0]);
  }
  
- 
- template<class BaseClass>
- void equalizerNband_audio_module<BaseClass>::params_changed()
+ template<class BaseClass, bool has_lphp>
+ void equalizerNband_audio_module<BaseClass, has_lphp>::params_changed()
  {
      // set the params of all filters
      
-     // lp/hp first
-     float hpfreq = *params[AM::param_hp_freq], lpfreq = *params[AM::param_lp_freq];
-     
-     if(hpfreq != hp_freq_old) {
-         hp[0][0].set_hp_rbj(hpfreq, 0.707, (float)srate, 1.0);
-         copy_lphp(hp);
-         hp_freq_old = hpfreq;
-     }
-     if(lpfreq != lp_freq_old) {
-         lp[0][0].set_lp_rbj(lpfreq, 0.707, (float)srate, 1.0);
-         copy_lphp(lp);
-         lp_freq_old = lpfreq;
-     }
+     // lp/hp first (if available)
+     if (has_lphp)
+     {
+         hp_mode = (CalfEqMode)(int)*params[AM::param_hp_mode];
+         lp_mode = (CalfEqMode)(int)*params[AM::param_lp_mode];
  
+         float hpfreq = *params[AM::param_hp_freq], lpfreq = *params[AM::param_lp_freq];
+         
+         if(hpfreq != hp_freq_old) {
+             hp[0][0].set_hp_rbj(hpfreq, 0.707, (float)srate, 1.0);
+             copy_lphp(hp);
+             hp_freq_old = hpfreq;
+         }
+         if(lpfreq != lp_freq_old) {
+             lp[0][0].set_lp_rbj(lpfreq, 0.707, (float)srate, 1.0);
+             copy_lphp(lp);
+             lp_freq_old = lpfreq;
+         }
+     }
+     
      // then shelves
      float hsfreq = *params[AM::param_hs_freq], hslevel = *params[AM::param_hs_level];
      float lsfreq = *params[AM::param_ls_freq], lslevel = *params[AM::param_ls_level];
@@@ -1814,28 -1819,53 +1819,53 @@@
      }
  }
  
- static void process_hplp(float &procL, float &procR, dsp::biquad_d2<float> filter[3][2], CalfEqMode mode)
+ template<class BaseClass, bool has_lphp>
+ inline void equalizerNband_audio_module<BaseClass, has_lphp>::process_hplp(float &left, float &right)
  {
-     switch(mode) {
-         case MODE12DB:
-             procL = filter[0][0].process(procL);
-             procR = filter[0][1].process(procR);
-             break;
-         case MODE24DB:
-             procL = filter[1][0].process(filter[0][0].process(procL));
-             procR = filter[1][1].process(filter[0][1].process(procR));
-             break;
-         case MODE36DB:
-             procL = filter[2][0].process(filter[1][0].process(filter[0][0].process(procL)));
-             procR = filter[2][1].process(filter[1][1].process(filter[0][1].process(procR)));
-             break;
+     if (!has_lphp)
+         return;
+     if (*params[AM::param_lp_active] > 0.f)
+     {
+         switch(lp_mode)
+         {
+             case MODE12DB:
+                 left = lp[0][0].process(left);
+                 right = lp[0][1].process(right);
+                 break;
+             case MODE24DB:
+                 left = lp[1][0].process(lp[0][0].process(left));
+                 right = lp[1][1].process(lp[0][1].process(right));
+                 break;
+             case MODE36DB:
+                 left = lp[2][0].process(lp[1][0].process(lp[0][0].process(left)));
+                 right = lp[2][1].process(lp[1][1].process(lp[0][1].process(right)));
+                 break;
+         }
+     }
+     if (*params[AM::param_hp_active] > 0.f)
+     {
+         switch(hp_mode)
+         {
+             case MODE12DB:
+                 left = hp[0][0].process(left);
+                 right = hp[0][1].process(right);
+                 break;
+             case MODE24DB:
+                 left = hp[1][0].process(hp[0][0].process(left));
+                 right = hp[1][1].process(hp[0][1].process(right));
+                 break;
+             case MODE36DB:
+                 left = hp[2][0].process(hp[1][0].process(hp[0][0].process(left)));
+                 right = hp[2][1].process(hp[1][1].process(hp[0][1].process(right)));
+                 break;
+         }
      }
  }
  
  #define SET_IF_CONNECTED(param) if (params[AM::param_##param] != NULL) *params[AM::param_##param] = param;
  
- template<class BaseClass>
- uint32_t equalizerNband_audio_module<BaseClass>::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
+ template<class BaseClass, bool has_lphp>
+ uint32_t equalizerNband_audio_module<BaseClass, has_lphp>::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
  {
      bool bypass = *params[AM::param_bypass] > 0.f;
      numsamples += offset;
@@@ -1859,8 -1889,6 +1889,6 @@@
          meter_inR = 0.f;
          meter_outL = 0.f;
          meter_outR = 0.f;
-         CalfEqMode hp_mode = (CalfEqMode)(int)*params[AM::param_hp_mode];
-         CalfEqMode lp_mode = (CalfEqMode)(int)*params[AM::param_lp_mode];
          
          // process
          while(offset < numsamples) {
@@@ -1877,12 -1905,7 +1905,7 @@@
              float procR = inR;
              
              // all filters in chain
-             if(*params[AM::param_hp_active] > 0.f) {
-                 process_hplp(procL, procR, hp, hp_mode);
-             }
-             if(*params[AM::param_lp_active] > 0.f) {
-                 process_hplp(procL, procR, lp, lp_mode);
-             }
+             process_hplp(procL, procR);
              if(*params[AM::param_ls_active] > 0.f) {
                  procL = lsL.process(procL);
                  procR = lsR.process(procR);
@@@ -1965,8 -1988,8 +1988,8 @@@
  
  #undef SET_IF_CONNECTED
  
- template<class BaseClass>
- bool equalizerNband_audio_module<BaseClass>::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
+ template<class BaseClass, bool has_lphp>
+ bool equalizerNband_audio_module<BaseClass, has_lphp>::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
  {
      if (!is_active)
          return false;
@@@ -1977,8 -2000,8 +2000,8 @@@
      return false;
  }
  
- template<class BaseClass>
- bool equalizerNband_audio_module<BaseClass>::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
+ template<class BaseClass, bool has_lphp>
+ bool equalizerNband_audio_module<BaseClass, has_lphp>::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
  {
      if (!is_active) {
          return false;
@@@ -1987,8 -2010,8 +2010,8 @@@
      }
  }
  
- template<class BaseClass>
- int equalizerNband_audio_module<BaseClass>::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+ template<class BaseClass, bool has_lphp>
+ int equalizerNband_audio_module<BaseClass, has_lphp>::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
  {
      if (!is_active) {
          return false;
@@@ -2036,12 -2059,15 +2059,15 @@@ static inline float adjusted_lphp_gain(
      return 1;
  }
  
- template<class BaseClass>
- float equalizerNband_audio_module<BaseClass>::freq_gain(int index, double freq, uint32_t sr)
+ template<class BaseClass, bool use_hplp>
+ float equalizerNband_audio_module<BaseClass, use_hplp>::freq_gain(int index, double freq, uint32_t sr)
  {
      float ret = 1.f;
-     ret *= adjusted_lphp_gain(params, AM::param_hp_active, AM::param_hp_mode, hp[0][0], freq, (float)sr);
-     ret *= adjusted_lphp_gain(params, AM::param_lp_active, AM::param_lp_mode, lp[0][0], freq, (float)sr);
+     if (use_hplp)
+     {
+         ret *= adjusted_lphp_gain(params, AM::param_hp_active, AM::param_hp_mode, hp[0][0], freq, (float)sr);
+         ret *= adjusted_lphp_gain(params, AM::param_lp_active, AM::param_lp_mode, lp[0][0], freq, (float)sr);
+     }
      ret *= (*params[AM::param_ls_active] > 0.f) ? lsL.freq_gain(freq, sr) : 1;
      ret *= (*params[AM::param_hs_active] > 0.f) ? hsL.freq_gain(freq, sr) : 1;
      for (int i = 0; i < PeakBands; i++)
@@@ -2049,105 -2075,216 +2075,216 @@@
      return ret;
  }
  
- template class equalizerNband_audio_module<equalizer8band_metadata>;
- template class equalizerNband_audio_module<equalizer12band_metadata>;
+ template class equalizerNband_audio_module<equalizer5band_metadata, false>;
+ template class equalizerNband_audio_module<equalizer8band_metadata, true>;
+ template class equalizerNband_audio_module<equalizer12band_metadata, true>;
+ 
+ /// LFO module by Markus
+ /// This module provides simple LFO's (sine=0, triangle=1, square=2, saw_up=3, saw_down=4)
+ /// get_value() returns a value between -1 and 1
+ ////////////////////////////////////////////////////////////////////////////////
+ lfo_audio_module::lfo_audio_module()
+ {
+     is_active       = false;
+     phase = 0.f;
+ }
+ 
+ void lfo_audio_module::activate()
+ {
+     is_active = true;
+     phase = 0.f;
+ }
+ 
+ void lfo_audio_module::deactivate()
+ {
+     is_active = false;
+ }
+ 
+ float lfo_audio_module::get_value()
+ {
+     return get_value_from_phase(phase, offset) * amount;
+ }
+ 
+ float lfo_audio_module::get_value_from_phase(float ph, float off)
+ {
+     float val = 0.f;
+     float phs = ph + off;
+     if (phs >= 1.0)
+         phs = fmod(phs, 1.f);
+     switch (mode) {
+         default:
+         case 0:
+             // sine
+             val = sin((phs * 360.f) * M_PI / 180);
+             break;
+         case 1:
+             // triangle
+             if(phs > 0.75)
+                 val = (phs - 0.75) * 4 - 1;
+             else if(phs > 0.5)
+                 val = (phs - 0.5) * 4 * -1;
+             else if(phs > 0.25)
+                 val = 1 - (phs - 0.25) * 4;
+             else
+                 val = phs * 4;
+             break;
+         case 2:
+             // square
+             val = (phs < 0.5) ? -1 : +1;
+             break;
+         case 3:
+             // saw up
+                 val = phs * 2.f - 1;
+             break;
+         case 4:
+             // saw down
+             val = 1 - phs * 2.f;
+             break;
+     }
+     return val;
+ }
+ 
+ void lfo_audio_module::advance(uint32_t count)
+ {
+     //this function walks from 0.f to 1.f and starts all over again
+     phase += count * freq * (1.0 / srate);
+     if (phase >= 1.0)
+         phase = fmod(phase, 1.f);
+ }
+ 
+ void lfo_audio_module::set_phase(float ph)
+ {
+     //set the phase from outsinde
+     phase = fabs(ph);
+     if (phase >= 1.0)
+         phase = fmod(phase, 1.f);
+ }
+ 
+ void lfo_audio_module::set_params(float f, int m, float o, uint32_t sr, float a)
+ {
+     // freq: a value in Hz
+     // mode: sine=0, triangle=1, square=2, saw_up=3, saw_down=4
+     // offset: value between 0.f and 1.f to offset the lfo in time
+     freq = f;
+     mode = m;
+     offset = o;
+     srate = sr;
+     amount = a;
+ }
+ 
+ bool lfo_audio_module::get_graph(float *data, int points, cairo_iface *context)
+ {
+     if (!is_active)
+         return false;
+     for (int i = 0; i < points; i++) {
+         float ph = (float)i / (float)points;
+         data[i] = get_value_from_phase(ph, offset) * amount;
+     }
+     return true;
+ }
+ 
+ bool lfo_audio_module::get_dot(float &x, float &y, int &size, cairo_iface *context)
+ {
+     if (!is_active)
+         return false;
+     float phs = phase + offset;
+     if (phs >= 1.0)
+         phs = fmod(phs, 1.f);
+     x = phase;
+     y = get_value_from_phase(phase, offset) * amount;
+     return true;
+ }
  
- /// Equalizer 5 Band by Markus Schmidt
+ /// Pulsator by Markus Schmidt
  ///
- /// This module is based on Krzysztof's filters. It provides a couple
- /// of different chained filters.
+ /// This module provides a couple
+ /// of different LFO's for modulating the level of a signal.
  ///////////////////////////////////////////////////////////////////////////////////////////////
  
- equalizer5band_audio_module::equalizer5band_audio_module()
+ pulsator_audio_module::pulsator_audio_module()
  {
      is_active = false;
      srate = 0;
-     last_generation = 0;
-     clip_in    = 0.f;
-     clip_out   = 0.f;
-     meter_in  = 0.f;
-     meter_out = 0.f;
+ //    last_generation = 0;
+     clip_inL    = 0.f;
+     clip_inR    = 0.f;
+     clip_outL   = 0.f;
+     clip_outR   = 0.f;
+     meter_inL  = 0.f;
+     meter_inR  = 0.f;
+     meter_outL = 0.f;
+     meter_outR = 0.f;
  }
  
- void equalizer5band_audio_module::activate()
+ void pulsator_audio_module::activate()
  {
      is_active = true;
-     // set all filters
+     lfoL.activate();
+     lfoR.activate();
      params_changed();
  }
- void equalizer5band_audio_module::deactivate()
+ void pulsator_audio_module::deactivate()
  {
      is_active = false;
+     lfoL.deactivate();
+     lfoR.deactivate();
  }
  
- void equalizer5band_audio_module::params_changed()
+ void pulsator_audio_module::params_changed()
  {
-     // set the params of all filters
-     if(*params[param_ls_freq] != ls_freq_old or *params[param_ls_level] != ls_level_old) {
-         lsL.set_lowshelf_rbj(*params[param_ls_freq], 0.707, *params[param_ls_level], (float)srate);
-         lsR.copy_coeffs(lsL);
-         ls_level_old = *params[param_ls_level];
-         ls_freq_old = *params[param_ls_freq];
-     }
-     if(*params[param_hs_freq] != hs_freq_old or *params[param_hs_level] != hs_level_old) {
-         hsL.set_highshelf_rbj(*params[param_hs_freq], 0.707, *params[param_hs_level], (float)srate);
-         hsR.copy_coeffs(hsL);
-         hs_level_old = *params[param_hs_level];
-         hs_freq_old = *params[param_hs_freq];
-     }
-     if(*params[param_p1_freq] != p_freq_old[0] or *params[param_p1_level] != p_level_old[0] or *params[param_p1_q] != p_q_old[0]) {
-         pL[0].set_peakeq_rbj((float)*params[param_p1_freq], *params[param_p1_q], *params[param_p1_level], (float)srate);
-         pR[0].copy_coeffs(pL[0]);
-         p_freq_old[0] = *params[param_p1_freq];
-         p_level_old[0] = *params[param_p1_level];
-         p_q_old[0] = *params[param_p1_q];
-     }
-     if(*params[param_p2_freq] != p_freq_old[1] or *params[param_p2_level] != p_level_old[1] or *params[param_p2_q] != p_q_old[1]) {
-         pL[1].set_peakeq_rbj((float)*params[param_p2_freq], *params[param_p2_q], *params[param_p2_level], (float)srate);
-         pR[1].copy_coeffs(pL[1]);
-         p_freq_old[1] = *params[param_p2_freq];
-         p_level_old[1] = *params[param_p2_level];
-         p_q_old[1] = *params[param_p2_q];
-     }
-     if(*params[param_p3_freq] != p_freq_old[2] or *params[param_p3_level] != p_level_old[2] or *params[param_p3_q] != p_q_old[2]) {
-         pL[2].set_peakeq_rbj((float)*params[param_p3_freq], *params[param_p3_q], *params[param_p3_level], (float)srate);
-         pR[2].copy_coeffs(pL[2]);
-         p_freq_old[2] = *params[param_p3_freq];
-         p_level_old[2] = *params[param_p3_level];
-         p_q_old[2] = *params[param_p3_q];
+     lfoL.set_params(*params[param_freq], *params[param_mode], 0.f, srate, *params[param_amount]);
+     lfoR.set_params(*params[param_freq], *params[param_mode], *params[param_offset], srate, *params[param_amount]);
+     clear_reset = false;
+     if (*params[param_reset] >= 0.5) {
+         clear_reset = true;
+         lfoL.set_phase(0.f);
+         lfoR.set_phase(0.f);
      }
  }
  
- void equalizer5band_audio_module::set_sample_rate(uint32_t sr)
+ void pulsator_audio_module::set_sample_rate(uint32_t sr)
  {
      srate = sr;
  }
  
- uint32_t equalizer5band_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
+ uint32_t pulsator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
  {
      bool bypass = *params[param_bypass] > 0.5f;
-     numsamples += offset;
+     uint32_t samples = numsamples + offset;
      if(bypass) {
          // everything bypassed
-         while(offset < numsamples) {
+         while(offset < samples) {
              outs[0][offset] = ins[0][offset];
              outs[1][offset] = ins[1][offset];
              ++offset;
          }
          // displays, too
-         clip_in    = 0.f;
-         clip_out   = 0.f;
-         meter_in  = 0.f;
-         meter_out = 0.f;
+         clip_inL    = 0.f;
+         clip_inR    = 0.f;
+         clip_outL   = 0.f;
+         clip_outR   = 0.f;
+         meter_inL  = 0.f;
+         meter_inR  = 0.f;
+         meter_outL = 0.f;
+         meter_outR = 0.f;
+         
+         // LFO's should go on
+         lfoL.advance(numsamples);
+         lfoR.advance(numsamples);
+         
      } else {
          
-         clip_in    -= std::min(clip_in,  numsamples);
-         clip_out   -= std::min(clip_out, numsamples);
-         meter_in = 0.f;
-         meter_out = 0.f;
+         clip_inL    -= std::min(clip_inL,  numsamples);
+         clip_inR    -= std::min(clip_inR,  numsamples);
+         clip_outL   -= std::min(clip_outL, numsamples);
+         clip_outR   -= std::min(clip_outR, numsamples);
+         meter_inL = 0.f;
+         meter_inR = 0.f;
+         meter_outL = 0.f;
+         meter_outR = 0.f;
          
          // process
-         while(offset < numsamples) {
+         while(offset < samples) {
              // cycle through samples
              float outL = 0.f;
              float outR = 0.f;
@@@ -2157,940 -2294,130 +2294,914 @@@
              inR *= *params[param_level_in];
              inL *= *params[param_level_in];
              
+             if(*params[param_mono] > 0.5) {
+                 inL = (inL + inR) * 0.5;
+                 inR = inL;
+             }
              float procL = inL;
              float procR = inR;
              
-             // all filters in chain
-             if(*params[param_ls_active] > 0.f) {
-                 procL = lsL.process(procL);
-                 procR = lsR.process(procR);
-             }
-             if(*params[param_hs_active] > 0.f) {
-                 procL = hsL.process(procL);
-                 procR = hsR.process(procR);
-             }
-             if(*params[param_p1_active] > 0.f) {
-                 procL = pL[0].process(procL);
-                 procR = pR[0].process(procR);
-             }
-             if(*params[param_p2_active] > 0.f) {
-                 procL = pL[1].process(procL);
-                 procR = pR[1].process(procR);
-             }
-             if(*params[param_p3_active] > 0.f) {
-                 procL = pL[2].process(procL);
-                 procR = pR[2].process(procR);
-             }
+             procL *= (lfoL.get_value() * 0.5 + *params[param_amount] / 2);
+             procR *= (lfoR.get_value() * 0.5 + *params[param_amount] / 2);
+             
+             outL = procL + inL * (1 - *params[param_amount]);
+             outR = procR + inR * (1 - *params[param_amount]);
              
-             outL = procL * *params[param_level_out];
-             outR = procR * *params[param_level_out];
+             outL *=  *params[param_level_out];
+             outR *=  *params[param_level_out];
              
              // send to output
              outs[0][offset] = outL;
              outs[1][offset] = outR;
              
              // clip LED's
-             float maxIn = std::max(fabs(inL), fabs(inR));
-             float maxOut = std::max(fabs(outL), fabs(outR));
-             
-             if(maxIn > 1.f) {
-                 clip_in  = srate >> 3;
+             if(inL > 1.f) {
+                 clip_inL  = srate >> 3;
+             }
+             if(inR > 1.f) {
+                 clip_inR  = srate >> 3;
+             }
+             if(outL > 1.f) {
+                 clip_outL = srate >> 3;
              }
-             if(maxOut > 1.f) {
-                 clip_out = srate >> 3;
+             if(outR > 1.f) {
+                 clip_outR = srate >> 3;
              }
              // set up in / out meters
-             if(maxIn > meter_in) {
-                 meter_in = maxIn;
+             if(inL > meter_inL) {
+                 meter_inL = inL;
              }
-             if(maxOut > meter_out) {
-                 meter_out = maxOut;
+             if(inR > meter_inR) {
+                 meter_inR = inR;
+             }
+             if(outL > meter_outL) {
+                 meter_outL = outL;
+             }
+             if(outR > meter_outR) {
+                 meter_outR = outR;
              }
              
              // next sample
              ++offset;
+             
+             // advance lfo's
+             lfoL.advance(1);
+             lfoR.advance(1);
          } // cycle trough samples
-         // clean up
-         lsL.sanitize();
-         hsR.sanitize();
-         for(int i = 0; i < 3; ++i) {
-             pL[i].sanitize();
-             pR[i].sanitize();
-         }
      }
      // draw meters
-     if(params[param_clip_in] != NULL) {
-         *params[param_clip_in] = clip_in;
+     if(params[param_clip_inL] != NULL) {
+         *params[param_clip_inL] = clip_inL;
      }
-     if(params[param_clip_out] != NULL) {
-         *params[param_clip_out] = clip_out;
+     if(params[param_clip_inR] != NULL) {
+         *params[param_clip_inR] = clip_inR;
+     }
+     if(params[param_clip_outL] != NULL) {
+         *params[param_clip_outL] = clip_outL;
+     }
+     if(params[param_clip_outR] != NULL) {
+         *params[param_clip_outR] = clip_outR;
      }
      
-     if(params[param_meter_in] != NULL) {
-         *params[param_meter_in] = meter_in;
+     if(params[param_meter_inL] != NULL) {
+         *params[param_meter_inL] = meter_inL;
      }
-     if(params[param_meter_out] != NULL) {
-         *params[param_meter_out] = meter_out;
+     if(params[param_meter_inR] != NULL) {
+         *params[param_meter_inR] = meter_inR;
+     }
+     if(params[param_meter_outL] != NULL) {
+         *params[param_meter_outL] = meter_outL;
+     }
+     if(params[param_meter_outR] != NULL) {
+         *params[param_meter_outR] = meter_outR;
      }
      // whatever has to be returned x)
      return outputs_mask;
  }
- bool equalizer5band_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
+ bool pulsator_audio_module::get_graph(int index, int subindex, float *data, int points, cairo_iface *context)
  {
-     if (!is_active)
+     if (!is_active) {
          return false;
-     if (index == param_p1_freq && !subindex) {
-         context->set_line_width(1.5);
-         return ::get_graph(*this, subindex, data, points);
+     } else if(index == param_freq) {
+         if(subindex == 0) {
+             context->set_source_rgba(0.35, 0.4, 0.2, 1);
+             return lfoL.get_graph(data, points, context);
+         }
+         if(subindex == 1) {
+             context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
+             return lfoR.get_graph(data, points, context);
+         }
      }
      return false;
  }
- 
- bool equalizer5band_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
+ bool pulsator_audio_module::get_dot(int index, int subindex, float &x, float &y, int &size, cairo_iface *context)
  {
      if (!is_active) {
          return false;
-     } else {
-         return get_freq_gridline(subindex, pos, vertical, legend, context);
+     } else if(index == param_freq) {
+         if(subindex == 0) {
+             context->set_source_rgba(0.35, 0.4, 0.2, 1);
+             return lfoL.get_dot(x, y, size, context);
+         }
+         if(subindex == 1) {
+             context->set_source_rgba(0.35, 0.4, 0.2, 0.5);
+             return lfoR.get_dot(x, y, size, context);
+         }
+         return false;
      }
+     return false;
  }
- 
- int equalizer5band_audio_module::get_changed_offsets(int index, int generation, int &subindex_graph, int &subindex_dot, int &subindex_gridline)
+ bool pulsator_audio_module::get_gridline(int index, int subindex, float &pos, bool &vertical, std::string &legend, cairo_iface *context)
  {
-     if (!is_active) {
-         return false;
-     } else {
-         if (*params[param_ls_freq] != ls_freq_old1
-             or *params[param_ls_level] != ls_level_old1
-             or *params[param_hs_freq] != hs_freq_old1
-             or *params[param_hs_level] != hs_level_old1
-             
-             or *params[param_p1_freq] != p_freq_old1[0]
-             or *params[param_p1_level] != p_level_old1[0]
-             or *params[param_p1_q] != p_q_old1[0]
-             
-             or *params[param_p2_freq] != p_freq_old1[1]
-             or *params[param_p2_level] != p_level_old1[1]
-             or *params[param_p2_q] != p_q_old1[1]
-                         
-             or *params[param_p3_freq] != p_freq_old1[2]
-             or *params[param_p3_level] != p_level_old1[2]
-             or *params[param_p3_q] != p_q_old1[2])
-         {
-             
-             ls_freq_old1 = *params[param_ls_freq];
-             ls_level_old1 = *params[param_ls_level];
-             hs_freq_old1 = *params[param_hs_freq];
-             hs_level_old1 = *params[param_hs_level];
-             
-             p_freq_old1[0] = *params[param_p1_freq];
-             p_level_old1[0] = *params[param_p1_level];
-             p_q_old1[0] = *params[param_p1_q];
-             
-             p_freq_old1[1] = *params[param_p2_freq];
-             p_level_old1[1] = *params[param_p2_level];
-             p_q_old1[1] = *params[param_p2_q];
-             
-             p_freq_old1[2] = *params[param_p3_freq];
-             p_level_old1[2] = *params[param_p3_level];
-             p_q_old1[2] = *params[param_p3_q];
-             
-             last_generation++;
-             subindex_graph = 0;
-             subindex_dot = INT_MAX;
-             subindex_gridline = INT_MAX;
-         }
-         else {
-             subindex_graph = 0;
-             subindex_dot = subindex_gridline = generation ? INT_MAX : 0;
-         }
-         if (generation == last_calculated_generation)
-             subindex_graph = INT_MAX;
-         return last_generation;
+    if (index == param_freq && !subindex)
+     {
+         pos = 0;
+         vertical = false;
+         return true;
      }
      return false;
  }
 +
 +/// Saturator Band by Markus Schmidt
 +///
 +/// This module is based on Krzysztof's filters and distortion routine.
 +/// It provides a blendable saturation stage followed by a highpass, a lowpass and a peak filter
 +///////////////////////////////////////////////////////////////////////////////////////////////
 +
 +saturator_audio_module::saturator_audio_module()
 +{
 +    is_active = false;
 +    srate = 0;
 +    clip_in    = 0.f;
 +    clip_out   = 0.f;
 +    meter_in  = 0.f;
 +    meter_out = 0.f;
 +    meter_drive = 0.f;
 +}
 +
 +void saturator_audio_module::activate()
 +{
 +    is_active = true;
 +    // set all filters
 +    params_changed();
 +}
 +void saturator_audio_module::deactivate()
 +{
 +    is_active = false;
 +}
 +
 +void saturator_audio_module::params_changed()
 +{
 +    // set the params of all filters
 +    if(*params[param_lp_pre_freq] != lp_pre_freq_old) {
 +        lp[0][0].set_lp_rbj(*params[param_lp_pre_freq], 0.707, (float)srate);
 +        if(in_count > 1 && out_count > 1)
 +            lp[1][0].copy_coeffs(lp[0][0]);
 +        lp[0][1].copy_coeffs(lp[0][0]);
 +        if(in_count > 1 && out_count > 1)
 +            lp[1][1].copy_coeffs(lp[0][0]);
 +        lp_pre_freq_old = *params[param_lp_pre_freq];
 +    }
 +    if(*params[param_hp_pre_freq] != hp_pre_freq_old) {
 +        hp[0][0].set_hp_rbj(*params[param_hp_pre_freq], 0.707, (float)srate);
 +        if(in_count > 1 && out_count > 1)
 +            hp[1][0].copy_coeffs(hp[0][0]);
 +        hp[0][1].copy_coeffs(hp[0][0]);
 +        if(in_count > 1 && out_count > 1)
 +            hp[1][1].copy_coeffs(hp[0][0]);
 +        hp_pre_freq_old = *params[param_hp_pre_freq];
 +    }
 +    if(*params[param_lp_post_freq] != lp_post_freq_old) {
 +        lp[0][2].set_lp_rbj(*params[param_lp_post_freq], 0.707, (float)srate);
 +        if(in_count > 1 && out_count > 1)
 +            lp[1][2].copy_coeffs(lp[0][2]);
 +        lp[0][3].copy_coeffs(lp[0][2]);
 +        if(in_count > 1 && out_count > 1)
 +            lp[1][3].copy_coeffs(lp[0][2]);
 +        lp_post_freq_old = *params[param_lp_post_freq];
 +    }
 +    if(*params[param_hp_post_freq] != hp_post_freq_old) {
 +        hp[0][2].set_hp_rbj(*params[param_hp_post_freq], 0.707, (float)srate);
 +        if(in_count > 1 && out_count > 1)
 +            hp[1][2].copy_coeffs(hp[0][2]);
 +        hp[0][3].copy_coeffs(hp[0][2]);
 +        if(in_count > 1 && out_count > 1)
 +            hp[1][3].copy_coeffs(hp[0][2]);
 +        hp_post_freq_old = *params[param_hp_post_freq];
 +    }
 +    if(*params[param_p_freq] != p_freq_old or *params[param_p_level] != p_level_old or *params[param_p_q] != p_q_old) {
 +        p[0].set_peakeq_rbj((float)*params[param_p_freq], (float)*params[param_p_q], (float)*params[param_p_level], (float)srate);
 +        if(in_count > 1 && out_count > 1)
 +            p[1].copy_coeffs(p[0]);
 +        p_freq_old = *params[param_p_freq];
 +        p_level_old = *params[param_p_level];
 +        p_q_old = *params[param_p_q];
 +    }
 +    // set distortion
 +    dist[0].set_params(*params[param_blend], *params[param_drive]);
 +    if(in_count > 1 && out_count > 1)
 +        dist[1].set_params(*params[param_blend], *params[param_drive]);
 +}
 +
 +void saturator_audio_module::set_sample_rate(uint32_t sr)
 +{
 +    srate = sr;
 +    dist[0].set_sample_rate(sr);
 +    if(in_count > 1 && out_count > 1)
 +        dist[1].set_sample_rate(sr);
 +}
 +
 +uint32_t saturator_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
 +{
 +    bool bypass = *params[param_bypass] > 0.5f;
 +    numsamples += offset;
 +    if(bypass) {
 +        // everything bypassed
 +        while(offset < numsamples) {
 +            if(in_count > 1 && out_count > 1) {
 +                outs[0][offset] = ins[0][offset];
 +                outs[1][offset] = ins[1][offset];
 +            } else if(in_count > 1) {
 +                outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
 +            } else if(out_count > 1) {
 +                outs[0][offset] = ins[0][offset];
 +                outs[1][offset] = ins[0][offset];
 +            } else {
 +                outs[0][offset] = ins[0][offset];
 +            }
 +            ++offset;
 +        }
 +        // displays, too
 +        clip_in    = 0.f;
 +        clip_out   = 0.f;
 +        meter_in  = 0.f;
 +        meter_out = 0.f;
 +        meter_drive = 0.f;
 +    } else {
 +        
 +        clip_in    -= std::min(clip_in,  numsamples);
 +        clip_out   -= std::min(clip_out, numsamples);
 +        meter_in = 0.f;
 +        meter_out = 0.f;
 +        meter_drive = 0.f;
 +        
 +        // process
 +        while(offset < numsamples) {
 +            // cycle through samples
 +            float out[2], in[2] = {0.f, 0.f};
 +            float maxIn, maxOut, maxDrive = 0.f;
 +            int c = 0;
 +            
 +            if(in_count > 1 && out_count > 1) {
 +                // stereo in/stereo out
 +                // handle full stereo
 +                in[0] = ins[0][offset];
 +                in[0] *= *params[param_level_in];
 +                in[1] = ins[1][offset];
 +                in[1] *= *params[param_level_in];
 +                c = 2;
 +            } else {
 +                // in and/or out mono
 +                // handle mono
 +                in[0] = ins[0][offset];
 +                in[0] *= *params[param_level_in];
 +                in[1] = in[0];
 +                c = 1;
 +            }
 +            
 +            float proc[2];
 +            proc[0] = in[0];
 +            proc[1] = in[1];
 +            
 +            for (int i = 0; i < c; ++i) {
 +                // all pre filters in chain
 +                proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
 +                proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
 +                
 +                // saturate
 +                proc[i] = dist[i].process(proc[i]);
 +                
 +                // tone control
 +                proc[i] = p[i].process(proc[i]);
 +
 +                // all post filters in chain
 +                proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
 +                proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
 +            }
 +            
 +            if(in_count > 1 && out_count > 1) {
 +                // full stereo
 +                out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                out[1] = ((proc[1] * *params[param_mix]) + in[1] * (1 - *params[param_mix])) * *params[param_level_out];
 +                outs[1][offset] = out[1];
 +                maxIn = std::max(fabs(in[0]), fabs(in[1]));
 +                maxOut = std::max(fabs(out[0]), fabs(out[1]));
 +                maxDrive = std::max(dist[0].get_distortion_level(), dist[1].get_distortion_level());
 +            } else if(out_count > 1) {
 +                // mono -> pseudo stereo
 +                out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                out[1] = out[0];
 +                outs[1][offset] = out[1];
 +                maxOut = fabs(out[0]);
 +                maxIn = fabs(in[0]);
 +                maxDrive = dist[0].get_distortion_level();
 +            } else {
 +                // stereo -> mono
 +                // or full mono
 +                out[0] = ((proc[0] * *params[param_mix]) + in[0] * (1 - *params[param_mix])) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                maxIn = fabs(in[0]);
 +                maxOut = fabs(out[0]);
 +                maxDrive = dist[0].get_distortion_level();
 +            }
 +            
 +            if(maxIn > 1.f) {
 +                clip_in  = srate >> 3;
 +            }
 +            if(maxOut > 1.f) {
 +                clip_out = srate >> 3;
 +            }
 +            // set up in / out meters
 +            if(maxIn > meter_in) {
 +                meter_in = maxIn;
 +            }
 +            if(maxOut > meter_out) {
 +                meter_out = maxOut;
 +            }
 +            if(maxDrive > meter_drive) {
 +                meter_drive = maxDrive;
 +            }
 +            
 +            // next sample
 +            ++offset;
 +        } // cycle trough samples
 +        // clean up
 +        lp[0][0].sanitize();
 +        lp[1][0].sanitize();
 +        lp[0][1].sanitize();
 +        lp[1][1].sanitize();
 +        lp[0][2].sanitize();
 +        lp[1][2].sanitize();
 +        lp[0][3].sanitize();
 +        lp[1][3].sanitize();
 +        hp[0][0].sanitize();
 +        hp[1][0].sanitize();
 +        hp[0][1].sanitize();
 +        hp[1][1].sanitize();
 +        hp[0][2].sanitize();
 +        hp[1][2].sanitize();
 +        hp[0][3].sanitize();
 +        hp[1][3].sanitize();
 +        p[0].sanitize();
 +        p[1].sanitize();
 +    }
 +    // draw meters
 +    if(params[param_clip_in] != NULL) {
 +        *params[param_clip_in] = clip_in;
 +    }
 +    if(params[param_clip_out] != NULL) {
 +        *params[param_clip_out] = clip_out;
 +    }
 +    
 +    if(params[param_meter_in] != NULL) {
 +        *params[param_meter_in] = meter_in;
 +    }
 +    if(params[param_meter_out] != NULL) {
 +        *params[param_meter_out] = meter_out;
 +    }
 +    if(params[param_meter_drive] != NULL) {
 +        *params[param_meter_drive] = meter_drive;
 +    }
 +    // whatever has to be returned x)
 +    return outputs_mask;
 +}
 +
 +/// Exciter by Markus Schmidt
 +///
 +/// This module is based on Krzysztof's filters and distortion routine.
 +/// It sends the signal through a highpass, saturates it and sends it through a highpass again
 +///////////////////////////////////////////////////////////////////////////////////////////////
 +
 +exciter_audio_module::exciter_audio_module()
 +{
 +    is_active = false;
 +    srate = 0;
 +    clip_in    = 0.f;
 +    clip_out   = 0.f;
 +    meter_in  = 0.f;
 +    meter_out = 0.f;
 +    meter_drive = 0.f;
 +}
 +
 +void exciter_audio_module::activate()
 +{
 +    is_active = true;
 +    // set all filters
 +    params_changed();
 +}
 +void exciter_audio_module::deactivate()
 +{
 +    is_active = false;
 +}
 +
 +void exciter_audio_module::params_changed()
 +{
 +    // set the params of all filters
 +    if(*params[param_freq] != freq_old) {
 +        hp[0][0].set_hp_rbj(*params[param_freq], 0.707, (float)srate);
 +        hp[0][1].copy_coeffs(hp[0][0]);
 +        hp[0][2].copy_coeffs(hp[0][0]);
 +        hp[0][3].copy_coeffs(hp[0][0]);
 +        if(in_count > 1 && out_count > 1) {
 +            hp[1][0].copy_coeffs(hp[0][0]);
 +            hp[1][1].copy_coeffs(hp[0][0]);
 +            hp[1][2].copy_coeffs(hp[0][0]);
 +            hp[1][3].copy_coeffs(hp[0][0]);
 +        }
 +        freq_old = *params[param_freq];
 +    }
 +    // set distortion
 +    dist[0].set_params(*params[param_blend], *params[param_drive]);
 +    if(in_count > 1 && out_count > 1)
 +        dist[1].set_params(*params[param_blend], *params[param_drive]);
 +}
 +
 +void exciter_audio_module::set_sample_rate(uint32_t sr)
 +{
 +    srate = sr;
 +    dist[0].set_sample_rate(sr);
 +    if(in_count > 1 && out_count > 1)
 +        dist[1].set_sample_rate(sr);
 +}
 +
 +uint32_t exciter_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
 +{
 +    bool bypass = *params[param_bypass] > 0.5f;
 +    numsamples += offset;
 +    if(bypass) {
 +        // everything bypassed
 +        while(offset < numsamples) {
 +            if(in_count > 1 && out_count > 1) {
 +                outs[0][offset] = ins[0][offset];
 +                outs[1][offset] = ins[1][offset];
 +            } else if(in_count > 1) {
 +                outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
 +            } else if(out_count > 1) {
 +                outs[0][offset] = ins[0][offset];
 +                outs[1][offset] = ins[0][offset];
 +            } else {
 +                outs[0][offset] = ins[0][offset];
 +            }
 +            ++offset;
 +        }
 +        // displays, too
 +        clip_in    = 0.f;
 +        clip_out   = 0.f;
 +        meter_in  = 0.f;
 +        meter_out = 0.f;
 +        meter_drive = 0.f;
 +    } else {
 +        
 +        clip_in    -= std::min(clip_in,  numsamples);
 +        clip_out   -= std::min(clip_out, numsamples);
 +        meter_in = 0.f;
 +        meter_out = 0.f;
 +        meter_drive = 0.f;
 +        
 +        // process
 +        while(offset < numsamples) {
 +            // cycle through samples
 +            float out[2], in[2] = {0.f, 0.f};
 +            float maxIn, maxOut, maxDrive = 0.f;
 +            int c = 0;
 +            
 +            if(in_count > 1 && out_count > 1) {
 +                // stereo in/stereo out
 +                // handle full stereo
 +                in[0] = ins[0][offset];
 +                in[0] *= *params[param_level_in];
 +                in[1] = ins[1][offset];
 +                in[1] *= *params[param_level_in];
 +                c = 2;
 +            } else {
 +                // in and/or out mono
 +                // handle mono
 +                in[0] = ins[0][offset];
 +                in[0] *= *params[param_level_in];
 +                in[1] = in[0];
 +                c = 1;
 +            }
 +            
 +            float proc[2];
 +            proc[0] = in[0];
 +            proc[1] = in[1];
 +            
 +            for (int i = 0; i < c; ++i) {
 +                // all pre filters in chain
 +                proc[i] = hp[i][1].process(hp[i][0].process(proc[i]));
 +                
 +                // saturate
 +                proc[i] = dist[i].process(proc[i]);
 +
 +                // all post filters in chain
 +                proc[i] = hp[i][2].process(hp[i][3].process(proc[i]));
 +            }
 +            
 +            if(in_count > 1 && out_count > 1) {
 +                // full stereo
 +                if(*params[param_listen] > 0.f)
 +                    out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                if(*params[param_listen] > 0.f)
 +                    out[1] = proc[1] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out];
 +                outs[1][offset] = out[1];
 +                maxIn = std::max(fabs(in[0]), fabs(in[1]));
 +                maxOut = std::max(fabs(out[0]), fabs(out[1]));
 +                maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount],
 +                                            dist[1].get_distortion_level() * *params[param_amount]);
 +            } else if(out_count > 1) {
 +                // mono -> pseudo stereo
 +                if(*params[param_listen] > 0.f)
 +                    out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                out[1] = out[0];
 +                outs[1][offset] = out[1];
 +                maxOut = fabs(out[0]);
 +                maxIn = fabs(in[0]);
 +                maxDrive = dist[0].get_distortion_level() * *params[param_amount];
 +            } else {
 +                // stereo -> mono
 +                // or full mono
 +                if(*params[param_listen] > 0.f)
 +                    out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                maxIn = fabs(in[0]);
 +                maxOut = fabs(out[0]);
 +                maxDrive = dist[0].get_distortion_level() * *params[param_amount];
 +            }
 +            
 +            if(maxIn > 1.f) {
 +                clip_in  = srate >> 3;
 +            }
 +            if(maxOut > 1.f) {
 +                clip_out = srate >> 3;
 +            }
 +            // set up in / out meters
 +            if(maxIn > meter_in) {
 +                meter_in = maxIn;
 +            }
 +            if(maxOut > meter_out) {
 +                meter_out = maxOut;
 +            }
 +            if(maxDrive > meter_drive) {
 +                meter_drive = maxDrive;
 +            }
 +            
 +            // next sample
 +            ++offset;
 +        } // cycle trough samples
 +        // clean up
 +        hp[0][0].sanitize();
 +        hp[1][0].sanitize();
 +        hp[0][1].sanitize();
 +        hp[1][1].sanitize();
 +        hp[0][2].sanitize();
 +        hp[1][2].sanitize();
 +        hp[0][3].sanitize();
 +        hp[1][3].sanitize();
 +    }
 +    // draw meters
 +    if(params[param_clip_in] != NULL) {
 +        *params[param_clip_in] = clip_in;
 +    }
 +    if(params[param_clip_out] != NULL) {
 +        *params[param_clip_out] = clip_out;
 +    }
 +    
 +    if(params[param_meter_in] != NULL) {
 +        *params[param_meter_in] = meter_in;
 +    }
 +    if(params[param_meter_out] != NULL) {
 +        *params[param_meter_out] = meter_out;
 +    }
 +    if(params[param_meter_drive] != NULL) {
 +        *params[param_meter_drive] = meter_drive;
 +    }
 +    // whatever has to be returned x)
 +    return outputs_mask;
 +}
 +
 +/// Bass Enhancer by Markus Schmidt
 +///
 +/// This module is based on Krzysztof's filters and distortion routine.
 +/// It sends the signal through a lowpass, saturates it and sends it through a lowpass again
 +///////////////////////////////////////////////////////////////////////////////////////////////
 +
 +bassenhancer_audio_module::bassenhancer_audio_module()
 +{
 +    is_active = false;
 +    srate = 0;
 +    clip_in    = 0.f;
 +    clip_out   = 0.f;
 +    meter_in  = 0.f;
 +    meter_out = 0.f;
 +    meter_drive = 0.f;
 +}
 +
 +void bassenhancer_audio_module::activate()
 +{
 +    is_active = true;
 +    // set all filters
 +    params_changed();
 +}
 +void bassenhancer_audio_module::deactivate()
 +{
 +    is_active = false;
 +}
 +
 +void bassenhancer_audio_module::params_changed()
 +{
 +    // set the params of all filters
 +    if(*params[param_freq] != freq_old) {
 +        lp[0][0].set_lp_rbj(*params[param_freq], 0.707, (float)srate);
 +        lp[0][1].copy_coeffs(lp[0][0]);
 +        lp[0][2].copy_coeffs(lp[0][0]);
 +        lp[0][3].copy_coeffs(lp[0][0]);
 +        if(in_count > 1 && out_count > 1) {
 +            lp[1][0].copy_coeffs(lp[0][0]);
 +            lp[1][1].copy_coeffs(lp[0][0]);
 +            lp[1][2].copy_coeffs(lp[0][0]);
 +            lp[1][3].copy_coeffs(lp[0][0]);
 +        }
 +        freq_old = *params[param_freq];
 +    }
 +    // set distortion
 +    dist[0].set_params(*params[param_blend], *params[param_drive]);
 +    if(in_count > 1 && out_count > 1)
 +        dist[1].set_params(*params[param_blend], *params[param_drive]);
 +}
 +
 +void bassenhancer_audio_module::set_sample_rate(uint32_t sr)
 +{
 +    srate = sr;
 +    dist[0].set_sample_rate(sr);
 +    if(in_count > 1 && out_count > 1)
 +        dist[1].set_sample_rate(sr);
 +}
 +
 +uint32_t bassenhancer_audio_module::process(uint32_t offset, uint32_t numsamples, uint32_t inputs_mask, uint32_t outputs_mask)
 +{
 +    bool bypass = *params[param_bypass] > 0.5f;
 +    numsamples += offset;
 +    if(bypass) {
 +        // everything bypassed
 +        while(offset < numsamples) {
 +            if(in_count > 1 && out_count > 1) {
 +                outs[0][offset] = ins[0][offset];
 +                outs[1][offset] = ins[1][offset];
 +            } else if(in_count > 1) {
 +                outs[0][offset] = (ins[0][offset] + ins[1][offset]) / 2;
 +            } else if(out_count > 1) {
 +                outs[0][offset] = ins[0][offset];
 +                outs[1][offset] = ins[0][offset];
 +            } else {
 +                outs[0][offset] = ins[0][offset];
 +            }
 +            ++offset;
 +        }
 +        // displays, too
 +        clip_in    = 0.f;
 +        clip_out   = 0.f;
 +        meter_in  = 0.f;
 +        meter_out = 0.f;
 +        meter_drive = 0.f;
 +    } else {
 +        
 +        clip_in    -= std::min(clip_in,  numsamples);
 +        clip_out   -= std::min(clip_out, numsamples);
 +        meter_in = 0.f;
 +        meter_out = 0.f;
 +        meter_drive = 0.f;
 +        
 +        // process
 +        while(offset < numsamples) {
 +            // cycle through samples
 +            float out[2], in[2] = {0.f, 0.f};
 +            float maxIn, maxOut, maxDrive = 0.f;
 +            int c = 0;
 +            
 +            if(in_count > 1 && out_count > 1) {
 +                // stereo in/stereo out
 +                // handle full stereo
 +                in[0] = ins[0][offset];
 +                in[0] *= *params[param_level_in];
 +                in[1] = ins[1][offset];
 +                in[1] *= *params[param_level_in];
 +                c = 2;
 +            } else {
 +                // in and/or out mono
 +                // handle mono
 +                in[0] = ins[0][offset];
 +                in[0] *= *params[param_level_in];
 +                in[1] = in[0];
 +                c = 1;
 +            }
 +            
 +            float proc[2];
 +            proc[0] = in[0];
 +            proc[1] = in[1];
 +            
 +            for (int i = 0; i < c; ++i) {
 +                // all pre filters in chain
 +                proc[i] = lp[i][1].process(lp[i][0].process(proc[i]));
 +                
 +                // saturate
 +                proc[i] = dist[i].process(proc[i]);
 +
 +                // all post filters in chain
 +                proc[i] = lp[i][2].process(lp[i][3].process(proc[i]));
 +            }
 +            
 +            if(in_count > 1 && out_count > 1) {
 +                // full stereo
 +                if(*params[param_listen] > 0.f)
 +                    out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                if(*params[param_listen] > 0.f)
 +                    out[1] = proc[1] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[1] = (proc[1] * *params[param_amount] + in[1]) * *params[param_level_out];
 +                outs[1][offset] = out[1];
 +                maxIn = std::max(fabs(in[0]), fabs(in[1]));
 +                maxOut = std::max(fabs(out[0]), fabs(out[1]));
 +                maxDrive = std::max(dist[0].get_distortion_level() * *params[param_amount],
 +                                            dist[1].get_distortion_level() * *params[param_amount]);
 +            } else if(out_count > 1) {
 +                // mono -> pseudo stereo
 +                if(*params[param_listen] > 0.f)
 +                    out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                out[1] = out[0];
 +                outs[1][offset] = out[1];
 +                maxOut = fabs(out[0]);
 +                maxIn = fabs(in[0]);
 +                maxDrive = dist[0].get_distortion_level() * *params[param_amount];
 +            } else {
 +                // stereo -> mono
 +                // or full mono
 +                if(*params[param_listen] > 0.f)
 +                    out[0] = proc[0] * *params[param_amount] * *params[param_level_out];
 +                else
 +                    out[0] = (proc[0] * *params[param_amount] + in[0]) * *params[param_level_out];
 +                outs[0][offset] = out[0];
 +                maxIn = fabs(in[0]);
 +                maxOut = fabs(out[0]);
 +                maxDrive = dist[0].get_distortion_level() * *params[param_amount];
 +            }
 +            
 +            if(maxIn > 1.f) {
 +                clip_in  = srate >> 3;
 +            }
 +            if(maxOut > 1.f) {
 +                clip_out = srate >> 3;
 +            }
 +            // set up in / out meters
 +            if(maxIn > meter_in) {
 +                meter_in = maxIn;
 +            }
 +            if(maxOut > meter_out) {
 +                meter_out = maxOut;
 +            }
 +            if(maxDrive > meter_drive) {
 +                meter_drive = maxDrive;
 +            }
 +            
 +            // next sample
 +            ++offset;
 +        } // cycle trough samples
 +        // clean up
 +        lp[0][0].sanitize();
 +        lp[1][0].sanitize();
 +        lp[0][1].sanitize();
 +        lp[1][1].sanitize();
 +        lp[0][2].sanitize();
 +        lp[1][2].sanitize();
 +        lp[0][3].sanitize();
 +        lp[1][3].sanitize();
 +    }
 +    // draw meters
 +    if(params[param_clip_in] != NULL) {
 +        *params[param_clip_in] = clip_in;
 +    }
 +    if(params[param_clip_out] != NULL) {
 +        *params[param_clip_out] = clip_out;
 +    }
 +    
 +    if(params[param_meter_in] != NULL) {
 +        *params[param_meter_in] = meter_in;
 +    }
 +    if(params[param_meter_out] != NULL) {
 +        *params[param_meter_out] = meter_out;
 +    }
 +    if(params[param_meter_drive] != NULL) {
 +        *params[param_meter_drive] = meter_drive;
 +    }
 +    // whatever has to be returned x)
 +    return outputs_mask;
 +}
 +
 +
 +/// Distortion Module by Krzysztof Foltman
 +///
 +/// This module provides a blendable saturation stage
 +///////////////////////////////////////////////////////////////////////////////////////////////
 +
 +distortion_audio_module::distortion_audio_module()
 +{
 +    is_active = false;
 +    srate = 0;
 +    meter = 0.f;
 +}
 +
 +void distortion_audio_module::activate()
 +{
 +    is_active = true;
 +    set_params(0.f, 0.f);
 +}
 +void distortion_audio_module::deactivate()
 +{
 +    is_active = false;
 +}
 +
 +void distortion_audio_module::set_params(float blend, float drive)
 +{
 +    // set distortion coeffs
 +    // NOTICE!! This routine is implemented for testing purposes only!
 +    // It is taken from TAP Plugins and will act as a placeholder until
 +    // Krzysztof's distrotion routine is ready!
 +    if ((drive_old != drive) || (blend_old != blend)) {
 +        rdrive = 12.0f / drive;
 +        rbdr = rdrive / (10.5f - blend) * 780.0f / 33.0f;
 +        kpa = D(2.0f * (rdrive*rdrive) - 1.0f) + 1.0f;
 +        kpb = (2.0f - kpa) / 2.0f;
 +        ap = ((rdrive*rdrive) - kpa + 1.0f) / 2.0f;
 +        kc = kpa / D(2.0f * D(2.0f * (rdrive*rdrive) - 1.0f) - 2.0f * rdrive*rdrive);
 +
 +        srct = (0.1f * srate) / (0.1f * srate + 1.0f);
 +        sq = kc*kc + 1.0f;
 +        knb = -1.0f * rbdr / D(sq);
 +        kna = 2.0f * kc * rbdr / D(sq);
 +        an = rbdr*rbdr / sq;
 +        imr = 2.0f * knb + D(2.0f * kna + 4.0f * an - 1.0f);
 +        pwrq = 2.0f / (imr + 1.0f);
 +        
 +        drive_old = drive;
 +        blend_old = blend;
 +    }
 +}
 +
 +void distortion_audio_module::set_sample_rate(uint32_t sr)
 +{
 +    srate = sr;
 +}
 +
 +float distortion_audio_module::process(float(in))
 +{
 +    // NOTICE!! This routine is implemented for testing purposes only!
 +    // It is taken from TAP Plugins and will act as a placeholder until
 +    // Krzysztof's distrotion routine is ready!
 +    meter = 0.f;
 +    float out = 0.f;
 +    float proc = in;
 +    float med;
 +    if (proc >= 0.0f) {
 +        med = (D(ap + proc * (kpa - proc)) + kpb) * pwrq;
 +    } else {
 +        med = (D(an - proc * (kna + proc)) + knb) * pwrq * -1.0f;
 +    }
 +    proc = srct * (med - prev_med + prev_out);
 +    prev_med = M(med);
 +    prev_out = M(proc);
 +    out = proc;
 +    meter = proc;
 +    return out;
 +}
 +
 +float distortion_audio_module::get_distortion_level()
 +{
 +    return meter;
 +}

-- 
calf audio plugins packaging



More information about the pkg-multimedia-commits mailing list