Files

copied
Last update 5 years 8 months
Filesframes
..
bootloader
drivers
hardware_design
resources
__init__.py
frames.cc
keyframer.cc
keyframer.h
makefile
poly_lfo.cc
poly_lfo.h
resources.cc
resources.h
ui.cc
ui.h
ui.cc
// Copyright 2013 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 "frames/ui.h" #include <algorithm> #include "frames/keyframer.h" #include "frames/poly_lfo.h" namespace frames { using namespace std; using namespace stmlib; const uint16_t kAdcThreshold = 1 << (16 - 10); // 10 bits const int32_t kLongPressDuration = 800; const int32_t kVeryLongPressDuration = 3000; const uint16_t kKeyframeGridTolerance = 2048; void Ui::Init(Keyframer* keyframer, PolyLfo* poly_lfo) { factory_testing_switch_.Init(); channel_leds_.Init(); keyframe_led_.Init(); rgb_led_.Init(); switches_.Init(); adc_.Init(false); fill(&adc_value_[0], &adc_value_[kNumAdcChannels], 0); keyframer_ = keyframer; poly_lfo_ = poly_lfo; mode_ = factory_testing_switch_.Read() ? UI_MODE_SPLASH : UI_MODE_FACTORY_TESTING; animation_counter_ = 0; FindNearestKeyframe(); active_keyframe_lock_ = false; uint32_t ui_flags = keyframer_->extra_settings(); poly_lfo_mode_ = ui_flags & 1; sequencer_mode_= ui_flags & 2; secret_handshake_counter_ = 0; } void Ui::TryCalibration() { if (switches_.pressed_immediate(1)) { keyframer_->Calibrate(frame_modulation()); FlushEvents(); } } void Ui::Poll() { 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(); detect_very_long_press_[i] = false; } if (switches_.pressed(i)) { int32_t pressed_time = system_clock.milliseconds() - press_time_[i]; if (!detect_very_long_press_[i]) { if (pressed_time > kLongPressDuration) { queue_.AddEvent(CONTROL_SWITCH, i, pressed_time); detect_very_long_press_[i] = true; } } else { if (pressed_time > kVeryLongPressDuration) { queue_.AddEvent(CONTROL_SWITCH, i, pressed_time); detect_very_long_press_[i] = false; press_time_[i] = 0; } } } if (switches_.released(i) && press_time_[i] != 0 && !detect_very_long_press_[i]) { queue_.AddEvent( CONTROL_SWITCH, i, system_clock.milliseconds() - press_time_[i] + 1); press_time_[i] = 0; detect_very_long_press_[i] = false; } } for (uint8_t i = 0; i <= kFrameAdcChannel; ++i) { int32_t value = (31 * adc_filtered_value_[i] + adc_.value(i)) >> 5; adc_filtered_value_[i] = value; int32_t current_value = static_cast<int32_t>(adc_value_[i]); if (value >= current_value + kAdcThreshold || value <= current_value - kAdcThreshold) { queue_.AddEvent(CONTROL_POT, i, value); adc_value_[i] = value; } } switch (mode_) { case UI_MODE_SPLASH: animation_counter_ += 128; channel_leds_.set_channel(0, (animation_counter_ + 49152) >> 8); channel_leds_.set_channel(1, (animation_counter_ + 32768) >> 8); channel_leds_.set_channel(2, (animation_counter_ + 16384) >> 8); channel_leds_.set_channel(3, (animation_counter_ + 0) >> 8); rgb_led_.set_color(255, 255, 255); break; case UI_MODE_SAVE_CONFIRMATION: animation_counter_ -= 256; channel_leds_.set_channel(0, (animation_counter_ + 0) >> 8); channel_leds_.set_channel(1, (animation_counter_ + 16384) >> 8); channel_leds_.set_channel(2, (animation_counter_ + 32768) >> 8); channel_leds_.set_channel(3, (animation_counter_ + 49152) >> 8); rgb_led_.set_color(0, 255, 0); break; case UI_MODE_ERASE_CONFIRMATION: animation_counter_ -= 256; channel_leds_.set_channel(0, (animation_counter_ + 0) >> 8); channel_leds_.set_channel(1, (animation_counter_ + 16384) >> 8); channel_leds_.set_channel(2, (animation_counter_ + 32768) >> 8); channel_leds_.set_channel(3, (animation_counter_ + 49152) >> 8); rgb_led_.set_color(255, 0, 0); break; case UI_MODE_FACTORY_TESTING: channel_leds_.set_channel(0, keyframer_->level(0) >> 8); channel_leds_.set_channel(1, keyframer_->level(1) >> 8); channel_leds_.set_channel(2, keyframer_->level(2) >> 8); channel_leds_.set_channel(3, keyframer_->level(3) >> 8); if (frame() < 4096) { rgb_led_.set_color(255, 0, 0); } else if (frame() > 61440) { rgb_led_.set_color(0, 255, 0); } else { uint8_t v = frame_modulation() >> 8; rgb_led_.set_color(0, 0, v); } if (test_led_) { keyframe_led_.High(); } else { keyframe_led_.Low(); } break; case UI_MODE_NORMAL: channel_leds_.set_channel(0, keyframer_->level(0) >> 8); channel_leds_.set_channel(1, keyframer_->level(1) >> 8); channel_leds_.set_channel(2, keyframer_->level(2) >> 8); channel_leds_.set_channel(3, keyframer_->level(3) >> 8); rgb_led_.set_color(keyframer_->color()); if (active_keyframe_ == -1) { keyframe_led_.Low(); } else { animation_counter_ += 256; int32_t distance = frame() - \ keyframer_->keyframe(active_keyframe_).timestamp; distance = min(distance * distance >> 18, int32_t(15)); ++keyframe_led_pwm_counter_; if ((keyframe_led_pwm_counter_ & 15) >= distance) { keyframe_led_.High(); } else { keyframe_led_.Low(); } if (active_keyframe_lock_) { if (animation_counter_ & 0x8000) { keyframe_led_.High(); } else { keyframe_led_.Low(); } } } if (poly_lfo_mode_) { channel_leds_.set_channel(0, poly_lfo_->level(0)); channel_leds_.set_channel(1, poly_lfo_->level(1)); channel_leds_.set_channel(2, poly_lfo_->level(2)); channel_leds_.set_channel(3, poly_lfo_->level(3)); rgb_led_.set_color(poly_lfo_->color()); if (poly_lfo_->level(0) > 128) { keyframe_led_.High(); } else { keyframe_led_.Low(); } } break; case UI_MODE_EDIT_RESPONSE: case UI_MODE_EDIT_EASING: { animation_counter_ += 48; for (uint8_t i = 0; i < 4; ++i) { channel_leds_.set_channel(i, active_channel_ == i ? 255 : 0); } if (mode_ == UI_MODE_EDIT_EASING) { rgb_led_.set_color(255, 16, 32); } else { rgb_led_.set_color(16, 192, 32); } uint16_t brightness = active_channel_ == -1 ? 65535 : keyframer_->SampleAnimation(active_channel_, animation_counter_, mode_ == UI_MODE_EDIT_EASING); rgb_led_.Dim(brightness); } break; } rgb_led_.Write(); channel_leds_.Write(); } void Ui::FlushEvents() { queue_.Flush(); } void Ui::OnSwitchPressed(const Event& e) { test_led_ = true; } void Ui::OnSwitchReleased(const Event& e) { if (mode_ == UI_MODE_FACTORY_TESTING) { test_led_ = false; } else { if (active_keyframe_lock_) { active_keyframe_lock_ = false; FindNearestKeyframe(); return; } switch (e.control_id) { case SWITCH_ADD_FRAME: if (e.data > kVeryLongPressDuration) { uint32_t ui_flags = 0; ui_flags |= poly_lfo_mode_ ? 1 : 0; ui_flags |= sequencer_mode_ ? 2 : 0; keyframer_->Save(ui_flags); mode_ = UI_MODE_SAVE_CONFIRMATION; } else if (e.data > kLongPressDuration) { if (!poly_lfo_mode_) { mode_ = UI_MODE_EDIT_EASING; active_channel_ = -1; } } else { if (mode_ == UI_MODE_NORMAL && !poly_lfo_mode_) { if (active_keyframe_ == -1) { keyframer_->AddKeyframe(frame(), &adc_value_[0]); } else { ++secret_handshake_counter_; if (secret_handshake_counter_ >= 5) { sequencer_mode_ = !sequencer_mode_; } // This abandoned feature allowed to select and continue editing // a keyframe with the 4 knobs on the top even when the big // frame knob is being played. For that, we select the keyframe // we are interested in, we press "add", and this "locks" the // 4 pots at the top of the module for editing this keyframe. //active_keyframe_lock_ = true; } FindNearestKeyframe(); } else { mode_ = UI_MODE_NORMAL; } } break; case SWITCH_DELETE_FRAME: if (frame() < 128) { --secret_handshake_counter_; if (secret_handshake_counter_ <= -10) { poly_lfo_mode_ = !poly_lfo_mode_; secret_handshake_counter_ = 0; } } if (e.data > kVeryLongPressDuration) { keyframer_->Clear(); FindNearestKeyframe(); SyncWithPots(); poly_lfo_mode_ = false; mode_ = UI_MODE_ERASE_CONFIRMATION; } else if (e.data > kLongPressDuration) { if (!poly_lfo_mode_) { mode_ = UI_MODE_EDIT_RESPONSE; active_channel_ = -1; } } else { if (mode_ == UI_MODE_NORMAL && !poly_lfo_mode_) { if (active_keyframe_ != -1) { keyframer_->RemoveKeyframe( keyframer_->keyframe(active_keyframe_).timestamp); } FindNearestKeyframe(); SyncWithPots(); } else { mode_ = UI_MODE_NORMAL; } } break; } } } void Ui::OnPotChanged(const Event& e) { if (mode_ == UI_MODE_FACTORY_TESTING) { switch (e.control_id) { case 0: case 1: case 2: case 3: keyframer_->set_immediate(e.control_id, e.data); break; } } else if (poly_lfo_mode_) { switch (e.control_id) { case 0: poly_lfo_->set_shape(e.data); break; case 1: poly_lfo_->set_shape_spread(e.data); break; case 2: poly_lfo_->set_spread(e.data); break; case 3: poly_lfo_->set_coupling(e.data); break; } } else { switch (e.control_id) { case 0: case 1: case 2: case 3: if (mode_ == UI_MODE_NORMAL || mode_ == UI_MODE_SPLASH) { if (active_keyframe_ != -1) { Keyframe* k = keyframer_->mutable_keyframe(active_keyframe_); k->values[e.control_id] = e.data; } else { keyframer_->set_immediate(e.control_id, e.data); } } else if (mode_ == UI_MODE_EDIT_RESPONSE) { active_channel_ = e.control_id; keyframer_->mutable_settings(e.control_id)->response = e.data >> 8; } else if (mode_ == UI_MODE_EDIT_EASING) { active_channel_ = e.control_id; keyframer_->mutable_settings(e.control_id)->easing_curve = \ static_cast<EasingCurve>(e.data * 6 >> 16); } break; case kFrameAdcChannel: if (!active_keyframe_lock_) { FindNearestKeyframe(); } break; case kFrameModulationAdcChannel: break; } } } void Ui::FindNearestKeyframe() { active_keyframe_ = keyframer_->FindNearestKeyframe( frame(), kKeyframeGridTolerance); } void Ui::SyncWithPots() { if (!keyframer_->num_keyframes()) { for (uint8_t i = 0; i < kNumChannels; ++i) { keyframer_->set_immediate(i, adc_filtered_value_[i]); } } } void Ui::DoEvents() { while (queue_.available()) { Event e = queue_.PullEvent(); if (e.control_type == CONTROL_SWITCH) { if (e.data == 0) { OnSwitchPressed(e); } else { OnSwitchReleased(e); } } else if (e.control_type == CONTROL_POT) { OnPotChanged(e); } } if (queue_.idle_time() > 500) { queue_.Touch(); if (mode_ == UI_MODE_SPLASH || mode_ == UI_MODE_SAVE_CONFIRMATION || mode_ == UI_MODE_ERASE_CONFIRMATION) { mode_ = UI_MODE_NORMAL; } secret_handshake_counter_ = 0; } } } // namespace frames
Report a bug