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.

182 lines
3.1KB

  1. #pragma once
  2. #include <dsp/common.hpp>
  3. namespace rack {
  4. namespace dsp {
  5. /** Detects when a boolean changes from false to true */
  6. struct BooleanTrigger {
  7. bool state = true;
  8. void reset() {
  9. state = true;
  10. }
  11. bool process(bool state) {
  12. bool triggered = (state && !this->state);
  13. this->state = state;
  14. return triggered;
  15. }
  16. };
  17. /** Turns HIGH when value reaches a threshold (default 0.f), turns LOW when value reaches a threshold (default 1.f).
  18. */
  19. template <typename T = float>
  20. struct TSchmittTrigger {
  21. T state;
  22. TSchmittTrigger() {
  23. reset();
  24. }
  25. void reset() {
  26. state = T::mask();
  27. }
  28. T process(T in, T offThreshold = 0.f, T onThreshold = 1.f) {
  29. T on = (in >= onThreshold);
  30. T off = (in <= offThreshold);
  31. T triggered = ~state & on;
  32. state = on | (state & ~off);
  33. return triggered;
  34. }
  35. T isHigh() {
  36. return state;
  37. }
  38. };
  39. template <>
  40. struct TSchmittTrigger<float> {
  41. bool state = true;
  42. void reset() {
  43. state = true;
  44. }
  45. /** Updates the state of the Schmitt Trigger given a value.
  46. Returns true if triggered, i.e. the value increases from 0 to 1.
  47. If different trigger thresholds are needed, use
  48. process(in, 0.1f, 2.f)
  49. for example.
  50. */
  51. bool process(float in, float offThreshold = 0.f, float onThreshold = 1.f) {
  52. if (state) {
  53. // HIGH to LOW
  54. if (in <= offThreshold) {
  55. state = false;
  56. }
  57. }
  58. else {
  59. // LOW to HIGH
  60. if (in >= onThreshold) {
  61. state = true;
  62. return true;
  63. }
  64. }
  65. return false;
  66. }
  67. bool isHigh() {
  68. return state;
  69. }
  70. };
  71. typedef TSchmittTrigger<> SchmittTrigger;
  72. /** When triggered, holds a high value for a specified time before going low again */
  73. struct PulseGenerator {
  74. float remaining = 0.f;
  75. /** Immediately disables the pulse */
  76. void reset() {
  77. remaining = 0.f;
  78. }
  79. /** Advances the state by `deltaTime`. Returns whether the pulse is in the HIGH state. */
  80. bool process(float deltaTime) {
  81. if (remaining > 0.f) {
  82. remaining -= deltaTime;
  83. return true;
  84. }
  85. return false;
  86. }
  87. /** Begins a trigger with the given `duration`. */
  88. void trigger(float duration = 1e-3f) {
  89. // Keep the previous pulse if the existing pulse will be held longer than the currently requested one.
  90. if (duration > remaining) {
  91. remaining = duration;
  92. }
  93. }
  94. };
  95. /** Accumulates a timer when process() is called. */
  96. template <typename T = float>
  97. struct TTimer {
  98. T time = 0.f;
  99. void reset() {
  100. time = 0.f;
  101. }
  102. /** Returns the time since last reset or initialization. */
  103. T process(T deltaTime) {
  104. time += deltaTime;
  105. return time;
  106. }
  107. T getTime() {
  108. return time;
  109. }
  110. };
  111. typedef TTimer<> Timer;
  112. /** Counts calls to process(), returning true every `division` calls.
  113. Example:
  114. if (divider.process()) {
  115. // Runs every `division` calls
  116. }
  117. */
  118. struct ClockDivider {
  119. uint32_t clock = 0;
  120. uint32_t division = 1;
  121. void reset() {
  122. clock = 0;
  123. }
  124. void setDivision(uint32_t division) {
  125. this->division = division;
  126. }
  127. uint32_t getDivision() {
  128. return division;
  129. }
  130. uint32_t getClock() {
  131. return clock;
  132. }
  133. /** Returns true when the clock reaches `division` and resets. */
  134. bool process() {
  135. clock++;
  136. if (clock >= division) {
  137. clock = 0;
  138. return true;
  139. }
  140. return false;
  141. }
  142. };
  143. } // namespace dsp
  144. } // namespace rack