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 &litude_,
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