1 // Copyright 2015 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 // String. 28 29 #ifndef ELEMENTS_DSP_STRING_H_ 30 #define ELEMENTS_DSP_STRING_H_ 31 32 #include "stmlib/stmlib.h" 33 34 #include <algorithm> 35 36 #include "stmlib/dsp/delay_line.h" 37 #include "stmlib/dsp/filter.h" 38 39 namespace elements { 40 41 const size_t kDelayLineSize = 2048; 42 43 class DampingFilter { 44 public: DampingFilter()45 DampingFilter() { } ~DampingFilter()46 ~DampingFilter() { } 47 Init()48 void Init() { 49 x_ = 0.0f; 50 x__ = 0.0f; 51 brightness_ = 0.0f; 52 brightness_increment_ = 0.0f; 53 damping_ = 0.0f; 54 damping_increment_ = 0.0f; 55 } 56 Configure(float damping,float brightness,size_t size)57 inline void Configure(float damping, float brightness, size_t size) { 58 if (!size) { 59 damping_ = damping; 60 brightness_ = brightness; 61 damping_increment_ = 0.0f; 62 brightness_increment_ = 0.0f; 63 } else { 64 float step = 1.0f / static_cast<float>(size); 65 damping_increment_ = (damping - damping_) * step; 66 brightness_increment_ = (brightness - brightness_) * step; 67 } 68 } 69 Process(float x)70 inline float Process(float x) { 71 float h0 = (1.0f + brightness_) * 0.5f; 72 float h1 = (1.0f - brightness_) * 0.25f; 73 float y = damping_ * (h0 * x_ + h1 * (x + x__)); 74 x__ = x_; 75 x_ = x; 76 brightness_ += brightness_increment_; 77 damping_ += damping_increment_; 78 return y; 79 } 80 private: 81 float x_; 82 float x__; 83 float brightness_; 84 float brightness_increment_; 85 float damping_; 86 float damping_increment_; 87 88 DISALLOW_COPY_AND_ASSIGN(DampingFilter); 89 }; 90 91 typedef stmlib::DelayLine<float, kDelayLineSize> StringDelayLine; 92 typedef stmlib::DelayLine<float, kDelayLineSize / 2> StiffnessDelayLine; 93 94 class String { 95 public: String()96 String() { } ~String()97 ~String() { } 98 99 void Init(bool enable_dispersion); 100 void Process(const float* in, float* out, float* aux, size_t size); 101 set_frequency(float frequency)102 inline void set_frequency(float frequency) { 103 frequency_ = frequency; 104 } 105 set_frequency(float frequency,float coefficient)106 inline void set_frequency(float frequency, float coefficient) { 107 frequency_ += coefficient * (frequency - frequency_); 108 } 109 set_dispersion(float dispersion)110 inline void set_dispersion(float dispersion) { 111 dispersion = dispersion < 0.24f 112 ? (dispersion - 0.24f) * 4.166f 113 : (dispersion > 0.26f ? (dispersion - 0.26f) * 1.35135f : 0.0f); 114 dispersion_ = dispersion; 115 } 116 set_brightness(float brightness)117 inline void set_brightness(float brightness) { 118 brightness_ = brightness; 119 } 120 set_damping(float damping)121 inline void set_damping(float damping) { 122 damping_ = damping; 123 } 124 set_position(float position)125 inline void set_position(float position) { 126 position_ = position; 127 } 128 mutable_string()129 inline StringDelayLine* mutable_string() { return &string_; } 130 131 private: 132 template<bool enable_dispersion> 133 void ProcessInternal(const float* in, float* out, float* aux, size_t size); 134 135 float frequency_; 136 float dispersion_; 137 float brightness_; 138 float damping_; 139 float position_; 140 141 float delay_; 142 float clamped_position_; 143 float previous_dispersion_; 144 float previous_damping_compensation_; 145 146 bool enable_dispersion_; 147 bool enable_iir_damping_; 148 float dispersion_noise_; 149 150 // Very crappy linear interpolation upsampler used for low pitches that 151 // do not fit the delay line. Rarely used. 152 float src_phase_; 153 float out_sample_[2]; 154 float aux_sample_[2]; 155 156 float curved_bridge_; 157 158 StringDelayLine string_; 159 StiffnessDelayLine stretch_; 160 161 DampingFilter fir_damping_filter_; 162 stmlib::Svf iir_damping_filter_; 163 stmlib::DCBlocker dc_blocker_; 164 165 DISALLOW_COPY_AND_ASSIGN(String); 166 }; 167 168 } // namespace elements 169 170 #endif // ELEMENTS_DSP_STRING_H_ 171