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.

172 lines
5.0KB

  1. // Copyright 2015 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. // Handles the "hold button to tweak a hidden parameter" behaviour of pots.
  28. // A pot can be in 4 states:
  29. // - POT_STATE_TRACKING: the main parameter tracks the position of the pot.
  30. // - POT_STATE_LOCKING: the main parameter no longer tracks the position of
  31. // the pot. We wait for the pot to move further from its original position
  32. // to start modifying the hidden parameter.
  33. // - POT_STATE_HIDDEN_PARAMETER: the hidden parameter tracks the position of
  34. // the pot.
  35. // - POT_STATE_CATCHING_UP: the pot adjusts the main parameter in a relative
  36. // way, until the position of the pot and the value of the parameter match
  37. // again.
  38. #ifndef PLAITS_POT_CONTROLLER_H_
  39. #define PLAITS_POT_CONTROLLER_H_
  40. #include "stmlib/stmlib.h"
  41. #include "stmlib/dsp/dsp.h"
  42. namespace plaits {
  43. enum PotState {
  44. POT_STATE_TRACKING,
  45. POT_STATE_LOCKING,
  46. POT_STATE_HIDDEN_PARAMETER,
  47. POT_STATE_CATCHING_UP
  48. };
  49. class PotController {
  50. public:
  51. PotController() { }
  52. ~PotController() { }
  53. inline void Init(
  54. float* main_parameter,
  55. float* hidden_parameter,
  56. float scale,
  57. float offset) {
  58. state_ = POT_STATE_TRACKING;
  59. was_catching_up_ = false;
  60. main_parameter_ = main_parameter;
  61. hidden_parameter_ = hidden_parameter;
  62. value_ = 0.0f;
  63. stored_value_ = 0.0f;
  64. previous_value_ = 0.0f;
  65. scale_ = scale;
  66. offset_ = offset;
  67. }
  68. inline void Lock() {
  69. if (state_ == POT_STATE_LOCKING || state_ == POT_STATE_HIDDEN_PARAMETER) {
  70. return;
  71. }
  72. if (hidden_parameter_) {
  73. was_catching_up_ = state_ == POT_STATE_CATCHING_UP;
  74. state_ = POT_STATE_LOCKING;
  75. }
  76. }
  77. inline bool editing_hidden_parameter() const {
  78. return state_ == POT_STATE_HIDDEN_PARAMETER;
  79. }
  80. inline void Unlock() {
  81. if (state_ == POT_STATE_HIDDEN_PARAMETER || was_catching_up_) {
  82. state_ = POT_STATE_CATCHING_UP;
  83. } else {
  84. state_ = POT_STATE_TRACKING;
  85. }
  86. }
  87. inline void Realign() {
  88. state_ = POT_STATE_TRACKING;
  89. }
  90. inline void ProcessControlRate(float adc_value) {
  91. ONE_POLE(value_, adc_value, 0.01f);
  92. if (state_ == POT_STATE_TRACKING) {
  93. *main_parameter_ = value_ * scale_ + offset_;
  94. }
  95. }
  96. inline void ProcessUIRate() {
  97. switch (state_) {
  98. case POT_STATE_TRACKING:
  99. previous_value_ = value_;
  100. break;
  101. case POT_STATE_LOCKING:
  102. if (fabsf(value_ - previous_value_) > 0.03f) {
  103. stored_value_ = previous_value_;
  104. *hidden_parameter_ = value_;
  105. state_ = POT_STATE_HIDDEN_PARAMETER;
  106. previous_value_ = value_;
  107. }
  108. break;
  109. case POT_STATE_HIDDEN_PARAMETER:
  110. *hidden_parameter_ = value_;
  111. previous_value_ = value_;
  112. break;
  113. case POT_STATE_CATCHING_UP:
  114. {
  115. if (fabsf(value_ - previous_value_) > 0.005f) {
  116. float delta = value_ - previous_value_;
  117. float skew_ratio = delta > 0.0f
  118. ? (1.001f - stored_value_) / (1.001f - previous_value_)
  119. : (0.001f + stored_value_) / (0.001f + previous_value_);
  120. CONSTRAIN(skew_ratio, 0.1f, 10.0f);
  121. stored_value_ += skew_ratio * delta;
  122. CONSTRAIN(stored_value_, 0.0f, 1.0f);
  123. if (fabsf(stored_value_ - value_) < 0.005f) {
  124. state_ = POT_STATE_TRACKING;
  125. }
  126. previous_value_ = value_;
  127. *main_parameter_ = stored_value_ * scale_ + offset_;
  128. }
  129. }
  130. break;
  131. }
  132. }
  133. private:
  134. PotState state_;
  135. bool was_catching_up_;
  136. float* main_parameter_;
  137. float* hidden_parameter_;
  138. float value_;
  139. float stored_value_;
  140. float previous_value_;
  141. float scale_;
  142. float offset_;
  143. DISALLOW_COPY_AND_ASSIGN(PotController);
  144. };
  145. } // namespace plaits
  146. #endif // PLAITS_POT_CONTROLLER_H_