Deluge Firmware 1.3.0
Build date: 2025.04.16
Loading...
Searching...
No Matches
repeat.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/sample/utils.h"
21#include "gui/menu_item/selection.h"
22#include "gui/ui/sound_editor.h"
23#include "gui/views/instrument_clip_view.h"
24#include "model/clip/instrument_clip.h"
25#include "model/drum/drum.h"
26#include "model/instrument/kit.h"
27#include "model/song/song.h"
28#include "processing/sound/sound_drum.h"
29
30namespace deluge::gui::menu_item::sample {
31
32class Repeat final : public Selection, public FormattedTitle {
33public:
34 Repeat(l10n::String name, l10n::String title_format_str) : Selection(name), FormattedTitle(title_format_str) {}
35
36 [[nodiscard]] std::string_view getTitle() const override { return FormattedTitle::title(); }
37
38 bool isRelevant(ModControllableAudio* modControllable, int32_t whichThing) final {
39 return isSampleModeSample(modControllable, whichThing);
40 }
41
42 bool usesAffectEntire() override { return true; }
43 void readCurrentValue() override { this->setValue(soundEditor.currentSource->repeatMode); }
44 void writeCurrentValue() override {
45 auto current_value = this->getValue<SampleRepeatMode>();
46
47 Kit* kit = getCurrentKit();
48
49 // If affect-entire button held, do whole kit
50 if (currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR && soundEditor.editingKitRow()) {
51
52 for (Drum* thisDrum = kit->firstDrum; thisDrum != nullptr; thisDrum = thisDrum->next) {
53 if (thisDrum->type == DrumType::SOUND) {
54 auto* soundDrum = static_cast<SoundDrum*>(thisDrum);
55 Source* source = &soundDrum->sources[soundEditor.currentSourceIndex];
56
57 // Automatically switch pitch/speed independence on / off if stretch-to-note-length mode is selected
58 if (current_value == SampleRepeatMode::STRETCH) {
59 soundDrum->killAllVoices();
60 source->sampleControls.pitchAndSpeedAreIndependent = true;
61 }
62 else if (source->repeatMode == SampleRepeatMode::STRETCH) {
63 soundDrum->killAllVoices();
64 soundEditor.currentSource->sampleControls.pitchAndSpeedAreIndependent = false;
65 }
66
67 if (current_value == SampleRepeatMode::ONCE) {
68 // Send note-off for kit arpeggiator to avoid stuck notes
69 int32_t noteRowIndex;
70 NoteRow* noteRow = getCurrentInstrumentClip()->getNoteRowForDrum(soundDrum, &noteRowIndex);
71 char modelStackMemory[MODEL_STACK_MAX_SIZE];
72 ModelStack* modelStack = (ModelStack*)modelStackMemory;
73 ModelStackWithThreeMainThings* modelStackWithThreeMainThings =
74 modelStack->addTimelineCounter(getCurrentClip())
75 ->addNoteRow(noteRowIndex, noteRow)
76 ->addOtherTwoThings(soundEditor.currentModControllable,
77 soundEditor.currentParamManager);
78 kit->noteOffPreKitArp(modelStackWithThreeMainThings, soundDrum);
79 }
80
81 source->repeatMode = current_value;
82 }
83 }
84 }
85 // Or, the normal case of just one sound
86 else {
87 // Automatically switch pitch/speed independence on / off if stretch-to-note-length mode is selected
88 if (static_cast<SampleRepeatMode>(current_value) == SampleRepeatMode::STRETCH) {
89 soundEditor.currentSound->killAllVoices();
90 soundEditor.currentSource->sampleControls.pitchAndSpeedAreIndependent = true;
91 }
92 else if (soundEditor.currentSource->repeatMode == SampleRepeatMode::STRETCH) {
93 soundEditor.currentSound->killAllVoices();
94 soundEditor.currentSource->sampleControls.pitchAndSpeedAreIndependent = false;
95 }
96
97 if (current_value == SampleRepeatMode::ONCE) {
98 // Send note-off for kit arpeggiator to avoid stuck notes
99 int32_t noteRowIndex;
100 NoteRow* noteRow = getCurrentInstrumentClip()->getNoteRowForDrum(kit->selectedDrum, &noteRowIndex);
101 char modelStackMemory[MODEL_STACK_MAX_SIZE];
102 ModelStack* modelStack = (ModelStack*)modelStackMemory;
103 ModelStackWithThreeMainThings* modelStackWithThreeMainThings =
104 modelStack->addTimelineCounter(getCurrentClip())
105 ->addNoteRow(noteRowIndex, noteRow)
106 ->addOtherTwoThings(soundEditor.currentModControllable, soundEditor.currentParamManager);
107 kit->noteOffPreKitArp(modelStackWithThreeMainThings, kit->selectedDrum);
108 }
109
110 soundEditor.currentSource->repeatMode = current_value;
111 }
112
113 // We need to re-render all rows, because this will have changed whether Note tails are displayed. Probably just
114 // one row, but we don't know which
115 uiNeedsRendering(&instrumentClipView, 0xFFFFFFFF, 0);
116 }
117 deluge::vector<std::string_view> getOptions(OptType optType) override {
118 (void)optType;
119 return {
120 l10n::getView(l10n::String::STRING_FOR_CUT),
121 l10n::getView(l10n::String::STRING_FOR_ONCE),
122 l10n::getView(l10n::String::STRING_FOR_LOOP),
123 l10n::getView(l10n::String::STRING_FOR_STRETCH),
124 };
125 }
126};
127
128} // namespace deluge::gui::menu_item::sample
Definition drum.h:44
Definition kit.h:34
Definition mod_controllable_audio.h:47
ModelStackWithThreeMainThings * addOtherTwoThings(ModControllable *newModControllable, ParamManager *newParamManager) const
Definition model_stack.h:385
Definition model_stack.h:231
Definition model_stack.h:123
Definition note_row.h:98
Definition sound_drum.h:28
void killAllVoices() override
Immediately ends all active voices.
Definition sound.cpp:4826
Definition source.h:31
Definition selection.h:26
bool isRelevant(ModControllableAudio *modControllable, int32_t whichThing) final
Check if this MenuItem should show up in a containing deluge::gui::menu_item::Submenu.
Definition repeat.h:38
void readCurrentValue() override
Like readValueAgain, but does not redraw.
Definition repeat.h:43
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 repeat.h:36
bool usesAffectEntire() override
Claim support for Kit AFFECT_ENTIRE editing.
Definition repeat.h:42