Deluge Firmware 1.3.0
Build date: 2025.09.14
Loading...
Searching...
No Matches
type.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 "definitions_cxx.hpp"
19#include "gui/menu_item/formatted_title.h"
20#include "gui/menu_item/selection.h"
21#include "gui/menu_item/submenu.h"
22#include "gui/ui/sound_editor.h"
23#include "model/song/song.h"
24#include "processing/engines/audio_engine.h"
25#include "processing/sound/sound.h"
26#include "processing/source.h"
27#include "util/comparison.h"
28
29#include <hid/display/oled.h>
30
31extern gui::menu_item::Submenu dxMenu;
32
33namespace deluge::gui::menu_item::osc {
34class Type final : public Selection, public FormattedTitle {
35public:
36 Type(l10n::String name, l10n::String title_format_str, uint8_t source_id)
37 : Selection(name), FormattedTitle(title_format_str, source_id + 1), sourceId_{source_id} {};
38 void beginSession(MenuItem* navigatedBackwardFrom) override { Selection::beginSession(navigatedBackwardFrom); }
39
40 bool mayUseDx() const { return !soundEditor.editingKit() && sourceId_ == 0; }
41
42 void readCurrentValue() override {
43 int32_t rawVal = static_cast<int32_t>(soundEditor.currentSound->sources[sourceId_].oscType);
44 if (!mayUseDx() && rawVal > static_cast<int32_t>(OscType::DX7)) {
45 rawVal -= 1;
46 }
47 setValue(rawVal);
48 }
49 void writeCurrentValue() override {
50 OscType oldValue = soundEditor.currentSound->sources[sourceId_].oscType;
51 auto newValue = getValue<OscType>();
52 if (!mayUseDx() && static_cast<int32_t>(newValue) >= static_cast<int32_t>(OscType::DX7)) {
53 newValue = static_cast<OscType>(static_cast<int32_t>(newValue) + 1);
54 }
55
56 const auto needs_unassignment = {
57 OscType::INPUT_L,
58 OscType::INPUT_R,
59 OscType::INPUT_STEREO,
60 OscType::SAMPLE,
61 OscType::DX7,
62
63 // Haven't actually really determined if this needs to be here - maybe not?
64 OscType::WAVETABLE,
65 };
66
67 if (util::one_of(oldValue, needs_unassignment) || util::one_of(newValue, needs_unassignment)) {
68 soundEditor.currentSound->killAllVoices();
69 }
70
71 soundEditor.currentSound->sources[sourceId_].setOscType(newValue);
72
73 if (oldValue == OscType::SQUARE || newValue == OscType::SQUARE) {
74 soundEditor.currentSound->setupPatchingForAllParamManagers(currentSong);
75 }
76 }
77
78 [[nodiscard]] std::string_view getTitle() const override { return FormattedTitle::title(); }
79
80 deluge::vector<std::string_view> getOptions(OptType optType) override {
81 (void)optType;
82 using enum l10n::String;
83 deluge::vector options = {
84 l10n::getView(STRING_FOR_SINE), //<
85 l10n::getView(STRING_FOR_TRIANGLE), //<
86 l10n::getView(STRING_FOR_SQUARE), //<
87 l10n::getView(STRING_FOR_ANALOG_SQUARE), //<
88 l10n::getView(STRING_FOR_SAW), //<
89 l10n::getView(STRING_FOR_ANALOG_SAW), //<
90 l10n::getView(STRING_FOR_WAVETABLE), //<
91 };
92
93 if (soundEditor.currentSound->getSynthMode() == SynthMode::RINGMOD) {
94 return options;
95 }
96
97 options.emplace_back(l10n::getView(STRING_FOR_SAMPLE));
98
99 if (mayUseDx()) {
100 options.emplace_back(l10n::getView(STRING_FOR_DX7));
101 }
102
103 if (AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn) {
104 options.emplace_back(l10n::getView(STRING_FOR_INPUT_LEFT));
105 options.emplace_back(l10n::getView(STRING_FOR_INPUT_RIGHT));
106 options.emplace_back(l10n::getView(STRING_FOR_INPUT_STEREO));
107 }
108 else {
109 options.emplace_back(l10n::getView(STRING_FOR_INPUT));
110 }
111
112 return options;
113 }
114
115 bool isRelevant(ModControllableAudio* modControllable, int32_t whichThing) override {
116 Sound* sound = static_cast<Sound*>(modControllable);
117 return (sound->getSynthMode() != SynthMode::FM);
118 }
119
120 MenuItem* selectButtonPress() override {
121 if (soundEditor.currentSound->sources[sourceId_].oscType != OscType::DX7) {
122 return nullptr;
123 }
124 return &dxMenu;
125 }
126
127 [[nodiscard]] bool showColumnLabel() const override { return false; }
128
129 void renderInHorizontalMenu(int32_t startX, int32_t width, int32_t startY, int32_t height) override {
130 oled_canvas::Canvas& image = OLED::main;
131
132 const OscType oscType = soundEditor.currentSound->sources[sourceId_].oscType;
133 if (oscType == OscType::DX7) {
134 const auto option = getOptions(OptType::FULL)[getValue()].data();
135 return image.drawStringCentered(option, startX, startY + 8, kTextTitleSpacingX, kTextTitleSizeY, width);
136 }
137
138 const Icon& icon = [&] {
139 switch (oscType) {
140 case OscType::SINE:
141 return OLED::sineIcon;
142 case OscType::TRIANGLE:
143 return OLED::triangleIcon;
144 case OscType::SQUARE:
145 case OscType::ANALOG_SQUARE:
146 return OLED::squareIcon;
147 case OscType::SAW:
148 case OscType::ANALOG_SAW_2:
149 return OLED::sawIcon;
150 case OscType::SAMPLE:
151 return OLED::sampleIcon;
152 case OscType::INPUT_STEREO:
153 case OscType::INPUT_L:
154 case OscType::INPUT_R:
155 return OLED::inputIcon;
156 case OscType::WAVETABLE:
157 return OLED::wavetableIcon;
158 default:
159 return OLED::sineIcon;
160 }
161 }();
162
163 image.drawIconCentered(icon, startX, width, startY + 4);
164
165 if (oscType == OscType::ANALOG_SQUARE || oscType == OscType::ANALOG_SAW_2) {
166 const int32_t x = startX + 4;
167 constexpr int32_t y = OLED_MAIN_HEIGHT_PIXELS - kTextSpacingY - 8;
168 image.clearAreaExact(x - 1, y - 1, x + kTextSpacingX + 1, y + kTextSpacingY + 1);
169 image.drawChar('A', x, y, kTextSpacingX, kTextSpacingY);
170 }
171 }
172
173private:
174 uint8_t sourceId_;
175};
176
177} // namespace deluge::gui::menu_item::osc
Definition mod_controllable_audio.h:47
Definition sound.h:71
void beginSession(MenuItem *navigatedBackwardFrom) override
Begin an editing session with this menu item.
Definition enumeration.cpp:8
Definition selection.h:26
Definition submenu.h:28
void beginSession(MenuItem *navigatedBackwardFrom) override
Begin an editing session with this menu item.
Definition type.h:38
MenuItem * selectButtonPress() override
Handle a select button press.
Definition type.h:120
bool showColumnLabel() const override
Show a label for the parameter in Horizontal menu.
Definition type.h:127
void readCurrentValue() override
Like readValueAgain, but does not redraw.
Definition type.h:42
bool isRelevant(ModControllableAudio *modControllable, int32_t whichThing) override
Check if this MenuItem should show up in a containing deluge::gui::menu_item::Submenu.
Definition type.h:115
std::string_view getTitle() const override
Get the title to be used when rendering on OLED, both as a deluge::gui::menu_item::Submenu and when d...
Definition type.h:78