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 // Main synthesis voice. 28 29 #ifndef PLAITS_DSP_VOICE_H_ 30 #define PLAITS_DSP_VOICE_H_ 31 32 #include "stmlib/stmlib.h" 33 34 #include "stmlib/dsp/filter.h" 35 #include "stmlib/dsp/limiter.h" 36 #include "stmlib/utils/buffer_allocator.h" 37 38 #include "plaits/dsp/engine/additive_engine.h" 39 #include "plaits/dsp/engine/bass_drum_engine.h" 40 #include "plaits/dsp/engine/chord_engine.h" 41 #include "plaits/dsp/engine/engine.h" 42 #include "plaits/dsp/engine/fm_engine.h" 43 #include "plaits/dsp/engine/grain_engine.h" 44 #include "plaits/dsp/engine/hi_hat_engine.h" 45 #include "plaits/dsp/engine/modal_engine.h" 46 #include "plaits/dsp/engine/noise_engine.h" 47 #include "plaits/dsp/engine/particle_engine.h" 48 #include "plaits/dsp/engine/snare_drum_engine.h" 49 #include "plaits/dsp/engine/speech_engine.h" 50 #include "plaits/dsp/engine/string_engine.h" 51 #include "plaits/dsp/engine/swarm_engine.h" 52 #include "plaits/dsp/engine/virtual_analog_engine.h" 53 #include "plaits/dsp/engine/waveshaping_engine.h" 54 #include "plaits/dsp/engine/wavetable_engine.h" 55 56 #include "plaits/dsp/envelope.h" 57 58 #include "plaits/dsp/fx/low_pass_gate.h" 59 60 namespace plaits { 61 62 const int kMaxEngines = 16; 63 const int kMaxTriggerDelay = 8; 64 const int kTriggerDelay = 5; 65 66 class ChannelPostProcessor { 67 public: ChannelPostProcessor()68 ChannelPostProcessor() { } ~ChannelPostProcessor()69 ~ChannelPostProcessor() { } 70 Init()71 void Init() { 72 lpg_.Init(); 73 Reset(); 74 } 75 Reset()76 void Reset() { 77 limiter_.Init(); 78 } 79 Process(float gain,bool bypass_lpg,float low_pass_gate_gain,float low_pass_gate_frequency,float low_pass_gate_hf_bleed,float * in,short * out,size_t size,size_t stride)80 void Process( 81 float gain, 82 bool bypass_lpg, 83 float low_pass_gate_gain, 84 float low_pass_gate_frequency, 85 float low_pass_gate_hf_bleed, 86 float* in, 87 short* out, 88 size_t size, 89 size_t stride) { 90 if (gain < 0.0f) { 91 limiter_.Process(-gain, in, size); 92 } 93 const float post_gain = (gain < 0.0f ? 1.0f : gain) * -32767.0f; 94 if (!bypass_lpg) { 95 lpg_.Process( 96 post_gain * low_pass_gate_gain, 97 low_pass_gate_frequency, 98 low_pass_gate_hf_bleed, 99 in, 100 out, 101 size, 102 stride); 103 } else { 104 while (size--) { 105 *out = stmlib::Clip16(1 + static_cast<int32_t>(*in++ * post_gain)); 106 out += stride; 107 } 108 } 109 } 110 111 private: 112 stmlib::Limiter limiter_; 113 LowPassGate lpg_; 114 115 DISALLOW_COPY_AND_ASSIGN(ChannelPostProcessor); 116 }; 117 118 struct Patch { 119 float note; 120 float harmonics; 121 float timbre; 122 float morph; 123 float frequency_modulation_amount; 124 float timbre_modulation_amount; 125 float morph_modulation_amount; 126 127 int engine; 128 float decay; 129 float lpg_colour; 130 }; 131 132 struct Modulations { 133 float engine; 134 float note; 135 float frequency; 136 float harmonics; 137 float timbre; 138 float morph; 139 float trigger; 140 float level; 141 142 bool frequency_patched; 143 bool timbre_patched; 144 bool morph_patched; 145 bool trigger_patched; 146 bool level_patched; 147 }; 148 149 class Voice { 150 public: Voice()151 Voice() { } ~Voice()152 ~Voice() { } 153 154 struct Frame { 155 short out; 156 short aux; 157 }; 158 159 void Init(stmlib::BufferAllocator* allocator); 160 void Render( 161 const Patch& patch, 162 const Modulations& modulations, 163 Frame* frames, 164 size_t size); active_engine()165 inline int active_engine() const { return previous_engine_index_; } 166 167 private: 168 void ComputeDecayParameters(const Patch& settings); 169 ApplyModulations(float base_value,float modulation_amount,bool use_external_modulation,float external_modulation,bool use_internal_envelope,float envelope,float default_internal_modulation,float minimum_value,float maximum_value)170 inline float ApplyModulations( 171 float base_value, 172 float modulation_amount, 173 bool use_external_modulation, 174 float external_modulation, 175 bool use_internal_envelope, 176 float envelope, 177 float default_internal_modulation, 178 float minimum_value, 179 float maximum_value) { 180 float value = base_value; 181 modulation_amount *= std::max(fabsf(modulation_amount) - 0.05f, 0.05f); 182 modulation_amount *= 1.05f; 183 184 float modulation = use_external_modulation 185 ? external_modulation 186 : (use_internal_envelope ? envelope : default_internal_modulation); 187 value += modulation_amount * modulation; 188 CONSTRAIN(value, minimum_value, maximum_value); 189 return value; 190 } 191 192 AdditiveEngine additive_engine_; 193 BassDrumEngine bass_drum_engine_; 194 ChordEngine chord_engine_; 195 FMEngine fm_engine_; 196 GrainEngine grain_engine_; 197 HiHatEngine hi_hat_engine_; 198 ModalEngine modal_engine_; 199 NoiseEngine noise_engine_; 200 ParticleEngine particle_engine_; 201 SnareDrumEngine snare_drum_engine_; 202 SpeechEngine speech_engine_; 203 StringEngine string_engine_; 204 SwarmEngine swarm_engine_; 205 VirtualAnalogEngine virtual_analog_engine_; 206 WaveshapingEngine waveshaping_engine_; 207 WavetableEngine wavetable_engine_; 208 209 stmlib::HysteresisQuantizer engine_quantizer_; 210 211 int previous_engine_index_; 212 float engine_cv_; 213 214 float previous_note_; 215 bool trigger_state_; 216 217 DecayEnvelope decay_envelope_; 218 LPGEnvelope lpg_envelope_; 219 220 float trigger_delay_line_[kMaxTriggerDelay]; 221 DelayLine<float, kMaxTriggerDelay> trigger_delay_; 222 223 ChannelPostProcessor out_post_processor_; 224 ChannelPostProcessor aux_post_processor_; 225 226 EngineRegistry<kMaxEngines> engines_; 227 228 float out_buffer_[kMaxBlockSize]; 229 float aux_buffer_[kMaxBlockSize]; 230 231 DISALLOW_COPY_AND_ASSIGN(Voice); 232 }; 233 234 } // namespace plaits 235 236 #endif // PLAITS_DSP_VOICE_H_ 237