| 
							- // Copyright 2014 Olivier Gillet.
 - //
 - // Author: Olivier Gillet (ol.gillet@gmail.com)
 - //
 - // Permission is hereby granted, free of charge, to any person obtaining a copy
 - // of this software and associated documentation files (the "Software"), to deal
 - // in the Software without restriction, including without limitation the rights
 - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 - // copies of the Software, and to permit persons to whom the Software is
 - // furnished to do so, subject to the following conditions:
 - // 
 - // The above copyright notice and this permission notice shall be included in
 - // all copies or substantial portions of the Software.
 - // 
 - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 - // THE SOFTWARE.
 - // 
 - // See http://creativecommons.org/licenses/MIT/ for more information.
 - //
 - // -----------------------------------------------------------------------------
 - //
 - // User interface.
 - 
 - #include "clouds/ui.h"
 - 
 - #include "stmlib/system/system_clock.h"
 - 
 - #include "clouds/dsp/granular_processor.h"
 - #include "clouds/cv_scaler.h"
 - #include "clouds/meter.h"
 - 
 - namespace clouds {
 - 
 - const int32_t kLongPressDuration = 1000;
 - const int32_t kVeryLongPressDuration = 4000;
 - 
 - using namespace stmlib;
 - 
 - void Ui::Init(
 -     Settings* settings,
 -     CvScaler* cv_scaler,
 -     GranularProcessor* processor,
 -     Meter* meter) {
 -   settings_ = settings;
 -   cv_scaler_ = cv_scaler;
 -   leds_.Init();
 -   switches_.Init();
 -   
 -   processor_ = processor;
 -   meter_ = meter;
 -   mode_ = UI_MODE_SPLASH;
 -   
 -   const State& state = settings_->state();
 -   
 -   // Sanitize saved settings.
 -   cv_scaler_->set_blend_parameter(
 -       static_cast<BlendParameter>(state.blend_parameter & 3));
 -   cv_scaler_->MatchKnobPosition();
 -   processor_->set_quality(state.quality & 3);
 -   processor_->set_playback_mode(
 -       static_cast<PlaybackMode>(state.playback_mode & 3));
 -   for (int32_t i = 0; i < BLEND_PARAMETER_LAST; ++i) {
 -     cv_scaler_->set_blend_value(
 -         static_cast<BlendParameter>(i),
 -         static_cast<float>(state.blend_value[i]) / 255.0f);
 -   }
 -   cv_scaler_->UnlockBlendKnob();
 - }
 - 
 - void Ui::SaveState() {
 -   State* state = settings_->mutable_state();
 -   state->blend_parameter = cv_scaler_->blend_parameter();
 -   state->quality = processor_->quality();
 -   state->playback_mode = processor_->playback_mode();
 -   for (int32_t i = 0; i < BLEND_PARAMETER_LAST; ++i) {
 -     state->blend_value[i] = static_cast<uint8_t>(
 -         cv_scaler_->blend_value(static_cast<BlendParameter>(i)) * 255.0f);
 -   }
 -   settings_->Save();
 - }
 - 
 - void Ui::Poll() {
 -   system_clock.Tick();
 -   switches_.Debounce();
 -   
 -   for (uint8_t i = 0; i < kNumSwitches; ++i) {
 -     if (switches_.just_pressed(i)) {
 -       queue_.AddEvent(CONTROL_SWITCH, i, 0);
 -       press_time_[i] = system_clock.milliseconds();
 -       long_press_time_[i] = system_clock.milliseconds();
 -     }
 -     if (switches_.pressed(i) && press_time_[i] != 0) {
 -       int32_t pressed_time = system_clock.milliseconds() - press_time_[i];
 -       if (pressed_time > kLongPressDuration) {
 -         queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
 -         press_time_[i] = 0;
 -       }
 -     }
 -     if (switches_.pressed(i) && long_press_time_[i] != 0) {
 -       int32_t pressed_time = system_clock.milliseconds() - long_press_time_[i];
 -       if (pressed_time > kVeryLongPressDuration) {
 -         queue_.AddEvent(CONTROL_SWITCH, i, pressed_time);
 -         long_press_time_[i] = 0;
 -       }
 -     }
 -     
 -     if (switches_.released(i) && press_time_[i] != 0) {
 -       queue_.AddEvent(
 -           CONTROL_SWITCH,
 -           i,
 -           system_clock.milliseconds() - press_time_[i] + 1);
 -       press_time_[i] = 0;
 -     }
 -   }
 -   PaintLeds();
 - }
 - 
 - void Ui::PaintLeds() {
 -   leds_.Clear();
 -   bool blink = (system_clock.milliseconds() & 127) > 64;
 -   uint8_t fade = system_clock.milliseconds() >> 1;
 -   fade = fade <= 127 ? (fade << 1) : 255 - (fade << 1);
 -   fade = static_cast<uint16_t>(fade) * fade >> 8;
 -   switch (mode_) {
 -     case UI_MODE_SPLASH:
 -       {
 -         uint8_t index = ((system_clock.milliseconds() >> 8) + 1) & 3;
 -         uint8_t fade = (system_clock.milliseconds() >> 2);
 -         fade = fade <= 127 ? (fade << 1) : 255 - (fade << 1);
 -         leds_.set_intensity(3 - index, fade);
 -       }
 -       break;
 -       
 -     case UI_MODE_VU_METER:
 -       leds_.PaintBar(lut_db[meter_->peak() >> 7]);
 -       break;
 -     
 -     case UI_MODE_BLEND_METER:
 -       for (int32_t i = 0; i < 4; ++i) {
 -         leds_.set_intensity(
 -             i,
 -             cv_scaler_->blend_value(static_cast<BlendParameter>(i)) * 255.0f);
 -       }
 -       break;
 -     
 -     case UI_MODE_QUALITY:
 -       leds_.set_status(processor_->quality(), 255, 0);
 -       break;
 -       
 -     case UI_MODE_BLENDING:
 -       leds_.set_status(cv_scaler_->blend_parameter(), 0, 255);
 -       break;
 -       
 -     case UI_MODE_PLAYBACK_MODE:
 -       leds_.set_status(
 -           processor_->playback_mode(),
 -           128 + (fade >> 1),
 -           255 - (fade >> 1));
 -       break;
 -       
 -     case UI_MODE_LOAD:
 -       leds_.set_status(load_save_location_, 0, blink ? 255 : 0);
 -       break;
 - 
 -     case UI_MODE_SAVE:
 -       leds_.set_status(load_save_location_, blink ? 255 : 0, 0);
 -       break;
 -     
 -     case UI_MODE_SAVING:
 -       leds_.set_status(load_save_location_, 255, 0);
 -       break;
 -       
 -     case UI_MODE_CALIBRATION_1:
 -       leds_.set_status(0, blink ? 255 : 0, blink ? 255 : 0);
 -       leds_.set_status(1, blink ? 255 : 0, blink ? 255 : 0);
 -       leds_.set_status(2, 0, 0);
 -       leds_.set_status(3, 0, 0);
 -       break;
 - 
 -     case UI_MODE_CALIBRATION_2:
 -       leds_.set_status(0, blink ? 255 : 0, blink ? 255 : 0);
 -       leds_.set_status(1, blink ? 255 : 0, blink ? 255 : 0);
 -       leds_.set_status(2, blink ? 255 : 0, blink ? 255 : 0);
 -       leds_.set_status(3, blink ? 255 : 0, blink ? 255 : 0);
 -       break;
 -       
 -     case UI_MODE_PANIC:
 -       leds_.set_status(0, 255, 0);
 -       leds_.set_status(1, 255, 0);
 -       leds_.set_status(2, 255, 0);
 -       leds_.set_status(3, 255, 0);
 -       break;
 -       
 -     default:
 -       break;
 -   }
 -   
 -   leds_.set_freeze(processor_->frozen());
 -   if (processor_->bypass()) {
 -     leds_.PaintBar(lut_db[meter_->peak() >> 7]);
 -     leds_.set_freeze(true);
 -   }
 -   
 -   leds_.Write();
 - }
 - 
 - void Ui::FlushEvents() {
 -   queue_.Flush();
 - }
 - 
 - void Ui::OnSwitchPressed(const Event& e) {
 -   if (e.control_id == SWITCH_FREEZE) {
 -     processor_->ToggleFreeze();
 -   }
 - }
 - 
 - void Ui::CalibrateC1() {
 -   cv_scaler_->CalibrateC1();
 -   cv_scaler_->CalibrateOffsets();
 -   mode_ = UI_MODE_CALIBRATION_2;
 - }
 - 
 - void Ui::CalibrateC3() {
 -   bool success = cv_scaler_->CalibrateC3();
 -   if (success) {
 -     settings_->Save();
 -     mode_ = UI_MODE_VU_METER;
 -   } else {
 -     mode_ = UI_MODE_PANIC;
 -   }
 - }
 - 
 - void Ui::OnSecretHandshake() {
 -   mode_ = UI_MODE_PLAYBACK_MODE;
 - }
 - 
 - void Ui::OnSwitchReleased(const Event& e) {
 -   switch (e.control_id) {
 -     case SWITCH_FREEZE:
 -       break;
 - 
 -     case SWITCH_MODE:
 -       if (e.data >= kVeryLongPressDuration) {
 -         mode_ = UI_MODE_PLAYBACK_MODE;
 -       } else if (e.data >= kLongPressDuration) {
 -         if (mode_ == UI_MODE_QUALITY) {
 -           mode_ = UI_MODE_VU_METER;
 -         } else {
 -           mode_ = UI_MODE_QUALITY;
 -         }
 -       } else if (mode_ == UI_MODE_VU_METER || mode_ == UI_MODE_BLEND_METER) {
 -         mode_ = UI_MODE_BLENDING;
 -       } else if (mode_ == UI_MODE_BLENDING) {
 -         uint8_t parameter = (cv_scaler_->blend_parameter() + 1) & 3;
 -         cv_scaler_->set_blend_parameter(static_cast<BlendParameter>(parameter));
 -         SaveState();
 -       } else if (mode_ == UI_MODE_QUALITY) {
 -         processor_->set_quality((processor_->quality() + 1) & 3);
 -         SaveState();
 -       } else if (mode_ == UI_MODE_PLAYBACK_MODE) {
 -         uint8_t mode = (processor_->playback_mode() + 1) & 3;
 -         processor_->set_playback_mode(static_cast<PlaybackMode>(mode));
 -         SaveState();
 -       } else if (mode_ == UI_MODE_SAVE || mode_ == UI_MODE_LOAD) {
 -         load_save_location_ = (load_save_location_ + 1) & 3;
 -       } else {
 -         mode_ = UI_MODE_VU_METER;
 -       }
 -       break;
 - 
 -     case SWITCH_WRITE:
 -       if (e.data >= kLongPressDuration && switches_.pressed(SWITCH_MODE)) {
 -         press_time_[SWITCH_MODE] = 0;
 -         mode_ = UI_MODE_CALIBRATION_1;
 -       } else if (mode_ == UI_MODE_CALIBRATION_1) {
 -         CalibrateC1();
 -       } else if (mode_ == UI_MODE_CALIBRATION_2) {
 -         CalibrateC3();
 -       } else if (mode_ == UI_MODE_SAVE) {
 -         // Get pointers on data chunks to save.
 -         PersistentBlock blocks[4];
 -         size_t num_blocks = 0;
 -         
 -         mode_ = UI_MODE_SAVING;
 -         // Silence the processor during the long erase/write.
 -         processor_->set_silence(true);
 -         system_clock.Delay(5);
 -         processor_->PreparePersistentData();
 -         processor_->GetPersistentData(blocks, &num_blocks);
 -         settings_->SaveSampleMemory(load_save_location_, blocks, num_blocks);
 -         processor_->set_silence(false);
 -         load_save_location_ = (load_save_location_ + 1) & 3;
 -         mode_ = UI_MODE_VU_METER;
 -       } else if (mode_ == UI_MODE_LOAD) {
 -         processor_->LoadPersistentData(settings_->sample_flash_data(
 -             load_save_location_));
 -         load_save_location_ = (load_save_location_ + 1) & 3;
 -         mode_ = UI_MODE_VU_METER;
 -       } else if (e.data >= kLongPressDuration) {
 -         mode_ = UI_MODE_SAVE;
 -       } else {
 -         mode_ = UI_MODE_LOAD;
 -       }
 -       break;
 -   }
 - }
 - 
 - void Ui::DoEvents() {
 -   while (queue_.available()) {
 -     Event e = queue_.PullEvent();
 -     if (e.control_type == CONTROL_SWITCH) {
 -       if (e.data == 0) {
 -         OnSwitchPressed(e);
 -       } else {
 -         if (e.data >= kLongPressDuration &&
 -             e.control_id == SWITCH_MODE && 
 -             switches_.pressed(SWITCH_WRITE)) {
 -           press_time_[SWITCH_WRITE] = 0;
 -           OnSecretHandshake();
 -         } else {
 -           OnSwitchReleased(e);
 -         }
 -       }
 -     }
 -   }
 -   
 -   if (queue_.idle_time() > 1000 && mode_ == UI_MODE_PANIC) {
 -     queue_.Touch();
 -     mode_ = UI_MODE_VU_METER;
 -   }
 -   
 -   if ((mode_ == UI_MODE_VU_METER || mode_ == UI_MODE_BLEND_METER ||
 -        mode_ == UI_MODE_BLENDING) && \
 -       cv_scaler_->blend_knob_touched()) {
 -     queue_.Touch();
 -     mode_ = UI_MODE_BLEND_METER;
 -   }
 -   
 -   if (queue_.idle_time() > 3000) {
 -     queue_.Touch();
 -     if (mode_ == UI_MODE_BLENDING || mode_ == UI_MODE_QUALITY ||
 -         mode_ == UI_MODE_PLAYBACK_MODE || mode_ == UI_MODE_SAVE ||
 -         mode_ == UI_MODE_LOAD || mode_ == UI_MODE_BLEND_METER ||
 -         mode_ == UI_MODE_SPLASH) {
 -       mode_ = UI_MODE_VU_METER;
 -     }
 -   }
 - }
 - 
 - uint8_t Ui::HandleFactoryTestingRequest(uint8_t command) {
 -   uint8_t argument = command & 0x1f;
 -   command = command >> 5;
 -   uint8_t reply = 0;
 -   switch (command) {
 -     case FACTORY_TESTING_READ_POT:
 -     case FACTORY_TESTING_READ_CV:
 -       reply = cv_scaler_->adc_value(argument);
 -       break;
 -       
 -     case FACTORY_TESTING_READ_GATE:
 -       if (argument <= 2) {
 -         return switches_.pressed(argument);
 -       } else {
 -         return cv_scaler_->gate(argument - 3);
 -       }
 -       break;
 -       
 -     case FACTORY_TESTING_SET_BYPASS:
 -       processor_->set_bypass(argument);
 -       break;
 -       
 -     case FACTORY_TESTING_CALIBRATE:
 -       if (argument == 0) {
 -         mode_ = UI_MODE_CALIBRATION_1;
 -       } else if (argument == 1) {
 -         CalibrateC1();
 -       } else {
 -         CalibrateC3();
 -         cv_scaler_->set_blend_parameter(static_cast<BlendParameter>(0));
 -         SaveState();
 -       }
 -       break;
 -   }
 -   return reply;
 - }
 - 
 - }  // namespace clouds
 
 
  |