1 // Copyright 2016 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.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 // Integrated wavetable synthesis.
28 
29 #ifndef PLAITS_DSP_OSCILLATOR_WAVETABLE_OSCILLATOR_H_
30 #define PLAITS_DSP_OSCILLATOR_WAVETABLE_OSCILLATOR_H_
31 
32 #include <algorithm>
33 
34 #include "stmlib/dsp/dsp.h"
35 #include "stmlib/dsp/parameter_interpolator.h"
36 
37 #include "plaits/dsp/oscillator/oscillator.h"
38 
39 namespace plaits {
40 
41 class Differentiator {
42  public:
Differentiator()43   Differentiator() { }
~Differentiator()44   ~Differentiator() { }
45 
Init()46   void Init() {
47     previous_ = 0.0f;
48     lp_ = 0.0f;
49   }
50 
Process(float coefficient,float s)51   float Process(float coefficient, float s) {
52     ONE_POLE(lp_, s - previous_, coefficient);
53     previous_ = s;
54     return lp_;
55   }
56  private:
57   float lp_;
58   float previous_;
59 
60   DISALLOW_COPY_AND_ASSIGN(Differentiator);
61 };
62 
InterpolateWave(const int16_t * table,int32_t index_integral,float index_fractional)63 inline float InterpolateWave(
64     const int16_t* table,
65     int32_t index_integral,
66     float index_fractional) {
67   float a = static_cast<float>(table[index_integral]);
68   float b = static_cast<float>(table[index_integral + 1]);
69   float t = index_fractional;
70   return a + (b - a) * t;
71 }
72 
InterpolateWaveHermite(const int16_t * table,int32_t index_integral,float index_fractional)73 inline float InterpolateWaveHermite(
74     const int16_t* table,
75     int32_t index_integral,
76     float index_fractional) {
77   const float xm1 = table[index_integral];
78   const float x0 = table[index_integral + 1];
79   const float x1 = table[index_integral + 2];
80   const float x2 = table[index_integral + 3];
81   const float c = (x1 - xm1) * 0.5f;
82   const float v = x0 - x1;
83   const float w = c + v;
84   const float a = w + v + (x2 - x0) * 0.5f;
85   const float b_neg = w + a;
86   const float f = index_fractional;
87   return (((a * f) - b_neg) * f + c) * f + x0;
88 }
89 
90 template<
91     size_t wavetable_size,
92     size_t num_waves,
93     bool approximate_scale=true>
94 class WavetableOscillator {
95  public:
WavetableOscillator()96   WavetableOscillator() { }
~WavetableOscillator()97   ~WavetableOscillator() { }
98 
Init()99   void Init() {
100     phase_ = 0.0f;
101     frequency_ = 0.0f;
102     amplitude_ = 0.0f;
103     waveform_ = 0.0f;
104     lp_ = 0.0f;
105     differentiator_.Init();
106   }
107 
Render(float frequency,float amplitude,float waveform,const int16_t ** wavetable,float * out,size_t size)108   void Render(
109       float frequency,
110       float amplitude,
111       float waveform,
112       const int16_t** wavetable,
113       float* out,
114       size_t size) {
115     if (frequency >= kMaxFrequency) {
116       frequency = kMaxFrequency;
117     }
118     amplitude *= 1.0f - 2.0f * frequency;
119     if (approximate_scale) {
120       amplitude *= 1.0f / (frequency * 131072.0f) * (0.95f - frequency);
121     }
122 
123     stmlib::ParameterInterpolator frequency_modulation(
124         &frequency_,
125         frequency,
126         size);
127     stmlib::ParameterInterpolator amplitude_modulation(
128         &amplitude_,
129         amplitude,
130         size);
131     stmlib::ParameterInterpolator waveform_modulation(
132         &waveform_,
133         waveform * float(num_waves - 1.0001f),
134         size);
135 
136     float lp = lp_;
137     float phase = phase_;
138     while (size--) {
139       const float f0 = frequency_modulation.Next();
140       const float cutoff = std::min(float(wavetable_size) * f0, 1.0f);
141 
142       const float scale = approximate_scale ? 1.0f : 1.0f / (f0 * 131072.0f) * (0.95f - f0);
143 
144       phase += f0;
145       if (phase >= 1.0f) {
146         phase -= 1.0f;
147       }
148 
149       const float waveform = waveform_modulation.Next();
150       MAKE_INTEGRAL_FRACTIONAL(waveform);
151 
152       const float p = phase * float(wavetable_size);
153       MAKE_INTEGRAL_FRACTIONAL(p);
154 
155       const float x0 = InterpolateWave(
156           wavetable[waveform_integral], p_integral, p_fractional);
157       const float x1 = InterpolateWave(
158           wavetable[waveform_integral + 1], p_integral, p_fractional);
159 
160       const float s = differentiator_.Process(
161           cutoff,
162           x0 + (x1 - x0) * waveform_fractional);
163       ONE_POLE(lp, s * scale, cutoff * 0.5f);
164       *out++ += amplitude_modulation.Next() * lp;
165     }
166     lp_ = lp;
167     phase_ = phase;
168   }
169 
170  private:
171   // Oscillator state.
172   float phase_;
173 
174   // For interpolation of parameters.
175   float frequency_;
176   float amplitude_;
177   float waveform_;
178   float lp_;
179 
180   Differentiator differentiator_;
181 
182   DISALLOW_COPY_AND_ASSIGN(WavetableOscillator);
183 };
184 
185 }  // namespace plaits
186 
187 #endif  // PLAITS_DSP_OSCILLATOR_WAVETABLE_OSCILLATOR_H_
188