Deluge Firmware 1.3.0
Build date: 2025.07.11
Loading...
Searching...
No Matches
preset_mode.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/arpeggiator/octave_mode.h"
20#include "gui/menu_item/selection.h"
21#include "gui/ui/sound_editor.h"
22#include "model/clip/clip.h"
23#include "model/clip/instrument_clip.h"
24#include "model/drum/drum.h"
25#include "model/instrument/kit.h"
26#include "model/model_stack.h"
27#include "model/song/song.h"
28#include "processing/sound/sound.h"
29
30#include <hid/display/oled.h>
31
32namespace deluge::gui::menu_item::arpeggiator {
33class PresetMode final : public Selection {
34public:
35 using Selection::Selection;
36 void readCurrentValue() override { this->setValue(soundEditor.currentArpSettings->preset); }
37
38 bool usesAffectEntire() override { return true; }
39 void writeCurrentValue() override {
40 auto current_value = this->getValue<ArpPreset>();
41
42 // If affect-entire button held, do the whole kit
43 if (currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR && soundEditor.editingKitRow()) {
44
45 Kit* kit = getCurrentKit();
46
47 // If was off, or is now becoming off...
48 if (soundEditor.currentArpSettings->mode == ArpMode::OFF || current_value == ArpPreset::OFF) {
49 if (getCurrentClip()->isActiveOnOutput() && !soundEditor.editingKitAffectEntire()) {
50 kit->cutAllSound();
51 }
52 }
53
54 for (Drum* thisDrum = kit->firstDrum; thisDrum != nullptr; thisDrum = thisDrum->next) {
55 thisDrum->arpSettings.preset = current_value;
56 thisDrum->arpSettings.updateSettingsFromCurrentPreset();
57 thisDrum->arpSettings.flagForceArpRestart = true;
58 }
59 }
60 // Or, the normal case of just one sound
61 else {
62 // If was off, or is now becoming off...
63 if (soundEditor.currentArpSettings->mode == ArpMode::OFF || current_value == ArpPreset::OFF) {
64 if (getCurrentClip()->isActiveOnOutput() && !soundEditor.editingKitAffectEntire()) {
65 char modelStackMemory[MODEL_STACK_MAX_SIZE];
66 ModelStackWithThreeMainThings* modelStack = soundEditor.getCurrentModelStack(modelStackMemory);
67
68 if (soundEditor.editingKit()) {
69 // Drum
70 Drum* currentDrum = ((Kit*)getCurrentClip()->output)->selectedDrum;
71 if (currentDrum != nullptr) {
72 currentDrum->killAllVoices();
73 }
74 }
75 else if (soundEditor.editingCVOrMIDIClip()) {
76 getCurrentInstrumentClip()->stopAllNotesForMIDIOrCV(modelStack->toWithTimelineCounter());
77 }
78 else {
79 ModelStackWithSoundFlags* modelStackWithSoundFlags = modelStack->addSoundFlags();
80 soundEditor.currentSound->allNotesOff(
81 modelStackWithSoundFlags,
82 soundEditor.currentSound
83 ->getArp()); // Must switch off all notes when switching arp on / off
84 soundEditor.currentSound->reassessRenderSkippingStatus(modelStackWithSoundFlags);
85 }
86 }
87 }
88
89 soundEditor.currentArpSettings->preset = current_value;
90 soundEditor.currentArpSettings->updateSettingsFromCurrentPreset();
91 soundEditor.currentArpSettings->flagForceArpRestart = true;
92 }
93 }
94
95 deluge::vector<std::string_view> getOptions(OptType optType) override {
96 (void)optType;
97 using enum l10n::String;
98 return {
99 l10n::getView(STRING_FOR_OFF), //<
100 l10n::getView(STRING_FOR_UP), //<
101 l10n::getView(STRING_FOR_DOWN), //<
102 l10n::getView(STRING_FOR_BOTH), //<
103 l10n::getView(STRING_FOR_RANDOM), //<
104 l10n::getView(STRING_FOR_WALK), //<
105 l10n::getView(STRING_FOR_CUSTOM), //<
106 };
107 }
108
109 MenuItem* selectButtonPress() override {
110 auto current_value = this->getValue<ArpPreset>();
111 if (current_value == ArpPreset::CUSTOM) {
112 if (soundEditor.editingKitRow()) {
113 return &arpOctaveModeToNoteModeMenuForDrums;
114 }
115 return &arpOctaveModeToNoteModeMenu;
116 }
117 return nullptr;
118 }
119
120 [[nodiscard]] bool showColumnLabel() const override { return false; }
121
122 void getColumnLabel(StringBuf& label) override { label.append(l10n::get(l10n::String::STRING_FOR_MODE)); }
123
124 void renderInHorizontalMenu(int32_t startX, int32_t width, int32_t startY, int32_t height) override {
125 using namespace deluge::hid::display;
126 oled_canvas::Canvas& image = OLED::main;
127
128 if (this->getValue<ArpPreset>() == ArpPreset::OFF) {
129 const auto offString = l10n::get(l10n::String::STRING_FOR_OFF);
130 return image.drawStringCentered(offString, startX, startY + 8, kTextTitleSpacingX, kTextTitleSizeY, width);
131 }
132
133 const std::vector<std::reference_wrapper<const std::vector<uint8_t>>> bitmaps = [&] {
134 switch (this->getValue<ArpPreset>()) {
135 case ArpPreset::UP:
136 return std::vector{std::cref(OLED::arpModeIconUp)};
137 case ArpPreset::DOWN:
138 return std::vector{std::cref(OLED::arpModeIconDown)};
139 case ArpPreset::BOTH:
140 return std::vector{std::cref(OLED::arpModeIconUp), std::cref(OLED::arpModeIconDown)};
141 case ArpPreset::RANDOM:
142 return std::vector{std::cref(OLED::diceIcon)};
143 case ArpPreset::WALK:
144 return std::vector{std::cref(OLED::arpModeIconWalk)};
145 case ArpPreset::CUSTOM:
146 return std::vector{std::cref(OLED::arpModeIconCustom)};
147 default:
148 return std::vector<std::reference_wrapper<const std::vector<uint8_t>>>{};
149 }
150 }();
151
152 constexpr int32_t numBytesTall = 2;
153 const int32_t bitmapsWidth = std::accumulate(
154 bitmaps.begin(), bitmaps.end(), 0, [](int32_t acc, auto v) { return acc + v.get().size() / numBytesTall; });
155
156 // Calc center position
157 int32_t x = startX + (width - bitmapsWidth) / 2;
158 int32_t y = startY + (height - numBytesTall * 8) / 2;
159
160 // Draw icons
161 for (auto bitmap : bitmaps) {
162 image.drawGraphicMultiLine(bitmap.get().data(), x, y, bitmap.get().size() / numBytesTall, numBytesTall * 8,
163 numBytesTall);
164 x += bitmap.get().size() / numBytesTall;
165 }
166 }
167};
168} // namespace deluge::gui::menu_item::arpeggiator
Definition drum.h:44
Definition kit.h:34
Definition model_stack.h:231
static constexpr size_t size()
Used in combination with operator[] and begin end.
Definition rgb.h:218
Definition d_stringbuf.h:16
Definition selection.h:26
void readCurrentValue() override
Like readValueAgain, but does not redraw.
Definition preset_mode.h:36
MenuItem * selectButtonPress() override
Handle a select button press.
Definition preset_mode.h:109
bool showColumnLabel() const override
Show a label for the parameter in the horizontal menu.
Definition preset_mode.h:120
bool usesAffectEntire() override
Claim support for Kit AFFECT_ENTIRE editing.
Definition preset_mode.h:38