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