1 // Copyright 2014 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 "warps/ui.h"
30
31 #include <algorithm>
32
33 #include "stmlib/system/system_clock.h"
34 #include "stmlib/dsp/units.h"
35
36 #include "warps/cv_scaler.h"
37
38 namespace warps {
39
40 using namespace std;
41 using namespace stmlib;
42
43 /* static */
44 const uint8_t Ui::palette_[10][3] = {
45 { 0, 192, 64 },
46 { 64, 255, 0 },
47 { 255, 255, 0 },
48 { 255, 64, 0 },
49 { 255, 0, 0 },
50 { 255, 0, 64 },
51 { 255, 0, 255 },
52 { 0, 0, 255 },
53 { 0, 255, 192 },
54 { 0, 255, 192 },
55 };
56
57 /* static */
58 const uint8_t Ui::feature_mode_palette_[10][3] = {
59 { 255, 64, 0 },
60 { 0, 192, 64 },
61 { 255, 0, 64 },
62 { 0, 255, 192 },
63 { 64, 255, 0 },
64 { 0, 0, 255 },
65 { 255, 255, 0 },
66 { 255, 0, 255 },
67 { 0, 255, 192 },
68 { 255, 0, 0 },
69 };
70
71 /* static */
72 const uint8_t Ui::freq_shifter_palette_[10][3] = {
73 { 0, 0, 64 },
74 { 0, 0, 255 },
75 { 0, 255, 192 },
76 { 0, 192, 64 },
77 { 64, 255, 0 },
78 { 255, 255, 0 },
79 { 255, 192, 0 },
80 { 255, 64, 0 },
81 { 255, 0, 0 },
82 { 255, 0, 0 },
83 };
84
85 const float kAlgoChangeThreshold = 0.01f;
86
Init(Settings * settings,CvScaler * cv_scaler,Modulator * modulator)87 void Ui::Init(Settings* settings, CvScaler* cv_scaler, Modulator* modulator) {
88 leds_.Init();
89 switches_.Init();
90
91 mode_ = UI_MODE_NORMAL;
92 settings_ = settings;
93 cv_scaler_ = cv_scaler;
94 modulator_ = modulator;
95
96 modulator_->set_feature_mode(static_cast<FeatureMode>(settings_->state().feature_mode));
97 feature_mode_ = modulator_->feature_mode();
98 carrier_shape_ = settings_->state().carrier_shape;
99 UpdateSettings();
100
101 last_algo_pot_ = 0.0f;
102 feature_mode_changed_ = false;
103 }
104
UpdateSettings()105 void Ui::UpdateSettings() {
106 modulator_->set_feature_mode(static_cast<FeatureMode>(feature_mode_));
107 settings_->mutable_state()->feature_mode = feature_mode_;
108 modulator_->mutable_parameters()->carrier_shape = carrier_shape_;
109 settings_->mutable_state()->carrier_shape = carrier_shape_;
110 }
111
Poll()112 void Ui::Poll() {
113 // Called at 1.6kHz instead of 1kHz, so the "milliseconds" clock actually runs
114 // 1.6x faster. Not a big deal since it is used only for controlling LED
115 // blinking rate and detecting long button presses.
116 system_clock.Tick();
117 switches_.Debounce();
118 if (switches_.just_pressed(0)) {
119 queue_.AddEvent(CONTROL_SWITCH, 0, 0);
120 press_time_ = system_clock.milliseconds();
121 }
122
123 if (switches_.pressed(0) && \
124 press_time_ &&
125 (system_clock.milliseconds() - press_time_) >= 7800) {
126 if (!feature_mode_changed_ && cv_scaler_->ready_for_calibration()) {
127 queue_.AddEvent(CONTROL_SWITCH, 1, 0);
128 press_time_ = 0;
129 }
130 }
131
132 if (switches_.released(0) && press_time_) {
133 queue_.AddEvent(
134 CONTROL_SWITCH,
135 0,
136 system_clock.milliseconds() - press_time_ + 1);
137 }
138
139 bool blink = (system_clock.milliseconds() & 127) > 64;
140 bool slow_blink = (system_clock.milliseconds() & 255) > 128;
141
142 switch (mode_) {
143 case UI_MODE_NORMAL:
144 {
145 uint8_t rgb[3];
146 float zone;
147 const Parameters& p = modulator_->parameters();
148 const uint8_t (*palette)[3];
149
150 switch (modulator_->feature_mode()) {
151 case FEATURE_MODE_META:
152 zone = p.modulation_algorithm;
153 palette = palette_;
154 break;
155
156 default:
157 zone = p.raw_algorithm;
158 palette = freq_shifter_palette_;
159 break;
160 }
161
162 zone *= 8.0f;
163 MAKE_INTEGRAL_FRACTIONAL(zone);
164 int32_t zone_fractional_i = static_cast<int32_t>(
165 zone_fractional * 256.0f);
166 for (int32_t i = 0; i < 3; ++i) {
167 int32_t a = palette[zone_integral][i];
168 int32_t b = palette[zone_integral + 1][i];
169 rgb[i] = a + ((b - a) * zone_fractional_i >> 8);
170 }
171 leds_.set_main(rgb[0], rgb[1], rgb[2]);
172 leds_.set_osc(
173 carrier_shape_ >= 2 ? 255 : 0,
174 carrier_shape_ > 0 && carrier_shape_ <= 2 ? 255 : 0);
175 }
176 break;
177
178 case UI_MODE_FEATURE_SWITCH:
179 {
180 const Parameters& p = modulator_->parameters();
181 if (p.raw_algorithm_pot >= last_algo_pot_ + kAlgoChangeThreshold ||
182 p.raw_algorithm_pot <= last_algo_pot_ - kAlgoChangeThreshold) {
183 feature_mode_changed_ = true;
184 }
185
186 if (feature_mode_changed_) {
187 feature_mode_ = static_cast<uint8_t>(p.raw_algorithm_pot * 8.0f + 0.5f);
188 int8_t ramp = system_clock.milliseconds() & 127;
189 uint8_t tri = (system_clock.milliseconds() & 255) < 128 ?
190 127 + ramp : 255 - ramp;
191 leds_.set_main((feature_mode_palette_[feature_mode_][0] * tri) >> 8,
192 (feature_mode_palette_[feature_mode_][1] * tri) >> 8,
193 (feature_mode_palette_[feature_mode_][2] * tri) >> 8);
194 }
195 }
196 break;
197
198 case UI_MODE_CALIBRATION_C1:
199 leds_.set_main(0, blink ? 255 : 0, blink ? 64 : 0);
200 leds_.set_osc(blink ? 255 : 0, blink ? 255 : 0);
201 break;
202
203 case UI_MODE_CALIBRATION_C3:
204 leds_.set_main(blink ? 255 : 0, 0, blink ? 32 : 0);
205 leds_.set_osc(blink ? 255 : 0, 0);
206 break;
207
208 case UI_MODE_CALIBRATION_LOW:
209 leds_.set_main(slow_blink ? 255 : 0, 0, 0);
210 leds_.set_osc(slow_blink ? 255 : 0, 0);
211 break;
212
213 case UI_MODE_CALIBRATION_HIGH:
214 leds_.set_main(0, slow_blink ? 255 : 0, 0);
215 leds_.set_osc(0, slow_blink ? 255 : 0);
216 break;
217
218 case UI_MODE_CALIBRATION_ERROR:
219 case UI_MODE_PANIC:
220 leds_.set_osc(blink ? 255 : 0, 0);
221 leds_.set_main(blink ? 255 : 0, 0, 0);
222 break;
223 }
224
225 if (modulator_->bypass()) {
226 uint16_t red = system_clock.milliseconds() & 4095;
227 uint16_t green = (system_clock.milliseconds() + 1333) & 4095;
228 uint16_t blue = (system_clock.milliseconds() + 2667) & 4095;
229 green = green < 2048 ? green : 4095 - green;
230 red = red < 2048 ? red : 4095 - red;
231 blue = blue < 2048 ? blue : 4095 - blue;
232 leds_.set_osc(255, 255);
233 leds_.set_main(red >> 3, green >> 3, blue >> 3);
234 }
235 leds_.Write();
236 }
237
OnSwitchPressed(const Event & e)238 void Ui::OnSwitchPressed(const Event& e) {
239 switch (e.control_id) {
240 case 0:
241 switch (mode_) {
242 case UI_MODE_CALIBRATION_C1:
243 CalibrateC1();
244 break;
245 case UI_MODE_CALIBRATION_C3:
246 CalibrateC3();
247 break;
248 case UI_MODE_CALIBRATION_LOW:
249 CalibrateLow();
250 break;
251 case UI_MODE_CALIBRATION_HIGH:
252 CalibrateHigh();
253 break;
254 case UI_MODE_NORMAL:
255 last_algo_pot_ = modulator_->parameters().raw_algorithm_pot;
256 mode_ = UI_MODE_FEATURE_SWITCH;
257 break;
258 default:
259 break;
260 }
261 break;
262
263 case 1:
264 StartCalibration();
265 break;
266
267 case 2:
268 StartNormalizationCalibration();
269 break;
270
271 default:
272 break;
273 }
274 }
275
OnSwitchReleased(const Event & e)276 void Ui::OnSwitchReleased(const Event& e) {
277 switch (e.control_id) {
278 case 0:
279 if (mode_ == UI_MODE_CALIBRATION_C1 ||
280 mode_ == UI_MODE_CALIBRATION_C3 ||
281 mode_ == UI_MODE_CALIBRATION_LOW ||
282 mode_ == UI_MODE_CALIBRATION_HIGH) {
283 CalibrateC1();
284 } else if (mode_ == UI_MODE_CALIBRATION_C3) {
285 CalibrateC3();
286 } else {
287 mode_ = UI_MODE_NORMAL;
288 if (feature_mode_changed_) {
289 feature_mode_changed_ = false;
290 }
291 else {
292 carrier_shape_ = (carrier_shape_ + 1) & 3;
293 }
294 UpdateSettings();
295 settings_->Save();
296 }
297 }
298 }
299
StartCalibration()300 void Ui::StartCalibration() {
301 cv_scaler_->StartCalibration();
302 mode_ = UI_MODE_CALIBRATION_C1;
303 }
304
CalibrateC1()305 void Ui::CalibrateC1() {
306 cv_scaler_->CalibrateC1();
307 cv_scaler_->CalibrateOffsets();
308 mode_ = UI_MODE_CALIBRATION_C3;
309 }
310
CalibrateC3()311 void Ui::CalibrateC3() {
312 if (cv_scaler_->CalibrateC3()) {
313 settings_->Save();
314 mode_ = UI_MODE_NORMAL;
315 } else {
316 mode_ = UI_MODE_CALIBRATION_ERROR;
317 }
318 }
319
StartNormalizationCalibration()320 void Ui::StartNormalizationCalibration() {
321 cv_scaler_->StartNormalizationCalibration();
322 mode_ = UI_MODE_CALIBRATION_LOW;
323 }
324
CalibrateLow()325 void Ui::CalibrateLow() {
326 cv_scaler_->CalibrateLow();
327 mode_ = UI_MODE_CALIBRATION_HIGH;
328 }
329
CalibrateHigh()330 void Ui::CalibrateHigh() {
331 if (cv_scaler_->CalibrateHigh()) {
332 settings_->Save();
333 mode_ = UI_MODE_NORMAL;
334 } else {
335 mode_ = UI_MODE_CALIBRATION_ERROR;
336 }
337
338 }
339
DoEvents()340 void Ui::DoEvents() {
341 while (queue_.available()) {
342 Event e = queue_.PullEvent();
343 if (e.control_type == CONTROL_SWITCH) {
344 if (e.data == 0) {
345 OnSwitchPressed(e);
346 } else {
347 OnSwitchReleased(e);
348 }
349 }
350 }
351 if (mode_ == UI_MODE_CALIBRATION_ERROR) {
352 if (queue_.idle_time() > 6000) {
353 mode_ = UI_MODE_NORMAL;
354 }
355 } else {
356 if (queue_.idle_time() > 1000) {
357 queue_.Touch();
358 }
359 }
360 }
361
HandleFactoryTestingRequest(uint8_t command)362 uint8_t Ui::HandleFactoryTestingRequest(uint8_t command) {
363 uint8_t argument = command & 0x1f;
364 command = command >> 5;
365 uint8_t reply = 0;
366 switch (command) {
367 case FACTORY_TESTING_READ_POT:
368 case FACTORY_TESTING_READ_CV:
369 reply = cv_scaler_->adc_value(argument);
370 break;
371
372 case FACTORY_TESTING_READ_NORMALIZATION:
373 reply = cv_scaler_->normalization(argument);
374 break;
375
376 case FACTORY_TESTING_READ_GATE:
377 return switches_.pressed(argument);
378 break;
379
380 case FACTORY_TESTING_SET_BYPASS:
381 modulator_->set_bypass(argument);
382 break;
383
384 case FACTORY_TESTING_CALIBRATE:
385 {
386 switch (argument) {
387 case 0:
388 StartCalibration();
389 break;
390
391 case 1:
392 CalibrateC1();
393 break;
394
395 case 2:
396 CalibrateC3();
397 break;
398
399 case 3:
400 StartNormalizationCalibration();
401 break;
402
403 case 4:
404 CalibrateLow();
405 break;
406
407 case 5:
408 CalibrateHigh();
409 carrier_shape_ = 0;
410 UpdateSettings();
411 break;
412 }
413 }
414 break;
415 }
416 return reply;
417 }
418
419 } // namespace warps
420