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 // Modulator.
28 
29 #ifndef WARPS_DSP_MODULATOR_H_
30 #define WARPS_DSP_MODULATOR_H_
31 
32 #include "stmlib/stmlib.h"
33 #include "stmlib/dsp/dsp.h"
34 #include "stmlib/dsp/filter.h"
35 #include "stmlib/dsp/parameter_interpolator.h"
36 
37 #include "warps/dsp/oscillator.h"
38 #include "warps/dsp/parameters.h"
39 #include "warps/dsp/quadrature_oscillator.h"
40 #include "warps/dsp/quadrature_transform.h"
41 #include "warps/dsp/sample_rate_converter.h"
42 #include "warps/dsp/vocoder.h"
43 #include "warps/resources.h"
44 
45 namespace warps {
46 
47 const size_t kMaxBlockSize = 96;
48 const size_t kOversampling = 6;
49 const size_t kLessOversampling = 4;
50 const size_t kNumOscillators = 1;
51 
52 typedef struct { short l; short r; } ShortFrame;
53 typedef struct { float l; float r; } FloatFrame;
54 
55 class SaturatingAmplifier {
56  public:
SaturatingAmplifier()57   SaturatingAmplifier() { }
~SaturatingAmplifier()58   ~SaturatingAmplifier() { }
Init()59   void Init() {
60     drive_ = 0.0f;
61   }
62 
Process(float drive,float limit,short * in,float * out,float * out_raw,size_t in_stride,size_t size)63   void Process(
64       float drive,
65       float limit,
66       short* in,
67       float* out,
68       float* out_raw,
69       size_t in_stride,
70       size_t size) {
71     // Process noise gate and compute raw output
72     stmlib::ParameterInterpolator drive_modulation(&drive_, drive, size);
73     float level = level_;
74     for (size_t i = 0; i < size; ++i) {
75       float s = static_cast<float>(*in) / 32768.0f;
76       float error = s * s - level;
77       level += error * (error > 0.0f ? 0.1f: 0.0001f);
78       s *= level <= 0.0001f ? (1.0f / 0.0001f) * level : 1.0f;
79       out[i] = s;
80       out_raw[i] += s * drive_modulation.Next();
81       in += in_stride;
82     }
83     level_ = level;
84 
85     // Process overdrive / gain
86     float drive_2 = drive * drive;
87     float pre_gain_a = drive * 0.5f;
88     float pre_gain_b = drive_2 * drive_2 * drive * 24.0f;
89     float pre_gain = pre_gain_a + (pre_gain_b - pre_gain_a) * drive_2;
90     float drive_squished = drive * (2.0f - drive);
91     float post_gain = 1.0f / stmlib::SoftClip(
92           0.33f + drive_squished * (pre_gain - 0.33f));
93     stmlib::ParameterInterpolator pre_gain_modulation(
94         &pre_gain_,
95         pre_gain,
96         size);
97     stmlib::ParameterInterpolator post_gain_modulation(
98         &post_gain_,
99         post_gain,
100         size);
101 
102     for (size_t i = 0; i < size; ++i) {
103       float pre = pre_gain_modulation.Next() * out[i];
104       float post = stmlib::SoftClip(pre) * post_gain_modulation.Next();
105       out[i] = pre + (post - pre) * limit;
106     }
107   }
108 
109  private:
110   float level_;
111   float drive_;
112   float post_gain_;
113   float pre_gain_;
114   float unclipped_gain_;
115 
116   DISALLOW_COPY_AND_ASSIGN(SaturatingAmplifier);
117 };
118 
119 enum XmodAlgorithm {
120   ALGORITHM_XFADE,
121   ALGORITHM_FOLD,
122   ALGORITHM_ANALOG_RING_MODULATION,
123   ALGORITHM_DIGITAL_RING_MODULATION,
124   ALGORITHM_RING_MODULATION,
125   ALGORITHM_XOR,
126   ALGORITHM_COMPARATOR,
127   ALGORITHM_COMPARATOR8,
128   ALGORITHM_CHEBYSCHEV,
129   ALGORITHM_COMPARATOR_CHEBYSCHEV,
130   ALGORITHM_BITCRUSHER,
131   ALGORITHM_NOP,
132   ALGORITHM_LAST
133 };
134 
135 class Modulator {
136  public:
137   typedef void (Modulator::*XmodFn)(
138       float balance,
139       float balance_end,
140       float parameter,
141       float parameter_end,
142       const float* in_1,
143       const float* in_2,
144       float* out,
145       size_t size);
146 
Modulator()147   Modulator() { }
~Modulator()148   ~Modulator() { }
149 
150   void Init(float sample_rate);
151   void Process(ShortFrame* input, ShortFrame* output, size_t size);
152   template<XmodAlgorithm algorithm>
153   void Process1(ShortFrame* input, ShortFrame* output, size_t size);
154   void ProcessFreqShifter(ShortFrame* input, ShortFrame* output, size_t size);
155   void ProcessVocoder(ShortFrame* input, ShortFrame* output, size_t size);
156   void ProcessBitcrusher(ShortFrame* input, ShortFrame* output, size_t size);
157   void ProcessDelay(ShortFrame* input, ShortFrame* output, size_t size);
158   void ProcessDoppler(ShortFrame* input, ShortFrame* output, size_t size);
159   void ProcessMeta(ShortFrame* input, ShortFrame* output, size_t size);
mutable_parameters()160   inline Parameters* mutable_parameters() { return &parameters_; }
parameters()161   inline const Parameters& parameters() { return parameters_; }
162 
bypass()163   inline bool bypass() const { return bypass_; }
set_bypass(bool bypass)164   inline void set_bypass(bool bypass) { bypass_ = bypass; }
165 
feature_mode()166   inline FeatureMode feature_mode() const { return feature_mode_; }
set_feature_mode(FeatureMode feature_mode)167   inline void set_feature_mode(FeatureMode feature_mode) { feature_mode_ = feature_mode; }
168 
169  private:
170   template<XmodAlgorithm algorithm_1, XmodAlgorithm algorithm_2>
ProcessXmod(float balance,float balance_end,float parameter,float parameter_end,const float * in_1,const float * in_2,float * out,size_t size)171   void ProcessXmod(
172       float balance,
173       float balance_end,
174       float parameter,
175       float parameter_end,
176       const float* in_1,
177       const float* in_2,
178       float* out,
179       size_t size) {
180     float step = 1.0f / static_cast<float>(size);
181     float parameter_increment = (parameter_end - parameter) * step;
182     float balance_increment = (balance_end - balance) * step;
183     while (size) {
184       {
185         const float x_1 = *in_1++;
186         const float x_2 = *in_2++;
187         float a = Xmod<algorithm_1>(x_1, x_2, parameter);
188         float b = Xmod<algorithm_2>(x_1, x_2, parameter);
189         *out++ = a + (b - a) * balance;
190         parameter += parameter_increment;
191         balance += balance_increment;
192         size--;
193       }
194       {
195         const float x_1 = *in_1++;
196         const float x_2 = *in_2++;
197         float a = Xmod<algorithm_1>(x_1, x_2, parameter);
198         float b = Xmod<algorithm_2>(x_1, x_2, parameter);
199         *out++ = a + (b - a) * balance;
200         parameter += parameter_increment;
201         balance += balance_increment;
202         size--;
203       }
204       {
205         const float x_1 = *in_1++;
206         const float x_2 = *in_2++;
207         float a = Xmod<algorithm_1>(x_1, x_2, parameter);
208         float b = Xmod<algorithm_2>(x_1, x_2, parameter);
209         *out++ = a + (b - a) * balance;
210         parameter += parameter_increment;
211         balance += balance_increment;
212         size--;
213       }
214     }
215   }
216 
217   template<XmodAlgorithm algorithm>
ProcessXmod(float p_1,float p_1_end,float p_2,float p_2_end,const float * in_1,const float * in_2,float * out,size_t size)218   void ProcessXmod(
219       float p_1,
220       float p_1_end,
221       float p_2,
222       float p_2_end,
223       const float* in_1,
224       const float* in_2,
225       float* out,
226       size_t size) {
227     float step = 1.0f / static_cast<float>(size);
228     float p_1_increment = (p_1_end - p_1) * step;
229     float p_2_increment = (p_2_end - p_2) * step;
230     while (size) {
231       const float x_1 = *in_1++;
232       const float x_2 = *in_2++;
233       *out++ = Xmod<algorithm>(x_1, x_2, p_1, p_2);
234       p_1 += p_1_increment;
235       p_2 += p_2_increment;
236       size--;
237     }
238   }
239 
240   template<XmodAlgorithm algorithm>
ProcessXmod(float p_1,float p_1_end,float p_2,float p_2_end,const float * in_1,const float * in_2,float * out_1,float * out_2,size_t size)241   void ProcessXmod(
242       float p_1,
243       float p_1_end,
244       float p_2,
245       float p_2_end,
246       const float* in_1,
247       const float* in_2,
248       float* out_1,
249       float* out_2,
250       size_t size) {
251     float step = 1.0f / static_cast<float>(size);
252     float p_1_increment = (p_1_end - p_1) * step;
253     float p_2_increment = (p_2_end - p_2) * step;
254     while (size) {
255       const float x_1 = *in_1++;
256       const float x_2 = *in_2++;
257       *out_1++ = Xmod<algorithm>(x_1, x_2, p_1, p_2, out_2++); /* TODO error */
258       p_1 += p_1_increment;
259       p_2 += p_2_increment;
260       size--;
261     }
262   }
263 
264   template<XmodAlgorithm algorithm>
265   static float Xmod(float x_1, float x_2, float parameter);
266 
267   template<XmodAlgorithm algorithm>
268   static float Xmod(float x_1, float x_2, float p_1, float p_2);
269 
270   template<XmodAlgorithm algorithm>
271   static float Xmod(float x_1, float x_2, float p_1, float p_2, float *out_2);
272 
273   template<XmodAlgorithm algorithm>
ProcessMod(float p,float p_end,const float * in,float * out,size_t size)274   void ProcessMod(
275       float p,
276       float p_end,
277       const float* in,
278       float* out,
279       size_t size) {
280     float step = 1.0f / static_cast<float>(size);
281     float p_increment = (p_end - p) * step;
282     while (size) {
283       const float x = *in++;
284       *out++ = Mod<algorithm>(x, p);
285       p += p_increment;
286       size--;
287     }
288   }
289 
290   template<XmodAlgorithm algorithm>
291   static float Mod(float x, float p);
292 
293   static float Diode(float x);
294 
295   bool bypass_;
296 
297   FeatureMode feature_mode_;
298 
299   Parameters parameters_;
300   Parameters previous_parameters_;
301 
302   SaturatingAmplifier amplifier_[2];
303 
304   Oscillator xmod_oscillator_;
305   Oscillator vocoder_oscillator_;
306   QuadratureOscillator quadrature_oscillator_;
307   SampleRateConverter<SRC_UP, kOversampling, 48> src_up_[2];
308   SampleRateConverter<SRC_DOWN, kOversampling, 48> src_down_;
309   SampleRateConverter<SRC_UP, kLessOversampling, 48> src_up2_[2];
310   SampleRateConverter<SRC_DOWN, kLessOversampling, 48> src_down2_[2];
311   Vocoder vocoder_;
312   QuadratureTransform quadrature_transform_[2];
313 
314   stmlib::OnePole filter_[4];
315 
316   /* everything that follows will be used as delay buffer */
317   ShortFrame delay_buffer_[8192+4096];
318   float internal_modulation_[kMaxBlockSize];
319   float buffer_[3][kMaxBlockSize];
320   float src_buffer_[2][kMaxBlockSize * kOversampling];
321   float feedback_sample_;
322 
323   enum DelaySize {
324     DELAY_SIZE = (sizeof(delay_buffer_)
325                   + sizeof(internal_modulation_)
326                   + sizeof(buffer_)
327                   + sizeof(src_buffer_)
328                   + sizeof(feedback_sample_)) / sizeof(ShortFrame) - 4
329   };
330 
331   enum DelayInterpolation {
332     INTERPOLATION_ZOH,
333     INTERPOLATION_LINEAR,
334     INTERPOLATION_HERMITE,
335   };
336 
337   DelayInterpolation delay_interpolation_;
338 
339   static XmodFn xmod_table_[];
340 
341   DISALLOW_COPY_AND_ASSIGN(Modulator);
342 };
343 
344 }  // namespace warps
345 
346 #endif  // WARPS_DSP_MODULATOR_H_
347