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.

249 lines
6.4KB

  1. // Copyright 2012 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (olivier@mutable-instruments.net)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. //
  16. // User interface handling.
  17. #include "edges/ui.h"
  18. #include <string.h>
  19. #include "edges/midi_handler.h"
  20. #include "edges/settings.h"
  21. namespace edges {
  22. const uint16_t kLongPressTime = 600; // ms
  23. using namespace avrlibx;
  24. /* <static> */
  25. Mode Ui::mode_;
  26. uint8_t Ui::gate_;
  27. uint8_t Ui::edited_channel_;
  28. uint16_t Ui::leds_pwm_counter_;
  29. uint16_t Ui::switch_time_counter_;
  30. uint16_t Ui::calibration_cv_[2];
  31. uint16_t Ui::cv_[2 * kNumChannels];
  32. uint16_t Ui::root_cv_;
  33. Leds Ui::leds_;
  34. Switches Ui::switches_;
  35. Gpio<PortC, 1> Ui::midi_learn_switch_;
  36. Gpio<PortC, 3> Ui::midi_mode_switch_;
  37. uint8_t Ui::debounce_history_[kNumSwitches];
  38. /* </static> */
  39. /* static */
  40. void Ui::Init() {
  41. leds_.set_direction(OUTPUT);
  42. switches_.set_direction(INPUT);
  43. midi_learn_switch_.set_direction(INPUT);
  44. midi_mode_switch_.set_direction(INPUT);
  45. switches_.set_mode(PORT_MODE_PULL_UP);
  46. midi_learn_switch_.set_mode(PORT_MODE_PULL_UP);
  47. midi_mode_switch_.set_mode(PORT_MODE_PULL_UP);
  48. mode_ = MODE_NORMAL;
  49. leds_pwm_counter_ = 0;
  50. edited_channel_ = 0;
  51. memset(debounce_history_, 0xff, sizeof(debounce_history_));
  52. memset(cv_, 0, sizeof(cv_));
  53. }
  54. /* static */
  55. void Ui::OnSwitchHeld(uint8_t index) {
  56. if (index < kNumChannels) {
  57. if (mode_ == MODE_MENU) {
  58. mode_ = MODE_NORMAL;
  59. settings.Save();
  60. } else {
  61. mode_ = MODE_MENU;
  62. edited_channel_ = index;
  63. }
  64. } else if (index == kNumChannels + 1) {
  65. midi_handler.DisableMidiCoupling();
  66. }
  67. }
  68. /* static */
  69. void Ui::OnSwitchReleased(uint8_t index) {
  70. if (index < kNumChannels) {
  71. switch (mode_) {
  72. case MODE_MENU:
  73. switch (index) {
  74. case 0:
  75. settings.ToggleQuantizer(edited_channel_);
  76. break;
  77. case 1:
  78. settings.ToggleArpeggio(edited_channel_);
  79. break;
  80. case 2:
  81. mode_ = MODE_RECORDING;
  82. root_cv_ = cv_[edited_channel_];
  83. settings.mutable_channel_data(edited_channel_)->StartRecording();
  84. break;
  85. case 3:
  86. mode_ = MODE_CALIBRATE_1;
  87. break;
  88. }
  89. break;
  90. case MODE_NORMAL:
  91. settings.StepPW(index);
  92. break;
  93. case MODE_CALIBRATE_1:
  94. mode_ = MODE_CALIBRATE_2;
  95. break;
  96. case MODE_CALIBRATE_2:
  97. settings.Calibrate(
  98. edited_channel_,
  99. calibration_cv_[0],
  100. calibration_cv_[1],
  101. cv_[edited_channel_ + 4]);
  102. mode_ = MODE_NORMAL;
  103. break;
  104. case MODE_RECORDING:
  105. {
  106. ChannelData* channel = settings.mutable_channel_data(edited_channel_);
  107. uint8_t current_step = channel->num_arpeggio_steps - 1;
  108. if (index == (current_step & 3)) {
  109. channel->StopRecording();
  110. settings.Save();
  111. mode_ = MODE_NORMAL;
  112. } else if (index == ((current_step + 1) & 3)) {
  113. if (!channel->NextArpeggiatorStep()) {
  114. settings.Save();
  115. mode_ = MODE_NORMAL;
  116. }
  117. }
  118. }
  119. break;
  120. }
  121. } else if (index == kNumChannels) {
  122. mode_ = MODE_LEARNING_MIDI_CHANNEL;
  123. midi_handler.Learn();
  124. } else {
  125. midi_handler.ToggleMidiMode();
  126. }
  127. }
  128. static const uint8_t bit_reverse[] = {
  129. 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
  130. };
  131. /* static */
  132. void Ui::Poll() {
  133. ++leds_pwm_counter_;
  134. ++switch_time_counter_;
  135. // Refresh leds.
  136. uint8_t leds_value = 0;
  137. switch (mode_) {
  138. case MODE_NORMAL:
  139. leds_value = gate_;
  140. break;
  141. case MODE_MENU:
  142. if (settings.quantized(edited_channel_)) {
  143. leds_value |= 0x1;
  144. }
  145. if (settings.arpeggio(edited_channel_)) {
  146. leds_value |= 0x2;
  147. }
  148. if (leds_pwm_counter_ & 128) {
  149. leds_value |= 0x4;
  150. } else {
  151. leds_value |= 0x8;
  152. }
  153. break;
  154. case MODE_LEARNING_MIDI_CHANNEL:
  155. if (leds_pwm_counter_ & 128) {
  156. leds_value = 0xff;
  157. }
  158. if (!midi_handler.learning()) {
  159. mode_ = MODE_NORMAL;
  160. }
  161. break;
  162. case MODE_CALIBRATE_1:
  163. leds_value |= 0x3;
  164. break;
  165. case MODE_CALIBRATE_2:
  166. leds_value |= 0xf;
  167. break;
  168. case MODE_RECORDING:
  169. leds_value |= 1 << ((settings.num_steps(edited_channel_) - 1) & 0x03);
  170. break;
  171. }
  172. leds_.set_value(bit_reverse[leds_value & 0xf]);
  173. // Scan switches.
  174. uint8_t switches_value = bit_reverse[switches_.Read()];
  175. for (uint8_t i = 0; i < kNumChannels; ++i) {
  176. debounce_history_[i] = (debounce_history_[i] << 1) | (switches_value & 1);
  177. switches_value >>= 1;
  178. }
  179. debounce_history_[kNumChannels] = \
  180. (debounce_history_[kNumChannels] << 1) | midi_learn_switch_.value();
  181. debounce_history_[kNumChannels + 1] = \
  182. (debounce_history_[kNumChannels + 1] << 1) | midi_mode_switch_.value();
  183. // Trigger switch events.
  184. for (uint8_t i = 0; i < kNumSwitches; ++i) {
  185. // When a switch is pressed, start the time counter.
  186. if (debounce_history_[i] == 0xfe) {
  187. switch_time_counter_ = 0;
  188. }
  189. // When a switch is held, enable calibration mode.
  190. if (debounce_history_[i] == 0x00 &&
  191. switch_time_counter_ == kLongPressTime) {
  192. OnSwitchHeld(i);
  193. }
  194. // When a switch is released, do something depending on the event.
  195. if (debounce_history_[i] == 0x01 &&
  196. switch_time_counter_ < kLongPressTime) {
  197. OnSwitchReleased(i);
  198. }
  199. }
  200. // Update arpeggiator pattern.
  201. if (mode_ == MODE_RECORDING) {
  202. if (settings.num_steps(edited_channel_) == 1) {
  203. root_cv_ = cv_[edited_channel_];
  204. }
  205. settings.mutable_channel_data(edited_channel_)->UpdateArpeggiatorStep(
  206. root_cv_,
  207. cv_[edited_channel_]
  208. );
  209. }
  210. }
  211. /* extern */
  212. Ui ui;
  213. } // namespace edges