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