DISTRHO Plugin Framework
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.

205 lines
5.2KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
  4. * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com>
  5. *
  6. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  7. * or without fee is hereby granted, provided that the above copyright notice and this
  8. * permission notice appear in all copies.
  9. *
  10. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  11. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  12. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  13. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  14. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  15. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #ifndef DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED
  18. #define DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED
  19. #include "../DistrhoUtils.hpp"
  20. START_NAMESPACE_DISTRHO
  21. // --------------------------------------------------------------------------------------------------------------------
  22. /**
  23. * @brief An exponential smoother for control values
  24. *
  25. * This continually smooths a value towards a defined target,
  26. * using a low-pass filter of the 1st order, which creates an exponential curve.
  27. *
  28. * The length of the curve is defined by a T60 constant,
  29. * which is the time it takes for a 1-to-0 smoothing to fall to -60dB.
  30. *
  31. * Note that this smoother has asymptotical behavior,
  32. * and it must not be assumed that the final target is ever reached.
  33. */
  34. class ExponentialValueSmoother {
  35. float coef;
  36. float target;
  37. float mem;
  38. float tau;
  39. float sampleRate;
  40. public:
  41. ExponentialValueSmoother()
  42. : coef(0.f),
  43. target(0.f),
  44. mem(0.f),
  45. tau(0.f),
  46. sampleRate(0.f) {}
  47. void setSampleRate(const float newSampleRate) noexcept
  48. {
  49. if (d_isNotEqual(sampleRate, newSampleRate))
  50. {
  51. sampleRate = newSampleRate;
  52. updateCoef();
  53. }
  54. }
  55. void setTimeConstant(const float newT60) noexcept
  56. {
  57. const float newTau = newT60 * (float)(1.0 / 6.91);
  58. if (d_isNotEqual(tau, newTau))
  59. {
  60. tau = newTau;
  61. updateCoef();
  62. }
  63. }
  64. float getCurrentValue() const noexcept
  65. {
  66. return mem;
  67. }
  68. float getTargetValue() const noexcept
  69. {
  70. return target;
  71. }
  72. void setTargetValue(const float newTarget) noexcept
  73. {
  74. target = newTarget;
  75. }
  76. void clearToTargetValue() noexcept
  77. {
  78. mem = target;
  79. }
  80. inline float peek() const noexcept
  81. {
  82. return mem * coef + target * (1.f - coef);
  83. }
  84. inline float next() noexcept
  85. {
  86. return (mem = mem * coef + target * (1.f - coef));
  87. }
  88. private:
  89. void updateCoef() noexcept
  90. {
  91. coef = std::exp(-1.f / (tau * sampleRate));
  92. }
  93. };
  94. // --------------------------------------------------------------------------------------------------------------------
  95. /**
  96. * @brief A linear smoother for control values
  97. *
  98. * This continually smooths a value towards a defined target, using linear segments.
  99. *
  100. * The duration of the smoothing segment is defined by the given time constant.
  101. * Every time the target changes, a new segment restarts for the whole duration of the time constant.
  102. *
  103. * Note that this smoother, unlike an exponential smoother, eventually should converge to its target value.
  104. */
  105. class LinearValueSmoother {
  106. float step;
  107. float target;
  108. float mem;
  109. float tau;
  110. float sampleRate;
  111. public:
  112. LinearValueSmoother()
  113. : step(0.f),
  114. target(0.f),
  115. mem(0.f),
  116. tau(0.f),
  117. sampleRate(0.f) {}
  118. void setSampleRate(const float newSampleRate) noexcept
  119. {
  120. if (d_isNotEqual(sampleRate, newSampleRate))
  121. {
  122. sampleRate = newSampleRate;
  123. updateStep();
  124. }
  125. }
  126. void setTimeConstant(const float newTau) noexcept
  127. {
  128. if (d_isNotEqual(tau, newTau))
  129. {
  130. tau = newTau;
  131. updateStep();
  132. }
  133. }
  134. float getCurrentValue() const noexcept
  135. {
  136. return mem;
  137. }
  138. float getTargetValue() const noexcept
  139. {
  140. return target;
  141. }
  142. void setTargetValue(const float newTarget) noexcept
  143. {
  144. if (d_isNotEqual(target, newTarget))
  145. {
  146. target = newTarget;
  147. updateStep();
  148. }
  149. }
  150. void clearToTargetValue() noexcept
  151. {
  152. mem = target;
  153. }
  154. inline float peek() const noexcept
  155. {
  156. const float dy = target - mem;
  157. return mem + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy);
  158. }
  159. inline float next() noexcept
  160. {
  161. const float y0 = mem;
  162. const float dy = target - y0;
  163. return (mem = y0 + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy));
  164. }
  165. private:
  166. void updateStep() noexcept
  167. {
  168. step = (target - mem) / (tau * sampleRate);
  169. }
  170. };
  171. // --------------------------------------------------------------------------------------------------------------------
  172. END_NAMESPACE_DISTRHO
  173. #endif // DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED