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.

174 lines
3.2KB

  1. #pragma once
  2. #include "dsp/common.hpp"
  3. namespace rack {
  4. namespace dsp {
  5. /** The simplest possible analog filter using an Euler solver.
  6. https://en.wikipedia.org/wiki/RC_circuit
  7. Use two RC filters in series for a bandpass filter.
  8. */
  9. template <typename T = float>
  10. struct TRCFilter {
  11. T c = 0.f;
  12. T xstate[1];
  13. T ystate[1];
  14. TRCFilter() {
  15. reset();
  16. }
  17. void reset() {
  18. xstate[0] = 0.f;
  19. ystate[0] = 0.f;
  20. }
  21. /** Sets the cutoff frequency.
  22. `r` is the ratio between the cutoff frequency and sample rate, i.e. r = f_c / f_s
  23. */
  24. void setCutoff(T r) {
  25. c = 2.f / r;
  26. }
  27. void process(T x) {
  28. T y = (x + xstate[0] - ystate[0] * (1 - c)) / (1 + c);
  29. xstate[0] = x;
  30. ystate[0] = y;
  31. }
  32. T lowpass() {
  33. return ystate[0];
  34. }
  35. T highpass() {
  36. return xstate[0] - ystate[0];
  37. }
  38. };
  39. typedef TRCFilter<> RCFilter;
  40. /** Applies exponential smoothing to a signal with the ODE
  41. \f$ \frac{dy}{dt} = x \lambda \f$.
  42. */
  43. template <typename T = float>
  44. struct TExponentialFilter {
  45. T out = 0.f;
  46. T lambda = 0.f;
  47. void reset() {
  48. out = 0.f;
  49. }
  50. void setLambda(T lambda) {
  51. this->lambda = lambda;
  52. }
  53. T process(T deltaTime, T in) {
  54. T y = out + (in - out) * lambda * deltaTime;
  55. // If no change was made between the old and new output, assume T granularity is too small and snap output to input
  56. out = simd::ifelse(out == y, in, y);
  57. return out;
  58. }
  59. DEPRECATED T process(T in) {
  60. return process(1.f, in);
  61. }
  62. };
  63. typedef TExponentialFilter<> ExponentialFilter;
  64. /** Like ExponentialFilter but jumps immediately to higher values.
  65. */
  66. template <typename T = float>
  67. struct TPeakFilter {
  68. T out = 0.f;
  69. T lambda = 0.f;
  70. void reset() {
  71. out = 0.f;
  72. }
  73. void setLambda(T lambda) {
  74. this->lambda = lambda;
  75. }
  76. T process(T deltaTime, T in) {
  77. T y = out + (in - out) * lambda * deltaTime;
  78. out = simd::fmax(y, in);
  79. return out;
  80. }
  81. /** Use the return value of process() instead. */
  82. DEPRECATED T peak() {
  83. return out;
  84. }
  85. /** Use setLambda() instead. */
  86. DEPRECATED void setRate(T r) {
  87. lambda = 1.f - r;
  88. }
  89. DEPRECATED T process(T x) {
  90. return process(1.f, x);
  91. }
  92. };
  93. typedef TPeakFilter<> PeakFilter;
  94. template <typename T = float>
  95. struct TSlewLimiter {
  96. T out = 0.f;
  97. T rise = 0.f;
  98. T fall = 0.f;
  99. void reset() {
  100. out = 0.f;
  101. }
  102. void setRiseFall(T rise, T fall) {
  103. this->rise = rise;
  104. this->fall = fall;
  105. }
  106. T process(T deltaTime, T in) {
  107. out = simd::clamp(in, out - fall * deltaTime, out + rise * deltaTime);
  108. return out;
  109. }
  110. DEPRECATED T process(T in) {
  111. return process(1.f, in);
  112. }
  113. };
  114. typedef TSlewLimiter<> SlewLimiter;
  115. template <typename T = float>
  116. struct TExponentialSlewLimiter {
  117. T out = 0.f;
  118. T riseLambda = 0.f;
  119. T fallLambda = 0.f;
  120. void reset() {
  121. out = 0.f;
  122. }
  123. void setRiseFall(T riseLambda, T fallLambda) {
  124. this->riseLambda = riseLambda;
  125. this->fallLambda = fallLambda;
  126. }
  127. T process(T deltaTime, T in) {
  128. T lambda = simd::ifelse(in > out, riseLambda, fallLambda);
  129. T y = out + (in - out) * lambda * deltaTime;
  130. // If the change from the old out to the new out is too small for floats, set `in` directly.
  131. out = simd::ifelse(out == y, in, y);
  132. return out;
  133. }
  134. DEPRECATED T process(T in) {
  135. return process(1.f, in);
  136. }
  137. };
  138. typedef TExponentialSlewLimiter<> ExponentialSlewLimiter;
  139. } // namespace dsp
  140. } // namespace rack