Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
follow_channel.h
1/*
2 * Copyright (c) 2024 Sean Ditny
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
18#pragma once
19#include "gui/menu_item/integer.h"
20#include "gui/ui/sound_editor.h"
21#include "hid/display/oled.h"
22#include "io/midi/midi_engine.h"
23
24class MIDICable;
25
26namespace deluge::gui::menu_item::midi {
27class FollowChannel final : public Integer {
28public:
29 using Integer::Integer;
30
31 FollowChannel(l10n::String newName, l10n::String title, MIDIFollowChannelType type)
32 : Integer(newName, title), channelType(type),
33 midiInput(midiEngine.midiFollowChannelType[util::to_underlying(type)]) {}
34
35 void readCurrentValue() override { this->setValue(midiInput.channelOrZone); }
36 void writeCurrentValue() override { midiInput.channelOrZone = this->getValue(); }
37 [[nodiscard]] int32_t getMaxValue() const override { return NUM_CHANNELS; }
38 bool allowsLearnMode() override { return true; }
39
40 void drawInteger(int32_t textWidth, int32_t textHeight, int32_t yPixel) override {
41 deluge::hid::display::oled_canvas::Canvas& canvas = hid::display::OLED::main;
42
43 yPixel = 20;
44
45 char const* differentiationString;
46 if (MIDIDeviceManager::differentiatingInputsByDevice) {
47 differentiationString = l10n::get(l10n::String::STRING_FOR_INPUT_DIFFERENTIATION_ON);
48 }
49 else {
50 differentiationString = l10n::get(l10n::String::STRING_FOR_INPUT_DIFFERENTIATION_OFF);
51 }
52 canvas.drawString(differentiationString, 0, yPixel, kTextSpacingX, kTextSizeYUpdated);
53
54 yPixel += kTextSpacingY;
55
56 char const* deviceString = l10n::get(l10n::String::STRING_FOR_FOLLOW_DEVICE_UNASSIGNED);
57 if (midiInput.cable) {
58 deviceString = midiInput.cable->getDisplayName();
59 }
60 canvas.drawString(deviceString, 0, yPixel, kTextSpacingX, kTextSizeYUpdated);
61 deluge::hid::display::OLED::setupSideScroller(0, deviceString, kTextSpacingX, OLED_MAIN_WIDTH_PIXELS, yPixel,
62 yPixel + 8, kTextSpacingX, kTextSpacingY, false);
63
64 yPixel += kTextSpacingY;
65
66 char const* channelText;
67 if (this->getValue() == MIDI_CHANNEL_MPE_LOWER_ZONE) {
68 channelText = l10n::get(l10n::String::STRING_FOR_MPE_LOWER_ZONE);
69 }
70 else if (this->getValue() == MIDI_CHANNEL_MPE_UPPER_ZONE) {
71 channelText = l10n::get(l10n::String::STRING_FOR_MPE_UPPER_ZONE);
72 }
73 else if (this->getValue() == MIDI_CHANNEL_NONE) {
74 channelText = l10n::get(l10n::String::STRING_FOR_FOLLOW_CHANNEL_UNASSIGNED);
75 }
76 else {
77 channelText = l10n::get(l10n::String::STRING_FOR_CHANNEL);
78 char buffer[12];
79 int32_t channelmod = (midiInput.channelOrZone >= IS_A_CC) * IS_A_CC;
80 intToString(midiInput.channelOrZone + 1 - channelmod, buffer, 1);
81 canvas.drawString(buffer, kTextSpacingX * 8, yPixel, kTextSpacingX, kTextSizeYUpdated);
82 }
83 canvas.drawString(channelText, 0, yPixel, kTextSpacingX, kTextSizeYUpdated);
84 }
85
86 void drawValue() override {
87 if (this->getValue() == MIDI_CHANNEL_MPE_LOWER_ZONE) {
88 display->setText(l10n::get(l10n::String::STRING_FOR_MPE_LOWER_ZONE));
89 }
90 else if (this->getValue() == MIDI_CHANNEL_MPE_UPPER_ZONE) {
91 display->setText(l10n::get(l10n::String::STRING_FOR_MPE_UPPER_ZONE));
92 }
93 else if (this->getValue() == MIDI_CHANNEL_NONE) {
94 display->setText(l10n::get(l10n::String::STRING_FOR_NONE));
95 }
96 else {
97 display->setTextAsNumber(this->getValue() + 1);
98 }
99 }
100
101 void selectEncoderAction(int32_t offset) override {
102 if (this->getValue() == MIDI_CHANNEL_NONE) {
103 if (offset > 0) {
104 this->setValue(0);
105 }
106 else if (offset < 0) {
107 this->setValue(MIDI_CHANNEL_MPE_UPPER_ZONE);
108 }
109 }
110 else {
111 this->setValue(this->getValue() + offset);
112 if ((this->getValue() >= NUM_CHANNELS) || (this->getValue() < 0)) {
113 this->setValue(MIDI_CHANNEL_NONE);
114 midiInput.clear();
115 renderDisplay();
116 return;
117 }
118 }
120 }
121
123 this->setValue(MIDI_CHANNEL_NONE);
124 midiInput.clear();
125 if (soundEditor.getCurrentMenuItem() == this) {
126 renderDisplay();
127 }
128 else {
129 display->displayPopup(l10n::get(l10n::String::STRING_FOR_UNLEARNED));
130 }
131 }
132
133 bool learnNoteOn(MIDICable& cable, int32_t channel, int32_t noteCode) {
134 this->setValue(channel);
135 midiInput.cable = &cable;
136 midiInput.channelOrZone = channel;
137
138 if (soundEditor.getCurrentMenuItem() == this) {
139 renderDisplay();
140 }
141 else {
142 display->displayPopup(l10n::get(l10n::String::STRING_FOR_LEARNED));
143 }
144
145 return true;
146 }
147
148 void learnCC(MIDICable& cable, int32_t channel, int32_t ccNumber, int32_t value) {
149 this->setValue(channel);
150 midiInput.cable = &cable;
151 midiInput.channelOrZone = channel;
152
153 if (soundEditor.getCurrentMenuItem() == this) {
154 renderDisplay();
155 }
156 else {
157 display->displayPopup(l10n::get(l10n::String::STRING_FOR_LEARNED));
158 }
159 }
160
161 void renderDisplay() {
162 if (display->haveOLED()) {
163 renderUIsForOled();
164 }
165 else {
166 drawValue();
167 }
168 }
169
170private:
171 MIDIFollowChannelType channelType;
172 LearnedMIDI& midiInput;
173};
174} // 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:94
deluge::l10n::String title
Can get overridden by getTitle(). Actual max num chars for OLED display is 14.
Definition menu_item.h:208
virtual void selectEncoderAction(int32_t offset)
Handle select encoder movement.
Definition menu_item.h:81
Definition integer.h:24
void readCurrentValue() override
Like readValueAgain, but does not redraw.
Definition follow_channel.h:35
void selectEncoderAction(int32_t offset) override
Handle select encoder movement.
Definition follow_channel.h:101
bool allowsLearnMode() override
Used by SoundEditor to determine if the current menu item can accept MIDI learning.
Definition follow_channel.h:38
bool learnNoteOn(MIDICable &cable, int32_t channel, int32_t noteCode)
Attempt to bind this menu item to a note code.
Definition follow_channel.h:133
void unlearnAction()
Unlearn the parameter controlled by this menu.
Definition follow_channel.h:122
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:123