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 // Modal synthesis voice.
28
29 #include "elements/dsp/voice.h"
30
31 #include "stmlib/dsp/dsp.h"
32
33 #include <algorithm>
34
35 namespace elements {
36
37 using namespace std;
38 using namespace stmlib;
39
Init()40 void Voice::Init() {
41 envelope_.Init();
42 bow_.Init();
43 blow_.Init();
44 strike_.Init();
45 diffuser_.Init(diffuser_buffer_);
46
47 ResetResonator();
48
49 bow_.set_model(EXCITER_MODEL_FLOW);
50 bow_.set_parameter(0.7f);
51 bow_.set_timbre(0.5f);
52
53 blow_.set_model(EXCITER_MODEL_GRANULAR_SAMPLE_PLAYER);
54
55 envelope_.set_adsr(0.5f, 0.5f, 0.5f, 0.5f);
56
57 previous_gate_ = false;
58 strength_ = 0.0f;
59 exciter_level_ = 0.0f;
60 envelope_value_ = 0.0f;
61 }
62
ResetResonator()63 void Voice::ResetResonator() {
64 resonator_.Init();
65 resonator_.set_resolution(52); // Runs with 56 extremely tightly.
66 }
67
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)68 void Voice::Process(
69 const Patch& patch,
70 float frequency,
71 float strength,
72 const bool gate_in,
73 const float* blow_in,
74 const float* strike_in,
75 float* raw,
76 float* center,
77 float* sides,
78 size_t size) {
79 uint8_t flags = GetGateFlags(gate_in);
80
81 // Compute the envelope.
82 float envelope_gain = 1.0f;
83 if (patch.exciter_envelope_shape < 0.4f) {
84 float a = patch.exciter_envelope_shape * 0.75f + 0.15f;
85 float dr = a * 1.8f;
86 envelope_.set_adsr(a, dr, 0.0f, dr);
87 envelope_gain = 5.0f - patch.exciter_envelope_shape * 10.0f;
88 } else if (patch.exciter_envelope_shape < 0.6f) {
89 float s = (patch.exciter_envelope_shape - 0.4f) * 5.0f;
90 envelope_.set_adsr(0.45f, 0.81f, s, 0.81f);
91 } else {
92 float a = (1.0f - patch.exciter_envelope_shape) * 0.75f + 0.15f;
93 float dr = a * 1.8f;
94 envelope_.set_adsr(a, dr, 1.0f, dr);
95 }
96 float envelope_value = envelope_.Process(flags) * envelope_gain;
97 float envelope_increment = (envelope_value - envelope_value_) / size;
98
99 // Configure and evaluate exciters.
100 float brightness_factor = 0.4f + 0.6f * patch.resonator_brightness;
101 bow_.set_timbre(patch.exciter_bow_timbre * brightness_factor);
102
103 blow_.set_parameter(patch.exciter_blow_meta);
104 blow_.set_timbre(patch.exciter_blow_timbre);
105 blow_.set_signature(patch.exciter_signature);
106
107 float strike_meta = patch.exciter_strike_meta;
108 strike_.set_meta(
109 strike_meta <= 0.4f ? strike_meta * 0.625f : strike_meta * 1.25f - 0.25f,
110 EXCITER_MODEL_SAMPLE_PLAYER,
111 EXCITER_MODEL_PARTICLES);
112 strike_.set_timbre(patch.exciter_strike_timbre);
113 strike_.set_signature(patch.exciter_signature);
114
115 bow_.Process(flags, bow_buffer_, size);
116
117 float blow_level, tube_level;
118 blow_level = patch.exciter_blow_level * 1.5f;
119 tube_level = blow_level > 1.0f ? (blow_level - 1.0f) * 2.0f : 0.0f;
120 blow_level = blow_level < 1.0f ? blow_level * 0.4f : 0.4f;
121 blow_.Process(flags, blow_buffer_, size);
122 tube_.Process(
123 frequency,
124 envelope_value,
125 patch.resonator_damping,
126 tube_level,
127 blow_buffer_,
128 tube_level * 0.5f,
129 size);
130
131 for (size_t i = 0; i < size; ++i) {
132 blow_buffer_[i] = blow_buffer_[i] * blow_level + blow_in[i];
133 }
134 diffuser_.Process(blow_buffer_, size);
135 strike_.Process(flags, strike_buffer_, size);
136
137 // The Strike exciter is implemented in such a way that raising the level
138 // beyond a certain point doesn't change the exciter amplitude, but instead,
139 // increasingly mixes the raw exciter signal into the resonator output.
140 float strike_level, strike_bleed;
141 strike_level = patch.exciter_strike_level * 1.25f;
142 strike_bleed = strike_level > 1.0f ? (strike_level - 1.0f) * 2.0f : 0.0f;
143 strike_level = strike_level < 1.0f ? strike_level : 1.0f;
144 strike_level *= 1.5f;
145
146 // The strength parameter is very sensitive to zipper noise.
147 strength *= 256.0f;
148 float strength_increment = (strength - strength_) / size;
149
150 // Sum all sources of excitation.
151 for (size_t i = 0; i < size; ++i) {
152 strength_ += strength_increment;
153 envelope_value_ += envelope_increment;
154 float input_sample = 0.0f;
155 float e = envelope_value_;
156 float strength_lut = strength_;
157 MAKE_INTEGRAL_FRACTIONAL(strength_lut);
158 float accent = lut_accent_gain_coarse[strength_lut_integral] *
159 lut_accent_gain_fine[
160 static_cast<int32_t>(256.0f * strength_lut_fractional)];
161 bow_strength_buffer_[i] = e * patch.exciter_bow_level;
162
163 strike_buffer_[i] *= accent;
164 e *= accent;
165
166 input_sample += bow_buffer_[i] * bow_strength_buffer_[i] * 0.125f * accent;
167 input_sample += blow_buffer_[i] * e;
168 input_sample += strike_buffer_[i] * strike_level;
169 input_sample += strike_in[i];
170 raw[i] = input_sample * 0.5f;
171 }
172
173 // Update meter for exciter.
174 for (size_t i = 0; i < size; ++i) {
175 float error = raw[i] * raw[i] - exciter_level_;
176 exciter_level_ += error * (error > 0.0f ? 0.5f : 0.001f);
177 }
178
179 // Some exciters can cause palm mutes on release.
180 float damping = patch.resonator_damping;
181 damping -= strike_.damping() * strike_level * 0.125f;
182 damping -= (1.0f - bow_strength_buffer_[0]) * \
183 patch.exciter_bow_level * 0.0625f;
184
185 if (damping <= 0.0f) {
186 damping = 0.0f;
187 }
188
189 // Configure resonator.
190 resonator_.set_frequency(frequency);
191 resonator_.set_geometry(patch.resonator_geometry);
192 resonator_.set_brightness(patch.resonator_brightness);
193 resonator_.set_position(patch.resonator_position);
194 resonator_.set_damping(damping);
195 resonator_.set_modulation_frequency(patch.resonator_modulation_frequency);
196 resonator_.set_modulation_offset(patch.resonator_modulation_offset);
197
198 // Process through resonator.
199 resonator_.Process(bow_strength_buffer_, raw, center, sides, size);
200
201 // This is where the raw mallet signal bleeds through the exciter output.
202 for (size_t i = 0; i < size; ++i) {
203 center[i] += strike_bleed * strike_buffer_[i];
204 }
205 }
206
207 } // namespace elements
208