1 // Copyright 2013 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.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
29 #include "frames/ui.h"
30
31 #include <algorithm>
32
33 #include "frames/keyframer.h"
34 #include "frames/poly_lfo.h"
35
36 namespace frames {
37
38 using namespace std;
39 using namespace stmlib;
40
41 const uint16_t kAdcThreshold = 1 << (16 - 10); // 10 bits
42 const int32_t kLongPressDuration = 800;
43 const int32_t kVeryLongPressDuration = 3000;
44 const uint16_t kKeyframeGridTolerance = 2048;
45
Init(Keyframer * keyframer,PolyLfo * poly_lfo)46 void Ui::Init(Keyframer* keyframer, PolyLfo* poly_lfo) {
47 factory_testing_switch_.Init();
48 channel_leds_.Init();
49 keyframe_led_.Init();
50 rgb_led_.Init();
51 switches_.Init();
52 adc_.Init(false);
53
54 fill(&adc_value_[0], &adc_value_[kNumAdcChannels], 0);
55
56 keyframer_ = keyframer;
57 poly_lfo_ = poly_lfo;
58 mode_ = factory_testing_switch_.Read()
59 ? UI_MODE_SPLASH
60 : UI_MODE_FACTORY_TESTING;
61 animation_counter_ = 0;
62
63 FindNearestKeyframe();
64 active_keyframe_lock_ = false;
65
66 uint32_t ui_flags = keyframer_->extra_settings();
67 poly_lfo_mode_ = ui_flags & 1;
68 sequencer_mode_= ui_flags & 2;
69 secret_handshake_counter_ = 0;
70 }
71
TryCalibration()72 void Ui::TryCalibration() {
73 if (switches_.pressed_immediate(1)) {
74 keyframer_->Calibrate(frame_modulation());
75 FlushEvents();
76 }
77 }
78
Poll()79 void Ui::Poll() {
80 switches_.Debounce();
81
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 detect_very_long_press_[i] = false;
87 }
88 if (switches_.pressed(i)) {
89 int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
90
91 if (!detect_very_long_press_[i]) {
92 if (pressed_time > kLongPressDuration) {
93 queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
94 detect_very_long_press_[i] = true;
95 }
96 } else {
97 if (pressed_time > kVeryLongPressDuration) {
98 queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
99 detect_very_long_press_[i] = false;
100 press_time_[i] = 0;
101 }
102 }
103 }
104
105 if (switches_.released(i) &&
106 press_time_[i] != 0 &&
107 !detect_very_long_press_[i]) {
108 queue_.AddEvent(
109 CONTROL_SWITCH,
110 i,
111 system_clock.milliseconds() - press_time_[i] + 1);
112 press_time_[i] = 0;
113 detect_very_long_press_[i] = false;
114 }
115 }
116
117 for (uint8_t i = 0; i <= kFrameAdcChannel; ++i) {
118 int32_t value = (31 * adc_filtered_value_[i] + adc_.value(i)) >> 5;
119 adc_filtered_value_[i] = value;
120 int32_t current_value = static_cast<int32_t>(adc_value_[i]);
121 if (value >= current_value + kAdcThreshold ||
122 value <= current_value - kAdcThreshold) {
123 queue_.AddEvent(CONTROL_POT, i, value);
124 adc_value_[i] = value;
125 }
126 }
127
128 switch (mode_) {
129 case UI_MODE_SPLASH:
130 animation_counter_ += 128;
131 channel_leds_.set_channel(0, (animation_counter_ + 49152) >> 8);
132 channel_leds_.set_channel(1, (animation_counter_ + 32768) >> 8);
133 channel_leds_.set_channel(2, (animation_counter_ + 16384) >> 8);
134 channel_leds_.set_channel(3, (animation_counter_ + 0) >> 8);
135 rgb_led_.set_color(255, 255, 255);
136 break;
137
138 case UI_MODE_SAVE_CONFIRMATION:
139 animation_counter_ -= 256;
140 channel_leds_.set_channel(0, (animation_counter_ + 0) >> 8);
141 channel_leds_.set_channel(1, (animation_counter_ + 16384) >> 8);
142 channel_leds_.set_channel(2, (animation_counter_ + 32768) >> 8);
143 channel_leds_.set_channel(3, (animation_counter_ + 49152) >> 8);
144 rgb_led_.set_color(0, 255, 0);
145 break;
146
147 case UI_MODE_ERASE_CONFIRMATION:
148 animation_counter_ -= 256;
149 channel_leds_.set_channel(0, (animation_counter_ + 0) >> 8);
150 channel_leds_.set_channel(1, (animation_counter_ + 16384) >> 8);
151 channel_leds_.set_channel(2, (animation_counter_ + 32768) >> 8);
152 channel_leds_.set_channel(3, (animation_counter_ + 49152) >> 8);
153 rgb_led_.set_color(255, 0, 0);
154 break;
155
156 case UI_MODE_FACTORY_TESTING:
157 channel_leds_.set_channel(0, keyframer_->level(0) >> 8);
158 channel_leds_.set_channel(1, keyframer_->level(1) >> 8);
159 channel_leds_.set_channel(2, keyframer_->level(2) >> 8);
160 channel_leds_.set_channel(3, keyframer_->level(3) >> 8);
161 if (frame() < 4096) {
162 rgb_led_.set_color(255, 0, 0);
163 } else if (frame() > 61440) {
164 rgb_led_.set_color(0, 255, 0);
165 } else {
166 uint8_t v = frame_modulation() >> 8;
167 rgb_led_.set_color(0, 0, v);
168 }
169 if (test_led_) {
170 keyframe_led_.High();
171 } else {
172 keyframe_led_.Low();
173 }
174 break;
175
176 case UI_MODE_NORMAL:
177 channel_leds_.set_channel(0, keyframer_->level(0) >> 8);
178 channel_leds_.set_channel(1, keyframer_->level(1) >> 8);
179 channel_leds_.set_channel(2, keyframer_->level(2) >> 8);
180 channel_leds_.set_channel(3, keyframer_->level(3) >> 8);
181 rgb_led_.set_color(keyframer_->color());
182 if (active_keyframe_ == -1) {
183 keyframe_led_.Low();
184 } else {
185 animation_counter_ += 256;
186 int32_t distance = frame() - \
187 keyframer_->keyframe(active_keyframe_).timestamp;
188 distance = min(distance * distance >> 18, int32_t(15));
189 ++keyframe_led_pwm_counter_;
190 if ((keyframe_led_pwm_counter_ & 15) >= distance) {
191 keyframe_led_.High();
192 } else {
193 keyframe_led_.Low();
194 }
195 if (active_keyframe_lock_) {
196 if (animation_counter_ & 0x8000) {
197 keyframe_led_.High();
198 } else {
199 keyframe_led_.Low();
200 }
201 }
202 }
203
204 if (poly_lfo_mode_) {
205 channel_leds_.set_channel(0, poly_lfo_->level(0));
206 channel_leds_.set_channel(1, poly_lfo_->level(1));
207 channel_leds_.set_channel(2, poly_lfo_->level(2));
208 channel_leds_.set_channel(3, poly_lfo_->level(3));
209 rgb_led_.set_color(poly_lfo_->color());
210 if (poly_lfo_->level(0) > 128) {
211 keyframe_led_.High();
212 } else {
213 keyframe_led_.Low();
214 }
215 }
216 break;
217
218 case UI_MODE_EDIT_RESPONSE:
219 case UI_MODE_EDIT_EASING:
220 {
221 animation_counter_ += 48;
222 for (uint8_t i = 0; i < 4; ++i) {
223 channel_leds_.set_channel(i, active_channel_ == i ? 255 : 0);
224 }
225 if (mode_ == UI_MODE_EDIT_EASING) {
226 rgb_led_.set_color(255, 16, 32);
227 } else {
228 rgb_led_.set_color(16, 192, 32);
229 }
230 uint16_t brightness = active_channel_ == -1
231 ? 65535
232 : keyframer_->SampleAnimation(active_channel_,
233 animation_counter_,
234 mode_ == UI_MODE_EDIT_EASING);
235 rgb_led_.Dim(brightness);
236 }
237 break;
238 }
239
240 rgb_led_.Write();
241 channel_leds_.Write();
242 }
243
FlushEvents()244 void Ui::FlushEvents() {
245 queue_.Flush();
246 }
247
OnSwitchPressed(const Event & e)248 void Ui::OnSwitchPressed(const Event& e) {
249 test_led_ = true;
250 }
251
OnSwitchReleased(const Event & e)252 void Ui::OnSwitchReleased(const Event& e) {
253 if (mode_ == UI_MODE_FACTORY_TESTING) {
254 test_led_ = false;
255 } else {
256 if (active_keyframe_lock_) {
257 active_keyframe_lock_ = false;
258 FindNearestKeyframe();
259 return;
260 }
261
262 switch (e.control_id) {
263 case SWITCH_ADD_FRAME:
264 if (e.data > kVeryLongPressDuration) {
265 uint32_t ui_flags = 0;
266 ui_flags |= poly_lfo_mode_ ? 1 : 0;
267 ui_flags |= sequencer_mode_ ? 2 : 0;
268 keyframer_->Save(ui_flags);
269 mode_ = UI_MODE_SAVE_CONFIRMATION;
270 } else if (e.data > kLongPressDuration) {
271 if (!poly_lfo_mode_) {
272 mode_ = UI_MODE_EDIT_EASING;
273 active_channel_ = -1;
274 }
275 } else {
276 if (mode_ == UI_MODE_NORMAL && !poly_lfo_mode_) {
277 if (active_keyframe_ == -1) {
278 keyframer_->AddKeyframe(frame(), &adc_value_[0]);
279 } else {
280 ++secret_handshake_counter_;
281 if (secret_handshake_counter_ >= 5) {
282 sequencer_mode_ = !sequencer_mode_;
283 }
284 // This abandoned feature allowed to select and continue editing
285 // a keyframe with the 4 knobs on the top even when the big
286 // frame knob is being played. For that, we select the keyframe
287 // we are interested in, we press "add", and this "locks" the
288 // 4 pots at the top of the module for editing this keyframe.
289 //active_keyframe_lock_ = true;
290 }
291 FindNearestKeyframe();
292 } else {
293 mode_ = UI_MODE_NORMAL;
294 }
295 }
296 break;
297
298 case SWITCH_DELETE_FRAME:
299 if (frame() < 128) {
300 --secret_handshake_counter_;
301 if (secret_handshake_counter_ <= -10) {
302 poly_lfo_mode_ = !poly_lfo_mode_;
303 secret_handshake_counter_ = 0;
304 }
305 }
306 if (e.data > kVeryLongPressDuration) {
307 keyframer_->Clear();
308 FindNearestKeyframe();
309 SyncWithPots();
310 poly_lfo_mode_ = false;
311 mode_ = UI_MODE_ERASE_CONFIRMATION;
312 } else if (e.data > kLongPressDuration) {
313 if (!poly_lfo_mode_) {
314 mode_ = UI_MODE_EDIT_RESPONSE;
315 active_channel_ = -1;
316 }
317 } else {
318 if (mode_ == UI_MODE_NORMAL && !poly_lfo_mode_) {
319 if (active_keyframe_ != -1) {
320 keyframer_->RemoveKeyframe(
321 keyframer_->keyframe(active_keyframe_).timestamp);
322 }
323 FindNearestKeyframe();
324 SyncWithPots();
325 } else {
326 mode_ = UI_MODE_NORMAL;
327 }
328 }
329 break;
330 }
331 }
332 }
333
334
OnPotChanged(const Event & e)335 void Ui::OnPotChanged(const Event& e) {
336 if (mode_ == UI_MODE_FACTORY_TESTING) {
337 switch (e.control_id) {
338 case 0:
339 case 1:
340 case 2:
341 case 3:
342 keyframer_->set_immediate(e.control_id, e.data);
343 break;
344 }
345 } else if (poly_lfo_mode_) {
346 switch (e.control_id) {
347 case 0:
348 poly_lfo_->set_shape(e.data);
349 break;
350 case 1:
351 poly_lfo_->set_shape_spread(e.data);
352 break;
353 case 2:
354 poly_lfo_->set_spread(e.data);
355 break;
356 case 3:
357 poly_lfo_->set_coupling(e.data);
358 break;
359 }
360 } else {
361 switch (e.control_id) {
362 case 0:
363 case 1:
364 case 2:
365 case 3:
366 if (mode_ == UI_MODE_NORMAL || mode_ == UI_MODE_SPLASH) {
367 if (active_keyframe_ != -1) {
368 Keyframe* k = keyframer_->mutable_keyframe(active_keyframe_);
369 k->values[e.control_id] = e.data;
370 } else {
371 keyframer_->set_immediate(e.control_id, e.data);
372 }
373 } else if (mode_ == UI_MODE_EDIT_RESPONSE) {
374 active_channel_ = e.control_id;
375 keyframer_->mutable_settings(e.control_id)->response = e.data >> 8;
376 } else if (mode_ == UI_MODE_EDIT_EASING) {
377 active_channel_ = e.control_id;
378 keyframer_->mutable_settings(e.control_id)->easing_curve = \
379 static_cast<EasingCurve>(e.data * 6 >> 16);
380 }
381 break;
382
383 case kFrameAdcChannel:
384 if (!active_keyframe_lock_) {
385 FindNearestKeyframe();
386 }
387 break;
388
389 case kFrameModulationAdcChannel:
390 break;
391 }
392 }
393 }
394
FindNearestKeyframe()395 void Ui::FindNearestKeyframe() {
396 active_keyframe_ = keyframer_->FindNearestKeyframe(
397 frame(),
398 kKeyframeGridTolerance);
399 }
400
SyncWithPots()401 void Ui::SyncWithPots() {
402 if (!keyframer_->num_keyframes()) {
403 for (uint8_t i = 0; i < kNumChannels; ++i) {
404 keyframer_->set_immediate(i, adc_filtered_value_[i]);
405 }
406 }
407 }
408
DoEvents()409 void Ui::DoEvents() {
410 while (queue_.available()) {
411 Event e = queue_.PullEvent();
412 if (e.control_type == CONTROL_SWITCH) {
413 if (e.data == 0) {
414 OnSwitchPressed(e);
415 } else {
416 OnSwitchReleased(e);
417 }
418 } else if (e.control_type == CONTROL_POT) {
419 OnPotChanged(e);
420 }
421 }
422 if (queue_.idle_time() > 500) {
423 queue_.Touch();
424 if (mode_ == UI_MODE_SPLASH
425 || mode_ == UI_MODE_SAVE_CONFIRMATION
426 || mode_ == UI_MODE_ERASE_CONFIRMATION) {
427 mode_ = UI_MODE_NORMAL;
428 }
429 secret_handshake_counter_ = 0;
430 }
431 }
432
433 } // namespace frames
434