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.

188 lines
6.3KB

  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. // Resonator.
  28. #include "elements/dsp/resonator.h"
  29. #include "stmlib/dsp/dsp.h"
  30. #include "stmlib/dsp/cosine_oscillator.h"
  31. #include "elements/drivers/debug_pin.h"
  32. #include "elements/dsp/dsp.h"
  33. #include "elements/resources.h"
  34. namespace elements {
  35. using namespace std;
  36. using namespace stmlib;
  37. void Resonator::Init() {
  38. for (size_t i = 0; i < kMaxModes; ++i) {
  39. f_[i].Init();
  40. }
  41. for (size_t i = 0; i < kMaxBowedModes; ++i) {
  42. f_bow_[i].Init();
  43. d_bow_[i].Init();
  44. }
  45. set_frequency(220.0f / kSampleRate);
  46. set_geometry(0.25f);
  47. set_brightness(0.5f);
  48. set_damping(0.3f);
  49. set_position(0.999f);
  50. set_resolution(kMaxModes);
  51. bow_signal_ = 0.0f;
  52. }
  53. size_t Resonator::ComputeFilters() {
  54. ++clock_divider_;
  55. float stiffness = Interpolate(lut_stiffness, geometry_, 256.0f);
  56. float harmonic = frequency_;
  57. float stretch_factor = 1.0f;
  58. float q = 500.0f * Interpolate(
  59. lut_4_decades,
  60. damping_ * 0.8f,
  61. 256.0f);
  62. float brightness_attenuation = 1.0f - geometry_;
  63. // Reduces the range of brightness when geometry is very low, to prevent
  64. // clipping.
  65. brightness_attenuation *= brightness_attenuation;
  66. brightness_attenuation *= brightness_attenuation;
  67. brightness_attenuation *= brightness_attenuation;
  68. float brightness = brightness_ * (1.0f - 0.2f * brightness_attenuation);
  69. float q_loss = brightness * (2.0f - brightness) * 0.85f + 0.15f;
  70. float q_loss_damping_rate = geometry_ * (2.0f - geometry_) * 0.1f;
  71. size_t num_modes = 0;
  72. for (size_t i = 0; i < min(kMaxModes, resolution_); ++i) {
  73. // Update the first 24 modes every time (2kHz). The higher modes are
  74. // refreshed as a slowest rate.
  75. bool update = i <= 24 || ((i & 1) == (clock_divider_ & 1));
  76. float partial_frequency = harmonic * stretch_factor;
  77. if (partial_frequency >= 0.49f) {
  78. partial_frequency = 0.49f;
  79. } else {
  80. num_modes = i + 1;
  81. }
  82. if (update) {
  83. f_[i].set_f_q<FREQUENCY_FAST>(
  84. partial_frequency,
  85. 1.0f + partial_frequency * q);
  86. if (i < kMaxBowedModes) {
  87. size_t period = 1.0f / partial_frequency;
  88. while (period >= kMaxDelayLineSize) period >>= 1;
  89. d_bow_[i].set_delay(period);
  90. f_bow_[i].set_g_q(f_[i].g(), 1.0f + partial_frequency * 1500.0f);
  91. }
  92. }
  93. stretch_factor += stiffness;
  94. if (stiffness < 0.0f) {
  95. // Make sure that the partials do not fold back into negative frequencies.
  96. stiffness *= 0.93f;
  97. } else {
  98. // This helps adding a few extra partials in the highest frequencies.
  99. stiffness *= 0.98f;
  100. }
  101. // This prevents the highest partials from decaying too fast.
  102. q_loss += q_loss_damping_rate * (1.0f - q_loss);
  103. harmonic += frequency_;
  104. q *= q_loss;
  105. }
  106. return num_modes;
  107. }
  108. void Resonator::Process(
  109. const float* bow_strength,
  110. const float* in,
  111. float* center,
  112. float* sides,
  113. size_t size) {
  114. size_t num_modes = ComputeFilters();
  115. size_t num_banded_wg = min(kMaxBowedModes, num_modes);
  116. // Linearly interpolate position. This parameter is extremely sensitive to
  117. // zipper noise.
  118. float position_increment = (position_ - previous_position_) / size;
  119. while (size--) {
  120. float s;
  121. // 0.5 Hz LFO used to modulate the position of the stereo side channel.
  122. lfo_phase_ += modulation_frequency_;
  123. if (lfo_phase_ >= 1.0f) {
  124. lfo_phase_ -= 1.0f;
  125. }
  126. previous_position_ += position_increment;
  127. float lfo = lfo_phase_ > 0.5f ? 1.0f - lfo_phase_ : lfo_phase_;
  128. CosineOscillator amplitudes;
  129. CosineOscillator aux_amplitudes;
  130. amplitudes.Init<COSINE_OSCILLATOR_APPROXIMATE>(previous_position_);
  131. aux_amplitudes.Init<COSINE_OSCILLATOR_APPROXIMATE>(
  132. modulation_offset_ + lfo);
  133. // Render normal modes.
  134. float input = *in++ * 0.125f;
  135. float sum_center = 0.0f;
  136. float sum_side = 0.0f;
  137. // Note: For a steady sound, the correct way of simulating the effect of
  138. // a pickup is to use a comb filter. But it sounds very flange-y when
  139. // modulated, even mildly, and incur a slight delay/smearing of the
  140. // attacks.
  141. // Thus, we directly apply the comb filter in the frequency domain by
  142. // adjusting the amplitude of each mode in the sum. Because the
  143. // partials may not be in an integer ratios, what we are doing here is
  144. // approximative when the stretch factor is non null.
  145. // It sounds interesting nevertheless.
  146. amplitudes.Start();
  147. aux_amplitudes.Start();
  148. for (size_t i = 0; i < num_modes; i++) {
  149. s = f_[i].Process<FILTER_MODE_BAND_PASS>(input);
  150. sum_center += s * amplitudes.Next();
  151. sum_side += s * aux_amplitudes.Next();
  152. }
  153. *sides++ = sum_side - sum_center;
  154. // Render bowed modes.
  155. float bow_signal = 0.0f;
  156. input += bow_signal_;
  157. amplitudes.Start();
  158. for (size_t i = 0; i < num_banded_wg; ++i) {
  159. s = 0.99f * d_bow_[i].Read();
  160. bow_signal += s;
  161. s = f_bow_[i].Process<FILTER_MODE_BAND_PASS_NORMALIZED>(input + s);
  162. d_bow_[i].Write(s);
  163. sum_center += s * amplitudes.Next() * 8.0f;
  164. }
  165. bow_signal_ = BowTable(bow_signal, *bow_strength++);
  166. *center++ = sum_center;
  167. }
  168. }
  169. } // namespace elements