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