|
- // Copyright 2012 Olivier Gillet.
- //
- // Author: Olivier Gillet (olivier@mutable-instruments.net)
- //
- // This program is free software: you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation, either version 3 of the License, or
- // (at your option) any later version.
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // You should have received a copy of the GNU General Public License
- // along with this program. If not, see <http://www.gnu.org/licenses/>.
- //
- // User interface handling.
-
- #include "edges/ui.h"
-
- #include <string.h>
-
- #include "edges/midi_handler.h"
- #include "edges/settings.h"
-
- namespace edges {
-
- const uint16_t kLongPressTime = 600; // ms
-
- using namespace avrlibx;
-
- /* <static> */
- Mode Ui::mode_;
- uint8_t Ui::gate_;
- uint8_t Ui::edited_channel_;
- uint16_t Ui::leds_pwm_counter_;
- uint16_t Ui::switch_time_counter_;
- uint16_t Ui::calibration_cv_[2];
- uint16_t Ui::cv_[2 * kNumChannels];
- uint16_t Ui::root_cv_;
-
- Leds Ui::leds_;
- Switches Ui::switches_;
- Gpio<PortC, 1> Ui::midi_learn_switch_;
- Gpio<PortC, 3> Ui::midi_mode_switch_;
-
- uint8_t Ui::debounce_history_[kNumSwitches];
- /* </static> */
-
- /* static */
- void Ui::Init() {
- leds_.set_direction(OUTPUT);
- switches_.set_direction(INPUT);
- midi_learn_switch_.set_direction(INPUT);
- midi_mode_switch_.set_direction(INPUT);
-
- switches_.set_mode(PORT_MODE_PULL_UP);
- midi_learn_switch_.set_mode(PORT_MODE_PULL_UP);
- midi_mode_switch_.set_mode(PORT_MODE_PULL_UP);
- mode_ = MODE_NORMAL;
- leds_pwm_counter_ = 0;
- edited_channel_ = 0;
- memset(debounce_history_, 0xff, sizeof(debounce_history_));
- memset(cv_, 0, sizeof(cv_));
- }
-
- /* static */
- void Ui::OnSwitchHeld(uint8_t index) {
- if (index < kNumChannels) {
- if (mode_ == MODE_MENU) {
- mode_ = MODE_NORMAL;
- settings.Save();
- } else {
- mode_ = MODE_MENU;
- edited_channel_ = index;
- }
- } else if (index == kNumChannels + 1) {
- midi_handler.DisableMidiCoupling();
- }
- }
-
- /* static */
- void Ui::OnSwitchReleased(uint8_t index) {
- if (index < kNumChannels) {
- switch (mode_) {
- case MODE_MENU:
- switch (index) {
- case 0:
- settings.ToggleQuantizer(edited_channel_);
- break;
-
- case 1:
- settings.ToggleArpeggio(edited_channel_);
- break;
-
- case 2:
- mode_ = MODE_RECORDING;
- root_cv_ = cv_[edited_channel_];
- settings.mutable_channel_data(edited_channel_)->StartRecording();
- break;
-
- case 3:
- mode_ = MODE_CALIBRATE_1;
- break;
- }
- break;
-
- case MODE_NORMAL:
- settings.StepPW(index);
- break;
-
- case MODE_CALIBRATE_1:
- mode_ = MODE_CALIBRATE_2;
- break;
-
- case MODE_CALIBRATE_2:
- settings.Calibrate(
- edited_channel_,
- calibration_cv_[0],
- calibration_cv_[1],
- cv_[edited_channel_ + 4]);
- mode_ = MODE_NORMAL;
- break;
-
- case MODE_RECORDING:
- {
- ChannelData* channel = settings.mutable_channel_data(edited_channel_);
- uint8_t current_step = channel->num_arpeggio_steps - 1;
- if (index == (current_step & 3)) {
- channel->StopRecording();
- settings.Save();
- mode_ = MODE_NORMAL;
- } else if (index == ((current_step + 1) & 3)) {
- if (!channel->NextArpeggiatorStep()) {
- settings.Save();
- mode_ = MODE_NORMAL;
- }
- }
- }
- break;
- }
- } else if (index == kNumChannels) {
- mode_ = MODE_LEARNING_MIDI_CHANNEL;
- midi_handler.Learn();
- } else {
- midi_handler.ToggleMidiMode();
- }
- }
-
- static const uint8_t bit_reverse[] = {
- 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf
- };
-
- /* static */
- void Ui::Poll() {
- ++leds_pwm_counter_;
- ++switch_time_counter_;
-
- // Refresh leds.
- uint8_t leds_value = 0;
- switch (mode_) {
- case MODE_NORMAL:
- leds_value = gate_;
- break;
-
- case MODE_MENU:
- if (settings.quantized(edited_channel_)) {
- leds_value |= 0x1;
- }
- if (settings.arpeggio(edited_channel_)) {
- leds_value |= 0x2;
- }
- if (leds_pwm_counter_ & 128) {
- leds_value |= 0x4;
- } else {
- leds_value |= 0x8;
- }
- break;
-
- case MODE_LEARNING_MIDI_CHANNEL:
- if (leds_pwm_counter_ & 128) {
- leds_value = 0xff;
- }
- if (!midi_handler.learning()) {
- mode_ = MODE_NORMAL;
- }
- break;
-
- case MODE_CALIBRATE_1:
- leds_value |= 0x3;
- break;
-
- case MODE_CALIBRATE_2:
- leds_value |= 0xf;
- break;
-
- case MODE_RECORDING:
- leds_value |= 1 << ((settings.num_steps(edited_channel_) - 1) & 0x03);
- break;
- }
- leds_.set_value(bit_reverse[leds_value & 0xf]);
-
- // Scan switches.
- uint8_t switches_value = bit_reverse[switches_.Read()];
- for (uint8_t i = 0; i < kNumChannels; ++i) {
- debounce_history_[i] = (debounce_history_[i] << 1) | (switches_value & 1);
- switches_value >>= 1;
- }
- debounce_history_[kNumChannels] = \
- (debounce_history_[kNumChannels] << 1) | midi_learn_switch_.value();
- debounce_history_[kNumChannels + 1] = \
- (debounce_history_[kNumChannels + 1] << 1) | midi_mode_switch_.value();
-
- // Trigger switch events.
- for (uint8_t i = 0; i < kNumSwitches; ++i) {
- // When a switch is pressed, start the time counter.
- if (debounce_history_[i] == 0xfe) {
- switch_time_counter_ = 0;
- }
-
- // When a switch is held, enable calibration mode.
- if (debounce_history_[i] == 0x00 &&
- switch_time_counter_ == kLongPressTime) {
- OnSwitchHeld(i);
- }
-
- // When a switch is released, do something depending on the event.
- if (debounce_history_[i] == 0x01 &&
- switch_time_counter_ < kLongPressTime) {
- OnSwitchReleased(i);
- }
- }
-
- // Update arpeggiator pattern.
- if (mode_ == MODE_RECORDING) {
- if (settings.num_steps(edited_channel_) == 1) {
- root_cv_ = cv_[edited_channel_];
- }
- settings.mutable_channel_data(edited_channel_)->UpdateArpeggiatorStep(
- root_cv_,
- cv_[edited_channel_]
- );
- }
- }
-
- /* extern */
- Ui ui;
-
- } // namespace edges
|