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