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.

393 lines
12KB

  1. // Copyright 2014 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. // User interface.
  28. #include "clouds/ui.h"
  29. #include "stmlib/system/system_clock.h"
  30. #include "clouds/dsp/granular_processor.h"
  31. #include "clouds/cv_scaler.h"
  32. #include "clouds/meter.h"
  33. namespace clouds {
  34. const int32_t kLongPressDuration = 1000;
  35. const int32_t kVeryLongPressDuration = 4000;
  36. using namespace stmlib;
  37. void Ui::Init(
  38. Settings* settings,
  39. CvScaler* cv_scaler,
  40. GranularProcessor* processor,
  41. Meter* meter) {
  42. settings_ = settings;
  43. cv_scaler_ = cv_scaler;
  44. leds_.Init();
  45. switches_.Init();
  46. processor_ = processor;
  47. meter_ = meter;
  48. mode_ = UI_MODE_SPLASH;
  49. const State& state = settings_->state();
  50. // Sanitize saved settings.
  51. cv_scaler_->set_blend_parameter(
  52. static_cast<BlendParameter>(state.blend_parameter & 3));
  53. cv_scaler_->MatchKnobPosition();
  54. processor_->set_quality(state.quality & 3);
  55. processor_->set_playback_mode(
  56. static_cast<PlaybackMode>(state.playback_mode & 3));
  57. for (int32_t i = 0; i < BLEND_PARAMETER_LAST; ++i) {
  58. cv_scaler_->set_blend_value(
  59. static_cast<BlendParameter>(i),
  60. static_cast<float>(state.blend_value[i]) / 255.0f);
  61. }
  62. cv_scaler_->UnlockBlendKnob();
  63. }
  64. void Ui::SaveState() {
  65. State* state = settings_->mutable_state();
  66. state->blend_parameter = cv_scaler_->blend_parameter();
  67. state->quality = processor_->quality();
  68. state->playback_mode = processor_->playback_mode();
  69. for (int32_t i = 0; i < BLEND_PARAMETER_LAST; ++i) {
  70. state->blend_value[i] = static_cast<uint8_t>(
  71. cv_scaler_->blend_value(static_cast<BlendParameter>(i)) * 255.0f);
  72. }
  73. settings_->Save();
  74. }
  75. void Ui::Poll() {
  76. system_clock.Tick();
  77. switches_.Debounce();
  78. for (uint8_t i = 0; i < kNumSwitches; ++i) {
  79. if (switches_.just_pressed(i)) {
  80. queue_.AddEvent(CONTROL_SWITCH, i, 0);
  81. press_time_[i] = system_clock.milliseconds();
  82. long_press_time_[i] = system_clock.milliseconds();
  83. }
  84. if (switches_.pressed(i) && press_time_[i] != 0) {
  85. int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
  86. if (pressed_time > kLongPressDuration) {
  87. queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
  88. press_time_[i] = 0;
  89. }
  90. }
  91. if (switches_.pressed(i) && long_press_time_[i] != 0) {
  92. int32_t pressed_time = system_clock.milliseconds() - long_press_time_[i];
  93. if (pressed_time > kVeryLongPressDuration) {
  94. queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
  95. long_press_time_[i] = 0;
  96. }
  97. }
  98. if (switches_.released(i) && press_time_[i] != 0) {
  99. queue_.AddEvent(
  100. CONTROL_SWITCH,
  101. i,
  102. system_clock.milliseconds() - press_time_[i] + 1);
  103. press_time_[i] = 0;
  104. }
  105. }
  106. PaintLeds();
  107. }
  108. void Ui::PaintLeds() {
  109. leds_.Clear();
  110. bool blink = (system_clock.milliseconds() & 127) > 64;
  111. uint8_t fade = system_clock.milliseconds() >> 1;
  112. fade = fade <= 127 ? (fade << 1) : 255 - (fade << 1);
  113. fade = static_cast<uint16_t>(fade) * fade >> 8;
  114. switch (mode_) {
  115. case UI_MODE_SPLASH:
  116. {
  117. uint8_t index = ((system_clock.milliseconds() >> 8) + 1) & 3;
  118. uint8_t fade = (system_clock.milliseconds() >> 2);
  119. fade = fade <= 127 ? (fade << 1) : 255 - (fade << 1);
  120. leds_.set_intensity(3 - index, fade);
  121. }
  122. break;
  123. case UI_MODE_VU_METER:
  124. leds_.PaintBar(lut_db[meter_->peak() >> 7]);
  125. break;
  126. case UI_MODE_BLEND_METER:
  127. for (int32_t i = 0; i < 4; ++i) {
  128. leds_.set_intensity(
  129. i,
  130. cv_scaler_->blend_value(static_cast<BlendParameter>(i)) * 255.0f);
  131. }
  132. break;
  133. case UI_MODE_QUALITY:
  134. leds_.set_status(processor_->quality(), 255, 0);
  135. break;
  136. case UI_MODE_BLENDING:
  137. leds_.set_status(cv_scaler_->blend_parameter(), 0, 255);
  138. break;
  139. case UI_MODE_PLAYBACK_MODE:
  140. leds_.set_status(
  141. processor_->playback_mode(),
  142. 128 + (fade >> 1),
  143. 255 - (fade >> 1));
  144. break;
  145. case UI_MODE_LOAD:
  146. leds_.set_status(load_save_location_, 0, blink ? 255 : 0);
  147. break;
  148. case UI_MODE_SAVE:
  149. leds_.set_status(load_save_location_, blink ? 255 : 0, 0);
  150. break;
  151. case UI_MODE_SAVING:
  152. leds_.set_status(load_save_location_, 255, 0);
  153. break;
  154. case UI_MODE_CALIBRATION_1:
  155. leds_.set_status(0, blink ? 255 : 0, blink ? 255 : 0);
  156. leds_.set_status(1, blink ? 255 : 0, blink ? 255 : 0);
  157. leds_.set_status(2, 0, 0);
  158. leds_.set_status(3, 0, 0);
  159. break;
  160. case UI_MODE_CALIBRATION_2:
  161. leds_.set_status(0, blink ? 255 : 0, blink ? 255 : 0);
  162. leds_.set_status(1, blink ? 255 : 0, blink ? 255 : 0);
  163. leds_.set_status(2, blink ? 255 : 0, blink ? 255 : 0);
  164. leds_.set_status(3, blink ? 255 : 0, blink ? 255 : 0);
  165. break;
  166. case UI_MODE_PANIC:
  167. leds_.set_status(0, 255, 0);
  168. leds_.set_status(1, 255, 0);
  169. leds_.set_status(2, 255, 0);
  170. leds_.set_status(3, 255, 0);
  171. break;
  172. default:
  173. break;
  174. }
  175. leds_.set_freeze(processor_->frozen());
  176. if (processor_->bypass()) {
  177. leds_.PaintBar(lut_db[meter_->peak() >> 7]);
  178. leds_.set_freeze(true);
  179. }
  180. leds_.Write();
  181. }
  182. void Ui::FlushEvents() {
  183. queue_.Flush();
  184. }
  185. void Ui::OnSwitchPressed(const Event& e) {
  186. if (e.control_id == SWITCH_FREEZE) {
  187. processor_->ToggleFreeze();
  188. }
  189. }
  190. void Ui::CalibrateC1() {
  191. cv_scaler_->CalibrateC1();
  192. cv_scaler_->CalibrateOffsets();
  193. mode_ = UI_MODE_CALIBRATION_2;
  194. }
  195. void Ui::CalibrateC3() {
  196. bool success = cv_scaler_->CalibrateC3();
  197. if (success) {
  198. settings_->Save();
  199. mode_ = UI_MODE_VU_METER;
  200. } else {
  201. mode_ = UI_MODE_PANIC;
  202. }
  203. }
  204. void Ui::OnSecretHandshake() {
  205. mode_ = UI_MODE_PLAYBACK_MODE;
  206. }
  207. void Ui::OnSwitchReleased(const Event& e) {
  208. switch (e.control_id) {
  209. case SWITCH_FREEZE:
  210. break;
  211. case SWITCH_MODE:
  212. if (e.data >= kVeryLongPressDuration) {
  213. mode_ = UI_MODE_PLAYBACK_MODE;
  214. } else if (e.data >= kLongPressDuration) {
  215. if (mode_ == UI_MODE_QUALITY) {
  216. mode_ = UI_MODE_VU_METER;
  217. } else {
  218. mode_ = UI_MODE_QUALITY;
  219. }
  220. } else if (mode_ == UI_MODE_VU_METER || mode_ == UI_MODE_BLEND_METER) {
  221. mode_ = UI_MODE_BLENDING;
  222. } else if (mode_ == UI_MODE_BLENDING) {
  223. uint8_t parameter = (cv_scaler_->blend_parameter() + 1) & 3;
  224. cv_scaler_->set_blend_parameter(static_cast<BlendParameter>(parameter));
  225. SaveState();
  226. } else if (mode_ == UI_MODE_QUALITY) {
  227. processor_->set_quality((processor_->quality() + 1) & 3);
  228. SaveState();
  229. } else if (mode_ == UI_MODE_PLAYBACK_MODE) {
  230. uint8_t mode = (processor_->playback_mode() + 1) & 3;
  231. processor_->set_playback_mode(static_cast<PlaybackMode>(mode));
  232. SaveState();
  233. } else if (mode_ == UI_MODE_SAVE || mode_ == UI_MODE_LOAD) {
  234. load_save_location_ = (load_save_location_ + 1) & 3;
  235. } else {
  236. mode_ = UI_MODE_VU_METER;
  237. }
  238. break;
  239. case SWITCH_WRITE:
  240. if (e.data >= kLongPressDuration && switches_.pressed(SWITCH_MODE)) {
  241. press_time_[SWITCH_MODE] = 0;
  242. mode_ = UI_MODE_CALIBRATION_1;
  243. } else if (mode_ == UI_MODE_CALIBRATION_1) {
  244. CalibrateC1();
  245. } else if (mode_ == UI_MODE_CALIBRATION_2) {
  246. CalibrateC3();
  247. } else if (mode_ == UI_MODE_SAVE) {
  248. // Get pointers on data chunks to save.
  249. PersistentBlock blocks[4];
  250. size_t num_blocks = 0;
  251. mode_ = UI_MODE_SAVING;
  252. // Silence the processor during the long erase/write.
  253. processor_->set_silence(true);
  254. system_clock.Delay(5);
  255. processor_->PreparePersistentData();
  256. processor_->GetPersistentData(blocks, &num_blocks);
  257. settings_->SaveSampleMemory(load_save_location_, blocks, num_blocks);
  258. processor_->set_silence(false);
  259. load_save_location_ = (load_save_location_ + 1) & 3;
  260. mode_ = UI_MODE_VU_METER;
  261. } else if (mode_ == UI_MODE_LOAD) {
  262. processor_->LoadPersistentData(settings_->sample_flash_data(
  263. load_save_location_));
  264. load_save_location_ = (load_save_location_ + 1) & 3;
  265. mode_ = UI_MODE_VU_METER;
  266. } else if (e.data >= kLongPressDuration) {
  267. mode_ = UI_MODE_SAVE;
  268. } else {
  269. mode_ = UI_MODE_LOAD;
  270. }
  271. break;
  272. }
  273. }
  274. void Ui::DoEvents() {
  275. while (queue_.available()) {
  276. Event e = queue_.PullEvent();
  277. if (e.control_type == CONTROL_SWITCH) {
  278. if (e.data == 0) {
  279. OnSwitchPressed(e);
  280. } else {
  281. if (e.data >= kLongPressDuration &&
  282. e.control_id == SWITCH_MODE &&
  283. switches_.pressed(SWITCH_WRITE)) {
  284. press_time_[SWITCH_WRITE] = 0;
  285. OnSecretHandshake();
  286. } else {
  287. OnSwitchReleased(e);
  288. }
  289. }
  290. }
  291. }
  292. if (queue_.idle_time() > 1000 && mode_ == UI_MODE_PANIC) {
  293. queue_.Touch();
  294. mode_ = UI_MODE_VU_METER;
  295. }
  296. if ((mode_ == UI_MODE_VU_METER || mode_ == UI_MODE_BLEND_METER ||
  297. mode_ == UI_MODE_BLENDING) && \
  298. cv_scaler_->blend_knob_touched()) {
  299. queue_.Touch();
  300. mode_ = UI_MODE_BLEND_METER;
  301. }
  302. if (queue_.idle_time() > 3000) {
  303. queue_.Touch();
  304. if (mode_ == UI_MODE_BLENDING || mode_ == UI_MODE_QUALITY ||
  305. mode_ == UI_MODE_PLAYBACK_MODE || mode_ == UI_MODE_SAVE ||
  306. mode_ == UI_MODE_LOAD || mode_ == UI_MODE_BLEND_METER ||
  307. mode_ == UI_MODE_SPLASH) {
  308. mode_ = UI_MODE_VU_METER;
  309. }
  310. }
  311. }
  312. uint8_t Ui::HandleFactoryTestingRequest(uint8_t command) {
  313. uint8_t argument = command & 0x1f;
  314. command = command >> 5;
  315. uint8_t reply = 0;
  316. switch (command) {
  317. case FACTORY_TESTING_READ_POT:
  318. case FACTORY_TESTING_READ_CV:
  319. reply = cv_scaler_->adc_value(argument);
  320. break;
  321. case FACTORY_TESTING_READ_GATE:
  322. if (argument <= 2) {
  323. return switches_.pressed(argument);
  324. } else {
  325. return cv_scaler_->gate(argument - 3);
  326. }
  327. break;
  328. case FACTORY_TESTING_SET_BYPASS:
  329. processor_->set_bypass(argument);
  330. break;
  331. case FACTORY_TESTING_CALIBRATE:
  332. if (argument == 0) {
  333. mode_ = UI_MODE_CALIBRATION_1;
  334. } else if (argument == 1) {
  335. CalibrateC1();
  336. } else {
  337. CalibrateC3();
  338. cv_scaler_->set_blend_parameter(static_cast<BlendParameter>(0));
  339. SaveState();
  340. }
  341. break;
  342. }
  343. return reply;
  344. }
  345. } // namespace clouds