1 // Copyright 2014 Olivier Gillet.
2 //
3 // Author: Olivier Gillet (ol.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 //
27 // Resonestor.
28 
29 #ifndef CLOUDS_DSP_RESONESTOR_H_
30 #define CLOUDS_DSP_RESONESTOR_H_
31 
32 #include "stmlib/stmlib.h"
33 #include "stmlib/utils/random.h"
34 #include "stmlib/dsp/units.h"
35 #include "clouds/dsp/fx/fx_engine.h"
36 #include "clouds/resources.h"
37 
38 using namespace stmlib;
39 
40 namespace clouds {
41 
42 const float chords[3][18] =
43   {
44     { 0.0f, 4.0f/128.0f, 16.0f/128.0f, 4.0f/128.0f, 4.0f/128.0f,
45       12.0f, 12.0f, 4.0f, 4.0f,
46       3.0f, 3.0f, 2.0f, 4.0f,
47       3.0f, 4.0f, 3.0f, 4.0f,
48       4.0f },
49     { 0.0f, 8.0f/128.0f, 32.0f/128.0f, 7.0f, 12.0f,
50       24.0f, 7.0f, 7.0f, 7.0f,
51       7.0f, 7.0f, 7.0f, 7.0f,
52       7.0f, 7.0f, 7.0f, 7.0f,
53       7.0f },
54     { 0.0f, 12.0f/128.0f, 48.0f/128.0f, 7.0f + 4.0f/128.0f, 12.0f + 4.0f/128.0f,
55       36.0f, 19.0f, 12.0f, 11.0f,
56       10.0f, 12.0f, 12.0f, 12.0f,
57       14.0f, 14.0f, 16.0f, 16.0f,
58       16.0f }
59   };
60 
61 #define PLATEAU 2.0f
62 
InterpolatePlateau(const float * table,float index,float size)63 inline float InterpolatePlateau(const float* table, float index, float size) {
64   index *= size;
65   MAKE_INTEGRAL_FRACTIONAL(index)
66   float a = table[index_integral];
67   float b = table[index_integral + 1];
68   if (index_fractional < 1.0f/PLATEAU)
69     return a + (b - a) * index_fractional * PLATEAU;
70   else
71     return b;
72 }
73 
74 class Resonestor {
75  public:
Resonestor()76   Resonestor() { }
~Resonestor()77   ~Resonestor() { }
78 
Init(float * buffer)79   void Init(float* buffer) {
80     engine_.Init(buffer);
81     for (int v=0; v<2; v++) {
82       pitch_[v] = 0.0f;
83       chord_[v] = 0.0f;
84       feedback_[v] = 0.0f;
85       narrow_[v] = 0.001f;
86       damp_[v] = 1.0f;
87       harmonicity_[v] = 1.0f;
88       distortion_[v] = 0.0f;
89     }
90     spread_amount_ = 0.0f;
91     stereo_ = 0.0f;
92     burst_time_ = 0.0f;
93     burst_damp_ = 1.0f;
94     burst_comb_ = 1.0f;
95     burst_duration_ = 0.0f;
96     trigger_ = previous_trigger_ = 0.0f;
97     freeze_ = previous_freeze_ = 0.0f;
98     voice_ = false;
99     for (int i=0; i<3; i++)
100       spread_delay_[i] = Random::GetFloat() * 3999;
101     burst_lp_.Init();
102     rand_lp_.Init();
103     rand_hp_.Init();
104     rand_hp_.set_f<FREQUENCY_FAST>(1.0f / 48000.0f);
105     for (int v=0; v<2; v++)
106       for (int p=0; p<4; p++) {
107         lp_[p][v].Init();
108         bp_[p][v].Init();
109         hp_[p][v] = 0.0f;
110         comb_period_[p][v] = 0.0f;
111         comb_feedback_[p][v] = 0.0f;
112       }
113   }
114 
115 #define MAX_COMB 1000
116 #define BASE_PITCH 261.626f
117 
Process(FloatFrame * in_out,size_t size)118   void Process(FloatFrame* in_out, size_t size) {
119 
120     typedef E::Reserve<MAX_COMB,
121       E::Reserve<MAX_COMB,
122       E::Reserve<MAX_COMB,
123       E::Reserve<MAX_COMB,
124       E::Reserve<200,          /* bc */
125       E::Reserve<4000,          /* bd0 */
126       E::Reserve<4000,          /* bd1 */
127       E::Reserve<MAX_COMB,
128       E::Reserve<MAX_COMB,
129       E::Reserve<MAX_COMB,
130       E::Reserve<MAX_COMB > > > > > > > > > > > Memory;
131     E::DelayLine<Memory, 0> c00;
132     E::DelayLine<Memory, 1> c10;
133     E::DelayLine<Memory, 2> c20;
134     E::DelayLine<Memory, 3> c30;
135     E::DelayLine<Memory, 4> bc;
136     E::DelayLine<Memory, 5> bd0;
137     E::DelayLine<Memory, 6> bd1;
138     E::DelayLine<Memory, 7> c01;
139     E::DelayLine<Memory, 8> c11;
140     E::DelayLine<Memory, 9> c21;
141     E::DelayLine<Memory, 10> c31;
142     E::Context c;
143 
144     /* switch active voice */
145     if (trigger_ && !previous_trigger_ && !freeze_) {
146       voice_ = !voice_;
147     }
148 
149     if (freeze_ && !previous_freeze_) {
150       previous_freeze_ = freeze_;
151       voice_ = !voice_;
152     }
153 
154     /* set comb filters pitch */
155     comb_period_[0][voice_] = 48000.0f / BASE_PITCH / SemitonesToRatio(pitch_[voice_]);
156     CONSTRAIN(comb_period_[0][voice_], 0, MAX_COMB);
157     for (int p=1; p<4; p++) {
158       float pitch = InterpolatePlateau(chords[p-1], chord_[voice_], 16);
159       comb_period_[p][voice_] = comb_period_[0][voice_] / SemitonesToRatio(pitch);
160       CONSTRAIN(comb_period_[p][voice_], 0, MAX_COMB);
161     }
162 
163     /* set LP/BP filters frequencies and feedback */
164     for (int p=0; p<4; p++) {
165       float freq = 1.0f / comb_period_[p][voice_];
166       bp_[p][voice_].set_f_q<FREQUENCY_FAST>(freq, narrow_[voice_]);
167       float lp_freq = (2.0f * freq + 1.0f) * damp_[voice_];
168       CONSTRAIN(lp_freq, 0.0f, 1.0f);
169       lp_[p][voice_].set_f_q<FREQUENCY_FAST>(lp_freq, 0.4f);
170       comb_feedback_[p][voice_] = powf(feedback_[voice_], comb_period_[p][voice_] / 48000.0f);
171     }
172 
173     /* initiate burst if trigger */
174     if (trigger_ && !previous_trigger_) {
175       previous_trigger_ = trigger_;
176       burst_time_ = comb_period_[0][voice_];
177       burst_time_ *= 2.0f * burst_duration_;
178 
179       for (int i=0; i<3; i++)
180         spread_delay_[i] = Random::GetFloat() * (bd0.length - 1);
181     }
182 
183     rand_lp_.set_f_q<FREQUENCY_FAST>(distortion_[voice_] * 0.4f, 1.0f);
184 
185     while (size--) {
186       engine_.Start(&c);
187 
188       burst_time_--;
189       float burst_gain = burst_time_ > 0.0f ? 1.0f : 0.0f;
190 
191       float random = Random::GetFloat() * 2.0f - 1.0f;
192       /* burst noise generation */
193       c.Read(random, burst_gain);
194       // goes through comb and lp filters
195       const float comb_fb = 0.6f - burst_comb_ * 0.4f;
196       float comb_del = burst_comb_ * bc.length;
197       if (comb_del <= 1.0f) comb_del = 1.0f;
198       c.InterpolateHermite(bc, comb_del, comb_fb);
199       c.Write(bc, 1.0f);
200       float burst;
201       c.Write(burst);
202       c.Load(burst_lp_.Process<FILTER_MODE_LOW_PASS>(burst));
203       c.Write(burst);
204 
205       c.Load(burst);
206       c.Read(in_out->l, 1.0f);
207       c.Write(bd0, 0.0f);
208 
209       c.Load(burst);
210       c.Read(in_out->r, 1.0f);
211       c.Write(bd1, 0.0f);
212 
213       float amplitude = distortion_[voice_];
214       amplitude = 1.0f - amplitude;
215       amplitude *= 0.3f;
216       amplitude *= amplitude;
217       random *= amplitude;
218       random = rand_lp_.Process<FILTER_MODE_LOW_PASS>(random);
219       random = rand_hp_.Process<FILTER_MODE_HIGH_PASS>(random);
220 
221 #define COMB(pre, part, voice, vol)                                     \
222       {                                                                 \
223         c.Load(0.0f);                                                   \
224         c.Read(bd ## voice, pre * spread_amount_, vol);                 \
225         float tap = comb_period_[part][voice] * (1.0f + random);        \
226         c.InterpolateHermite(c ## part ## voice, tap ,                  \
227                              comb_feedback_[part][voice] * 0.7f);      \
228         c.InterpolateHermite(c ## part ## voice,                        \
229                              tap * harmonicity_[voice],                 \
230                              comb_feedback_[part][voice] * 0.3f);       \
231         float acc;                                                      \
232         c.Write(acc);                                                   \
233         acc = lp_[part][voice].Process<FILTER_MODE_LOW_PASS>(acc);      \
234         acc = bp_[part][voice].Process<FILTER_MODE_BAND_PASS_NORMALIZED>(acc); \
235         c.Load(acc);                                                    \
236         c.Hp(hp_[part][voice], 10.0f / 48000.0f);                       \
237         c.Write(acc, 0.5f);                                             \
238         c.SoftLimit();                                                  \
239         c.Write(acc, 2.0f);                                             \
240         c.Write(c ## part ## voice, 0.0f);                              \
241       }                                                                 \
242 
243       /* first voice: */
244       COMB(0, 0, 0, !voice_);
245       COMB(spread_delay_[0], 1, 0, !voice_);
246       COMB(spread_delay_[1], 2, 0, !voice_);
247       COMB(spread_delay_[2], 3, 0, !voice_);
248 
249       /* second voice: */
250       COMB(0, 0, 1, voice_);
251       COMB(spread_delay_[0], 1, 1, voice_);
252       COMB(spread_delay_[1], 2, 1, voice_);
253       COMB(spread_delay_[2], 3, 1, voice_);
254 
255       /* left mix */
256       c.Read(c00, (1.0f + 0.5f * narrow_[0]) *
257              0.25f * (1.0f - stereo_) * (1.0f - separation_));
258       c.Read(c10, (1.0f + 0.5f * narrow_[0]) *
259              (0.25f + 0.25f * stereo_) * (1.0f - separation_));
260       c.Read(c20, (1.0f + 0.5f * narrow_[0]) *
261              (0.25f * (1.0f - stereo_)) * (1.0f - separation_));
262       c.Read(c30, (1.0f + 0.5f * narrow_[0]) *
263              (0.25f + 0.25f * stereo_) * (1.0f - separation_));
264       c.Read(c01, (1.0f + 0.5f * narrow_[1]) * (0.25f + 0.25f * stereo_));
265       c.Read(c11, (1.0f + 0.5f * narrow_[1]) * 0.25f * (1.0f - stereo_));
266       c.Read(c21, (1.0f + 0.5f * narrow_[1]) * (0.25f + 0.25 * stereo_));
267       c.Read(c31, (1.0f + 0.5f * narrow_[1]) * 0.25f * (1.0f - stereo_));
268       c.Write(in_out->l, 0.0f);
269 
270       /* right mix */
271       c.Read(c00, (1.0f + 0.5f * narrow_[0]) * (0.25f + 0.25f * stereo_));
272       c.Read(c10, (1.0f + 0.5f * narrow_[0]) * 0.25f * (1.0f - stereo_));
273       c.Read(c20, (1.0f + 0.5f * narrow_[0]) * (0.25f + 0.25f * stereo_));
274       c.Read(c30, (1.0f + 0.5f * narrow_[0]) * 0.25f * (1.0f - stereo_));
275       c.Read(c01, (1.0f + 0.5f * narrow_[1]) *
276              0.25f * (1.0f - stereo_) * (1.0f - separation_));
277       c.Read(c11, (1.0f + 0.5f * narrow_[1]) *
278              (0.25f + 0.25f * stereo_) * (1.0f - separation_));
279       c.Read(c21, (1.0f + 0.5f * narrow_[1]) *
280              0.25f * (1.0f - stereo_) * (1.0f - separation_));
281       c.Read(c31, (1.0f + 0.5f * narrow_[1]) *
282              (0.25f + 0.25f * stereo_) * (1.0f - separation_));
283       c.Write(in_out->r, 0.0f);
284 
285       ++in_out;
286     }
287   }
288 
set_pitch(float pitch)289   void set_pitch(float pitch) {
290     pitch_[voice_] = pitch;
291   }
292 
set_chord(float chord)293   void set_chord(float chord) {
294     chord_[voice_] = chord;
295   }
296 
set_feedback(float feedback)297   void set_feedback(float feedback) {
298     feedback_[voice_] = feedback;
299   }
300 
set_narrow(float narrow)301   void set_narrow(float narrow) {
302     narrow_[voice_] = narrow;
303   }
304 
set_damp(float damp)305   void set_damp(float damp) {
306     damp_[voice_] = damp;
307   }
308 
set_distortion(float distortion)309   void set_distortion(float distortion) {
310     distortion *= distortion * distortion;
311     distortion_[voice_] = distortion;
312   }
313 
set_trigger(bool trigger)314   void set_trigger(bool trigger) {
315     previous_trigger_ = trigger_;
316     trigger_ = trigger;
317   }
318 
set_burst_damp(float burst_damp)319   void set_burst_damp(float burst_damp) {
320     burst_lp_.set_f_q<FREQUENCY_FAST>(burst_damp * burst_damp * 0.5f, 0.8f);
321   }
322 
set_burst_comb(float burst_comb)323   void set_burst_comb(float burst_comb) {
324     burst_comb_ = burst_comb;
325   }
326 
set_burst_duration(float burst_duration)327   void set_burst_duration(float burst_duration) {
328     burst_duration_ = burst_duration;
329   }
330 
set_spread_amount(float spread_amount)331   void set_spread_amount(float spread_amount) {
332     spread_amount_ = spread_amount;
333   }
334 
set_stereo(float stereo)335   void set_stereo(float stereo) {
336     stereo_ = stereo;
337   }
338 
set_separation(float separation)339   void set_separation(float separation) {
340     separation_ = separation;
341   }
342 
set_freeze(float freeze)343   void set_freeze(float freeze) {
344     previous_freeze_ = freeze_;
345     freeze_ = freeze;
346   }
347 
set_harmonicity(float harmonicity)348   void set_harmonicity(float harmonicity) {
349     harmonicity_[voice_] = harmonicity;
350   }
351 
352  private:
353   typedef FxEngine<16384, FORMAT_32_BIT> E;
354   E engine_;
355 
356   /* parameters: */
357   float feedback_[2];
358   float pitch_[2];
359   float chord_[2];
360   float narrow_[2];
361   float damp_[2];
362   float harmonicity_[2];
363   float distortion_[2];
364   float spread_amount_;
365   float stereo_;
366   float separation_;
367   float burst_time_;
368   float burst_damp_;
369   float burst_comb_;
370   float burst_duration_;
371   int16_t trigger_, previous_trigger_;
372   int16_t freeze_, previous_freeze_;
373 
374   /* internal states: */
375   float spread_delay_[3];
376   float comb_period_[4][2];
377   float comb_feedback_[4][2];
378 
379   float hp_[4][2];
380   Svf lp_[4][2];
381   Svf bp_[4][2];
382   Svf burst_lp_;
383   Svf rand_lp_;
384   OnePole rand_hp_;
385 
386   int32_t voice_, __align1;
387 
388 
389   DISALLOW_COPY_AND_ASSIGN(Resonestor);
390 };
391 
392 }  // namespace clouds
393 
394 #endif  // CLOUDS_DSP_RESONESTOR_H_
395