Files
-
blinds / hardware_design / pcb / blinds_v60.brd
-
blinds / hardware_design / pcb / blinds_v60.sch
-
braids / hardware_design / pcb / braids_v50.brd
-
braids / hardware_design / pcb / braids_v50.sch
-
branches / hardware_design / pcb / branches_v40.brd
-
branches / hardware_design / pcb / branches_v40.sch
-
clouds / hardware_design / pcb / clouds_v30.brd
-
clouds / hardware_design / pcb / clouds_v30.sch
-
ears / hardware_design / panel / ears_panel_v30.brd
-
ears / hardware_design / panel / ears_panel_v30.sch
-
ears / hardware_design / pcb / ears_v40.brd
-
ears / hardware_design / pcb / ears_v40.sch
-
edges / hardware_design / pcb / edges_expander_v01.brd
-
edges / hardware_design / pcb / edges_expander_v01.sch
-
edges / hardware_design / pcb / edges_v20.brd
-
edges / hardware_design / pcb / edges_v20.sch
-
elements / hardware_design / pcb / elements_v02.brd
-
elements / hardware_design / pcb / elements_v02.sch
-
frames / hardware_design / pcb / frames_v03.brd
-
frames / hardware_design / pcb / frames_v03.sch
-
grids / hardware_design / pcb / grids_v02.brd
-
grids / hardware_design / pcb / grids_v02.sch
-
kinks / hardware_design / pcb / kinks_v41.brd
-
kinks / hardware_design / pcb / kinks_v41.sch
-
links / hardware_design / pcb / links_v40.brd
-
links / hardware_design / pcb / links_v40.sch
-
marbles / hardware_design / pcb / marbles_v70.brd
-
marbles / hardware_design / pcb / marbles_v70.sch
-
peaks / hardware_design / pcb / peaks_v30.brd
-
peaks / hardware_design / pcb / peaks_v30.sch
-
plaits / hardware_design / pcb / plaits_v50.brd
-
plaits / hardware_design / pcb / plaits_v50.sch
-
rings / hardware_design / pcb / rings_v30.brd
-
rings / hardware_design / pcb / rings_v30.sch
-
ripples / hardware_design / pcb / ripples_v40.brd
-
ripples / hardware_design / pcb / ripples_v40.sch
-
shades / hardware_design / pcb / shades_v30.brd
-
shades / hardware_design / pcb / shades_v30.sch
-
shelves / hardware_design / pcb / shelves_expander_v10.brd
-
shelves / hardware_design / pcb / shelves_expander_v10.sch
-
shelves / hardware_design / pcb / shelves_v05.brd
-
shelves / hardware_design / pcb / shelves_v05.sch
-
stages / hardware_design / pcb / stages_v70.brd
-
stages / hardware_design / pcb / stages_v70.sch
-
streams / hardware_design / pcb / streams_v02_bargraph.brd
-
streams / hardware_design / pcb / streams_v02_bargraph.sch
-
streams / hardware_design / pcb / streams_v05.brd
-
streams / hardware_design / pcb / streams_v05.sch
-
tides / hardware_design / pcb / tides_v40.brd
-
tides / hardware_design / pcb / tides_v40.sch
-
veils / hardware_design / pcb / veils_v40.brd
-
veils / hardware_design / pcb / veils_v40.sch
-
volts / hardware_design / pcb / volts_v01.brd
-
volts / hardware_design / pcb / volts_v01.sch
-
warps / hardware_design / pcb / warps_v30.brd
-
warps / hardware_design / pcb / warps_v30.sch
-
yarns / hardware_design / pcb / yarns_v03.brd
-
yarns / hardware_design / pcb / yarns_v03.sch
Last update 6 years 1 month
by
Olivier Gillet
Filesclouds | |
---|---|
.. | |
bootloader | |
drivers | |
dsp | |
hardware_design | |
resources | |
test | |
__init__.py | |
clouds.cc | |
cv_scaler.cc | |
cv_scaler.h | |
makefile | |
meter.h | |
resources.cc | |
resources.h | |
settings.cc | |
settings.h | |
ui.cc | |
ui.h |
ui.cc// 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