davbassfilter.cc 4.27 KB
Newer Older
Tim Janik's avatar
Tim Janik committed
1
// Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
2
#include "davbassfilter.genidl.hh"
Tim Janik's avatar
Tim Janik committed
3

4
namespace Bse {
Tim Janik's avatar
Tim Janik committed
5
6
7
8
namespace Dav {

class BassFilter : public BassFilterBase {
  class Module : public SynthesisModule {
9
10
11
12
    /* proeprties */
    double filt_cutoff, filt_reso, env_mod, env_decay;
    /* satte */
    double decay, resonance;
Tim Janik's avatar
Tim Janik committed
13
14
    double a, b, c0;
    double d1, d2;
Tim Janik's avatar
Tim Janik committed
15
    double e0, e1;
16
    float last_trigger;
Tim Janik's avatar
Tim Janik committed
17
18
    gint envbound; /* 64 at 44100 */
    gint envpos;
19
20
    inline void
    recalc_resonance ()
21
    {
22
23
      /* Update resonance. */
      resonance = exp (-1.20 + 3.455 * filt_reso);
Tim Janik's avatar
Tim Janik committed
24
    }
25
26
    inline void
    recalc_filter ()
Tim Janik's avatar
Tim Janik committed
27
28
29
    {
      /* Update vars given envmod, cutoff, and reso. */
      e0 = exp (5.613 - 0.8 * env_mod + 2.1553 * filt_cutoff - 0.7696 * (1.0 - filt_reso));
Tim Janik's avatar
Tim Janik committed
30
      e1 = exp (6.109 + 1.5876 * env_mod + 2.1553 * filt_cutoff - 1.2 * (1.0 - filt_reso));
Tim Janik's avatar
Tim Janik committed
31
32
33
      e0 *= PI / mix_freq();
      e1 *= PI / mix_freq();
      e1 -= e0;
34
35
36
37
    }
    inline void
    recalc_decay ()
    {
Tim Janik's avatar
Tim Janik committed
38
39
40
41
42
43
44
      /* Update decay given envdecay. */
      envbound = dtoi (0.001452 * mix_freq()); // 64 at 44100;
      envbound = MAX (envbound, 1);
      double d = env_decay;
      d = 0.2 + (2.3 * d);
      d *= mix_freq();
      decay = pow (0.1, envbound / d);
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
    }
    inline void
    recalc_a_b ()
    {
      double whopping = e0 + c0;
      double k = exp (-whopping / resonance);
      a = 2.0 * cos (2.0 * whopping) * k;
      b = -k * k;
    }
  public:
    void
    reset ()
    {
      last_trigger = 0;
      c0 = 0;
      d1 = d2 = 0;
      envpos = 0;
    }
    void
    config (BassFilterProperties *props)
    {
      filt_cutoff = props->cutoff_perc * 0.01;
      filt_reso = props->reso_perc * 0.01;
      env_mod = props->env_mod * 0.01;
      env_decay = props->env_decay * 0.01;
Tim Janik's avatar
Tim Janik committed
70

71
72
73
74
      recalc_resonance();
      recalc_filter();
      recalc_decay();
      recalc_a_b();
Tim Janik's avatar
Tim Janik committed
75

76
      if (props->trigger)
Tim Janik's avatar
Tim Janik committed
77
78
79
80
81
        {
          /* Reset filter delta freq. */
          c0 = e1;
          envpos = 0;
        }
82
    }
Tim Janik's avatar
Tim Janik committed
83
    void
84
85
    auto_update (BassFilterPropertyID prop_id,
                 double               value)
86
    {
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
      switch (prop_id)
        {
        case PROP_CUTOFF_PERC:
          filt_cutoff = value * 0.01;
          recalc_filter();
          recalc_a_b();
          break;
        case PROP_RESO_PERC:
          filt_reso = value * 0.01;
          recalc_resonance();
          recalc_filter();
          recalc_a_b();
          break;
        case PROP_ENV_MOD:
          env_mod = value * 0.01;
          recalc_filter();
          recalc_a_b();
          break;
        case PROP_ENV_DECAY:
          env_decay = value * 0.01;
          recalc_decay();
          break;
        default: ;
        }
    }
    void
    process (unsigned int n_values)
    {   /* this function runs in various synthesis threads */
Tim Janik's avatar
Tim Janik committed
115
      const float *in = istream (ICHANNEL_AUDIO_IN).values;
Tim Janik's avatar
Tim Janik committed
116
      const float *trigger = istream (ICHANNEL_TRIGGER_IN).values;
Tim Janik's avatar
Tim Janik committed
117
118
      float *out = ostream (OCHANNEL_AUDIO_OUT).values;
      float *bound = out + n_values;
Tim Janik's avatar
Tim Janik committed
119
120
121
122
      if (istream (ICHANNEL_TRIGGER_IN).connected)
        while (out < bound)
          {
            gfloat current_trigger = *trigger++;
Tim Janik's avatar
Tim Janik committed
123
            if (G_UNLIKELY (last_trigger < current_trigger))
Tim Janik's avatar
Tim Janik committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
              {
                c0 = e1;
                envpos = 0;
              }
            last_trigger = current_trigger;
            double c = (1.0 - a - b) * 0.2;
            double v = a * d1 + b * d2 + c * *in++;
            d2 = d1;
            d1 = v;
            *out++ = v;
            if (++envpos >= envbound)
              {
                envpos = 0;
                c0 *= decay;
                recalc_a_b ();
              }
          }
      else
        while (out < bound)
          {
            double c = (1.0 - a - b) * 0.2;
            double v = a * d1 + b * d2 + c * *in++;
            d2 = d1;
            d1 = v;
            *out++ = v;
            if (++envpos >= envbound)
              {
                envpos = 0;
                c0 *= decay;
                recalc_a_b ();
              }
          }
156
    }
Tim Janik's avatar
Tim Janik committed
157
158
159
160
161
  };
public:
  /* implement creation and config methods for synthesis Module */
  BSE_EFFECT_INTEGRATE_MODULE (BassFilter, Module, BassFilterProperties);
};
162

Tim Janik's avatar
Tim Janik committed
163
164
BSE_CXX_DEFINE_EXPORTS();
BSE_CXX_REGISTER_EFFECT (BassFilter);
165

Tim Janik's avatar
Tim Janik committed
166
} // Dav
167
} // Bse