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