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 // Modulator. 28 29 #ifndef WARPS_DSP_MODULATOR_H_ 30 #define WARPS_DSP_MODULATOR_H_ 31 32 #include "stmlib/stmlib.h" 33 #include "stmlib/dsp/dsp.h" 34 #include "stmlib/dsp/filter.h" 35 #include "stmlib/dsp/parameter_interpolator.h" 36 37 #include "warps/dsp/oscillator.h" 38 #include "warps/dsp/parameters.h" 39 #include "warps/dsp/quadrature_oscillator.h" 40 #include "warps/dsp/quadrature_transform.h" 41 #include "warps/dsp/sample_rate_converter.h" 42 #include "warps/dsp/vocoder.h" 43 #include "warps/resources.h" 44 45 namespace warps { 46 47 const size_t kMaxBlockSize = 96; 48 const size_t kOversampling = 6; 49 const size_t kLessOversampling = 4; 50 const size_t kNumOscillators = 1; 51 52 typedef struct { short l; short r; } ShortFrame; 53 typedef struct { float l; float r; } FloatFrame; 54 55 class SaturatingAmplifier { 56 public: SaturatingAmplifier()57 SaturatingAmplifier() { } ~SaturatingAmplifier()58 ~SaturatingAmplifier() { } Init()59 void Init() { 60 drive_ = 0.0f; 61 } 62 Process(float drive,float limit,short * in,float * out,float * out_raw,size_t in_stride,size_t size)63 void Process( 64 float drive, 65 float limit, 66 short* in, 67 float* out, 68 float* out_raw, 69 size_t in_stride, 70 size_t size) { 71 // Process noise gate and compute raw output 72 stmlib::ParameterInterpolator drive_modulation(&drive_, drive, size); 73 float level = level_; 74 for (size_t i = 0; i < size; ++i) { 75 float s = static_cast<float>(*in) / 32768.0f; 76 float error = s * s - level; 77 level += error * (error > 0.0f ? 0.1f: 0.0001f); 78 s *= level <= 0.0001f ? (1.0f / 0.0001f) * level : 1.0f; 79 out[i] = s; 80 out_raw[i] += s * drive_modulation.Next(); 81 in += in_stride; 82 } 83 level_ = level; 84 85 // Process overdrive / gain 86 float drive_2 = drive * drive; 87 float pre_gain_a = drive * 0.5f; 88 float pre_gain_b = drive_2 * drive_2 * drive * 24.0f; 89 float pre_gain = pre_gain_a + (pre_gain_b - pre_gain_a) * drive_2; 90 float drive_squished = drive * (2.0f - drive); 91 float post_gain = 1.0f / stmlib::SoftClip( 92 0.33f + drive_squished * (pre_gain - 0.33f)); 93 stmlib::ParameterInterpolator pre_gain_modulation( 94 &pre_gain_, 95 pre_gain, 96 size); 97 stmlib::ParameterInterpolator post_gain_modulation( 98 &post_gain_, 99 post_gain, 100 size); 101 102 for (size_t i = 0; i < size; ++i) { 103 float pre = pre_gain_modulation.Next() * out[i]; 104 float post = stmlib::SoftClip(pre) * post_gain_modulation.Next(); 105 out[i] = pre + (post - pre) * limit; 106 } 107 } 108 109 private: 110 float level_; 111 float drive_; 112 float post_gain_; 113 float pre_gain_; 114 float unclipped_gain_; 115 116 DISALLOW_COPY_AND_ASSIGN(SaturatingAmplifier); 117 }; 118 119 enum XmodAlgorithm { 120 ALGORITHM_XFADE, 121 ALGORITHM_FOLD, 122 ALGORITHM_ANALOG_RING_MODULATION, 123 ALGORITHM_DIGITAL_RING_MODULATION, 124 ALGORITHM_RING_MODULATION, 125 ALGORITHM_XOR, 126 ALGORITHM_COMPARATOR, 127 ALGORITHM_COMPARATOR8, 128 ALGORITHM_CHEBYSCHEV, 129 ALGORITHM_COMPARATOR_CHEBYSCHEV, 130 ALGORITHM_BITCRUSHER, 131 ALGORITHM_NOP, 132 ALGORITHM_LAST 133 }; 134 135 class Modulator { 136 public: 137 typedef void (Modulator::*XmodFn)( 138 float balance, 139 float balance_end, 140 float parameter, 141 float parameter_end, 142 const float* in_1, 143 const float* in_2, 144 float* out, 145 size_t size); 146 Modulator()147 Modulator() { } ~Modulator()148 ~Modulator() { } 149 150 void Init(float sample_rate); 151 void Process(ShortFrame* input, ShortFrame* output, size_t size); 152 template<XmodAlgorithm algorithm> 153 void Process1(ShortFrame* input, ShortFrame* output, size_t size); 154 void ProcessFreqShifter(ShortFrame* input, ShortFrame* output, size_t size); 155 void ProcessVocoder(ShortFrame* input, ShortFrame* output, size_t size); 156 void ProcessBitcrusher(ShortFrame* input, ShortFrame* output, size_t size); 157 void ProcessDelay(ShortFrame* input, ShortFrame* output, size_t size); 158 void ProcessDoppler(ShortFrame* input, ShortFrame* output, size_t size); 159 void ProcessMeta(ShortFrame* input, ShortFrame* output, size_t size); mutable_parameters()160 inline Parameters* mutable_parameters() { return ¶meters_; } parameters()161 inline const Parameters& parameters() { return parameters_; } 162 bypass()163 inline bool bypass() const { return bypass_; } set_bypass(bool bypass)164 inline void set_bypass(bool bypass) { bypass_ = bypass; } 165 feature_mode()166 inline FeatureMode feature_mode() const { return feature_mode_; } set_feature_mode(FeatureMode feature_mode)167 inline void set_feature_mode(FeatureMode feature_mode) { feature_mode_ = feature_mode; } 168 169 private: 170 template<XmodAlgorithm algorithm_1, XmodAlgorithm algorithm_2> ProcessXmod(float balance,float balance_end,float parameter,float parameter_end,const float * in_1,const float * in_2,float * out,size_t size)171 void ProcessXmod( 172 float balance, 173 float balance_end, 174 float parameter, 175 float parameter_end, 176 const float* in_1, 177 const float* in_2, 178 float* out, 179 size_t size) { 180 float step = 1.0f / static_cast<float>(size); 181 float parameter_increment = (parameter_end - parameter) * step; 182 float balance_increment = (balance_end - balance) * step; 183 while (size) { 184 { 185 const float x_1 = *in_1++; 186 const float x_2 = *in_2++; 187 float a = Xmod<algorithm_1>(x_1, x_2, parameter); 188 float b = Xmod<algorithm_2>(x_1, x_2, parameter); 189 *out++ = a + (b - a) * balance; 190 parameter += parameter_increment; 191 balance += balance_increment; 192 size--; 193 } 194 { 195 const float x_1 = *in_1++; 196 const float x_2 = *in_2++; 197 float a = Xmod<algorithm_1>(x_1, x_2, parameter); 198 float b = Xmod<algorithm_2>(x_1, x_2, parameter); 199 *out++ = a + (b - a) * balance; 200 parameter += parameter_increment; 201 balance += balance_increment; 202 size--; 203 } 204 { 205 const float x_1 = *in_1++; 206 const float x_2 = *in_2++; 207 float a = Xmod<algorithm_1>(x_1, x_2, parameter); 208 float b = Xmod<algorithm_2>(x_1, x_2, parameter); 209 *out++ = a + (b - a) * balance; 210 parameter += parameter_increment; 211 balance += balance_increment; 212 size--; 213 } 214 } 215 } 216 217 template<XmodAlgorithm algorithm> ProcessXmod(float p_1,float p_1_end,float p_2,float p_2_end,const float * in_1,const float * in_2,float * out,size_t size)218 void ProcessXmod( 219 float p_1, 220 float p_1_end, 221 float p_2, 222 float p_2_end, 223 const float* in_1, 224 const float* in_2, 225 float* out, 226 size_t size) { 227 float step = 1.0f / static_cast<float>(size); 228 float p_1_increment = (p_1_end - p_1) * step; 229 float p_2_increment = (p_2_end - p_2) * step; 230 while (size) { 231 const float x_1 = *in_1++; 232 const float x_2 = *in_2++; 233 *out++ = Xmod<algorithm>(x_1, x_2, p_1, p_2); 234 p_1 += p_1_increment; 235 p_2 += p_2_increment; 236 size--; 237 } 238 } 239 240 template<XmodAlgorithm algorithm> ProcessXmod(float p_1,float p_1_end,float p_2,float p_2_end,const float * in_1,const float * in_2,float * out_1,float * out_2,size_t size)241 void ProcessXmod( 242 float p_1, 243 float p_1_end, 244 float p_2, 245 float p_2_end, 246 const float* in_1, 247 const float* in_2, 248 float* out_1, 249 float* out_2, 250 size_t size) { 251 float step = 1.0f / static_cast<float>(size); 252 float p_1_increment = (p_1_end - p_1) * step; 253 float p_2_increment = (p_2_end - p_2) * step; 254 while (size) { 255 const float x_1 = *in_1++; 256 const float x_2 = *in_2++; 257 *out_1++ = Xmod<algorithm>(x_1, x_2, p_1, p_2, out_2++); /* TODO error */ 258 p_1 += p_1_increment; 259 p_2 += p_2_increment; 260 size--; 261 } 262 } 263 264 template<XmodAlgorithm algorithm> 265 static float Xmod(float x_1, float x_2, float parameter); 266 267 template<XmodAlgorithm algorithm> 268 static float Xmod(float x_1, float x_2, float p_1, float p_2); 269 270 template<XmodAlgorithm algorithm> 271 static float Xmod(float x_1, float x_2, float p_1, float p_2, float *out_2); 272 273 template<XmodAlgorithm algorithm> ProcessMod(float p,float p_end,const float * in,float * out,size_t size)274 void ProcessMod( 275 float p, 276 float p_end, 277 const float* in, 278 float* out, 279 size_t size) { 280 float step = 1.0f / static_cast<float>(size); 281 float p_increment = (p_end - p) * step; 282 while (size) { 283 const float x = *in++; 284 *out++ = Mod<algorithm>(x, p); 285 p += p_increment; 286 size--; 287 } 288 } 289 290 template<XmodAlgorithm algorithm> 291 static float Mod(float x, float p); 292 293 static float Diode(float x); 294 295 bool bypass_; 296 297 FeatureMode feature_mode_; 298 299 Parameters parameters_; 300 Parameters previous_parameters_; 301 302 SaturatingAmplifier amplifier_[2]; 303 304 Oscillator xmod_oscillator_; 305 Oscillator vocoder_oscillator_; 306 QuadratureOscillator quadrature_oscillator_; 307 SampleRateConverter<SRC_UP, kOversampling, 48> src_up_[2]; 308 SampleRateConverter<SRC_DOWN, kOversampling, 48> src_down_; 309 SampleRateConverter<SRC_UP, kLessOversampling, 48> src_up2_[2]; 310 SampleRateConverter<SRC_DOWN, kLessOversampling, 48> src_down2_[2]; 311 Vocoder vocoder_; 312 QuadratureTransform quadrature_transform_[2]; 313 314 stmlib::OnePole filter_[4]; 315 316 /* everything that follows will be used as delay buffer */ 317 ShortFrame delay_buffer_[8192+4096]; 318 float internal_modulation_[kMaxBlockSize]; 319 float buffer_[3][kMaxBlockSize]; 320 float src_buffer_[2][kMaxBlockSize * kOversampling]; 321 float feedback_sample_; 322 323 enum DelaySize { 324 DELAY_SIZE = (sizeof(delay_buffer_) 325 + sizeof(internal_modulation_) 326 + sizeof(buffer_) 327 + sizeof(src_buffer_) 328 + sizeof(feedback_sample_)) / sizeof(ShortFrame) - 4 329 }; 330 331 enum DelayInterpolation { 332 INTERPOLATION_ZOH, 333 INTERPOLATION_LINEAR, 334 INTERPOLATION_HERMITE, 335 }; 336 337 DelayInterpolation delay_interpolation_; 338 339 static XmodFn xmod_table_[]; 340 341 DISALLOW_COPY_AND_ASSIGN(Modulator); 342 }; 343 344 } // namespace warps 345 346 #endif // WARPS_DSP_MODULATOR_H_ 347