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.

432 lines
13KB

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