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