You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
7.4KB

  1. // Copyright 2015 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. // Resonator.
  28. #include "elements/dsp/string.h"
  29. #include <cmath>
  30. #include "stmlib/dsp/dsp.h"
  31. #include "stmlib/dsp/parameter_interpolator.h"
  32. #include "stmlib/dsp/units.h"
  33. #include "stmlib/utils/random.h"
  34. #include "elements/dsp/dsp.h"
  35. #include "elements/resources.h"
  36. namespace elements {
  37. using namespace std;
  38. using namespace stmlib;
  39. void String::Init(bool enable_dispersion) {
  40. enable_dispersion_ = enable_dispersion;
  41. string_.Init();
  42. stretch_.Init();
  43. fir_damping_filter_.Init();
  44. iir_damping_filter_.Init();
  45. set_frequency(220.0f / kSampleRate);
  46. set_dispersion(0.25f);
  47. set_brightness(0.5f);
  48. set_damping(0.3f);
  49. set_position(0.8f);
  50. delay_ = 1.0f / frequency_;
  51. clamped_position_ = 0.0f;
  52. previous_dispersion_ = 0.0f;
  53. dispersion_noise_ = 0.0f;
  54. curved_bridge_ = 0.0f;
  55. previous_damping_compensation_ = 0.0f;
  56. out_sample_[0] = out_sample_[1] = 0.0f;
  57. aux_sample_[0] = aux_sample_[1] = 0.0f;
  58. dc_blocker_.Init(1.0f - 20.0f / kSampleRate);
  59. }
  60. template<bool enable_dispersion>
  61. void String::ProcessInternal(
  62. const float* in,
  63. float* out,
  64. float* aux,
  65. size_t size) {
  66. float delay = 1.0f / frequency_;
  67. CONSTRAIN(delay, 4.0f, kDelayLineSize - 4.0f);
  68. // If there is not enough delay time in the delay line, we play at the
  69. // lowest possible note and we upsample on the fly with a shitty linear
  70. // interpolator. We don't care because it's a corner case (f0 < 11.7Hz)
  71. float src_ratio = delay * frequency_;
  72. if (src_ratio >= 0.9999f) {
  73. // When we are above 11.7 Hz, we make sure that the linear interpolator
  74. // does not get in the way.
  75. src_phase_ = 1.0f;
  76. src_ratio = 1.0f;
  77. }
  78. float clamped_position = 0.5f - 0.98f * fabs(position_ - 0.5f);
  79. // Linearly interpolate all comb-related CV parameters for each sample.
  80. ParameterInterpolator delay_modulation(
  81. &delay_, delay, size);
  82. ParameterInterpolator position_modulation(
  83. &clamped_position_, clamped_position, size);
  84. ParameterInterpolator dispersion_modulation(
  85. &previous_dispersion_, dispersion_, size);
  86. // For damping/absorption, the interpolation is done in the filter code.
  87. float lf_damping = damping_ * (2.0f - damping_);
  88. float rt60 = 0.07f * SemitonesToRatio(lf_damping * 96.0f) * kSampleRate;
  89. float rt60_base_2_12 = max(-120.0f * delay / src_ratio / rt60, -127.0f);
  90. float damping_coefficient = SemitonesToRatio(rt60_base_2_12);
  91. float brightness = brightness_ * brightness_;
  92. float noise_filter = SemitonesToRatio((brightness_ - 1.0f) * 48.0f);
  93. float damping_cutoff = min(
  94. 24.0f + damping_ * damping_ * 48.0f + brightness_ * brightness_ * 24.0f,
  95. 84.0f);
  96. float damping_f = min(frequency_ * SemitonesToRatio(damping_cutoff), 0.499f);
  97. // Crossfade to infinite decay.
  98. if (damping_ >= 0.95f) {
  99. float to_infinite = 20.0f * (damping_ - 0.95f);
  100. damping_coefficient += to_infinite * (1.0f - damping_coefficient);
  101. brightness += to_infinite * (1.0f - brightness);
  102. damping_f += to_infinite * (0.4999f - damping_f);
  103. damping_cutoff += to_infinite * (128.0f - damping_cutoff);
  104. }
  105. fir_damping_filter_.Configure(damping_coefficient, brightness, size);
  106. iir_damping_filter_.set_f_q<FREQUENCY_ACCURATE>(damping_f, 0.5f);
  107. ParameterInterpolator damping_compensation_modulation(
  108. &previous_damping_compensation_,
  109. 1.0f - Interpolate(lut_svf_shift, damping_cutoff, 1.0f),
  110. size);
  111. while (size--) {
  112. src_phase_ += src_ratio;
  113. if (src_phase_ > 1.0f) {
  114. src_phase_ -= 1.0f;
  115. float delay = delay_modulation.Next();
  116. float comb_delay = delay * position_modulation.Next();
  117. #ifndef MIC_W
  118. delay *= damping_compensation_modulation.Next(); // IIR delay.
  119. #endif // MIC_W
  120. delay -= 1.0f; // FIR delay.
  121. float s = 0.0f;
  122. if (enable_dispersion) {
  123. float noise = 2.0f * Random::GetFloat() - 1.0f;
  124. noise *= 1.0f / (0.2f + noise_filter);
  125. dispersion_noise_ += noise_filter * (noise - dispersion_noise_);
  126. float dispersion = dispersion_modulation.Next();
  127. float stretch_point = dispersion <= 0.0f
  128. ? 0.0f
  129. : dispersion * (2.0f - dispersion) * 0.475f;
  130. float noise_amount = dispersion > 0.75f
  131. ? 4.0f * (dispersion - 0.75f)
  132. : 0.0f;
  133. float bridge_curving = dispersion < 0.0f
  134. ? -dispersion
  135. : 0.0f;
  136. noise_amount = noise_amount * noise_amount * 0.025f;
  137. float ac_blocking_amount = bridge_curving;
  138. bridge_curving = bridge_curving * bridge_curving * 0.01f;
  139. float ap_gain = -0.618f * dispersion / (0.15f + fabs(dispersion));
  140. float delay_fm = 1.0f;
  141. delay_fm += dispersion_noise_ * noise_amount;
  142. delay_fm -= curved_bridge_ * bridge_curving;
  143. delay *= delay_fm;
  144. float ap_delay = delay * stretch_point;
  145. float main_delay = delay - ap_delay;
  146. if (ap_delay >= 4.0f && main_delay >= 4.0f) {
  147. s = string_.ReadHermite(main_delay);
  148. s = stretch_.Allpass(s, ap_delay, ap_gain);
  149. } else {
  150. s = string_.ReadHermite(delay);
  151. }
  152. float s_ac = s;
  153. dc_blocker_.Process(&s_ac, 1);
  154. s += ac_blocking_amount * (s_ac - s);
  155. float value = fabs(s) - 0.025f;
  156. float sign = s > 0.0f ? 1.0f : -1.5f;
  157. curved_bridge_ = (fabs(value) + value) * sign;
  158. } else {
  159. s = string_.ReadHermite(delay);
  160. }
  161. s += *in; // When f0 < 11.7 Hz, causes ugly bitcrushing on the input!
  162. s = fir_damping_filter_.Process(s);
  163. #ifndef MIC_W
  164. s = iir_damping_filter_.Process<FILTER_MODE_LOW_PASS>(s);
  165. #endif // MIC_W
  166. string_.Write(s);
  167. out_sample_[1] = out_sample_[0];
  168. aux_sample_[1] = aux_sample_[0];
  169. out_sample_[0] = s;
  170. aux_sample_[0] = string_.Read(comb_delay);
  171. }
  172. *out++ += Crossfade(out_sample_[1], out_sample_[0], src_phase_);
  173. *aux++ += Crossfade(aux_sample_[1], aux_sample_[0], src_phase_);
  174. in++;
  175. }
  176. }
  177. void String::Process(const float* in, float* out, float* aux, size_t size) {
  178. if (enable_dispersion_) {
  179. ProcessInternal<true>(in, out, aux, size);
  180. } else {
  181. ProcessInternal<false>(in, out, aux, size);
  182. }
  183. }
  184. } // namespace elements