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(¶meters[0], 2);
275 processors[1].CopyParameters(¶meters[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(¶meters[0], 4);
280 processors[1].CopyParameters(¶meters[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