1 // Copyright 2014 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 // Modal synthesis voice.
28
29 #include "elements/dsp/voice.h"
30
31 #include "stmlib/dsp/dsp.h"
32 #include "stmlib/dsp/units.h"
33
34 #include <algorithm>
35
36 namespace elements {
37
38 using namespace std;
39 using namespace stmlib;
40
Init()41 void Voice::Init() {
42 envelope_.Init();
43 bow_.Init();
44 blow_.Init();
45 strike_.Init();
46 diffuser_.Init(diffuser_buffer_);
47
48 ResetResonator();
49
50 bow_.set_model(EXCITER_MODEL_FLOW);
51 bow_.set_parameter(0.7f);
52 bow_.set_timbre(0.5f);
53
54 blow_.set_model(EXCITER_MODEL_GRANULAR_SAMPLE_PLAYER);
55
56 envelope_.set_adsr(0.5f, 0.5f, 0.5f, 0.5f);
57
58 previous_gate_ = false;
59 strength_ = 0.0f;
60 exciter_level_ = 0.0f;
61 envelope_value_ = 0.0f;
62 chord_index_ = 0.0f;
63
64 resonator_model_ = RESONATOR_MODEL_MODAL;
65 }
66
ResetResonator()67 void Voice::ResetResonator() {
68 resonator_.Init();
69 for (size_t i = 0; i < kNumStrings; ++i) {
70 string_[i].Init(true);
71 }
72 dc_blocker_.Init(1.0f - 10.0f / kSampleRate);
73 resonator_.set_resolution(52); // Runs with 56 extremely tightly.
74 }
75
76 float chords[11][5] = {
77 { 0.0f, -12.0f, 0.0f, 0.01f, 12.0f },
78 { 0.0f, -12.0f, 3.0f, 7.0f, 10.0f },
79 { 0.0f, -12.0f, 3.0f, 7.0f, 12.0f },
80 { 0.0f, -12.0f, 3.0f, 7.0f, 14.0f },
81 { 0.0f, -12.0f, 3.0f, 7.0f, 17.0f },
82 { 0.0f, -12.0f, 7.0f, 12.0f, 19.0f },
83 { 0.0f, -12.0f, 4.0f, 7.0f, 17.0f },
84 { 0.0f, -12.0f, 4.0f, 7.0f, 14.0f },
85 { 0.0f, -12.0f, 4.0f, 7.0f, 12.0f },
86 { 0.0f, -12.0f, 4.0f, 7.0f, 11.0f },
87 { 0.0f, -12.0f, 5.0f, 7.0f, 12.0f },
88 };
89
Process(const Patch & patch,float frequency,float strength,const bool gate_in,const float * blow_in,const float * strike_in,float * raw,float * center,float * sides,size_t size)90 void Voice::Process(
91 const Patch& patch,
92 float frequency,
93 float strength,
94 const bool gate_in,
95 const float* blow_in,
96 const float* strike_in,
97 float* raw,
98 float* center,
99 float* sides,
100 size_t size) {
101 uint8_t flags = GetGateFlags(gate_in);
102
103 // Compute the envelope.
104 float envelope_gain = 1.0f;
105 if (patch.exciter_envelope_shape < 0.4f) {
106 float a = patch.exciter_envelope_shape * 0.75f + 0.15f;
107 float dr = a * 1.8f;
108 envelope_.set_adsr(a, dr, 0.0f, dr);
109 envelope_gain = 5.0f - patch.exciter_envelope_shape * 10.0f;
110 } else if (patch.exciter_envelope_shape < 0.6f) {
111 float s = (patch.exciter_envelope_shape - 0.4f) * 5.0f;
112 envelope_.set_adsr(0.45f, 0.81f, s, 0.81f);
113 } else {
114 float a = (1.0f - patch.exciter_envelope_shape) * 0.75f + 0.15f;
115 float dr = a * 1.8f;
116 envelope_.set_adsr(a, dr, 1.0f, dr);
117 }
118 float envelope_value = envelope_.Process(flags) * envelope_gain;
119 float envelope_increment = (envelope_value - envelope_value_) / size;
120
121 // Configure and evaluate exciters.
122 float brightness_factor = 0.4f + 0.6f * patch.resonator_brightness;
123 bow_.set_timbre(patch.exciter_bow_timbre * brightness_factor);
124
125 blow_.set_parameter(patch.exciter_blow_meta);
126 blow_.set_timbre(patch.exciter_blow_timbre);
127 blow_.set_signature(patch.exciter_signature);
128
129 float strike_meta = patch.exciter_strike_meta;
130 strike_.set_meta(
131 strike_meta <= 0.4f ? strike_meta * 0.625f : strike_meta * 1.25f - 0.25f,
132 EXCITER_MODEL_SAMPLE_PLAYER,
133 EXCITER_MODEL_PARTICLES);
134 strike_.set_timbre(patch.exciter_strike_timbre);
135 strike_.set_signature(patch.exciter_signature);
136
137 bow_.Process(flags, bow_buffer_, size);
138
139 float blow_level, tube_level;
140 blow_level = patch.exciter_blow_level * 1.5f;
141 tube_level = blow_level > 1.0f ? (blow_level - 1.0f) * 2.0f : 0.0f;
142 blow_level = blow_level < 1.0f ? blow_level * 0.4f : 0.4f;
143 blow_.Process(flags, blow_buffer_, size);
144 tube_.Process(
145 frequency,
146 envelope_value,
147 patch.resonator_damping,
148 tube_level,
149 blow_buffer_,
150 tube_level * 0.5f,
151 size);
152
153 for (size_t i = 0; i < size; ++i) {
154 blow_buffer_[i] = blow_buffer_[i] * blow_level + blow_in[i];
155 }
156 diffuser_.Process(blow_buffer_, size);
157 strike_.Process(flags, strike_buffer_, size);
158
159 // The Strike exciter is implemented in such a way that raising the level
160 // beyond a certain point doesn't change the exciter amplitude, but instead,
161 // increasingly mixes the raw exciter signal into the resonator output.
162 float strike_level, strike_bleed;
163 strike_level = patch.exciter_strike_level * 1.25f;
164 strike_bleed = strike_level > 1.0f ? (strike_level - 1.0f) * 2.0f : 0.0f;
165 strike_level = strike_level < 1.0f ? strike_level : 1.0f;
166 strike_level *= 1.5f;
167
168 // The strength parameter is very sensitive to zipper noise.
169 strength *= 256.0f;
170 float strength_increment = (strength - strength_) / size;
171
172 // Sum all sources of excitation.
173 for (size_t i = 0; i < size; ++i) {
174 strength_ += strength_increment;
175 envelope_value_ += envelope_increment;
176 float input_sample = 0.0f;
177 float e = envelope_value_;
178 float strength_lut = strength_;
179 MAKE_INTEGRAL_FRACTIONAL(strength_lut);
180 float accent = lut_accent_gain_coarse[strength_lut_integral] *
181 lut_accent_gain_fine[
182 static_cast<int32_t>(256.0f * strength_lut_fractional)];
183 bow_strength_buffer_[i] = e * patch.exciter_bow_level;
184
185 strike_buffer_[i] *= accent;
186 e *= accent;
187
188 input_sample += bow_buffer_[i] * bow_strength_buffer_[i] * 0.125f * accent;
189 input_sample += blow_buffer_[i] * e;
190 input_sample += strike_buffer_[i] * strike_level;
191 input_sample += strike_in[i];
192 raw[i] = input_sample * 0.5f;
193 }
194
195 // Update meter for exciter.
196 for (size_t i = 0; i < size; ++i) {
197 float error = raw[i] * raw[i] - exciter_level_;
198 exciter_level_ += error * (error > 0.0f ? 0.5f : 0.001f);
199 }
200
201 // Some exciters can cause palm mutes on release.
202 float damping = patch.resonator_damping;
203 damping -= strike_.damping() * strike_level * 0.125f;
204 damping -= (1.0f - bow_strength_buffer_[0]) * \
205 patch.exciter_bow_level * 0.0625f;
206
207 if (damping <= 0.0f) {
208 damping = 0.0f;
209 }
210
211 // Configure resonator.
212 if (resonator_model_ == RESONATOR_MODEL_MODAL) {
213 resonator_.set_frequency(frequency);
214 resonator_.set_geometry(patch.resonator_geometry);
215 resonator_.set_brightness(patch.resonator_brightness);
216 resonator_.set_position(patch.resonator_position);
217 resonator_.set_damping(damping);
218 resonator_.set_modulation_frequency(patch.resonator_modulation_frequency);
219 resonator_.set_modulation_offset(patch.resonator_modulation_offset);
220
221 // Process through resonator.
222 resonator_.Process(bow_strength_buffer_, raw, center, sides, size);
223 } else {
224 size_t num_notes = resonator_model_ == RESONATOR_MODEL_STRING
225 ? 1
226 : kNumStrings;
227
228 float normalization = 1.0f / static_cast<float>(num_notes);
229 dc_blocker_.Process(raw, size);
230 for (size_t i = 0; i < size; ++i) {
231 raw[i] *= normalization;
232 }
233
234 float chord = patch.resonator_geometry * 10.0f;
235 float hysteresis = chord > chord_index_ ? -0.1f : 0.1f;
236 int chord_index = static_cast<int>(chord + hysteresis + 0.5f);
237 CONSTRAIN(chord_index, 0, 10);
238 chord_index_ = static_cast<float>(chord_index);
239
240 fill(¢er[0], ¢er[size], 0.0f);
241 fill(&sides[0], &sides[size], 0.0f);
242 for (size_t i = 0; i < num_notes; ++i) {
243 float transpose = chords[chord_index][i];
244 string_[i].set_frequency(frequency * SemitonesToRatio(transpose));
245 string_[i].set_brightness(patch.resonator_brightness);
246 string_[i].set_position(patch.resonator_position);
247 string_[i].set_damping(damping);
248 if (num_notes == 1) {
249 string_[i].set_dispersion(patch.resonator_geometry);
250 } else {
251 float b = patch.resonator_brightness;
252 string_[i].set_dispersion(b < 0.5f ? 0.0f : (b - 0.5f) * -0.4f);
253 }
254 string_[i].Process(raw, center, sides, size);
255 }
256 for (size_t i = 0; i < size; ++i) {
257 float left = center[i];
258 float right = sides[i];
259 center[i] = left - right;
260 sides[i] = left + right;
261 }
262 }
263
264 // This is where the raw mallet signal bleeds through the exciter output.
265 for (size_t i = 0; i < size; ++i) {
266 center[i] += strike_bleed * strike_buffer_[i];
267 }
268 }
269
270 } // namespace elements
271