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.

171 lines
2.9KB

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