Deluge Firmware 1.3.0
Build date: 2026.03.02
Loading...
Searching...
No Matches
follow_channel.h
1/*
2 * Copyright (c) 2014-2023 Synthstrom Audible Limited
3 *
4 * This file is part of The Synthstrom Audible Deluge Firmware.
5 *
6 * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software Foundation,
8 * either version 3 of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
11 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * See the GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along with this program.
15 * If not, see <https://www.gnu.org/licenses/>.
16 */
17#pragma once
18#include "gui/menu_item/integer.h"
19#include "gui/ui/sound_editor.h"
20#include "hid/display/oled.h"
21#include "io/midi/midi_engine.h"
22
23class MIDICable;
24
25namespace deluge::gui::menu_item::midi {
26class FollowChannel final : public Integer {
27public:
28 using Integer::Integer;
29
30 FollowChannel(l10n::String newName, l10n::String title, MIDIFollowChannelType type)
31 : Integer(newName, title), channelType(type),
32 midiInput(midiEngine.midiFollowChannelType[util::to_underlying(type)]) {}
33
34 void readCurrentValue() override { this->setValue(midiInput.channelOrZone); }
35 void writeCurrentValue() override { midiInput.channelOrZone = this->getValue(); }
36 [[nodiscard]] int32_t getMaxValue() const override { return NUM_CHANNELS; }
37 bool allowsLearnMode() override { return true; }
38
39 void drawInteger(int32_t textWidth, int32_t textHeight, int32_t yPixel) override {
40 deluge::hid::display::oled_canvas::Canvas& canvas = hid::display::OLED::main;
41
42 yPixel = 20;
43
44 char const* differentiationString;
45 if (MIDIDeviceManager::differentiatingInputsByDevice) {
46 differentiationString = l10n::get(l10n::String::STRING_FOR_INPUT_DIFFERENTIATION_ON);
47 }
48 else {
49 differentiationString = l10n::get(l10n::String::STRING_FOR_INPUT_DIFFERENTIATION_OFF);
50 }
51 canvas.drawString(differentiationString, 0, yPixel, kTextSpacingX, kTextSizeYUpdated);
52
53 yPixel += kTextSpacingY;
54
55 char const* deviceString = l10n::get(l10n::String::STRING_FOR_FOLLOW_DEVICE_UNASSIGNED);
56 if (midiInput.cable) {
57 deviceString = midiInput.cable->getDisplayName();
58 }
59 canvas.drawString(deviceString, 0, yPixel, kTextSpacingX, kTextSizeYUpdated);
60 deluge::hid::display::OLED::setupSideScroller(0, deviceString, kTextSpacingX, OLED_MAIN_WIDTH_PIXELS, yPixel,
61 yPixel + 8, kTextSpacingX, kTextSpacingY, false);
62
63 yPixel += kTextSpacingY;
64
65 char const* channelText;
66 if (this->getValue() == MIDI_CHANNEL_MPE_LOWER_ZONE) {
67 channelText = l10n::get(l10n::String::STRING_FOR_MPE_LOWER_ZONE);
68 }
69 else if (this->getValue() == MIDI_CHANNEL_MPE_UPPER_ZONE) {
70 channelText = l10n::get(l10n::String::STRING_FOR_MPE_UPPER_ZONE);
71 }
72 else if (this->getValue() == MIDI_CHANNEL_NONE) {
73 channelText = l10n::get(l10n::String::STRING_FOR_FOLLOW_CHANNEL_UNASSIGNED);
74 }
75 else {
76 channelText = l10n::get(l10n::String::STRING_FOR_CHANNEL);
77 char buffer[12];
78 int32_t channelmod = (midiInput.channelOrZone >= IS_A_CC) * IS_A_CC;
79 intToString(midiInput.channelOrZone + 1 - channelmod, buffer, 1);
80 canvas.drawString(buffer, kTextSpacingX * 8, yPixel, kTextSpacingX, kTextSizeYUpdated);
81 }
82 canvas.drawString(channelText, 0, yPixel, kTextSpacingX, kTextSizeYUpdated);
83 }
84
85 void drawValue() override {
86 if (this->getValue() == MIDI_CHANNEL_MPE_LOWER_ZONE) {
87 display->setText(l10n::get(l10n::String::STRING_FOR_MPE_LOWER_ZONE));
88 }
89 else if (this->getValue() == MIDI_CHANNEL_MPE_UPPER_ZONE) {
90 display->setText(l10n::get(l10n::String::STRING_FOR_MPE_UPPER_ZONE));
91 }
92 else if (this->getValue() == MIDI_CHANNEL_NONE) {
93 display->setText(l10n::get(l10n::String::STRING_FOR_NONE));
94 }
95 else {
96 display->setTextAsNumber(this->getValue() + 1);
97 }
98 }
99
100 void selectEncoderAction(int32_t offset) override {
101 if (this->getValue() == MIDI_CHANNEL_NONE) {
102 if (offset > 0) {
103 this->setValue(0);
104 }
105 else if (offset < 0) {
106 this->setValue(MIDI_CHANNEL_MPE_UPPER_ZONE);
107 }
108 }
109 else {
110 this->setValue(this->getValue() + offset);
111 if ((this->getValue() >= NUM_CHANNELS) || (this->getValue() < 0)) {
112 this->setValue(MIDI_CHANNEL_NONE);
113 midiInput.clear();
114 renderDisplay();
115 return;
116 }
117 }
119 }
120
122 this->setValue(MIDI_CHANNEL_NONE);
123 midiInput.clear();
124 if (soundEditor.getCurrentMenuItem() == this) {
125 renderDisplay();
126 }
127 else {
128 display->displayPopup(l10n::get(l10n::String::STRING_FOR_UNLEARNED));
129 }
130 }
131
132 bool learnNoteOn(MIDICable& cable, int32_t channel, int32_t noteCode) {
133 this->setValue(channel);
134 midiInput.cable = &cable;
135 midiInput.channelOrZone = channel;
136
137 if (soundEditor.getCurrentMenuItem() == this) {
138 renderDisplay();
139 }
140 else {
141 display->displayPopup(l10n::get(l10n::String::STRING_FOR_LEARNED));
142 }
143
144 return true;
145 }
146
147 void learnCC(MIDICable& cable, int32_t channel, int32_t ccNumber, int32_t value) {
148 this->setValue(channel);
149 midiInput.cable = &cable;
150 midiInput.channelOrZone = channel;
151
152 if (soundEditor.getCurrentMenuItem() == this) {
153 renderDisplay();
154 }
155 else {
156 display->displayPopup(l10n::get(l10n::String::STRING_FOR_LEARNED));
157 }
158 }
159
160 void renderDisplay() {
161 if (display->haveOLED()) {
162 renderUIsForOled();
163 }
164 else {
165 drawValue();
166 }
167 }
168
169private:
170 MIDIFollowChannelType channelType;
171 LearnedMIDI& midiInput;
172};
173} // namespace deluge::gui::menu_item::midi
A MIDI cable connection. Stores all state specific to a given cable and its contained ports and chann...
Definition midi_device.h:96
deluge::l10n::String title
Can get overridden by getTitle(). Actual max num chars for OLED display is 14.
Definition menu_item.h:222
virtual void selectEncoderAction(int32_t offset)
Handle select encoder movement.
Definition menu_item.h:92
Definition integer.h:24
void readCurrentValue() override
Like readValueAgain, but does not redraw.
Definition follow_channel.h:34
void selectEncoderAction(int32_t offset) override
Handle select encoder movement.
Definition follow_channel.h:100
bool allowsLearnMode() override
Used by SoundEditor to determine if the current menu item can accept MIDI learning.
Definition follow_channel.h:37
bool learnNoteOn(MIDICable &cable, int32_t channel, int32_t noteCode)
Attempt to bind this menu item to a note code.
Definition follow_channel.h:132
void unlearnAction()
Unlearn the parameter controlled by this menu.
Definition follow_channel.h:121
void drawString(std::string_view str, int32_t pixelX, int32_t pixelY, int32_t textWidth, int32_t textHeight, int32_t scrollPos=0, int32_t endX=OLED_MAIN_WIDTH_PIXELS, bool useTextWidth=false)
Definition canvas.cpp:245