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.

221 lines
7.9KB

  1. // Copyright 2013 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. // Calibration settings.
  28. #include "elements/cv_scaler.h"
  29. #include <algorithm>
  30. #include "stmlib/dsp/dsp.h"
  31. #include "stmlib/system/storage.h"
  32. #include "elements/dsp/part.h"
  33. #include "elements/dsp/patch.h"
  34. namespace elements {
  35. using namespace std;
  36. using namespace stmlib;
  37. /* static */
  38. Law CvScaler::law_[POT_LAST] = {
  39. LAW_LINEAR, // POT_EXCITER_ENVELOPE_SHAPE,
  40. LAW_LINEAR, // POT_EXCITER_BOW_LEVEL,
  41. LAW_LINEAR, // POT_EXCITER_BOW_TIMBRE,
  42. LAW_QUADRATIC_BIPOLAR, // POT_EXCITER_BOW_TIMBRE_ATTENUVERTER,
  43. LAW_LINEAR, // POT_EXCITER_BLOW_LEVEL,
  44. LAW_LINEAR, // POT_EXCITER_BLOW_META,
  45. LAW_QUADRATIC_BIPOLAR, // POT_EXCITER_BLOW_META_ATTENUVERTER,
  46. LAW_LINEAR, // POT_EXCITER_BLOW_TIMBRE,
  47. LAW_QUADRATIC_BIPOLAR, // POT_EXCITER_BLOW_TIMBRE_ATTENUVERTER,
  48. LAW_LINEAR, // POT_EXCITER_STRIKE_LEVEL,
  49. LAW_LINEAR, // POT_EXCITER_STRIKE_META,
  50. LAW_QUADRATIC_BIPOLAR, // POT_EXCITER_STRIKE_META_ATTENUVERTER,
  51. LAW_LINEAR, // POT_EXCITER_STRIKE_TIMBRE,
  52. LAW_QUADRATIC_BIPOLAR, // POT_EXCITER_STRIKE_TIMBRE_ATTENUVERTER,
  53. LAW_QUANTIZED_NOTE, // POT_RESONATOR_COARSE,
  54. LAW_QUADRATIC_BIPOLAR, // POT_RESONATOR_FINE,
  55. LAW_QUARTIC_BIPOLAR, // POT_RESONATOR_FM_ATTENUVERTER,
  56. LAW_LINEAR, // POT_RESONATOR_GEOMETRY,
  57. LAW_QUADRATIC_BIPOLAR, // POT_RESONATOR_GEOMETRY_ATTENUVERTER,
  58. LAW_LINEAR, // POT_RESONATOR_BRIGHTNESS,
  59. LAW_QUADRATIC_BIPOLAR, // POT_RESONATOR_BRIGHTNESS_ATTENUVERTER,
  60. LAW_LINEAR, // POT_RESONATOR_DAMPING,
  61. LAW_QUADRATIC_BIPOLAR, // POT_RESONATOR_DAMPING_ATTENUVERTER,
  62. LAW_LINEAR, // POT_RESONATOR_POSITION,
  63. LAW_QUADRATIC_BIPOLAR, // POT_RESONATOR_POSITION_ATTENUVERTER,
  64. LAW_LINEAR, // POT_SPACE,
  65. LAW_QUADRATIC_BIPOLAR // POT_SPACE_ATTENUVERTER
  66. };
  67. Storage<1> storage;
  68. void CvScaler::Init() {
  69. pots_.Init();
  70. cv_.Init(false);
  71. gate_input_.Init();
  72. freshly_baked_ = false;
  73. if (!storage.ParsimoniousLoad(&calibration_settings_, &version_token_)) {
  74. calibration_settings_.pitch_offset = 66.67f;
  75. calibration_settings_.pitch_scale = -84.26f;
  76. for (size_t i = 0; i < CV_ADC_CHANNEL_LAST; ++i) {
  77. calibration_settings_.offset[i] = 10.0f * 20.0f / 120.0f / 3.3f;
  78. }
  79. calibration_settings_.boot_in_easter_egg_mode = false;
  80. calibration_settings_.resonator_model = 0;
  81. freshly_baked_ = true;
  82. SaveCalibration();
  83. }
  84. CONSTRAIN(calibration_settings_.resonator_model, 0, 2);
  85. note_ = 0.0f;
  86. modulation_ = 0.0f;
  87. fill(&pot_raw_[0], &pot_raw_[POT_LAST], 0.0f);
  88. fill(&pot_lp_[0], &pot_lp_[POT_LAST], 0.0f);
  89. fill(&pot_quantized_[0], &pot_quantized_[POT_LAST], 0.0f);
  90. }
  91. void CvScaler::SaveCalibration() {
  92. storage.ParsimoniousSave(calibration_settings_, &version_token_);
  93. }
  94. void CvScaler::ReadPanelPots() {
  95. // Read one pot from the front panel, and map it to the correct range.
  96. pots_.Scan();
  97. uint8_t index = pots_.last_read();
  98. switch (law_[index]) {
  99. case LAW_LINEAR:
  100. pot_raw_[index] = static_cast<float>(pots_.value(index)) / 65536.0f;
  101. break;
  102. case LAW_QUADRATIC_BIPOLAR:
  103. {
  104. float x = static_cast<float>(pots_.value(index)) / 32768.0f - 1.0f;
  105. float x2 = x * x * 3.3f;
  106. pot_raw_[index] = x < 0.0f ? -x2 : x2;
  107. }
  108. break;
  109. case LAW_QUARTIC_BIPOLAR:
  110. {
  111. float x = static_cast<float>(pots_.value(index)) / 32768.0f - 1.0f;
  112. float x2 = x * x;
  113. float x4 = x2 * x2 * 3.3f;
  114. pot_raw_[index] = x < 0.0f ? -x4 : x4;
  115. }
  116. break;
  117. case LAW_QUANTIZED_NOTE:
  118. {
  119. // 5 octaves.
  120. float note = 60.0f * static_cast<float>(pots_.value(index)) / 65536.0f;
  121. pot_raw_[index] += 0.5f * (note - pot_raw_[index]);
  122. float n = pot_raw_[index];
  123. float hysteresis = n - pot_quantized_[index] > 0.0f ? -0.3f : +0.3f;
  124. pot_quantized_[index] = static_cast<int32_t>(n + hysteresis + 0.5f);
  125. }
  126. break;
  127. }
  128. // Low-pass filter all front-panel pots.
  129. for (size_t i = 0; i < POT_LAST; ++i) {
  130. pot_lp_[i] += 0.01f * (pot_raw_[i] - pot_lp_[i]);
  131. }
  132. }
  133. #define BIND(destination, NAME, lp_coefficient, min, max) \
  134. { \
  135. const float* offset = calibration_settings_.offset; \
  136. float pot = pot_lp_[POT_ ## NAME]; \
  137. float cv = offset[CV_ADC_ ## NAME] - cv_.float_value(CV_ADC_ ## NAME); \
  138. float value = pot + pot_lp_[POT_ ## NAME ## _ATTENUVERTER] * cv; \
  139. CONSTRAIN(value, min, max); \
  140. if (lp_coefficient != 1.0f) { \
  141. destination += (value - destination) * lp_coefficient; \
  142. } else { \
  143. destination = value; \
  144. } \
  145. }
  146. void CvScaler::Read(
  147. Patch* patch,
  148. PerformanceState* state) {
  149. ReadPanelPots();
  150. patch->exciter_envelope_shape = pot_lp_[POT_EXCITER_ENVELOPE_SHAPE];
  151. patch->exciter_bow_level = pot_lp_[POT_EXCITER_BOW_LEVEL];
  152. patch->exciter_blow_level = pot_lp_[POT_EXCITER_BLOW_LEVEL];
  153. patch->exciter_strike_level = pot_lp_[POT_EXCITER_STRIKE_LEVEL];
  154. BIND(patch->exciter_bow_timbre, EXCITER_BOW_TIMBRE, 1.0f, 0.0f, 0.9995f);
  155. BIND(patch->exciter_blow_meta, EXCITER_BLOW_META, 0.05f, 0.0f, 0.9995f);
  156. BIND(patch->exciter_blow_timbre, EXCITER_BLOW_TIMBRE, 1.0f, 0.0f, 0.9995f);
  157. BIND(patch->exciter_strike_meta, EXCITER_STRIKE_META, 0.05f, 0.0f, 0.9995f);
  158. BIND(patch->exciter_strike_timbre, EXCITER_STRIKE_TIMBRE, 1.0f, 0.0f, 0.995f);
  159. BIND(patch->resonator_geometry, RESONATOR_GEOMETRY, 0.05f, 0.0f, 0.9995f);
  160. BIND(patch->resonator_brightness, RESONATOR_BRIGHTNESS, 1.0f, 0.0f, 0.9995f);
  161. BIND(patch->resonator_damping, RESONATOR_DAMPING, 1.0f, 0.0f, 0.9995f);
  162. BIND(patch->resonator_position, RESONATOR_POSITION, 0.01f, 0.0f, 0.9995f);
  163. BIND(patch->space, SPACE, 0.01f, 0.0f, 2.0f);
  164. float note = calibration_settings_.pitch_offset;
  165. note += cv_.float_value(CV_ADC_V_OCT) * calibration_settings_.pitch_scale;
  166. float interval = note - note_;
  167. // When a pitch difference of more than 1 quartertone is observed, do
  168. // not attempt to slew-limit and jump straight to the right pitch.
  169. if (interval < -0.4f || interval > 0.4f) {
  170. note_ = note;
  171. } else {
  172. note_ += 0.1f * interval;
  173. }
  174. float modulation = pot_lp_[POT_RESONATOR_FM_ATTENUVERTER] * 49.5f *
  175. (calibration_settings_.offset[CV_ADC_FM] - cv_.float_value(CV_ADC_FM));
  176. modulation_ += 0.5f * (modulation - modulation_);
  177. state->modulation = modulation_;
  178. state->note = note_;
  179. state->note += pot_quantized_[POT_RESONATOR_COARSE] + 19.0f;
  180. state->note += pot_lp_[POT_RESONATOR_FINE] * (2.0f / 3.3f);
  181. state->strength = 1.0f - cv_.float_value(CV_ADC_PRESSURE);
  182. CONSTRAIN(state->strength, 0.0f, 1.0f);
  183. CONSTRAIN(state->modulation, -60.0f, 60.0f);
  184. // Scan the gate input 1ms after the other CVs to prevent lag.
  185. state->gate = previous_gate_;
  186. previous_gate_ = gate_;
  187. gate_ = gate_input_.Read();
  188. cv_.Convert();
  189. }
  190. } // namespace elements