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 "peaks/ui.h"
30 
31 #include "stmlib/system/storage.h"
32 
33 #include <algorithm>
34 
35 #include "peaks/calibration_data.h"
36 
37 namespace peaks {
38 
39 using namespace std;
40 using namespace stmlib;
41 
42 const uint16_t kAdcThresholdUnlocked = 1 << (16 - 10);  // 10 bits
43 const uint16_t kAdcThresholdLocked = 1 << (16 - 8);  // 8 bits
44 const int32_t kLongPressDuration = 600;
45 
46 /* static */
47 const ProcessorFunction Ui::function_table_[FUNCTION_LAST][2] = {
48   { PROCESSOR_FUNCTION_ENVELOPE, PROCESSOR_FUNCTION_ENVELOPE },
49   { PROCESSOR_FUNCTION_LFO, PROCESSOR_FUNCTION_LFO },
50   { PROCESSOR_FUNCTION_TAP_LFO, PROCESSOR_FUNCTION_TAP_LFO },
51   { PROCESSOR_FUNCTION_BASS_DRUM, PROCESSOR_FUNCTION_SNARE_DRUM },
52 
53   { PROCESSOR_FUNCTION_MINI_SEQUENCER, PROCESSOR_FUNCTION_MINI_SEQUENCER },
54   { PROCESSOR_FUNCTION_PULSE_SHAPER, PROCESSOR_FUNCTION_PULSE_SHAPER },
55   { PROCESSOR_FUNCTION_PULSE_RANDOMIZER, PROCESSOR_FUNCTION_PULSE_RANDOMIZER },
56   { PROCESSOR_FUNCTION_FM_DRUM, PROCESSOR_FUNCTION_FM_DRUM },
57 };
58 
59 Storage<0x8020000, 16> storage;
60 
Init(CalibrationData * calibration_data)61 void Ui::Init(CalibrationData* calibration_data) {
62   calibration_data_ = calibration_data;
63 
64   leds_.Init();
65   switches_.Init();
66   adc_.Init();
67   system_clock.Tick();
68 
69   fill(&adc_lp_[0], &adc_lp_[kNumAdcChannels], 0);
70   fill(&adc_value_[0], &adc_value_[kNumAdcChannels], 0);
71   fill(&adc_threshold_[0], &adc_threshold_[kNumAdcChannels], 0);
72   fill(&snapped_[0], &snapped_[kNumAdcChannels], false);
73   panel_gate_state_ = 0;
74 
75   calibrating_ = switches_.pressed_immediate(1);
76 
77   if (!storage.ParsimoniousLoad(&settings_, &version_token_)) {
78     edit_mode_ = EDIT_MODE_TWIN;
79     function_[0] = FUNCTION_ENVELOPE;
80     function_[1] = FUNCTION_ENVELOPE;
81     settings_.snap_mode = false;
82   } else {
83     edit_mode_ = static_cast<EditMode>(settings_.edit_mode);
84     function_[0] = static_cast<Function>(settings_.function[0]);
85     function_[1] = static_cast<Function>(settings_.function[1]);
86     copy(&settings_.pot_value[0], &settings_.pot_value[8], &pot_value_[0]);
87 
88     if (edit_mode_ == EDIT_MODE_FIRST || edit_mode_ == EDIT_MODE_SECOND) {
89       LockPots();
90       for (uint8_t i = 0; i < 4; ++i) {
91         processors[0].set_parameter(
92             i,
93             static_cast<uint16_t>(pot_value_[i]) << 8);
94         processors[1].set_parameter(
95             i,
96             static_cast<uint16_t>(pot_value_[i + 4]) << 8);
97       }
98     }
99   }
100 
101   if (switches_.pressed_immediate(SWITCH_TWIN_MODE)) {
102     settings_.snap_mode = !settings_.snap_mode;
103     SaveState();
104   }
105 
106   ChangeControlMode();
107   SetFunction(0, function_[0]);
108   SetFunction(1, function_[1]);
109   double_press_counter_ = 0;
110 }
111 
LockPots()112 void Ui::LockPots() {
113   fill(
114       &adc_threshold_[0],
115       &adc_threshold_[kNumAdcChannels],
116       kAdcThresholdLocked);
117   fill(&snapped_[0], &snapped_[kNumAdcChannels], false);
118 }
119 
SaveState()120 void Ui::SaveState() {
121   settings_.edit_mode = edit_mode_;
122   settings_.function[0] = function_[0];
123   settings_.function[1] = function_[1];
124   copy(&pot_value_[0], &pot_value_[8], &settings_.pot_value[0]);
125   storage.ParsimoniousSave(settings_, &version_token_);
126 }
127 
RefreshLeds()128 inline void Ui::RefreshLeds() {
129   if (calibrating_) {
130     leds_.set_pattern(0xf);
131     leds_.set_twin_mode(true);
132     leds_.set_levels(0, 0);
133     return;
134   }
135 
136   uint8_t flash = (system_clock.milliseconds() >> 7) & 7;
137   switch (edit_mode_) {
138     case EDIT_MODE_FIRST:
139       leds_.set_twin_mode(flash == 1);
140       break;
141     case EDIT_MODE_SECOND:
142       leds_.set_twin_mode(flash == 1 || flash == 3);
143       break;
144     default:
145       leds_.set_twin_mode(edit_mode_ & 1);
146       break;
147   }
148   if ((system_clock.milliseconds() & 256) &&
149       function() >= FUNCTION_FIRST_ALTERNATE_FUNCTION) {
150     leds_.set_function(4);
151   } else {
152     leds_.set_function(function() & 3);
153   }
154 
155   uint8_t b[2];
156   for (uint8_t i = 0; i < 2; ++i) {
157     switch (function_[i]) {
158       case FUNCTION_DRUM_GENERATOR:
159       case FUNCTION_FM_DRUM_GENERATOR:
160         b[i] = abs(brightness_[i]) >> 8;
161         b[i] = b[i] > 255 ? 255 : b[i];
162         break;
163       case FUNCTION_LFO:
164       case FUNCTION_TAP_LFO:
165       case FUNCTION_MINI_SEQUENCER:
166         {
167           int32_t brightness = int32_t(brightness_[i]) * 409 >> 8;
168           brightness += 32768;
169           brightness >>= 8;
170           CONSTRAIN(brightness, 0, 255);
171           b[i] = brightness;
172         }
173         break;
174       default:
175         b[i] = brightness_[i] >> 7;
176         break;
177     }
178   }
179 
180   if (processors[0].function() == PROCESSOR_FUNCTION_NUMBER_STATION) {
181     leds_.set_pattern(
182         processors[0].number_station().digit() ^ \
183         processors[1].number_station().digit());
184     b[0] = processors[0].number_station().gate() ? 255 : 0;
185     b[1] = processors[1].number_station().gate() ? 255 : 0;
186   }
187 
188   leds_.set_levels(b[0], b[1]);
189 }
190 
PollPots()191 void Ui::PollPots() {
192   for (uint8_t i = 0; i < kNumAdcChannels; ++i) {
193     adc_lp_[i] = (int32_t(adc_.value(i)) + adc_lp_[i] * 7) >> 3;
194     int32_t value = adc_lp_[i];
195     int32_t current_value = adc_value_[i];
196     if (value >= current_value + adc_threshold_[i] ||
197         value <= current_value - adc_threshold_[i] ||
198         !adc_threshold_[i]) {
199       Event e;
200       e.control_id = i;
201       e.data = value;
202       OnPotChanged(e);
203       adc_value_[i] = value;
204       adc_threshold_[i] = kAdcThresholdUnlocked;
205     }
206   }
207 }
208 
Poll()209 void Ui::Poll() {
210   system_clock.Tick();
211   switches_.Debounce();
212   for (uint8_t i = 0; i < kNumSwitches; ++i) {
213     if (switches_.just_pressed(i)) {
214       queue_.AddEvent(CONTROL_SWITCH, i, 0);
215       press_time_[i] = system_clock.milliseconds();
216     }
217     if (switches_.pressed(i) && press_time_[i] != 0 && i < SWITCH_GATE_TRIG_1) {
218       int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
219       if (pressed_time > kLongPressDuration) {
220         if (switches_.pressed(1 - i)) {
221           ++double_press_counter_;
222           press_time_[0] = press_time_[1] = 0;
223           if (double_press_counter_ == 3) {
224             double_press_counter_ = 0;
225             processors[0].set_function(PROCESSOR_FUNCTION_NUMBER_STATION);
226             processors[1].set_function(PROCESSOR_FUNCTION_NUMBER_STATION);
227           }
228         } else {
229           queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
230           press_time_[i] = 0;  // Inhibit next release event
231         }
232       }
233     }
234     if (switches_.released(i) && press_time_[i] != 0) {
235       queue_.AddEvent(
236           CONTROL_SWITCH,
237           i,
238           system_clock.milliseconds() - press_time_[i] + 1);
239     }
240   }
241 
242   RefreshLeds();
243   leds_.Write();
244 }
245 
FlushEvents()246 void Ui::FlushEvents() {
247   queue_.Flush();
248 }
249 
OnSwitchPressed(const Event & e)250 void Ui::OnSwitchPressed(const Event& e) {
251   switch (e.control_id) {
252     case SWITCH_TWIN_MODE:
253       break;
254 
255     case SWITCH_FUNCTION:
256       break;
257 
258     case SWITCH_GATE_TRIG_1:
259       panel_gate_control_[0] = true;
260       break;
261 
262     case SWITCH_GATE_TRIG_2:
263       panel_gate_control_[1] = true;
264       break;
265   }
266 }
267 
ChangeControlMode()268 void Ui::ChangeControlMode() {
269   uint16_t parameters[4];
270   for (int i = 0; i < 4; ++i) {
271     parameters[i] = adc_value_[i];
272   }
273   if (edit_mode_ == EDIT_MODE_SPLIT) {
274     processors[0].CopyParameters(&parameters[0], 2);
275     processors[1].CopyParameters(&parameters[2], 2);
276     processors[0].set_control_mode(CONTROL_MODE_HALF);
277     processors[1].set_control_mode(CONTROL_MODE_HALF);
278   } else if (edit_mode_ == EDIT_MODE_TWIN) {
279     processors[0].CopyParameters(&parameters[0], 4);
280     processors[1].CopyParameters(&parameters[0], 4);
281     processors[0].set_control_mode(CONTROL_MODE_FULL);
282     processors[1].set_control_mode(CONTROL_MODE_FULL);
283   } else {
284     processors[0].set_control_mode(CONTROL_MODE_FULL);
285     processors[1].set_control_mode(CONTROL_MODE_FULL);
286   }
287 }
288 
SetFunction(uint8_t index,Function f)289 void Ui::SetFunction(uint8_t index, Function f) {
290   if (edit_mode_ == EDIT_MODE_SPLIT || edit_mode_ == EDIT_MODE_TWIN) {
291     function_[0] = function_[1] = f;
292     processors[0].set_function(function_table_[f][0]);
293     processors[1].set_function(function_table_[f][1]);
294   } else {
295     function_[index] = f;
296     processors[index].set_function(function_table_[f][index]);
297   }
298 }
299 
OnSwitchReleased(const Event & e)300 void Ui::OnSwitchReleased(const Event& e) {
301   if (calibrating_) {
302     if (e.control_id == SWITCH_TWIN_MODE) {
303       // Save calibration.
304       calibration_data_->Save();
305 
306       // Reset all settings to defaults.
307       edit_mode_ = EDIT_MODE_TWIN;
308       function_[0] = FUNCTION_ENVELOPE;
309       function_[1] = FUNCTION_ENVELOPE;
310       settings_.snap_mode = false;
311 
312       SaveState();
313       ChangeControlMode();
314       SetFunction(0, function_[0]);
315       SetFunction(1, function_[1]);
316 
317       // Done with calibration.
318       calibrating_ = false;
319     }
320     return;
321   }
322 
323   switch (e.control_id) {
324     case SWITCH_TWIN_MODE:
325       if (e.data > kLongPressDuration) {
326         edit_mode_ = static_cast<EditMode>(
327             (edit_mode_ + EDIT_MODE_FIRST) % EDIT_MODE_LAST);
328         function_[0] = function_[1];
329         processors[0].set_function(function_table_[function_[0]][0]);
330         processors[1].set_function(function_table_[function_[0]][1]);
331         LockPots();
332       } else {
333         if (edit_mode_ <= EDIT_MODE_SPLIT) {
334           edit_mode_ = static_cast<EditMode>(EDIT_MODE_SPLIT - edit_mode_);
335         } else {
336           edit_mode_ = static_cast<EditMode>(EDIT_MODE_SECOND - (edit_mode_ & 1));
337           LockPots();
338         }
339       }
340 
341       ChangeControlMode();
342       SaveState();
343       break;
344 
345     case SWITCH_FUNCTION:
346       {
347         Function f = function();
348         if (e.data > kLongPressDuration) {
349           f = static_cast<Function>((f + FUNCTION_FIRST_ALTERNATE_FUNCTION) % FUNCTION_LAST);
350         } else {
351           if (f <= FUNCTION_DRUM_GENERATOR) {
352             f = static_cast<Function>((f + 1) & 3);
353           } else {
354             f = static_cast<Function>(((f + 1) & 3) + FUNCTION_FIRST_ALTERNATE_FUNCTION);
355           }
356         }
357         SetFunction(edit_mode_ - EDIT_MODE_FIRST, f);
358         SaveState();
359       }
360       break;
361 
362     case SWITCH_GATE_TRIG_1:
363       panel_gate_control_[0] = false;
364       break;
365 
366     case SWITCH_GATE_TRIG_2:
367       panel_gate_control_[1] = false;
368       break;
369   }
370 }
371 
OnPotChanged(const Event & e)372 void Ui::OnPotChanged(const Event& e) {
373   if (calibrating_) {
374     pot_value_[e.control_id] = e.data >> 8;
375     for (uint8_t i = 0; i < 2; ++i) {
376       int32_t coarse = pot_value_[i * 2];
377       int32_t fine = pot_value_[i * 2 + 1];
378       int32_t offset = ((coarse - 128) << 3) + ((fine - 128) >> 1);
379       calibration_data_->set_dac_offset(i, -offset);
380     }
381     return;
382   }
383 
384   switch (edit_mode_) {
385     case EDIT_MODE_TWIN:
386       processors[0].set_parameter(e.control_id, e.data);
387       processors[1].set_parameter(e.control_id, e.data);
388       pot_value_[e.control_id] = e.data >> 8;
389       break;
390     case EDIT_MODE_SPLIT:
391       if (e.control_id < 2) {
392         processors[0].set_parameter(e.control_id, e.data);
393       } else {
394         processors[1].set_parameter(e.control_id - 2, e.data);
395       }
396       pot_value_[e.control_id] = e.data >> 8;
397       break;
398     case EDIT_MODE_FIRST:
399     case EDIT_MODE_SECOND:
400       {
401         uint8_t index = e.control_id + (edit_mode_ - EDIT_MODE_FIRST) * 4;
402         Processors* p = &processors[edit_mode_ - EDIT_MODE_FIRST];
403 
404         int16_t delta = static_cast<int16_t>(pot_value_[index]) - \
405             static_cast<int16_t>(e.data >> 8);
406         if (delta < 0) {
407           delta = -delta;
408         }
409 
410         if (!settings_.snap_mode || snapped_[e.control_id] || delta <= 2) {
411           p->set_parameter(e.control_id, e.data);
412           pot_value_[index] = e.data >> 8;
413           snapped_[e.control_id] = true;
414         }
415       }
416       break;
417     case EDIT_MODE_LAST:
418       break;
419   }
420 }
421 
DoEvents()422 void Ui::DoEvents() {
423   while (queue_.available()) {
424     Event e = queue_.PullEvent();
425     if (e.control_type == CONTROL_SWITCH) {
426       if (e.data == 0) {
427         OnSwitchPressed(e);
428       } else {
429         OnSwitchReleased(e);
430       }
431     } else if (e.control_type == CONTROL_POT) {
432       OnPotChanged(e);
433     }
434   }
435   if (queue_.idle_time() > 1000) {
436     queue_.Touch();
437   }
438 }
439 
440 }  // namespace peaks
441