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