diff --git a/.clang-format b/.clang-format index 1471bfe307..ea9296cb9c 100644 --- a/.clang-format +++ b/.clang-format @@ -16,5 +16,7 @@ BreakBeforeBinaryOperators: NonAssignment BreakBeforeTernaryOperators: True AccessModifierOffset: -4 AlwaysBreakTemplateDeclarations: Yes +#IndentRequiresClause: False +#RequiresClausePosition: OwnLine SortIncludes: CaseSensitive diff --git a/CMakeLists.txt b/CMakeLists.txt index df9a29e1b0..51e9379eeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -187,17 +187,6 @@ add_compile_options( # ASM stuff $<$:-x> $<$:assembler-with-cpp> - - # Warnings - # $<$:-Wextra> # TODO: Enable when ready - # $<$:-Wall> # TODO: Enable when ready - # $<$:-Wpedantic> # TODO: Enable when ready - $<$:-Wnull-dereference> - $<$:-Wno-psabi> - - # Stack usage - $<$:-Wstack-usage=100> - $<$:-Wstack-usage=1000> ) add_link_options( @@ -224,9 +213,27 @@ if(FORCE_COLORED_OUTPUT) endif() endif(FORCE_COLORED_OUTPUT) +# Add libraries +add_subdirectory(lib) + # Add our sources add_subdirectory(src) +# Project-only compile options (warnings, etc.) +target_compile_options(deluge INTERFACE + + # Warnings + # $<$:-Wextra> # TODO: Enable when ready + # $<$:-Wall> # TODO: Enable when ready + # $<$:-Wpedantic> # TODO: Enable when ready + $<$:-Wnull-dereference> + $<$:-Wno-psabi> + + # Stack usage + $<$:-Wstack-usage=100> + $<$:-Wstack-usage=1000> +) + # 7SEG configuration add_firmware(deluge7SEG deluge) diff --git a/SConstruct b/SConstruct index 9049a4e695..c2108aaca6 100644 --- a/SConstruct +++ b/SConstruct @@ -139,6 +139,12 @@ for build_env in env_standalone_builds: duplicate=False, ) + VariantDir( + os.path.relpath(os.path.join(build_env["BUILD_DIR"], 'lib')), + "#lib", + duplicate=False, + ) + # If we're in "only prepare mode" don't queue up any of the actual compilation steps. # Just bail at this point. There's also no point putting compilation db creation # before this as it won't compile the DB without awareness of the build steps. @@ -151,6 +157,8 @@ for build_env in env_standalone_builds: # Compilation DB settings wrapper build_env.Tool("compdb") + build_env.StaticLibrary('fmt', ['lib/fmt/format.cc']) + # Using the specified include dirs rather than walking every path in src was # preventing a successful .elf build so generically went with the latter approach. # This will serve us better later, buuuuut could also potentially break something. diff --git a/lib/.gitkeep b/lib/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000000..daddaad00c --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,8 @@ +include(FetchContent) + +FetchContent_Declare( + fmt + GIT_REPOSITORY https://github.com/fmtlib/fmt/ + GIT_TAG a0b8a92e3d1532361c2f7feb63babc5c18d00ef2 # release-10.0.0 +) +FetchContent_MakeAvailable(fmt) diff --git a/site_scons/build_opts.scons b/site_scons/build_opts.scons index 195de410af..73483d7e43 100644 --- a/site_scons/build_opts.scons +++ b/site_scons/build_opts.scons @@ -27,7 +27,7 @@ env.AppendUnique( ASMPATH=[ "src/NE10/common", ], - CPPPATH=["src/deluge", "src/NE10/modules", "src/NE10/inc", "src", "src/fatfs"], + CPPPATH=["src/deluge", "src/NE10/modules", "src/NE10/inc", "src", "src/fatfs", 'lib/fmt/include'], ) env["ASPATH"] = " {}".format(" ".join(['-I"{}"'.format(inc) for inc in env["ASMPATH"]])) diff --git a/src/NE10/inc/NE10_macros.h b/src/NE10/inc/NE10_macros.h index 0b9eb2c4a4..66bf4fcc44 100644 --- a/src/NE10/inc/NE10_macros.h +++ b/src/NE10/inc/NE10_macros.h @@ -50,7 +50,7 @@ extern "C" { // some external macro definitions to be exposed to the users ///////////////////////////////////////////////////////// -void* delugeAlloc(int requiredSize); +void* delugeAlloc(unsigned int requiredSize); void delugeDealloc(void* address); #define NE10_MALLOC delugeAlloc diff --git a/src/definitions.h b/src/definitions.h index 7e93557d4b..30a694a373 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -23,6 +23,8 @@ #define XTAL_SPEED_MHZ 13225625 #endif +#define RUNTIME_FEATURE_SETTING_MAX_OPTIONS 8 + // UART #define MIDI_TX_BUFFER_SIZE 1024 diff --git a/src/definitions_cxx.hpp b/src/definitions_cxx.hpp index 3a5a092908..9d611c59d9 100644 --- a/src/definitions_cxx.hpp +++ b/src/definitions_cxx.hpp @@ -19,6 +19,8 @@ #include "definitions.h" #include "util/misc.h" #include +#include +#include #include #define ALPHA_OR_BETA_VERSION 1 // Whether to compile with additional error-checking @@ -576,6 +578,7 @@ enum class SynthMode { FM, RINGMOD, }; +constexpr int kNumSynthModes = util::to_underlying(SynthMode::RINGMOD) + 1; enum class ModFXType { NONE, diff --git a/src/deluge/CMakeLists.txt b/src/deluge/CMakeLists.txt index 24b206cfa3..fc65b5210d 100644 --- a/src/deluge/CMakeLists.txt +++ b/src/deluge/CMakeLists.txt @@ -21,11 +21,7 @@ target_link_libraries(deluge INTERFACE fatfs RTT NE10 -) - -target_compile_options(deluge INTERFACE - # Set preinclude - $<$:-includepreinclude_cxx.h> + fmt::fmt # fmtlib ) target_compile_definitions(deluge INTERFACE diff --git a/src/deluge/gui/menu_item/arpeggiator/gate.h b/src/deluge/gui/menu_item/arpeggiator/gate.h index 160a943dbe..774ae6501c 100644 --- a/src/deluge/gui/menu_item/arpeggiator/gate.h +++ b/src/deluge/gui/menu_item/arpeggiator/gate.h @@ -18,11 +18,11 @@ #include "gui/menu_item/unpatched_param.h" #include "gui/ui/sound_editor.h" -namespace menu_item::arpeggiator { +namespace deluge::gui::menu_item::arpeggiator { class Gate final : public UnpatchedParam { public: - Gate(char const* newName = NULL, int32_t newP = 0) : UnpatchedParam(newName, newP) {} - bool isRelevant(Sound* sound, int32_t whichThing) { return !soundEditor.editingCVOrMIDIClip(); } + using UnpatchedParam::UnpatchedParam; + bool isRelevant(Sound* sound, int32_t whichThing) override { return !soundEditor.editingCVOrMIDIClip(); } }; -} // namespace menu_item::arpeggiator +} // namespace deluge::gui::menu_item::arpeggiator diff --git a/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h b/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h index 76929d888c..2cbfedae7d 100644 --- a/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h +++ b/src/deluge/gui/menu_item/arpeggiator/midi_cv/gate.h @@ -20,20 +20,20 @@ #include "model/clip/instrument_clip.h" #include "model/song/song.h" -namespace menu_item::arpeggiator::midi_cv { +namespace deluge::gui::menu_item::arpeggiator::midi_cv { class Gate final : public Integer { public: using Integer::Integer; - void readCurrentValue() { - InstrumentClip* current_clip = static_cast(currentSong->currentClip); + void readCurrentValue() override { + auto* current_clip = static_cast(currentSong->currentClip); int64_t arp_gate = (int64_t)current_clip->arpeggiatorGate + 2147483648; - soundEditor.currentValue = (arp_gate * 50 + 2147483648) >> 32; + this->value_ = (arp_gate * 50 + 2147483648) >> 32; } - void writeCurrentValue() { - ((InstrumentClip*)currentSong->currentClip)->arpeggiatorGate = - (uint32_t)soundEditor.currentValue * 85899345 - 2147483648; + void writeCurrentValue() override { + (static_cast(currentSong->currentClip))->arpeggiatorGate = + (uint32_t)this->value_ * 85899345 - 2147483648; } - int32_t getMaxValue() const { return 50; } - bool isRelevant(Sound* sound, int32_t whichThing) { return soundEditor.editingCVOrMIDIClip(); } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + bool isRelevant(Sound* sound, int32_t whichThing) override { return soundEditor.editingCVOrMIDIClip(); } }; -} // namespace menu_item::arpeggiator::midi_cv +} // namespace deluge::gui::menu_item::arpeggiator::midi_cv diff --git a/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h b/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h index 605884ff09..c933a1bdea 100644 --- a/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h +++ b/src/deluge/gui/menu_item/arpeggiator/midi_cv/rate.h @@ -20,25 +20,26 @@ #include "model/clip/instrument_clip.h" #include "model/song/song.h" -namespace menu_item::arpeggiator::midi_cv { +namespace deluge::gui::menu_item::arpeggiator::midi_cv { class Rate final : public Integer { public: - Rate(char const* newName = NULL) : Integer(newName) {} - void readCurrentValue() { - soundEditor.currentValue = - (((int64_t)((InstrumentClip*)currentSong->currentClip)->arpeggiatorRate + 2147483648) * 50 + 2147483648) + using Integer::Integer; + void readCurrentValue() override { + this->value_ = + (((int64_t)(static_cast(currentSong->currentClip))->arpeggiatorRate + 2147483648) * 50 + + 2147483648) >> 32; } - void writeCurrentValue() { - if (soundEditor.currentValue == 25) { - ((InstrumentClip*)currentSong->currentClip)->arpeggiatorRate = 0; + void writeCurrentValue() override { + if (this->value_ == 25) { + (static_cast(currentSong->currentClip))->arpeggiatorRate = 0; } else { - ((InstrumentClip*)currentSong->currentClip)->arpeggiatorRate = - (uint32_t)soundEditor.currentValue * 85899345 - 2147483648; + (static_cast(currentSong->currentClip))->arpeggiatorRate = + (uint32_t)this->value_ * 85899345 - 2147483648; } } - int32_t getMaxValue() const { return 50; } - bool isRelevant(Sound* sound, int32_t whichThing) { return soundEditor.editingCVOrMIDIClip(); } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + bool isRelevant(Sound* sound, int32_t whichThing) override { return soundEditor.editingCVOrMIDIClip(); } }; -} // namespace menu_item::arpeggiator::midi_cv +} // namespace deluge::gui::menu_item::arpeggiator::midi_cv diff --git a/src/deluge/gui/menu_item/arpeggiator/mode.h b/src/deluge/gui/menu_item/arpeggiator/mode.h index 4d60bfe6bd..f4ef779aa8 100644 --- a/src/deluge/gui/menu_item/arpeggiator/mode.h +++ b/src/deluge/gui/menu_item/arpeggiator/mode.h @@ -16,7 +16,7 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "model/clip/clip.h" #include "model/clip/instrument_clip.h" @@ -25,22 +25,21 @@ #include "processing/sound/sound.h" #include "util/misc.h" -namespace menu_item::arpeggiator { -class Mode final : public Selection { +namespace deluge::gui::menu_item::arpeggiator { +class Mode final : public TypedSelection { public: - Mode(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(soundEditor.currentArpSettings->mode); } - void writeCurrentValue() { + using TypedSelection::TypedSelection; + void readCurrentValue() override { this->value_ = soundEditor.currentArpSettings->mode; } + void writeCurrentValue() override { // If was off, or is now becoming off... - if (soundEditor.currentArpSettings->mode == ArpMode::OFF - || static_cast(soundEditor.currentValue) == ArpMode::OFF) { + if (soundEditor.currentArpSettings->mode == ArpMode::OFF || this->value_ == ArpMode::OFF) { if (currentSong->currentClip->isActiveOnOutput()) { char modelStackMemory[MODEL_STACK_MAX_SIZE]; ModelStackWithThreeMainThings* modelStack = soundEditor.getCurrentModelStack(modelStackMemory); if (soundEditor.editingCVOrMIDIClip()) { - ((InstrumentClip*)currentSong->currentClip) + (static_cast(currentSong->currentClip)) ->stopAllNotesForMIDIOrCV(modelStack->toWithTimelineCounter()); } else { @@ -52,18 +51,13 @@ class Mode final : public Selection { } } } - soundEditor.currentArpSettings->mode = static_cast(soundEditor.currentValue); + soundEditor.currentArpSettings->mode = this->value_; // Only update the Clip-level arp setting if they hadn't been playing with other synth parameters first (so it's clear that switching the arp on or off was their main intention) if (!soundEditor.editingKit()) { - bool arpNow = - (static_cast(soundEditor.currentValue) != ArpMode::OFF); // Uh.... this does nothing... + bool arpNow = (this->value_ != ArpMode::OFF); // Uh.... this does nothing... } } - char const** getOptions() { - static char const* options[] = {"OFF", "UP", "DOWN", "BOTH", "Random", NULL}; - return options; - } - int32_t getNumOptions() { return kNumArpModes; } + static_vector getOptions() override { return {"OFF", "UP", "DOWN", "BOTH", "Random"}; } }; -} // namespace menu_item::arpeggiator +} // namespace deluge::gui::menu_item::arpeggiator diff --git a/src/deluge/gui/menu_item/arpeggiator/octaves.h b/src/deluge/gui/menu_item/arpeggiator/octaves.h index 09b340ecf1..03bde15579 100644 --- a/src/deluge/gui/menu_item/arpeggiator/octaves.h +++ b/src/deluge/gui/menu_item/arpeggiator/octaves.h @@ -18,13 +18,13 @@ #include "gui/menu_item/integer.h" #include "gui/ui/sound_editor.h" -namespace menu_item::arpeggiator { +namespace deluge::gui::menu_item::arpeggiator { class Octaves final : public Integer { public: - Octaves(char const* newName = NULL) : Integer(newName) {} - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentArpSettings->numOctaves; } - void writeCurrentValue() { soundEditor.currentArpSettings->numOctaves = soundEditor.currentValue; } - int32_t getMinValue() const { return 1; } - int32_t getMaxValue() const { return 8; } + using Integer::Integer; + void readCurrentValue() override { this->value_ = soundEditor.currentArpSettings->numOctaves; } + void writeCurrentValue() override { soundEditor.currentArpSettings->numOctaves = this->value_; } + [[nodiscard]] int32_t getMinValue() const override { return 1; } + [[nodiscard]] int32_t getMaxValue() const override { return 8; } }; -} // namespace menu_item::arpeggiator +} // namespace deluge::gui::menu_item::arpeggiator diff --git a/src/deluge/gui/menu_item/arpeggiator/rate.h b/src/deluge/gui/menu_item/arpeggiator/rate.h index 536b6619db..01825ed224 100644 --- a/src/deluge/gui/menu_item/arpeggiator/rate.h +++ b/src/deluge/gui/menu_item/arpeggiator/rate.h @@ -18,11 +18,11 @@ #include "gui/menu_item/patched_param/integer.h" #include "gui/ui/sound_editor.h" -namespace menu_item::arpeggiator { +namespace deluge::gui::menu_item::arpeggiator { class Rate final : public patched_param::Integer { public: - Rate(char const* newName = NULL, int32_t newP = 0) : Integer(newName, newP) {} - bool isRelevant(Sound* sound, int32_t whichThing) { return !soundEditor.editingCVOrMIDIClip(); } + using patched_param::Integer::Integer; + bool isRelevant(Sound* sound, int32_t whichThing) override { return !soundEditor.editingCVOrMIDIClip(); } }; -} // namespace menu_item::arpeggiator +} // namespace deluge::gui::menu_item::arpeggiator diff --git a/src/deluge/gui/menu_item/arpeggiator/sync.h b/src/deluge/gui/menu_item/arpeggiator/sync.h index 6e8cfa36c7..20cf8f8271 100644 --- a/src/deluge/gui/menu_item/arpeggiator/sync.h +++ b/src/deluge/gui/menu_item/arpeggiator/sync.h @@ -18,18 +18,18 @@ #include "gui/menu_item/sync_level.h" #include "gui/ui/sound_editor.h" -namespace menu_item::arpeggiator { +namespace deluge::gui::menu_item::arpeggiator { class Sync final : public SyncLevel { public: - Sync(char const* newName = NULL) : SyncLevel(newName) {} + using SyncLevel::SyncLevel; void readCurrentValue() { - soundEditor.currentValue = syncTypeAndLevelToMenuOption(soundEditor.currentArpSettings->syncType, - soundEditor.currentArpSettings->syncLevel); + this->value_ = syncTypeAndLevelToMenuOption(soundEditor.currentArpSettings->syncType, + soundEditor.currentArpSettings->syncLevel); } void writeCurrentValue() { - soundEditor.currentArpSettings->syncType = menuOptionToSyncType(soundEditor.currentValue); - soundEditor.currentArpSettings->syncLevel = menuOptionToSyncLevel(soundEditor.currentValue); + soundEditor.currentArpSettings->syncType = menuOptionToSyncType(this->value_); + soundEditor.currentArpSettings->syncLevel = menuOptionToSyncLevel(this->value_); } }; -} // namespace menu_item::arpeggiator +} // namespace deluge::gui::menu_item::arpeggiator diff --git a/src/deluge/gui/menu_item/audio_clip/attack.h b/src/deluge/gui/menu_item/audio_clip/attack.h index 67abafa32e..9b5fb85cb9 100644 --- a/src/deluge/gui/menu_item/audio_clip/attack.h +++ b/src/deluge/gui/menu_item/audio_clip/attack.h @@ -20,18 +20,19 @@ #include "model/clip/audio_clip.h" #include "model/song/song.h" -namespace menu_item::audio_clip { +namespace deluge::gui::menu_item::audio_clip { class Attack final : public Integer { public: using Integer::Integer; - void readCurrentValue() { - soundEditor.currentValue = - (((int64_t)((AudioClip*)currentSong->currentClip)->attack + 2147483648) * 50 + 2147483648) >> 32; + void readCurrentValue() override { + this->value_ = + (((int64_t)(static_cast(currentSong->currentClip))->attack + 2147483648) * 50 + 2147483648) + >> 32; } - void writeCurrentValue() { - ((AudioClip*)currentSong->currentClip)->attack = (uint32_t)soundEditor.currentValue * 85899345 - 2147483648; + void writeCurrentValue() override { + (static_cast(currentSong->currentClip))->attack = (uint32_t)this->value_ * 85899345 - 2147483648; } - int32_t getMaxValue() const { return 50; } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } }; -} // namespace menu_item::audio_clip +} // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/audio_clip/hpf_freq.h b/src/deluge/gui/menu_item/audio_clip/hpf_freq.h index 4fadfc6351..57047b1ef6 100644 --- a/src/deluge/gui/menu_item/audio_clip/hpf_freq.h +++ b/src/deluge/gui/menu_item/audio_clip/hpf_freq.h @@ -18,13 +18,13 @@ #include "gui/menu_item/unpatched_param.h" #include "gui/ui/sound_editor.h" -namespace menu_item::audio_clip { +namespace deluge::gui::menu_item::audio_clip { class HPFFreq final : public UnpatchedParam { public: using UnpatchedParam::UnpatchedParam; #if !HAVE_OLED - void drawValue() { - if (soundEditor.currentValue == 0) { + void drawValue() override { + if (this->value_ == 0) { numericDriver.setText("OFF"); } else { @@ -33,4 +33,4 @@ class HPFFreq final : public UnpatchedParam { } #endif }; -} // namespace menu_item::audio_clip +} // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/audio_clip/lpf_freq.h b/src/deluge/gui/menu_item/audio_clip/lpf_freq.h index 70526d51e3..d1ca512a3a 100644 --- a/src/deluge/gui/menu_item/audio_clip/lpf_freq.h +++ b/src/deluge/gui/menu_item/audio_clip/lpf_freq.h @@ -18,13 +18,13 @@ #include "gui/menu_item/unpatched_param.h" #include "gui/ui/sound_editor.h" -namespace menu_item::audio_clip { +namespace deluge::gui::menu_item::audio_clip { class LPFFreq final : public UnpatchedParam { public: using UnpatchedParam::UnpatchedParam; #if !HAVE_OLED - void drawValue() { - if (soundEditor.currentValue == 50) { + void drawValue() override { + if (this->value_ == 50) { numericDriver.setText("OFF"); } else { @@ -33,4 +33,4 @@ class LPFFreq final : public UnpatchedParam { } #endif }; -} // namespace menu_item::audio_clip +} // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/audio_clip/mod_fx/type.h b/src/deluge/gui/menu_item/audio_clip/mod_fx/type.h index 11afdc857a..6ab9489254 100644 --- a/src/deluge/gui/menu_item/audio_clip/mod_fx/type.h +++ b/src/deluge/gui/menu_item/audio_clip/mod_fx/type.h @@ -15,26 +15,29 @@ * If not, see . */ #pragma once +#include "definitions_cxx.hpp" #include "gui/menu_item/mod_fx/type.h" +#include "util/misc.h" -namespace menu_item::audio_clip::mod_fx { +namespace deluge::gui::menu_item::audio_clip::mod_fx { class Type final : public menu_item::mod_fx::Type { public: using menu_item::mod_fx::Type::Type; // We override this to set min value to 1. We don't inherit any getMinValue() function to override more easily void selectEncoderAction(int32_t offset) override { - soundEditor.currentValue += offset; - int32_t numOptions = getNumOptions(); + auto current = util::to_underlying(this->value_) + offset; + int32_t numOptions = getOptions().size(); - if (soundEditor.currentValue >= numOptions) { - soundEditor.currentValue -= (numOptions - 1); + if (current >= numOptions) { + current -= (numOptions - 1); } - else if (soundEditor.currentValue < 1) { - soundEditor.currentValue += (numOptions - 1); + else if (current < 1) { + current += (numOptions - 1); } + this->value_ = static_cast(current); Value::selectEncoderAction(offset); } }; -} // namespace menu_item::audio_clip::mod_fx +} // namespace deluge::gui::menu_item::audio_clip::mod_fx diff --git a/src/deluge/gui/menu_item/audio_clip/reverse.h b/src/deluge/gui/menu_item/audio_clip/reverse.h index 0c4808b05b..49ac0b4a6d 100644 --- a/src/deluge/gui/menu_item/audio_clip/reverse.h +++ b/src/deluge/gui/menu_item/audio_clip/reverse.h @@ -15,7 +15,7 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "gui/views/audio_clip_view.h" #include "model/clip/audio_clip.h" @@ -24,25 +24,25 @@ #include "model/song/song.h" #include "playback/playback_handler.h" -namespace menu_item::audio_clip { -class Reverse final : public Selection { +namespace deluge::gui::menu_item::audio_clip { +class Reverse final : public Toggle { public: - using Selection::Selection; + using Toggle::Toggle; - void readCurrentValue() { - soundEditor.currentValue = ((AudioClip*)currentSong->currentClip)->sampleControls.reversed; + void readCurrentValue() override { + this->value_ = (static_cast(currentSong->currentClip))->sampleControls.reversed; } - void writeCurrentValue() { - AudioClip* clip = (AudioClip*)currentSong->currentClip; + void writeCurrentValue() override { + auto* clip = static_cast(currentSong->currentClip); bool active = (playbackHandler.isEitherClockActive() && currentSong->isClipActive(clip) && clip->voiceSample); clip->unassignVoiceSample(); - clip->sampleControls.reversed = soundEditor.currentValue; + clip->sampleControls.reversed = this->value_; - if (clip->sampleHolder.audioFile) { + if (clip->sampleHolder.audioFile != nullptr) { if (clip->sampleControls.reversed) { - uint64_t lengthInSamples = ((Sample*)clip->sampleHolder.audioFile)->lengthInSamples; + uint64_t lengthInSamples = (static_cast(clip->sampleHolder.audioFile))->lengthInSamples; if (clip->sampleHolder.endPos > lengthInSamples) { clip->sampleHolder.endPos = lengthInSamples; } @@ -62,4 +62,4 @@ class Reverse final : public Selection { } } }; -} // namespace menu_item::audio_clip +} // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.cpp b/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.cpp index 1f3c5dab58..f31e2f8d8f 100644 --- a/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.cpp +++ b/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.cpp @@ -25,7 +25,7 @@ #include "model/clip/audio_clip.h" #include "model/song/song.h" -namespace menu_item::audio_clip { +namespace deluge::gui::menu_item::audio_clip { MenuPermission SampleMarkerEditor::checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) { @@ -35,7 +35,7 @@ MenuPermission SampleMarkerEditor::checkPermissionToBeginSession(Sound* sound, i } // Before going ahead, make sure a Sample is loaded - if (!((AudioClip*)currentSong->currentClip)->sampleHolder.audioFile) { + if ((static_cast(currentSong->currentClip))->sampleHolder.audioFile == nullptr) { return MenuPermission::NO; } @@ -52,4 +52,4 @@ void SampleMarkerEditor::beginSession(MenuItem* navigatedBackwardFrom) { } } -} // namespace menu_item::audio_clip +} // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.h b/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.h index 125132623a..39ca302902 100644 --- a/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.h +++ b/src/deluge/gui/menu_item/audio_clip/sample_marker_editor.h @@ -19,18 +19,17 @@ #include "definitions_cxx.hpp" #include "gui/menu_item/menu_item.h" -namespace menu_item::audio_clip { +namespace deluge::gui::menu_item::audio_clip { class SampleMarkerEditor final : public MenuItem { public: - SampleMarkerEditor(char const* newName = NULL, MarkerType newWhichMarker = MarkerType::START) : MenuItem(newName) { - whichMarker = newWhichMarker; - } + SampleMarkerEditor(char const* newName = nullptr, MarkerType newWhichMarker = MarkerType::START) + : MenuItem(newName), whichMarker(newWhichMarker) {} - MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange); - void beginSession(MenuItem* navigatedBackwardFrom); + virtual MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange); + void beginSession(MenuItem* navigatedBackwardFrom) override; MarkerType whichMarker; }; -} // namespace menu_item::audio_clip +} // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/audio_clip/transpose.h b/src/deluge/gui/menu_item/audio_clip/transpose.h index 1b8fecc208..6a33b2fe17 100644 --- a/src/deluge/gui/menu_item/audio_clip/transpose.h +++ b/src/deluge/gui/menu_item/audio_clip/transpose.h @@ -21,42 +21,42 @@ #include "model/clip/audio_clip.h" #include "model/song/song.h" -namespace menu_item::audio_clip { +namespace deluge::gui::menu_item::audio_clip { class Transpose final : public Decimal, public MenuItemWithCCLearning { public: using Decimal::Decimal; - void readCurrentValue() { - soundEditor.currentValue = ((AudioClip*)currentSong->currentClip)->sampleHolder.transpose * 100 - + ((AudioClip*)currentSong->currentClip)->sampleHolder.cents; + void readCurrentValue() override { + this->value_ = (static_cast(currentSong->currentClip))->sampleHolder.transpose * 100 + + (static_cast(currentSong->currentClip))->sampleHolder.cents; } - void writeCurrentValue() { - int32_t currentValue = soundEditor.currentValue + 25600; + void writeCurrentValue() override { + int32_t currentValue = this->value_ + 25600; int32_t semitones = (currentValue + 50) / 100; int32_t cents = currentValue - semitones * 100; int32_t transpose = semitones - 256; - ((AudioClip*)currentSong->currentClip)->sampleHolder.transpose = transpose; - ((AudioClip*)currentSong->currentClip)->sampleHolder.cents = cents; - - ((AudioClip*)currentSong->currentClip)->sampleHolder.recalculateNeutralPhaseIncrement(); + auto& sampleHolder = (static_cast(currentSong->currentClip))->sampleHolder; + sampleHolder.transpose = transpose; + sampleHolder.cents = cents; + sampleHolder.recalculateNeutralPhaseIncrement(); } - int32_t getMinValue() const { return -9600; } - int32_t getMaxValue() const { return 9600; } - int32_t getNumDecimalPlaces() const { return 2; } + [[nodiscard]] int32_t getMinValue() const override { return -9600; } + [[nodiscard]] int32_t getMaxValue() const override { return 9600; } + [[nodiscard]] int32_t getNumDecimalPlaces() const override { return 2; } - void unlearnAction() { MenuItemWithCCLearning::unlearnAction(); } - bool allowsLearnMode() { return MenuItemWithCCLearning::allowsLearnMode(); } - void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) { + void unlearnAction() override { MenuItemWithCCLearning::unlearnAction(); } + bool allowsLearnMode() override { return MenuItemWithCCLearning::allowsLearnMode(); } + void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) override { MenuItemWithCCLearning::learnKnob(fromDevice, whichKnob, modKnobMode, midiChannel); }; - ParamDescriptor getLearningThing() { + ParamDescriptor getLearningThing() override { ParamDescriptor paramDescriptor; paramDescriptor.setToHaveParamOnly(::Param::Unpatched::START + ::Param::Unpatched::GlobalEffectable::PITCH_ADJUST); return paramDescriptor; } }; -} // namespace menu_item::audio_clip +} // namespace deluge::gui::menu_item::audio_clip diff --git a/src/deluge/gui/menu_item/bend_range.h b/src/deluge/gui/menu_item/bend_range.h index 57747f6e37..7f0cb15e73 100644 --- a/src/deluge/gui/menu_item/bend_range.h +++ b/src/deluge/gui/menu_item/bend_range.h @@ -17,10 +17,10 @@ #pragma once #include "integer.h" -namespace menu_item { +namespace deluge::gui::menu_item { class BendRange : public Integer { public: - BendRange(char const* newName = NULL) : Integer(newName) {} - int32_t getMaxValue() const { return 96; } + using Integer::Integer; + [[nodiscard]] int32_t getMaxValue() const override { return 96; } }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/bend_range/main.h b/src/deluge/gui/menu_item/bend_range/main.h index 1c8c2d59c9..09f9889b28 100644 --- a/src/deluge/gui/menu_item/bend_range/main.h +++ b/src/deluge/gui/menu_item/bend_range/main.h @@ -21,22 +21,22 @@ #include "modulation/params/param_set.h" #include "storage/flash_storage.h" -namespace menu_item::bend_range { +namespace deluge::gui::menu_item::bend_range { class Main final : public BendRange { public: using BendRange::BendRange; - void readCurrentValue() { + void readCurrentValue() override { ExpressionParamSet* expressionParams = soundEditor.currentParamManager->getOrCreateExpressionParamSet(soundEditor.editingKit()); - soundEditor.currentValue = expressionParams ? expressionParams->bendRanges[BEND_RANGE_MAIN] - : FlashStorage::defaultBendRange[BEND_RANGE_MAIN]; + this->value_ = expressionParams != nullptr ? expressionParams->bendRanges[BEND_RANGE_MAIN] + : FlashStorage::defaultBendRange[BEND_RANGE_MAIN]; } - void writeCurrentValue() { + void writeCurrentValue() override { ExpressionParamSet* expressionParams = soundEditor.currentParamManager->getOrCreateExpressionParamSet(soundEditor.editingKit()); - if (expressionParams) { - expressionParams->bendRanges[BEND_RANGE_MAIN] = soundEditor.currentValue; + if (expressionParams != nullptr) { + expressionParams->bendRanges[BEND_RANGE_MAIN] = this->value_; } } }; -} // namespace menu_item::bend_range +} // namespace deluge::gui::menu_item::bend_range diff --git a/src/deluge/gui/menu_item/bend_range/per_finger.h b/src/deluge/gui/menu_item/bend_range/per_finger.h index 095d3475f4..f67c06fd2e 100644 --- a/src/deluge/gui/menu_item/bend_range/per_finger.h +++ b/src/deluge/gui/menu_item/bend_range/per_finger.h @@ -21,25 +21,25 @@ #include "modulation/params/param_set.h" #include "storage/flash_storage.h" -namespace menu_item::bend_range { +namespace deluge::gui::menu_item::bend_range { class PerFinger final : public BendRange { public: using BendRange::BendRange; - void readCurrentValue() { + void readCurrentValue() override { ExpressionParamSet* expressionParams = soundEditor.currentParamManager->getOrCreateExpressionParamSet(soundEditor.editingKit()); - soundEditor.currentValue = expressionParams ? expressionParams->bendRanges[BEND_RANGE_FINGER_LEVEL] - : FlashStorage::defaultBendRange[BEND_RANGE_FINGER_LEVEL]; + this->value_ = expressionParams != nullptr ? expressionParams->bendRanges[BEND_RANGE_FINGER_LEVEL] + : FlashStorage::defaultBendRange[BEND_RANGE_FINGER_LEVEL]; } - void writeCurrentValue() { + void writeCurrentValue() override { ExpressionParamSet* expressionParams = soundEditor.currentParamManager->getOrCreateExpressionParamSet(soundEditor.editingKit()); - if (expressionParams) { - expressionParams->bendRanges[BEND_RANGE_FINGER_LEVEL] = soundEditor.currentValue; + if (expressionParams != nullptr) { + expressionParams->bendRanges[BEND_RANGE_FINGER_LEVEL] = this->value_; } } - bool isRelevant(Sound* sound, int32_t whichThing) { + bool isRelevant(Sound* sound, int32_t whichThing) override { return soundEditor.navigationDepth == 1 || soundEditor.editingKit(); } }; -} // namespace menu_item::bend_range +} // namespace deluge::gui::menu_item::bend_range diff --git a/src/deluge/gui/menu_item/colour.cpp b/src/deluge/gui/menu_item/colour.cpp index 3cd0683a23..5256818582 100644 --- a/src/deluge/gui/menu_item/colour.cpp +++ b/src/deluge/gui/menu_item/colour.cpp @@ -20,30 +20,13 @@ #include "gui/ui/sound_editor.h" #include "gui/ui/ui.h" -namespace menu_item { +namespace deluge::gui::menu_item { Colour activeColourMenu{"ACTIVE"}; Colour stoppedColourMenu{"STOPPED"}; Colour mutedColourMenu{"MUTED"}; Colour soloColourMenu{"SOLOED"}; -void Colour::readCurrentValue() { - soundEditor.currentValue = value; -} -void Colour::writeCurrentValue() { - value = soundEditor.currentValue; - renderingNeededRegardlessOfUI(); -} - -char const** Colour::getOptions() { - static char const* options[] = {"RED", "GREEN", "BLUE", "YELLOW", "CYAN", "PURPLE", "AMBER", "WHITE", "PINK", NULL}; - return options; -} - -int32_t Colour::getNumOptions() { - return 9; -} - void Colour::getRGB(uint8_t rgb[3]) { switch (value) { case 0: // Red @@ -101,4 +84,4 @@ void Colour::getRGB(uint8_t rgb[3]) { break; } } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/colour.h b/src/deluge/gui/menu_item/colour.h index e31c315397..1c4523493d 100644 --- a/src/deluge/gui/menu_item/colour.h +++ b/src/deluge/gui/menu_item/colour.h @@ -16,17 +16,21 @@ */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" -namespace menu_item { +namespace deluge::gui::menu_item { -class Colour final : public Selection { +class Colour final : public Selection<9> { public: - Colour(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue(); - void writeCurrentValue(); - char const** getOptions(); - int32_t getNumOptions(); + using Selection::Selection; + void readCurrentValue() override { this->value_ = value; } + void writeCurrentValue() override { + value = this->value_; + renderingNeededRegardlessOfUI(); + }; + static_vector getOptions() override { + return {"RED", "GREEN", "BLUE", "YELLOW", "CYAN", "PURPLE", "AMBER", "WHITE", "PINK"}; + } void getRGB(uint8_t rgb[3]); uint8_t value; }; @@ -36,4 +40,4 @@ extern Colour stoppedColourMenu; extern Colour mutedColourMenu; extern Colour soloColourMenu; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/compressor/attack.h b/src/deluge/gui/menu_item/compressor/attack.h index 2e64345988..3c42a0894b 100644 --- a/src/deluge/gui/menu_item/compressor/attack.h +++ b/src/deluge/gui/menu_item/compressor/attack.h @@ -20,21 +20,20 @@ #include "processing/engines/audio_engine.h" #include "processing/sound/sound.h" -namespace menu_item::compressor { +namespace deluge::gui::menu_item::compressor { class Attack final : public Integer { public: using Integer::Integer; - void readCurrentValue() { - soundEditor.currentValue = - getLookupIndexFromValue(soundEditor.currentCompressor->attack >> 2, attackRateTable, 50); + void readCurrentValue() override { + this->value_ = getLookupIndexFromValue(soundEditor.currentCompressor->attack >> 2, attackRateTable, 50); } - void writeCurrentValue() { - soundEditor.currentCompressor->attack = attackRateTable[soundEditor.currentValue] << 2; + void writeCurrentValue() override { + soundEditor.currentCompressor->attack = attackRateTable[this->value_] << 2; AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } - int32_t getMaxValue() const { return 50; } - bool isRelevant(Sound* sound, int32_t whichThing) { - return !(soundEditor.editingReverbCompressor() && AudioEngine::reverbCompressorVolume < 0); + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + bool isRelevant(Sound* sound, int32_t whichThing) override { + return !soundEditor.editingReverbCompressor() || AudioEngine::reverbCompressorVolume >= 0; } }; -} // namespace menu_item::compressor +} // namespace deluge::gui::menu_item::compressor diff --git a/src/deluge/gui/menu_item/compressor/release.h b/src/deluge/gui/menu_item/compressor/release.h index b7c6f0853b..7a5bceefb4 100644 --- a/src/deluge/gui/menu_item/compressor/release.h +++ b/src/deluge/gui/menu_item/compressor/release.h @@ -20,21 +20,20 @@ #include "processing/engines/audio_engine.h" #include "processing/sound/sound.h" -namespace menu_item::compressor { +namespace deluge::gui::menu_item::compressor { class Release final : public Integer { public: using Integer::Integer; - void readCurrentValue() { - soundEditor.currentValue = - getLookupIndexFromValue(soundEditor.currentCompressor->release >> 3, releaseRateTable, 50); + void readCurrentValue() override { + this->value_ = getLookupIndexFromValue(soundEditor.currentCompressor->release >> 3, releaseRateTable, 50); } - void writeCurrentValue() { - soundEditor.currentCompressor->release = releaseRateTable[soundEditor.currentValue] << 3; + void writeCurrentValue() override { + soundEditor.currentCompressor->release = releaseRateTable[this->value_] << 3; AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } - int32_t getMaxValue() const { return 50; } - bool isRelevant(Sound* sound, int32_t whichThing) { - return !(soundEditor.editingReverbCompressor() && AudioEngine::reverbCompressorVolume < 0); + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + bool isRelevant(Sound* sound, int32_t whichThing) override { + return !soundEditor.editingReverbCompressor() || AudioEngine::reverbCompressorVolume >= 0; } }; -} // namespace menu_item::compressor +} // namespace deluge::gui::menu_item::compressor diff --git a/src/deluge/gui/menu_item/compressor/volume.h b/src/deluge/gui/menu_item/compressor/volume.h index 9357677818..33664463e1 100644 --- a/src/deluge/gui/menu_item/compressor/volume.h +++ b/src/deluge/gui/menu_item/compressor/volume.h @@ -18,15 +18,15 @@ #include "gui/menu_item/patch_cable_strength/fixed.h" #include "processing/engines/audio_engine.h" -namespace menu_item::compressor { +namespace deluge::gui::menu_item::compressor { class VolumeShortcut final : public patch_cable_strength::Fixed { public: using Fixed::Fixed; - void writeCurrentValue() { + void writeCurrentValue() override { Fixed::writeCurrentValue(); AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } }; -} // namespace menu_item::compressor +} // namespace deluge::gui::menu_item::compressor diff --git a/src/deluge/gui/menu_item/cv/selection.h b/src/deluge/gui/menu_item/cv/selection.h index 886c95dcef..f02a38c377 100644 --- a/src/deluge/gui/menu_item/cv/selection.h +++ b/src/deluge/gui/menu_item/cv/selection.h @@ -15,47 +15,45 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/menu_item/submenu.h" #include "gui/ui/sound_editor.h" #include "transpose.h" #include "volts.h" extern void setCvNumberForTitle(int32_t m); -extern menu_item::Submenu cvSubmenu; +extern deluge::gui::menu_item::Submenu<2> cvSubmenu; -namespace menu_item::cv { -#if HAVE_OLED -static char const* cvOutputChannel[] = {"CV output 1", "CV output 2", NULL}; -#else -static char const* cvOutputChannel[] = {"Out1", "Out2", NULL}; -#endif - -class Selection final : public menu_item::Selection { +namespace deluge::gui::menu_item::cv { +class Selection final : public menu_item::Selection<2> { public: - Selection(char const* newName = NULL) : menu_item::Selection(newName) { -#if HAVE_OLED - basicTitle = "CV outputs"; -#endif - basicOptions = cvOutputChannel; - } - void beginSession(MenuItem* navigatedBackwardFrom) { - if (!navigatedBackwardFrom) { - soundEditor.currentValue = 0; + using menu_item::Selection<2>::Selection; + + void beginSession(MenuItem* navigatedBackwardFrom) override { + if (navigatedBackwardFrom == nullptr) { + this->value_ = 0; } else { - soundEditor.currentValue = soundEditor.currentSourceIndex; + this->value_ = soundEditor.currentSourceIndex; } - menu_item::Selection::beginSession(navigatedBackwardFrom); + menu_item::Selection<2>::beginSession(navigatedBackwardFrom); } - MenuItem* selectButtonPress() { - soundEditor.currentSourceIndex = soundEditor.currentValue; + MenuItem* selectButtonPress() override { + soundEditor.currentSourceIndex = this->value_; #if HAVE_OLED - cvSubmenu.basicTitle = cvOutputChannel[soundEditor.currentValue]; - setCvNumberForTitle(soundEditor.currentValue); + cvSubmenu.title = getOptions().at(this->value_); + setCvNumberForTitle(this->value_); #endif return &cvSubmenu; } + + static_vector getOptions() override { +#if HAVE_OLED + return {"CV output 1", "CV output 2"}; +#else + return {"Out1", "Out2"}; +#endif + } }; -} // namespace menu_item::cv +} // namespace deluge::gui::menu_item::cv diff --git a/src/deluge/gui/menu_item/cv/transpose.h b/src/deluge/gui/menu_item/cv/transpose.h index b67c9d257c..f23755f6ef 100644 --- a/src/deluge/gui/menu_item/cv/transpose.h +++ b/src/deluge/gui/menu_item/cv/transpose.h @@ -16,27 +16,32 @@ */ #pragma once #include "gui/menu_item/decimal.h" +#include "gui/menu_item/formatted_title.h" #include "gui/ui/sound_editor.h" #include "processing/engines/cv_engine.h" -namespace menu_item::cv { -class Transpose final : public Decimal { +namespace deluge::gui::menu_item::cv { +class Transpose final : public Decimal, public FormattedTitle { public: - using Decimal::Decimal; - int32_t getMinValue() const { return -9600; } - int32_t getMaxValue() const { return 9600; } - int32_t getNumDecimalPlaces() const { return 2; } - void readCurrentValue() { - soundEditor.currentValue = (int32_t)cvEngine.cvChannels[soundEditor.currentSourceIndex].transpose * 100 - + cvEngine.cvChannels[soundEditor.currentSourceIndex].cents; + Transpose(const string& name, const string& title_format_str) : Decimal(name), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + [[nodiscard]] int32_t getMinValue() const override { return -9600; } + [[nodiscard]] int32_t getMaxValue() const override { return 9600; } + [[nodiscard]] int32_t getNumDecimalPlaces() const override { return 2; } + + void readCurrentValue() override { + this->value_ = (int32_t)cvEngine.cvChannels[soundEditor.currentSourceIndex].transpose * 100 + + cvEngine.cvChannels[soundEditor.currentSourceIndex].cents; } - void writeCurrentValue() { - int32_t currentValue = soundEditor.currentValue + 25600; + + void writeCurrentValue() override { + int32_t currentValue = this->value_ + 25600; int32_t semitones = (currentValue + 50) / 100; int32_t cents = currentValue - semitones * 100; cvEngine.setCVTranspose(soundEditor.currentSourceIndex, semitones - 256, cents); } }; - -} // namespace menu_item::cv +} // namespace deluge::gui::menu_item::cv diff --git a/src/deluge/gui/menu_item/cv/volts.h b/src/deluge/gui/menu_item/cv/volts.h index 1714fa933a..4962514104 100644 --- a/src/deluge/gui/menu_item/cv/volts.h +++ b/src/deluge/gui/menu_item/cv/volts.h @@ -16,25 +16,30 @@ */ #pragma once #include "gui/menu_item/decimal.h" +#include "gui/menu_item/formatted_title.h" #include "gui/ui/sound_editor.h" #include "hid/display/oled.h" #include "processing/engines/cv_engine.h" -namespace menu_item::cv { -class Volts final : public Decimal { +namespace deluge::gui::menu_item::cv { +class Volts final : public Decimal, public FormattedTitle { public: using Decimal::Decimal; - int32_t getMinValue() const { return 0; } - int32_t getMaxValue() const { return 200; } - int32_t getNumDecimalPlaces() const { return 2; } - int32_t getDefaultEditPos() { return 1; } - void readCurrentValue() { - soundEditor.currentValue = cvEngine.cvChannels[soundEditor.currentSourceIndex].voltsPerOctave; + Volts(const string& name, const string& title_format_str) : Decimal(name), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + [[nodiscard]] int32_t getMinValue() const override { return 0; } + [[nodiscard]] int32_t getMaxValue() const override { return 200; } + [[nodiscard]] int32_t getNumDecimalPlaces() const override { return 2; } + [[nodiscard]] int32_t getDefaultEditPos() const override { return 1; } + void readCurrentValue() override { + this->value_ = cvEngine.cvChannels[soundEditor.currentSourceIndex].voltsPerOctave; } - void writeCurrentValue() { cvEngine.setCVVoltsPerOctave(soundEditor.currentSourceIndex, soundEditor.currentValue); } + void writeCurrentValue() override { cvEngine.setCVVoltsPerOctave(soundEditor.currentSourceIndex, this->value_); } #if HAVE_OLED - void drawPixelsForOled() { - if (soundEditor.currentValue == 0) { + void drawPixelsForOled() override { + if (this->value_ == 0) { OLED::drawStringCentred("Hz/V", 20, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, kTextHugeSpacingX, kTextHugeSizeY); } @@ -43,18 +48,19 @@ class Volts final : public Decimal { } } #else - void drawValue() { - if (soundEditor.currentValue == 0) + void drawValue() override { + if (this->value_ == 0) { numericDriver.setText("HZPV", false, 255, true); + } else { Decimal::drawValue(); } } #endif - void horizontalEncoderAction(int32_t offset) { - if (soundEditor.currentValue != 0) { + void horizontalEncoderAction(int32_t offset) override { + if (this->value_ != 0) { Decimal::horizontalEncoderAction(offset); } } }; -} // namespace menu_item::cv +} // namespace deluge::gui::menu_item::cv diff --git a/src/deluge/gui/menu_item/decimal.cpp b/src/deluge/gui/menu_item/decimal.cpp index b59d333d65..45c09cd927 100644 --- a/src/deluge/gui/menu_item/decimal.cpp +++ b/src/deluge/gui/menu_item/decimal.cpp @@ -31,7 +31,7 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item { +namespace deluge::gui::menu_item { void Decimal::beginSession(MenuItem* navigatedBackwardFrom) { soundEditor.numberScrollAmount = 0; @@ -59,21 +59,21 @@ void Decimal::drawValue() { void Decimal::selectEncoderAction(int32_t offset) { - soundEditor.currentValue += offset * soundEditor.numberEditSize; + this->value_ += offset * soundEditor.numberEditSize; // If turned down if (offset < 0) { int32_t minValue = getMinValue(); - if (soundEditor.currentValue < minValue) { - soundEditor.currentValue = minValue; + if (this->value_ < minValue) { + this->value_ = minValue; } } // If turned up else { int32_t maxValue = getMaxValue(); - if (soundEditor.currentValue > maxValue) { - soundEditor.currentValue = maxValue; + if (this->value_ > maxValue) { + this->value_ = maxValue; } } @@ -110,10 +110,10 @@ void Decimal::horizontalEncoderAction(int32_t offset) { } void Decimal::scrollToGoodPos() { - int32_t numDigits = getNumDecimalDigits(std::abs(soundEditor.currentValue)); + int32_t numDigits = getNumDecimalDigits(std::abs(this->value_)); // Negative numbers - if (soundEditor.currentValue < 0) { + if (this->value_ < 0) { soundEditor.numberScrollAmount = std::max(numDigits - 3, soundEditor.numberEditPos - 2); } @@ -138,7 +138,7 @@ void Decimal::scrollToGoodPos() { void Decimal::drawPixelsForOled() { int32_t numDecimalPlaces = getNumDecimalPlaces(); char buffer[13]; - intToString(soundEditor.currentValue, buffer, numDecimalPlaces + 1); + intToString(this->value_, buffer, numDecimalPlaces + 1); int32_t length = strlen(buffer); int32_t editingChar = length - soundEditor.numberEditPos; @@ -169,7 +169,7 @@ void Decimal::drawActualValue(bool justDidHorizontalScroll) { char buffer[12]; int32_t minNumDigits = getNumDecimalPlaces() + 1; minNumDigits = std::max(minNumDigits, soundEditor.numberEditPos + 1); - intToString(soundEditor.currentValue, buffer, minNumDigits); + intToString(this->value_, buffer, minNumDigits); int32_t stringLength = strlen(buffer); char* outputText = buffer + std::max(stringLength - 4 - soundEditor.numberScrollAmount, 0_i32); @@ -199,4 +199,4 @@ void Decimal::drawActualValue(bool justDidHorizontalScroll) { } #endif -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/decimal.h b/src/deluge/gui/menu_item/decimal.h index 8a94252061..9ed9e775fa 100644 --- a/src/deluge/gui/menu_item/decimal.h +++ b/src/deluge/gui/menu_item/decimal.h @@ -20,19 +20,19 @@ #include "number.h" #include "patched_param.h" -namespace menu_item { +namespace deluge::gui::menu_item { class Decimal : public Number { public: - Decimal(char const* newName = NULL) : Number(newName) {} - void beginSession(MenuItem* navigatedBackwardFrom = NULL); + using Number::Number; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override; void selectEncoderAction(int32_t offset) final; - void horizontalEncoderAction(int32_t offset); + void horizontalEncoderAction(int32_t offset) override; protected: - void drawValue(); - virtual int32_t getNumDecimalPlaces() const = 0; - virtual int32_t getDefaultEditPos() const { return 2; } + virtual void drawValue(); + [[nodiscard]] virtual int32_t getNumDecimalPlaces() const = 0; + [[nodiscard]] virtual int32_t getDefaultEditPos() const { return 2; } #if HAVE_OLED void drawPixelsForOled(); #else @@ -43,4 +43,4 @@ class Decimal : public Number { void scrollToGoodPos(); }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/defaults/bend_range.h b/src/deluge/gui/menu_item/defaults/bend_range.h index 0af89632b9..d7f7227c8c 100644 --- a/src/deluge/gui/menu_item/defaults/bend_range.h +++ b/src/deluge/gui/menu_item/defaults/bend_range.h @@ -19,11 +19,11 @@ #include "gui/ui/sound_editor.h" #include "storage/flash_storage.h" -namespace menu_item::defaults { +namespace deluge::gui::menu_item::defaults { class BendRange final : public menu_item::BendRange { public: using menu_item::BendRange::BendRange; - void readCurrentValue() { soundEditor.currentValue = FlashStorage::defaultBendRange[BEND_RANGE_MAIN]; } - void writeCurrentValue() { FlashStorage::defaultBendRange[BEND_RANGE_MAIN] = soundEditor.currentValue; } + void readCurrentValue() override { this->value_ = FlashStorage::defaultBendRange[BEND_RANGE_MAIN]; } + void writeCurrentValue() override { FlashStorage::defaultBendRange[BEND_RANGE_MAIN] = this->value_; } }; -} // namespace menu_item::defaults +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/defaults/magnitude.h b/src/deluge/gui/menu_item/defaults/magnitude.h index 3339d3e481..4a939ba936 100644 --- a/src/deluge/gui/menu_item/defaults/magnitude.h +++ b/src/deluge/gui/menu_item/defaults/magnitude.h @@ -15,30 +15,29 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/enumeration/enumeration.h" #include "gui/ui/sound_editor.h" #include "hid/display/numeric_driver.h" #include "hid/display/oled.h" #include "storage/flash_storage.h" -namespace menu_item::defaults { -class Magnitude final : public Selection { +namespace deluge::gui::menu_item::defaults { +class Magnitude final : public Enumeration<7> { public: - using Selection::Selection; - int32_t getNumOptions() { return 7; } - void readCurrentValue() { soundEditor.currentValue = FlashStorage::defaultMagnitude; } - void writeCurrentValue() { FlashStorage::defaultMagnitude = soundEditor.currentValue; } + using Enumeration::Enumeration; + void readCurrentValue() override { this->value_ = FlashStorage::defaultMagnitude; } + void writeCurrentValue() override { FlashStorage::defaultMagnitude = this->value_; } #if HAVE_OLED - void drawPixelsForOled() { + void drawPixelsForOled() override { char buffer[12]; - intToString(96 << soundEditor.currentValue, buffer); + intToString(96 << this->value_, buffer); OLED::drawStringCentred(buffer, 20 + OLED_MAIN_TOPMOST_PIXEL, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, 18, 20); } #else - void drawValue() { - numericDriver.setTextAsNumber(96 << soundEditor.currentValue); + void drawValue() override { + numericDriver.setTextAsNumber(96 << this->value_); } #endif }; -} // namespace menu_item::defaults +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/defaults/scale.h b/src/deluge/gui/menu_item/defaults/scale.h index 65ed77f487..15a9ebe1ec 100644 --- a/src/deluge/gui/menu_item/defaults/scale.h +++ b/src/deluge/gui/menu_item/defaults/scale.h @@ -15,18 +15,20 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" #include "storage/flash_storage.h" +#include "util/container/static_vector.hpp" #include "util/lookuptables/lookuptables.h" -namespace menu_item::defaults { -class Scale final : public Selection { +namespace deluge::gui::menu_item::defaults { +class Scale final : public Selection { public: using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = FlashStorage::defaultScale; } - void writeCurrentValue() { FlashStorage::defaultScale = soundEditor.currentValue; } - int32_t getNumOptions() { return NUM_PRESET_SCALES + 2; } - char const** getOptions() { return presetScaleNames; } + void readCurrentValue() override { this->value_ = FlashStorage::defaultScale; } + void writeCurrentValue() override { FlashStorage::defaultScale = this->value_; } + static_vector getOptions() override { + return {presetScaleNames.begin(), presetScaleNames.begin() + capacity()}; + } }; -} // namespace menu_item::defaults +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/defaults/velocity.h b/src/deluge/gui/menu_item/defaults/velocity.h index 55b87208fa..44c89c9248 100644 --- a/src/deluge/gui/menu_item/defaults/velocity.h +++ b/src/deluge/gui/menu_item/defaults/velocity.h @@ -20,16 +20,16 @@ #include "model/song/song.h" #include "storage/flash_storage.h" -namespace menu_item::defaults { +namespace deluge::gui::menu_item::defaults { class Velocity final : public Integer { public: using Integer::Integer; - int32_t getMinValue() const { return 1; } - int32_t getMaxValue() const { return 127; } - void readCurrentValue() { soundEditor.currentValue = FlashStorage::defaultVelocity; } - void writeCurrentValue() { - FlashStorage::defaultVelocity = soundEditor.currentValue; + [[nodiscard]] int32_t getMinValue() const override { return 1; } + [[nodiscard]] int32_t getMaxValue() const override { return 127; } + void readCurrentValue() override { this->value_ = FlashStorage::defaultVelocity; } + void writeCurrentValue() override { + FlashStorage::defaultVelocity = this->value_; currentSong->setDefaultVelocityForAllInstruments(FlashStorage::defaultVelocity); } }; -} // namespace menu_item::defaults +} // namespace deluge::gui::menu_item::defaults diff --git a/src/deluge/gui/menu_item/delay/analog.h b/src/deluge/gui/menu_item/delay/analog.h index 9cf9384805..4606ad5de8 100644 --- a/src/deluge/gui/menu_item/delay/analog.h +++ b/src/deluge/gui/menu_item/delay/analog.h @@ -15,30 +15,19 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/menu_item/sync_level.h" #include "gui/ui/sound_editor.h" #include "model/mod_controllable/mod_controllable_audio.h" -namespace menu_item::delay { +namespace deluge::gui::menu_item::delay { -class Analog final : public Selection { +class Analog final : public Selection<2> { public: using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentModControllable->delay.analog; } - void writeCurrentValue() { soundEditor.currentModControllable->delay.analog = soundEditor.currentValue; } - char const** getOptions() { - static char const* options[] = { - "Digital", -#if HAVE_OLED - "Analog", - NULL -#else - "ANA" -#endif - }; - return options; - } + void readCurrentValue() override { this->value_ = soundEditor.currentModControllable->delay.analog; } + void writeCurrentValue() override { soundEditor.currentModControllable->delay.analog = this->value_; } + static_vector getOptions() override { return {"Digital", HAVE_OLED ? "Analog" : "ANA"}; } }; -} // namespace menu_item::delay +} // namespace deluge::gui::menu_item::delay diff --git a/src/deluge/gui/menu_item/delay/ping_pong.h b/src/deluge/gui/menu_item/delay/ping_pong.h index 1d737913d3..4e898b1f09 100644 --- a/src/deluge/gui/menu_item/delay/ping_pong.h +++ b/src/deluge/gui/menu_item/delay/ping_pong.h @@ -15,18 +15,18 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" #include "gui/menu_item/sync_level.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "model/mod_controllable/mod_controllable_audio.h" -namespace menu_item::delay { +namespace deluge::gui::menu_item::delay { -class PingPong final : public Selection { +class PingPong final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentModControllable->delay.pingPong; } - void writeCurrentValue() { soundEditor.currentModControllable->delay.pingPong = soundEditor.currentValue; } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = soundEditor.currentModControllable->delay.pingPong; } + void writeCurrentValue() override { soundEditor.currentModControllable->delay.pingPong = this->value_; } }; -} // namespace menu_item::delay +} // namespace deluge::gui::menu_item::delay diff --git a/src/deluge/gui/menu_item/delay/sync.h b/src/deluge/gui/menu_item/delay/sync.h index 709d062057..1324df51c8 100644 --- a/src/deluge/gui/menu_item/delay/sync.h +++ b/src/deluge/gui/menu_item/delay/sync.h @@ -15,23 +15,23 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/menu_item/sync_level.h" #include "gui/ui/sound_editor.h" #include "model/mod_controllable/mod_controllable_audio.h" -namespace menu_item::delay { +namespace deluge::gui::menu_item::delay { class Sync final : public SyncLevel { public: using SyncLevel::SyncLevel; - void readCurrentValue() { - soundEditor.currentValue = syncTypeAndLevelToMenuOption(soundEditor.currentModControllable->delay.syncType, - soundEditor.currentModControllable->delay.syncLevel); + void readCurrentValue() override { + this->value_ = syncTypeAndLevelToMenuOption(soundEditor.currentModControllable->delay.syncType, + soundEditor.currentModControllable->delay.syncLevel); } - void writeCurrentValue() { - soundEditor.currentModControllable->delay.syncType = menuOptionToSyncType(soundEditor.currentValue); - soundEditor.currentModControllable->delay.syncLevel = menuOptionToSyncLevel(soundEditor.currentValue); + void writeCurrentValue() override { + soundEditor.currentModControllable->delay.syncType = menuOptionToSyncType(this->value_); + soundEditor.currentModControllable->delay.syncLevel = menuOptionToSyncLevel(this->value_); } }; -} // namespace menu_item::delay +} // namespace deluge::gui::menu_item::delay diff --git a/src/deluge/gui/menu_item/dev_var/dev_var.h b/src/deluge/gui/menu_item/dev_var/dev_var.h index 9a92ee6119..5789b090a4 100644 --- a/src/deluge/gui/menu_item/dev_var/dev_var.h +++ b/src/deluge/gui/menu_item/dev_var/dev_var.h @@ -19,62 +19,62 @@ #include "gui/ui/sound_editor.h" #include "storage/storage_manager.h" -namespace menu_item::dev_var { +namespace deluge::gui::menu_item::dev_var { class AMenu final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { soundEditor.currentValue = storageManager.devVarA; } - void writeCurrentValue() override { storageManager.devVarA = soundEditor.currentValue; } - int32_t getMaxValue() const override { return 512; } + void readCurrentValue() override { this->value_ = storageManager.devVarA; } + void writeCurrentValue() override { storageManager.devVarA = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 512; } }; class BMenu final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { soundEditor.currentValue = storageManager.devVarB; } - void writeCurrentValue() override { storageManager.devVarB = soundEditor.currentValue; } - int32_t getMaxValue() const override { return 512; } + void readCurrentValue() override { this->value_ = storageManager.devVarB; } + void writeCurrentValue() override { storageManager.devVarB = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 512; } }; class CMenu final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { soundEditor.currentValue = storageManager.devVarC; } - void writeCurrentValue() override { storageManager.devVarC = soundEditor.currentValue; } - int32_t getMaxValue() const override { return 1024; } + void readCurrentValue() override { this->value_ = storageManager.devVarC; } + void writeCurrentValue() override { storageManager.devVarC = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 1024; } }; class DMenu final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { soundEditor.currentValue = storageManager.devVarD; } - void writeCurrentValue() override { storageManager.devVarD = soundEditor.currentValue; } - int32_t getMaxValue() const override { return 1024; } + void readCurrentValue() override { this->value_ = storageManager.devVarD; } + void writeCurrentValue() override { storageManager.devVarD = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 1024; } }; class EMenu final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { soundEditor.currentValue = storageManager.devVarE; } - void writeCurrentValue() override { storageManager.devVarE = soundEditor.currentValue; } - int32_t getMaxValue() const override { return 1024; } + void readCurrentValue() override { this->value_ = storageManager.devVarE; } + void writeCurrentValue() override { storageManager.devVarE = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 1024; } }; class FMenu final : public Integer { public: using Integer::Integer; - void readCurrentValue() override { soundEditor.currentValue = storageManager.devVarF; } - void writeCurrentValue() override { storageManager.devVarF = soundEditor.currentValue; } - int32_t getMaxValue() const override { return 1024; } + void readCurrentValue() override { this->value_ = storageManager.devVarF; } + void writeCurrentValue() override { storageManager.devVarF = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 1024; } }; class GMenu final : public Integer { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = storageManager.devVarG; } - void writeCurrentValue() { storageManager.devVarG = soundEditor.currentValue; } - int32_t getMaxValue() const override { return 1024; } - int32_t getMinValue() const override { return -1024; } + void readCurrentValue() override { this->value_ = storageManager.devVarG; } + void writeCurrentValue() override { storageManager.devVarG = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 1024; } + [[nodiscard]] int32_t getMinValue() const override { return -1024; } }; -} // namespace menu_item::dev_var +} // namespace deluge::gui::menu_item::dev_var diff --git a/src/deluge/gui/menu_item/drum_name.cpp b/src/deluge/gui/menu_item/drum_name.cpp index fbf34247fb..49f1a86241 100644 --- a/src/deluge/gui/menu_item/drum_name.cpp +++ b/src/deluge/gui/menu_item/drum_name.cpp @@ -21,7 +21,7 @@ #include "hid/matrix/matrix_driver.h" #include "util/functions.h" -namespace menu_item { +namespace deluge::gui::menu_item { bool DrumName::isRelevant(Sound* sound, int32_t whichThing) { return soundEditor.editingKit(); @@ -32,4 +32,4 @@ void DrumName::beginSession(MenuItem* navigatedBackwardFrom) { openUI(&renameDrumUI); } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/drum_name.h b/src/deluge/gui/menu_item/drum_name.h index b00954ee56..a8700a830a 100644 --- a/src/deluge/gui/menu_item/drum_name.h +++ b/src/deluge/gui/menu_item/drum_name.h @@ -19,12 +19,12 @@ #include "gui/menu_item/menu_item.h" -namespace menu_item { +namespace deluge::gui::menu_item { class DrumName final : public MenuItem { public: using MenuItem::MenuItem; - void beginSession(MenuItem* navigatedBackwardFrom); - bool isRelevant(Sound* sound, int32_t whichThing); + void beginSession(MenuItem* navigatedBackwardFrom) override; + bool isRelevant(Sound* sound, int32_t whichThing) override; }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/enumeration/enumeration.h b/src/deluge/gui/menu_item/enumeration/enumeration.h new file mode 100644 index 0000000000..e11ff1c4d4 --- /dev/null +++ b/src/deluge/gui/menu_item/enumeration/enumeration.h @@ -0,0 +1,79 @@ +#pragma once +#include "gui/menu_item/value.h" +#include "gui/ui/sound_editor.h" +#include "hid/display/numeric_driver.h" +#include "util/sized.h" + +extern "C" { +#if HAVE_OLED +#include "RZA1/oled/oled_low_level.h" +#endif +} + +namespace deluge::gui::menu_item { + +/** + * @brief An enumeration has a fixed number of items, with values from 1 to n (exclusive) + */ +template +class Enumeration : public Value { +public: + using Value::Value; + void beginSession(MenuItem* navigatedBackwardFrom) override; + void selectEncoderAction(int32_t offset) override; + + virtual size_t size() { return n; }; + +protected: +#if HAVE_OLED + virtual void drawValue(); + virtual void drawPixelsForOled() = 0; +#else + void drawValue() override; +#endif +}; + +template +void Enumeration::beginSession(MenuItem* navigatedBackwardFrom) { + Value::beginSession(navigatedBackwardFrom); +#if HAVE_OLED + soundEditor.menuCurrentScroll = 0; +#else + drawValue(); +#endif +} + +template +void Enumeration::selectEncoderAction(int32_t offset) { + this->value_ += offset; + int32_t numOptions = size(); + +#if HAVE_OLED + if (this->value_ >= numOptions) { + this->value_ = numOptions - 1; + } + else if (this->value_ < 0) { + this->value_ = 0; + } +#else + if (this->value_ >= numOptions) { + this->value_ -= numOptions; + } + else if (this->value_ < 0) { + this->value_ += numOptions; + } +#endif + + Value::selectEncoderAction(offset); +} + +template +void Enumeration::drawValue() { +#if HAVE_OLED + renderUIsForOled(); +#else + numericDriver.setTextAsNumber(this->value_); +#endif +} + +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/enumeration/typed_enumeration.h b/src/deluge/gui/menu_item/enumeration/typed_enumeration.h new file mode 100644 index 0000000000..04195ba979 --- /dev/null +++ b/src/deluge/gui/menu_item/enumeration/typed_enumeration.h @@ -0,0 +1,84 @@ +#pragma once + +#include "util/misc.h" +#include +#pragma once +#include "gui/menu_item/value.h" +#include "gui/ui/sound_editor.h" +#include "hid/display/numeric_driver.h" +#include "util/sized.h" + +extern "C" { +#if HAVE_OLED +#include "RZA1/oled/oled_low_level.h" +#endif +} + +namespace deluge::gui::menu_item { + +/** + * @brief An enumeration has a fixed number of items, with values from 1 to n (exclusive) + */ +template +class TypedEnumeration : public Value { +public: + using Value::Value; + void beginSession(MenuItem* navigatedBackwardFrom) override; + void selectEncoderAction(int32_t offset) override; + + virtual size_t size() { return n; }; + +protected: +#if HAVE_OLED + virtual void drawValue(); + virtual void drawPixelsForOled() = 0; +#else + void drawValue() override; +#endif +}; + +template +void TypedEnumeration::beginSession(MenuItem* navigatedBackwardFrom) { + Value::beginSession(navigatedBackwardFrom); +#if HAVE_OLED + soundEditor.menuCurrentScroll = 0; +#else + drawValue(); +#endif +} + +template +void TypedEnumeration::selectEncoderAction(int32_t offset) { + auto current = util::to_underlying(this->value_) + offset; + auto numOptions = size(); + +#if HAVE_OLED + if (current >= numOptions) { + current = numOptions - 1; + } + else if (current < 0) { + current = 0; + } +#else + if (current >= numOptions) { + current -= numOptions; + } + else if (current < 0) { + current += numOptions; + } +#endif + + this->value_ = static_cast(current); + Value::selectEncoderAction(offset); +} + +template +void TypedEnumeration::drawValue() { +#if HAVE_OLED + renderUIsForOled(); +#else + numericDriver.setTextAsNumber(util::to_underlying(this->value_)); +#endif +} + +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/selection_for_value.h b/src/deluge/gui/menu_item/envelope/segment.h similarity index 63% rename from src/deluge/gui/menu_item/selection_for_value.h rename to src/deluge/gui/menu_item/envelope/segment.h index f0ae9146fb..2199d2daf5 100644 --- a/src/deluge/gui/menu_item/selection_for_value.h +++ b/src/deluge/gui/menu_item/envelope/segment.h @@ -15,19 +15,16 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/formatted_title.h" +#include "gui/menu_item/source/patched_param.h" #include "gui/ui/sound_editor.h" -#include - -namespace menu_item { -template -class SelectionForValue : public Selection { - T& ref_; +namespace deluge::gui::menu_item::envelope { +class Segment : public source::PatchedParam, public FormattedTitle { public: - SelectionForValue(T& value, char const* name = NULL) : ref_(value), Selection(name) {} - void readCurrentValue() { soundEditor.currentValue = ref_; } - void writeCurrentValue() { ref_ = soundEditor.currentValue; }; -}; + Segment(const string& name, const string& title_format_str, int32_t newP) + : PatchedParam(name, newP), FormattedTitle(title_format_str) {} -} // namespace menu_item + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } +}; +} // namespace deluge::gui::menu_item::envelope diff --git a/src/deluge/gui/menu_item/file_selector.cpp b/src/deluge/gui/menu_item/file_selector.cpp index 0cb127ada6..a246a29fa6 100644 --- a/src/deluge/gui/menu_item/file_selector.cpp +++ b/src/deluge/gui/menu_item/file_selector.cpp @@ -28,7 +28,7 @@ #include "processing/sound/sound.h" #include "util/functions.h" -namespace menu_item { +namespace deluge::gui::menu_item { FileSelector fileSelectorMenu{"File browser"}; @@ -72,4 +72,4 @@ MenuPermission FileSelector::checkPermissionToBeginSession(Sound* sound, int32_t return soundEditor.checkPermissionToBeginSessionForRangeSpecificParam(sound, whichThing, false, currentRange); } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/file_selector.h b/src/deluge/gui/menu_item/file_selector.h index 27272b083b..e1ee67646d 100644 --- a/src/deluge/gui/menu_item/file_selector.h +++ b/src/deluge/gui/menu_item/file_selector.h @@ -19,16 +19,17 @@ #include "gui/menu_item/menu_item.h" -namespace menu_item { +namespace deluge::gui::menu_item { class MultiRange; class FileSelector final : public MenuItem { public: using MenuItem::MenuItem; - void beginSession(MenuItem* navigatedBackwardFrom); - bool isRelevant(Sound* sound, int32_t whichThing); - MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, ::MultiRange** currentRange); + void beginSession(MenuItem* navigatedBackwardFrom) override; + bool isRelevant(Sound* sound, int32_t whichThing) override; + MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, + ::MultiRange** currentRange) override; }; extern FileSelector fileSelectorMenu; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/filter/hpf_freq.h b/src/deluge/gui/menu_item/filter/hpf_freq.h index 18a00103fc..37d09dbdb2 100644 --- a/src/deluge/gui/menu_item/filter/hpf_freq.h +++ b/src/deluge/gui/menu_item/filter/hpf_freq.h @@ -19,14 +19,14 @@ #include "gui/ui/sound_editor.h" #include "modulation/patch/patch_cable_set.h" -namespace menu_item::filter { +namespace deluge::gui::menu_item::filter { class HPFFreq final : public patched_param::IntegerNonFM { public: - HPFFreq(char const* newName = 0, int32_t newP = 0) : patched_param::IntegerNonFM(newName, newP) {} + using patched_param::IntegerNonFM::IntegerNonFM; #if !HAVE_OLED - void drawValue() { - if (soundEditor.currentValue == 0 + void drawValue() override { + if (this->value_ == 0 && !soundEditor.currentParamManager->getPatchCableSet()->doesParamHaveSomethingPatchedToIt( ::Param::Local::HPF_FREQ)) { numericDriver.setText("OFF"); @@ -37,4 +37,4 @@ class HPFFreq final : public patched_param::IntegerNonFM { } #endif }; -} // namespace menu_item::filter +} // namespace deluge::gui::menu_item::filter diff --git a/src/deluge/gui/menu_item/filter/lpf_freq.h b/src/deluge/gui/menu_item/filter/lpf_freq.h index 12b771866a..4f55d6c4a9 100644 --- a/src/deluge/gui/menu_item/filter/lpf_freq.h +++ b/src/deluge/gui/menu_item/filter/lpf_freq.h @@ -19,13 +19,13 @@ #include "gui/ui/sound_editor.h" #include "modulation/patch/patch_cable_set.h" -namespace menu_item::filter { +namespace deluge::gui::menu_item::filter { class LPFFreq final : public patched_param::IntegerNonFM { public: - LPFFreq(char const* newName = 0, int32_t newP = 0) : patched_param::IntegerNonFM(newName, newP) {} + using patched_param::IntegerNonFM::IntegerNonFM; #if !HAVE_OLED - void drawValue() { - if (soundEditor.currentValue == 50 + void drawValue() override { + if (this->value_ == 50 && !soundEditor.currentParamManager->getPatchCableSet()->doesParamHaveSomethingPatchedToIt( ::Param::Local::LPF_FREQ)) { numericDriver.setText("Off"); @@ -36,4 +36,4 @@ class LPFFreq final : public patched_param::IntegerNonFM { } #endif }; -} // namespace menu_item::filter +} // namespace deluge::gui::menu_item::filter diff --git a/src/deluge/gui/menu_item/filter/lpf_mode.h b/src/deluge/gui/menu_item/filter/lpf_mode.h index 91f156264e..8b9146f060 100644 --- a/src/deluge/gui/menu_item/filter/lpf_mode.h +++ b/src/deluge/gui/menu_item/filter/lpf_mode.h @@ -16,27 +16,21 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "model/mod_controllable/mod_controllable_audio.h" #include "processing/sound/sound.h" #include "util/misc.h" -namespace menu_item::filter { -class LPFMode final : public Selection { +namespace deluge::gui::menu_item::filter { +class LPFMode final : public TypedSelection<::LPFMode, kNumLPFModes> { public: - LPFMode(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue() { - soundEditor.currentValue = util::to_underlying(soundEditor.currentModControllable->lpfMode); + using TypedSelection::TypedSelection; + void readCurrentValue() override { this->value_ = soundEditor.currentModControllable->lpfMode; } + void writeCurrentValue() override { soundEditor.currentModControllable->lpfMode = this->value_; } + static_vector getOptions() override { return {"12dB", "24dB", "Drive", "SVF"}; } + bool isRelevant(Sound* sound, int32_t whichThing) override { + return ((sound == nullptr) || sound->synthMode != SynthMode::FM); } - void writeCurrentValue() { - soundEditor.currentModControllable->lpfMode = static_cast<::LPFMode>(soundEditor.currentValue); - } - char const** getOptions() { - static char const* options[] = {"12dB", "24dB", "Drive", "SVF", NULL}; - return options; - } - int32_t getNumOptions() { return kNumLPFModes; } - bool isRelevant(Sound* sound, int32_t whichThing) { return (!sound || sound->synthMode != SynthMode::FM); } }; -} // namespace menu_item::filter +} // namespace deluge::gui::menu_item::filter diff --git a/src/deluge/gui/menu_item/firmware/version.h b/src/deluge/gui/menu_item/firmware/version.h index 7c5fa6c522..2f98f9f794 100644 --- a/src/deluge/gui/menu_item/firmware/version.h +++ b/src/deluge/gui/menu_item/firmware/version.h @@ -15,13 +15,13 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" #include "hid/display/numeric_driver.h" #include "hid/display/oled.h" #include -namespace menu_item::firmware { +namespace deluge::gui::menu_item::firmware { class Version final : public MenuItem { public: using MenuItem::MenuItem; @@ -32,7 +32,7 @@ class Version final : public MenuItem { OLED_MAIN_WIDTH_PIXELS, 18, 20); } #else - void beginSession(MenuItem* navigatedBackwardFrom) { + void beginSession(MenuItem* navigatedBackwardFrom) override { drawValue(); } @@ -41,4 +41,4 @@ class Version final : public MenuItem { } #endif }; -} // namespace menu_item::firmware +} // namespace deluge::gui::menu_item::firmware diff --git a/src/deluge/gui/menu_item/flash/status.h b/src/deluge/gui/menu_item/flash/status.h index 8d380d12b7..7f1e2f1fdf 100644 --- a/src/deluge/gui/menu_item/flash/status.h +++ b/src/deluge/gui/menu_item/flash/status.h @@ -15,26 +15,22 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" #include "hid/led/pad_leds.h" #include "storage/flash_storage.h" -namespace menu_item::flash { -class Status final : public Selection { +namespace deluge::gui::menu_item::flash { +class Status final : public Selection<3> { public: using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = PadLEDs::flashCursor; } - void writeCurrentValue() { + void readCurrentValue() override { this->value_ = PadLEDs::flashCursor; } + void writeCurrentValue() override { if (PadLEDs::flashCursor == FLASH_CURSOR_SLOW) { PadLEDs::clearTickSquares(); } - PadLEDs::flashCursor = soundEditor.currentValue; + PadLEDs::flashCursor = this->value_; } - char const** getOptions() { - static char const* options[] = {"Fast", "Off", "Slow", NULL}; - return options; - } - int32_t getNumOptions() { return 3; } + static_vector getOptions() override { return {"Fast", "Off", "Slow"}; } }; -} // namespace menu_item::flash +} // namespace deluge::gui::menu_item::flash diff --git a/src/deluge/gui/menu_item/formatted_title.h b/src/deluge/gui/menu_item/formatted_title.h new file mode 100644 index 0000000000..cd16354b14 --- /dev/null +++ b/src/deluge/gui/menu_item/formatted_title.h @@ -0,0 +1,22 @@ +#pragma once +#include +#include + +#include "util/string.h" + +// Mixin for a formatted title +class FormattedTitle { +public: + FormattedTitle(deluge::string format_str) : format_str_(std::move(format_str)) {} + + template + void format(Args&&... args) { + title_ = fmt::format(fmt::runtime(format_str_), args...); + } + + [[nodiscard]] const deluge::string& title() const { return title_; } + +private: + deluge::string format_str_; + deluge::string title_; +}; diff --git a/src/deluge/gui/menu_item/fx/clipping.h b/src/deluge/gui/menu_item/fx/clipping.h index ed6ce23037..0b9d70de16 100644 --- a/src/deluge/gui/menu_item/fx/clipping.h +++ b/src/deluge/gui/menu_item/fx/clipping.h @@ -19,15 +19,15 @@ #include "gui/ui/sound_editor.h" #include "model/mod_controllable/mod_controllable_audio.h" -namespace menu_item::fx { +namespace deluge::gui::menu_item::fx { class Clipping final : public IntegerWithOff { public: using IntegerWithOff::IntegerWithOff; - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentModControllable->clippingAmount; } - void writeCurrentValue() { soundEditor.currentModControllable->clippingAmount = soundEditor.currentValue; } - int32_t getMaxValue() const { return 15; } + void readCurrentValue() override { this->value_ = soundEditor.currentModControllable->clippingAmount; } + void writeCurrentValue() override { soundEditor.currentModControllable->clippingAmount = this->value_; } + [[nodiscard]] int32_t getMaxValue() const override { return 15; } }; -} // namespace menu_item::fx +} // namespace deluge::gui::menu_item::fx diff --git a/src/deluge/gui/menu_item/gate/mode.h b/src/deluge/gui/menu_item/gate/mode.h index 021ba7ed30..1814f9329b 100644 --- a/src/deluge/gui/menu_item/gate/mode.h +++ b/src/deluge/gui/menu_item/gate/mode.h @@ -16,35 +16,53 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "processing/engines/cv_engine.h" #include "util/misc.h" -namespace menu_item::gate { -#if HAVE_OLED -// Why'd I put two NULLs? (Rohan) -// Gets updated in gate::Selection lol (Kate) -static char const* mode_options[] = {"V-trig", "S-trig", NULL, NULL}; -#else -static char const* mode_options[] = {"VTRI", "STRI", NULL, NULL}; -#endif +namespace deluge::gui::menu_item::gate { +static deluge::string mode_title = HAVE_OLED ? "Gate outX mode" : ""; + +class Mode final : public TypedSelection { #if HAVE_OLED -static char mode_title[] = "Gate outX mode"; + static_vector options_ = {"V-trig", "S-trig"}; #else -static char* mode_title = nullptr; + static_vector options_ = {"VTRI", "STRI"}; #endif -class Mode final : public Selection { public: - Mode() : Selection(mode_title) { basicOptions = mode_options; } - void readCurrentValue() { - soundEditor.currentValue = util::to_underlying(cvEngine.gateChannels[soundEditor.currentSourceIndex].mode); + Mode() : TypedSelection(mode_title) { + } + void readCurrentValue() override { + this->value_ = cvEngine.gateChannels[soundEditor.currentSourceIndex].mode; } - void writeCurrentValue() { - cvEngine.setGateType(soundEditor.currentSourceIndex, static_cast(soundEditor.currentValue)); + void writeCurrentValue() override { + cvEngine.setGateType(soundEditor.currentSourceIndex, this->value_); + } + static_vector getOptions() override { + return options_; + } + + void updateOptions(int32_t value) { + switch (value) { + case WHICH_GATE_OUTPUT_IS_CLOCK: + options_[2] = "Clock"; + break; + + case WHICH_GATE_OUTPUT_IS_RUN: + options_[2] = HAVE_OLED ? "\"Run\" signal" : "Run"; + break; + + default: + // Remove the extra entry if it's present + if (options_.size() > 2) { + options_.pop_back(); + } + break; + } } }; -} // namespace menu_item::gate +} // namespace deluge::gui::menu_item::gate diff --git a/src/deluge/gui/menu_item/gate/off_time.h b/src/deluge/gui/menu_item/gate/off_time.h index b51516d067..00148280f2 100644 --- a/src/deluge/gui/menu_item/gate/off_time.h +++ b/src/deluge/gui/menu_item/gate/off_time.h @@ -19,15 +19,15 @@ #include "gui/ui/sound_editor.h" #include "processing/engines/cv_engine.h" -namespace menu_item::gate { +namespace deluge::gui::menu_item::gate { class OffTime final : public Decimal { public: using Decimal::Decimal; - int32_t getMinValue() const { return 1; } - int32_t getMaxValue() const { return 100; } - int32_t getNumDecimalPlaces() const { return 1; } - int32_t getDefaultEditPos() { return 1; } - void readCurrentValue() { soundEditor.currentValue = cvEngine.minGateOffTime; } - void writeCurrentValue() { cvEngine.minGateOffTime = soundEditor.currentValue; } + [[nodiscard]] int32_t getMinValue() const override { return 1; } + [[nodiscard]] int32_t getMaxValue() const override { return 100; } + [[nodiscard]] int32_t getNumDecimalPlaces() const override { return 1; } + [[nodiscard]] int32_t getDefaultEditPos() const override { return 1; } + void readCurrentValue() override { this->value_ = cvEngine.minGateOffTime; } + void writeCurrentValue() override { cvEngine.minGateOffTime = this->value_; } }; -} // namespace menu_item::gate +} // namespace deluge::gui::menu_item::gate diff --git a/src/deluge/gui/menu_item/gate/selection.h b/src/deluge/gui/menu_item/gate/selection.h index 76374909e0..2a70813086 100644 --- a/src/deluge/gui/menu_item/gate/selection.h +++ b/src/deluge/gui/menu_item/gate/selection.h @@ -16,63 +16,51 @@ */ #pragma once #include "gui/menu_item/gate/mode.h" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" #include "mode.h" #include "off_time.h" +#include "util/container/static_vector.hpp" -extern menu_item::gate::OffTime gateOffTimeMenu; -extern menu_item::gate::Mode gateModeMenu; +extern deluge::gui::menu_item::gate::OffTime gateOffTimeMenu; +extern deluge::gui::menu_item::gate::Mode gateModeMenu; +namespace deluge::gui::menu_item::gate { -namespace menu_item::gate { -class Selection final : public menu_item::Selection { +class Selection final : public menu_item::Selection<5> { public: - Selection(char const* newName = NULL) : menu_item::Selection(newName) { -#if HAVE_OLED - basicTitle = "Gate outputs"; - static char const* options[] = {"Gate output 1", "Gate output 2", "Gate output 3", - "Gate output 4", "Minimum off-time", NULL}; -#else - static char const* options[] = {"Out1", "Out2", "Out3", "Out4", "OFFT", NULL}; -#endif - basicOptions = options; - } - void beginSession(MenuItem* navigatedBackwardFrom) { - if (!navigatedBackwardFrom) { - soundEditor.currentValue = 0; + using menu_item::Selection::Selection; + + void beginSession(MenuItem* navigatedBackwardFrom) override { + if (navigatedBackwardFrom == nullptr) { + this->value_ = 0; } else { - soundEditor.currentValue = soundEditor.currentSourceIndex; + this->value_ = soundEditor.currentSourceIndex; } - menu_item::Selection::beginSession(navigatedBackwardFrom); + menu_item::Selection::beginSession(navigatedBackwardFrom); } - MenuItem* selectButtonPress() { - if (soundEditor.currentValue == NUM_GATE_CHANNELS) { + MenuItem* selectButtonPress() override { + if (this->value_ == NUM_GATE_CHANNELS) { return &gateOffTimeMenu; } - else { - soundEditor.currentSourceIndex = soundEditor.currentValue; + soundEditor.currentSourceIndex = this->value_; #if HAVE_OLED - gate::mode_title[8] = '1' + soundEditor.currentValue; + gate::mode_title[8] = '1' + this->value_; #endif - // TODO: this needs to be a "UpdateOptions" method on gate::Mode - switch (soundEditor.currentValue) { - case WHICH_GATE_OUTPUT_IS_CLOCK: - mode_options[2] = "Clock"; - break; + // TODO: this needs to be a "UpdateOptions" method on gate::Mode + gateModeMenu.updateOptions(this->value_); + return &gateModeMenu; + } - case WHICH_GATE_OUTPUT_IS_RUN: - mode_options[2] = HAVE_OLED ? "\"Run\" signal" : "Run"; - break; + static_vector getOptions() override { +#if HAVE_OLED - default: - mode_options[2] = NULL; - break; - } - return &gateModeMenu; - } + return {"Gate output 1", "Gate output 2", "Gate output 3", "Gate output 4", "Minimum off-time"}; +#else + return {"Out1", "Out2", "Out3", "Out4", "OFFT"}; +#endif } }; -} // namespace menu_item::gate +} // namespace deluge::gui::menu_item::gate diff --git a/src/deluge/gui/menu_item/integer.cpp b/src/deluge/gui/menu_item/integer.cpp index 5647a57fcb..2c65d4e1d4 100644 --- a/src/deluge/gui/menu_item/integer.cpp +++ b/src/deluge/gui/menu_item/integer.cpp @@ -28,18 +28,18 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item { +namespace deluge::gui::menu_item { void Integer::selectEncoderAction(int32_t offset) { - soundEditor.currentValue += offset; + this->value_ += offset; int32_t maxValue = getMaxValue(); - if (soundEditor.currentValue > maxValue) { - soundEditor.currentValue = maxValue; + if (this->value_ > maxValue) { + this->value_ = maxValue; } else { int32_t minValue = getMinValue(); - if (soundEditor.currentValue < minValue) { - soundEditor.currentValue = minValue; + if (this->value_ < minValue) { + this->value_ = minValue; } } @@ -48,11 +48,11 @@ void Integer::selectEncoderAction(int32_t offset) { #if !HAVE_OLED void Integer::drawValue() { - numericDriver.setTextAsNumber(soundEditor.currentValue); + numericDriver.setTextAsNumber(this->value_); } void IntegerWithOff::drawValue() { - if (soundEditor.currentValue == 0) { + if (this->value_ == 0) { numericDriver.setText("OFF"); } else { @@ -64,7 +64,7 @@ void IntegerWithOff::drawValue() { #if HAVE_OLED void Integer::drawInteger(int32_t textWidth, int32_t textHeight, int32_t yPixel) { char buffer[12]; - intToString(soundEditor.currentValue, buffer, 1); + intToString(this->value_, buffer, 1); OLED::drawStringCentred(buffer, yPixel + OLED_MAIN_TOPMOST_PIXEL, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, textWidth, textHeight); } @@ -84,4 +84,4 @@ void IntegerContinuous::drawPixelsForOled() { drawBar(35, 10); } #endif -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/integer.h b/src/deluge/gui/menu_item/integer.h index 60941ffb66..94ef84b2bc 100644 --- a/src/deluge/gui/menu_item/integer.h +++ b/src/deluge/gui/menu_item/integer.h @@ -19,7 +19,7 @@ #include "number.h" -namespace menu_item { +namespace deluge::gui::menu_item { class Integer : public Number { public: @@ -53,4 +53,4 @@ class IntegerContinuous : public Integer { #endif }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/integer_range.cpp b/src/deluge/gui/menu_item/integer_range.cpp index 26ccf41b25..647cdf86c4 100644 --- a/src/deluge/gui/menu_item/integer_range.cpp +++ b/src/deluge/gui/menu_item/integer_range.cpp @@ -24,12 +24,7 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item { - -IntegerRange::IntegerRange(char const* newName, int32_t newMin, int32_t newMax) : Range(newName) { - minValue = newMin; - maxValue = newMax; -} +namespace deluge::gui::menu_item { void IntegerRange::beginSession(MenuItem* navigatedBackwardFrom) { Range::beginSession(navigatedBackwardFrom); @@ -151,4 +146,4 @@ int32_t IntegerRange::getRandomValueInRange() { return lower + random(upper - lower); } } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/integer_range.h b/src/deluge/gui/menu_item/integer_range.h index 2fdadf9900..eaebd95d57 100644 --- a/src/deluge/gui/menu_item/integer_range.h +++ b/src/deluge/gui/menu_item/integer_range.h @@ -19,18 +19,19 @@ #include "range.h" -namespace menu_item { +namespace deluge::gui::menu_item { class IntegerRange final : public Range { public: - IntegerRange(char const* newName = NULL, int32_t newMin = 0, int32_t newMax = 0); - void beginSession(MenuItem* navigatedBackwardFrom); - void getText(char* buffer, int32_t* getLeftLength, int32_t* getRightLength, bool mayShowJustOne); - void selectEncoderAction(int32_t offset); + IntegerRange(const string& newName, const string& title, int32_t newMin, int32_t newMax) + : Range(newName, title), minValue(newMin), maxValue(newMax) {} + void beginSession(MenuItem* navigatedBackwardFrom) override; + void getText(char* buffer, int32_t* getLeftLength, int32_t* getRightLength, bool mayShowJustOne) override; + void selectEncoderAction(int32_t offset) override; int32_t getRandomValueInRange(); int32_t lower, upper; int32_t minValue, maxValue; }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/key_range.cpp b/src/deluge/gui/menu_item/key_range.cpp index f4268ea8c9..584713476a 100644 --- a/src/deluge/gui/menu_item/key_range.cpp +++ b/src/deluge/gui/menu_item/key_range.cpp @@ -20,7 +20,7 @@ #include "gui/ui/sound_editor.h" #include "util/functions.h" -namespace menu_item { +namespace deluge::gui::menu_item { void KeyRange::selectEncoderAction(int32_t offset) { @@ -169,4 +169,4 @@ bool KeyRange::isTotallyRandom() { return (range == 11); } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/key_range.h b/src/deluge/gui/menu_item/key_range.h index 94181f84a3..0ac6ea90a9 100644 --- a/src/deluge/gui/menu_item/key_range.h +++ b/src/deluge/gui/menu_item/key_range.h @@ -18,13 +18,13 @@ #pragma once #include "range.h" -namespace menu_item { +namespace deluge::gui::menu_item { class KeyRange final : public Range { public: - KeyRange(char const* newName = NULL) : Range(newName) {} - void getText(char* buffer, int32_t* getLeftLength, int32_t* getRightLength, bool mayShowJustOne); - void selectEncoderAction(int32_t offset); + using Range::Range; + void getText(char* buffer, int32_t* getLeftLength, int32_t* getRightLength, bool mayShowJustOne) override; + void selectEncoderAction(int32_t offset) override; int32_t getRandomValueInRange(); int32_t lower, upper; @@ -32,4 +32,4 @@ class KeyRange final : public Range { private: bool isTotallyRandom(); }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/keyboard/layout.h b/src/deluge/gui/menu_item/keyboard/layout.h index 94da5d66b6..fb43658191 100644 --- a/src/deluge/gui/menu_item/keyboard/layout.h +++ b/src/deluge/gui/menu_item/keyboard/layout.h @@ -16,32 +16,19 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "storage/flash_storage.h" #include "util/misc.h" -namespace menu_item::keyboard { -class Layout final : public Selection { +namespace deluge::gui::menu_item::keyboard { +class Layout final : public TypedSelection { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(FlashStorage::keyboardLayout); } - void writeCurrentValue() { FlashStorage::keyboardLayout = static_cast(soundEditor.currentValue); } - char const** getOptions() { - static char const* options[] = { - "QWERTY", - "AZERTY", -#if HAVE_OLED - "QWERTZ", - NULL -#else - "QRTZ" -#endif - }; - return options; - } - int32_t getNumOptions() { - return kNumKeyboardLayouts; + using TypedSelection::TypedSelection; + void readCurrentValue() override { this->value_ = FlashStorage::keyboardLayout; } + void writeCurrentValue() override { FlashStorage::keyboardLayout = this->value_; } + static_vector getOptions() override { + return {"QWERTY", "AZERTY", HAVE_OLED ? "QWERTZ" : "QRTZ"}; } }; -} // namespace menu_item::keyboard +} // namespace deluge::gui::menu_item::keyboard diff --git a/src/deluge/gui/menu_item/lfo/global/rate.h b/src/deluge/gui/menu_item/lfo/global/rate.h index a3d103b919..311d65e41f 100644 --- a/src/deluge/gui/menu_item/lfo/global/rate.h +++ b/src/deluge/gui/menu_item/lfo/global/rate.h @@ -18,11 +18,11 @@ #include "gui/menu_item/patched_param/integer.h" #include "processing/sound/sound.h" -namespace menu_item::lfo::global { +namespace deluge::gui::menu_item::lfo::global { class Rate final : public patched_param::Integer { public: using Integer::Integer; - bool isRelevant(Sound* sound, int32_t whichThing) { return (sound->lfoGlobalSyncLevel == 0); } + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->lfoGlobalSyncLevel == 0); } }; -} // namespace menu_item::lfo::global +} // namespace deluge::gui::menu_item::lfo::global diff --git a/src/deluge/gui/menu_item/lfo/global/sync.h b/src/deluge/gui/menu_item/lfo/global/sync.h index 3e923c36e3..d686f427d9 100644 --- a/src/deluge/gui/menu_item/lfo/global/sync.h +++ b/src/deluge/gui/menu_item/lfo/global/sync.h @@ -21,21 +21,21 @@ #include "model/song/song.h" #include "processing/sound/sound.h" -namespace menu_item::lfo::global { +namespace deluge::gui::menu_item::lfo::global { class Sync final : public SyncLevel { public: using SyncLevel::SyncLevel; void readCurrentValue() { - soundEditor.currentValue = syncTypeAndLevelToMenuOption(soundEditor.currentSound->lfoGlobalSyncType, - soundEditor.currentSound->lfoGlobalSyncLevel); + this->value_ = syncTypeAndLevelToMenuOption(soundEditor.currentSound->lfoGlobalSyncType, + soundEditor.currentSound->lfoGlobalSyncLevel); } void writeCurrentValue() { - soundEditor.currentSound->setLFOGlobalSyncType(menuOptionToSyncType(soundEditor.currentValue)); - soundEditor.currentSound->setLFOGlobalSyncLevel(menuOptionToSyncLevel(soundEditor.currentValue)); + soundEditor.currentSound->setLFOGlobalSyncType(menuOptionToSyncType(this->value_)); + soundEditor.currentSound->setLFOGlobalSyncLevel(menuOptionToSyncLevel(this->value_)); soundEditor.currentSound->setupPatchingForAllParamManagers(currentSong); } }; -} // namespace menu_item::lfo::global +} // namespace deluge::gui::menu_item::lfo::global diff --git a/src/deluge/gui/menu_item/lfo/global/type.h b/src/deluge/gui/menu_item/lfo/global/type.h index 32ef3711a9..81f13c88fd 100644 --- a/src/deluge/gui/menu_item/lfo/global/type.h +++ b/src/deluge/gui/menu_item/lfo/global/type.h @@ -21,18 +21,16 @@ #include "processing/sound/sound.h" #include "util/misc.h" -namespace menu_item::lfo::global { +namespace deluge::gui::menu_item::lfo::global { class Type final : public Shape { public: using Shape::Shape; - void readCurrentValue() { - soundEditor.currentValue = util::to_underlying(soundEditor.currentSound->lfoGlobalWaveType); - } - void writeCurrentValue() { - soundEditor.currentSound->setLFOGlobalWave(static_cast(soundEditor.currentValue)); + void readCurrentValue() override { this->value_ = soundEditor.currentSound->lfoGlobalWaveType; } + void writeCurrentValue() override { + soundEditor.currentSound->setLFOGlobalWave(static_cast(this->value_)); } }; -} // namespace menu_item::lfo::global +} // namespace deluge::gui::menu_item::lfo::global diff --git a/src/deluge/gui/menu_item/lfo/local/type.h b/src/deluge/gui/menu_item/lfo/local/type.h index 0382d234a9..b4c9806db6 100644 --- a/src/deluge/gui/menu_item/lfo/local/type.h +++ b/src/deluge/gui/menu_item/lfo/local/type.h @@ -21,17 +21,15 @@ #include "processing/sound/sound.h" #include "util/misc.h" -namespace menu_item::lfo::local { +namespace deluge::gui::menu_item::lfo::local { class Type final : public Shape { public: using Shape::Shape; - void readCurrentValue() { - soundEditor.currentValue = util::to_underlying(soundEditor.currentSound->lfoLocalWaveType); - } - void writeCurrentValue() { - soundEditor.currentSound->lfoLocalWaveType = static_cast(soundEditor.currentValue); + void readCurrentValue() override { this->value_ = soundEditor.currentSound->lfoLocalWaveType; } + void writeCurrentValue() override { + soundEditor.currentSound->lfoLocalWaveType = static_cast(this->value_); } }; -} // namespace menu_item::lfo::local +} // namespace deluge::gui::menu_item::lfo::local diff --git a/src/deluge/gui/menu_item/lfo/shape.h b/src/deluge/gui/menu_item/lfo/shape.h index b20d4c0c51..daa0003528 100644 --- a/src/deluge/gui/menu_item/lfo/shape.h +++ b/src/deluge/gui/menu_item/lfo/shape.h @@ -16,19 +16,17 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" -namespace menu_item::lfo { +namespace deluge::gui::menu_item::lfo { -class Shape : public Selection { +class Shape : public TypedSelection { public: - using Selection::Selection; + using TypedSelection::TypedSelection; - char const** getOptions() { - static char const* options[] = {"Sine", "Triangle", "Square", "Saw", "S&H", "Random Walk", NULL}; - return options; + static_vector getOptions() override { + return {"Sine", "Triangle", "Square", "Saw", "S&H", "Random Walk"}; } - int32_t getNumOptions() { return kNumLFOTypes; } }; -} // namespace menu_item::lfo +} // namespace deluge::gui::menu_item::lfo diff --git a/src/deluge/gui/menu_item/master_transpose.h b/src/deluge/gui/menu_item/master_transpose.h index dec33e1764..3c2cf6d035 100644 --- a/src/deluge/gui/menu_item/master_transpose.h +++ b/src/deluge/gui/menu_item/master_transpose.h @@ -23,21 +23,21 @@ #include "model/model_stack.h" #include "processing/sound/sound.h" -namespace menu_item { +namespace deluge::gui::menu_item { class MasterTranspose final : public Integer, public PatchedParam { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSound->transpose; } - void writeCurrentValue() { - soundEditor.currentSound->transpose = soundEditor.currentValue; + void readCurrentValue() override { this->value_ = soundEditor.currentSound->transpose; } + void writeCurrentValue() override { + soundEditor.currentSound->transpose = this->value_; char modelStackMemory[MODEL_STACK_MAX_SIZE]; ModelStackWithSoundFlags* modelStack = soundEditor.getCurrentModelStack(modelStackMemory)->addSoundFlags(); soundEditor.currentSound->recalculateAllVoicePhaseIncrements(modelStack); } - MenuItem* selectButtonPress() { return PatchedParam::selectButtonPress(); } - uint8_t shouldDrawDotOnName() { return PatchedParam::shouldDrawDotOnName(); } - uint8_t getPatchedParamIndex() { return ::Param::Local::PITCH_ADJUST; } - uint8_t getP() { return ::Param::Local::PITCH_ADJUST; } + MenuItem* selectButtonPress() override { return PatchedParam::selectButtonPress(); } + uint8_t shouldDrawDotOnName() override { return PatchedParam::shouldDrawDotOnName(); } + uint8_t getPatchedParamIndex() override { return ::Param::Local::PITCH_ADJUST; } + uint8_t getP() override { return ::Param::Local::PITCH_ADJUST; } uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) override { return PatchedParam::shouldBlinkPatchingSourceShortcut(s, colour); } @@ -45,26 +45,26 @@ class MasterTranspose final : public Integer, public PatchedParam { return PatchedParam::patchingSourceShortcutPress(s, previousPressStillActive); } #if !HAVE_OLED - void drawValue() { - PatchedParam::drawValue(); + void drawValue() override { + numericDriver.setTextAsNumber(this->value_, shouldDrawDotOnName()); } #endif - void unlearnAction() { + void unlearnAction() override { MenuItemWithCCLearning::unlearnAction(); } - bool allowsLearnMode() { + bool allowsLearnMode() override { return MenuItemWithCCLearning::allowsLearnMode(); } - void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) { + void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) override { MenuItemWithCCLearning::learnKnob(fromDevice, whichKnob, modKnobMode, midiChannel); }; - int32_t getMinValue() const { + [[nodiscard]] int32_t getMinValue() const override { return -96; } - int32_t getMaxValue() const { + [[nodiscard]] int32_t getMaxValue() const override { return 96; } }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/menu_item.cpp b/src/deluge/gui/menu_item/menu_item.cpp index 8560d2b3e5..da0f4cd744 100644 --- a/src/deluge/gui/menu_item/menu_item.cpp +++ b/src/deluge/gui/menu_item/menu_item.cpp @@ -18,9 +18,7 @@ #include "menu_item.h" #include "hid/display/numeric_driver.h" -#if HAVE_OLED -#include "hid/display/oled.h" -#endif +using namespace deluge; MenuPermission MenuItem::checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) { bool toReturn = isRelevant(sound, whichThing); @@ -33,45 +31,15 @@ void MenuItem::learnCC(MIDIDevice* fromDevice, int32_t channel, int32_t ccNumber #if HAVE_OLED -// This is virtual. Some classes with override it and generate some name on the fly. -// May return pointer to that buffer, or to some other constant char string. -char const* MenuItem::getTitle() { - return basicTitle; -} - void MenuItem::renderOLED() { - OLED::drawScreenTitle(getTitle()); + OLED::drawScreenTitle(getTitle().c_str()); drawPixelsForOled(); } -// A couple of our child classes call this - that's all -void MenuItem::drawItemsForOled(char const** options, int32_t selectedOption) { - - int32_t baseY = (OLED_MAIN_HEIGHT_PIXELS == 64) ? 15 : 14; - baseY += OLED_MAIN_TOPMOST_PIXEL; - - for (int32_t o = 0; o < OLED_HEIGHT_CHARS - 1; o++) { - if (!options[o]) { - break; - } - - int32_t yPixel = o * kTextSpacingY + baseY; - - OLED::drawString(options[o], kTextSpacingX, yPixel, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, - kTextSpacingX, kTextSpacingY); - - if (o == selectedOption) { - OLED::invertArea(0, OLED_MAIN_WIDTH_PIXELS, yPixel, yPixel + 8, &OLED::oledMainImage[0]); - OLED::setupSideScroller(0, options[o], kTextSpacingX, OLED_MAIN_WIDTH_PIXELS, yPixel, yPixel + 8, - kTextSpacingX, kTextSpacingY, true); - } - } -} - #else void MenuItem::drawName() { - numericDriver.setText(getName(), false, shouldDrawDotOnName()); + numericDriver.setText(getName().c_str(), false, shouldDrawDotOnName()); } #endif diff --git a/src/deluge/gui/menu_item/menu_item.h b/src/deluge/gui/menu_item/menu_item.h index 006af3cc95..ceff645b44 100644 --- a/src/deluge/gui/menu_item/menu_item.h +++ b/src/deluge/gui/menu_item/menu_item.h @@ -18,8 +18,15 @@ #pragma once #include "definitions_cxx.hpp" +#include "util/container/static_vector.hpp" +#include "util/sized.h" +#include "util/string.h" #include +#if HAVE_OLED +#include "hid/display/oled.h" +#endif + enum class MenuPermission { NO, YES, @@ -32,83 +39,82 @@ class MIDIDevice; class MenuItem { public: - MenuItem(char const* newName = NULL) { - name = newName; -#if HAVE_OLED - basicTitle = newName; -#endif + MenuItem(const deluge::string& newName = "", const deluge::string& newTitle = "") : name(newName), title(newTitle) { + if (newTitle.empty()) { + title = newName; + } } - char const* name; // As viewed in a menu list. For OLED, up to 20 chars. - virtual char const* getName() { - return name; - } + deluge::string name; // As viewed in a menu list. For OLED, up to 20 chars. + [[nodiscard]] virtual const deluge::string& getName() const { return name; } - virtual void horizontalEncoderAction(int32_t offset) { - } - virtual void selectEncoderAction(int32_t offset) { - } - virtual void beginSession(MenuItem* navigatedBackwardFrom = NULL){}; - virtual bool isRelevant(Sound* sound, int32_t whichThing) { - return true; - } - virtual MenuItem* selectButtonPress() { - return NULL; - } + virtual void horizontalEncoderAction(int32_t offset) {} + virtual void selectEncoderAction(int32_t offset) {} + virtual void beginSession(MenuItem* navigatedBackwardFrom = nullptr){}; + virtual bool isRelevant(Sound* sound, int32_t whichThing) { return true; } + virtual MenuItem* selectButtonPress() { return nullptr; } virtual MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange); - virtual void readValueAgain() { - } - virtual bool selectEncoderActionEditsInstrument() { - return false; - } - virtual uint8_t getPatchedParamIndex() { - return 255; - } - virtual uint8_t getIndexOfPatchedParamToBlink() { - return 255; - } - virtual uint8_t shouldDrawDotOnName() { - return 255; - } - virtual uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) { - return 255; - } + virtual void readValueAgain() {} + virtual bool selectEncoderActionEditsInstrument() { return false; } + virtual uint8_t getPatchedParamIndex() { return 255; } + virtual uint8_t getIndexOfPatchedParamToBlink() { return 255; } + virtual uint8_t shouldDrawDotOnName() { return 255; } + virtual uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) { return 255; } + virtual MenuItem* patchingSourceShortcutPress(PatchSource s, bool previousPressStillActive = false) { - return NULL; - } // NULL means do nothing. 0xFFFFFFFF means go up a level - virtual void unlearnAction() { - } - virtual bool allowsLearnMode() { - return false; - } - virtual void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) { + return nullptr; // nullptr means do nothing. 0xFFFFFFFF means go up a level } + + virtual void unlearnAction() {} + virtual bool allowsLearnMode() { return false; } + virtual void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) {} virtual bool learnNoteOn(MIDIDevice* fromDevice, int32_t channel, int32_t noteCode) { return false; } // Returns whether it was used, I think? virtual void learnCC(MIDIDevice* fromDevice, int32_t channel, int32_t ccNumber, int32_t value); - virtual bool shouldBlinkLearnLed() { - return false; - } - virtual bool isRangeDependent() { - return false; - } - virtual bool usesAffectEntire() { - return false; - } + virtual bool shouldBlinkLearnLed() { return false; } + virtual bool isRangeDependent() { return false; } + virtual bool usesAffectEntire() { return false; } + + deluge::string title; // Can get overridden by getTitle(). Actual max num chars for OLED display is 14. + + /// Get the title to be used when rendering on OLED. If not overriden, defaults to returning `title`. + [[nodiscard]] virtual const deluge::string& getTitle() const { return title; } #if HAVE_OLED - char const* basicTitle; // Can get overridden by getTitle(). Actual max num chars for OLED display is 14. virtual void renderOLED(); virtual void drawPixelsForOled() { } - void drawItemsForOled(char const** options, int32_t selectedOption); - - /// Get the title to be used when rendering on OLED. If not overriden, defaults to returning `basicTitle`. - virtual char const* getTitle(); + template + static void drawItemsForOled(deluge::static_vector& options, int32_t selectedOption, + int32_t offset = 0); #else + /// Get the title to be used when rendering on OLED. If not overriden, defaults to returning `title`. virtual void drawName(); - #endif }; + +#if HAVE_OLED +// A couple of our child classes call this - that's all +template +void MenuItem::drawItemsForOled(deluge::static_vector& options, const int32_t selectedOption, + const int32_t offset) { + int32_t baseY = (OLED_MAIN_HEIGHT_PIXELS == 64) ? 15 : 14; + baseY += OLED_MAIN_TOPMOST_PIXEL; + + auto* it = std::next(options.begin(), offset); // fast-forward to the first option visible + for (int32_t o = 0; o < OLED_HEIGHT_CHARS - 1 && o < options.size() - offset; o++) { + int32_t yPixel = o * kTextSpacingY + baseY; + + OLED::drawString(options[o + offset].c_str(), kTextSpacingX, yPixel, OLED::oledMainImage[0], + OLED_MAIN_WIDTH_PIXELS, kTextSpacingX, kTextSpacingY); + + if (o == selectedOption) { + OLED::invertArea(0, OLED_MAIN_WIDTH_PIXELS, yPixel, yPixel + 8, &OLED::oledMainImage[0]); + OLED::setupSideScroller(0, options[o + offset].c_str(), kTextSpacingX, OLED_MAIN_WIDTH_PIXELS, yPixel, + yPixel + 8, kTextSpacingX, kTextSpacingY, true); + } + } +} +#endif diff --git a/src/deluge/gui/menu_item/menu_item_with_cc_learning.h b/src/deluge/gui/menu_item/menu_item_with_cc_learning.h index d626025c50..c60839a0ea 100644 --- a/src/deluge/gui/menu_item/menu_item_with_cc_learning.h +++ b/src/deluge/gui/menu_item/menu_item_with_cc_learning.h @@ -22,10 +22,10 @@ class MenuItemWithCCLearning { public: - MenuItemWithCCLearning() {} + MenuItemWithCCLearning() = default; virtual ParamDescriptor getLearningThing() = 0; void unlearnAction(); - bool allowsLearnMode() { return true; } + [[nodiscard]] bool allowsLearnMode() const { return true; } void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel); }; diff --git a/src/deluge/gui/menu_item/midi/bank.h b/src/deluge/gui/menu_item/midi/bank.h index aa105b49ae..a73c290dac 100644 --- a/src/deluge/gui/menu_item/midi/bank.h +++ b/src/deluge/gui/menu_item/midi/bank.h @@ -17,16 +17,19 @@ #pragma once #include "gui/menu_item/midi/preset.h" -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { class Bank final : public Preset { public: using Preset::Preset; - void readCurrentValue() { soundEditor.currentValue = ((InstrumentClip*)currentSong->currentClip)->midiBank; } - void writeCurrentValue() { - ((InstrumentClip*)currentSong->currentClip)->midiBank = soundEditor.currentValue; - if (((InstrumentClip*)currentSong->currentClip)->isActiveOnOutput()) { - ((InstrumentClip*)currentSong->currentClip)->sendMIDIPGM(); + void readCurrentValue() override { + this->value_ = (static_cast(currentSong->currentClip))->midiBank; + } + void writeCurrentValue() override { + auto& currentClip = *static_cast(currentSong->currentClip); + currentClip.midiBank = this->value_; + if (currentClip.isActiveOnOutput()) { + currentClip.sendMIDIPGM(); } } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/clock_in_status.h b/src/deluge/gui/menu_item/midi/clock_in_status.h index 371565e315..5a9d4be9ab 100644 --- a/src/deluge/gui/menu_item/midi/clock_in_status.h +++ b/src/deluge/gui/menu_item/midi/clock_in_status.h @@ -15,15 +15,15 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "playback/playback_handler.h" -namespace menu_item::midi { -class ClockInStatus final : public Selection { +namespace deluge::gui::menu_item::midi { +class ClockInStatus final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = playbackHandler.midiInClockEnabled; } - void writeCurrentValue() { playbackHandler.setMidiInClockEnabled(soundEditor.currentValue); } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = playbackHandler.midiInClockEnabled; } + void writeCurrentValue() override { playbackHandler.setMidiInClockEnabled(this->value_); } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/clock_out_status.h b/src/deluge/gui/menu_item/midi/clock_out_status.h index f6ea3382ce..4c98712620 100644 --- a/src/deluge/gui/menu_item/midi/clock_out_status.h +++ b/src/deluge/gui/menu_item/midi/clock_out_status.h @@ -15,15 +15,15 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "playback/playback_handler.h" -namespace menu_item::midi { -class ClockOutStatus final : public Selection { +namespace deluge::gui::menu_item::midi { +class ClockOutStatus final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = playbackHandler.midiOutClockEnabled; } - void writeCurrentValue() { playbackHandler.setMidiOutClockMode(soundEditor.currentValue); } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = playbackHandler.midiOutClockEnabled; } + void writeCurrentValue() override { playbackHandler.setMidiOutClockMode(this->value_); } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/command.cpp b/src/deluge/gui/menu_item/midi/command.cpp index de6394e5a8..da52eaf1bd 100644 --- a/src/deluge/gui/menu_item/midi/command.cpp +++ b/src/deluge/gui/menu_item/midi/command.cpp @@ -28,7 +28,7 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { void Command::beginSession(MenuItem* navigatedBackwardFrom) { #if !HAVE_OLED @@ -91,12 +91,14 @@ void Command::drawPixelsForOled() { } } #else -void Command::drawValue() { - char const* output; - if (!midiEngine.globalMIDICommands[util::to_underlying(commandNumber)].containsSomething()) +void Command::drawValue() const { + char const* output = nullptr; + if (!midiEngine.globalMIDICommands[util::to_underlying(commandNumber)].containsSomething()) { output = "NONE"; - else + } + else { output = "SET"; + } numericDriver.setText(output); } #endif @@ -142,7 +144,8 @@ bool Command::learnNoteOn(MIDIDevice* device, int32_t channel, int32_t noteCode) } void Command::learnCC(MIDIDevice* device, int32_t channel, int32_t ccNumber, int32_t value) { - if (value) + if (value != 0) { learnNoteOn(device, channel + IS_A_CC, ccNumber); + } } -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/command.h b/src/deluge/gui/menu_item/midi/command.h index 86f284354a..e18f9003b1 100644 --- a/src/deluge/gui/menu_item/midi/command.h +++ b/src/deluge/gui/menu_item/midi/command.h @@ -19,27 +19,28 @@ #include "definitions_cxx.hpp" #include "gui/menu_item/menu_item.h" +#include "util/string.h" class MIDIDevice; -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { class Command final : public MenuItem { public: - Command(char const* newName = NULL, GlobalMIDICommand newCommandNumber = GlobalMIDICommand::PLAYBACK_RESTART) + Command(const string& newName, GlobalMIDICommand newCommandNumber = GlobalMIDICommand::PLAYBACK_RESTART) : MenuItem(newName), commandNumber(newCommandNumber) {} - void beginSession(MenuItem* navigatedBackwardFrom); - void drawValue(); - void selectEncoderAction(int32_t offset); - bool allowsLearnMode() { return true; } - bool shouldBlinkLearnLed() { return true; } - void unlearnAction(); - bool learnNoteOn(MIDIDevice* device, int32_t channel, int32_t noteCode); - void learnCC(MIDIDevice* device, int32_t channel, int32_t ccNumber, int32_t value); + void beginSession(MenuItem* navigatedBackwardFrom) override; + void drawValue() const; + void selectEncoderAction(int32_t offset) override; + bool allowsLearnMode() override { return true; } + bool shouldBlinkLearnLed() override { return true; } + void unlearnAction() override; + bool learnNoteOn(MIDIDevice* device, int32_t channel, int32_t noteCode) override; + void learnCC(MIDIDevice* device, int32_t channel, int32_t ccNumber, int32_t value) override; #if HAVE_OLED void drawPixelsForOled(); #endif GlobalMIDICommand commandNumber; }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/default_velocity_to_level.h b/src/deluge/gui/menu_item/midi/default_velocity_to_level.h index d65bc0d746..a0e89d0dae 100644 --- a/src/deluge/gui/menu_item/midi/default_velocity_to_level.h +++ b/src/deluge/gui/menu_item/midi/default_velocity_to_level.h @@ -20,19 +20,18 @@ #include "io/midi/midi_device.h" #include "model/song/song.h" -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { class DefaultVelocityToLevel final : public IntegerWithOff { public: DefaultVelocityToLevel(char const* newName = NULL) : IntegerWithOff(newName) {} - int32_t getMaxValue() const { return 50; } - void readCurrentValue() { - soundEditor.currentValue = - ((int64_t)soundEditor.currentMIDIDevice->defaultVelocityToLevel * 50 + 536870912) >> 30; + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + void readCurrentValue() override { + this->value_ = ((int64_t)soundEditor.currentMIDIDevice->defaultVelocityToLevel * 50 + 536870912) >> 30; } - void writeCurrentValue() { - soundEditor.currentMIDIDevice->defaultVelocityToLevel = soundEditor.currentValue * 21474836; + void writeCurrentValue() override { + soundEditor.currentMIDIDevice->defaultVelocityToLevel = this->value_ * 21474836; currentSong->grabVelocityToLevelFromMIDIDeviceAndSetupPatchingForEverything(soundEditor.currentMIDIDevice); MIDIDeviceManager::anyChangesToSave = true; } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/devices.cpp b/src/deluge/gui/menu_item/midi/devices.cpp index 9be9bd0bf1..f8a7d7b80e 100644 --- a/src/deluge/gui/menu_item/midi/devices.cpp +++ b/src/deluge/gui/menu_item/midi/devices.cpp @@ -21,30 +21,30 @@ #include "hid/display/numeric_driver.h" #include "io/midi/midi_device.h" #include "io/midi/midi_device_manager.h" +#include -extern menu_item::Submenu midiDeviceMenu; +extern deluge::gui::menu_item::Submenu<2> midiDeviceMenu; -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { static const int32_t lowestDeviceNum = -3; void Devices::beginSession(MenuItem* navigatedBackwardFrom) { - if (navigatedBackwardFrom) { - for (soundEditor.currentValue = lowestDeviceNum; - soundEditor.currentValue < MIDIDeviceManager::hostedMIDIDevices.getNumElements(); - soundEditor.currentValue++) { - if (getDevice(soundEditor.currentValue) == soundEditor.currentMIDIDevice) { + if (navigatedBackwardFrom != nullptr) { + for (this->value_ = lowestDeviceNum; this->value_ < MIDIDeviceManager::hostedMIDIDevices.getNumElements(); + this->value_++) { + if (getDevice(this->value_) == soundEditor.currentMIDIDevice) { goto decidedDevice; } } } - soundEditor.currentValue = lowestDeviceNum; // Start on "DIN". That's the only one that'll always be there. + this->value_ = lowestDeviceNum; // Start on "DIN". That's the only one that'll always be there. decidedDevice: - soundEditor.currentMIDIDevice = getDevice(soundEditor.currentValue); + soundEditor.currentMIDIDevice = getDevice(this->value_); #if HAVE_OLED - soundEditor.menuCurrentScroll = soundEditor.currentValue; + soundEditor.menuCurrentScroll = this->value_; #else drawValue(); #endif @@ -52,7 +52,7 @@ void Devices::beginSession(MenuItem* navigatedBackwardFrom) { void Devices::selectEncoderAction(int32_t offset) { do { - int32_t newValue = soundEditor.currentValue + offset; + int32_t newValue = this->value_ + offset; if (newValue >= MIDIDeviceManager::hostedMIDIDevices.getNumElements()) { if (HAVE_OLED) { @@ -67,20 +67,20 @@ void Devices::selectEncoderAction(int32_t offset) { newValue = MIDIDeviceManager::hostedMIDIDevices.getNumElements() - 1; } - soundEditor.currentValue = newValue; + this->value_ = newValue; - soundEditor.currentMIDIDevice = getDevice(soundEditor.currentValue); + soundEditor.currentMIDIDevice = getDevice(this->value_); } while (!soundEditor.currentMIDIDevice->connectionFlags); // Don't show devices which aren't connected. Sometimes we won't even have a name to display for them. #if HAVE_OLED - if (soundEditor.currentValue < soundEditor.menuCurrentScroll) { - soundEditor.menuCurrentScroll = soundEditor.currentValue; + if (this->value_ < soundEditor.menuCurrentScroll) { + soundEditor.menuCurrentScroll = this->value_; } if (offset >= 0) { - int32_t d = soundEditor.currentValue; + int32_t d = this->value_; int32_t numSeen = 1; while (true) { d--; @@ -103,17 +103,19 @@ void Devices::selectEncoderAction(int32_t offset) { } MIDIDevice* Devices::getDevice(int32_t deviceIndex) { - if (deviceIndex == -3) { + switch (deviceIndex) { + case -3: { return &MIDIDeviceManager::dinMIDIPorts; } - else if (deviceIndex == -2) { + case -2: { return &MIDIDeviceManager::upstreamUSBMIDIDevice_port1; } - else if (deviceIndex == -1) { + case -1: { return &MIDIDeviceManager::upstreamUSBMIDIDevice_port2; } - else { - return (MIDIDevice*)MIDIDeviceManager::hostedMIDIDevices.getElement(deviceIndex); + default: { + return static_cast(MIDIDeviceManager::hostedMIDIDevices.getElement(deviceIndex)); + } } } @@ -128,7 +130,7 @@ void Devices::drawValue() { MenuItem* Devices::selectButtonPress() { #if HAVE_OLED - midiDeviceMenu.basicTitle = + midiDeviceMenu.title = soundEditor.currentMIDIDevice->getDisplayName(); // A bit ugly, but saves us extending a class. #endif return &midiDeviceMenu; @@ -137,31 +139,26 @@ MenuItem* Devices::selectButtonPress() { #if HAVE_OLED void Devices::drawPixelsForOled() { - char const* itemNames[kOLEDMenuNumOptionsVisible]; + static_vector itemNames = {}; int32_t selectedRow = -1; - int32_t d = soundEditor.menuCurrentScroll; - int32_t r = 0; - while (r < kOLEDMenuNumOptionsVisible && d < MIDIDeviceManager::hostedMIDIDevices.getNumElements()) { - MIDIDevice* device = getDevice(d); - if (device->connectionFlags) { - itemNames[r] = device->getDisplayName(); - if (d == soundEditor.currentValue) { - selectedRow = r; + int32_t device_idx = soundEditor.menuCurrentScroll; + size_t row = 0; + while (row < kOLEDMenuNumOptionsVisible && device_idx < MIDIDeviceManager::hostedMIDIDevices.getNumElements()) { + MIDIDevice* device = getDevice(device_idx); + if (device->connectionFlags != 0u) { + itemNames[row] = device->getDisplayName(); + if (device_idx == this->value_) { + selectedRow = static_cast(row); } - r++; + row++; } - d++; - } - - while (r < kOLEDMenuNumOptionsVisible) { - itemNames[r] = NULL; - r++; + device_idx++; } - drawItemsForOled(itemNames, selectedRow); + drawItemsForOled(itemNames, selectedRow, soundEditor.menuCurrentScroll); } #endif -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/devices.h b/src/deluge/gui/menu_item/midi/devices.h index 188f9bc419..9242e5006e 100644 --- a/src/deluge/gui/menu_item/midi/devices.h +++ b/src/deluge/gui/menu_item/midi/devices.h @@ -17,22 +17,22 @@ #pragma once -#include "gui/menu_item/menu_item.h" +#include "gui/menu_item/value.h" class MIDIDevice; -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { -class Devices final : public MenuItem { +class Devices final : public Value { public: - using MenuItem::MenuItem; - void beginSession(MenuItem* navigatedBackwardFrom = NULL); - void selectEncoderAction(int32_t offset); + using Value::Value; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override; + void selectEncoderAction(int32_t offset) override; MIDIDevice* getDevice(int32_t deviceIndex); - void drawValue(); - MenuItem* selectButtonPress(); + virtual void drawValue(); + MenuItem* selectButtonPress() override; void drawPixelsForOled(); }; extern Devices devicesMenu; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/input_differentiation.h b/src/deluge/gui/menu_item/midi/input_differentiation.h index a7b28bd8aa..cc2af45a76 100644 --- a/src/deluge/gui/menu_item/midi/input_differentiation.h +++ b/src/deluge/gui/menu_item/midi/input_differentiation.h @@ -15,15 +15,15 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "io/midi/midi_device_manager.h" -namespace menu_item::midi { -class InputDifferentiation final : public Selection { +namespace deluge::gui::menu_item::midi { +class InputDifferentiation final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = MIDIDeviceManager::differentiatingInputsByDevice; } - void writeCurrentValue() { MIDIDeviceManager::differentiatingInputsByDevice = soundEditor.currentValue; } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = MIDIDeviceManager::differentiatingInputsByDevice; } + void writeCurrentValue() override { MIDIDeviceManager::differentiatingInputsByDevice = this->value_; } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/pgm.h b/src/deluge/gui/menu_item/midi/pgm.h index 414875eea9..f0ea4b84af 100644 --- a/src/deluge/gui/menu_item/midi/pgm.h +++ b/src/deluge/gui/menu_item/midi/pgm.h @@ -17,16 +17,19 @@ #pragma once #include "gui/menu_item/midi/preset.h" -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { class PGM final : public Preset { public: using Preset::Preset; - void readCurrentValue() { soundEditor.currentValue = ((InstrumentClip*)currentSong->currentClip)->midiPGM; } - void writeCurrentValue() { - ((InstrumentClip*)currentSong->currentClip)->midiPGM = soundEditor.currentValue; - if (((InstrumentClip*)currentSong->currentClip)->isActiveOnOutput()) { - ((InstrumentClip*)currentSong->currentClip)->sendMIDIPGM(); + void readCurrentValue() override { + this->value_ = (static_cast(currentSong->currentClip))->midiPGM; + } + void writeCurrentValue() override { + auto& currentClip = *(static_cast(currentSong->currentClip)); + currentClip.midiPGM = this->value_; + if (currentClip.isActiveOnOutput()) { + currentClip.sendMIDIPGM(); } } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/preset.h b/src/deluge/gui/menu_item/midi/preset.h index 1e696bf875..2747fb983c 100644 --- a/src/deluge/gui/menu_item/midi/preset.h +++ b/src/deluge/gui/menu_item/midi/preset.h @@ -24,50 +24,50 @@ #include "model/output.h" #include "model/song/song.h" -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { class Preset : public Integer { public: using Integer::Integer; - int32_t getMaxValue() const { return 128; } // Probably not needed cos we override below... + [[nodiscard]] int32_t getMaxValue() const override { return 128; } // Probably not needed cos we override below... #if HAVE_OLED void drawInteger(int32_t textWidth, int32_t textHeight, int32_t yPixel) { char buffer[12]; char const* text; - if (soundEditor.currentValue == 128) { + if (this->value_ == 128) { text = "NONE"; } else { - intToString(soundEditor.currentValue + 1, buffer, 1); + intToString(this->value_ + 1, buffer, 1); text = buffer; } OLED::drawStringCentred(text, yPixel + OLED_MAIN_TOPMOST_PIXEL, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, textWidth, textHeight); } #else - void drawValue() { - if (soundEditor.currentValue == 128) { + void drawValue() override { + if (this->value_ == 128) { numericDriver.setText("NONE"); } else { - numericDriver.setTextAsNumber(soundEditor.currentValue + 1); + numericDriver.setTextAsNumber(this->value_ + 1); } } #endif - bool isRelevant(Sound* sound, int32_t whichThing) { + bool isRelevant(Sound* sound, int32_t whichThing) override { return currentSong->currentClip->output->type == InstrumentType::MIDI_OUT; } - void selectEncoderAction(int32_t offset) { - soundEditor.currentValue += offset; - if (soundEditor.currentValue >= 129) { - soundEditor.currentValue -= 129; + void selectEncoderAction(int32_t offset) override { + this->value_ += offset; + if (this->value_ >= 129) { + this->value_ -= 129; } - else if (soundEditor.currentValue < 0) { - soundEditor.currentValue += 129; + else if (this->value_ < 0) { + this->value_ += 129; } Number::selectEncoderAction(offset); } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/sub.h b/src/deluge/gui/menu_item/midi/sub.h index 3b1f5f7273..bcb4fc69b3 100644 --- a/src/deluge/gui/menu_item/midi/sub.h +++ b/src/deluge/gui/menu_item/midi/sub.h @@ -17,16 +17,17 @@ #pragma once #include "gui/menu_item/midi/preset.h" -namespace menu_item::midi { +namespace deluge::gui::menu_item::midi { class Sub final : public Preset { public: using Preset::Preset; - void readCurrentValue() { soundEditor.currentValue = ((InstrumentClip*)currentSong->currentClip)->midiSub; } + void readCurrentValue() { this->value_ = (static_cast(currentSong->currentClip))->midiSub; } void writeCurrentValue() { - ((InstrumentClip*)currentSong->currentClip)->midiSub = soundEditor.currentValue; - if (((InstrumentClip*)currentSong->currentClip)->isActiveOnOutput()) { - ((InstrumentClip*)currentSong->currentClip)->sendMIDIPGM(); + auto& currentClip = *(static_cast(currentSong->currentClip)); + currentClip.midiSub = this->value_; + if (currentClip.isActiveOnOutput()) { + currentClip.sendMIDIPGM(); } } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/takeover.h b/src/deluge/gui/menu_item/midi/takeover.h index 085487eda1..fe7bc00ab0 100644 --- a/src/deluge/gui/menu_item/midi/takeover.h +++ b/src/deluge/gui/menu_item/midi/takeover.h @@ -16,21 +16,17 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "io/midi/midi_engine.h" #include "util/misc.h" -namespace menu_item::midi { -class Takeover final : public Selection { +namespace deluge::gui::menu_item::midi { +class Takeover final : public TypedSelection { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(midiEngine.midiTakeover); } - void writeCurrentValue() { midiEngine.midiTakeover = static_cast(soundEditor.currentValue); } - char const** getOptions() { - static char const* options[] = {"Jump", "Pickup", "Scale", NULL}; - return options; - } - int32_t getNumOptions() { return kNumMIDITakeoverModes; } + using TypedSelection::TypedSelection; + void readCurrentValue() override { this->value_ = midiEngine.midiTakeover; } + void writeCurrentValue() override { midiEngine.midiTakeover = this->value_; } + static_vector getOptions() override { return {"Jump", "Pickup", "Scale"}; } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/midi/thru.h b/src/deluge/gui/menu_item/midi/thru.h index 298e715aaa..69f3dd1fcd 100644 --- a/src/deluge/gui/menu_item/midi/thru.h +++ b/src/deluge/gui/menu_item/midi/thru.h @@ -15,15 +15,15 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "io/midi/midi_engine.h" -namespace menu_item::midi { -class Thru final : public Selection { +namespace deluge::gui::menu_item::midi { +class Thru final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = midiEngine.midiThru; } - void writeCurrentValue() { midiEngine.midiThru = soundEditor.currentValue; } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = midiEngine.midiThru; } + void writeCurrentValue() override { midiEngine.midiThru = this->value_; } }; -} // namespace menu_item::midi +} // namespace deluge::gui::menu_item::midi diff --git a/src/deluge/gui/menu_item/mod_fx/depth.h b/src/deluge/gui/menu_item/mod_fx/depth.h index 81eaf3ad18..aa87022bd0 100644 --- a/src/deluge/gui/menu_item/mod_fx/depth.h +++ b/src/deluge/gui/menu_item/mod_fx/depth.h @@ -20,7 +20,7 @@ #include "processing/sound/sound.h" #include "util/comparison.h" -namespace menu_item::mod_fx { +namespace deluge::gui::menu_item::mod_fx { class Depth final : public patched_param::Integer { public: using patched_param::Integer::Integer; @@ -29,4 +29,4 @@ class Depth final : public patched_param::Integer { return util::one_of(sound->modFXType, {ModFXType::CHORUS, ModFXType::CHORUS_STEREO, ModFXType::PHASER}); } }; -} // namespace menu_item::mod_fx +} // namespace deluge::gui::menu_item::mod_fx diff --git a/src/deluge/gui/menu_item/mod_fx/feedback.h b/src/deluge/gui/menu_item/mod_fx/feedback.h index 750a01afab..06b34741ec 100644 --- a/src/deluge/gui/menu_item/mod_fx/feedback.h +++ b/src/deluge/gui/menu_item/mod_fx/feedback.h @@ -19,7 +19,7 @@ #include "processing/sound/sound.h" #include "util/comparison.h" -namespace menu_item::mod_fx { +namespace deluge::gui::menu_item::mod_fx { class Feedback final : public UnpatchedParam { public: using UnpatchedParam::UnpatchedParam; @@ -28,4 +28,4 @@ class Feedback final : public UnpatchedParam { return (!sound || util::one_of(sound->modFXType, {ModFXType::FLANGER, ModFXType::PHASER})); } }; -} // namespace menu_item::mod_fx +} // namespace deluge::gui::menu_item::mod_fx diff --git a/src/deluge/gui/menu_item/mod_fx/offset.h b/src/deluge/gui/menu_item/mod_fx/offset.h index b1a1309ee0..0c2d74aa6d 100644 --- a/src/deluge/gui/menu_item/mod_fx/offset.h +++ b/src/deluge/gui/menu_item/mod_fx/offset.h @@ -19,7 +19,7 @@ #include "processing/sound/sound.h" #include "util/comparison.h" -namespace menu_item::mod_fx { +namespace deluge::gui::menu_item::mod_fx { class Offset final : public UnpatchedParam { public: @@ -31,4 +31,4 @@ class Offset final : public UnpatchedParam { } }; -} // namespace menu_item::mod_fx +} // namespace deluge::gui::menu_item::mod_fx diff --git a/src/deluge/gui/menu_item/mod_fx/type.h b/src/deluge/gui/menu_item/mod_fx/type.h index 6757d65bad..8a51528876 100644 --- a/src/deluge/gui/menu_item/mod_fx/type.h +++ b/src/deluge/gui/menu_item/mod_fx/type.h @@ -16,32 +16,27 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "hid/display/numeric_driver.h" #include "model/mod_controllable/mod_controllable_audio.h" #include "util/misc.h" -namespace menu_item::mod_fx { +namespace deluge::gui::menu_item::mod_fx { -class Type : public Selection { +class Type : public TypedSelection { public: - using Selection::Selection; + using TypedSelection::TypedSelection; - void readCurrentValue() override { - soundEditor.currentValue = util::to_underlying(soundEditor.currentModControllable->modFXType); - } + void readCurrentValue() override { this->value_ = soundEditor.currentModControllable->modFXType; } void writeCurrentValue() override { - if (!soundEditor.currentModControllable->setModFXType(static_cast(soundEditor.currentValue))) { + if (!soundEditor.currentModControllable->setModFXType(this->value_)) { numericDriver.displayError(ERROR_INSUFFICIENT_RAM); } } - char const** getOptions() override { - static char const* options[] = {"OFF", "FLANGER", "CHORUS", "PHASER", "STEREO CHORUS", NULL}; - return options; + static_vector getOptions() override { + return {"OFF", "FLANGER", "CHORUS", "PHASER", "STEREO CHORUS"}; } - - int32_t getNumOptions() override { return kNumModFXTypes; } }; -} // namespace menu_item::mod_fx +} // namespace deluge::gui::menu_item::mod_fx diff --git a/src/deluge/gui/menu_item/modulator/destination.h b/src/deluge/gui/menu_item/modulator/destination.h index b68ea0346d..c17021a052 100644 --- a/src/deluge/gui/menu_item/modulator/destination.h +++ b/src/deluge/gui/menu_item/modulator/destination.h @@ -15,21 +15,20 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" #include "processing/sound/sound.h" -namespace menu_item::modulator { -class Destination final : public Selection { +namespace deluge::gui::menu_item::modulator { +class Destination final : public Selection<2> { public: - Destination(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSound->modulator1ToModulator0; } - void writeCurrentValue() { soundEditor.currentSound->modulator1ToModulator0 = soundEditor.currentValue; } - char const** getOptions() { - static char const* options[] = {"Carriers", HAVE_OLED ? "Modulator 1" : "MOD1", NULL}; - return options; + using Selection::Selection; + void readCurrentValue() override { this->value_ = soundEditor.currentSound->modulator1ToModulator0; } + void writeCurrentValue() override { soundEditor.currentSound->modulator1ToModulator0 = this->value_; } + static_vector getOptions() override { return {"Carriers", HAVE_OLED ? "Modulator 1" : "MOD1"}; } + bool isRelevant(Sound* sound, int32_t whichThing) override { + return (whichThing == 1 && sound->synthMode == SynthMode::FM); } - bool isRelevant(Sound* sound, int32_t whichThing) { return (whichThing == 1 && sound->synthMode == SynthMode::FM); } }; -} // namespace menu_item::modulator +} // namespace deluge::gui::menu_item::modulator diff --git a/src/deluge/gui/menu_item/modulator/transpose.h b/src/deluge/gui/menu_item/modulator/transpose.h index 08795aa6aa..bbfe01198b 100644 --- a/src/deluge/gui/menu_item/modulator/transpose.h +++ b/src/deluge/gui/menu_item/modulator/transpose.h @@ -15,23 +15,26 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/source/transpose.h" #include "processing/sound/sound.h" -namespace menu_item::modulator { +namespace deluge::gui::menu_item::modulator { -class Transpose final : public source::Transpose { +class Transpose final : public source::Transpose, public FormattedTitle { public: - using source::Transpose::Transpose; + Transpose(const string& name, const string& title_format_str, int32_t newP) + : source::Transpose(name, newP), FormattedTitle(title_format_str) {} - void readCurrentValue() { - soundEditor.currentValue = - (int32_t)soundEditor.currentSound->modulatorTranspose[soundEditor.currentSourceIndex] * 100 - + soundEditor.currentSound->modulatorCents[soundEditor.currentSourceIndex]; + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + void readCurrentValue() override { + this->value_ = (int32_t)soundEditor.currentSound->modulatorTranspose[soundEditor.currentSourceIndex] * 100 + + soundEditor.currentSound->modulatorCents[soundEditor.currentSourceIndex]; } - void writeCurrentValue() { - int32_t currentValue = soundEditor.currentValue + 25600; + void writeCurrentValue() override { + int32_t currentValue = this->value_ + 25600; int32_t semitones = (currentValue + 50) / 100; int32_t cents = currentValue - semitones * 100; @@ -43,7 +46,7 @@ class Transpose final : public source::Transpose { soundEditor.currentSound->setModulatorCents(soundEditor.currentSourceIndex, cents, modelStack); } - bool isRelevant(Sound* sound, int32_t whichThing) { return (sound->getSynthMode() == SynthMode::FM); } + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->getSynthMode() == SynthMode::FM); } }; -} // namespace menu_item::modulator +} // namespace deluge::gui::menu_item::modulator diff --git a/src/deluge/gui/menu_item/monitor/mode.h b/src/deluge/gui/menu_item/monitor/mode.h index f4442cf75d..e6cfc81f49 100644 --- a/src/deluge/gui/menu_item/monitor/mode.h +++ b/src/deluge/gui/menu_item/monitor/mode.h @@ -16,24 +16,18 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "processing/engines/audio_engine.h" #include "util/misc.h" -namespace menu_item::monitor { -class Mode final : public Selection { +namespace deluge::gui::menu_item::monitor { +class Mode final : public TypedSelection { public: - using Selection::Selection; + using TypedSelection::TypedSelection; - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(AudioEngine::inputMonitoringMode); } - void writeCurrentValue() { - AudioEngine::inputMonitoringMode = static_cast(soundEditor.currentValue); - } - char const** getOptions() { - static char const* options[] = {"Conditional", "On", "Off", NULL}; - return options; - } - int32_t getNumOptions() { return kNumInputMonitoringModes; } + void readCurrentValue() override { this->value_ = AudioEngine::inputMonitoringMode; } + void writeCurrentValue() override { AudioEngine::inputMonitoringMode = this->value_; } + static_vector getOptions() override { return {"Conditional", "On", "Off"}; } }; -} // namespace menu_item::monitor +} // namespace deluge::gui::menu_item::monitor diff --git a/src/deluge/gui/menu_item/mpe/direction_selector.cpp b/src/deluge/gui/menu_item/mpe/direction_selector.cpp index c2fc5423ef..dc8ad8cc53 100644 --- a/src/deluge/gui/menu_item/mpe/direction_selector.cpp +++ b/src/deluge/gui/menu_item/mpe/direction_selector.cpp @@ -20,32 +20,16 @@ #include "io/midi/midi_device.h" #include "zone_selector.h" -namespace menu_item::mpe { +namespace deluge::gui::menu_item::mpe { void DirectionSelector::beginSession(MenuItem* navigatedBackwardFrom) { - if (!navigatedBackwardFrom) { + if (navigatedBackwardFrom == nullptr) { whichDirection = MIDI_DIRECTION_INPUT_TO_DELUGE; } Selection::beginSession(navigatedBackwardFrom); } -char const** DirectionSelector::getOptions() { - static char const* options[] = {"In", "Out", NULL}; - return options; -} - -void DirectionSelector::readCurrentValue() { - soundEditor.currentValue = whichDirection; -} - -void DirectionSelector::writeCurrentValue() { - whichDirection = soundEditor.currentValue; -} - MenuItem* DirectionSelector::selectButtonPress() { -#if HAVE_OLED - zoneSelectorMenu.basicTitle = whichDirection ? "MPE output" : "MPE input"; -#endif return &zoneSelectorMenu; } -} // namespace menu_item::mpe +} // namespace deluge::gui::menu_item::mpe diff --git a/src/deluge/gui/menu_item/mpe/direction_selector.h b/src/deluge/gui/menu_item/mpe/direction_selector.h index e675ad3696..5abbaa3f0e 100644 --- a/src/deluge/gui/menu_item/mpe/direction_selector.h +++ b/src/deluge/gui/menu_item/mpe/direction_selector.h @@ -17,21 +17,27 @@ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" +#include "zone_selector.h" -namespace menu_item::mpe { +namespace deluge::gui::menu_item::mpe { -class DirectionSelector final : public Selection { +class DirectionSelector final : public Selection<2> { public: - DirectionSelector(char const* newName = NULL) : Selection(newName) {} - void beginSession(MenuItem* navigatedBackwardFrom = NULL); - char const** getOptions(); - void readCurrentValue(); - void writeCurrentValue(); - MenuItem* selectButtonPress(); + using Selection::Selection; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override; + static_vector getOptions() override { return {"In", "Out"}; } + void readCurrentValue() override { this->value_ = whichDirection; } + void writeCurrentValue() override { whichDirection = this->value_; } + MenuItem* selectButtonPress() override; uint8_t whichDirection; +#if HAVE_OLED + [[nodiscard]] const string& getTitle() const override { + return whichDirection ? "MPE output" : "MPE input"; + } +#endif }; extern DirectionSelector directionSelectorMenu; -} // namespace menu_item::mpe +} // namespace deluge::gui::menu_item::mpe diff --git a/src/deluge/gui/menu_item/mpe/zone_num_member_channels.cpp b/src/deluge/gui/menu_item/mpe/zone_num_member_channels.cpp index fb18f973e7..da89c5c928 100644 --- a/src/deluge/gui/menu_item/mpe/zone_num_member_channels.cpp +++ b/src/deluge/gui/menu_item/mpe/zone_num_member_channels.cpp @@ -23,16 +23,10 @@ #include "io/midi/midi_engine.h" #include "string.h" -namespace menu_item::mpe { +namespace deluge::gui::menu_item::mpe { ZoneNumMemberChannels zoneNumMemberChannelsMenu{}; -ZoneNumMemberChannels::ZoneNumMemberChannels() { -#if HAVE_OLED - basicTitle = "Num member ch."; -#endif -} - MIDIPort* ZoneNumMemberChannels::getPort() const { return &soundEditor.currentMIDIDevice->ports[directionSelectorMenu.whichDirection]; } @@ -63,20 +57,20 @@ int32_t ZoneNumMemberChannels::getMaxValue() const { void ZoneNumMemberChannels::readCurrentValue() { MIDIPort* port = getPort(); if (zoneSelectorMenu.whichZone == MPE_ZONE_LOWER_NUMBERED_FROM_0) { - soundEditor.currentValue = port->mpeLowerZoneLastMemberChannel; + this->value_ = port->mpeLowerZoneLastMemberChannel; } else { - soundEditor.currentValue = 15 - port->mpeUpperZoneLastMemberChannel; + this->value_ = 15 - port->mpeUpperZoneLastMemberChannel; } } void ZoneNumMemberChannels::writeCurrentValue() { MIDIPort* port = getPort(); if (zoneSelectorMenu.whichZone == MPE_ZONE_LOWER_NUMBERED_FROM_0) { - port->mpeLowerZoneLastMemberChannel = soundEditor.currentValue; + port->mpeLowerZoneLastMemberChannel = this->value_; } else { - port->mpeUpperZoneLastMemberChannel = 15 - soundEditor.currentValue; + port->mpeUpperZoneLastMemberChannel = 15 - this->value_; } MIDIDeviceManager::recountSmallestMPEZones(); @@ -86,7 +80,7 @@ void ZoneNumMemberChannels::writeCurrentValue() { if (directionSelectorMenu.whichDirection == MIDI_DIRECTION_OUTPUT_FROM_DELUGE) { int32_t masterChannel = (zoneSelectorMenu.whichZone == MPE_ZONE_LOWER_NUMBERED_FROM_0) ? 0 : 15; - soundEditor.currentMIDIDevice->sendRPN(masterChannel, 0, 6, soundEditor.currentValue); + soundEditor.currentMIDIDevice->sendRPN(masterChannel, 0, 6, this->value_); } } -} // namespace menu_item::mpe +} // namespace deluge::gui::menu_item::mpe diff --git a/src/deluge/gui/menu_item/mpe/zone_num_member_channels.h b/src/deluge/gui/menu_item/mpe/zone_num_member_channels.h index f6f93e94fc..68950148f0 100644 --- a/src/deluge/gui/menu_item/mpe/zone_num_member_channels.h +++ b/src/deluge/gui/menu_item/mpe/zone_num_member_channels.h @@ -22,23 +22,29 @@ class MIDIPort; -namespace menu_item::mpe { +namespace deluge::gui::menu_item::mpe { class ZoneNumMemberChannels final : public IntegerWithOff { public: - ZoneNumMemberChannels(); + using IntegerWithOff::IntegerWithOff; /* #if HAVE_OLED void beginSession(MenuItem* navigatedBackwardFrom); #endif */ - int32_t getMaxValue() const; - void readCurrentValue(); - void writeCurrentValue(); + [[nodiscard]] int32_t getMaxValue() const override; + void readCurrentValue() override; + void writeCurrentValue() override; //char nameChars[16]; +#if HAVE_OLED + [[nodiscard]] const string& getTitle() const override { + return "Num member ch."; + } +#endif + private: - MIDIPort* getPort() const; + [[nodiscard]] MIDIPort* getPort() const; }; extern ZoneNumMemberChannels zoneNumMemberChannelsMenu; -} // namespace menu_item::mpe +} // namespace deluge::gui::menu_item::mpe diff --git a/src/deluge/gui/menu_item/mpe/zone_selector.cpp b/src/deluge/gui/menu_item/mpe/zone_selector.cpp index e90600f0ea..5bbf32da45 100644 --- a/src/deluge/gui/menu_item/mpe/zone_selector.cpp +++ b/src/deluge/gui/menu_item/mpe/zone_selector.cpp @@ -20,7 +20,7 @@ #include "gui/ui/sound_editor.h" #include "zone_num_member_channels.h" -namespace menu_item::mpe { +namespace deluge::gui::menu_item::mpe { ZoneSelector zoneSelectorMenu{}; @@ -31,25 +31,7 @@ void ZoneSelector::beginSession(MenuItem* navigatedBackwardFrom) { Selection::beginSession(navigatedBackwardFrom); } -char const** ZoneSelector::getOptions() { - static char const* options[] = -#if HAVE_OLED - {"Lower zone", "Upper zone", NULL}; -#else - {"Lowe", "Uppe", NULL}; -#endif - return options; -} - -void ZoneSelector::readCurrentValue() { - soundEditor.currentValue = whichZone; -} - -void ZoneSelector::writeCurrentValue() { - whichZone = soundEditor.currentValue; -} - MenuItem* ZoneSelector::selectButtonPress() { return &zoneNumMemberChannelsMenu; } -} // namespace menu_item::mpe +} // namespace deluge::gui::menu_item::mpe diff --git a/src/deluge/gui/menu_item/mpe/zone_selector.h b/src/deluge/gui/menu_item/mpe/zone_selector.h index db36101cc0..325c5d4951 100644 --- a/src/deluge/gui/menu_item/mpe/zone_selector.h +++ b/src/deluge/gui/menu_item/mpe/zone_selector.h @@ -17,24 +17,27 @@ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" -namespace menu_item::mpe { +namespace deluge::gui::menu_item::mpe { -class ZoneSelector final : public Selection { +class ZoneSelector final : public Selection<2> { public: - ZoneSelector(char const* newName = NULL) : Selection(newName) {} - void beginSession(MenuItem* navigatedBackwardFrom = NULL); - char const** getOptions(); - void readCurrentValue(); - void writeCurrentValue(); - MenuItem* selectButtonPress(); - uint8_t whichZone; + using Selection::Selection; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override; + void readCurrentValue() override { this->value_ = whichZone; } + void writeCurrentValue() override { whichZone = this->value_; } + + static_vector getOptions() override { + return { + HAVE_OLED ? "Lower zone" : "LOWE", //< + HAVE_OLED ? "Upper zone" : "UPPE" //< + }; + } -#if HAVE_OLED - char const* getTitle(char* buffer); -#endif + MenuItem* selectButtonPress() override; + uint8_t whichZone; }; extern ZoneSelector zoneSelectorMenu; -} // namespace menu_item::mpe +} // namespace deluge::gui::menu_item::mpe diff --git a/src/deluge/gui/menu_item/multi_range.cpp b/src/deluge/gui/menu_item/multi_range.cpp index 2a0eea1894..706ef659d1 100644 --- a/src/deluge/gui/menu_item/multi_range.cpp +++ b/src/deluge/gui/menu_item/multi_range.cpp @@ -33,20 +33,14 @@ #include "util/functions.h" #include -namespace menu_item { +namespace deluge::gui::menu_item { MultiRange multiRangeMenu{}; -MultiRange::MultiRange() { -#if HAVE_OLED - basicTitle = "Note range"; -#endif -} - void MultiRange::beginSession(MenuItem* navigatedBackwardFrom) { // If there's already a range (e.g. because we just came back out of a menu)... - if (soundEditor.currentMultiRange) { + if (soundEditor.currentMultiRange != nullptr) { soundEditor.currentSource->defaultRangeI = soundEditor.currentMultiRangeIndex; } @@ -56,14 +50,14 @@ void MultiRange::beginSession(MenuItem* navigatedBackwardFrom) { soundEditor.currentSource->defaultRangeI = numRanges >> 1; } - soundEditor.currentValue = soundEditor.currentSource->defaultRangeI; + this->value_ = soundEditor.currentSource->defaultRangeI; soundEditor.currentSource->getOrCreateFirstRange(); // TODO: deal with error - soundEditor.setCurrentMultiRange(soundEditor.currentValue); + soundEditor.setCurrentMultiRange(this->value_); #if HAVE_OLED - soundEditor.menuCurrentScroll = soundEditor.currentValue - 1; - if (soundEditor.menuCurrentScroll > soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1) { - soundEditor.menuCurrentScroll = soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1; + soundEditor.menuCurrentScroll = this->value_ - 1; + if (soundEditor.menuCurrentScroll > this->value_ - kOLEDMenuNumOptionsVisible + 1) { + soundEditor.menuCurrentScroll = this->value_ - kOLEDMenuNumOptionsVisible + 1; } if (soundEditor.menuCurrentScroll < 0) { soundEditor.menuCurrentScroll = 0; @@ -85,13 +79,13 @@ void MultiRange::selectEncoderAction(int32_t offset) { // Editing left if (soundEditor.editingRangeEdge == RangeEdit::LEFT) { - ::MultiRange* lowerRange = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue - 1); + ::MultiRange* lowerRange = soundEditor.currentSource->ranges.getElement(this->value_ - 1); // Raising if (offset >= 0) { int32_t maximum; - if (soundEditor.currentValue < soundEditor.currentSource->ranges.getNumElements() - 1) { - ::MultiRange* currentRange = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue); + if (this->value_ < soundEditor.currentSource->ranges.getNumElements() - 1) { + ::MultiRange* currentRange = soundEditor.currentSource->ranges.getElement(this->value_); maximum = currentRange->topNote - 1; } else { @@ -106,9 +100,8 @@ void MultiRange::selectEncoderAction(int32_t offset) { // Lowering else { int32_t minimum; - if (soundEditor.currentValue >= 2) { - ::MultiRange* lowerLowerRange = - soundEditor.currentSource->ranges.getElement(soundEditor.currentValue - 2); + if (this->value_ >= 2) { + ::MultiRange* lowerLowerRange = soundEditor.currentSource->ranges.getElement(this->value_ - 2); minimum = lowerLowerRange->topNote + 1; } else { @@ -124,14 +117,13 @@ void MultiRange::selectEncoderAction(int32_t offset) { // Editing right else { - ::MultiRange* currentRange = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue); + ::MultiRange* currentRange = soundEditor.currentSource->ranges.getElement(this->value_); // Raising if (offset >= 0) { int32_t maximum; - if (soundEditor.currentValue < soundEditor.currentSource->ranges.getNumElements() - 2) { - ::MultiRange* higherRange = - soundEditor.currentSource->ranges.getElement(soundEditor.currentValue + 1); + if (this->value_ < soundEditor.currentSource->ranges.getNumElements() - 2) { + ::MultiRange* higherRange = soundEditor.currentSource->ranges.getElement(this->value_ + 1); maximum = higherRange->topNote - 1; } else { @@ -146,9 +138,8 @@ void MultiRange::selectEncoderAction(int32_t offset) { // Lowering else { int32_t minimum; - if (soundEditor.currentValue >= 1) { - ::MultiRange* lowerRange = - soundEditor.currentSource->ranges.getElement(soundEditor.currentValue - 1); + if (this->value_ >= 1) { + ::MultiRange* lowerRange = soundEditor.currentSource->ranges.getElement(this->value_ - 1); minimum = lowerRange->topNote + 1; } else { @@ -175,27 +166,25 @@ void MultiRange::selectEncoderAction(int32_t offset) { if (Buttons::isShiftButtonPressed()) { int32_t currentRangeBottom; - if (soundEditor.currentValue == 0) { - currentRangeBottom = - soundEditor.currentSource->ranges.getElement(soundEditor.currentValue)->topNote - 1; + if (this->value_ == 0) { + currentRangeBottom = soundEditor.currentSource->ranges.getElement(this->value_)->topNote - 1; if (currentRangeBottom > 0) { currentRangeBottom = 0; } } else { - currentRangeBottom = - soundEditor.currentSource->ranges.getElement(soundEditor.currentValue - 1)->topNote + 1; + currentRangeBottom = soundEditor.currentSource->ranges.getElement(this->value_ - 1)->topNote + 1; } int32_t currentRangeTop; - if (soundEditor.currentValue == soundEditor.currentSource->ranges.getNumElements() - 1) { + if (this->value_ == soundEditor.currentSource->ranges.getNumElements() - 1) { currentRangeTop = currentRangeBottom + 1; if (currentRangeTop < 127) { currentRangeTop = 127; } } else { - currentRangeTop = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue)->topNote; + currentRangeTop = soundEditor.currentSource->ranges.getElement(this->value_)->topNote; } if (currentRangeTop == currentRangeBottom) { @@ -205,7 +194,7 @@ void MultiRange::selectEncoderAction(int32_t offset) { int32_t midPoint = (currentRangeTop + currentRangeBottom) >> 1; - int32_t newI = soundEditor.currentValue; + int32_t newI = this->value_; if (offset == 1) { newI++; } @@ -223,7 +212,7 @@ void MultiRange::selectEncoderAction(int32_t offset) { // Inserted after if (offset >= 0) { newRange->topNote = currentRangeTop; - ::MultiRange* oldRange = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue); + ::MultiRange* oldRange = soundEditor.currentSource->ranges.getElement(this->value_); oldRange->topNote = midPoint; } @@ -236,14 +225,14 @@ void MultiRange::selectEncoderAction(int32_t offset) { #endif } - soundEditor.currentValue = newI; + this->value_ = newI; #if HAVE_OLED OLED::consoleText("Range inserted"); - if (soundEditor.menuCurrentScroll > soundEditor.currentValue) { - soundEditor.menuCurrentScroll = soundEditor.currentValue; + if (soundEditor.menuCurrentScroll > this->value_) { + soundEditor.menuCurrentScroll = this->value_; } - else if (soundEditor.menuCurrentScroll < soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1) { - soundEditor.menuCurrentScroll = soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1; + else if (soundEditor.menuCurrentScroll < this->value_ - kOLEDMenuNumOptionsVisible + 1) { + soundEditor.menuCurrentScroll = this->value_ - kOLEDMenuNumOptionsVisible + 1; } #else numericDriver.displayPopup("INSERT"); @@ -253,25 +242,25 @@ void MultiRange::selectEncoderAction(int32_t offset) { // Or the normal thing of just flicking through existing ranges else { // Stay within bounds - int32_t newValue = soundEditor.currentValue + offset; + int32_t newValue = this->value_ + offset; if (newValue < 0 || newValue >= soundEditor.currentSource->ranges.getNumElements()) { return; } - soundEditor.currentValue = newValue; - soundEditor.currentSource->defaultRangeI = soundEditor.currentValue; + this->value_ = newValue; + soundEditor.currentSource->defaultRangeI = this->value_; #if HAVE_OLED - if (soundEditor.menuCurrentScroll > soundEditor.currentValue) { - soundEditor.menuCurrentScroll = soundEditor.currentValue; + if (soundEditor.menuCurrentScroll > this->value_) { + soundEditor.menuCurrentScroll = this->value_; } - else if (soundEditor.menuCurrentScroll < soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1) { - soundEditor.menuCurrentScroll = soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1; + else if (soundEditor.menuCurrentScroll < this->value_ - kOLEDMenuNumOptionsVisible + 1) { + soundEditor.menuCurrentScroll = this->value_ - kOLEDMenuNumOptionsVisible + 1; } #endif } - soundEditor.setCurrentMultiRange(soundEditor.currentValue); + soundEditor.setCurrentMultiRange(this->value_); soundEditor.possibleChangeToCurrentRangeDisplay(); #if HAVE_OLED renderUIsForOled(); @@ -298,29 +287,29 @@ void MultiRange::deletePress() { return; } - ::MultiRange* oldRange = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue); + ::MultiRange* oldRange = soundEditor.currentSource->ranges.getElement(this->value_); int32_t oldTopNote = oldRange->topNote; soundEditor.currentSound->deleteMultiRange(soundEditor.currentSourceIndex, - soundEditor.currentValue); // Unassigns all Voices + this->value_); // Unassigns all Voices // If bottom one, nothing to do - if (soundEditor.currentValue == 0) { - soundEditor.setCurrentMultiRange(soundEditor.currentValue); + if (this->value_ == 0) { + soundEditor.setCurrentMultiRange(this->value_); } // Otherwise... else { - soundEditor.currentValue--; - soundEditor.setCurrentMultiRange(soundEditor.currentValue); + this->value_--; + soundEditor.setCurrentMultiRange(this->value_); #if HAVE_OLED - if (soundEditor.menuCurrentScroll > soundEditor.currentValue) { - soundEditor.menuCurrentScroll = soundEditor.currentValue; + if (soundEditor.menuCurrentScroll > this->value_) { + soundEditor.menuCurrentScroll = this->value_; } #endif // If top one... - if (soundEditor.currentValue == oldNum - 2) { + if (this->value_ == oldNum - 2) { soundEditor.currentMultiRange->topNote = 32767; } @@ -342,14 +331,14 @@ void MultiRange::deletePress() { void MultiRange::getText(char* buffer, int32_t* getLeftLength, int32_t* getRightLength, bool mayShowJustOne) { // Lower end - if (soundEditor.currentValue == 0) { + if (this->value_ == 0) { strcpy(buffer, HAVE_OLED ? "Bottom" : "BOT"); if (getLeftLength) { *getLeftLength = HAVE_OLED ? 6 : 3; } } else { - int32_t note = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue - 1)->topNote + 1; + int32_t note = soundEditor.currentSource->ranges.getElement(this->value_ - 1)->topNote + 1; noteCodeToString(note, buffer, getLeftLength); } @@ -363,7 +352,7 @@ void MultiRange::getText(char* buffer, int32_t* getLeftLength, int32_t* getRight #endif // Upper end - if (soundEditor.currentValue == soundEditor.currentSource->ranges.getNumElements() - 1) { + if (this->value_ == soundEditor.currentSource->ranges.getNumElements() - 1) { *(bufferPos++) = '-'; #if HAVE_OLED *(bufferPos++) = ' '; @@ -377,10 +366,10 @@ void MultiRange::getText(char* buffer, int32_t* getLeftLength, int32_t* getRight } } else { - int32_t note = soundEditor.currentSource->ranges.getElement(soundEditor.currentValue)->topNote; + int32_t note = soundEditor.currentSource->ranges.getElement(this->value_)->topNote; - if (mayShowJustOne && soundEditor.currentValue > 0 - && note == soundEditor.currentSource->ranges.getElement(soundEditor.currentValue - 1)->topNote + 1) { + if (mayShowJustOne && this->value_ > 0 + && note == soundEditor.currentSource->ranges.getElement(this->value_ - 1)->topNote + 1) { return; } @@ -397,16 +386,16 @@ MenuItem* MultiRange::selectButtonPress() { void MultiRange::noteOnToChangeRange(int32_t noteCode) { if (soundEditor.editingRangeEdge == RangeEdit::OFF) { int32_t newI = soundEditor.currentSource->getRangeIndex(noteCode); - if (newI != soundEditor.currentValue) { - soundEditor.currentValue = newI; - soundEditor.setCurrentMultiRange(soundEditor.currentValue); + if (newI != this->value_) { + this->value_ = newI; + soundEditor.setCurrentMultiRange(this->value_); soundEditor.possibleChangeToCurrentRangeDisplay(); #if HAVE_OLED - if (soundEditor.menuCurrentScroll > soundEditor.currentValue) { - soundEditor.menuCurrentScroll = soundEditor.currentValue; + if (soundEditor.menuCurrentScroll > this->value_) { + soundEditor.menuCurrentScroll = this->value_; } - else if (soundEditor.menuCurrentScroll < soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1) { - soundEditor.menuCurrentScroll = soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1; + else if (soundEditor.menuCurrentScroll < this->value_ - kOLEDMenuNumOptionsVisible + 1) { + soundEditor.menuCurrentScroll = this->value_ - kOLEDMenuNumOptionsVisible + 1; } renderUIsForOled(); @@ -419,63 +408,55 @@ void MultiRange::noteOnToChangeRange(int32_t noteCode) { bool MultiRange::mayEditRangeEdge(RangeEdit whichEdge) { if (whichEdge == RangeEdit::LEFT) { - return (soundEditor.currentValue != 0); + return (this->value_ != 0); } - return (soundEditor.currentValue != soundEditor.currentSource->ranges.getNumElements() - 1); + return (this->value_ != soundEditor.currentSource->ranges.getNumElements() - 1); } #if HAVE_OLED void MultiRange::drawPixelsForOled() { - - char const* itemNames[kOLEDMenuNumOptionsVisible]; + static_vector itemNames{}; char nameBuffers[kOLEDMenuNumOptionsVisible][20]; - int32_t actualCurrentRange = soundEditor.currentValue; + int32_t actualCurrentRange = this->value_; - soundEditor.currentValue = soundEditor.menuCurrentScroll; - int32_t i = 0; - while (i < kOLEDMenuNumOptionsVisible) { - if (soundEditor.currentValue >= soundEditor.currentSource->ranges.getNumElements()) { + this->value_ = soundEditor.menuCurrentScroll; + size_t idx = 0; + for (idx = 0; idx < kOLEDMenuNumOptionsVisible; idx++) { + if (this->value_ >= soundEditor.currentSource->ranges.getNumElements()) { break; } - getText(nameBuffers[i], NULL, NULL, false); - itemNames[i] = nameBuffers[i]; + getText(nameBuffers[idx], nullptr, nullptr, false); + itemNames.push_back(nameBuffers[idx]); - i++; - soundEditor.currentValue++; + this->value_++; } - while (i < kOLEDMenuNumOptionsVisible) { - itemNames[i] = NULL; - i++; - } - - soundEditor.currentValue = actualCurrentRange; + this->value_ = actualCurrentRange; - int32_t selectedOption; - if (soundEditor.editingRangeEdge != RangeEdit::OFF) { - selectedOption = -1; - } - else { - selectedOption = soundEditor.currentValue - soundEditor.menuCurrentScroll; + int32_t selectedOption = -1; + if (soundEditor.editingRangeEdge == RangeEdit::OFF) { + selectedOption = this->value_ - soundEditor.menuCurrentScroll; } drawItemsForOled(itemNames, selectedOption); - int32_t hilightStartX, hilightWidth; + if (soundEditor.editingRangeEdge != RangeEdit::OFF) { + int32_t hilightStartX = 0; + int32_t hilightWidth = 0; + + if (soundEditor.editingRangeEdge == RangeEdit::LEFT) { + hilightStartX = kTextSpacingX; + hilightWidth = kTextSpacingX * 6; + } + else if (soundEditor.editingRangeEdge == RangeEdit::RIGHT) { + hilightStartX = kTextSpacingX * 10; + hilightWidth = OLED_MAIN_WIDTH_PIXELS - hilightStartX; + } - if (soundEditor.editingRangeEdge == RangeEdit::LEFT) { - hilightStartX = kTextSpacingX; - hilightWidth = kTextSpacingX * 6; -doHilightJustOneEdge: int32_t baseY = (OLED_MAIN_HEIGHT_PIXELS == 64) ? 15 : 14; baseY += OLED_MAIN_TOPMOST_PIXEL; - baseY += (soundEditor.currentValue - soundEditor.menuCurrentScroll) * kTextSpacingY; + baseY += (this->value_ - soundEditor.menuCurrentScroll) * kTextSpacingY; OLED::invertArea(hilightStartX, hilightWidth, baseY, baseY + kTextSpacingY, OLED::oledMainImage); } - else if (soundEditor.editingRangeEdge == RangeEdit::RIGHT) { - hilightStartX = kTextSpacingX * 10; - hilightWidth = OLED_MAIN_WIDTH_PIXELS - hilightStartX; - goto doHilightJustOneEdge; - } } #endif -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/multi_range.h b/src/deluge/gui/menu_item/multi_range.h index bef06902aa..cffb68990d 100644 --- a/src/deluge/gui/menu_item/multi_range.h +++ b/src/deluge/gui/menu_item/multi_range.h @@ -19,29 +19,33 @@ #include "menu_item.h" #include "range.h" -namespace menu_item { +namespace deluge::gui::menu_item { class MultiRange final : public Range { public: - MultiRange(); + using Range::Range; - void beginSession(MenuItem* navigatedBackwardFrom); - void selectEncoderAction(int32_t offset); - MenuItem* selectButtonPress(); + void beginSession(MenuItem* navigatedBackwardFrom) override; + void selectEncoderAction(int32_t offset) override; + MenuItem* selectButtonPress() override; void noteOnToChangeRange(int32_t noteCode); - bool isRangeDependent() { return true; } + bool isRangeDependent() override { return true; } void deletePress(); MenuItem* menuItemHeadingTo; protected: - void getText(char* buffer, int32_t* getLeftLength = NULL, int32_t* getRightLength = NULL, - bool mayShowJustOne = true); - bool mayEditRangeEdge(RangeEdit whichEdge); + void getText(char* buffer, int32_t* getLeftLength = nullptr, int32_t* getRightLength = nullptr, + + bool mayShowJustOne = true) override; + bool mayEditRangeEdge(RangeEdit whichEdge) override; #if HAVE_OLED - void drawPixelsForOled(); + const string& getTitle() const override { + return "Note range"; + }; + void drawPixelsForOled() override; #endif }; extern MultiRange multiRangeMenu; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/number.cpp b/src/deluge/gui/menu_item/number.cpp index acaa4ccd96..18df617d0c 100644 --- a/src/deluge/gui/menu_item/number.cpp +++ b/src/deluge/gui/menu_item/number.cpp @@ -23,7 +23,7 @@ #include "hid/display/oled.h" #endif -namespace menu_item { +namespace deluge::gui::menu_item { #if HAVE_OLED void Number::drawBar(int32_t yTop, int32_t marginL, int32_t marginR) { @@ -47,7 +47,7 @@ void Number::drawBar(int32_t yTop, int32_t marginL, int32_t marginR) { int32_t minValue = getMinValue(); int32_t maxValue = getMaxValue(); uint32_t range = maxValue - minValue; - float posFractional = (float)(soundEditor.currentValue - minValue) / range; + float posFractional = (float)(this->value_ - minValue) / range; float zeroPosFractional = (float)(-minValue) / range; int32_t width = rightMost - leftMost; @@ -66,4 +66,4 @@ void Number::drawBar(int32_t yTop, int32_t marginL, int32_t marginR) { } #endif -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/number.h b/src/deluge/gui/menu_item/number.h index 508e7745d8..eaf6754f92 100644 --- a/src/deluge/gui/menu_item/number.h +++ b/src/deluge/gui/menu_item/number.h @@ -20,9 +20,8 @@ #include "value.h" #include -namespace menu_item { - -class Number : public Value { +namespace deluge::gui::menu_item { +class Number : public Value { public: using Value::Value; #if HAVE_OLED @@ -30,10 +29,10 @@ class Number : public Value { #endif protected: - virtual int32_t getMaxValue() const = 0; - virtual int32_t getMinValue() const { + [[nodiscard]] virtual int32_t getMaxValue() const = 0; + [[nodiscard]] virtual int32_t getMinValue() const { return 0; } }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/osc/audio_recorder.h b/src/deluge/gui/menu_item/osc/audio_recorder.h index 4025c6d435..284783ba97 100644 --- a/src/deluge/gui/menu_item/osc/audio_recorder.h +++ b/src/deluge/gui/menu_item/osc/audio_recorder.h @@ -22,11 +22,11 @@ #include "hid/display/numeric_driver.h" #include "processing/sound/sound.h" -namespace menu_item::osc { +namespace deluge::gui::menu_item::osc { class AudioRecorder final : public MenuItem { public: - AudioRecorder(char const* newName = 0) : MenuItem(newName) {} - void beginSession(MenuItem* navigatedBackwardFrom) { + using MenuItem::MenuItem; + void beginSession(MenuItem* navigatedBackwardFrom) override { soundEditor.shouldGoUpOneLevelOnBegin = true; bool success = openUI(&audioRecorder); if (!success) { @@ -39,12 +39,13 @@ class AudioRecorder final : public MenuItem { audioRecorder.process(); } } - bool isRelevant(Sound* sound, int32_t whichThing) { + bool isRelevant(Sound* sound, int32_t whichThing) override { Source* source = &sound->sources[whichThing]; return (sound->getSynthMode() == SynthMode::SUBTRACTIVE); } - MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, ::MultiRange** currentRange) { + MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, + ::MultiRange** currentRange) override { bool can = isRelevant(sound, whichThing); if (!can) { @@ -55,4 +56,4 @@ class AudioRecorder final : public MenuItem { return soundEditor.checkPermissionToBeginSessionForRangeSpecificParam(sound, whichThing, false, currentRange); } }; -} // namespace menu_item::osc +} // namespace deluge::gui::menu_item::osc diff --git a/src/deluge/gui/menu_item/osc/pulse_width.h b/src/deluge/gui/menu_item/osc/pulse_width.h index 4be99f9ff4..c85da139e5 100644 --- a/src/deluge/gui/menu_item/osc/pulse_width.h +++ b/src/deluge/gui/menu_item/osc/pulse_width.h @@ -16,23 +16,28 @@ */ #pragma once #include "definitions_cxx.hpp" +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/source/patched_param.h" #include "modulation/params/param_set.h" #include "processing/sound/sound.h" -namespace menu_item::osc { -class PulseWidth final : public menu_item::source::PatchedParam { +namespace deluge::gui::menu_item::osc { +class PulseWidth final : public menu_item::source::PatchedParam, public FormattedTitle { public: using menu_item::source::PatchedParam::PatchedParam; + PulseWidth(const string& name, const string& title_format_str, int32_t newP) + : source::PatchedParam(name, newP), FormattedTitle(title_format_str) {} - int32_t getFinalValue() { return (uint32_t)soundEditor.currentValue * (85899345 >> 1); } + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } - void readCurrentValue() { - soundEditor.currentValue = + int32_t getFinalValue() override { return (uint32_t)this->value_ * (85899345 >> 1); } + + void readCurrentValue() override { + this->value_ = ((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) * 100 + 2147483648) >> 32; } - bool isRelevant(Sound* sound, int32_t whichThing) { + bool isRelevant(Sound* sound, int32_t whichThing) override { if (sound->getSynthMode() == SynthMode::FM) { return false; } @@ -42,4 +47,4 @@ class PulseWidth final : public menu_item::source::PatchedParam { } }; -} // namespace menu_item::osc +} // namespace deluge::gui::menu_item::osc diff --git a/src/deluge/gui/menu_item/osc/retrigger_phase.h b/src/deluge/gui/menu_item/osc/retrigger_phase.h index 74fb2c0842..5e6d047421 100644 --- a/src/deluge/gui/menu_item/osc/retrigger_phase.h +++ b/src/deluge/gui/menu_item/osc/retrigger_phase.h @@ -16,50 +16,57 @@ */ #pragma once #include "gui/menu_item/decimal.h" +#include "gui/menu_item/formatted_title.h" #include "gui/ui/sound_editor.h" #include "hid/display/oled.h" #include "processing/sound/sound.h" -namespace menu_item::osc { -class RetriggerPhase final : public Decimal { +namespace deluge::gui::menu_item::osc { +class RetriggerPhase final : public Decimal, public FormattedTitle { public: - RetriggerPhase(char const* newName = NULL, bool newForModulator = false) : Decimal(newName) { - forModulator = newForModulator; - } - int32_t getMinValue() const { return -soundEditor.numberEditSize; } - int32_t getMaxValue() const { return 360; } - int32_t getNumDecimalPlaces() const { return 0; } - int32_t getDefaultEditPos() const { return 1; } - void readCurrentValue() { + RetriggerPhase(const string& newName, const deluge::string& title, bool newForModulator = false) + : Decimal(newName), FormattedTitle(title), forModulator(newForModulator) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + [[nodiscard]] int32_t getMinValue() const override { return -soundEditor.numberEditSize; } + [[nodiscard]] int32_t getMaxValue() const override { return 360; } + [[nodiscard]] int32_t getNumDecimalPlaces() const override { return 0; } + [[nodiscard]] int32_t getDefaultEditPos() const override { return 1; } + + void readCurrentValue() override { uint32_t value = *getValueAddress(); if (value == 0xFFFFFFFF) { - soundEditor.currentValue = -soundEditor.numberEditSize; + this->value_ = -soundEditor.numberEditSize; } else { - soundEditor.currentValue = value / 11930464; + this->value_ = value / 11930464; } } - void writeCurrentValue() { + + void writeCurrentValue() override { uint32_t value; - if (soundEditor.currentValue < 0) { + if (this->value_ < 0) { value = 0xFFFFFFFF; } else { - value = soundEditor.currentValue * 11930464; + value = this->value_ * 11930464; } *getValueAddress() = value; } - void drawValue() { - if (soundEditor.currentValue < 0) { + + void drawValue() override { + if (this->value_ < 0) { numericDriver.setText("OFF", false, 255, true); } else { Decimal::drawValue(); } } + #if HAVE_OLED - void drawPixelsForOled() { - if (soundEditor.currentValue < 0) { + void drawPixelsForOled() override { + if (this->value_ < 0) { OLED::drawStringCentred("OFF", 20, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, kTextHugeSpacingX, kTextHugeSizeY); } @@ -68,13 +75,13 @@ class RetriggerPhase final : public Decimal { } } #endif - void horizontalEncoderAction(int32_t offset) { - if (soundEditor.currentValue >= 0) { + void horizontalEncoderAction(int32_t offset) override { + if (this->value_ >= 0) { Decimal::horizontalEncoderAction(offset); } } - bool isRelevant(Sound* sound, int32_t whichThing) { + bool isRelevant(Sound* sound, int32_t whichThing) override { Source* source = &sound->sources[whichThing]; if (forModulator && sound->getSynthMode() != SynthMode::FM) { return false; @@ -84,13 +91,11 @@ class RetriggerPhase final : public Decimal { private: bool forModulator; - uint32_t* getValueAddress() { + [[nodiscard]] uint32_t* getValueAddress() const { if (forModulator) { return &soundEditor.currentSound->modulatorRetriggerPhase[soundEditor.currentSourceIndex]; } - else { - return &soundEditor.currentSound->oscRetriggerPhase[soundEditor.currentSourceIndex]; - } + return &soundEditor.currentSound->oscRetriggerPhase[soundEditor.currentSourceIndex]; } }; -} // namespace menu_item::osc +} // namespace deluge::gui::menu_item::osc diff --git a/src/deluge/gui/menu_item/osc/source/feedback.h b/src/deluge/gui/menu_item/osc/source/feedback.h index 4172277ee3..9eb76e12e8 100644 --- a/src/deluge/gui/menu_item/osc/source/feedback.h +++ b/src/deluge/gui/menu_item/osc/source/feedback.h @@ -15,14 +15,19 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/source/patched_param.h" #include "processing/sound/sound.h" -namespace menu_item::osc::source { -class Feedback final : public menu_item::source::PatchedParam { +namespace deluge::gui::menu_item::osc::source { +class Feedback final : public menu_item::source::PatchedParam, public FormattedTitle { public: - using PatchedParam::PatchedParam; - bool isRelevant(Sound* sound, int32_t whichThing) { return (sound->getSynthMode() == SynthMode::FM); } + Feedback(const string& name, const string& title_format_str, int32_t newP) + : PatchedParam(name, newP), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->getSynthMode() == SynthMode::FM); } }; -} // namespace menu_item::osc::source +} // namespace deluge::gui::menu_item::osc::source diff --git a/src/deluge/gui/menu_item/osc/source/volume.h b/src/deluge/gui/menu_item/osc/source/volume.h index ce2b36f6c1..74b4ecfb92 100644 --- a/src/deluge/gui/menu_item/osc/source/volume.h +++ b/src/deluge/gui/menu_item/osc/source/volume.h @@ -15,14 +15,19 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/source/patched_param.h" #include "processing/sound/sound.h" -namespace menu_item::osc::source { +namespace deluge::gui::menu_item::osc::source { -class Volume final : public menu_item::source::PatchedParam { +class Volume final : public menu_item::source::PatchedParam, public FormattedTitle { public: - using PatchedParam::PatchedParam; - bool isRelevant(Sound* sound, int32_t whichThing) { return (sound->getSynthMode() != SynthMode::RINGMOD); } + Volume(const string& name, const string& title_format_str, int32_t newP) + : PatchedParam(name, newP), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->getSynthMode() != SynthMode::RINGMOD); } }; -} // namespace menu_item::osc::source +} // namespace deluge::gui::menu_item::osc::source diff --git a/src/deluge/gui/menu_item/osc/source/wave_index.h b/src/deluge/gui/menu_item/osc/source/wave_index.h index 7f41854fa9..790a21e58f 100644 --- a/src/deluge/gui/menu_item/osc/source/wave_index.h +++ b/src/deluge/gui/menu_item/osc/source/wave_index.h @@ -15,16 +15,21 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/source/patched_param.h" #include "processing/sound/sound.h" -namespace menu_item::osc::source { -class WaveIndex final : public menu_item::source::PatchedParam { +namespace deluge::gui::menu_item::osc::source { +class WaveIndex final : public menu_item::source::PatchedParam, public FormattedTitle { public: - using PatchedParam::PatchedParam; - bool isRelevant(Sound* sound, int32_t whichThing) { + WaveIndex(const string& name, const string& title_format_str, int32_t newP) + : PatchedParam(name, newP), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + bool isRelevant(Sound* sound, int32_t whichThing) override { Source* source = &sound->sources[whichThing]; return (sound->getSynthMode() != SynthMode::FM && source->oscType == OscType::WAVETABLE); } }; -} // namespace menu_item::osc::source +} // namespace deluge::gui::menu_item::osc::source diff --git a/src/deluge/gui/menu_item/osc/sync.h b/src/deluge/gui/menu_item/osc/sync.h index 1990c9d3f8..3ad4ac99ae 100644 --- a/src/deluge/gui/menu_item/osc/sync.h +++ b/src/deluge/gui/menu_item/osc/sync.h @@ -15,20 +15,21 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/formatted_title.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "processing/sound/sound.h" -namespace menu_item::osc { -class Sync final : public Selection { +namespace deluge::gui::menu_item::osc { +class Sync final : public Toggle { public: - Sync(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSound->oscillatorSync; } - void writeCurrentValue() { soundEditor.currentSound->oscillatorSync = soundEditor.currentValue; } - bool isRelevant(Sound* sound, int32_t whichThing) { + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = soundEditor.currentSound->oscillatorSync; } + void writeCurrentValue() override { soundEditor.currentSound->oscillatorSync = this->value_; } + bool isRelevant(Sound* sound, int32_t whichThing) override { return (whichThing == 1 && sound->synthMode != SynthMode::FM && sound->sources[0].oscType != OscType::SAMPLE && sound->sources[1].oscType != OscType::SAMPLE); } }; -} // namespace menu_item::osc +} // namespace deluge::gui::menu_item::osc diff --git a/src/deluge/gui/menu_item/osc/type.h b/src/deluge/gui/menu_item/osc/type.h index f714c82763..a679d51597 100644 --- a/src/deluge/gui/menu_item/osc/type.h +++ b/src/deluge/gui/menu_item/osc/type.h @@ -16,7 +16,8 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/formatted_title.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "model/song/song.h" #include "processing/engines/audio_engine.h" @@ -25,28 +26,22 @@ #include "util/comparison.h" #include "util/misc.h" -extern char oscTypeTitle[]; -namespace menu_item::osc { -class Type final : public Selection { +namespace deluge::gui::menu_item::osc { +class Type final : public TypedSelection, public FormattedTitle { public: - Type(char const* newName = NULL) : Selection(newName) { + Type(const string& name, const string& title_format_str) : TypedSelection(name), FormattedTitle(title_format_str){}; #if HAVE_OLED - basicTitle = oscTypeTitle; -#endif - } -#if HAVE_OLED - void beginSession(MenuItem* navigatedBackwardFrom) { - oscTypeTitle[3] = '1' + soundEditor.currentSourceIndex; - Selection::beginSession(navigatedBackwardFrom); + void beginSession(MenuItem* navigatedBackwardFrom) override { + TypedSelection::beginSession(navigatedBackwardFrom); } #endif - void readCurrentValue() { - soundEditor.currentValue = util::to_underlying(soundEditor.currentSource->oscType); + void readCurrentValue() override { + this->value_ = soundEditor.currentSource->oscType; } - void writeCurrentValue() { + void writeCurrentValue() override { OscType oldValue = soundEditor.currentSource->oscType; - auto newValue = static_cast(soundEditor.currentValue); + auto newValue = this->value_; auto needs_unassignment = {OscType::INPUT_L, OscType::INPUT_R, OscType::INPUT_STEREO, OscType::SAMPLE, @@ -63,37 +58,44 @@ class Type final : public Selection { } } + [[nodiscard]] const string& getTitle() const override { + return FormattedTitle::title(); + } + //char const** getOptions() { static char const* options[] = {"SINE", "TRIANGLE", "SQUARE", "SAW", "MMS1", "SUB1", "SAMPLE", "INL", "INR", "INLR", "SQ50", "SQ02", "SQ01", "SUB2", "SQ20", "SA50", "S101", "S303", "MMS2", "MMS3", "TABLE"}; return options; } - char const** getOptions() { + static_vector getOptions() override { + static_vector options = { + "SINE", + "TRIANGLE", + "SQUARE", + HAVE_OLED ? "Analog square" : "ASQUARE", + "Saw", + HAVE_OLED ? "Analog saw" : "ASAW", + "Wavetable", + "SAMPLE", + HAVE_OLED ? "Input (left)" : "INL", + HAVE_OLED ? "Input (right)" : "INR", + HAVE_OLED ? "Input (stereo)" : "INLR", + }; #if HAVE_OLED - static char inLText[] = "Input (left)"; - static char const* options[] = {"SINE", "TRIANGLE", "SQUARE", "Analog square", - "Saw", "Analog saw", "Wavetable", "SAMPLE", - inLText, "Input (right)", "Input (stereo)", NULL}; - inLText[5] = ((AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn)) ? ' ' : 0; + options[8] = ((AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn)) ? "Input (left)" : "Input"; #else - static char inLText[4] = "INL"; - static char const* options[] = {"SINE", "TRIANGLE", "SQUARE", "ASQUARE", "SAW", "ASAW", - "Wavetable", "SAMPLE", inLText, "INR", "INLR"}; - inLText[2] = ((AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn)) ? 'L' : 0; + + options[8] = ((AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn)) ? "INL" : "IN"; #endif - return options; - } - int32_t getNumOptions() { if (soundEditor.currentSound->getSynthMode() == SynthMode::RINGMOD) { - return kNumOscTypesRingModdable; + return {options.begin(), options.begin() + kNumOscTypesRingModdable}; } - else if (AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn) { - return kNumOscTypes; - } - else { - return kNumOscTypes - 2; + if (AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn) { + return {options.begin(), options.begin() + kNumOscTypes}; } + return {options.begin(), options.begin() + kNumOscTypes - 2}; } - bool isRelevant(Sound* sound, int32_t whichThing) { + + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->getSynthMode() != SynthMode::FM); } }; -} // namespace menu_item::osc +} // namespace deluge::gui::menu_item::osc diff --git a/src/deluge/gui/menu_item/param.cpp b/src/deluge/gui/menu_item/param.cpp index a972ceed22..f9096b8607 100644 --- a/src/deluge/gui/menu_item/param.cpp +++ b/src/deluge/gui/menu_item/param.cpp @@ -27,7 +27,7 @@ #include "modulation/params/param_set.h" #include "processing/engines/audio_engine.h" -namespace menu_item { +namespace deluge::gui::menu_item { MenuItem* Param::selectButtonPress() { @@ -48,4 +48,4 @@ MenuItem* Param::selectButtonPress() { return NULL; // Navigate backwards } } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/param.h b/src/deluge/gui/menu_item/param.h index 147fa35247..3ea4080580 100644 --- a/src/deluge/gui/menu_item/param.h +++ b/src/deluge/gui/menu_item/param.h @@ -22,14 +22,14 @@ class ParamSet; class ModelStackWithAutoParam; -namespace menu_item { +namespace deluge::gui::menu_item { // Note that this does *not* inherit from MenuItem actually! class Param { public: - Param(int32_t newP = 0) { p = newP; } - virtual int32_t getMaxValue() const { return 50; } - virtual int32_t getMinValue() const { return 0; } + Param(int32_t newP = 0) : p(newP) {} + [[nodiscard]] virtual int32_t getMaxValue() const { return 50; } + [[nodiscard]] virtual int32_t getMinValue() const { return 0; } virtual uint8_t getP() { return p; }; MenuItem* selectButtonPress(); virtual ModelStackWithAutoParam* getModelStack(void* memory) = 0; @@ -39,4 +39,4 @@ class Param { protected: virtual ParamSet* getParamSet() = 0; }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/patch_cable_strength.cpp b/src/deluge/gui/menu_item/patch_cable_strength.cpp index f4aeaec6a1..aa7e2e885f 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength.cpp +++ b/src/deluge/gui/menu_item/patch_cable_strength.cpp @@ -35,7 +35,7 @@ #include "modulation/patch/patch_cable_set.h" #include "util/functions.h" -namespace menu_item { +namespace deluge::gui::menu_item { extern bool movingCursor; void PatchCableStrength::beginSession(MenuItem* navigatedBackwardFrom) { @@ -104,7 +104,7 @@ void PatchCableStrength::renderOLED() { char buffer[12]; if (preferBarDrawing) { - int32_t rounded = (soundEditor.currentValue + 50 * (soundEditor.currentValue > 0 ? 1 : -1)) / 100; + int32_t rounded = (this->value_ + 50 * (this->value_ > 0 ? 1 : -1)) / 100; intToString(rounded, buffer, 1); OLED::drawStringAlignRight(buffer, extraY + OLED_MAIN_TOPMOST_PIXEL + 4 + destinationDescriptor.isJustAParam(), OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, 18, 20); @@ -116,7 +116,7 @@ void PatchCableStrength::renderOLED() { else { const int32_t digitWidth = kTextBigSpacingX; const int32_t digitHeight = kTextBigSizeY; - intToString(soundEditor.currentValue, buffer, 3); + intToString(this->value_, buffer, 3); int32_t textPixelY = extraY + OLED_MAIN_TOPMOST_PIXEL + 10 + destinationDescriptor.isJustAParam(); OLED::drawStringAlignRight(buffer, textPixelY, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, digitWidth, digitHeight); @@ -135,13 +135,13 @@ void PatchCableStrength::readCurrentValue() { PatchCableSet* patchCableSet = soundEditor.currentParamManager->getPatchCableSet(); uint32_t c = patchCableSet->getPatchCableIndex(getS(), getDestinationDescriptor()); if (c == 255) { - soundEditor.currentValue = 0; + this->value_ = 0; } else { int32_t paramValue = patchCableSet->patchCables[c].param.getCurrentValue(); // the internal values are stored in the range -(2^30) to 2^30. // rescale them to the range -5000 to 5000 and round to nearest. - soundEditor.currentValue = ((int64_t)paramValue * 5000 + (1 << 29)) >> 30; + this->value_ = ((int64_t)paramValue * 5000 + (1 << 29)) >> 30; } } @@ -165,7 +165,7 @@ void PatchCableStrength::writeCurrentValue() { } // rescale from 5000 to 2**30. The magic constant is ((2^30)/5000), shifted 32 bits for precision ((1<<(30+32))/5000) - int32_t finalValue = ((int64_t)922337203685477 * soundEditor.currentValue) >> 32; + int32_t finalValue = ((int64_t)922337203685477 * this->value_) >> 32; modelStackWithParam->autoParam->setCurrentValueInResponseToUserInput(finalValue, modelStackWithParam); } @@ -223,4 +223,4 @@ MenuItem* PatchCableStrength::selectButtonPress() { } return nullptr; // Navigate back } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/patch_cable_strength.h b/src/deluge/gui/menu_item/patch_cable_strength.h index 80e37626ab..e37c0f9128 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength.h +++ b/src/deluge/gui/menu_item/patch_cable_strength.h @@ -19,23 +19,23 @@ #include "decimal.h" #include "menu_item_with_cc_learning.h" -namespace menu_item { +namespace deluge::gui::menu_item { class PatchCableStrength : public Decimal, public MenuItemWithCCLearning { public: using Decimal::Decimal; void beginSession(MenuItem* navigatedBackwardFrom) final; void readCurrentValue() final; - void writeCurrentValue(); - int32_t getMinValue() const final { return -5000; } - int32_t getMaxValue() const final { return 5000; } - int32_t getNumDecimalPlaces() const final { return 2; } + void writeCurrentValue() override; + [[nodiscard]] int32_t getMinValue() const final { return -5000; } + [[nodiscard]] int32_t getMaxValue() const final { return 5000; } + [[nodiscard]] int32_t getNumDecimalPlaces() const final { return 2; } virtual int32_t getDefaultEditPos() { return 2; } - virtual MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange); + MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) override; virtual ParamDescriptor getDestinationDescriptor() = 0; virtual PatchSource getS() = 0; uint8_t getIndexOfPatchedParamToBlink() final; - MenuItem* selectButtonPress(); + MenuItem* selectButtonPress() override; #if HAVE_OLED void renderOLED(); #endif @@ -55,4 +55,4 @@ class PatchCableStrength : public Decimal, public MenuItemWithCCLearning { ModelStackWithAutoParam* getModelStack(void* memory, bool allowCreation = false); }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/patch_cable_strength/fixed.cpp b/src/deluge/gui/menu_item/patch_cable_strength/fixed.cpp index 934501741e..7482a58b3c 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength/fixed.cpp +++ b/src/deluge/gui/menu_item/patch_cable_strength/fixed.cpp @@ -23,24 +23,21 @@ #include "processing/sound/sound.h" #include "storage/multi_range/multi_range.h" -namespace menu_item::patch_cable_strength { +namespace deluge::gui::menu_item::patch_cable_strength { MenuPermission Fixed::checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) { soundEditor.patchingParamSelected = p; source_selection::regularMenu.s = s; return PatchCableStrength::checkPermissionToBeginSession(sound, whichThing, currentRange); } -uint8_t Fixed::shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* sourceShortcutBlinkColours) { - - PatchCableSet* patchCableSet = soundEditor.currentParamManager->getPatchCableSet(); +uint8_t Fixed::shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) { + PatchCableSet& patchCableSet = *soundEditor.currentParamManager->getPatchCableSet(); // If it's the source controlling the range of the source we're editing for... - if (patchCableSet->getPatchCableIndex(s, getLearningThing()) != 255) { + if (patchCableSet.getPatchCableIndex(s, getLearningThing()) != 255) { return 3; } - else { - return 255; - } + return 255; } MenuItem* Fixed::patchingSourceShortcutPress(PatchSource s, bool previousPressStillActive) { @@ -48,4 +45,4 @@ MenuItem* Fixed::patchingSourceShortcutPress(PatchSource s, bool previousPressSt return &patch_cable_strength::rangeMenu; } -} // namespace menu_item::patch_cable_strength +} // namespace deluge::gui::menu_item::patch_cable_strength diff --git a/src/deluge/gui/menu_item/patch_cable_strength/fixed.h b/src/deluge/gui/menu_item/patch_cable_strength/fixed.h index 3b86811c71..7382483c9f 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength/fixed.h +++ b/src/deluge/gui/menu_item/patch_cable_strength/fixed.h @@ -18,14 +18,12 @@ #include "definitions_cxx.hpp" #include "regular.h" -namespace menu_item::patch_cable_strength { +namespace deluge::gui::menu_item::patch_cable_strength { class Fixed : public Regular { public: - Fixed(char const* newName = NULL, int32_t newP = 0, PatchSource newS = PatchSource::LFO_GLOBAL) : Regular(newName) { - p = newP; - s = newS; - } + Fixed(const string& newName, int32_t newP = 0, PatchSource newS = PatchSource::LFO_GLOBAL) + : Regular(newName), p(newP), s(newS) {} MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) final; uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) final; @@ -35,4 +33,4 @@ class Fixed : public Regular { uint8_t p; PatchSource s; }; -} // namespace menu_item::patch_cable_strength +} // namespace deluge::gui::menu_item::patch_cable_strength diff --git a/src/deluge/gui/menu_item/patch_cable_strength/range.cpp b/src/deluge/gui/menu_item/patch_cable_strength/range.cpp index 45492c8d17..3da652982e 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength/range.cpp +++ b/src/deluge/gui/menu_item/patch_cable_strength/range.cpp @@ -19,7 +19,7 @@ #include "gui/menu_item/source_selection/regular.h" #include "gui/ui/sound_editor.h" -namespace menu_item::patch_cable_strength { +namespace deluge::gui::menu_item::patch_cable_strength { Range rangeMenu{}; ParamDescriptor Range::getLearningThing() { @@ -61,4 +61,4 @@ MenuItem* Range::patchingSourceShortcutPress(PatchSource newS, bool previousPres // FixedPatchCableStrength ---------------------------------------------------------------------------- -} // namespace menu_item::patch_cable_strength +} // namespace deluge::gui::menu_item::patch_cable_strength diff --git a/src/deluge/gui/menu_item/patch_cable_strength/range.h b/src/deluge/gui/menu_item/patch_cable_strength/range.h index 4149eed510..852310d4e3 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength/range.h +++ b/src/deluge/gui/menu_item/patch_cable_strength/range.h @@ -18,15 +18,15 @@ #include "definitions_cxx.hpp" #include "gui/menu_item/patch_cable_strength.h" -namespace menu_item::patch_cable_strength { +namespace deluge::gui::menu_item::patch_cable_strength { class Range final : public PatchCableStrength { public: - Range(char const* newName = NULL) : PatchCableStrength(newName) {} - ParamDescriptor getDestinationDescriptor(); - PatchSource getS(); - ParamDescriptor getLearningThing(); + using PatchCableStrength::PatchCableStrength; + ParamDescriptor getDestinationDescriptor() override; + PatchSource getS() override; + ParamDescriptor getLearningThing() override; uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) override; MenuItem* patchingSourceShortcutPress(PatchSource s, bool previousPressStillActive) override; }; extern Range rangeMenu; -} // namespace menu_item::patch_cable_strength +} // namespace deluge::gui::menu_item::patch_cable_strength diff --git a/src/deluge/gui/menu_item/patch_cable_strength/regular.cpp b/src/deluge/gui/menu_item/patch_cable_strength/regular.cpp index 710ccd40b6..d7b5d32eeb 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength/regular.cpp +++ b/src/deluge/gui/menu_item/patch_cable_strength/regular.cpp @@ -24,7 +24,7 @@ #include "modulation/patch/patch_cable_set.h" #include "processing/sound/sound.h" -namespace menu_item::patch_cable_strength { +namespace deluge::gui::menu_item::patch_cable_strength { Regular regularMenu{}; MenuItem* Regular::selectButtonPress() { @@ -33,9 +33,7 @@ MenuItem* Regular::selectButtonPress() { if (Buttons::isShiftButtonPressed()) { return PatchCableStrength::selectButtonPress(); } - else { - return &source_selection::rangeMenu; - } + return &source_selection::rangeMenu; } ParamDescriptor Regular::getLearningThing() { @@ -98,4 +96,4 @@ MenuItem* Regular::patchingSourceShortcutPress(PatchSource s, bool previousPress return (MenuItem*)0xFFFFFFFF; } -} // namespace menu_item::patch_cable_strength +} // namespace deluge::gui::menu_item::patch_cable_strength diff --git a/src/deluge/gui/menu_item/patch_cable_strength/regular.h b/src/deluge/gui/menu_item/patch_cable_strength/regular.h index 6912fcc006..c0cbfbb222 100644 --- a/src/deluge/gui/menu_item/patch_cable_strength/regular.h +++ b/src/deluge/gui/menu_item/patch_cable_strength/regular.h @@ -18,7 +18,7 @@ #include "definitions_cxx.hpp" #include "gui/menu_item/patch_cable_strength.h" -namespace menu_item::patch_cable_strength { +namespace deluge::gui::menu_item::patch_cable_strength { class Regular : public PatchCableStrength { public: @@ -27,11 +27,11 @@ class Regular : public PatchCableStrength { ParamDescriptor getDestinationDescriptor() final; PatchSource getS() final; ParamDescriptor getLearningThing() final; - MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange); + MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) override; uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) override; MenuItem* patchingSourceShortcutPress(PatchSource s, bool previousPressStillActive) override; MenuItem* selectButtonPress() final; }; extern Regular regularMenu; -} // namespace menu_item::patch_cable_strength +} // namespace deluge::gui::menu_item::patch_cable_strength diff --git a/src/deluge/gui/menu_item/patched_param.cpp b/src/deluge/gui/menu_item/patched_param.cpp index 33bcd6d0db..0cc519d648 100644 --- a/src/deluge/gui/menu_item/patched_param.cpp +++ b/src/deluge/gui/menu_item/patched_param.cpp @@ -37,7 +37,7 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item { +namespace deluge::gui::menu_item { MenuItem* PatchedParam::selectButtonPress() { // If shift held down, user wants to delete automation @@ -54,20 +54,14 @@ MenuItem* PatchedParam::selectButtonPress() { } } -#if !HAVE_OLED -void PatchedParam::drawValue() { - ParamDescriptor paramDescriptor; - paramDescriptor.setToHaveParamOnly(this->getP()); - uint8_t drawDot = - soundEditor.currentParamManager->getPatchCableSet()->isAnySourcePatchedToParamVolumeInspecific(paramDescriptor) - ? 3 - : 255; - numericDriver.setTextAsNumber(soundEditor.currentValue, drawDot); -} -#endif +// #if !HAVE_OLED +// void PatchedParam::drawValue() { +// numericDriver.setTextAsNumber(soundEditor.currentValue, shouldDrawDotOnName()); +// } +// #endif uint8_t PatchedParam::shouldDrawDotOnName() { - ParamDescriptor paramDescriptor; + ParamDescriptor paramDescriptor{}; paramDescriptor.setToHaveParamOnly(this->getP()); return soundEditor.currentParamManager->getPatchCableSet()->isAnySourcePatchedToParamVolumeInspecific( paramDescriptor) @@ -90,7 +84,7 @@ uint8_t PatchedParam::getPatchedParamIndex() { } uint8_t PatchedParam::shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) { - ParamDescriptor paramDescriptor; + ParamDescriptor paramDescriptor{}; paramDescriptor.setToHaveParamOnly(this->getP()); return soundEditor.currentParamManager->getPatchCableSet()->isSourcePatchedToDestinationDescriptorVolumeInspecific( s, paramDescriptor) @@ -109,7 +103,7 @@ ModelStackWithAutoParam* PatchedParam::getModelStack(void* memory) { ParamCollectionSummary* summary = modelStack->paramManager->getPatchedParamSetSummary(); int32_t p = this->getP(); return modelStack->addParam(summary->paramCollection, summary, p, - &((ParamSet*)summary->paramCollection)->params[p]); + &(static_cast(summary->paramCollection))->params[p]); } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/patched_param.h b/src/deluge/gui/menu_item/patched_param.h index 275a27ca77..cf68e0048c 100644 --- a/src/deluge/gui/menu_item/patched_param.h +++ b/src/deluge/gui/menu_item/patched_param.h @@ -24,26 +24,26 @@ class ModelStackWithAutoParam; -namespace menu_item { +namespace deluge::gui::menu_item { class PatchedParam : public Param, public MenuItemWithCCLearning { public: - PatchedParam() {} + PatchedParam() = default; PatchedParam(int32_t newP) : Param(newP) {} MenuItem* selectButtonPress(); #if !HAVE_OLED - void drawValue(); + virtual void drawValue() = 0; #endif - ParamDescriptor getLearningThing(); - uint8_t getPatchedParamIndex(); - uint8_t shouldDrawDotOnName(); + ParamDescriptor getLearningThing() override; + virtual uint8_t getPatchedParamIndex(); + virtual uint8_t shouldDrawDotOnName(); uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour); MenuItem* patchingSourceShortcutPress(PatchSource s, bool previousPressStillActive = false); - ModelStackWithAutoParam* getModelStack(void* memory); + ModelStackWithAutoParam* getModelStack(void* memory) override; protected: - ParamSet* getParamSet(); + ParamSet* getParamSet() override; }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/patched_param/integer.cpp b/src/deluge/gui/menu_item/patched_param/integer.cpp index cd9144dca6..6549863ffe 100644 --- a/src/deluge/gui/menu_item/patched_param/integer.cpp +++ b/src/deluge/gui/menu_item/patched_param/integer.cpp @@ -19,12 +19,11 @@ #include "modulation/automation/auto_param.h" #include "modulation/params/param_set.h" -namespace menu_item::patched_param { +namespace deluge::gui::menu_item::patched_param { void Integer::readCurrentValue() { - soundEditor.currentValue = - (((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) + 2147483648) * 50 - + 2147483648) - >> 32; + this->value_ = (((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) + 2147483648) * 50 + + 2147483648) + >> 32; } void Integer::writeCurrentValue() { @@ -36,10 +35,10 @@ void Integer::writeCurrentValue() { } int32_t Integer::getFinalValue() { - if (soundEditor.currentValue == 25) { + if (this->value_ == 25) { return 0; } - return (uint32_t)soundEditor.currentValue * 85899345 - 2147483648; + return (uint32_t)this->value_ * 85899345 - 2147483648; } -} // namespace menu_item::patched_param +} // namespace deluge::gui::menu_item::patched_param diff --git a/src/deluge/gui/menu_item/patched_param/integer.h b/src/deluge/gui/menu_item/patched_param/integer.h index a539d036f4..49e113cabf 100644 --- a/src/deluge/gui/menu_item/patched_param/integer.h +++ b/src/deluge/gui/menu_item/patched_param/integer.h @@ -17,23 +17,26 @@ #pragma once #include "definitions_cxx.hpp" #include "gui/menu_item/patched_param.h" +#include "util/string.h" -namespace menu_item::patched_param { +namespace deluge::gui::menu_item::patched_param { class Integer : public PatchedParam, public menu_item::IntegerContinuous { public: - Integer(char const* newName = NULL, int32_t newP = 0) : PatchedParam(newP), IntegerContinuous(newName) {} + Integer(const string& newName, int32_t newP = 0) : PatchedParam(newP), IntegerContinuous(newName) {} + Integer(const string& newName, const deluge::string& title, int32_t newP = 0) + : PatchedParam(newP), IntegerContinuous(newName, title) {} #if !HAVE_OLED - void drawValue() { - PatchedParam::drawValue(); + void drawValue() override { + numericDriver.setTextAsNumber(this->value_, shouldDrawDotOnName()); } #endif ParamDescriptor getLearningThing() final { return PatchedParam::getLearningThing(); } - int32_t getMaxValue() const { + [[nodiscard]] int32_t getMaxValue() const override { return PatchedParam::getMaxValue(); } - int32_t getMinValue() const { + [[nodiscard]] int32_t getMinValue() const override { return PatchedParam::getMinValue(); } uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) final { @@ -65,8 +68,8 @@ class Integer : public PatchedParam, public menu_item::IntegerContinuous { }; protected: - void readCurrentValue(); + void readCurrentValue() override; void writeCurrentValue() final; virtual int32_t getFinalValue(); }; -} // namespace menu_item::patched_param +} // namespace deluge::gui::menu_item::patched_param diff --git a/src/deluge/gui/menu_item/patched_param/integer_non_fm.h b/src/deluge/gui/menu_item/patched_param/integer_non_fm.h index 8308d692f4..733a96d882 100644 --- a/src/deluge/gui/menu_item/patched_param/integer_non_fm.h +++ b/src/deluge/gui/menu_item/patched_param/integer_non_fm.h @@ -18,10 +18,10 @@ #include "integer.h" #include "processing/sound/sound.h" -namespace menu_item::patched_param { +namespace deluge::gui::menu_item::patched_param { class IntegerNonFM : public Integer { public: using Integer::Integer; - bool isRelevant(Sound* sound, int32_t whichThing) { return (sound->synthMode != SynthMode::FM); } + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->synthMode != SynthMode::FM); } }; -} // namespace menu_item::patched_param +} // namespace deluge::gui::menu_item::patched_param diff --git a/src/deluge/gui/menu_item/patched_param/pan.cpp b/src/deluge/gui/menu_item/patched_param/pan.cpp index 4c96f60d92..e9961bf7b9 100644 --- a/src/deluge/gui/menu_item/patched_param/pan.cpp +++ b/src/deluge/gui/menu_item/patched_param/pan.cpp @@ -26,7 +26,7 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item::patched_param { +namespace deluge::gui::menu_item::patched_param { #if !HAVE_OLED void Pan::drawValue() { ParamDescriptor paramDescriptor; @@ -36,11 +36,11 @@ void Pan::drawValue() { ? 3 : 255; char buffer[5]; - intToString(std::abs(soundEditor.currentValue), buffer, 1); - if (soundEditor.currentValue < 0) { + intToString(std::abs(this->value_), buffer, 1); + if (this->value_ < 0) { strcat(buffer, "L"); } - else if (soundEditor.currentValue > 0) { + else if (this->value_ > 0) { strcat(buffer, "R"); } numericDriver.setText(buffer, true, drawDot); @@ -48,17 +48,17 @@ void Pan::drawValue() { #endif int32_t Pan::getFinalValue() { - if (soundEditor.currentValue == 32) { + if (this->value_ == 32) { return 2147483647; } - if (soundEditor.currentValue == -32) { + if (this->value_ == -32) { return -2147483648; } - return ((int32_t)soundEditor.currentValue * 33554432 * 2); + return ((int32_t)this->value_ * 33554432 * 2); } void Pan::readCurrentValue() { - soundEditor.currentValue = + this->value_ = ((int64_t)soundEditor.currentParamManager->getPatchedParamSet()->getValue(getP()) * 64 + 2147483648) >> 32; } -} // namespace menu_item::patched_param +} // namespace deluge::gui::menu_item::patched_param diff --git a/src/deluge/gui/menu_item/patched_param/pan.h b/src/deluge/gui/menu_item/patched_param/pan.h index d4f161a383..afe66d71d8 100644 --- a/src/deluge/gui/menu_item/patched_param/pan.h +++ b/src/deluge/gui/menu_item/patched_param/pan.h @@ -17,21 +17,21 @@ #pragma once #include "integer.h" -namespace menu_item::patched_param { +namespace deluge::gui::menu_item::patched_param { class Pan : public Integer { public: - Pan(char const* newName = 0, int32_t newP = 0) : Integer(newName, newP) {} + using Integer::Integer; #if !HAVE_OLED - void drawValue(); + void drawValue() override; #endif protected: - int32_t getMaxValue() const override { + [[nodiscard]] int32_t getMaxValue() const override { return 32; } - int32_t getMinValue() const override { + [[nodiscard]] int32_t getMinValue() const override { return -32; } - int32_t getFinalValue(); - void readCurrentValue(); + int32_t getFinalValue() override; + void readCurrentValue() override; }; -} // namespace menu_item::patched_param +} // namespace deluge::gui::menu_item::patched_param diff --git a/src/deluge/gui/menu_item/ppqn.h b/src/deluge/gui/menu_item/ppqn.h index f7658da4be..fbcb3e9736 100644 --- a/src/deluge/gui/menu_item/ppqn.h +++ b/src/deluge/gui/menu_item/ppqn.h @@ -17,11 +17,11 @@ #pragma once #include "gui/menu_item/integer.h" -namespace menu_item { +namespace deluge::gui::menu_item { class PPQN : public Integer { public: using Integer::Integer; - int32_t getMinValue() const { return 1; } - int32_t getMaxValue() const { return 192; } + [[nodiscard]] int32_t getMinValue() const override { return 1; } + [[nodiscard]] int32_t getMaxValue() const override { return 192; } }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/range.cpp b/src/deluge/gui/menu_item/range.cpp index 6a83bd9412..d5f2ed98fa 100644 --- a/src/deluge/gui/menu_item/range.cpp +++ b/src/deluge/gui/menu_item/range.cpp @@ -26,7 +26,7 @@ #include "hid/matrix/matrix_driver.h" #include "util/functions.h" -namespace menu_item { +namespace deluge::gui::menu_item { void Range::beginSession(MenuItem* navigatedBackwardFrom) { @@ -201,4 +201,4 @@ void Range::drawPixelsForOled() { } } #endif -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/range.h b/src/deluge/gui/menu_item/range.h index 9f0f241d19..68e327def8 100644 --- a/src/deluge/gui/menu_item/range.h +++ b/src/deluge/gui/menu_item/range.h @@ -17,9 +17,9 @@ #pragma once -#include "menu_item.h" +#include "gui/menu_item/value.h" -namespace menu_item { +namespace deluge::gui::menu_item { enum class RangeEdit : uint8_t { OFF = 0, @@ -27,23 +27,24 @@ enum class RangeEdit : uint8_t { RIGHT = 2, }; -class Range : public MenuItem { +class Range : public Value { public: - Range(char const* newName = NULL) : MenuItem(newName){}; + using Value::Value; - void beginSession(MenuItem* navigatedBackwardFrom); + void beginSession(MenuItem* navigatedBackwardFrom) override; void horizontalEncoderAction(int32_t offset) final; bool cancelEditingIfItsOn(); protected: - virtual void getText(char* buffer, int32_t* getLeftLength = NULL, int32_t* getRightLength = NULL, + virtual void getText(char* buffer, int32_t* getLeftLength = nullptr, int32_t* getRightLength = nullptr, bool mayShowJustOne = true) = 0; virtual bool mayEditRangeEdge(RangeEdit whichEdge) { return true; } - void drawValue(int32_t startPos = 0, bool renderSidebarToo = true); + virtual void drawValue() { this->drawValue(0); } + void drawValue(int32_t startPos, bool renderSidebarToo = true); void drawValueForEditingRange(bool blinkImmediately); #if HAVE_OLED void drawPixelsForOled(); #endif }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/record/count_in.h b/src/deluge/gui/menu_item/record/count_in.h index 032375d529..28d4a78e67 100644 --- a/src/deluge/gui/menu_item/record/count_in.h +++ b/src/deluge/gui/menu_item/record/count_in.h @@ -15,15 +15,15 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "playback/playback_handler.h" -namespace menu_item::record { -class CountIn final : public Selection { +namespace deluge::gui::menu_item::record { +class CountIn final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = playbackHandler.countInEnabled; } - void writeCurrentValue() { playbackHandler.countInEnabled = soundEditor.currentValue; } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = playbackHandler.countInEnabled; } + void writeCurrentValue() override { playbackHandler.countInEnabled = this->value_; } }; -} // namespace menu_item::record +} // namespace deluge::gui::menu_item::record diff --git a/src/deluge/gui/menu_item/record/margins.h b/src/deluge/gui/menu_item/record/margins.h index 72ceb02c30..fafc8637a4 100644 --- a/src/deluge/gui/menu_item/record/margins.h +++ b/src/deluge/gui/menu_item/record/margins.h @@ -16,13 +16,14 @@ */ #pragma once #include "gui/menu_item/sync_level/relative_to_song.h" +#include "gui/menu_item/toggle.h" #include "storage/flash_storage.h" -namespace menu_item::record { -class Margins final : public Selection { +namespace deluge::gui::menu_item::record { +class Margins final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = FlashStorage::audioClipRecordMargins; } - void writeCurrentValue() { FlashStorage::audioClipRecordMargins = soundEditor.currentValue; } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = FlashStorage::audioClipRecordMargins; } + void writeCurrentValue() override { FlashStorage::audioClipRecordMargins = this->value_; } }; -} // namespace menu_item::record +} // namespace deluge::gui::menu_item::record diff --git a/src/deluge/gui/menu_item/record/quantize.h b/src/deluge/gui/menu_item/record/quantize.h index 7f36072e7e..c2f92904ea 100644 --- a/src/deluge/gui/menu_item/record/quantize.h +++ b/src/deluge/gui/menu_item/record/quantize.h @@ -18,11 +18,11 @@ #include "gui/menu_item/sync_level/relative_to_song.h" #include "storage/flash_storage.h" -namespace menu_item::record { +namespace deluge::gui::menu_item::record { class Quantize final : public sync_level::RelativeToSong { public: using RelativeToSong::RelativeToSong; - void readCurrentValue() { soundEditor.currentValue = FlashStorage::recordQuantizeLevel; } - void writeCurrentValue() { FlashStorage::recordQuantizeLevel = soundEditor.currentValue; } + void readCurrentValue() { this->value_ = FlashStorage::recordQuantizeLevel; } + void writeCurrentValue() { FlashStorage::recordQuantizeLevel = this->value_; } }; -} // namespace menu_item::record +} // namespace deluge::gui::menu_item::record diff --git a/src/deluge/gui/menu_item/reverb/compressor/shape.h b/src/deluge/gui/menu_item/reverb/compressor/shape.h index 2a1050a010..cecc12be27 100644 --- a/src/deluge/gui/menu_item/reverb/compressor/shape.h +++ b/src/deluge/gui/menu_item/reverb/compressor/shape.h @@ -20,19 +20,19 @@ #include "processing/engines/audio_engine.h" #include "processing/sound/sound.h" -namespace menu_item::reverb::compressor { +namespace deluge::gui::menu_item::reverb::compressor { class Shape final : public Integer { public: - Shape(char const* newName = NULL) : Integer(newName) {} - void readCurrentValue() { - soundEditor.currentValue = (((int64_t)AudioEngine::reverbCompressorShape + 2147483648) * 50 + 2147483648) >> 32; + using Integer::Integer; + void readCurrentValue() override { + this->value_ = (((int64_t)AudioEngine::reverbCompressorShape + 2147483648) * 50 + 2147483648) >> 32; } - void writeCurrentValue() { - AudioEngine::reverbCompressorShape = (uint32_t)soundEditor.currentValue * 85899345 - 2147483648; + void writeCurrentValue() override { + AudioEngine::reverbCompressorShape = (uint32_t)this->value_ * 85899345 - 2147483648; AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } - int32_t getMaxValue() const { return 50; } - bool isRelevant(Sound* sound, int32_t whichThing) { return (AudioEngine::reverbCompressorVolume >= 0); } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + bool isRelevant(Sound* sound, int32_t whichThing) override { return (AudioEngine::reverbCompressorVolume >= 0); } }; -} // namespace menu_item::reverb::compressor +} // namespace deluge::gui::menu_item::reverb::compressor diff --git a/src/deluge/gui/menu_item/reverb/compressor/volume.h b/src/deluge/gui/menu_item/reverb/compressor/volume.h index 3420bfd5dc..9e198a8900 100644 --- a/src/deluge/gui/menu_item/reverb/compressor/volume.h +++ b/src/deluge/gui/menu_item/reverb/compressor/volume.h @@ -20,21 +20,21 @@ #include "processing/engines/audio_engine.h" #include "processing/sound/sound.h" -namespace menu_item::reverb::compressor { +namespace deluge::gui::menu_item::reverb::compressor { class Volume final : public Integer { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = AudioEngine::reverbCompressorVolume / 21474836; } - void writeCurrentValue() { - AudioEngine::reverbCompressorVolume = soundEditor.currentValue * 21474836; + void readCurrentValue() override { this->value_ = AudioEngine::reverbCompressorVolume / 21474836; } + void writeCurrentValue() override { + AudioEngine::reverbCompressorVolume = this->value_ * 21474836; AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } - int32_t getMaxValue() const { return 50; } - int32_t getMinValue() const { return -1; } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + [[nodiscard]] int32_t getMinValue() const override { return -1; } #if !HAVE_OLED - void drawValue() { - if (soundEditor.currentValue < 0) { + void drawValue() override { + if (this->value_ < 0) { numericDriver.setText("AUTO"); } else { @@ -44,4 +44,4 @@ class Volume final : public Integer { #endif }; -} // namespace menu_item::reverb::compressor +} // namespace deluge::gui::menu_item::reverb::compressor diff --git a/src/deluge/gui/menu_item/reverb/dampening.h b/src/deluge/gui/menu_item/reverb/dampening.h index 773ac6645c..522b3da021 100644 --- a/src/deluge/gui/menu_item/reverb/dampening.h +++ b/src/deluge/gui/menu_item/reverb/dampening.h @@ -21,12 +21,12 @@ #include "processing/engines/audio_engine.h" #include -namespace menu_item::reverb { +namespace deluge::gui::menu_item::reverb { class Dampening final : public Integer { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = std::round(AudioEngine::reverb.getdamp() * 50); } - void writeCurrentValue() { AudioEngine::reverb.setdamp((float)soundEditor.currentValue / 50); } - int32_t getMaxValue() const { return 50; } + void readCurrentValue() override { this->value_ = std::round(AudioEngine::reverb.getdamp() * 50); } + void writeCurrentValue() override { AudioEngine::reverb.setdamp((float)this->value_ / 50); } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } }; -} // namespace menu_item::reverb +} // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/reverb/pan.h b/src/deluge/gui/menu_item/reverb/pan.h index 6c09fd4ba8..aecc1f19ab 100644 --- a/src/deluge/gui/menu_item/reverb/pan.h +++ b/src/deluge/gui/menu_item/reverb/pan.h @@ -26,26 +26,26 @@ #include "processing/engines/audio_engine.h" -namespace menu_item::reverb { +namespace deluge::gui::menu_item::reverb { class Pan final : public Integer { public: using Integer::Integer; - void drawValue() { + virtual void drawValue() { char buffer[5]; - intToString(std::abs(soundEditor.currentValue), buffer, 1); - if (soundEditor.currentValue < 0) { + intToString(std::abs(this->value_), buffer, 1); + if (this->value_ < 0) { strcat(buffer, "L"); } - else if (soundEditor.currentValue > 0) { + else if (this->value_ > 0) { strcat(buffer, "R"); } numericDriver.setText(buffer, true); } - void writeCurrentValue() { AudioEngine::reverbPan = ((int32_t)soundEditor.currentValue * 33554432); } + void writeCurrentValue() override { AudioEngine::reverbPan = ((int32_t)this->value_ * 33554432); } - void readCurrentValue() { soundEditor.currentValue = ((int64_t)AudioEngine::reverbPan * 128 + 2147483648) >> 32; } - int32_t getMaxValue() const { return 32; } - int32_t getMinValue() const { return -32; } + void readCurrentValue() override { this->value_ = ((int64_t)AudioEngine::reverbPan * 128 + 2147483648) >> 32; } + [[nodiscard]] int32_t getMaxValue() const override { return 32; } + [[nodiscard]] int32_t getMinValue() const override { return -32; } }; -} // namespace menu_item::reverb +} // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/reverb/room_size.h b/src/deluge/gui/menu_item/reverb/room_size.h index c83446333d..15f86466b4 100644 --- a/src/deluge/gui/menu_item/reverb/room_size.h +++ b/src/deluge/gui/menu_item/reverb/room_size.h @@ -21,12 +21,12 @@ #include "processing/engines/audio_engine.h" #include -namespace menu_item::reverb { +namespace deluge::gui::menu_item::reverb { class RoomSize final : public Integer { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = std::round(AudioEngine::reverb.getroomsize() * 50); } - void writeCurrentValue() { AudioEngine::reverb.setroomsize((float)soundEditor.currentValue / 50); } - int32_t getMaxValue() const { return 50; } + void readCurrentValue() override { this->value_ = std::round(AudioEngine::reverb.getroomsize() * 50); } + void writeCurrentValue() override { AudioEngine::reverb.setroomsize((float)this->value_ / 50); } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } }; -} // namespace menu_item::reverb +} // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/reverb/width.h b/src/deluge/gui/menu_item/reverb/width.h index ad0ba10c8e..db6ef1d280 100644 --- a/src/deluge/gui/menu_item/reverb/width.h +++ b/src/deluge/gui/menu_item/reverb/width.h @@ -21,12 +21,12 @@ #include "processing/engines/audio_engine.h" #include -namespace menu_item::reverb { +namespace deluge::gui::menu_item::reverb { class Width final : public Integer { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = std::round(AudioEngine::reverb.getwidth() * 50); } - void writeCurrentValue() { AudioEngine::reverb.setwidth((float)soundEditor.currentValue / 50); } - int32_t getMaxValue() const { return 50; } + void readCurrentValue() override { this->value_ = std::round(AudioEngine::reverb.getwidth() * 50); } + void writeCurrentValue() override { AudioEngine::reverb.setwidth((float)this->value_ / 50); } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } }; -} // namespace menu_item::reverb +} // namespace deluge::gui::menu_item::reverb diff --git a/src/deluge/gui/menu_item/runtime_feature/setting.cpp b/src/deluge/gui/menu_item/runtime_feature/setting.cpp index 26654ca534..d861617710 100644 --- a/src/deluge/gui/menu_item/runtime_feature/setting.cpp +++ b/src/deluge/gui/menu_item/runtime_feature/setting.cpp @@ -16,9 +16,15 @@ */ #include "setting.h" +#include "gui/menu_item/runtime_feature/setting.h" #include "gui/ui/sound_editor.h" #include "model/settings/runtime_feature_settings.h" -namespace menu_item::runtime_feature { +#include "util/container/static_vector.hpp" +#include +#include +#include + +namespace deluge::gui::menu_item::runtime_feature { Setting::Setting(RuntimeFeatureSettingType ty) : currentSettingIndex(static_cast(ty)) { } @@ -27,50 +33,33 @@ void Setting::readCurrentValue() { for (uint32_t idx = 0; idx < RUNTIME_FEATURE_SETTING_MAX_OPTIONS; ++idx) { if (runtimeFeatureSettings.settings[currentSettingIndex].options[idx].value == runtimeFeatureSettings.settings[currentSettingIndex].value) { - soundEditor.currentValue = idx; + this->value_ = idx; return; } } - soundEditor.currentValue = 0; + this->value_ = 0; } void Setting::writeCurrentValue() { runtimeFeatureSettings.settings[currentSettingIndex].value = - runtimeFeatureSettings.settings[currentSettingIndex].options[soundEditor.currentValue].value; -} - -char const** Setting::getOptions() { - static char const* options[RUNTIME_FEATURE_SETTING_MAX_OPTIONS] = {0}; - uint32_t optionCount = 0; - for (uint32_t idx = 0; idx < RUNTIME_FEATURE_SETTING_MAX_OPTIONS; ++idx) { - if (runtimeFeatureSettings.settings[currentSettingIndex].options[idx].displayName != NULL) { - options[optionCount++] = runtimeFeatureSettings.settings[currentSettingIndex].options[idx].displayName; - } - else { - options[optionCount] = NULL; - break; - } - } - return (char const**)&options; + runtimeFeatureSettings.settings[currentSettingIndex].options[this->value_].value; } -int32_t Setting::getNumOptions() { - for (uint32_t idx = 0; idx < RUNTIME_FEATURE_SETTING_MAX_OPTIONS; ++idx) { - if (runtimeFeatureSettings.settings[currentSettingIndex].options[idx].displayName == NULL) { - return idx; - } +static_vector Setting::getOptions() { + static_vector options; + for (const RuntimeFeatureSettingOption& option : runtimeFeatureSettings.settings[currentSettingIndex].options) { + options.push_back(option.displayName); } - - return 0; + return options; } -char const* Setting::getName() { +const string& Setting::getName() const { return runtimeFeatureSettings.settings[currentSettingIndex].displayName; } -char const* Setting::getTitle() { +const string& Setting::getTitle() const { return runtimeFeatureSettings.settings[currentSettingIndex].displayName; } -} // namespace menu_item::runtime_feature +} // namespace deluge::gui::menu_item::runtime_feature diff --git a/src/deluge/gui/menu_item/runtime_feature/setting.h b/src/deluge/gui/menu_item/runtime_feature/setting.h index 9f1c8bb84a..0f8d152b27 100644 --- a/src/deluge/gui/menu_item/runtime_feature/setting.h +++ b/src/deluge/gui/menu_item/runtime_feature/setting.h @@ -17,24 +17,23 @@ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "model/settings/runtime_feature_settings.h" -namespace menu_item::runtime_feature { +namespace deluge::gui::menu_item::runtime_feature { class Settings; -class Setting final : public Selection { +class Setting final : public Selection { public: explicit Setting(RuntimeFeatureSettingType ty); - void readCurrentValue(); - void writeCurrentValue(); - char const** getOptions(); - int32_t getNumOptions(); - char const* getName(); - char const* getTitle(); + void readCurrentValue() override; + void writeCurrentValue() override; + static_vector getOptions() override; + [[nodiscard]] const string& getName() const override; + [[nodiscard]] const string& getTitle() const override; private: friend class Settings; uint32_t currentSettingIndex; }; -} // namespace menu_item::runtime_feature +} // namespace deluge::gui::menu_item::runtime_feature diff --git a/src/deluge/gui/menu_item/runtime_feature/settings.cpp b/src/deluge/gui/menu_item/runtime_feature/settings.cpp index 0e051d6b93..d5e9ce0e3e 100644 --- a/src/deluge/gui/menu_item/runtime_feature/settings.cpp +++ b/src/deluge/gui/menu_item/runtime_feature/settings.cpp @@ -20,16 +20,15 @@ #include "gui/ui/sound_editor.h" #include "hid/display/numeric_driver.h" -#include "model/settings/runtime_feature_settings.h" #include #include #include #include -extern menu_item::runtime_feature::Setting runtimeFeatureSettingMenuItem; +extern deluge::gui::menu_item::runtime_feature::Setting runtimeFeatureSettingMenuItem; -namespace menu_item::runtime_feature { +namespace deluge::gui::menu_item::runtime_feature { // Generic menu item instances Setting menuDrumRandomizer(RuntimeFeatureSettingType::DrumRandomizer); @@ -40,19 +39,13 @@ Setting menuPatchCableResolution(RuntimeFeatureSettingType::PatchCableResolution Setting menuCatchNotes(RuntimeFeatureSettingType::CatchNotes); Setting menuDeleteUnusedKitRows(RuntimeFeatureSettingType::DeleteUnusedKitRows); -std::array subMenuEntries{ - &menuDrumRandomizer, - &menuMasterCompressorFx, - &menuFineTempo, - &menuQuantize, - &menuPatchCableResolution, - &menuCatchNotes, - &menuDeleteUnusedKitRows, - - nullptr, +std::array subMenuEntries{ + &menuDrumRandomizer, &menuMasterCompressorFx, &menuFineTempo, &menuQuantize, + &menuPatchCableResolution, &menuCatchNotes, &menuDeleteUnusedKitRows, }; -Settings::Settings(char const* name) : menu_item::Submenu(name, &subMenuEntries[0]) { +Settings::Settings(char const* name, char const* title) + : menu_item::Submenu(name, title, subMenuEntries) { } -} // namespace menu_item::runtime_feature +} // namespace deluge::gui::menu_item::runtime_feature diff --git a/src/deluge/gui/menu_item/runtime_feature/settings.h b/src/deluge/gui/menu_item/runtime_feature/settings.h index 0d226cf799..fee6e79f97 100644 --- a/src/deluge/gui/menu_item/runtime_feature/settings.h +++ b/src/deluge/gui/menu_item/runtime_feature/settings.h @@ -17,17 +17,19 @@ #pragma once +#include "definitions.h" #include "gui/menu_item/submenu.h" +#include "model/settings/runtime_feature_settings.h" -namespace menu_item::runtime_feature { +namespace deluge::gui::menu_item::runtime_feature { -class Settings final : public Submenu { +class Settings final : public Submenu { public: - Settings(char const* name); + Settings(char const* name, char const* title); private: }; extern Settings runtimeFeatureSettingsMenu; -} // namespace menu_item::runtime_feature +} // namespace deluge::gui::menu_item::runtime_feature diff --git a/src/deluge/gui/menu_item/sample/browser_preview/mode.h b/src/deluge/gui/menu_item/sample/browser_preview/mode.h index 6d47328624..a046847b10 100644 --- a/src/deluge/gui/menu_item/sample/browser_preview/mode.h +++ b/src/deluge/gui/menu_item/sample/browser_preview/mode.h @@ -15,20 +15,16 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" #include "storage/flash_storage.h" -namespace menu_item::sample::browser_preview { -class Mode final : public Selection { +namespace deluge::gui::menu_item::sample::browser_preview { +class Mode final : public Selection<3> { public: using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = FlashStorage::sampleBrowserPreviewMode; } - void writeCurrentValue() { FlashStorage::sampleBrowserPreviewMode = soundEditor.currentValue; } - char const** getOptions() { - static char const* options[] = {"Off", "Conditional", "On", NULL}; - return options; - } - int32_t getNumOptions() { return 3; } + void readCurrentValue() override { this->value_ = FlashStorage::sampleBrowserPreviewMode; } + void writeCurrentValue() override { FlashStorage::sampleBrowserPreviewMode = this->value_; } + static_vector getOptions() override { return {"Off", "Conditional", "On"}; } }; -} // namespace menu_item::sample::browser_preview +} // namespace deluge::gui::menu_item::sample::browser_preview diff --git a/src/deluge/gui/menu_item/sample/end.h b/src/deluge/gui/menu_item/sample/end.h index 78075541ba..aeb7f265cf 100644 --- a/src/deluge/gui/menu_item/sample/end.h +++ b/src/deluge/gui/menu_item/sample/end.h @@ -17,9 +17,9 @@ #pragma once #include "loop_point.h" -namespace menu_item::sample { +namespace deluge::gui::menu_item::sample { class End final : public LoopPoint { public: - End(char const* newName = NULL) : LoopPoint(newName) { markerType = MarkerType::END; } + End(const string& newName) : LoopPoint(newName) { markerType = MarkerType::END; } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/interpolation.h b/src/deluge/gui/menu_item/sample/interpolation.h index 25ebd28d03..7a12c1f005 100644 --- a/src/deluge/gui/menu_item/sample/interpolation.h +++ b/src/deluge/gui/menu_item/sample/interpolation.h @@ -16,28 +16,29 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/formatted_title.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "model/sample/sample_controls.h" #include "processing/sound/sound.h" #include "util/misc.h" -namespace menu_item::sample { -class Interpolation final : public Selection { +namespace deluge::gui::menu_item::sample { +class Interpolation final : public TypedSelection, public FormattedTitle { public: - Interpolation(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue() { - soundEditor.currentValue = util::to_underlying(soundEditor.currentSampleControls->interpolationMode); - } - void writeCurrentValue() { - soundEditor.currentSampleControls->interpolationMode = static_cast(soundEditor.currentValue); - } - char const** getOptions() { - static char const* options[] = {"Linear", "Sinc", NULL}; - return options; - } - bool isRelevant(Sound* sound, int32_t whichThing) { - if (!sound) { + Interpolation(const string& name, const string& title_format_str) + : TypedSelection(name), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + void readCurrentValue() override { this->value_ = soundEditor.currentSampleControls->interpolationMode; } + + void writeCurrentValue() override { soundEditor.currentSampleControls->interpolationMode = this->value_; } + + static_vector getOptions() override { return {"Linear", "Sinc"}; } + + bool isRelevant(Sound* sound, int32_t whichThing) override { + if (sound == nullptr) { return true; } Source* source = &sound->sources[whichThing]; @@ -47,4 +48,4 @@ class Interpolation final : public Selection { || source->oscType == OscType::INPUT_STEREO)); } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/loop_point.cpp b/src/deluge/gui/menu_item/sample/loop_point.cpp index 3725b8240f..7f1d2b3539 100644 --- a/src/deluge/gui/menu_item/sample/loop_point.cpp +++ b/src/deluge/gui/menu_item/sample/loop_point.cpp @@ -26,7 +26,7 @@ #include "storage/audio/audio_file_holder.h" #include "storage/multi_range/multi_range.h" -namespace menu_item::sample { +namespace deluge::gui::menu_item::sample { bool LoopPoint::isRelevant(Sound* sound, int32_t whichThing) { @@ -70,4 +70,4 @@ void LoopPoint::beginSession(MenuItem* navigatedBackwardFrom) { uiTimerManager.unsetTimer(TIMER_SHORTCUT_BLINK); } } -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/loop_point.h b/src/deluge/gui/menu_item/sample/loop_point.h index 89a7d05a74..588cbd4cdf 100644 --- a/src/deluge/gui/menu_item/sample/loop_point.h +++ b/src/deluge/gui/menu_item/sample/loop_point.h @@ -20,12 +20,12 @@ #include "definitions_cxx.hpp" #include "gui/menu_item/menu_item.h" -namespace menu_item::sample { +namespace deluge::gui::menu_item::sample { class LoopPoint : public MenuItem { public: using MenuItem::MenuItem; - void beginSession(MenuItem* navigatedBackwardFrom = NULL) final; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) final; bool isRelevant(::Sound* sound, int32_t whichThing) final; bool isRangeDependent() final { return true; } MenuPermission checkPermissionToBeginSession(::Sound* sound, int32_t whichThing, ::MultiRange** currentRange) final; @@ -37,4 +37,4 @@ class LoopPoint : public MenuItem { MarkerType markerType; }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/pitch_speed.h b/src/deluge/gui/menu_item/sample/pitch_speed.h index 0085a1fa11..c806928b29 100644 --- a/src/deluge/gui/menu_item/sample/pitch_speed.h +++ b/src/deluge/gui/menu_item/sample/pitch_speed.h @@ -15,7 +15,7 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" #include "model/clip/clip.h" #include "model/drum/drum.h" @@ -23,42 +23,37 @@ #include "model/song/song.h" #include "processing/sound/sound_drum.h" -namespace menu_item::sample { -class PitchSpeed final : public Selection { +namespace deluge::gui::menu_item::sample { +class PitchSpeed final : public Selection<2> { public: - PitchSpeed(char const* newName = NULL) : Selection(newName) {} + using Selection::Selection; - bool usesAffectEntire() { return true; } + bool usesAffectEntire() override { return true; } - void readCurrentValue() { - soundEditor.currentValue = soundEditor.currentSampleControls->pitchAndSpeedAreIndependent; - } + void readCurrentValue() override { this->value_ = soundEditor.currentSampleControls->pitchAndSpeedAreIndependent; } - void writeCurrentValue() { + void writeCurrentValue() override { // If affect-entire button held, do whole kit if (currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR && soundEditor.editingKit()) { - Kit* kit = (Kit*)currentSong->currentClip->output; + Kit* kit = static_cast(currentSong->currentClip->output); - for (Drum* thisDrum = kit->firstDrum; thisDrum; thisDrum = thisDrum->next) { + for (Drum* thisDrum = kit->firstDrum; thisDrum != nullptr; thisDrum = thisDrum->next) { if (thisDrum->type == DrumType::SOUND) { - SoundDrum* soundDrum = (SoundDrum*)thisDrum; + auto* soundDrum = static_cast(thisDrum); Source* source = &soundDrum->sources[soundEditor.currentSourceIndex]; - source->sampleControls.pitchAndSpeedAreIndependent = soundEditor.currentValue; + source->sampleControls.pitchAndSpeedAreIndependent = this->value_; } } } // Or, the normal case of just one sound else { - soundEditor.currentSampleControls->pitchAndSpeedAreIndependent = soundEditor.currentValue; + soundEditor.currentSampleControls->pitchAndSpeedAreIndependent = this->value_; } } - char const** getOptions() { - static char const* options[] = {"Linked", "Independent", NULL}; - return options; - } + static_vector getOptions() override { return {"Linked", "Independent"}; } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/repeat.h b/src/deluge/gui/menu_item/sample/repeat.h index edce67d8af..e43861cc6f 100644 --- a/src/deluge/gui/menu_item/sample/repeat.h +++ b/src/deluge/gui/menu_item/sample/repeat.h @@ -16,6 +16,8 @@ */ #pragma once #include "definitions_cxx.hpp" +#include "gui/menu_item/formatted_title.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "gui/views/instrument_clip_view.h" #include "model/clip/clip.h" @@ -23,30 +25,33 @@ #include "model/drum/kit.h" #include "model/song/song.h" #include "processing/sound/sound_drum.h" -#include "selection.h" #include "util/misc.h" -namespace menu_item::sample { +namespace deluge::gui::menu_item::sample { -class Repeat final : public Selection { +class Repeat final : public TypedSelection, public FormattedTitle { public: - Repeat(char const* newName = NULL) : Selection(newName) {} - bool usesAffectEntire() { return true; } - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(soundEditor.currentSource->repeatMode); } - void writeCurrentValue() { + Repeat(const string& name, const string& title_format_str) + : TypedSelection(name), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + bool usesAffectEntire() override { return true; } + void readCurrentValue() override { this->value_ = soundEditor.currentSource->repeatMode; } + void writeCurrentValue() override { // If affect-entire button held, do whole kit if (currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR && soundEditor.editingKit()) { - Kit* kit = (Kit*)currentSong->currentClip->output; + Kit* kit = static_cast(currentSong->currentClip->output); - for (Drum* thisDrum = kit->firstDrum; thisDrum; thisDrum = thisDrum->next) { + for (Drum* thisDrum = kit->firstDrum; thisDrum != nullptr; thisDrum = thisDrum->next) { if (thisDrum->type == DrumType::SOUND) { - SoundDrum* soundDrum = (SoundDrum*)thisDrum; + auto* soundDrum = static_cast(thisDrum); Source* source = &soundDrum->sources[soundEditor.currentSourceIndex]; // Automatically switch pitch/speed independence on / off if stretch-to-note-length mode is selected - if (static_cast(soundEditor.currentValue) == SampleRepeatMode::STRETCH) { + if (this->value_ == SampleRepeatMode::STRETCH) { soundDrum->unassignAllVoices(); source->sampleControls.pitchAndSpeedAreIndependent = true; } @@ -55,7 +60,7 @@ class Repeat final : public Selection { soundEditor.currentSource->sampleControls.pitchAndSpeedAreIndependent = false; } - source->repeatMode = static_cast(soundEditor.currentValue); + source->repeatMode = this->value_; } } } @@ -63,7 +68,7 @@ class Repeat final : public Selection { // Or, the normal case of just one sound else { // Automatically switch pitch/speed independence on / off if stretch-to-note-length mode is selected - if (static_cast(soundEditor.currentValue) == SampleRepeatMode::STRETCH) { + if (static_cast(this->value_) == SampleRepeatMode::STRETCH) { soundEditor.currentSound->unassignAllVoices(); soundEditor.currentSource->sampleControls.pitchAndSpeedAreIndependent = true; } @@ -72,17 +77,13 @@ class Repeat final : public Selection { soundEditor.currentSource->sampleControls.pitchAndSpeedAreIndependent = false; } - soundEditor.currentSource->repeatMode = static_cast(soundEditor.currentValue); + soundEditor.currentSource->repeatMode = static_cast(this->value_); } // We need to re-render all rows, because this will have changed whether Note tails are displayed. Probably just one row, but we don't know which uiNeedsRendering(&instrumentClipView, 0xFFFFFFFF, 0); } - char const** getOptions() { - static char const* options[] = {"CUT", "ONCE", "LOOP", "STRETCH", NULL}; - return options; - } - int32_t getNumOptions() { return kNumRepeatModes; } + static_vector getOptions() override { return {"CUT", "ONCE", "LOOP", "STRETCH"}; } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/reverse.h b/src/deluge/gui/menu_item/sample/reverse.h index 7971f3da08..582454a32a 100644 --- a/src/deluge/gui/menu_item/sample/reverse.h +++ b/src/deluge/gui/menu_item/sample/reverse.h @@ -15,33 +15,39 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "model/clip/clip.h" #include "model/drum/kit.h" #include "model/song/song.h" #include "processing/sound/sound_drum.h" -#include "selection.h" -namespace menu_item::sample { -class Reverse final : public Selection { +namespace deluge::gui::menu_item::sample { +class Reverse final : public Toggle, public FormattedTitle { public: - Reverse(char const* newName = NULL) : Selection(newName) {} - bool usesAffectEntire() { return true; } - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSource->sampleControls.reversed; } - void writeCurrentValue() { + Reverse(const string& name, const string& title_format_str) : Toggle(name), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + bool usesAffectEntire() override { return true; } + + void readCurrentValue() override { this->value_ = soundEditor.currentSource->sampleControls.reversed; } + + void writeCurrentValue() override { // If affect-entire button held, do whole kit if (currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR && soundEditor.editingKit()) { - Kit* kit = (Kit*)currentSong->currentClip->output; + Kit* kit = static_cast(currentSong->currentClip->output); - for (Drum* thisDrum = kit->firstDrum; thisDrum; thisDrum = thisDrum->next) { + for (Drum* thisDrum = kit->firstDrum; thisDrum != nullptr; thisDrum = thisDrum->next) { if (thisDrum->type == DrumType::SOUND) { - SoundDrum* soundDrum = (SoundDrum*)thisDrum; + auto* soundDrum = static_cast(thisDrum); Source* source = &soundDrum->sources[soundEditor.currentSourceIndex]; soundDrum->unassignAllVoices(); - source->setReversed(soundEditor.currentValue); + source->setReversed(this->value_); } } } @@ -49,8 +55,8 @@ class Reverse final : public Selection { // Or, the normal case of just one sound else { soundEditor.currentSound->unassignAllVoices(); - soundEditor.currentSource->setReversed(soundEditor.currentValue); + soundEditor.currentSource->setReversed(this->value_); } } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/selection.h b/src/deluge/gui/menu_item/sample/selection.h index e534231bdf..9dc856815b 100644 --- a/src/deluge/gui/menu_item/sample/selection.h +++ b/src/deluge/gui/menu_item/sample/selection.h @@ -15,15 +15,16 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "processing/sound/sound.h" -namespace menu_item::sample { -class Selection : public menu_item::Selection { +namespace deluge::gui::menu_item::sample { +template +class Selection : public menu_item::Selection { public: - Selection(char const* newName = NULL) : menu_item::Selection(newName) {} - bool isRelevant(Sound* sound, int32_t whichThing) { - if (!sound) { + using menu_item::Selection::Selection; + bool isRelevant(Sound* sound, int32_t whichThing) override { + if (sound == nullptr) { return true; // For AudioClips } @@ -32,4 +33,4 @@ class Selection : public menu_item::Selection { && source->hasAtLeastOneAudioFileLoaded()); } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/start.h b/src/deluge/gui/menu_item/sample/start.h index 79f2ce2e18..505019808c 100644 --- a/src/deluge/gui/menu_item/sample/start.h +++ b/src/deluge/gui/menu_item/sample/start.h @@ -17,9 +17,9 @@ #pragma once #include "loop_point.h" -namespace menu_item::sample { +namespace deluge::gui::menu_item::sample { class Start final : public LoopPoint { public: - Start(char const* newName = NULL) : LoopPoint(newName) { markerType = MarkerType::START; } + Start(const string& newName) : LoopPoint(newName) { markerType = MarkerType::START; } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/time_stretch.h b/src/deluge/gui/menu_item/sample/time_stretch.h index 99aa173e6c..4dfb6c49b5 100644 --- a/src/deluge/gui/menu_item/sample/time_stretch.h +++ b/src/deluge/gui/menu_item/sample/time_stretch.h @@ -15,6 +15,7 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/integer.h" #include "gui/ui/sound_editor.h" #include "model/clip/clip.h" @@ -23,39 +24,44 @@ #include "model/song/song.h" #include "processing/sound/sound_drum.h" -namespace menu_item::sample { -class TimeStretch final : public Integer { +namespace deluge::gui::menu_item::sample { +class TimeStretch final : public Integer, public FormattedTitle { public: - TimeStretch(char const* newName = NULL) : Integer(newName) {} - bool usesAffectEntire() { return true; } - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSource->timeStretchAmount; } - void writeCurrentValue() { + TimeStretch(const string& name, const string& title_format_str) : Integer(name), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + bool usesAffectEntire() override { return true; } + + void readCurrentValue() override { this->value_ = soundEditor.currentSource->timeStretchAmount; } + + void writeCurrentValue() override { // If affect-entire button held, do whole kit if (currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR && soundEditor.editingKit()) { - Kit* kit = (Kit*)currentSong->currentClip->output; + Kit* kit = static_cast(currentSong->currentClip->output); - for (Drum* thisDrum = kit->firstDrum; thisDrum; thisDrum = thisDrum->next) { + for (Drum* thisDrum = kit->firstDrum; thisDrum != nullptr; thisDrum = thisDrum->next) { if (thisDrum->type == DrumType::SOUND) { - SoundDrum* soundDrum = (SoundDrum*)thisDrum; + auto* soundDrum = static_cast(thisDrum); Source* source = &soundDrum->sources[soundEditor.currentSourceIndex]; - source->timeStretchAmount = soundEditor.currentValue; + source->timeStretchAmount = this->value_; } } } // Or, the normal case of just one sound else { - soundEditor.currentSource->timeStretchAmount = soundEditor.currentValue; + soundEditor.currentSource->timeStretchAmount = this->value_; } } - int32_t getMinValue() const { return -48; } - int32_t getMaxValue() const { return 48; } - bool isRelevant(Sound* sound, int32_t whichThing) { + [[nodiscard]] int32_t getMinValue() const override { return -48; } + [[nodiscard]] int32_t getMaxValue() const override { return 48; } + bool isRelevant(Sound* sound, int32_t whichThing) override { Source* source = &sound->sources[whichThing]; return (sound->getSynthMode() == SynthMode::SUBTRACTIVE && source->oscType == OscType::SAMPLE); } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/sample/transpose.h b/src/deluge/gui/menu_item/sample/transpose.h index 2b9d98a76f..415556f458 100644 --- a/src/deluge/gui/menu_item/sample/transpose.h +++ b/src/deluge/gui/menu_item/sample/transpose.h @@ -15,39 +15,45 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/source/transpose.h" #include "processing/sound/sound.h" #include "storage/multi_range/multisample_range.h" -namespace menu_item::sample { -class Transpose final : public source::Transpose { +namespace deluge::gui::menu_item::sample { +class Transpose final : public source::Transpose, public FormattedTitle { public: - Transpose(char const* newName = NULL, int32_t newP = 0) : source::Transpose(newName, newP) {} - void readCurrentValue() { - int32_t transpose; - int32_t cents; - if (soundEditor.currentMultiRange && soundEditor.currentSound->getSynthMode() != SynthMode::FM + Transpose(const string& name, const string& title_format_str, int32_t newP) + : source::Transpose(name, newP), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + void readCurrentValue() override { + int32_t transpose = 0; + int32_t cents = 0; + if ((soundEditor.currentMultiRange != nullptr) && soundEditor.currentSound->getSynthMode() != SynthMode::FM && soundEditor.currentSource->oscType == OscType::SAMPLE) { - transpose = ((MultisampleRange*)soundEditor.currentMultiRange)->sampleHolder.transpose; - cents = ((MultisampleRange*)soundEditor.currentMultiRange)->sampleHolder.cents; + transpose = (static_cast(soundEditor.currentMultiRange))->sampleHolder.transpose; + cents = (static_cast(soundEditor.currentMultiRange))->sampleHolder.cents; } else { transpose = soundEditor.currentSource->transpose; cents = soundEditor.currentSource->cents; } - soundEditor.currentValue = transpose * 100 + cents; + this->value_ = transpose * 100 + cents; } - void writeCurrentValue() { - int32_t currentValue = soundEditor.currentValue + 25600; + + void writeCurrentValue() override { + int32_t currentValue = this->value_ + 25600; int32_t semitones = (currentValue + 50) / 100; int32_t cents = currentValue - semitones * 100; int32_t transpose = semitones - 256; - if (soundEditor.currentMultiRange && soundEditor.currentSound->getSynthMode() != SynthMode::FM + if ((soundEditor.currentMultiRange != nullptr) && soundEditor.currentSound->getSynthMode() != SynthMode::FM && soundEditor.currentSource->oscType == OscType::SAMPLE) { - ((MultisampleRange*)soundEditor.currentMultiRange)->sampleHolder.transpose = transpose; - ((MultisampleRange*)soundEditor.currentMultiRange)->sampleHolder.setCents(cents); + (static_cast(soundEditor.currentMultiRange))->sampleHolder.transpose = transpose; + (static_cast(soundEditor.currentMultiRange))->sampleHolder.setCents(cents); } else { soundEditor.currentSource->transpose = transpose; @@ -59,7 +65,9 @@ class Transpose final : public source::Transpose { soundEditor.currentSound->recalculateAllVoicePhaseIncrements(modelStack); } - MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, ::MultiRange** currentRange) { + + MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, + ::MultiRange** currentRange) override { if (!isRelevant(sound, whichThing)) { return MenuPermission::NO; @@ -68,11 +76,13 @@ class Transpose final : public source::Transpose { Source* source = &sound->sources[whichThing]; if (sound->getSynthMode() == SynthMode::FM - || (source->oscType != OscType::SAMPLE && source->oscType != OscType::WAVETABLE)) + || (source->oscType != OscType::SAMPLE && source->oscType != OscType::WAVETABLE)) { return MenuPermission::YES; + } return soundEditor.checkPermissionToBeginSessionForRangeSpecificParam(sound, whichThing, true, currentRange); } - bool isRangeDependent() { return true; } + + bool isRangeDependent() override { return true; } }; -} // namespace menu_item::sample +} // namespace deluge::gui::menu_item::sample diff --git a/src/deluge/gui/menu_item/selection.cpp b/src/deluge/gui/menu_item/selection.cpp deleted file mode 100644 index c002fc3910..0000000000 --- a/src/deluge/gui/menu_item/selection.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright © 2017-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ - -#include "selection.h" -#include "gui/ui/sound_editor.h" -#include "hid/display/numeric_driver.h" - -extern "C" { -#if HAVE_OLED -#include "RZA1/oled/oled_low_level.h" -#endif -} - -namespace menu_item { - -char const* onOffOptions[] = {"Off", "On", NULL}; - -Selection::Selection(char const* newName) : Value(newName) { - basicOptions = onOffOptions; -} - -void Selection::beginSession(MenuItem* navigatedBackwardFrom) { - Value::beginSession(navigatedBackwardFrom); -#if HAVE_OLED - soundEditor.menuCurrentScroll = 0; -#else - drawValue(); -#endif -} - -// Virtual - may be overriden. -char const** Selection::getOptions() { - return basicOptions; -} - -int32_t Selection::getNumOptions() { - int32_t i = 0; - while (basicOptions[i]) { - i++; - } - return i; -} - -void Selection::selectEncoderAction(int32_t offset) { - soundEditor.currentValue += offset; - int32_t numOptions = getNumOptions(); - -#if HAVE_OLED - if (soundEditor.currentValue > numOptions - 1) { - soundEditor.currentValue = numOptions - 1; - } - else if (soundEditor.currentValue < 0) { - soundEditor.currentValue = 0; - } -#else - if (soundEditor.currentValue >= numOptions) - soundEditor.currentValue -= numOptions; - else if (soundEditor.currentValue < 0) - soundEditor.currentValue += numOptions; -#endif - - Value::selectEncoderAction(offset); -} - -void Selection::drawValue() { -#if HAVE_OLED - renderUIsForOled(); -#else - numericDriver.setText(getOptions()[soundEditor.currentValue]); -#endif -} - -#if HAVE_OLED -void Selection::drawPixelsForOled() { - // Move scroll - if (soundEditor.menuCurrentScroll > soundEditor.currentValue) { - soundEditor.menuCurrentScroll = soundEditor.currentValue; - } - else if (soundEditor.menuCurrentScroll < soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1) { - soundEditor.menuCurrentScroll = soundEditor.currentValue - kOLEDMenuNumOptionsVisible + 1; - } - - char const** options = &getOptions()[soundEditor.menuCurrentScroll]; - int32_t selectedOption = soundEditor.currentValue - soundEditor.menuCurrentScroll; - - drawItemsForOled(options, selectedOption); -} -#endif -} // namespace menu_item diff --git a/src/deluge/gui/menu_item/selection.h b/src/deluge/gui/menu_item/selection.h deleted file mode 100644 index 70cb841cd3..0000000000 --- a/src/deluge/gui/menu_item/selection.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright © 2017-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ - -#pragma once - -#include "value.h" - -namespace menu_item { - -class Selection : public Value { -public: - Selection(char const* newName = NULL); - void beginSession(MenuItem* navigatedBackwardFrom); - void selectEncoderAction(int32_t offset); - - char const** basicOptions; - -protected: - virtual char const** getOptions(); - virtual int32_t getNumOptions(); - virtual void drawValue(); - -#if HAVE_OLED - void drawPixelsForOled(); -#endif -}; -} // namespace menu_item diff --git a/src/deluge/gui/menu_item/selection/selection.h b/src/deluge/gui/menu_item/selection/selection.h new file mode 100644 index 0000000000..5abe0d8a2e --- /dev/null +++ b/src/deluge/gui/menu_item/selection/selection.h @@ -0,0 +1,85 @@ +/* + * Copyright © 2017-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . +*/ + +#pragma once + +#include "gui/menu_item/enumeration/enumeration.h" +#include "gui/menu_item/menu_item.h" +#include "util/container/static_vector.hpp" +#include "util/sized.h" + +#include "gui/ui/sound_editor.h" +#include "hid/display/numeric_driver.h" +#include "hid/display/oled.h" + +extern "C" { +#if HAVE_OLED +#include "RZA1/oled/oled_low_level.h" +#endif +} + +namespace deluge::gui::menu_item { +template +class Selection : public Enumeration { +public: + using Enumeration::Enumeration; + + virtual static_vector getOptions() = 0; + + void drawValue() override; + +#if HAVE_OLED + void drawPixelsForOled() override; +#endif + size_t size() override { + return this->getOptions().size(); + } + constexpr static size_t capacity() { + return n; + } +}; + +template +void Selection::drawValue() { +#if HAVE_OLED + renderUIsForOled(); +#else + const auto options = getOptions(); + numericDriver.setText(options[this->value_].c_str()); +#endif +} + +#if HAVE_OLED + +template +void Selection::drawPixelsForOled() { + // Move scroll + if (soundEditor.menuCurrentScroll > this->value_) { + soundEditor.menuCurrentScroll = this->value_; + } + else if (soundEditor.menuCurrentScroll < this->value_ - kOLEDMenuNumOptionsVisible + 1) { + soundEditor.menuCurrentScroll = this->value_ - kOLEDMenuNumOptionsVisible + 1; + } + + const int32_t selectedOption = this->value_ - soundEditor.menuCurrentScroll; + + auto options = getOptions(); + MenuItem::drawItemsForOled(options, selectedOption, soundEditor.menuCurrentScroll); +} +#endif + +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/selection/typed_selection.h b/src/deluge/gui/menu_item/selection/typed_selection.h new file mode 100644 index 0000000000..11652df412 --- /dev/null +++ b/src/deluge/gui/menu_item/selection/typed_selection.h @@ -0,0 +1,88 @@ +/* + * Copyright © 2017-2023 Synthstrom Audible Limited + * + * This file is part of The Synthstrom Audible Deluge Firmware. + * + * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the + * terms of the GNU General Public License as published by the Free Software Foundation, + * either version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program. + * If not, see . +*/ + +#pragma once + +#include "gui/menu_item/enumeration/typed_enumeration.h" +#include "gui/menu_item/menu_item.h" +#include "util/container/static_vector.hpp" +#include "util/misc.h" +#include "util/sized.h" + +#include "gui/ui/sound_editor.h" +#include "hid/display/numeric_driver.h" +#include "hid/display/oled.h" + +extern "C" { +#if HAVE_OLED +#include "RZA1/oled/oled_low_level.h" +#endif +} + +namespace deluge::gui::menu_item { +template +class TypedSelection : public TypedEnumeration { +public: + using TypedEnumeration::TypedEnumeration; + + virtual static_vector getOptions() = 0; + + void drawValue() override; + +#if HAVE_OLED + void drawPixelsForOled() override; +#endif + size_t size() override { + return this->getOptions().size(); + } + constexpr static size_t capacity() { + return n; + } +}; + +template +void TypedSelection::drawValue() { +#if HAVE_OLED + renderUIsForOled(); +#else + const auto options = getOptions(); + auto idx = util::to_underlying(this->value_); + numericDriver.setText(options[idx].c_str()); +#endif +} + +#if HAVE_OLED + +template +void TypedSelection::drawPixelsForOled() { + auto current = util::to_underlying(this->value_); + // Move scroll + if (soundEditor.menuCurrentScroll > current) { + soundEditor.menuCurrentScroll = current; + } + else if (soundEditor.menuCurrentScroll < current - kOLEDMenuNumOptionsVisible + 1) { + soundEditor.menuCurrentScroll = current - kOLEDMenuNumOptionsVisible + 1; + } + + const int32_t selectedOption = current - soundEditor.menuCurrentScroll; + + auto options = getOptions(); + MenuItem::drawItemsForOled(options, selectedOption, soundEditor.menuCurrentScroll); +} +#endif + +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/sequence/direction.h b/src/deluge/gui/menu_item/sequence/direction.h index 0ae4a08119..86889b180a 100644 --- a/src/deluge/gui/menu_item/sequence/direction.h +++ b/src/deluge/gui/menu_item/sequence/direction.h @@ -16,7 +16,7 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "model/clip/instrument_clip.h" #include "model/drum/kit.h" @@ -25,77 +25,71 @@ #include "model/song/song.h" #include "util/misc.h" -namespace menu_item::sequence { -class Direction final : public Selection { +namespace deluge::gui::menu_item::sequence { +class Direction final : public TypedSelection { public: - using Selection::Selection; + using TypedSelection::TypedSelection; ModelStackWithNoteRow* getIndividualNoteRow(ModelStackWithTimelineCounter* modelStack) { - InstrumentClip* clip = (InstrumentClip*)modelStack->getTimelineCounter(); + auto* clip = static_cast(modelStack->getTimelineCounter()); if (!clip->affectEntire && clip->output->type == InstrumentType::KIT) { - Kit* kit = (Kit*)currentSong->currentClip->output; - if (kit->selectedDrum) { + Kit* kit = static_cast(currentSong->currentClip->output); + if (kit->selectedDrum != nullptr) { return clip->getNoteRowForDrum(modelStack, kit->selectedDrum); // Still might be NULL; } } - return modelStack->addNoteRow(0, NULL); + return modelStack->addNoteRow(0, nullptr); } - void readCurrentValue() { + void readCurrentValue() override { char modelStackMemory[MODEL_STACK_MAX_SIZE]; ModelStackWithTimelineCounter* modelStack = currentSong->setupModelStackWithCurrentClip(modelStackMemory); ModelStackWithNoteRow* modelStackWithNoteRow = getIndividualNoteRow(modelStack); - if (modelStackWithNoteRow->getNoteRowAllowNull()) { - soundEditor.currentValue = util::to_underlying(modelStackWithNoteRow->getNoteRow()->sequenceDirectionMode); + if (modelStackWithNoteRow->getNoteRowAllowNull() != nullptr) { + this->value_ = modelStackWithNoteRow->getNoteRow()->sequenceDirectionMode; } else { - soundEditor.currentValue = - util::to_underlying(((InstrumentClip*)currentSong->currentClip)->sequenceDirectionMode); + this->value_ = (static_cast(currentSong->currentClip))->sequenceDirectionMode; } } - void writeCurrentValue() { + void writeCurrentValue() override { char modelStackMemory[MODEL_STACK_MAX_SIZE]; ModelStackWithTimelineCounter* modelStack = currentSong->setupModelStackWithCurrentClip(modelStackMemory); ModelStackWithNoteRow* modelStackWithNoteRow = getIndividualNoteRow(modelStack); - if (modelStackWithNoteRow->getNoteRowAllowNull()) { - modelStackWithNoteRow->getNoteRow()->setSequenceDirectionMode( - modelStackWithNoteRow, static_cast(soundEditor.currentValue)); + if (modelStackWithNoteRow->getNoteRowAllowNull() != nullptr) { + modelStackWithNoteRow->getNoteRow()->setSequenceDirectionMode(modelStackWithNoteRow, + static_cast(this->value_)); } else { - ((InstrumentClip*)currentSong->currentClip) + (static_cast(currentSong->currentClip)) ->setSequenceDirectionMode(modelStackWithNoteRow->toWithTimelineCounter(), - static_cast(soundEditor.currentValue)); + static_cast(this->value_)); } } - int32_t getNumOptions() { - char modelStackMemory[MODEL_STACK_MAX_SIZE]; - ModelStackWithTimelineCounter* modelStack = currentSong->setupModelStackWithCurrentClip(modelStackMemory); - ModelStackWithNoteRow* modelStackWithNoteRow = getIndividualNoteRow(modelStack); - return modelStackWithNoteRow->getNoteRowAllowNull() ? 4 : 3; - } - - char const** getOptions() { - static char const* sequenceDirectionOptions[] = {"FORWARD", "REVERSED", "PING-PONG", NULL, NULL}; + static_vector getOptions() override { + static_vector sequenceDirectionOptions = {"FORWARD", "REVERSED", "PING-PONG"}; char modelStackMemory[MODEL_STACK_MAX_SIZE]; ModelStackWithTimelineCounter* modelStack = currentSong->setupModelStackWithCurrentClip(modelStackMemory); ModelStackWithNoteRow* modelStackWithNoteRow = getIndividualNoteRow(modelStack); - sequenceDirectionOptions[3] = modelStackWithNoteRow->getNoteRowAllowNull() ? "NONE" : NULL; + if (modelStackWithNoteRow->getNoteRowAllowNull() != nullptr) { + sequenceDirectionOptions.push_back("NONE"); + } + return sequenceDirectionOptions; } - MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, MultiRange** currentRange) { - if (!((InstrumentClip*)currentSong->currentClip)->affectEntire + MenuPermission checkPermissionToBeginSession(Sound* sound, int32_t whichThing, + ::MultiRange** currentRange) override { + if (!(static_cast(currentSong->currentClip))->affectEntire && currentSong->currentClip->output->type == InstrumentType::KIT - && !((Kit*)currentSong->currentClip->output)->selectedDrum) { + && ((static_cast(currentSong->currentClip->output))->selectedDrum == nullptr)) { return MenuPermission::NO; } - else { - return MenuPermission::YES; - } + return MenuPermission::YES; } }; -} // namespace menu_item::sequence +} // namespace deluge::gui::menu_item::sequence diff --git a/src/deluge/gui/menu_item/shortcuts/version.h b/src/deluge/gui/menu_item/shortcuts/version.h index 0e304b6903..b99fcab21e 100644 --- a/src/deluge/gui/menu_item/shortcuts/version.h +++ b/src/deluge/gui/menu_item/shortcuts/version.h @@ -15,30 +15,20 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/selection.h" #include "gui/ui/sound_editor.h" -namespace menu_item::shortcuts { -class Version final : public Selection { +namespace deluge::gui::menu_item::shortcuts { +class Version final : public Selection { public: using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = soundEditor.shortcutsVersion; } - void writeCurrentValue() { soundEditor.setShortcutsVersion(soundEditor.currentValue); } - char const** getOptions() { - static char const* options[] = { -#if HAVE_OLED - "1.0", - "3.0", - NULL -#else - " 1.0", - " 3.0" -#endif + void readCurrentValue() override { this->value_ = soundEditor.shortcutsVersion; } + void writeCurrentValue() override { soundEditor.setShortcutsVersion(this->value_); } + static_vector getOptions() override { + return { + HAVE_OLED ? "1.0" : " 1.0", //< + HAVE_OLED ? "3.0" : " 3.0", //< }; - return options; - } - int32_t getNumOptions() { - return NUM_SHORTCUTS_VERSIONS; } }; -} // namespace menu_item::shortcuts +} // namespace deluge::gui::menu_item::shortcuts diff --git a/src/deluge/gui/menu_item/sidechain/send.h b/src/deluge/gui/menu_item/sidechain/send.h index 1cb9da2c90..6a0506fcf7 100644 --- a/src/deluge/gui/menu_item/sidechain/send.h +++ b/src/deluge/gui/menu_item/sidechain/send.h @@ -19,22 +19,22 @@ #include "gui/ui/sound_editor.h" #include "processing/sound/sound.h" -namespace menu_item::sidechain { +namespace deluge::gui::menu_item::sidechain { class Send final : public Integer { public: using Integer::Integer; - void readCurrentValue() { - soundEditor.currentValue = ((uint64_t)soundEditor.currentSound->sideChainSendLevel * 50 + 1073741824) >> 31; + void readCurrentValue() override { + this->value_ = ((uint64_t)soundEditor.currentSound->sideChainSendLevel * 50 + 1073741824) >> 31; } - void writeCurrentValue() { - if (soundEditor.currentValue == 50) { + void writeCurrentValue() override { + if (this->value_ == 50) { soundEditor.currentSound->sideChainSendLevel = 2147483647; } else { - soundEditor.currentSound->sideChainSendLevel = soundEditor.currentValue * 42949673; + soundEditor.currentSound->sideChainSendLevel = this->value_ * 42949673; } } - int32_t getMaxValue() const { return 50; } - bool isRelevant(Sound* sound, int32_t whichThing) { return (soundEditor.editingKit()); } + [[nodiscard]] int32_t getMaxValue() const override { return 50; } + bool isRelevant(Sound* sound, int32_t whichThing) override { return (soundEditor.editingKit()); } }; -} // namespace menu_item::sidechain +} // namespace deluge::gui::menu_item::sidechain diff --git a/src/deluge/gui/menu_item/sidechain/sync.h b/src/deluge/gui/menu_item/sidechain/sync.h index e2435fc41d..446f264816 100644 --- a/src/deluge/gui/menu_item/sidechain/sync.h +++ b/src/deluge/gui/menu_item/sidechain/sync.h @@ -20,23 +20,23 @@ #include "processing/engines/audio_engine.h" #include "processing/sound/sound.h" -namespace menu_item::sidechain { +namespace deluge::gui::menu_item::sidechain { class Sync final : public SyncLevel { public: using SyncLevel::SyncLevel; - int32_t getNumOptions() override { return 10; }; + size_t size() override { return 10; }; void readCurrentValue() override { - soundEditor.currentValue = syncTypeAndLevelToMenuOption(soundEditor.currentCompressor->syncType, - soundEditor.currentCompressor->syncLevel); + this->value_ = syncTypeAndLevelToMenuOption(soundEditor.currentCompressor->syncType, + soundEditor.currentCompressor->syncLevel); } void writeCurrentValue() override { - soundEditor.currentCompressor->syncType = menuOptionToSyncType(soundEditor.currentValue); - soundEditor.currentCompressor->syncLevel = menuOptionToSyncLevel(soundEditor.currentValue); + soundEditor.currentCompressor->syncType = menuOptionToSyncType(this->value_); + soundEditor.currentCompressor->syncLevel = menuOptionToSyncLevel(this->value_); AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } bool isRelevant(Sound* sound, int32_t whichThing) override { - return !(soundEditor.editingReverbCompressor() && AudioEngine::reverbCompressorVolume < 0); + return !soundEditor.editingReverbCompressor() || AudioEngine::reverbCompressorVolume >= 0; } }; -} // namespace menu_item::sidechain +} // namespace deluge::gui::menu_item::sidechain diff --git a/src/deluge/gui/menu_item/source/patched_param.h b/src/deluge/gui/menu_item/source/patched_param.h index c33a059d8c..6b9c46fd74 100644 --- a/src/deluge/gui/menu_item/source/patched_param.h +++ b/src/deluge/gui/menu_item/source/patched_param.h @@ -18,10 +18,10 @@ #include "gui/menu_item/patched_param/integer.h" #include "gui/ui/sound_editor.h" -namespace menu_item::source { +namespace deluge::gui::menu_item::source { class PatchedParam : public menu_item::patched_param::Integer { public: using Integer::Integer; - uint8_t getP() { return menu_item::PatchedParam::getP() + soundEditor.currentSourceIndex; } + uint8_t getP() override { return menu_item::PatchedParam::getP() + soundEditor.currentSourceIndex; } }; -} // namespace menu_item::source +} // namespace deluge::gui::menu_item::source diff --git a/src/deluge/gui/menu_item/source/patched_param/fm.h b/src/deluge/gui/menu_item/source/patched_param/fm.h index f0e4990371..09be802523 100644 --- a/src/deluge/gui/menu_item/source/patched_param/fm.h +++ b/src/deluge/gui/menu_item/source/patched_param/fm.h @@ -15,13 +15,18 @@ * If not, see . */ #pragma once +#include "gui/menu_item/formatted_title.h" #include "gui/menu_item/source/patched_param.h" #include "processing/sound/sound.h" -namespace menu_item::source::patched_param { -class FM final : public source::PatchedParam { +namespace deluge::gui::menu_item::source::patched_param { +class FM final : public source::PatchedParam, public FormattedTitle { public: - using PatchedParam::PatchedParam; - bool isRelevant(Sound* sound, int32_t whichThing) { return (sound->getSynthMode() == SynthMode::FM); } + FM(const string& name, const string& title_format_str, int32_t newP) + : source::PatchedParam(name, newP), FormattedTitle(title_format_str) {} + + [[nodiscard]] const string& getTitle() const override { return FormattedTitle::title(); } + + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->getSynthMode() == SynthMode::FM); } }; -} // namespace menu_item::source::patched_param +} // namespace deluge::gui::menu_item::source::patched_param diff --git a/src/deluge/gui/menu_item/source/transpose.h b/src/deluge/gui/menu_item/source/transpose.h index 513c21794e..969de5ee50 100644 --- a/src/deluge/gui/menu_item/source/transpose.h +++ b/src/deluge/gui/menu_item/source/transpose.h @@ -19,13 +19,13 @@ #include "gui/menu_item/transpose.h" #include "gui/ui/sound_editor.h" -namespace menu_item::source { +namespace deluge::gui::menu_item::source { class Transpose : public menu_item::Transpose { public: - Transpose(char const* newName = NULL, int32_t newP = 0) : menu_item::Transpose(newName, newP) {} + using menu_item::Transpose::Transpose; ParamDescriptor getLearningThing() final { - ParamDescriptor paramDescriptor; + ParamDescriptor paramDescriptor{}; paramDescriptor.setToHaveParamOnly(getP()); return paramDescriptor; } @@ -33,4 +33,4 @@ class Transpose : public menu_item::Transpose { protected: uint8_t getP() final { return p + soundEditor.currentSourceIndex; } }; -} // namespace menu_item::source +} // namespace deluge::gui::menu_item::source diff --git a/src/deluge/gui/menu_item/source_selection.cpp b/src/deluge/gui/menu_item/source_selection.cpp index 57edd88d0c..16537b55e3 100644 --- a/src/deluge/gui/menu_item/source_selection.cpp +++ b/src/deluge/gui/menu_item/source_selection.cpp @@ -23,8 +23,9 @@ #include "modulation/patch/patch_cable_set.h" #include "patch_cable_strength.h" #include "processing/sound/sound.h" +#include -namespace menu_item { +namespace deluge::gui::menu_item { const PatchSource sourceMenuContents[] = { PatchSource::ENVELOPE_0, PatchSource::ENVELOPE_1, PatchSource::LFO_GLOBAL, PatchSource::LFO_LOCAL, PatchSource::VELOCITY, PatchSource::NOTE, PatchSource::COMPRESSOR, PatchSource::RANDOM, @@ -43,16 +44,12 @@ uint8_t SourceSelection::shouldDrawDotOnValue() { int32_t SourceSelection::selectedRowOnScreen; void SourceSelection::drawPixelsForOled() { - - char const* itemNames[kOLEDMenuNumOptionsVisible]; - for (int32_t i = 0; i < kOLEDMenuNumOptionsVisible; i++) { - itemNames[i] = NULL; - } + static_vector itemNames{}; selectedRowOnScreen = 0; int32_t thisOption = scrollPos; - int32_t i = 0; + size_t i = 0; while (i < kOLEDMenuNumOptionsVisible) { if (thisOption >= kNumPatchSources) { @@ -62,9 +59,9 @@ void SourceSelection::drawPixelsForOled() { const PatchSource sHere = sourceMenuContents[thisOption]; if (sourceIsAllowed(sHere)) { - itemNames[i] = getSourceDisplayNameForOLED(sHere); - if (thisOption == soundEditor.currentValue) { - selectedRowOnScreen = i; + itemNames.push_back(getSourceDisplayNameForOLED(sHere)); + if (thisOption == this->value_) { + selectedRowOnScreen = static_cast(i); } i++; } @@ -83,7 +80,7 @@ void SourceSelection::drawPixelsForOled() { void SourceSelection::drawValue() { char const* text; - switch (sourceMenuContents[soundEditor.currentValue]) { + switch (sourceMenuContents[this->value_]) { case PatchSource::LFO_GLOBAL: text = "LFO1"; break; @@ -137,18 +134,18 @@ void SourceSelection::drawValue() { #endif void SourceSelection::beginSession(MenuItem* navigatedBackwardFrom) { - soundEditor.currentValue = 0; + this->value_ = 0; if (navigatedBackwardFrom) { - while (sourceMenuContents[soundEditor.currentValue] != s) { - soundEditor.currentValue++; + while (sourceMenuContents[this->value_] != s) { + this->value_++; } // Scroll pos will be retained from before. } else { int32_t firstAllowedIndex = kNumPatchSources - 1; while (true) { - s = sourceMenuContents[soundEditor.currentValue]; + s = sourceMenuContents[this->value_]; // If patching already exists on this source, we use this as the initial one to show to the user if (soundEditor.currentParamManager->getPatchCableSet() @@ -157,21 +154,21 @@ void SourceSelection::beginSession(MenuItem* navigatedBackwardFrom) { } // Note down the first "allowed" or "editable" source - if (soundEditor.currentValue < firstAllowedIndex && sourceIsAllowed(s)) { - firstAllowedIndex = soundEditor.currentValue; + if (this->value_ < firstAllowedIndex && sourceIsAllowed(s)) { + firstAllowedIndex = this->value_; } - soundEditor.currentValue++; + this->value_++; #if HAVE_OLED - scrollPos = soundEditor.currentValue; + scrollPos = this->value_; #endif - if (soundEditor.currentValue >= kNumPatchSources) { - soundEditor.currentValue = firstAllowedIndex; + if (this->value_ >= kNumPatchSources) { + this->value_ = firstAllowedIndex; #if HAVE_OLED - scrollPos = soundEditor.currentValue; + scrollPos = this->value_; #endif - s = sourceMenuContents[soundEditor.currentValue]; + s = sourceMenuContents[this->value_]; break; } } @@ -192,7 +189,7 @@ void SourceSelection::readValueAgain() { void SourceSelection::selectEncoderAction(int32_t offset) { bool isAllowed; - int32_t newValue = soundEditor.currentValue; + int32_t newValue = this->value_; do { newValue += offset; @@ -210,11 +207,11 @@ void SourceSelection::selectEncoderAction(int32_t offset) { } while (!sourceIsAllowed(s)); - soundEditor.currentValue = newValue; + this->value_ = newValue; #if HAVE_OLED - if (soundEditor.currentValue < scrollPos) { - scrollPos = soundEditor.currentValue; + if (this->value_ < scrollPos) { + scrollPos = this->value_; } else if (offset >= 0 && selectedRowOnScreen == kOLEDMenuNumOptionsVisible - 1) { scrollPos++; @@ -275,4 +272,4 @@ uint8_t SourceSelection::shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_ : 255; } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/source_selection.h b/src/deluge/gui/menu_item/source_selection.h index ac74b17f9b..d9e6788e4e 100644 --- a/src/deluge/gui/menu_item/source_selection.h +++ b/src/deluge/gui/menu_item/source_selection.h @@ -17,15 +17,15 @@ #pragma once #include "definitions_cxx.hpp" -#include "menu_item.h" +#include "value.h" class ParamDescriptor; -namespace menu_item { -class SourceSelection : public MenuItem { +namespace deluge::gui::menu_item { +class SourceSelection : public Value { public: - SourceSelection() = default; - void beginSession(MenuItem* navigatedBackwardFrom = NULL); + using Value::Value; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override; void selectEncoderAction(int32_t offset) final; virtual ParamDescriptor getDestinationDescriptor() = 0; uint8_t getIndexOfPatchedParamToBlink() final; @@ -37,7 +37,7 @@ class SourceSelection : public MenuItem { static int32_t selectedRowOnScreen; int32_t scrollPos; // Each instance needs to store this separately #else - void drawValue(); + void drawValue() override; #endif PatchSource s; @@ -46,4 +46,4 @@ class SourceSelection : public MenuItem { bool sourceIsAllowed(PatchSource source); uint8_t shouldDrawDotOnValue(); }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/source_selection/range.cpp b/src/deluge/gui/menu_item/source_selection/range.cpp index 80db060e81..bb6725b0d1 100644 --- a/src/deluge/gui/menu_item/source_selection/range.cpp +++ b/src/deluge/gui/menu_item/source_selection/range.cpp @@ -20,17 +20,11 @@ #include "modulation/params/param_descriptor.h" #include "regular.h" -namespace menu_item::source_selection { +namespace deluge::gui::menu_item::source_selection { Range rangeMenu{}; -Range::Range() { -#if HAVE_OLED - basicTitle = "Modulate depth"; -#endif -} - ParamDescriptor Range::getDestinationDescriptor() { - ParamDescriptor descriptor; + ParamDescriptor descriptor{}; descriptor.setToHaveParamAndSource(soundEditor.patchingParamSelected, regularMenu.s); return descriptor; } @@ -39,8 +33,8 @@ MenuItem* Range::selectButtonPress() { return &patch_cable_strength::rangeMenu; } -MenuItem* Range::patchingSourceShortcutPress(int32_t newS, bool previousPressStillActive) { +MenuItem* Range::patchingSourceShortcutPress(PatchSource newS, bool previousPressStillActive) { return (MenuItem*)0xFFFFFFFF; } -} // namespace menu_item::source_selection +} // namespace deluge::gui::menu_item::source_selection diff --git a/src/deluge/gui/menu_item/source_selection/range.h b/src/deluge/gui/menu_item/source_selection/range.h index 355a588983..9508b83817 100644 --- a/src/deluge/gui/menu_item/source_selection/range.h +++ b/src/deluge/gui/menu_item/source_selection/range.h @@ -17,13 +17,18 @@ #pragma once #include "gui/menu_item/source_selection.h" -namespace menu_item::source_selection { +namespace deluge::gui::menu_item::source_selection { class Range final : public SourceSelection { public: - Range(); - ParamDescriptor getDestinationDescriptor(); - MenuItem* selectButtonPress(); - MenuItem* patchingSourceShortcutPress(int32_t newS, bool previousPressStillActive); + using SourceSelection::SourceSelection; + ParamDescriptor getDestinationDescriptor() override; + MenuItem* selectButtonPress() override; + MenuItem* patchingSourceShortcutPress(PatchSource newS, bool previousPressStillActive) override; +#if HAVE_OLED + const string& getTitle() const override { + return "Modulate depth"; + }; +#endif }; extern Range rangeMenu; -} // namespace menu_item::source_selection +} // namespace deluge::gui::menu_item::source_selection diff --git a/src/deluge/gui/menu_item/source_selection/regular.cpp b/src/deluge/gui/menu_item/source_selection/regular.cpp index 07e6cbd906..55bc497f8a 100644 --- a/src/deluge/gui/menu_item/source_selection/regular.cpp +++ b/src/deluge/gui/menu_item/source_selection/regular.cpp @@ -20,17 +20,11 @@ #include "gui/ui/sound_editor.h" #include "modulation/params/param_descriptor.h" -namespace menu_item::source_selection { +namespace deluge::gui::menu_item::source_selection { Regular regularMenu{}; -Regular::Regular() { -#if HAVE_OLED - basicTitle = "Modulate with"; -#endif -} - ParamDescriptor Regular::getDestinationDescriptor() { - ParamDescriptor descriptor; + ParamDescriptor descriptor{}; descriptor.setToHaveParamOnly(soundEditor.patchingParamSelected); return descriptor; } @@ -41,7 +35,7 @@ MenuItem* Regular::selectButtonPress() { void Regular::beginSession(MenuItem* navigatedBackwardFrom) { - if (navigatedBackwardFrom) { + if (navigatedBackwardFrom != nullptr) { if (soundEditor.patchingParamSelected == ::Param::Global::VOLUME_POST_REVERB_SEND || soundEditor.patchingParamSelected == ::Param::Local::VOLUME) { soundEditor.patchingParamSelected = ::Param::Global::VOLUME_POST_FX; @@ -56,4 +50,4 @@ MenuItem* Regular::patchingSourceShortcutPress(PatchSource newS, bool previousPr return ®ularMenu; } -} // namespace menu_item::source_selection +} // namespace deluge::gui::menu_item::source_selection diff --git a/src/deluge/gui/menu_item/source_selection/regular.h b/src/deluge/gui/menu_item/source_selection/regular.h index ea615d0962..6ff54ad3f0 100644 --- a/src/deluge/gui/menu_item/source_selection/regular.h +++ b/src/deluge/gui/menu_item/source_selection/regular.h @@ -18,15 +18,20 @@ #include "definitions_cxx.hpp" #include "gui/menu_item/source_selection.h" -namespace menu_item::source_selection { +namespace deluge::gui::menu_item::source_selection { class Regular final : public SourceSelection { public: - Regular(); - void beginSession(MenuItem* navigatedBackwardFrom = NULL); - ParamDescriptor getDestinationDescriptor(); - MenuItem* selectButtonPress(); + using SourceSelection::SourceSelection; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override; + ParamDescriptor getDestinationDescriptor() override; + MenuItem* selectButtonPress() override; MenuItem* patchingSourceShortcutPress(PatchSource newS, bool previousPressStillActive) override; +#if HAVE_OLED + const string& getTitle() const override { + return "Modulate with"; + }; +#endif }; extern Regular regularMenu; -} // namespace menu_item::source_selection +} // namespace deluge::gui::menu_item::source_selection diff --git a/src/deluge/gui/menu_item/submenu.cpp b/src/deluge/gui/menu_item/submenu.cpp deleted file mode 100644 index b981824fe5..0000000000 --- a/src/deluge/gui/menu_item/submenu.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright © 2017-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ - -#include "submenu.h" -#include "gui/ui/sound_editor.h" -#include "hid/display/numeric_driver.h" -#include "model/clip/instrument_clip.h" -#include "model/instrument/instrument.h" -#include "model/song/song.h" -#include "processing/engines/audio_engine.h" -#include "processing/sound/sound.h" -#include "processing/sound/sound_drum.h" - -extern "C" { -#if HAVE_OLED -#include "RZA1/oled/oled_low_level.h" -#endif -} - -namespace menu_item { - -void Submenu::beginSession(MenuItem* navigatedBackwardFrom) { - soundEditor.currentSubmenuItem = items; - soundEditor.menuCurrentScroll = 0; - soundEditor.currentMultiRange = NULL; - if (navigatedBackwardFrom) { - while (*soundEditor.currentSubmenuItem != navigatedBackwardFrom) { - if (!*soundEditor.currentSubmenuItem) { // If desired item not found - soundEditor.currentSubmenuItem = items; - break; - } - soundEditor.currentSubmenuItem++; - } - } - while (!(*soundEditor.currentSubmenuItem)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)) { - soundEditor.currentSubmenuItem++; - if (!*soundEditor.currentSubmenuItem) { // Not sure we need this since we don't wrap submenu items? - soundEditor.currentSubmenuItem = items; - } - } -#if !HAVE_OLED - updateDisplay(); -#endif -} - -void Submenu::updateDisplay() { -#if HAVE_OLED - renderUIsForOled(); -#else - (*soundEditor.currentSubmenuItem)->drawName(); -#endif -} - -#if HAVE_OLED -void Submenu::drawPixelsForOled() { - char const* itemNames[kOLEDMenuNumOptionsVisible]; - for (int32_t i = 0; i < kOLEDMenuNumOptionsVisible; i++) { - itemNames[i] = NULL; - } - - int32_t selectedRow = soundEditor.menuCurrentScroll; - itemNames[selectedRow] = (*soundEditor.currentSubmenuItem)->getName(); - - MenuItem** thisSubmenuItem = soundEditor.currentSubmenuItem; - for (int32_t i = selectedRow + 1; i < kOLEDMenuNumOptionsVisible; i++) { - do { - thisSubmenuItem++; - if (!*thisSubmenuItem) { - goto searchBack; - } - } while (!(*thisSubmenuItem)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)); - - itemNames[i] = (*thisSubmenuItem)->getName(); - } - -searchBack: - thisSubmenuItem = soundEditor.currentSubmenuItem; - for (int32_t i = selectedRow - 1; i >= 0; i--) { - do { - if (thisSubmenuItem == items) { - goto doneSearching; - } - thisSubmenuItem--; - } while (!(*thisSubmenuItem)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)); - - itemNames[i] = (*thisSubmenuItem)->getName(); - } - -doneSearching: - drawItemsForOled(itemNames, selectedRow); -} -#endif - -void Submenu::selectEncoderAction(int32_t offset) { - - MenuItem** thisSubmenuItem = soundEditor.currentSubmenuItem; - - do { - if (offset >= 0) { - thisSubmenuItem++; - if (!*thisSubmenuItem) { -#if HAVE_OLED - return; -#else - thisSubmenuItem = items; -#endif - } - } - else { - if (thisSubmenuItem == items) { -#if HAVE_OLED - return; -#else - while (*(thisSubmenuItem + 1)) { - thisSubmenuItem++; - } -#endif - } - else { - thisSubmenuItem--; - } - } - } while (!(*thisSubmenuItem)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)); - - soundEditor.currentSubmenuItem = thisSubmenuItem; - -#if HAVE_OLED - soundEditor.menuCurrentScroll += offset; - if (soundEditor.menuCurrentScroll < 0) { - soundEditor.menuCurrentScroll = 0; - } - else if (soundEditor.menuCurrentScroll > kOLEDMenuNumOptionsVisible - 1) { - soundEditor.menuCurrentScroll = kOLEDMenuNumOptionsVisible - 1; - } -#endif - - updateDisplay(); -} - -MenuItem* Submenu::selectButtonPress() { - return *soundEditor.currentSubmenuItem; -} - -void Submenu::unlearnAction() { - if (soundEditor.getCurrentMenuItem() == this) { - (*soundEditor.currentSubmenuItem)->unlearnAction(); - } -} - -bool Submenu::allowsLearnMode() { - if (soundEditor.getCurrentMenuItem() == this) { - return (*soundEditor.currentSubmenuItem)->allowsLearnMode(); - } - return false; -} - -void Submenu::learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) { - if (soundEditor.getCurrentMenuItem() == this) { - (*soundEditor.currentSubmenuItem)->learnKnob(fromDevice, whichKnob, modKnobMode, midiChannel); - } -} - -bool Submenu::learnNoteOn(MIDIDevice* fromDevice, int32_t channel, int32_t noteCode) { - if (soundEditor.getCurrentMenuItem() == this) { - return (*soundEditor.currentSubmenuItem)->learnNoteOn(fromDevice, channel, noteCode); - } - return false; -} -} // namespace menu_item diff --git a/src/deluge/gui/menu_item/submenu.h b/src/deluge/gui/menu_item/submenu.h index 9626c46f0c..8edc6b3547 100644 --- a/src/deluge/gui/menu_item/submenu.h +++ b/src/deluge/gui/menu_item/submenu.h @@ -17,14 +17,40 @@ #pragma once +#include "definitions.h" +#include "gui/menu_item/menu_item.h" +#include "gui/ui/sound_editor.h" +#include "hid/display/numeric_driver.h" #include "menu_item.h" +#include "model/clip/instrument_clip.h" +#include "model/instrument/instrument.h" +#include "model/song/song.h" +#include "processing/engines/audio_engine.h" +#include "processing/sound/sound.h" +#include "processing/sound/sound_drum.h" +#include "util/container/static_vector.hpp" +#include +#include -namespace menu_item { +extern "C" { +#if HAVE_OLED +#include "RZA1/oled/oled_low_level.h" +#endif +} +namespace deluge::gui::menu_item { + +template class Submenu : public MenuItem { public: - Submenu(char const* newName = NULL, MenuItem** newItems = NULL) : MenuItem(newName) { items = newItems; } - void beginSession(MenuItem* navigatedBackwardFrom = NULL); + Submenu(const string& newName, MenuItem* const (&newItems)[n]) + : MenuItem(newName), items{to_static_vector(newItems)} {} + Submenu(const string& newName, const string& title, MenuItem* const (&newItems)[n]) + : MenuItem(newName, title), items{to_static_vector(newItems)} {} + Submenu(const string& newName, const string& title, std::array newItems) + : MenuItem(newName, title), items{newItems.begin(), newItems.end()} {} + + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override; void updateDisplay(); void selectEncoderAction(int32_t offset) final; MenuItem* selectButtonPress() final; @@ -33,9 +59,160 @@ class Submenu : public MenuItem { bool allowsLearnMode() final; void learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) final; bool learnNoteOn(MIDIDevice* fromDevice, int32_t channel, int32_t noteCode) final; - void drawPixelsForOled(); +#if HAVE_OLED + void drawPixelsForOled() override; +#endif - MenuItem** items; + deluge::static_vector items; + typename decltype(items)::iterator current_item_; }; -} // namespace menu_item +template +void Submenu::beginSession(MenuItem* navigatedBackwardFrom) { + current_item_ = items.begin(); + soundEditor.menuCurrentScroll = 0; + soundEditor.currentMultiRange = nullptr; + if (navigatedBackwardFrom != nullptr) { + for (; *current_item_ != navigatedBackwardFrom; current_item_++) { + if (current_item_ == items.end()) { // If desired item not found + current_item_ = items.begin(); + break; + } + } + } + while (!(*current_item_)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)) { + current_item_++; + if (current_item_ == items.end()) { // Not sure we need this since we don't wrap submenu items? + current_item_ = items.begin(); + } + } +#if !HAVE_OLED + updateDisplay(); +#endif +} + +template +void Submenu::updateDisplay() { +#if HAVE_OLED + renderUIsForOled(); +#else + (*current_item_)->drawName(); +#endif +} + +#if HAVE_OLED + +template +void Submenu::drawPixelsForOled() { + int32_t selectedRow = soundEditor.menuCurrentScroll; + + // This finds the next relevant submenu item + static_vector nextItemNames = {}; + for (auto it = current_item_, idx = selectedRow; it != this->items.end() && idx < kOLEDMenuNumOptionsVisible; + it++) { + if ((*it)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)) { + nextItemNames.push_back((*it)->getName()); + idx++; + } + } + + static_vector prevItemNames = {}; + for (auto it = current_item_ - 1, idx = selectedRow - 1; it != this->items.begin() - 1 && idx >= 0; it--) { + if ((*it)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)) { + prevItemNames.push_back((*it)->getName()); + idx--; + } + } + std::reverse(prevItemNames.begin(), prevItemNames.end()); + + if (!prevItemNames.empty()) { + prevItemNames.insert(prevItemNames.end(), nextItemNames.begin(), nextItemNames.end()); + drawItemsForOled(prevItemNames, selectedRow); + } + else { + drawItemsForOled(nextItemNames, selectedRow); + } +} +#endif + +template +void Submenu::selectEncoderAction(int32_t offset) { + + auto thisSubmenuItem = current_item_; + + do { + if (offset >= 0) { + thisSubmenuItem++; + if (thisSubmenuItem == items.end()) { +#if HAVE_OLED + return; +#else + thisSubmenuItem = items.begin(); +#endif + } + } + else { + if (thisSubmenuItem == items.begin()) { +#if HAVE_OLED + return; +#else + thisSubmenuItem = &items.back(); +#endif + } + else { + thisSubmenuItem--; + } + } + } while (!(*thisSubmenuItem)->isRelevant(soundEditor.currentSound, soundEditor.currentSourceIndex)); + + current_item_ = thisSubmenuItem; + +#if HAVE_OLED + soundEditor.menuCurrentScroll += offset; + if (soundEditor.menuCurrentScroll < 0) { + soundEditor.menuCurrentScroll = 0; + } + else if (soundEditor.menuCurrentScroll > kOLEDMenuNumOptionsVisible - 1) { + soundEditor.menuCurrentScroll = kOLEDMenuNumOptionsVisible - 1; + } +#endif + + updateDisplay(); +} + +template +MenuItem* Submenu::selectButtonPress() { + return *current_item_; +} + +template +void Submenu::unlearnAction() { + if (soundEditor.getCurrentMenuItem() == this) { + (*current_item_)->unlearnAction(); + } +} + +template +bool Submenu::allowsLearnMode() { + if (soundEditor.getCurrentMenuItem() == this) { + return (*current_item_)->allowsLearnMode(); + } + return false; +} + +template +void Submenu::learnKnob(MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) { + if (soundEditor.getCurrentMenuItem() == this) { + (*current_item_)->learnKnob(fromDevice, whichKnob, modKnobMode, midiChannel); + } +} + +template +bool Submenu::learnNoteOn(MIDIDevice* fromDevice, int32_t channel, int32_t noteCode) { + if (soundEditor.getCurrentMenuItem() == this) { + return (*current_item_)->learnNoteOn(fromDevice, channel, noteCode); + } + return false; +} + +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/submenu/actual_source.h b/src/deluge/gui/menu_item/submenu/actual_source.h index e0731fce5f..b27025cb24 100644 --- a/src/deluge/gui/menu_item/submenu/actual_source.h +++ b/src/deluge/gui/menu_item/submenu/actual_source.h @@ -24,30 +24,33 @@ extern void setOscillatorNumberForTitles(int32_t); -namespace menu_item::submenu { - -class ActualSource final : public SubmenuReferringToOneThing { +namespace deluge::gui::menu_item::submenu { +template +class ActualSource final : public SubmenuReferringToOneThing { public: - ActualSource(char const* newName = 0, MenuItem** newItems = 0, int32_t newSourceIndex = 0) - : SubmenuReferringToOneThing(newName, newItems, newSourceIndex) {} + using SubmenuReferringToOneThing::SubmenuReferringToOneThing; #if HAVE_OLED void beginSession(MenuItem* navigatedBackwardFrom) { - setOscillatorNumberForTitles(thingIndex); - SubmenuReferringToOneThing::beginSession(navigatedBackwardFrom); + setOscillatorNumberForTitles(this->thingIndex); + SubmenuReferringToOneThing::beginSession(navigatedBackwardFrom); } #else - void drawName() { + void drawName() override { if (soundEditor.currentSound->getSynthMode() == SynthMode::FM) { char buffer[5]; strcpy(buffer, "CAR"); - intToString(thingIndex + 1, buffer + 3); + intToString(this->thingIndex + 1, buffer + 3); numericDriver.setText(buffer); } else { - SubmenuReferringToOneThing::drawName(); + SubmenuReferringToOneThing::drawName(); } } #endif }; -} // namespace menu_item::submenu +// Template deduction guide, will not be required with P2582@C++23 +template +ActualSource(const string&, MenuItem* const (&)[n], int32_t) -> ActualSource; + +} // namespace deluge::gui::menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/arpeggiator.cpp b/src/deluge/gui/menu_item/submenu/arpeggiator.cpp deleted file mode 100644 index 4e3d9c4502..0000000000 --- a/src/deluge/gui/menu_item/submenu/arpeggiator.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (c) 2014-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ -#include "arpeggiator.h" -#include "gui/ui/sound_editor.h" -#include "model/clip/instrument_clip.h" -#include "model/song/song.h" -#include "processing/sound/sound_drum.h" - -namespace menu_item::submenu { - -void Arpeggiator::beginSession(MenuItem* navigatedBackwardFrom) { - - soundEditor.currentArpSettings = soundEditor.editingKit() - ? &((SoundDrum*)soundEditor.currentSound)->arpSettings - : &((InstrumentClip*)currentSong->currentClip)->arpSettings; - Submenu::beginSession(navigatedBackwardFrom); -} - -} // namespace menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/arpeggiator.h b/src/deluge/gui/menu_item/submenu/arpeggiator.h index e597e5b976..a982d1e1e9 100644 --- a/src/deluge/gui/menu_item/submenu/arpeggiator.h +++ b/src/deluge/gui/menu_item/submenu/arpeggiator.h @@ -16,13 +16,28 @@ */ #pragma once #include "gui/menu_item/submenu.h" +#include "gui/ui/sound_editor.h" +#include "model/clip/instrument_clip.h" +#include "model/song/song.h" +#include "modulation/arpeggiator.h" +#include "processing/sound/sound_drum.h" -namespace menu_item::submenu { +namespace deluge::gui::menu_item::submenu { -class Arpeggiator final : public Submenu { +template +class Arpeggiator final : public Submenu { public: - Arpeggiator() {} - Arpeggiator(char const* newName, MenuItem** newItems) : Submenu(newName, newItems) {} - void beginSession(MenuItem* navigatedBackwardFrom = NULL); + using Submenu::Submenu; + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override { + + soundEditor.currentArpSettings = soundEditor.editingKit() + ? &(static_cast(soundEditor.currentSound))->arpSettings + : &(static_cast(currentSong->currentClip))->arpSettings; + Submenu::beginSession(navigatedBackwardFrom); + } }; -} // namespace menu_item::submenu + +// Template deduction guide, will not be required with P2582@C++23 +template +Arpeggiator(const string&, MenuItem* const (&)[n]) -> Arpeggiator; +} // namespace deluge::gui::menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/bend.h b/src/deluge/gui/menu_item/submenu/bend.h index cad7aa74f5..d19071e6e1 100644 --- a/src/deluge/gui/menu_item/submenu/bend.h +++ b/src/deluge/gui/menu_item/submenu/bend.h @@ -20,14 +20,20 @@ #include "model/output.h" #include "model/song/song.h" -namespace menu_item::submenu { -class Bend final : public Submenu { +namespace deluge::gui::menu_item::submenu { +template +class Bend final : public Submenu { public: - Bend(char const* newName = nullptr, MenuItem** newItems = nullptr) : Submenu(newName, newItems) {} + using Submenu::Submenu; bool isRelevant(Sound* sound, int32_t whichThing) override { // Drums within a Kit don't need the two-item submenu - they have their own single item. const auto type = currentSong->currentClip->output->type; return (type == InstrumentType::SYNTH || type == InstrumentType::CV); } }; -} // namespace menu_item::submenu + +// Template deduction guide, will not be required with P2582@C++23 +template +Bend(const string&, MenuItem* const (&)[n]) -> Bend; + +} // namespace deluge::gui::menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/compressor.cpp b/src/deluge/gui/menu_item/submenu/compressor.cpp deleted file mode 100644 index 965127d66e..0000000000 --- a/src/deluge/gui/menu_item/submenu/compressor.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (c) 2014-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ -#include "compressor.h" -#include "gui/ui/sound_editor.h" -#include "processing/engines/audio_engine.h" -#include "processing/sound/sound.h" - -namespace menu_item::submenu { -void Compressor::beginSession(MenuItem* navigatedBackwardFrom) { - soundEditor.currentCompressor = - forReverbCompressor ? &AudioEngine::reverbCompressor : &soundEditor.currentSound->compressor; - Submenu::beginSession(navigatedBackwardFrom); -} -} // namespace menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/compressor.h b/src/deluge/gui/menu_item/submenu/compressor.h index fbeec47a6b..38b74186d6 100644 --- a/src/deluge/gui/menu_item/submenu/compressor.h +++ b/src/deluge/gui/menu_item/submenu/compressor.h @@ -16,17 +16,26 @@ */ #pragma once #include "gui/menu_item/submenu.h" +#include "gui/ui/sound_editor.h" +#include "processing/engines/audio_engine.h" +#include "processing/sound/sound.h" -namespace menu_item::submenu { - -class Compressor final : public Submenu { +namespace deluge::gui::menu_item::submenu { +template +class Compressor final : public Submenu { public: - Compressor() {} - Compressor(char const* newName, MenuItem** newItems, bool newForReverbCompressor) : Submenu(newName, newItems) { - forReverbCompressor = newForReverbCompressor; + Compressor(const string& newName, const string& title, MenuItem* const (&newItems)[n], bool newForReverbCompressor) + : Submenu(newName, title, newItems), forReverbCompressor(newForReverbCompressor) {} + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override { + soundEditor.currentCompressor = + forReverbCompressor ? &AudioEngine::reverbCompressor : &soundEditor.currentSound->compressor; + Submenu::beginSession(navigatedBackwardFrom); } - void beginSession(MenuItem* navigatedBackwardFrom = NULL); bool forReverbCompressor; }; -} // namespace menu_item::submenu +// Template deduction guide, will not be required with P2582@C++23 +template +Compressor(const string&, MenuItem* const (&)[n]) -> Compressor; + +} // namespace deluge::gui::menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/envelope.h b/src/deluge/gui/menu_item/submenu/envelope.h index fbc0b1d7a5..f7ebe2ab8a 100644 --- a/src/deluge/gui/menu_item/submenu/envelope.h +++ b/src/deluge/gui/menu_item/submenu/envelope.h @@ -15,19 +15,25 @@ * If not, see . */ #pragma once -#include "gui/menu_item/submenu.h" +#include "gui/menu_item/submenu_referring_to_one_thing.h" extern void setEnvelopeNumberForTitles(int32_t); -namespace menu_item::submenu { -class Envelope final : public SubmenuReferringToOneThing { +namespace deluge::gui::menu_item::submenu { +template +class Envelope final : public SubmenuReferringToOneThing { public: - using SubmenuReferringToOneThing::SubmenuReferringToOneThing; + using SubmenuReferringToOneThing::SubmenuReferringToOneThing; #if HAVE_OLED - void beginSession(MenuItem* navigatedBackwardFrom = NULL) { - SubmenuReferringToOneThing::beginSession(navigatedBackwardFrom); - setEnvelopeNumberForTitles(thingIndex); + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) { + SubmenuReferringToOneThing::beginSession(navigatedBackwardFrom); + setEnvelopeNumberForTitles(this->thingIndex); } #endif }; -} // namespace menu_item::submenu + +// Template deduction guide, will not be required with P2582@C++23 +template +Envelope(const string&, MenuItem* const (&)[n], int32_t) -> Envelope; + +} // namespace deluge::gui::menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/filter.h b/src/deluge/gui/menu_item/submenu/filter.h index 555a795804..6d4359d5ab 100644 --- a/src/deluge/gui/menu_item/submenu/filter.h +++ b/src/deluge/gui/menu_item/submenu/filter.h @@ -18,10 +18,16 @@ #include "gui/menu_item/submenu.h" #include "processing/sound/sound.h" -namespace menu_item::submenu { -class Filter final : public Submenu { +namespace deluge::gui::menu_item::submenu { +template +class Filter final : public Submenu { public: - Filter(char const* newName = NULL, MenuItem** newFirstItem = NULL) : Submenu(newName, newFirstItem) {} - bool isRelevant(Sound* sound, int32_t whichThing) { return (sound->synthMode != SynthMode::FM); } + using Submenu::Submenu; + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->synthMode != SynthMode::FM); } }; -} // namespace menu_item::submenu + +// Template deduction guide, will not be required with P2582@C++23 +template +Filter(const string&, MenuItem* const (&)[n]) -> Filter; + +} // namespace deluge::gui::menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu/modulator.h b/src/deluge/gui/menu_item/submenu/modulator.h index d2a86755ae..ba6f96b4e5 100644 --- a/src/deluge/gui/menu_item/submenu/modulator.h +++ b/src/deluge/gui/menu_item/submenu/modulator.h @@ -20,14 +20,15 @@ extern void setModulatorNumberForTitles(int32_t); -namespace menu_item::submenu { -class Modulator final : public SubmenuReferringToOneThing { +namespace deluge::gui::menu_item::submenu { +template +class Modulator final : public SubmenuReferringToOneThing { public: - using SubmenuReferringToOneThing::SubmenuReferringToOneThing; + using SubmenuReferringToOneThing::SubmenuReferringToOneThing; #if HAVE_OLED void beginSession(MenuItem* navigatedBackwardFrom) { - setModulatorNumberForTitles(thingIndex); - SubmenuReferringToOneThing::beginSession(navigatedBackwardFrom); + setModulatorNumberForTitles(this->thingIndex); + SubmenuReferringToOneThing::beginSession(navigatedBackwardFrom); } #endif bool isRelevant(Sound* sound, int32_t whichThing) { @@ -35,4 +36,8 @@ class Modulator final : public SubmenuReferringToOneThing { } }; -} // namespace menu_item::submenu +// Template deduction guide, will not be required with P2582@C++23 +template +Modulator(const string&, MenuItem* const (&)[n], int32_t) -> Modulator; + +} // namespace deluge::gui::menu_item::submenu diff --git a/src/deluge/gui/menu_item/submenu_referring_to_one_thing.cpp b/src/deluge/gui/menu_item/submenu_referring_to_one_thing.cpp deleted file mode 100644 index c9991b2ac4..0000000000 --- a/src/deluge/gui/menu_item/submenu_referring_to_one_thing.cpp +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2014-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ -#include "submenu_referring_to_one_thing.h" -#include "gui/ui/sound_editor.h" -#include "processing/sound/sound.h" - -namespace menu_item { -void SubmenuReferringToOneThing::beginSession(MenuItem* navigatedBackwardFrom) { - soundEditor.currentSourceIndex = thingIndex; - soundEditor.currentSource = &soundEditor.currentSound->sources[thingIndex]; - soundEditor.currentSampleControls = &soundEditor.currentSource->sampleControls; - Submenu::beginSession(navigatedBackwardFrom); -} - -} // namespace menu_item diff --git a/src/deluge/gui/menu_item/submenu_referring_to_one_thing.h b/src/deluge/gui/menu_item/submenu_referring_to_one_thing.h index c94d92cdc5..330cc29b19 100644 --- a/src/deluge/gui/menu_item/submenu_referring_to_one_thing.h +++ b/src/deluge/gui/menu_item/submenu_referring_to_one_thing.h @@ -15,19 +15,24 @@ * If not, see . */ #pragma once +#include "gui/ui/sound_editor.h" +#include "processing/sound/sound.h" #include "submenu.h" -namespace menu_item { - -class SubmenuReferringToOneThing : public Submenu { +namespace deluge::gui::menu_item { +template +class SubmenuReferringToOneThing : public Submenu { public: - SubmenuReferringToOneThing() {} - SubmenuReferringToOneThing(char const* newName, MenuItem** newItems, int32_t newThingIndex) - : Submenu(newName, newItems) { - thingIndex = newThingIndex; + SubmenuReferringToOneThing(const string& newName, MenuItem* const (&newItems)[n], int32_t newThingIndex) + : Submenu(newName, newItems), thingIndex(newThingIndex) {} + + void beginSession(MenuItem* navigatedBackwardFrom = nullptr) override { + soundEditor.currentSourceIndex = thingIndex; + soundEditor.currentSource = &soundEditor.currentSound->sources[thingIndex]; + soundEditor.currentSampleControls = &soundEditor.currentSource->sampleControls; + Submenu::beginSession(navigatedBackwardFrom); } - void beginSession(MenuItem* navigatedBackwardFrom = NULL); uint8_t thingIndex; }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/swing/interval.h b/src/deluge/gui/menu_item/swing/interval.h index da67230ee6..c31bc52f3c 100644 --- a/src/deluge/gui/menu_item/swing/interval.h +++ b/src/deluge/gui/menu_item/swing/interval.h @@ -19,29 +19,29 @@ #include "gui/ui/sound_editor.h" #include "model/song/song.h" -namespace menu_item::swing { +namespace deluge::gui::menu_item::swing { class Interval final : public SyncLevel { public: using SyncLevel::SyncLevel; - void readCurrentValue() { soundEditor.currentValue = currentSong->swingInterval; } - void writeCurrentValue() { currentSong->changeSwingInterval(soundEditor.currentValue); } + void readCurrentValue() override { this->value_ = currentSong->swingInterval; } + void writeCurrentValue() override { currentSong->changeSwingInterval(this->value_); } - void selectEncoderAction(int32_t offset) { // So that there's no "off" option - soundEditor.currentValue += offset; - int32_t numOptions = getNumOptions(); + void selectEncoderAction(int32_t offset) override { // So that there's no "off" option + this->value_ += offset; + int32_t numOptions = this->size(); // Wrap value - if (soundEditor.currentValue >= numOptions) { - soundEditor.currentValue -= (numOptions - 1); + if (this->value_ >= numOptions) { + this->value_ -= (numOptions - 1); } - else if (soundEditor.currentValue < 1) { - soundEditor.currentValue += (numOptions - 1); + else if (this->value_ < 1) { + this->value_ += (numOptions - 1); } Value::selectEncoderAction(offset); } }; -} // namespace menu_item::swing +} // namespace deluge::gui::menu_item::swing diff --git a/src/deluge/gui/menu_item/sync_level.cpp b/src/deluge/gui/menu_item/sync_level.cpp index e048e5bb55..c1bbe64ec7 100644 --- a/src/deluge/gui/menu_item/sync_level.cpp +++ b/src/deluge/gui/menu_item/sync_level.cpp @@ -21,10 +21,10 @@ #include "hid/display/oled.h" #include "model/song/song.h" -namespace menu_item { +namespace deluge::gui::menu_item { void SyncLevel::drawValue() { - if (soundEditor.currentValue == 0) { + if (this->value_ == 0) { numericDriver.setText("OFF"); } else { @@ -41,17 +41,17 @@ void SyncLevel::drawValue() { void SyncLevel::getNoteLengthName(char* buffer) { char type[7] = ""; - if (soundEditor.currentValue < SYNC_TYPE_TRIPLET) { - currentSong->getNoteLengthName(buffer, (uint32_t)3 << (SYNC_LEVEL_256TH - soundEditor.currentValue)); + if (this->value_ < SYNC_TYPE_TRIPLET) { + currentSong->getNoteLengthName(buffer, (uint32_t)3 << (SYNC_LEVEL_256TH - this->value_)); } - else if (soundEditor.currentValue < SYNC_TYPE_DOTTED) { - currentSong->getNoteLengthName( - buffer, (uint32_t)3 << ((SYNC_TYPE_TRIPLET - 1) + SYNC_LEVEL_256TH - soundEditor.currentValue)); + else if (this->value_ < SYNC_TYPE_DOTTED) { + currentSong->getNoteLengthName(buffer, + (uint32_t)3 << ((SYNC_TYPE_TRIPLET - 1) + SYNC_LEVEL_256TH - this->value_)); strcpy(type, "-tplts"); } else { - currentSong->getNoteLengthName( - buffer, (uint32_t)3 << ((SYNC_TYPE_DOTTED - 1) + SYNC_LEVEL_256TH - soundEditor.currentValue)); + currentSong->getNoteLengthName(buffer, + (uint32_t)3 << ((SYNC_TYPE_DOTTED - 1) + SYNC_LEVEL_256TH - this->value_)); strcpy(type, "-dtted"); } if (strlen(type) > 0) { @@ -73,7 +73,7 @@ void SyncLevel::getNoteLengthName(char* buffer) { void SyncLevel::drawPixelsForOled() { char const* text = "Off"; char buffer[30]; - if (soundEditor.currentValue) { + if (this->value_) { text = buffer; getNoteLengthName(buffer); } @@ -111,4 +111,4 @@ ::SyncLevel SyncLevel::menuOptionToSyncLevel(int32_t option) { int32_t SyncLevel::syncTypeAndLevelToMenuOption(::SyncType type, ::SyncLevel level) { return static_cast(type) + (static_cast(level) - (type != SYNC_TYPE_EVEN ? 1 : 0)); } -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/sync_level.h b/src/deluge/gui/menu_item/sync_level.h index 9dd647ac41..bc7b9ed26d 100644 --- a/src/deluge/gui/menu_item/sync_level.h +++ b/src/deluge/gui/menu_item/sync_level.h @@ -17,25 +17,25 @@ #pragma once -#include "selection.h" +#include "gui/menu_item/enumeration/enumeration.h" +#include "gui/menu_item/selection/selection.h" -namespace menu_item { +namespace deluge::gui::menu_item { // This one is "absolute" - if song's insideWorldTickMagnitude changes, such a param's text value will display as a different one, but the music will sound the same -class SyncLevel : public Selection { +class SyncLevel : public Enumeration<28> { public: - using Selection::Selection; + using Enumeration::Enumeration; SyncType menuOptionToSyncType(int32_t option); ::SyncLevel menuOptionToSyncLevel(int32_t option); int32_t syncTypeAndLevelToMenuOption(SyncType type, ::SyncLevel level); protected: - int32_t getNumOptions() { return 28; } void drawValue() final; virtual void getNoteLengthName(char* buffer); #if HAVE_OLED - void drawPixelsForOled(); + void drawPixelsForOled() override; #endif }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/sync_level/relative_to_song.h b/src/deluge/gui/menu_item/sync_level/relative_to_song.h index e767697870..7e29d41685 100644 --- a/src/deluge/gui/menu_item/sync_level/relative_to_song.h +++ b/src/deluge/gui/menu_item/sync_level/relative_to_song.h @@ -19,7 +19,7 @@ #include "gui/ui/sound_editor.h" #include "model/song/song.h" -namespace menu_item::sync_level { +namespace deluge::gui::menu_item::sync_level { // This one is "relative to the song". In that it'll show its text value to the user, e.g. "16ths", regardless of any song variables, and // then when its value gets used for anything, it'll be transposed into the song's magnitude by adding / subtracting the song's insideWorldTickMagnitude @@ -28,8 +28,6 @@ class RelativeToSong : public SyncLevel { using SyncLevel::SyncLevel; protected: - void getNoteLengthName(char* buffer) final { - getNoteLengthNameFromMagnitude(buffer, -6 + 9 - soundEditor.currentValue); - } + void getNoteLengthName(char* buffer) final { getNoteLengthNameFromMagnitude(buffer, -6 + 9 - this->value_); } }; -} // namespace menu_item::sync_level +} // namespace deluge::gui::menu_item::sync_level diff --git a/src/deluge/gui/menu_item/synth_mode.h b/src/deluge/gui/menu_item/synth_mode.h index faa6f8fc66..6572d80045 100644 --- a/src/deluge/gui/menu_item/synth_mode.h +++ b/src/deluge/gui/menu_item/synth_mode.h @@ -15,30 +15,29 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "definitions_cxx.hpp" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "gui/views/view.h" #include "model/song/song.h" #include "processing/sound/sound.h" #include "util/misc.h" -namespace menu_item { -class SynthMode final : public Selection { +namespace deluge::gui::menu_item { +class SynthMode final : public TypedSelection<::SynthMode, kNumSynthModes> { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(soundEditor.currentSound->synthMode); } - void writeCurrentValue() { - soundEditor.currentSound->setSynthMode(static_cast<::SynthMode>(soundEditor.currentValue), currentSong); + using TypedSelection::TypedSelection; + void readCurrentValue() override { this->value_ = soundEditor.currentSound->synthMode; } + void writeCurrentValue() override { + soundEditor.currentSound->setSynthMode(this->value_, currentSong); view.setKnobIndicatorLevels(); } - char const** getOptions() { - static char const* options[] = {"Subtractive", "FM", "Ringmod", NULL}; - return options; - } - int32_t getNumOptions() { return 3; } - bool isRelevant(Sound* sound, int32_t whichThing) { + + static_vector getOptions() override { return {"Subtractive", "FM", "Ringmod"}; } + + bool isRelevant(Sound* sound, int32_t whichThing) override { return (sound->sources[0].oscType <= kLastRingmoddableOscType && sound->sources[1].oscType <= kLastRingmoddableOscType); } }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/tempo/magnitude_matching.h b/src/deluge/gui/menu_item/tempo/magnitude_matching.h index 70c3319f50..f62d946504 100644 --- a/src/deluge/gui/menu_item/tempo/magnitude_matching.h +++ b/src/deluge/gui/menu_item/tempo/magnitude_matching.h @@ -15,15 +15,15 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "playback/playback_handler.h" -namespace menu_item::tempo { -class MagnitudeMatching final : public Selection { +namespace deluge::gui::menu_item::tempo { +class MagnitudeMatching final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = playbackHandler.tempoMagnitudeMatchingEnabled; } - void writeCurrentValue() { playbackHandler.tempoMagnitudeMatchingEnabled = soundEditor.currentValue; } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = playbackHandler.tempoMagnitudeMatchingEnabled; } + void writeCurrentValue() override { playbackHandler.tempoMagnitudeMatchingEnabled = this->value_; } }; -} // namespace menu_item::tempo +} // namespace deluge::gui::menu_item::tempo diff --git a/src/deluge/gui/menu_item/toggle.cpp b/src/deluge/gui/menu_item/toggle.cpp new file mode 100644 index 0000000000..2f11820acd --- /dev/null +++ b/src/deluge/gui/menu_item/toggle.cpp @@ -0,0 +1,60 @@ +#include "toggle.h" +#include "gui/ui/sound_editor.h" +#include "hid/display/numeric_driver.h" +#include "hid/display/oled.h" +#include + +namespace deluge::gui::menu_item { + +void Toggle::beginSession(MenuItem* navigatedBackwardFrom) { + Value::beginSession(navigatedBackwardFrom); +#if HAVE_OLED + soundEditor.menuCurrentScroll = 0; +#else + drawValue(); +#endif +} + +void Toggle::selectEncoderAction(int32_t offset) { + const bool flip = offset & 0b1; + if (flip) { + this->value_ = !value_; + } + Value::selectEncoderAction(offset); +} + +void Toggle::drawValue() { +#if HAVE_OLED + renderUIsForOled(); +#else + numericDriver.setText(this->value_ ? "ON" : "OFF"); +#endif +} + +#if HAVE_OLED +void Toggle::drawPixelsForOled() { + const int32_t val = static_cast(this->value_); + // Move scroll + soundEditor.menuCurrentScroll = std::clamp(soundEditor.menuCurrentScroll, 0, 1); + + char const* options[] = {"Off", "On"}; + int32_t selectedOption = this->value_ - soundEditor.menuCurrentScroll; + + int32_t baseY = (OLED_MAIN_HEIGHT_PIXELS == 64) ? 15 : 14; + baseY += OLED_MAIN_TOPMOST_PIXEL; + + for (int32_t o = 0; o < 2; o++) { + int32_t yPixel = o * kTextSpacingY + baseY; + + OLED::drawString(options[o], kTextSpacingX, yPixel, OLED::oledMainImage[0], OLED_MAIN_WIDTH_PIXELS, + kTextSpacingX, kTextSpacingY); + + if (o == selectedOption) { + OLED::invertArea(0, OLED_MAIN_WIDTH_PIXELS, yPixel, yPixel + 8, &OLED::oledMainImage[0]); + OLED::setupSideScroller(0, options[o], kTextSpacingX, OLED_MAIN_WIDTH_PIXELS, yPixel, yPixel + 8, + kTextSpacingX, kTextSpacingY, true); + } + } +} +#endif +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/toggle.h b/src/deluge/gui/menu_item/toggle.h new file mode 100644 index 0000000000..edcaefccb4 --- /dev/null +++ b/src/deluge/gui/menu_item/toggle.h @@ -0,0 +1,19 @@ +#pragma once + +#include "util/sized.h" +#include "value.h" + +namespace deluge::gui::menu_item { + +class Toggle : public Value { +public: + using Value::Value; + void beginSession(MenuItem* navigatedBackwardFrom) override; + void selectEncoderAction(int32_t offset) override; + + virtual void drawValue(); +#if HAVE_OLED + void drawPixelsForOled(); +#endif +}; +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/transpose.h b/src/deluge/gui/menu_item/transpose.h index 3c95c61771..15ac8d2775 100644 --- a/src/deluge/gui/menu_item/transpose.h +++ b/src/deluge/gui/menu_item/transpose.h @@ -17,19 +17,30 @@ #pragma once #include "decimal.h" #include "definitions_cxx.hpp" -#include "patched_param.h" +#include "gui/menu_item/patched_param.h" -namespace menu_item { +namespace deluge::gui::menu_item { class Transpose : public Decimal, public PatchedParam { public: - Transpose(char const* newName = NULL, int32_t newP = 0) : PatchedParam(newP), Decimal(newName) {} + Transpose(const string& newName, int32_t newP = 0) : Decimal(newName), PatchedParam(newP) {} + + Transpose(const string& newName, const string& title, int32_t newP = 0) + : Decimal(newName, title), PatchedParam(newP) {} + MenuItem* selectButtonPress() final { return PatchedParam::selectButtonPress(); } - virtual int32_t getMinValue() const final { return -9600; } - virtual int32_t getMaxValue() const final { return 9600; } - virtual int32_t getNumDecimalPlaces() const final { return 2; } + [[nodiscard]] int32_t getMinValue() const final { return -9600; } + [[nodiscard]] int32_t getMaxValue() const final { return 9600; } + [[nodiscard]] int32_t getNumDecimalPlaces() const final { return 2; } uint8_t getPatchedParamIndex() final { return PatchedParam::getPatchedParamIndex(); } uint8_t shouldDrawDotOnName() final { return PatchedParam::shouldDrawDotOnName(); } + +#if !HAVE_OLED + void drawValue() override { + numericDriver.setTextAsNumber(this->value_, shouldDrawDotOnName()); + } +#endif + uint8_t shouldBlinkPatchingSourceShortcut(PatchSource s, uint8_t* colour) final { return PatchedParam::shouldBlinkPatchingSourceShortcut(s, colour); } @@ -37,11 +48,15 @@ class Transpose : public Decimal, public PatchedParam { return PatchedParam::patchingSourceShortcutPress(s, previousPressStillActive); } - void unlearnAction() final { MenuItemWithCCLearning::unlearnAction(); } - bool allowsLearnMode() final { return MenuItemWithCCLearning::allowsLearnMode(); } + void unlearnAction() final { + MenuItemWithCCLearning::unlearnAction(); + } + bool allowsLearnMode() final { + return MenuItemWithCCLearning::allowsLearnMode(); + } void learnKnob(::MIDIDevice* fromDevice, int32_t whichKnob, int32_t modKnobMode, int32_t midiChannel) final { MenuItemWithCCLearning::learnKnob(fromDevice, whichKnob, modKnobMode, midiChannel); }; }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/trigger/in/auto_start.h b/src/deluge/gui/menu_item/trigger/in/auto_start.h index 3b266a8755..b68360afb8 100644 --- a/src/deluge/gui/menu_item/trigger/in/auto_start.h +++ b/src/deluge/gui/menu_item/trigger/in/auto_start.h @@ -15,15 +15,15 @@ * If not, see . */ #pragma once -#include "gui/menu_item/selection.h" +#include "gui/menu_item/toggle.h" #include "gui/ui/sound_editor.h" #include "playback/playback_handler.h" -namespace menu_item::trigger::in { -class AutoStart final : public Selection { +namespace deluge::gui::menu_item::trigger::in { +class AutoStart final : public Toggle { public: - using Selection::Selection; - void readCurrentValue() { soundEditor.currentValue = playbackHandler.analogClockInputAutoStart; } - void writeCurrentValue() { playbackHandler.analogClockInputAutoStart = soundEditor.currentValue; } + using Toggle::Toggle; + void readCurrentValue() override { this->value_ = playbackHandler.analogClockInputAutoStart; } + void writeCurrentValue() override { playbackHandler.analogClockInputAutoStart = this->value_; } }; -} // namespace menu_item::trigger::in +} // namespace deluge::gui::menu_item::trigger::in diff --git a/src/deluge/gui/menu_item/trigger/in/ppqn.h b/src/deluge/gui/menu_item/trigger/in/ppqn.h index b6b7b965e5..0304745126 100644 --- a/src/deluge/gui/menu_item/trigger/in/ppqn.h +++ b/src/deluge/gui/menu_item/trigger/in/ppqn.h @@ -21,15 +21,15 @@ #include "playback/playback_handler.h" // Trigger clock in menu -namespace menu_item::trigger::in { +namespace deluge::gui::menu_item::trigger::in { class PPQN : public menu_item::PPQN { public: using menu_item::PPQN::PPQN; - void readCurrentValue() { soundEditor.currentValue = playbackHandler.analogInTicksPPQN; } - void writeCurrentValue() { - playbackHandler.analogInTicksPPQN = soundEditor.currentValue; + void readCurrentValue() override { this->value_ = playbackHandler.analogInTicksPPQN; } + void writeCurrentValue() override { + playbackHandler.analogInTicksPPQN = this->value_; if ((playbackHandler.playbackState & PLAYBACK_CLOCK_EXTERNAL_ACTIVE) && playbackHandler.usingAnalogClockInput) playbackHandler.resyncInternalTicksToInputTicks(currentSong); } }; -} // namespace menu_item::trigger::in +} // namespace deluge::gui::menu_item::trigger::in diff --git a/src/deluge/gui/menu_item/trigger/out/ppqn.h b/src/deluge/gui/menu_item/trigger/out/ppqn.h index 88cde4e5f8..4d1f2c533f 100644 --- a/src/deluge/gui/menu_item/trigger/out/ppqn.h +++ b/src/deluge/gui/menu_item/trigger/out/ppqn.h @@ -21,14 +21,14 @@ #include "playback/playback_handler.h" // Trigger clock out menu -namespace menu_item::trigger::out { +namespace deluge::gui::menu_item::trigger::out { class PPQN : public menu_item::PPQN { public: using menu_item::PPQN::PPQN; - void readCurrentValue() { soundEditor.currentValue = playbackHandler.analogOutTicksPPQN; } - void writeCurrentValue() { - playbackHandler.analogOutTicksPPQN = soundEditor.currentValue; + void readCurrentValue() override { this->value_ = playbackHandler.analogOutTicksPPQN; } + void writeCurrentValue() override { + playbackHandler.analogOutTicksPPQN = this->value_; playbackHandler.resyncAnalogOutTicksToInternalTicks(); } }; -} // namespace menu_item::trigger::out +} // namespace deluge::gui::menu_item::trigger::out diff --git a/src/deluge/gui/menu_item/unison/count.h b/src/deluge/gui/menu_item/unison/count.h index f608edee63..fe7a9e5393 100644 --- a/src/deluge/gui/menu_item/unison/count.h +++ b/src/deluge/gui/menu_item/unison/count.h @@ -21,20 +21,20 @@ #include "processing/sound/sound.h" #include "stereoSpread.h" -namespace menu_item::unison { +namespace deluge::gui::menu_item::unison { class Count final : public Integer { public: - Count(char const* newName = NULL) : Integer(newName) {} - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSound->numUnison; } - void writeCurrentValue() { + using Integer::Integer; + void readCurrentValue() override { this->value_ = soundEditor.currentSound->numUnison; } + void writeCurrentValue() override { char modelStackMemory[MODEL_STACK_MAX_SIZE]; ModelStackWithSoundFlags* modelStack = soundEditor.getCurrentModelStack(modelStackMemory)->addSoundFlags(); - soundEditor.currentSound->setNumUnison(soundEditor.currentValue, modelStack); + soundEditor.currentSound->setNumUnison(this->value_, modelStack); } - int32_t getMinValue() const { return 1; } - int32_t getMaxValue() const { return kMaxNumVoicesUnison; } + [[nodiscard]] int32_t getMinValue() const override { return 1; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxNumVoicesUnison; } - MenuItem* selectButtonPress() override { return &unisonStereoSpreadMenu; } + MenuItem* selectButtonPress() override { return &unison::stereoSpreadMenu; } }; -} // namespace menu_item::unison +} // namespace deluge::gui::menu_item::unison diff --git a/src/deluge/gui/menu_item/unison/detune.h b/src/deluge/gui/menu_item/unison/detune.h index f6935b7dd1..8706434078 100644 --- a/src/deluge/gui/menu_item/unison/detune.h +++ b/src/deluge/gui/menu_item/unison/detune.h @@ -20,17 +20,17 @@ #include "model/model_stack.h" #include "processing/sound/sound.h" -namespace menu_item::unison { +namespace deluge::gui::menu_item::unison { class Detune final : public Integer { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSound->unisonDetune; } - void writeCurrentValue() { + void readCurrentValue() override { this->value_ = soundEditor.currentSound->unisonDetune; } + void writeCurrentValue() override { char modelStackMemory[MODEL_STACK_MAX_SIZE]; ModelStackWithSoundFlags* modelStack = soundEditor.getCurrentModelStack(modelStackMemory)->addSoundFlags(); - soundEditor.currentSound->setUnisonDetune(soundEditor.currentValue, modelStack); + soundEditor.currentSound->setUnisonDetune(this->value_, modelStack); } - int32_t getMaxValue() const { return kMaxUnisonDetune; } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxUnisonDetune; } }; -} // namespace menu_item::unison +} // namespace deluge::gui::menu_item::unison diff --git a/src/deluge/gui/menu_item/unison/stereoSpread.h b/src/deluge/gui/menu_item/unison/stereoSpread.h index 272cf677ef..36b38ab038 100644 --- a/src/deluge/gui/menu_item/unison/stereoSpread.h +++ b/src/deluge/gui/menu_item/unison/stereoSpread.h @@ -20,14 +20,14 @@ #include "model/model_stack.h" #include "processing/sound/sound.h" -namespace menu_item::unison { +namespace deluge::gui::menu_item::unison { class StereoSpread final : public Integer { public: using Integer::Integer; - void readCurrentValue() { soundEditor.currentValue = soundEditor.currentSound->unisonStereoSpread; } - void writeCurrentValue() { soundEditor.currentSound->setUnisonStereoSpread(soundEditor.currentValue); } - int32_t getMaxValue() const { return kMaxUnisonStereoSpread; } + void readCurrentValue() { this->value_ = soundEditor.currentSound->unisonStereoSpread; } + void writeCurrentValue() { soundEditor.currentSound->setUnisonStereoSpread(this->value_); } + [[nodiscard]] int32_t getMaxValue() const override { return kMaxUnisonStereoSpread; } }; -} // namespace menu_item::unison -extern menu_item::unison::StereoSpread unisonStereoSpreadMenu; +extern StereoSpread stereoSpreadMenu; +} // namespace deluge::gui::menu_item::unison diff --git a/src/deluge/gui/menu_item/unpatched_param.cpp b/src/deluge/gui/menu_item/unpatched_param.cpp index 820b8eb166..a6831b1609 100644 --- a/src/deluge/gui/menu_item/unpatched_param.cpp +++ b/src/deluge/gui/menu_item/unpatched_param.cpp @@ -28,14 +28,10 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item { - -UnpatchedParam::UnpatchedParam() { - // TODO Auto-generated constructor stub -} +namespace deluge::gui::menu_item { void UnpatchedParam::readCurrentValue() { - soundEditor.currentValue = + this->value_ = (((int64_t)soundEditor.currentParamManager->getUnpatchedParamSet()->getValue(getP()) + 2147483648) * 50 + 2147483648) >> 32; @@ -56,11 +52,11 @@ void UnpatchedParam::writeCurrentValue() { } int32_t UnpatchedParam::getFinalValue() { - if (soundEditor.currentValue == 25) { + if (this->value_ == 25) { return 0; } else { - return (uint32_t)soundEditor.currentValue * 85899345 - 2147483648; + return (uint32_t)this->value_ * 85899345 - 2147483648; } } @@ -78,4 +74,4 @@ ParamSet* UnpatchedParam::getParamSet() { // --------------------------------------- -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/unpatched_param.h b/src/deluge/gui/menu_item/unpatched_param.h index 4bcf71b967..099c710746 100644 --- a/src/deluge/gui/menu_item/unpatched_param.h +++ b/src/deluge/gui/menu_item/unpatched_param.h @@ -22,18 +22,20 @@ class ModelStackWithAutoParam; -namespace menu_item { +namespace deluge::gui::menu_item { class UnpatchedParam : public Param, public IntegerContinuous, public MenuItemWithCCLearning { public: - UnpatchedParam(); - UnpatchedParam(char const* newName, int32_t newP) : Param(newP), IntegerContinuous(newName) {} + UnpatchedParam(const string& newName, const string& title, int32_t newP) + : Param(newP), IntegerContinuous(newName, title) {} - void readCurrentValue(); - void writeCurrentValue(); + UnpatchedParam(const string& newName, int32_t newP) : Param(newP), IntegerContinuous(newName) {} + + void readCurrentValue() override; + void writeCurrentValue() override; ParamDescriptor getLearningThing() final; - int32_t getMaxValue() const { return Param::getMaxValue(); } - int32_t getMinValue() const { return Param::getMinValue(); } + [[nodiscard]] int32_t getMaxValue() const override { return Param::getMaxValue(); } + [[nodiscard]] int32_t getMinValue() const override { return Param::getMinValue(); } MenuItem* selectButtonPress() final { return Param::selectButtonPress(); } void unlearnAction() final { MenuItemWithCCLearning::unlearnAction(); } @@ -49,4 +51,4 @@ class UnpatchedParam : public Param, public IntegerContinuous, public MenuItemWi virtual int32_t getFinalValue(); }; -} // namespace menu_item +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/unpatched_param/pan.cpp b/src/deluge/gui/menu_item/unpatched_param/pan.cpp index 705db968dd..4585a2be0a 100644 --- a/src/deluge/gui/menu_item/unpatched_param/pan.cpp +++ b/src/deluge/gui/menu_item/unpatched_param/pan.cpp @@ -27,36 +27,36 @@ extern "C" { #include "util/cfunctions.h" } -namespace menu_item::unpatched_param { +namespace deluge::gui::menu_item::unpatched_param { void Pan::drawValue() { // TODO: should really combine this with the "patched" version uint8_t drawDot = 255; //soundEditor.doesParamHaveAnyCables(getP()) ? 3 : 255; char buffer[5]; - intToString(std::abs(soundEditor.currentValue), buffer, 1); - if (soundEditor.currentValue < 0) { + intToString(std::abs(this->value_), buffer, 1); + if (this->value_ < 0) { strcat(buffer, "L"); } - else if (soundEditor.currentValue > 0) { + else if (this->value_ > 0) { strcat(buffer, "R"); } numericDriver.setText(buffer, true, drawDot); } int32_t Pan::getFinalValue() { - if (soundEditor.currentValue == 32) { + if (this->value_ == 32) { return 2147483647; } - else if (soundEditor.currentValue == -32) { + else if (this->value_ == -32) { return -2147483648; } else { - return ((int32_t)soundEditor.currentValue * 33554432 * 2); + return ((int32_t)this->value_ * 33554432 * 2); } } void Pan::readCurrentValue() { - soundEditor.currentValue = + this->value_ = ((int64_t)soundEditor.currentParamManager->getUnpatchedParamSet()->getValue(getP()) * 64 + 2147483648) >> 32; } -} // namespace menu_item::unpatched_param +} // namespace deluge::gui::menu_item::unpatched_param diff --git a/src/deluge/gui/menu_item/unpatched_param/pan.h b/src/deluge/gui/menu_item/unpatched_param/pan.h index 28a27bc93a..9ec2351bb9 100644 --- a/src/deluge/gui/menu_item/unpatched_param/pan.h +++ b/src/deluge/gui/menu_item/unpatched_param/pan.h @@ -18,17 +18,17 @@ #include "gui/menu_item/unpatched_param.h" #include -namespace menu_item::unpatched_param { +namespace deluge::gui::menu_item::unpatched_param { class Pan final : public UnpatchedParam { public: - Pan(char const* newName = 0, int32_t newP = 0) : UnpatchedParam(newName, newP) {} - void drawValue(); + using UnpatchedParam::UnpatchedParam; + virtual void drawValue(); protected: - int32_t getMaxValue() const { return 32; } - int32_t getMinValue() const { return -32; } - int32_t getFinalValue(); - void readCurrentValue(); + [[nodiscard]] int32_t getMaxValue() const override { return 32; } + [[nodiscard]] int32_t getMinValue() const override { return -32; } + int32_t getFinalValue() override; + void readCurrentValue() override; }; -} // namespace menu_item::unpatched_param +} // namespace deluge::gui::menu_item::unpatched_param diff --git a/src/deluge/gui/menu_item/unpatched_param/updating_reverb_params.h b/src/deluge/gui/menu_item/unpatched_param/updating_reverb_params.h index e63e1db819..8a6e38c9be 100644 --- a/src/deluge/gui/menu_item/unpatched_param/updating_reverb_params.h +++ b/src/deluge/gui/menu_item/unpatched_param/updating_reverb_params.h @@ -18,14 +18,14 @@ #include "gui/menu_item/unpatched_param.h" #include "processing/engines/audio_engine.h" -namespace menu_item::unpatched_param { +namespace deluge::gui::menu_item::unpatched_param { class UpdatingReverbParams final : public UnpatchedParam { public: using UnpatchedParam::UnpatchedParam; - void writeCurrentValue() { + void writeCurrentValue() override { UnpatchedParam::writeCurrentValue(); AudioEngine::mustUpdateReverbParamsBeforeNextRender = true; } }; -} // namespace menu_item::unpatched_param +} // namespace deluge::gui::menu_item::unpatched_param diff --git a/src/deluge/gui/menu_item/value.cpp b/src/deluge/gui/menu_item/value.cpp deleted file mode 100644 index d979c706dc..0000000000 --- a/src/deluge/gui/menu_item/value.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright © 2017-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . - */ - -#include "value.h" -#include "gui/ui/ui.h" - -namespace menu_item { - -void Value::beginSession(MenuItem* navigatedBackwardFrom) { -#if HAVE_OLED - readCurrentValue(); -#else - readValueAgain(); -#endif -} - -void Value::selectEncoderAction(int32_t offset) { - writeCurrentValue(); - - // For MenuItems referring to an AutoParam (so UnpatchedParam and PatchedParam), ideally we wouldn't want to render the display here, because that'll happen soon anyway due to a setting of TIMER_DISPLAY_AUTOMATION. -#if HAVE_OLED - renderUIsForOled(); -#else - drawValue(); // Probably not necessary either... -#endif -} - -void Value::readValueAgain() { - readCurrentValue(); -#if HAVE_OLED - renderUIsForOled(); -#else - drawValue(); -#endif -} -} // namespace menu_item diff --git a/src/deluge/gui/menu_item/value.h b/src/deluge/gui/menu_item/value.h index e650bf774e..109022f170 100644 --- a/src/deluge/gui/menu_item/value.h +++ b/src/deluge/gui/menu_item/value.h @@ -18,16 +18,17 @@ #pragma once #include "definitions_cxx.hpp" +#include "gui/ui/ui.h" #include "menu_item.h" -namespace menu_item { - +namespace deluge::gui::menu_item { +template class Value : public MenuItem { public: - Value(char const* newName = NULL) : MenuItem(newName) {} - void beginSession(MenuItem* navigatedBackwardFrom); - void selectEncoderAction(int32_t offset); - void readValueAgain() final; + using MenuItem::MenuItem; + void beginSession(MenuItem* navigatedBackwardFrom) override; + void selectEncoderAction(int32_t offset) override; + void readValueAgain() override; bool selectEncoderActionEditsInstrument() final { return true; } protected: @@ -36,6 +37,38 @@ class Value : public MenuItem { #if !HAVE_OLED virtual void drawValue() = 0; #endif + T value_; }; -} // namespace menu_item +template +void Value::beginSession(MenuItem* navigatedBackwardFrom) { +#if HAVE_OLED + readCurrentValue(); +#else + readValueAgain(); +#endif +} + +template +void Value::selectEncoderAction(int32_t offset) { + writeCurrentValue(); + + // For MenuItems referring to an AutoParam (so UnpatchedParam and PatchedParam), ideally we wouldn't want to render the display here, because that'll happen soon anyway due to a setting of TIMER_DISPLAY_AUTOMATION. +#if HAVE_OLED + renderUIsForOled(); +#else + drawValue(); // Probably not necessary either... +#endif +} + +template +void Value::readValueAgain() { + readCurrentValue(); +#if HAVE_OLED + renderUIsForOled(); +#else + drawValue(); +#endif +} + +} // namespace deluge::gui::menu_item diff --git a/src/deluge/gui/menu_item/voice/polyphony.h b/src/deluge/gui/menu_item/voice/polyphony.h index 6227538a5e..cec9b43771 100644 --- a/src/deluge/gui/menu_item/voice/polyphony.h +++ b/src/deluge/gui/menu_item/voice/polyphony.h @@ -17,7 +17,7 @@ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" #include "model/clip/clip.h" #include "model/drum/drum.h" @@ -25,46 +25,44 @@ #include "model/song/song.h" #include "processing/sound/sound.h" #include "processing/sound/sound_drum.h" +#include "util/container/static_vector.hpp" #include "util/misc.h" -namespace menu_item::voice { -class Polyphony final : public Selection { +namespace deluge::gui::menu_item::voice { +class Polyphony final : public TypedSelection { public: - Polyphony(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(soundEditor.currentSound->polyphonic); } - void writeCurrentValue() { + using TypedSelection::TypedSelection; + void readCurrentValue() override { this->value_ = soundEditor.currentSound->polyphonic; } + void writeCurrentValue() override { // If affect-entire button held, do whole kit if (currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR && soundEditor.editingKit()) { - Kit* kit = (Kit*)currentSong->currentClip->output; + Kit* kit = static_cast(currentSong->currentClip->output); - for (Drum* thisDrum = kit->firstDrum; thisDrum; thisDrum = thisDrum->next) { + for (Drum* thisDrum = kit->firstDrum; thisDrum != nullptr; thisDrum = thisDrum->next) { if (thisDrum->type == DrumType::SOUND) { - SoundDrum* soundDrum = (SoundDrum*)thisDrum; - soundDrum->polyphonic = static_cast(soundEditor.currentValue); + auto* soundDrum = static_cast(thisDrum); + soundDrum->polyphonic = this->value_; } } } // Or, the normal case of just one sound else { - soundEditor.currentSound->polyphonic = static_cast(soundEditor.currentValue); + soundEditor.currentSound->polyphonic = this->value_; } } - char const** getOptions() { - static char const* options[] = {"Auto", "Polyphonic", "Monophonic", "Legato", "Choke", NULL}; - return options; - } + static_vector getOptions() override { + static_vector options = {"Auto", "Polyphonic", "Monophonic", "Legato"}; - int32_t getNumOptions() { // Hack-ish way of hiding the "choke" option when not editing a Kit if (soundEditor.editingKit()) { - return kNumPolyphonyModes; + options.push_back("Choke"); } - return kNumPolyphonyModes - 1; + return options; } - bool usesAffectEntire() { return true; } + bool usesAffectEntire() override { return true; } }; -} // namespace menu_item::voice +} // namespace deluge::gui::menu_item::voice diff --git a/src/deluge/gui/menu_item/voice/priority.h b/src/deluge/gui/menu_item/voice/priority.h index 53f1842d07..e30da6e391 100644 --- a/src/deluge/gui/menu_item/voice/priority.h +++ b/src/deluge/gui/menu_item/voice/priority.h @@ -16,20 +16,17 @@ */ #pragma once #include "definitions_cxx.hpp" -#include "gui/menu_item/selection.h" +#include "gui/menu_item/selection/typed_selection.h" #include "gui/ui/sound_editor.h" +#include "util/container/static_vector.hpp" #include "util/misc.h" -namespace menu_item::voice { -class Priority final : public Selection { +namespace deluge::gui::menu_item::voice { +class Priority final : public TypedSelection { public: - Priority(char const* newName = NULL) : Selection(newName) {} - void readCurrentValue() { soundEditor.currentValue = util::to_underlying(*soundEditor.currentPriority); } - void writeCurrentValue() { *soundEditor.currentPriority = static_cast(soundEditor.currentValue); } - char const** getOptions() { - static char const* options[] = {"LOW", "MEDIUM", "HIGH", NULL}; - return options; - } - int32_t getNumOptions() { return kNumVoicePriorities; } + using TypedSelection::TypedSelection; + void readCurrentValue() override { this->value_ = *soundEditor.currentPriority; } + void writeCurrentValue() override { *soundEditor.currentPriority = this->value_; } + static_vector getOptions() override { return {"LOW", "MEDIUM", "HIGH"}; } }; -} // namespace menu_item::voice +} // namespace deluge::gui::menu_item::voice diff --git a/src/deluge/gui/ui/keyboard/keyboard_screen.cpp b/src/deluge/gui/ui/keyboard/keyboard_screen.cpp index b15dbea76c..410de4d87e 100644 --- a/src/deluge/gui/ui/keyboard/keyboard_screen.cpp +++ b/src/deluge/gui/ui/keyboard/keyboard_screen.cpp @@ -41,16 +41,15 @@ #include "playback/mode/playback_mode.h" #include "processing/engines/audio_engine.h" #include "processing/sound/sound_instrument.h" -#include -#include +#include #include "gui/ui/keyboard/layout/in_key.h" #include "gui/ui/keyboard/layout/isomorphic.h" #include "gui/ui/keyboard/layout/velocity_drums.h" -keyboard::KeyboardScreen keyboardScreen{}; +deluge::gui::ui::keyboard::KeyboardScreen keyboardScreen{}; -namespace keyboard { +namespace deluge::gui::ui::keyboard { layout::KeyboardLayoutIsomorphic keyboardLayoutIsomorphic{}; layout::KeyboardLayoutVelocityDrums keyboardLayoutVelocityDrums{}; @@ -751,4 +750,4 @@ void KeyboardScreen::graphicsRoutine() { PadLEDs::setTickSquares(keyboardTickSquares, colours); } -} // namespace keyboard +} // namespace deluge::gui::ui::keyboard diff --git a/src/deluge/gui/ui/keyboard/keyboard_screen.h b/src/deluge/gui/ui/keyboard/keyboard_screen.h index 76e6ef0736..f35ca04b05 100644 --- a/src/deluge/gui/ui/keyboard/keyboard_screen.h +++ b/src/deluge/gui/ui/keyboard/keyboard_screen.h @@ -27,7 +27,7 @@ class ModelStack; -namespace keyboard { +namespace deluge::gui::ui::keyboard { constexpr int32_t kMaxNumKeyboardPadPresses = 10; @@ -87,7 +87,7 @@ class KeyboardScreen final : public RootUI, public InstrumentClipMinder { bool keyboardButtonActive = false; bool keyboardButtonUsed = false; }; +}; // namespace deluge::gui::ui::keyboard -}; // namespace keyboard - -extern keyboard::KeyboardScreen keyboardScreen; +// TODO: should get moved into namespace once project namespacing is complete +extern deluge::gui::ui::keyboard::KeyboardScreen keyboardScreen; diff --git a/src/deluge/gui/ui/keyboard/layout.h b/src/deluge/gui/ui/keyboard/layout.h index 73c4f80c60..f79788c189 100644 --- a/src/deluge/gui/ui/keyboard/layout.h +++ b/src/deluge/gui/ui/keyboard/layout.h @@ -28,7 +28,7 @@ constexpr uint8_t kMaxNumKeyboardPadPresses = 10; -namespace keyboard { +namespace deluge::gui::ui::keyboard { inline InstrumentClip* currentClip() { return (InstrumentClip*)currentSong->currentClip; @@ -38,9 +38,7 @@ inline Instrument* currentInstrument() { return (Instrument*)currentSong->currentClip->output; } -struct PressedPad { - uint8_t x; - uint8_t y; +struct PressedPad : Cartesian { bool active; }; @@ -55,7 +53,7 @@ typedef uint8_t ModesArray[kModesArraySize]; class KeyboardLayout { public: - KeyboardLayout() {} + KeyboardLayout() = default; virtual ~KeyboardLayout() {} /// Handle input pad presses @@ -132,4 +130,4 @@ class KeyboardLayout { NotesState currentNotesState; }; -}; // namespace keyboard +}; // namespace deluge::gui::ui::keyboard diff --git a/src/deluge/gui/ui/keyboard/layout/in_key.cpp b/src/deluge/gui/ui/keyboard/layout/in_key.cpp index f7e5169eb6..7c3692acb4 100644 --- a/src/deluge/gui/ui/keyboard/layout/in_key.cpp +++ b/src/deluge/gui/ui/keyboard/layout/in_key.cpp @@ -22,7 +22,7 @@ #include "gui/ui/sound_editor.h" #include "util/functions.h" -namespace keyboard::layout { +namespace deluge::gui::ui::keyboard::layout { void KeyboardLayoutInKey::evaluatePads(PressedPad presses[kMaxNumKeyboardPadPresses]) { uint8_t noteIdx = 0; @@ -126,4 +126,4 @@ void KeyboardLayoutInKey::renderPads(uint8_t image[][kDisplayWidth + kSideBarWid } } -} // namespace keyboard::layout +} // namespace deluge::gui::ui::keyboard::layout diff --git a/src/deluge/gui/ui/keyboard/layout/in_key.h b/src/deluge/gui/ui/keyboard/layout/in_key.h index 93a1aab05c..51cf844731 100644 --- a/src/deluge/gui/ui/keyboard/layout/in_key.h +++ b/src/deluge/gui/ui/keyboard/layout/in_key.h @@ -19,7 +19,7 @@ #include "gui/ui/keyboard/layout.h" -namespace keyboard::layout { +namespace deluge::gui::ui::keyboard::layout { constexpr int32_t kMinInKeyRowInterval = 1; constexpr int32_t kMaxInKeyRowInterval = 16; @@ -92,4 +92,4 @@ class KeyboardLayoutInKey : public KeyboardLayout { uint8_t noteColours[kDisplayHeight * kMaxInKeyRowInterval + kDisplayWidth][3]; }; -}; // namespace keyboard::layout +}; // namespace deluge::gui::ui::keyboard::layout diff --git a/src/deluge/gui/ui/keyboard/layout/isomorphic.cpp b/src/deluge/gui/ui/keyboard/layout/isomorphic.cpp index b49c89dacc..910fc5339f 100644 --- a/src/deluge/gui/ui/keyboard/layout/isomorphic.cpp +++ b/src/deluge/gui/ui/keyboard/layout/isomorphic.cpp @@ -22,7 +22,7 @@ #include "gui/ui/sound_editor.h" #include "util/functions.h" -namespace keyboard::layout { +namespace deluge::gui::ui::keyboard::layout { void KeyboardLayoutIsomorphic::evaluatePads(PressedPad presses[kMaxNumKeyboardPadPresses]) { uint8_t noteIdx = 0; @@ -133,4 +133,4 @@ void KeyboardLayoutIsomorphic::renderPads(uint8_t image[][kDisplayWidth + kSideB } } -} // namespace keyboard::layout +} // namespace deluge::gui::ui::keyboard::layout diff --git a/src/deluge/gui/ui/keyboard/layout/isomorphic.h b/src/deluge/gui/ui/keyboard/layout/isomorphic.h index c19fc25a69..3afba4c1cb 100644 --- a/src/deluge/gui/ui/keyboard/layout/isomorphic.h +++ b/src/deluge/gui/ui/keyboard/layout/isomorphic.h @@ -19,7 +19,7 @@ #include "gui/ui/keyboard/layout.h" -namespace keyboard::layout { +namespace deluge::gui::ui::keyboard::layout { constexpr int32_t kMinIsomorphicRowInterval = 1; constexpr int32_t kMaxIsomorphicRowInterval = 16; @@ -48,4 +48,4 @@ class KeyboardLayoutIsomorphic : public KeyboardLayout { uint8_t noteColours[kDisplayHeight * kMaxIsomorphicRowInterval + kDisplayWidth][3]; }; -}; // namespace keyboard::layout +}; // namespace deluge::gui::ui::keyboard::layout diff --git a/src/deluge/gui/ui/keyboard/layout/velocity_drums.cpp b/src/deluge/gui/ui/keyboard/layout/velocity_drums.cpp index 2ddd3cfe48..c3b9e96ee7 100644 --- a/src/deluge/gui/ui/keyboard/layout/velocity_drums.cpp +++ b/src/deluge/gui/ui/keyboard/layout/velocity_drums.cpp @@ -21,7 +21,7 @@ #include "model/model_stack.h" #include "util/functions.h" -namespace keyboard::layout { +namespace deluge::gui::ui::keyboard::layout { void KeyboardLayoutVelocityDrums::evaluatePads(PressedPad presses[kMaxNumKeyboardPadPresses]) { uint8_t noteIdx = 0; @@ -109,4 +109,4 @@ void KeyboardLayoutVelocityDrums::renderPads(uint8_t image[][kDisplayWidth + kSi } } -}; // namespace keyboard::layout +}; // namespace deluge::gui::ui::keyboard::layout diff --git a/src/deluge/gui/ui/keyboard/layout/velocity_drums.h b/src/deluge/gui/ui/keyboard/layout/velocity_drums.h index 5c0732470b..b7618cf503 100644 --- a/src/deluge/gui/ui/keyboard/layout/velocity_drums.h +++ b/src/deluge/gui/ui/keyboard/layout/velocity_drums.h @@ -19,7 +19,7 @@ #include "gui/ui/keyboard/layout.h" -namespace keyboard::layout { +namespace deluge::gui::ui::keyboard::layout { constexpr int32_t kMinDrumPadEdgeSize = 1; constexpr int32_t kMaxDrumPadEdgeSize = 8; @@ -62,4 +62,4 @@ class KeyboardLayoutVelocityDrums : KeyboardLayout { uint8_t noteColours[kDisplayHeight * kDisplayWidth][3]; }; -}; // namespace keyboard::layout +}; // namespace deluge::gui::ui::keyboard::layout diff --git a/src/deluge/gui/ui/keyboard/notes_state.h b/src/deluge/gui/ui/keyboard/notes_state.h index d68ad8243b..91c069a42e 100644 --- a/src/deluge/gui/ui/keyboard/notes_state.h +++ b/src/deluge/gui/ui/keyboard/notes_state.h @@ -17,12 +17,13 @@ #pragma once +#include "definitions_cxx.hpp" #include -#include +#include constexpr uint8_t kMaxNumActiveNotes = 10; -namespace keyboard { +namespace deluge::gui::ui::keyboard { struct NoteState { uint8_t note = 0; @@ -61,4 +62,4 @@ struct NotesState { } }; -}; // namespace keyboard +}; // namespace deluge::gui::ui::keyboard diff --git a/src/deluge/gui/ui/keyboard/state_data.h b/src/deluge/gui/ui/keyboard/state_data.h index 92991067b4..30642baf85 100644 --- a/src/deluge/gui/ui/keyboard/state_data.h +++ b/src/deluge/gui/ui/keyboard/state_data.h @@ -18,7 +18,7 @@ #pragma once #include "definitions_cxx.hpp" -namespace keyboard { +namespace deluge::gui::ui::keyboard { enum KeyboardLayoutType : uint32_t { Isomorphic, @@ -54,4 +54,4 @@ struct KeyboardState { KeyboardStateInKey inKey; }; -}; // namespace keyboard +}; // namespace deluge::gui::ui::keyboard diff --git a/src/deluge/gui/ui/menus.cpp b/src/deluge/gui/ui/menus.cpp index ba1ca9901e..986ff85662 100644 --- a/src/deluge/gui/ui/menus.cpp +++ b/src/deluge/gui/ui/menus.cpp @@ -32,6 +32,7 @@ #include "gui/menu_item/delay/sync.h" #include "gui/menu_item/dev_var/dev_var.h" #include "gui/menu_item/drum_name.h" +#include "gui/menu_item/envelope/segment.h" #include "gui/menu_item/file_selector.h" #include "gui/menu_item/filter/hpf_freq.h" #include "gui/menu_item/filter/lpf_freq.h" @@ -118,8 +119,6 @@ #include "gui/menu_item/sample/start.h" #include "gui/menu_item/sample/time_stretch.h" #include "gui/menu_item/sample/transpose.h" -#include "gui/menu_item/selection.h" -#include "gui/menu_item/selection_for_value.h" #include "gui/menu_item/sequence/direction.h" #include "gui/menu_item/shortcuts/version.h" #include "gui/menu_item/sidechain/send.h" @@ -159,132 +158,88 @@ #include "gui/menu_item/voice/priority.h" #include "processing/sound/sound.h" -using namespace menu_item; - -#if HAVE_OLED -char oscTypeTitle[] = "OscX type"; -char oscLevelTitle[] = "OscX level"; -char waveIndexTitle[] = "OscX wave-ind."; -char carrierFeedback[] = "CarrierX feed."; -char sampleReverseTitle[] = "SampX reverse"; -char sampleModeTitle[] = "SampX repeat"; -char oscTransposeTitle[] = "OscX transpose"; -char sampleSpeedTitle[] = "SampX speed"; -char sampleInterpolationTitle[] = "SampX interp."; -char pulseWidthTitle[] = "OscX p. width"; -char retriggerPhaseTitle[] = "OscX r. phase"; - -char attackTitle[] = "EnvX attack"; -char decayTitle[] = "EnvX decay"; -char sustainTitle[] = "EnvX sustain"; -char releaseTitle[] = "EnvX release"; - -char modulatorTransposeTitle[] = "FM ModX tran."; -char modulatorLevelTitle[] = "FM ModX level"; -char modulatorFeedbackTitle[] = "FM ModX f.back"; -char modulatorRetriggerPhaseTitle[] = "FM ModX retrig"; - -char cvVoltsTitle[] = "CVx V/octave"; -char cvTransposeTitle[] = "CVx transpose"; - -void setOscillatorNumberForTitles(int32_t s) { - oscTypeTitle[3] = '1' + s; - oscLevelTitle[3] = '1' + s; - waveIndexTitle[3] = '1' + s; - oscTransposeTitle[3] = '1' + s; - pulseWidthTitle[3] = '1' + s; - retriggerPhaseTitle[3] = '1' + s; - - carrierFeedback[7] = '1' + s; - - sampleReverseTitle[4] = '1' + s; - sampleModeTitle[4] = '1' + s; - sampleSpeedTitle[4] = '1' + s; - sampleInterpolationTitle[4] = '1' + s; -} - -void setEnvelopeNumberForTitles(int32_t e) { - attackTitle[3] = '1' + e; - decayTitle[3] = '1' + e; - sustainTitle[3] = '1' + e; - releaseTitle[3] = '1' + e; -} - -void setModulatorNumberForTitles(int32_t m) { - modulatorTransposeTitle[6] = '1' + m; - modulatorLevelTitle[6] = '1' + m; - modulatorFeedbackTitle[6] = '1' + m; - modulatorRetriggerPhaseTitle[6] = '1' + m; -} - -void setCvNumberForTitle(int32_t m) { - cvVoltsTitle[2] = '1' + m; - cvTransposeTitle[2] = '1' + m; -} -#endif +using namespace deluge; +using namespace deluge::gui; +using namespace deluge::gui::menu_item; // Dev vars -dev_var::AMenu devVarAMenu; -dev_var::BMenu devVarBMenu; -dev_var::CMenu devVarCMenu; -dev_var::DMenu devVarDMenu; -dev_var::EMenu devVarEMenu; -dev_var::FMenu devVarFMenu; -dev_var::GMenu devVarGMenu; +dev_var::AMenu devVarAMenu{HAVE_OLED ? "Dev Menu A" : "DEVA"}; +dev_var::BMenu devVarBMenu{HAVE_OLED ? "Dev Menu B" : "DEVB"}; +dev_var::CMenu devVarCMenu{HAVE_OLED ? "Dev Menu C" : "DEVC"}; +dev_var::DMenu devVarDMenu{HAVE_OLED ? "Dev Menu D" : "DEVD"}; +dev_var::EMenu devVarEMenu{HAVE_OLED ? "Dev Menu E" : "DEVE"}; +dev_var::FMenu devVarFMenu{HAVE_OLED ? "Dev Menu F" : "DEVF"}; +dev_var::GMenu devVarGMenu{HAVE_OLED ? "Dev Menu G" : "DEVG"}; // LPF menu ---------------------------------------------------------------------------------------------------- -filter::LPFFreq lpfFreqMenu{"Frequency", ::Param::Local::LPF_FREQ}; -patched_param::IntegerNonFM lpfResMenu{"Resonance", ::Param::Local::LPF_RESONANCE}; -filter::LPFMode lpfModeMenu{"MODE"}; - -MenuItem* lpfMenuItems[] = {&lpfFreqMenu, &lpfResMenu, &lpfModeMenu, NULL}; -submenu::Filter lpfMenu{"LPF", lpfMenuItems}; +filter::LPFFreq lpfFreqMenu{"Frequency", "LPF frequency", ::Param::Local::LPF_FREQ}; +patched_param::IntegerNonFM lpfResMenu{"Resonance", "LPF resonance", ::Param::Local::LPF_RESONANCE}; +filter::LPFMode lpfModeMenu{"MODE", "LPF mode"}; + +submenu::Filter lpfMenu{ + "LPF", + { + &lpfFreqMenu, + &lpfResMenu, + &lpfModeMenu, + }, +}; // HPF menu ---------------------------------------------------------------------------------------------------- -filter::HPFFreq hpfFreqMenu{"Frequency", ::Param::Local::HPF_FREQ}; -patched_param::IntegerNonFM hpfResMenu{"Resonance", ::Param::Local::HPF_RESONANCE}; +filter::HPFFreq hpfFreqMenu{"Frequency", "HPF frequency", ::Param::Local::HPF_FREQ}; +patched_param::IntegerNonFM hpfResMenu{"Resonance", "HPF resonance", ::Param::Local::HPF_RESONANCE}; -MenuItem* hpfMenuItems[] = {&hpfFreqMenu, &hpfResMenu, NULL}; -submenu::Filter hpfMenu{"HPF", hpfMenuItems}; +submenu::Filter hpfMenu{ + "HPF", + { + &hpfFreqMenu, + &hpfResMenu, + }, +}; // Envelope menu ---------------------------------------------------------------------------------------------------- -source::PatchedParam envAttackMenu{"ATTACK", ::Param::Local::ENV_0_ATTACK}; -source::PatchedParam envDecayMenu{"DECAY", ::Param::Local::ENV_0_DECAY}; -source::PatchedParam envSustainMenu{"SUSTAIN", ::Param::Local::ENV_0_SUSTAIN}; -source::PatchedParam envReleaseMenu{"RELEASE", ::Param::Local::ENV_0_RELEASE}; -MenuItem* envMenuItems[] = {&envAttackMenu, &envDecayMenu, &envSustainMenu, &envReleaseMenu, NULL}; +envelope::Segment envAttackMenu{"ATTACK", "Env{} attack", ::Param::Local::ENV_0_ATTACK}; +envelope::Segment envDecayMenu{"DECAY", "Env{} decay", ::Param::Local::ENV_0_DECAY}; +envelope::Segment envSustainMenu{"SUSTAIN", "Env{} sustain", ::Param::Local::ENV_0_SUSTAIN}; +envelope::Segment envReleaseMenu{"RELEASE", "Env{} release", ::Param::Local::ENV_0_RELEASE}; +MenuItem* envMenuItems[] = { + &envAttackMenu, + &envDecayMenu, + &envSustainMenu, + &envReleaseMenu, +}; submenu::Envelope env0Menu{HAVE_OLED ? "Envelope 1" : "ENV1", envMenuItems, 0}; submenu::Envelope env1Menu{HAVE_OLED ? "Envelope 2" : "ENV2", envMenuItems, 1}; // Osc menu ------------------------------------------------------------------------------------------------------- -osc::Type oscTypeMenu{"TYPE"}; -osc::source::WaveIndex sourceWaveIndexMenu{"Wave-index", Param::Local::OSC_A_WAVE_INDEX}; -osc::source::Volume sourceVolumeMenu{HAVE_OLED ? "Level" : "VOLUME", Param::Local::OSC_A_VOLUME}; -osc::source::Feedback sourceFeedbackMenu{"FEEDBACK", Param::Local::CARRIER_0_FEEDBACK}; +osc::Type oscTypeMenu{"TYPE", "Osc{} type"}; +osc::source::WaveIndex sourceWaveIndexMenu{"Wave-index", "Osc{} wave-ind.", Param::Local::OSC_A_WAVE_INDEX}; +osc::source::Volume sourceVolumeMenu{HAVE_OLED ? "Level" : "VOLUME", "Osc{} level", Param::Local::OSC_A_VOLUME}; +osc::source::Feedback sourceFeedbackMenu{"FEEDBACK", "Carrier{} feed.", Param::Local::CARRIER_0_FEEDBACK}; osc::AudioRecorder audioRecorderMenu{"Record audio"}; -sample::Reverse sampleReverseMenu{"REVERSE"}; -sample::Repeat sampleRepeatMenu{HAVE_OLED ? "Repeat mode" : "MODE"}; +sample::Reverse sampleReverseMenu{"REVERSE", "Samp{} reverse"}; +sample::Repeat sampleRepeatMenu{HAVE_OLED ? "Repeat mode" : "MODE", "Samp{} repeat"}; sample::Start sampleStartMenu{"Start-point"}; sample::End sampleEndMenu{"End-point"}; -sample::Transpose sourceTransposeMenu{"TRANSPOSE", Param::Local::OSC_A_PITCH_ADJUST}; +sample::Transpose sourceTransposeMenu{"TRANSPOSE", "Osc{} transpose", Param::Local::OSC_A_PITCH_ADJUST}; sample::PitchSpeed samplePitchSpeedMenu{HAVE_OLED ? "Pitch/speed" : "PISP"}; -sample::TimeStretch timeStretchMenu{"SPEED"}; -sample::Interpolation interpolationMenu{"INTERPOLATION"}; -osc::PulseWidth pulseWidthMenu{"PULSE WIDTH", Param::Local::OSC_A_PHASE_WIDTH}; +sample::TimeStretch timeStretchMenu{"SPEED", "Samp{} speed"}; +sample::Interpolation interpolationMenu{"INTERPOLATION", "Samp{} interp."}; +osc::PulseWidth pulseWidthMenu{"PULSE WIDTH", "Osc{} p. width", Param::Local::OSC_A_PHASE_WIDTH}; osc::Sync oscSyncMenu{HAVE_OLED ? "Oscillator sync" : "SYNC"}; -osc::RetriggerPhase oscPhaseMenu{"Retrigger phase", false}; +osc::RetriggerPhase oscPhaseMenu{"Retrigger phase", "Osc{} r. phase", false}; -MenuItem* oscMenuItems[] = {&oscTypeMenu, &sourceVolumeMenu, &sourceWaveIndexMenu, - &sourceFeedbackMenu, &fileSelectorMenu, &audioRecorderMenu, - &sampleReverseMenu, &sampleRepeatMenu, &sampleStartMenu, - &sampleEndMenu, &sourceTransposeMenu, &samplePitchSpeedMenu, - &timeStretchMenu, &interpolationMenu, &pulseWidthMenu, - &oscSyncMenu, &oscPhaseMenu, NULL}; +MenuItem* oscMenuItems[] = { + &oscTypeMenu, &sourceVolumeMenu, &sourceWaveIndexMenu, &sourceFeedbackMenu, &fileSelectorMenu, + &audioRecorderMenu, &sampleReverseMenu, &sampleRepeatMenu, &sampleStartMenu, &sampleEndMenu, + &sourceTransposeMenu, &samplePitchSpeedMenu, &timeStretchMenu, &interpolationMenu, &pulseWidthMenu, + &oscSyncMenu, &oscPhaseMenu, +}; submenu::ActualSource source0Menu{HAVE_OLED ? "Oscillator 1" : "OSC1", oscMenuItems, 0}; submenu::ActualSource source1Menu{HAVE_OLED ? "Oscillator 2" : "OSC2", oscMenuItems, 1}; @@ -293,63 +248,87 @@ submenu::ActualSource source1Menu{HAVE_OLED ? "Oscillator 2" : "OSC2", oscMenuIt unison::Count numUnisonMenu{HAVE_OLED ? "Unison number" : "NUM"}; unison::Detune unisonDetuneMenu{HAVE_OLED ? "Unison detune" : "DETUNE"}; -unison::StereoSpread unisonStereoSpreadMenu{HAVE_OLED ? "Unison stereo spread" : "SPREAD"}; - -MenuItem* unisonMenuItems[] = {&numUnisonMenu, &unisonDetuneMenu, &unisonStereoSpreadMenu, NULL}; +unison::StereoSpread unison::stereoSpreadMenu{HAVE_OLED ? "Unison stereo spread" : "SPREAD"}; + +Submenu unisonMenu{ + "UNISON", + { + &numUnisonMenu, + &unisonDetuneMenu, + &unison::stereoSpreadMenu, + }, +}; // Arp -------------------------------------------------------------------------------------- -arpeggiator::Mode arpModeMenu{"MODE"}; -arpeggiator::Sync arpSyncMenu{"SYNC"}; -arpeggiator::Octaves arpOctavesMenu{HAVE_OLED ? "Number of octaves" : "OCTAVES"}; -arpeggiator::Gate arpGateMenu{"GATE", ::Param::Unpatched::Sound::ARP_GATE}; -arpeggiator::midi_cv::Gate arpGateMenuMIDIOrCV{"GATE"}; -arpeggiator::Rate arpRateMenu{"RATE", ::Param::Global::ARP_RATE}; -arpeggiator::midi_cv::Rate arpRateMenuMIDIOrCV{"RATE"}; - -MenuItem* arpMenuItems[] = {&arpModeMenu, &arpSyncMenu, &arpOctavesMenu, &arpGateMenu, - &arpGateMenuMIDIOrCV, &arpRateMenu, &arpRateMenuMIDIOrCV, NULL}; +arpeggiator::Mode arpModeMenu{"MODE", "Arp. mode"}; +arpeggiator::Sync arpSyncMenu{"SYNC", "Arp. sync"}; +arpeggiator::Octaves arpOctavesMenu{HAVE_OLED ? "Number of octaves" : "OCTAVES", "Arp. octaves"}; +arpeggiator::Gate arpGateMenu{"GATE", "Arp. gate", ::Param::Unpatched::Sound::ARP_GATE}; +arpeggiator::midi_cv::Gate arpGateMenuMIDIOrCV{"GATE", "Arp. gate"}; +arpeggiator::Rate arpRateMenu{"RATE", "Arp. rate", ::Param::Global::ARP_RATE}; +arpeggiator::midi_cv::Rate arpRateMenuMIDIOrCV{"RATE", "Arp. rate"}; + +submenu::Arpeggiator arpMenu{ + "ARPEGGIATOR", + { + &arpModeMenu, + &arpSyncMenu, + &arpOctavesMenu, + &arpGateMenu, + &arpGateMenuMIDIOrCV, + &arpRateMenu, + &arpRateMenuMIDIOrCV, + }, +}; // Voice menu ---------------------------------------------------------------------------------------------------- voice::Polyphony polyphonyMenu{"POLYPHONY"}; -Submenu unisonMenu{"UNISON", unisonMenuItems}; UnpatchedParam portaMenu{"PORTAMENTO", ::Param::Unpatched::Sound::PORTAMENTO}; -submenu::Arpeggiator arpMenu{"ARPEGGIATOR", arpMenuItems}; voice::Priority priorityMenu{"PRIORITY"}; -static MenuItem* voiceMenuItems[] = {&polyphonyMenu, &unisonMenu, &portaMenu, &arpMenu, &priorityMenu, NULL}; +Submenu voiceMenu{"VOICE", {&polyphonyMenu, &unisonMenu, &portaMenu, &arpMenu, &priorityMenu}}; // Modulator menu ----------------------------------------------------------------------- -modulator::Transpose modulatorTransposeMenu{"Transpose", ::Param::Local::MODULATOR_0_PITCH_ADJUST}; -source::patched_param::FM modulatorVolume{HAVE_OLED ? "Level" : "AMOUNT", ::Param::Local::MODULATOR_0_VOLUME}; -source::patched_param::FM modulatorFeedbackMenu{"FEEDBACK", ::Param::Local::MODULATOR_0_FEEDBACK}; -modulator::Destination modulatorDestMenu{"Destination"}; -osc::RetriggerPhase modulatorPhaseMenu{"Retrigger phase", true}; +modulator::Transpose modulatorTransposeMenu{"Transpose", "FM Mod{} tran.", ::Param::Local::MODULATOR_0_PITCH_ADJUST}; +source::patched_param::FM modulatorVolume{HAVE_OLED ? "Level" : "AMOUNT", "FM Mod{} level", + ::Param::Local::MODULATOR_0_VOLUME}; +source::patched_param::FM modulatorFeedbackMenu{"FEEDBACK", "FM Mod{} f.back", ::Param::Local::MODULATOR_0_FEEDBACK}; +modulator::Destination modulatorDestMenu{"Destination", "FM Mod2 dest."}; +osc::RetriggerPhase modulatorPhaseMenu{"Retrigger phase", "FM Mod{} retrig", true}; // LFO1 menu --------------------------------------------------------------------------------- -lfo::global::Type lfo1TypeMenu{HAVE_OLED ? "SHAPE" : "TYPE"}; -lfo::global::Rate lfo1RateMenu{"RATE", ::Param::Global::LFO_FREQ}; -lfo::global::Sync lfo1SyncMenu{"SYNC"}; +lfo::global::Type lfo1TypeMenu{HAVE_OLED ? "SHAPE" : "TYPE", "LFO1 type"}; +lfo::global::Rate lfo1RateMenu{"RATE", "LFO1 rate", ::Param::Global::LFO_FREQ}; +lfo::global::Sync lfo1SyncMenu{"SYNC", "LFO1 sync"}; -MenuItem* lfo1MenuItems[] = {&lfo1TypeMenu, &lfo1RateMenu, &lfo1SyncMenu, NULL}; +Submenu lfo0Menu{"LFO1", {&lfo1TypeMenu, &lfo1RateMenu, &lfo1SyncMenu}}; // LFO2 menu --------------------------------------------------------------------------------- -lfo::local::Type lfo2TypeMenu{HAVE_OLED ? "SHAPE" : "TYPE"}; -patched_param::Integer lfo2RateMenu{"RATE", ::Param::Local::LFO_LOCAL_FREQ}; +lfo::local::Type lfo2TypeMenu{HAVE_OLED ? "SHAPE" : "TYPE", "LFO2 type"}; +patched_param::Integer lfo2RateMenu{"RATE", "LFO2 rate", ::Param::Local::LFO_LOCAL_FREQ}; -MenuItem* lfo2MenuItems[] = {&lfo2TypeMenu, &lfo2RateMenu, NULL}; +Submenu lfo1Menu{"LFO2", {&lfo2TypeMenu, &lfo2RateMenu}}; // Mod FX ---------------------------------------------------------------------------------- -mod_fx::Type modFXTypeMenu{"TYPE"}; -patched_param::Integer modFXRateMenu{"RATE", ::Param::Global::MOD_FX_RATE}; -mod_fx::Feedback modFXFeedbackMenu{"FEEDBACK", ::Param::Unpatched::MOD_FX_FEEDBACK}; -mod_fx::Depth modFXDepthMenu{"DEPTH", ::Param::Global::MOD_FX_DEPTH}; -mod_fx::Offset modFXOffsetMenu{"OFFSET", ::Param::Unpatched::MOD_FX_OFFSET}; - -MenuItem* modFXMenuItems[] = {&modFXTypeMenu, &modFXRateMenu, &modFXFeedbackMenu, - &modFXDepthMenu, &modFXOffsetMenu, NULL}; +mod_fx::Type modFXTypeMenu{"TYPE", "MODFX type"}; +patched_param::Integer modFXRateMenu{"RATE", "MODFX rate", ::Param::Global::MOD_FX_RATE}; +mod_fx::Feedback modFXFeedbackMenu{"FEEDBACK", "MODFX feedback", ::Param::Unpatched::MOD_FX_FEEDBACK}; +mod_fx::Depth modFXDepthMenu{"DEPTH", "MODFX depth", ::Param::Global::MOD_FX_DEPTH}; +mod_fx::Offset modFXOffsetMenu{"OFFSET", "MODFX offset", ::Param::Unpatched::MOD_FX_OFFSET}; + +Submenu modFXMenu{ + HAVE_OLED ? "Mod-fx" : "MODU", + { + &modFXTypeMenu, + &modFXRateMenu, + &modFXFeedbackMenu, + &modFXDepthMenu, + &modFXOffsetMenu, + }, +}; // EQ ------------------------------------------------------------------------------------- UnpatchedParam bassMenu{"BASS", ::Param::Unpatched::BASS}; @@ -357,81 +336,130 @@ UnpatchedParam trebleMenu{"TREBLE", ::Param::Unpatched::TREBLE}; UnpatchedParam bassFreqMenu{HAVE_OLED ? "Bass frequency" : "BAFR", ::Param::Unpatched::BASS_FREQ}; UnpatchedParam trebleFreqMenu{HAVE_OLED ? "Treble frequency" : "TRFR", ::Param::Unpatched::TREBLE_FREQ}; -MenuItem* eqMenuItems[] = {&bassMenu, &trebleMenu, &bassFreqMenu, &trebleFreqMenu, NULL}; +Submenu eqMenu{ + "EQ", + { + &bassMenu, + &trebleMenu, + &bassFreqMenu, + &trebleFreqMenu, + }, +}; // Delay --------------------------------------------------------------------------------- -patched_param::Integer delayFeedbackMenu{"AMOUNT", ::Param::Global::DELAY_FEEDBACK}; -patched_param::Integer delayRateMenu{"RATE", ::Param::Global::DELAY_RATE}; -delay::PingPong delayPingPongMenu{"Pingpong"}; -delay::Analog delayAnalogMenu{"TYPE"}; -delay::Sync delaySyncMenu{"SYNC"}; - -MenuItem* delayMenuItems[] = {&delayFeedbackMenu, &delayRateMenu, &delayPingPongMenu, - &delayAnalogMenu, &delaySyncMenu, NULL}; +patched_param::Integer delayFeedbackMenu{"AMOUNT", "Delay amount", ::Param::Global::DELAY_FEEDBACK}; +patched_param::Integer delayRateMenu{"RATE", "Delay rate", ::Param::Global::DELAY_RATE}; +delay::PingPong delayPingPongMenu{"Pingpong", "Delay pingpong"}; +delay::Analog delayAnalogMenu{"TYPE", "Delay type"}; +delay::Sync delaySyncMenu{"SYNC", "Delay sync"}; + +Submenu delayMenu{ + "DELAY", + { + &delayFeedbackMenu, + &delayRateMenu, + &delayPingPongMenu, + &delayAnalogMenu, + &delaySyncMenu, + }, +}; // Bend Ranges ------------------------------------------------------------------------------- bend_range::Main mainBendRangeMenu{"Normal"}; bend_range::PerFinger perFingerBendRangeMenu{HAVE_OLED ? "Poly / finger / MPE" : "MPE"}; -MenuItem* bendMenuItems[] = {&mainBendRangeMenu, &perFingerBendRangeMenu, NULL}; +submenu::Bend bendMenu{ + "Bend range", + { + &mainBendRangeMenu, + &perFingerBendRangeMenu, + }, +}; // Sidechain/Compressor----------------------------------------------------------------------- -sidechain::Send sidechainSendMenu{"Send to sidechain"}; +sidechain::Send sidechainSendMenu{"Send to sidechain", "Send to sidech"}; compressor::VolumeShortcut compressorVolumeShortcutMenu{"Volume ducking", ::Param::Global::VOLUME_POST_REVERB_SEND, PatchSource::COMPRESSOR}; reverb::compressor::Volume reverbCompressorVolumeMenu{"Volume ducking"}; -sidechain::Sync sidechainSyncMenu{"SYNC"}; -compressor::Attack compressorAttackMenu{"ATTACK"}; -compressor::Release compressorReleaseMenu{"RELEASE"}; -unpatched_param::UpdatingReverbParams compressorShapeMenu{"SHAPE", ::Param::Unpatched::COMPRESSOR_SHAPE}; -reverb::compressor::Shape reverbCompressorShapeMenu{"SHAPE"}; - -MenuItem* sidechainMenuItemsForSound[] = {&sidechainSendMenu, - &compressorVolumeShortcutMenu, - &sidechainSyncMenu, - &compressorAttackMenu, - &compressorReleaseMenu, - &compressorShapeMenu, - NULL}; - -MenuItem* sidechainMenuItemsForReverb[] = {&reverbCompressorVolumeMenu, &sidechainSyncMenu, - &compressorAttackMenu, &compressorReleaseMenu, - &reverbCompressorShapeMenu, NULL}; +sidechain::Sync sidechainSyncMenu{"SYNC", "Sidechain sync"}; +compressor::Attack compressorAttackMenu{"ATTACK", "Sidech. attack"}; +compressor::Release compressorReleaseMenu{"RELEASE", "Sidech release"}; +unpatched_param::UpdatingReverbParams compressorShapeMenu{"SHAPE", "Sidech. shape", + ::Param::Unpatched::COMPRESSOR_SHAPE}; +reverb::compressor::Shape reverbCompressorShapeMenu{"SHAPE", "Sidech. shape"}; + +submenu::Compressor compressorMenu{ + "Sidechain compressor", + "Sidechain comp", + { + &sidechainSendMenu, + &compressorVolumeShortcutMenu, + &sidechainSyncMenu, + &compressorAttackMenu, + &compressorReleaseMenu, + &compressorShapeMenu, + }, + false, +}; + +submenu::Compressor reverbCompressorMenu{ + HAVE_OLED ? "Reverb sidechain" : "SIDE", + "Reverb sidech.", + { + &reverbCompressorVolumeMenu, + &sidechainSyncMenu, + &compressorAttackMenu, + &compressorReleaseMenu, + &reverbCompressorShapeMenu, + }, + true, +}; // Reverb ---------------------------------------------------------------------------------- -patched_param::Integer reverbAmountMenu{"AMOUNT", ::Param::Global::REVERB_AMOUNT}; +patched_param::Integer reverbAmountMenu{"AMOUNT", "Reverb amount", ::Param::Global::REVERB_AMOUNT}; reverb::RoomSize reverbRoomSizeMenu{HAVE_OLED ? "Room size" : "SIZE"}; reverb::Dampening reverbDampeningMenu{"DAMPENING"}; -reverb::Width reverbWidthMenu{"WIDTH"}; -reverb::Pan reverbPanMenu{"PAN"}; -submenu::Compressor reverbCompressorMenu{HAVE_OLED ? "Reverb sidechain" : "SIDE", sidechainMenuItemsForReverb, true}; - -MenuItem* reverbMenuItems[] = {&reverbAmountMenu, - &reverbRoomSizeMenu, - &reverbDampeningMenu, - &reverbWidthMenu, - &reverbPanMenu, - &reverbCompressorMenu, - NULL}; +reverb::Width reverbWidthMenu{"WIDTH", "Reverb width"}; +reverb::Pan reverbPanMenu{"PAN", "Reverb pan"}; + +Submenu reverbMenu{ + "REVERB", + { + &reverbAmountMenu, + &reverbRoomSizeMenu, + &reverbDampeningMenu, + &reverbWidthMenu, + &reverbPanMenu, + &reverbCompressorMenu, + }, +}; // FX ---------------------------------------------------------------------------------------- -Submenu modFXMenu{HAVE_OLED ? "Mod-fx" : "MODU", modFXMenuItems}; -Submenu eqMenu{"EQ", eqMenuItems}; -Submenu delayMenu{"DELAY", delayMenuItems}; -Submenu reverbMenu{"REVERB", reverbMenuItems}; + fx::Clipping clippingMenu{"SATURATION"}; UnpatchedParam srrMenu{"DECIMATION", ::Param::Unpatched::SAMPLE_RATE_REDUCTION}; UnpatchedParam bitcrushMenu{HAVE_OLED ? "Bitcrush" : "CRUSH", ::Param::Unpatched::BITCRUSHING}; -MenuItem* fxMenuItems[] = {&modFXMenu, &eqMenu, &delayMenu, &reverbMenu, &clippingMenu, &srrMenu, &bitcrushMenu, NULL}; +Submenu fxMenu{ + "FX", + { + &modFXMenu, + &eqMenu, + &delayMenu, + &reverbMenu, + &clippingMenu, + &srrMenu, + &bitcrushMenu, + }, +}; // MIDIInstrument menu ---------------------------------------------------------------------- -midi::Bank midiBankMenu{"BANK"}; -midi::Sub midiSubMenu{HAVE_OLED ? "Sub-bank" : "SUB"}; -midi::PGM midiPGMMenu{"PGM"}; +midi::Bank midiBankMenu{"BANK", "MIDI bank"}; +midi::Sub midiSubMenu{HAVE_OLED ? "Sub-bank" : "SUB", "MIDI sub-bank"}; +midi::PGM midiPGMMenu{"PGM", "MIDI PGM numb."}; // Clip-level stuff -------------------------------------------------------------------------- @@ -444,129 +472,193 @@ audio_clip::Reverse audioClipReverseMenu{"REVERSE"}; audio_clip::SampleMarkerEditor audioClipSampleMarkerEditorMenuStart{"", MarkerType::START}; audio_clip::SampleMarkerEditor audioClipSampleMarkerEditorMenuEnd{"WAVEFORM", MarkerType::END}; -MenuItem* audioClipSampleMenuItems[] = {&fileSelectorMenu, &audioClipReverseMenu, - &samplePitchSpeedMenu, &audioClipSampleMarkerEditorMenuEnd, - &interpolationMenu, NULL}; -Submenu audioClipSampleMenu{"SAMPLE", audioClipSampleMenuItems}; +Submenu audioClipSampleMenu{ + "SAMPLE", + { + &fileSelectorMenu, + &audioClipReverseMenu, + &samplePitchSpeedMenu, + &audioClipSampleMarkerEditorMenuEnd, + &interpolationMenu, + }, +}; // LPF Menu -audio_clip::LPFFreq audioClipLPFFreqMenu{"Frequency", ::Param::Unpatched::GlobalEffectable::LPF_FREQ}; -UnpatchedParam audioClipLPFResMenu{"Resonance", ::Param::Unpatched::GlobalEffectable::LPF_RES}; - -MenuItem* audioClipLPFMenuItems[] = {&audioClipLPFFreqMenu, &audioClipLPFResMenu, &lpfModeMenu, NULL}; -Submenu audioClipLPFMenu{"LPF", audioClipLPFMenuItems}; +audio_clip::LPFFreq audioClipLPFFreqMenu{"Frequency", "LPF frequency", ::Param::Unpatched::GlobalEffectable::LPF_FREQ}; +UnpatchedParam audioClipLPFResMenu{"Resonance", "LPF resonance", ::Param::Unpatched::GlobalEffectable::LPF_RES}; + +Submenu audioClipLPFMenu{ + "LPF", + { + &audioClipLPFFreqMenu, + &audioClipLPFResMenu, + &lpfModeMenu, + }, +}; // HPF Menu -audio_clip::HPFFreq audioClipHPFFreqMenu{"Frequency", ::Param::Unpatched::GlobalEffectable::HPF_FREQ}; -UnpatchedParam audioClipHPFResMenu{"Resonance", ::Param::Unpatched::GlobalEffectable::HPF_RES}; - -MenuItem* audioClipHPFMenuItems[] = {&audioClipHPFFreqMenu, &audioClipHPFResMenu, NULL}; -Submenu audioClipHPFMenu{"HPF", audioClipHPFMenuItems}; +audio_clip::HPFFreq audioClipHPFFreqMenu{"Frequency", "HPF frequency", ::Param::Unpatched::GlobalEffectable::HPF_FREQ}; +UnpatchedParam audioClipHPFResMenu{"Resonance", "HPF resonance", ::Param::Unpatched::GlobalEffectable::HPF_RES}; + +Submenu audioClipHPFMenu{ + "HPF", + { + &audioClipHPFFreqMenu, + &audioClipHPFResMenu, + }, +}; // Mod FX Menu -audio_clip::mod_fx::Type audioClipModFXTypeMenu{"TYPE"}; -UnpatchedParam audioClipModFXRateMenu{"RATE", ::Param::Unpatched::GlobalEffectable::MOD_FX_RATE}; -UnpatchedParam audioClipModFXDepthMenu{"DEPTH", ::Param::Unpatched::GlobalEffectable::MOD_FX_DEPTH}; - -MenuItem* audioClipModFXMenuItems[] = {&audioClipModFXTypeMenu, &audioClipModFXRateMenu, &modFXFeedbackMenu, - &audioClipModFXDepthMenu, &modFXOffsetMenu, NULL}; -Submenu audioClipModFXMenu{HAVE_OLED ? "Mod-fx" : "MODU", audioClipModFXMenuItems}; +audio_clip::mod_fx::Type audioClipModFXTypeMenu{"TYPE", "MOD FX type"}; +UnpatchedParam audioClipModFXRateMenu{"RATE", "MOD FX rate", ::Param::Unpatched::GlobalEffectable::MOD_FX_RATE}; +UnpatchedParam audioClipModFXDepthMenu{"DEPTH", "MOD FX depth", ::Param::Unpatched::GlobalEffectable::MOD_FX_DEPTH}; + +Submenu audioClipModFXMenu{ + HAVE_OLED ? "Mod-fx" : "MODU", + { + &audioClipModFXTypeMenu, + &audioClipModFXRateMenu, + &modFXFeedbackMenu, + &audioClipModFXDepthMenu, + &modFXOffsetMenu, + }, +}; // Delay Menu -UnpatchedParam audioClipDelayRateMenu{"AMOUNT", ::Param::Unpatched::GlobalEffectable::DELAY_AMOUNT}; -UnpatchedParam audioClipDelayFeedbackMenu{"RATE", ::Param::Unpatched::GlobalEffectable::DELAY_RATE}; - -MenuItem* audioClipDelayMenuItems[] = { - &audioClipDelayFeedbackMenu, &audioClipDelayRateMenu, &delayPingPongMenu, &delayAnalogMenu, &delaySyncMenu, NULL}; -Submenu audioClipDelayMenu{"DELAY", audioClipDelayMenuItems}; +UnpatchedParam audioClipDelayRateMenu{"AMOUNT", "Delay amount", ::Param::Unpatched::GlobalEffectable::DELAY_AMOUNT}; +UnpatchedParam audioClipDelayFeedbackMenu{"RATE", "Delay rate", ::Param::Unpatched::GlobalEffectable::DELAY_RATE}; + +Submenu audioClipDelayMenu{ + "DELAY", + { + &audioClipDelayFeedbackMenu, + &audioClipDelayRateMenu, + &delayPingPongMenu, + &delayAnalogMenu, + &delaySyncMenu, + }, +}; // Reverb Menu -UnpatchedParam audioClipReverbSendAmountMenu{"AMOUNT", ::Param::Unpatched::GlobalEffectable::REVERB_SEND_AMOUNT}; -MenuItem* audioClipReverbMenuItems[] = {&audioClipReverbSendAmountMenu, - &reverbRoomSizeMenu, - &reverbDampeningMenu, - &reverbWidthMenu, - &reverbPanMenu, - &reverbCompressorMenu, - NULL}; -Submenu audioClipReverbMenu{"REVERB", audioClipReverbMenuItems}; +UnpatchedParam audioClipReverbSendAmountMenu{ + "AMOUNT", + "Reverb amount", + ::Param::Unpatched::GlobalEffectable::REVERB_SEND_AMOUNT, +}; +Submenu audioClipReverbMenu{ + "REVERB", + { + &audioClipReverbSendAmountMenu, + &reverbRoomSizeMenu, + &reverbDampeningMenu, + &reverbWidthMenu, + &reverbPanMenu, + &reverbCompressorMenu, + }, +}; // Sidechain menu unpatched_param::UpdatingReverbParams audioClipCompressorVolumeMenu{ "Volume ducking", ::Param::Unpatched::GlobalEffectable::SIDECHAIN_VOLUME}; -MenuItem* audioClipSidechainMenuItems[] = {&audioClipCompressorVolumeMenu, &sidechainSyncMenu, &compressorAttackMenu, - &compressorReleaseMenu, &compressorShapeMenu, NULL}; -Submenu audioClipCompressorMenu{"Sidechain compressor", audioClipSidechainMenuItems}; +Submenu audioClipCompressorMenu{ + "Sidechain compressor", + { + &audioClipCompressorVolumeMenu, + &sidechainSyncMenu, + &compressorAttackMenu, + &compressorReleaseMenu, + &compressorShapeMenu, + }, +}; audio_clip::Transpose audioClipTransposeMenu{"TRANSPOSE"}; audio_clip::Attack audioClipAttackMenu{"ATTACK"}; -MenuItem* audioClipFXMenuItems[] = {&audioClipModFXMenu, &eqMenu, &audioClipDelayMenu, &audioClipReverbMenu, - &clippingMenu, &srrMenu, &bitcrushMenu, NULL}; -Submenu audioClipFXMenu{"FX", audioClipFXMenuItems}; +Submenu audioClipFXMenu{ + "FX", + { + &audioClipModFXMenu, + &eqMenu, + &audioClipDelayMenu, + &audioClipReverbMenu, + &clippingMenu, + &srrMenu, + &bitcrushMenu, + }, +}; UnpatchedParam audioClipLevelMenu{HAVE_OLED ? "Level" : "VOLUME", ::Param::Unpatched::GlobalEffectable::VOLUME}; unpatched_param::Pan audioClipPanMenu{"PAN", ::Param::Unpatched::GlobalEffectable::PAN}; -#define comingSoonMenu (MenuItem*)0xFFFFFFFF - const MenuItem* midiOrCVParamShortcuts[8] = { - &arpRateMenuMIDIOrCV, &arpSyncMenu, &arpGateMenuMIDIOrCV, &arpOctavesMenu, &arpModeMenu, NULL, NULL, NULL, + &arpRateMenuMIDIOrCV, &arpSyncMenu, &arpGateMenuMIDIOrCV, &arpOctavesMenu, &arpModeMenu, nullptr, nullptr, nullptr, }; // Gate stuff -gate::Mode gateModeMenu{}; +gate::Mode gateModeMenu; gate::OffTime gateOffTimeMenu{HAVE_OLED ? "Min. off-time" : ""}; // Root menu // CV Menu -cv::Volts cvVoltsMenu{"Volts per octave"}; -cv::Transpose cvTransposeMenu{"TRANSPOSE"}; +cv::Volts cvVoltsMenu{"Volts per octave", "CV{} V/octave"}; +cv::Transpose cvTransposeMenu{"TRANSPOSE", "CV{} transpose"}; -MenuItem* cvMenuItems[] = {&cvVoltsMenu, &cvTransposeMenu, NULL}; +Submenu<2> cvSubmenu{"", {&cvVoltsMenu, &cvTransposeMenu}}; -Submenu cvSubmenu{"", cvMenuItems}; - -cv::Selection cvSelectionMenu{"CV"}; -gate::Selection gateSelectionMenu{"GATE"}; +cv::Selection cvSelectionMenu{"CV", "CV outputs"}; +gate::Selection gateSelectionMenu{"GATE", "Gate outputs"}; swing::Interval swingIntervalMenu{HAVE_OLED ? "Swing interval" : "SWIN"}; // Pads menu -shortcuts::Version shortcutsVersionMenu{HAVE_OLED ? "Shortcuts version" : "SHOR"}; -menu_item::keyboard::Layout keyboardLayoutMenu{HAVE_OLED ? "Keyboard for text" : "KEYB"}; +shortcuts::Version shortcutsVersionMenu{HAVE_OLED ? "Shortcuts version" : "SHOR", "Shortcuts ver."}; +menu_item::keyboard::Layout keyboardLayoutMenu{HAVE_OLED ? "Keyboard for text" : "KEYB", "Key layout"}; // Colours submenu -MenuItem* coloursMenuItems[] = {&activeColourMenu, &stoppedColourMenu, &mutedColourMenu, &soloColourMenu, NULL}; -Submenu coloursSubmenu{"COLOURS", coloursMenuItems}; +Submenu coloursSubmenu{ + "COLOURS", + { + &activeColourMenu, + &stoppedColourMenu, + &mutedColourMenu, + &soloColourMenu, + }, +}; -static MenuItem* layoutMenuItems[] = {&shortcutsVersionMenu, &keyboardLayoutMenu, &coloursSubmenu, NULL}; -Submenu padsSubmenu{"PADS", layoutMenuItems}; +Submenu padsSubmenu{ + "PADS", + { + &shortcutsVersionMenu, + &keyboardLayoutMenu, + &coloursSubmenu, + }, +}; // Record submenu record::Quantize recordQuantizeMenu{"Quantization"}; record::Margins recordMarginsMenu{HAVE_OLED ? "Loop margins" : "MARGINS"}; -record::CountIn recordCountInMenu{"Count-in"}; -monitor::Mode monitorModeMenu{HAVE_OLED ? "Sampling monitoring" : "MONITORING"}; - -MenuItem* recordMenuItems[] = {&recordCountInMenu, &recordQuantizeMenu, &recordMarginsMenu, &monitorModeMenu, NULL}; -Submenu recordSubmenu{"Recording", recordMenuItems}; +record::CountIn recordCountInMenu{"Count-in", "Rec count-in"}; +monitor::Mode monitorModeMenu{HAVE_OLED ? "Sampling monitoring" : "MONITORING", "Monitoring"}; + +Submenu recordSubmenu{ + "Recording", + { + &recordCountInMenu, + &recordQuantizeMenu, + &recordMarginsMenu, + &monitorModeMenu, + }, +}; sample::browser_preview::Mode sampleBrowserPreviewModeMenu{HAVE_OLED ? "Sample preview" : "PREV"}; flash::Status flashStatusMenu{HAVE_OLED ? "Play-cursor" : "CURS"}; -#ifdef DBT_FW_VERSION_STRING -char const* firmwareString = DBT_FW_VERSION_STRING; -#else -char const* firmwareString = "4.1.4-alpha3-c"; -#endif // ifdef DBT_FW_VERSION_STRING +firmware::Version firmwareVersionMenu{HAVE_OLED ? "Firmware version" : "VER.", "Firmware ver."}; -firmware::Version firmwareVersionMenu{"Firmware version"}; - -runtime_feature::Settings runtimeFeatureSettingsMenu{HAVE_OLED ? "Community fts." : "FEAT"}; +runtime_feature::Settings runtimeFeatureSettingsMenu{HAVE_OLED ? "Community fts." : "FEAT", "Community fts."}; // CV menu @@ -586,78 +678,127 @@ midi::Command undoMidiCommand{"UNDO", GlobalMIDICommand::UNDO}; midi::Command redoMidiCommand{"REDO", GlobalMIDICommand::REDO}; midi::Command loopMidiCommand{"LOOP", GlobalMIDICommand::LOOP}; midi::Command loopContinuousLayeringMidiCommand{"LAYERING loop", GlobalMIDICommand::LOOP_CONTINUOUS_LAYERING}; -MenuItem* midiCommandsMenuItems[] = {&playMidiCommand, - &playbackRestartMidiCommand, - &recordMidiCommand, - &tapMidiCommand, - &undoMidiCommand, - &redoMidiCommand, - &loopMidiCommand, - &loopContinuousLayeringMidiCommand, - NULL}; -Submenu midiCommandsMenu{HAVE_OLED ? "Commands" : "CMD", midiCommandsMenuItems}; + +Submenu midiCommandsMenu{ + HAVE_OLED ? "Commands" : "CMD", + "MIDI commands", + { + &playMidiCommand, + &playbackRestartMidiCommand, + &recordMidiCommand, + &tapMidiCommand, + &undoMidiCommand, + &redoMidiCommand, + &loopMidiCommand, + &loopContinuousLayeringMidiCommand, + }, +}; // MIDI device submenu - for after we've selected which device we want it for midi::DefaultVelocityToLevel defaultVelocityToLevelMenu{"VELOCITY"}; -MenuItem* midiDeviceMenuItems[] = {&mpe::directionSelectorMenu, &defaultVelocityToLevelMenu, NULL}; -Submenu midiDeviceMenu{NULL, midiDeviceMenuItems}; +Submenu midiDeviceMenu{ + "", + { + &mpe::directionSelectorMenu, + &defaultVelocityToLevelMenu, + }, +}; // MIDI input differentiation menu midi::InputDifferentiation midiInputDifferentiationMenu{"Differentiate inputs"}; // MIDI clock menu -midi::ClockOutStatus midiClockOutStatusMenu{HAVE_OLED ? "Output" : "OUT"}; -midi::ClockInStatus midiClockInStatusMenu{HAVE_OLED ? "Input" : "IN"}; -tempo::MagnitudeMatching tempoMagnitudeMatchingMenu{HAVE_OLED ? "Tempo magnitude matching" : "MAGN"}; -MenuItem* midiClockMenuItems[] = {&midiClockInStatusMenu, &midiClockOutStatusMenu, &tempoMagnitudeMatchingMenu, NULL}; -Submenu midiClockMenu{"CLOCK", midiClockMenuItems}; +midi::ClockOutStatus midiClockOutStatusMenu{HAVE_OLED ? "Output" : "OUT", "MIDI clock out"}; +midi::ClockInStatus midiClockInStatusMenu{HAVE_OLED ? "Input" : "IN", "MIDI clock in"}; +tempo::MagnitudeMatching tempoMagnitudeMatchingMenu{HAVE_OLED ? "Tempo magnitude matching" : "MAGN", "Tempo m. match"}; //Midi devices menu -midi::Devices midi::devicesMenu{"Devices"}; +midi::Devices midi::devicesMenu{"Devices", "MIDI devices"}; mpe::DirectionSelector mpe::directionSelectorMenu{"MPE"}; //MIDI menu -MenuItem* midiMenuItems[] = { - &midiClockMenu, &midiThruMenu, &midiTakeoverMenu, &midiCommandsMenu, &midiInputDifferentiationMenu, - &midi::devicesMenu, NULL}; -Submenu midiMenu{"MIDI", midiMenuItems}; +Submenu midiClockMenu{ + "CLOCK", + "MIDI clock", + { + &midiClockInStatusMenu, + &midiClockOutStatusMenu, + &tempoMagnitudeMatchingMenu, + }, +}; +Submenu midiMenu{ + "MIDI", + { + &midiClockMenu, + &midiThruMenu, + &midiTakeoverMenu, + &midiCommandsMenu, + &midiInputDifferentiationMenu, + &midi::devicesMenu, + }, +}; +// Clock menu // Trigger clock in menu -trigger::in::PPQN triggerInPPQNMenu{"PPQN"}; +trigger::in::PPQN triggerInPPQNMenu{"PPQN", "Input PPQN"}; trigger::in::AutoStart triggerInAutoStartMenu{"Auto-start"}; -MenuItem* triggerClockInMenuItems[] = {&triggerInPPQNMenu, &triggerInAutoStartMenu, nullptr}; +Submenu triggerClockInMenu{ + HAVE_OLED ? "Input" : "IN", + "T. clock input", + { + &triggerInPPQNMenu, + &triggerInAutoStartMenu, + }, +}; // Trigger clock out menu -trigger::out::PPQN triggerOutPPQNMenu{"PPQN"}; -MenuItem* triggerClockOutMenuItems[] = {&triggerOutPPQNMenu, nullptr}; - -// Clock menu -Submenu triggerClockInMenu{HAVE_OLED ? "Input" : "IN", triggerClockInMenuItems}; -Submenu triggerClockOutMenu{HAVE_OLED ? "Output" : "OUT", triggerClockOutMenuItems}; +trigger::out::PPQN triggerOutPPQNMenu{"PPQN", "Output PPQN"}; +Submenu triggerClockOutMenu{ + HAVE_OLED ? "Output" : "OUT", + "T. clock out", + { + &triggerOutPPQNMenu, + }, +}; // Trigger clock menu -MenuItem* triggerClockMenuItems[] = {&triggerClockInMenu, &triggerClockOutMenu, NULL}; -Submenu triggerClockMenu{HAVE_OLED ? "Trigger clock" : "TCLOCK", triggerClockMenuItems}; +Submenu triggerClockMenu{ + HAVE_OLED ? "Trigger clock" : "TCLOCK", + { + &triggerClockInMenu, + &triggerClockOutMenu, + }, +}; // Defaults menu -IntegerRange defaultTempoMenu{"TEMPO", 60, 240}; -IntegerRange defaultSwingMenu{"SWING", 1, 99}; -KeyRange defaultKeyMenu{"KEY"}; -defaults::Scale defaultScaleMenu{"SCALE"}; -defaults::Velocity defaultVelocityMenu{"VELOCITY"}; -defaults::Magnitude defaultMagnitudeMenu{"RESOLUTION"}; -defaults::BendRange defaultBendRangeMenu{"Bend range"}; -MenuItem* defaultsMenuItems[] = {&defaultTempoMenu, &defaultSwingMenu, &defaultKeyMenu, &defaultScaleMenu, - &defaultVelocityMenu, &defaultMagnitudeMenu, &defaultBendRangeMenu, NULL}; - -Submenu defaultsSubmenu{"DEFAULTS", defaultsMenuItems}; +IntegerRange defaultTempoMenu{"TEMPO", "Default tempo", 60, 240}; +IntegerRange defaultSwingMenu{"SWING", "Default swing", 1, 99}; +KeyRange defaultKeyMenu{"KEY", "Default key"}; +defaults::Scale defaultScaleMenu{"SCALE", "Default scale"}; +defaults::Velocity defaultVelocityMenu{"VELOCITY", "Default veloc."}; +defaults::Magnitude defaultMagnitudeMenu{"RESOLUTION", "Default resol."}; +defaults::BendRange defaultBendRangeMenu{"Bend range", "Default bend r"}; + +Submenu defaultsSubmenu{ + "DEFAULTS", + { + &defaultTempoMenu, + &defaultSwingMenu, + &defaultKeyMenu, + &defaultScaleMenu, + &defaultVelocityMenu, + &defaultMagnitudeMenu, + &defaultBendRangeMenu, + }, +}; // Sound editor menu ----------------------------------------------------------------------------- // FM only -MenuItem* modulatorMenuItems[] = {&modulatorVolume, &modulatorTransposeMenu, &modulatorFeedbackMenu, - &modulatorDestMenu, &modulatorPhaseMenu, NULL}; +MenuItem* modulatorMenuItems[] = { + &modulatorVolume, &modulatorTransposeMenu, &modulatorFeedbackMenu, &modulatorDestMenu, &modulatorPhaseMenu, +}; submenu::Modulator modulator0Menu{HAVE_OLED ? "FM modulator 1" : "MOD1", modulatorMenuItems, 0}; submenu::Modulator modulator1Menu{HAVE_OLED ? "FM modulator 2" : "MOD2", modulatorMenuItems, 1}; @@ -665,7 +806,7 @@ submenu::Modulator modulator1Menu{HAVE_OLED ? "FM modulator 2" : "MOD2", modulat // Not FM patched_param::IntegerNonFM noiseMenu{HAVE_OLED ? "Noise level" : "NOISE", ::Param::Local::NOISE_VOLUME}; -MasterTranspose masterTransposeMenu{HAVE_OLED ? "Master transpose" : "TRANSPOSE"}; +MasterTranspose masterTransposeMenu{HAVE_OLED ? "Master transpose" : "TRANSPOSE", "Master tran."}; patch_cable_strength::Fixed vibratoMenu{"VIBRATO", ::Param::Local::PITCH_ADJUST, PatchSource::LFO_GLOBAL}; @@ -675,256 +816,166 @@ menu_item::DrumName drumNameMenu{"NAME"}; // Synth only menu_item::SynthMode synthModeMenu{HAVE_OLED ? "Synth mode" : "MODE"}; -Submenu lfo0Menu{"LFO1", lfo1MenuItems}; -Submenu lfo1Menu{"LFO2", lfo2MenuItems}; - -Submenu voiceMenu{"VOICE", voiceMenuItems}; -Submenu fxMenu{"FX", fxMenuItems}; -submenu::Compressor compressorMenu{"Sidechain compressor", sidechainMenuItemsForSound, false}; - -submenu::Bend bendMenu{"Bend range", bendMenuItems}; // The submenu bend_range::PerFinger drumBendRangeMenu{"Bend range"}; // The single option available for Drums -patched_param::Integer volumeMenu{HAVE_OLED ? "Level" : "VOLUME", ::Param::Global::VOLUME_POST_FX}; +patched_param::Integer volumeMenu{HAVE_OLED ? "Level" : "VOLUME", "Master level", ::Param::Global::VOLUME_POST_FX}; patched_param::Pan panMenu{"PAN", ::Param::Local::PAN}; -MenuItem* soundEditorRootMenuItems[] = {&source0Menu, - &source1Menu, - &modulator0Menu, - &modulator1Menu, - &noiseMenu, - &masterTransposeMenu, - &vibratoMenu, - &lpfMenu, - &hpfMenu, - &drumNameMenu, - &synthModeMenu, - &env0Menu, - &env1Menu, - &lfo0Menu, - &lfo1Menu, - &voiceMenu, - &fxMenu, - &compressorMenu, - &bendMenu, - &drumBendRangeMenu, - &volumeMenu, - &panMenu, - &sequenceDirectionMenu, - NULL}; - -menu_item::Submenu soundEditorRootMenu{"Sound", soundEditorRootMenuItems}; +menu_item::Submenu soundEditorRootMenu{ + "Sound", + { + &source0Menu, + &source1Menu, + &modulator0Menu, + &modulator1Menu, + &noiseMenu, + &masterTransposeMenu, + &vibratoMenu, + &lpfMenu, + &hpfMenu, + &drumNameMenu, + &synthModeMenu, + &env0Menu, + &env1Menu, + &lfo0Menu, + &lfo1Menu, + &voiceMenu, + &fxMenu, + &compressorMenu, + &bendMenu, + &drumBendRangeMenu, + &volumeMenu, + &panMenu, + &sequenceDirectionMenu, + }, +}; // Root menu for MIDI / CV -MenuItem* soundEditorRootMenuItemsMIDIOrCV[] = {&midiPGMMenu, &midiBankMenu, &midiSubMenu, &arpMenu, - &bendMenu, &sequenceDirectionMenu, NULL}; - -menu_item::Submenu soundEditorRootMenuMIDIOrCV{"MIDI inst.", soundEditorRootMenuItemsMIDIOrCV}; +menu_item::Submenu soundEditorRootMenuMIDIOrCV{ + "MIDI inst.", + { + &midiPGMMenu, + &midiBankMenu, + &midiSubMenu, + &arpMenu, + &bendMenu, + &sequenceDirectionMenu, + }, +}; // Root menu for AudioClips -MenuItem* soundEditorRootMenuItemsAudioClip[] = {&audioClipSampleMenu, - &audioClipTransposeMenu, - &audioClipLPFMenu, - &audioClipHPFMenu, - &audioClipAttackMenu, - &priorityMenu, - &audioClipFXMenu, - &audioClipCompressorMenu, - &audioClipLevelMenu, - &audioClipPanMenu, - NULL}; -menu_item::Submenu soundEditorRootMenuAudioClip{"Audio clip", soundEditorRootMenuItemsAudioClip}; +menu_item::Submenu soundEditorRootMenuAudioClip{ + "Audio clip", + { + &audioClipSampleMenu, + &audioClipTransposeMenu, + &audioClipLPFMenu, + &audioClipHPFMenu, + &audioClipAttackMenu, + &priorityMenu, + &audioClipFXMenu, + &audioClipCompressorMenu, + &audioClipLevelMenu, + &audioClipPanMenu, + }, +}; // Root Menu -MenuItem* rootSettingsMenuItems[] = {&cvSelectionMenu, - &gateSelectionMenu, - &triggerClockMenu, - &midiMenu, - &defaultsSubmenu, - &swingIntervalMenu, - &padsSubmenu, - &sampleBrowserPreviewModeMenu, - &flashStatusMenu, - &recordSubmenu, - &runtimeFeatureSettingsMenu, - &firmwareVersionMenu, - NULL}; -Submenu settingsRootMenu{"Settings", rootSettingsMenuItems}; +Submenu settingsRootMenu{ + "Settings", + { + &cvSelectionMenu, + &gateSelectionMenu, + &triggerClockMenu, + &midiMenu, + &defaultsSubmenu, + &swingIntervalMenu, + &padsSubmenu, + &sampleBrowserPreviewModeMenu, + &flashStatusMenu, + &recordSubmenu, + &runtimeFeatureSettingsMenu, + &firmwareVersionMenu, + }, +}; + +#define comingSoonMenu reinterpret_cast(0xFFFFFFFF) +// clang-format off MenuItem* paramShortcutsForSounds[][8] = { - // Post V3 - {&sampleRepeatMenu, &sampleReverseMenu, &timeStretchMenu, &samplePitchSpeedMenu, &audioRecorderMenu, - &fileSelectorMenu, &interpolationMenu, &sampleStartMenu}, - {&sampleRepeatMenu, &sampleReverseMenu, &timeStretchMenu, &samplePitchSpeedMenu, &audioRecorderMenu, - &fileSelectorMenu, &interpolationMenu, &sampleStartMenu}, - {&sourceVolumeMenu, &sourceTransposeMenu, &oscTypeMenu, &pulseWidthMenu, &oscPhaseMenu, &sourceFeedbackMenu, - &sourceWaveIndexMenu, &noiseMenu}, - {&sourceVolumeMenu, &sourceTransposeMenu, &oscTypeMenu, &pulseWidthMenu, &oscPhaseMenu, &sourceFeedbackMenu, - &sourceWaveIndexMenu, &oscSyncMenu}, - {&modulatorVolume, &modulatorTransposeMenu, comingSoonMenu, comingSoonMenu, &modulatorPhaseMenu, - &modulatorFeedbackMenu, comingSoonMenu, &sequenceDirectionMenu}, - {&modulatorVolume, &modulatorTransposeMenu, comingSoonMenu, comingSoonMenu, &modulatorPhaseMenu, - &modulatorFeedbackMenu, &modulatorDestMenu, NULL}, - {&volumeMenu, &masterTransposeMenu, &vibratoMenu, &panMenu, &synthModeMenu, &srrMenu, &bitcrushMenu, &clippingMenu}, - {&portaMenu, &polyphonyMenu, &priorityMenu, &unisonDetuneMenu, &numUnisonMenu, NULL, NULL, NULL}, - {&envReleaseMenu, &envSustainMenu, &envDecayMenu, &envAttackMenu, NULL, &lpfModeMenu, &lpfResMenu, &lpfFreqMenu}, - {&envReleaseMenu, &envSustainMenu, &envDecayMenu, &envAttackMenu, NULL, comingSoonMenu, &hpfResMenu, &hpfFreqMenu}, - {&compressorReleaseMenu, &sidechainSyncMenu, &compressorVolumeShortcutMenu, &compressorAttackMenu, - &compressorShapeMenu, &sidechainSendMenu, &bassMenu, &bassFreqMenu}, - {&arpRateMenu, &arpSyncMenu, &arpGateMenu, &arpOctavesMenu, &arpModeMenu, &drumNameMenu, &trebleMenu, - &trebleFreqMenu}, - {&lfo1RateMenu, &lfo1SyncMenu, &lfo1TypeMenu, &modFXTypeMenu, &modFXOffsetMenu, &modFXFeedbackMenu, &modFXDepthMenu, - &modFXRateMenu}, - {&lfo2RateMenu, comingSoonMenu, &lfo2TypeMenu, &reverbAmountMenu, &reverbPanMenu, &reverbWidthMenu, - &reverbDampeningMenu, &reverbRoomSizeMenu}, - {&delayRateMenu, &delaySyncMenu, &delayAnalogMenu, &delayFeedbackMenu, &delayPingPongMenu, NULL, NULL, NULL}}; + // Post V3 + {&sampleRepeatMenu, &sampleReverseMenu, &timeStretchMenu, &samplePitchSpeedMenu, &audioRecorderMenu, &fileSelectorMenu, &interpolationMenu, &sampleStartMenu }, + {&sampleRepeatMenu, &sampleReverseMenu, &timeStretchMenu, &samplePitchSpeedMenu, &audioRecorderMenu, &fileSelectorMenu, &interpolationMenu, &sampleStartMenu }, + {&sourceVolumeMenu, &sourceTransposeMenu, &oscTypeMenu, &pulseWidthMenu, &oscPhaseMenu, &sourceFeedbackMenu, &sourceWaveIndexMenu, &noiseMenu }, + {&sourceVolumeMenu, &sourceTransposeMenu, &oscTypeMenu, &pulseWidthMenu, &oscPhaseMenu, &sourceFeedbackMenu, &sourceWaveIndexMenu, &oscSyncMenu }, + {&modulatorVolume, &modulatorTransposeMenu, comingSoonMenu, comingSoonMenu, &modulatorPhaseMenu, &modulatorFeedbackMenu, comingSoonMenu, &sequenceDirectionMenu}, + {&modulatorVolume, &modulatorTransposeMenu, comingSoonMenu, comingSoonMenu, &modulatorPhaseMenu, &modulatorFeedbackMenu, &modulatorDestMenu, NULL }, + {&volumeMenu, &masterTransposeMenu, &vibratoMenu, &panMenu, &synthModeMenu, &srrMenu, &bitcrushMenu, &clippingMenu }, + {&portaMenu, &polyphonyMenu, &priorityMenu, &unisonDetuneMenu, &numUnisonMenu, nullptr, nullptr, NULL }, + {&envReleaseMenu, &envSustainMenu, &envDecayMenu, &envAttackMenu, nullptr, &lpfModeMenu, &lpfResMenu, &lpfFreqMenu }, + {&envReleaseMenu, &envSustainMenu, &envDecayMenu, &envAttackMenu, nullptr, comingSoonMenu, &hpfResMenu, &hpfFreqMenu }, + {&compressorReleaseMenu, &sidechainSyncMenu, &compressorVolumeShortcutMenu, &compressorAttackMenu, &compressorShapeMenu, &sidechainSendMenu, &bassMenu, &bassFreqMenu }, + {&arpRateMenu, &arpSyncMenu, &arpGateMenu, &arpOctavesMenu, &arpModeMenu, &drumNameMenu, &trebleMenu, &trebleFreqMenu }, + {&lfo1RateMenu, &lfo1SyncMenu, &lfo1TypeMenu, &modFXTypeMenu, &modFXOffsetMenu, &modFXFeedbackMenu, &modFXDepthMenu, &modFXRateMenu }, + {&lfo2RateMenu, comingSoonMenu, &lfo2TypeMenu, &reverbAmountMenu, &reverbPanMenu, &reverbWidthMenu, &reverbDampeningMenu, &reverbRoomSizeMenu }, + {&delayRateMenu, &delaySyncMenu, &delayAnalogMenu, &delayFeedbackMenu, &delayPingPongMenu, nullptr, nullptr, NULL }, +}; MenuItem* paramShortcutsForAudioClips[][8] = { - {NULL, &audioClipReverseMenu, NULL, &samplePitchSpeedMenu, NULL, &fileSelectorMenu, &interpolationMenu, - &audioClipSampleMarkerEditorMenuEnd}, - {NULL, &audioClipReverseMenu, NULL, &samplePitchSpeedMenu, NULL, &fileSelectorMenu, &interpolationMenu, - &audioClipSampleMarkerEditorMenuEnd}, - {&audioClipLevelMenu, &audioClipTransposeMenu, NULL, NULL, NULL, NULL, NULL, NULL}, - {&audioClipLevelMenu, &audioClipTransposeMenu, NULL, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, - {&audioClipLevelMenu, &audioClipTransposeMenu, NULL, &audioClipPanMenu, NULL, &srrMenu, &bitcrushMenu, - &clippingMenu}, - {NULL, NULL, &priorityMenu, NULL, NULL, NULL, NULL, NULL}, - {NULL, NULL, NULL, &audioClipAttackMenu, NULL, &lpfModeMenu, &audioClipLPFResMenu, &audioClipLPFFreqMenu}, - {NULL, NULL, NULL, &audioClipAttackMenu, NULL, comingSoonMenu, &audioClipHPFResMenu, &audioClipHPFFreqMenu}, - {&compressorReleaseMenu, &sidechainSyncMenu, &audioClipCompressorVolumeMenu, &compressorAttackMenu, - &compressorShapeMenu, NULL, &bassMenu, &bassFreqMenu}, - {NULL, NULL, NULL, NULL, NULL, NULL, &trebleMenu, &trebleFreqMenu}, - {NULL, NULL, NULL, &audioClipModFXTypeMenu, &modFXOffsetMenu, &modFXFeedbackMenu, &audioClipModFXDepthMenu, - &audioClipModFXRateMenu}, - {NULL, NULL, NULL, &audioClipReverbSendAmountMenu, &reverbPanMenu, &reverbWidthMenu, &reverbDampeningMenu, - &reverbRoomSizeMenu}, - {&audioClipDelayRateMenu, &delaySyncMenu, &delayAnalogMenu, &audioClipDelayFeedbackMenu, &delayPingPongMenu, NULL, - NULL, NULL}}; + {nullptr, &audioClipReverseMenu, nullptr, &samplePitchSpeedMenu, nullptr, &fileSelectorMenu, &interpolationMenu, &audioClipSampleMarkerEditorMenuEnd}, + {nullptr, &audioClipReverseMenu, nullptr, &samplePitchSpeedMenu, nullptr, &fileSelectorMenu, &interpolationMenu, &audioClipSampleMarkerEditorMenuEnd}, + {&audioClipLevelMenu, &audioClipTransposeMenu, nullptr, nullptr, nullptr, nullptr, nullptr, NULL }, + {&audioClipLevelMenu, &audioClipTransposeMenu, nullptr, nullptr, nullptr, nullptr, nullptr, NULL }, + {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, NULL }, + {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, NULL }, + {&audioClipLevelMenu, &audioClipTransposeMenu, nullptr, &audioClipPanMenu, nullptr, &srrMenu, &bitcrushMenu, &clippingMenu }, + {nullptr, nullptr, &priorityMenu, nullptr, nullptr, nullptr, nullptr, NULL }, + {nullptr, nullptr, nullptr, &audioClipAttackMenu, nullptr, &lpfModeMenu, &audioClipLPFResMenu, &audioClipLPFFreqMenu }, + {nullptr, nullptr, nullptr, &audioClipAttackMenu, nullptr, comingSoonMenu, &audioClipHPFResMenu, &audioClipHPFFreqMenu }, + {&compressorReleaseMenu, &sidechainSyncMenu, &audioClipCompressorVolumeMenu, &compressorAttackMenu, &compressorShapeMenu, nullptr, &bassMenu, &bassFreqMenu }, + {nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, &trebleMenu, &trebleFreqMenu }, + {nullptr, nullptr, nullptr, &audioClipModFXTypeMenu, &modFXOffsetMenu, &modFXFeedbackMenu, &audioClipModFXDepthMenu, &audioClipModFXRateMenu }, + {nullptr, nullptr, nullptr, &audioClipReverbSendAmountMenu, &reverbPanMenu, &reverbWidthMenu, &reverbDampeningMenu, &reverbRoomSizeMenu }, + {&audioClipDelayRateMenu, &delaySyncMenu, &delayAnalogMenu, &audioClipDelayFeedbackMenu, &delayPingPongMenu, nullptr, nullptr, NULL }, +}; +//clang-format on #if HAVE_OLED -void init_menu_titles() { - triggerClockInMenu.basicTitle = "T. clock input"; - triggerClockOutMenu.basicTitle = "T. clock out"; - triggerInPPQNMenu.basicTitle = "Input PPQN"; - triggerOutPPQNMenu.basicTitle = "Output PPQN"; - - midiClockMenu.basicTitle = "MIDI clock"; - midiClockInStatusMenu.basicTitle = "MIDI clock in"; - midiClockOutStatusMenu.basicTitle = "MIDI clock out"; - tempoMagnitudeMatchingMenu.basicTitle = "Tempo m. match"; - midiCommandsMenu.basicTitle = "MIDI commands"; - midi::devicesMenu.basicTitle = "MIDI devices"; - - defaultTempoMenu.basicTitle = "Default tempo"; - defaultSwingMenu.basicTitle = "Default swing"; - defaultKeyMenu.basicTitle = "Default key"; - defaultScaleMenu.basicTitle = "Default scale"; - defaultVelocityMenu.basicTitle = "Default veloc."; - defaultMagnitudeMenu.basicTitle = "Default resol."; - defaultBendRangeMenu.basicTitle = "Default bend r"; - - shortcutsVersionMenu.basicTitle = "Shortcuts ver."; - keyboardLayoutMenu.basicTitle = "Key layout"; - - recordCountInMenu.basicTitle = "Rec count-in"; - monitorModeMenu.basicTitle = "Monitoring"; - runtimeFeatureSettingsMenu.basicTitle = "Community fts."; - firmwareVersionMenu.basicTitle = "Firmware ver."; - - reverbAmountMenu.basicTitle = "Reverb amount"; - reverbWidthMenu.basicTitle = "Reverb width"; - reverbPanMenu.basicTitle = "Reverb pan"; - reverbCompressorMenu.basicTitle = "Reverb sidech."; - - sidechainSendMenu.basicTitle = "Send to sidech"; - sidechainSyncMenu.basicTitle = "Sidechain sync"; - compressorAttackMenu.basicTitle = "Sidech. attack"; - compressorReleaseMenu.basicTitle = "Sidech release"; - compressorShapeMenu.basicTitle = "Sidech. shape"; - reverbCompressorShapeMenu.basicTitle = "Sidech. shape"; - - modFXTypeMenu.basicTitle = "MOD FX type"; - modFXRateMenu.basicTitle = "MOD FX rate"; - modFXFeedbackMenu.basicTitle = "MODFX feedback"; - modFXDepthMenu.basicTitle = "MOD FX depth"; - modFXOffsetMenu.basicTitle = "MOD FX offset"; - - delayFeedbackMenu.basicTitle = "Delay amount"; - delayRateMenu.basicTitle = "Delay rate"; - delayPingPongMenu.basicTitle = "Delay pingpong"; - delayAnalogMenu.basicTitle = "Delay type"; - delaySyncMenu.basicTitle = "Delay sync"; - - lfo1TypeMenu.basicTitle = "LFO1 type"; - lfo1RateMenu.basicTitle = "LFO1 rate"; - lfo1SyncMenu.basicTitle = "LFO1 sync"; - - lfo2TypeMenu.basicTitle = "LFO2 type"; - lfo2RateMenu.basicTitle = "LFO2 rate"; - - oscTypeMenu.basicTitle = oscTypeTitle; - sourceVolumeMenu.basicTitle = oscLevelTitle; - sourceWaveIndexMenu.basicTitle = waveIndexTitle; - sourceFeedbackMenu.basicTitle = carrierFeedback; - sampleReverseMenu.basicTitle = sampleReverseTitle; - sampleRepeatMenu.basicTitle = sampleModeTitle; - sourceTransposeMenu.basicTitle = oscTransposeTitle; - timeStretchMenu.basicTitle = sampleSpeedTitle; - interpolationMenu.basicTitle = sampleInterpolationTitle; - pulseWidthMenu.basicTitle = pulseWidthTitle; - oscPhaseMenu.basicTitle = retriggerPhaseTitle; - - modulatorTransposeMenu.basicTitle = modulatorTransposeTitle; - modulatorDestMenu.basicTitle = "FM Mod2 dest."; - modulatorVolume.basicTitle = modulatorLevelTitle; - modulatorFeedbackMenu.basicTitle = modulatorFeedbackTitle; - modulatorPhaseMenu.basicTitle = modulatorRetriggerPhaseTitle; - - lpfFreqMenu.basicTitle = "LPF frequency"; - lpfResMenu.basicTitle = "LPF resonance"; - lpfModeMenu.basicTitle = "LPF mode"; - - hpfFreqMenu.basicTitle = "HPF frequency"; - hpfResMenu.basicTitle = "HPF resonance"; - - envAttackMenu.basicTitle = attackTitle; - envDecayMenu.basicTitle = decayTitle; - envSustainMenu.basicTitle = sustainTitle; - envReleaseMenu.basicTitle = releaseTitle; - - arpModeMenu.basicTitle = "Arp. mode"; - arpSyncMenu.basicTitle = "Arp. sync"; - arpOctavesMenu.basicTitle = "Arp. octaves"; - arpGateMenu.basicTitle = "Arp. gate"; - arpGateMenuMIDIOrCV.basicTitle = "Arp. gate"; - arpRateMenu.basicTitle = "Arp. rate"; - arpRateMenuMIDIOrCV.basicTitle = "Arp. rate"; - - masterTransposeMenu.basicTitle = "Master tran."; - compressorMenu.basicTitle = "Sidechain comp"; - volumeMenu.basicTitle = "Master level"; - - midiBankMenu.basicTitle = "MIDI bank"; - midiSubMenu.basicTitle = "MIDI sub-bank"; - midiPGMMenu.basicTitle = "MIDI PGM numb."; - - audioClipReverbSendAmountMenu.basicTitle = "Reverb amount"; - - audioClipDelayFeedbackMenu.basicTitle = "Delay amount"; - audioClipDelayRateMenu.basicTitle = "Delay rate"; - - audioClipModFXTypeMenu.basicTitle = "MOD FX type"; - audioClipModFXRateMenu.basicTitle = "MOD FX rate"; - audioClipModFXDepthMenu.basicTitle = "MOD FX depth"; - - audioClipLPFFreqMenu.basicTitle = "LPF frequency"; - audioClipLPFResMenu.basicTitle = "LPF resonance"; - - audioClipHPFFreqMenu.basicTitle = "HPF frequency"; - audioClipHPFResMenu.basicTitle = "HPF resonance"; - - cvVoltsMenu.basicTitle = cvVoltsTitle; - cvTransposeMenu.basicTitle = cvTransposeTitle; +void setOscillatorNumberForTitles(int32_t num) { + num += 1; + oscTypeMenu.format(num); + sourceVolumeMenu.format(num); + sourceWaveIndexMenu.format(num); + sourceTransposeMenu.format(num); + pulseWidthMenu.format(num); + oscPhaseMenu.format(num); + + sourceFeedbackMenu.format(num); + + sampleReverseMenu.format(num); + sampleRepeatMenu.format(num); + timeStretchMenu.format(num); + interpolationMenu.format(num); +} + +void setEnvelopeNumberForTitles(int32_t num) { + num += 1; + envAttackMenu.format(num); + envDecayMenu.format(num); + envSustainMenu.format(num); + envReleaseMenu.format(num); +} + +void setModulatorNumberForTitles(int32_t num) { + num += 1; + modulatorTransposeMenu.format(num); + modulatorVolume.format(num); + modulatorFeedbackMenu.format(num); + modulatorPhaseMenu.format(num); +} + +void setCvNumberForTitle(int32_t num) { + num += 1; + cvVoltsMenu.format(num); + cvTransposeMenu.format(num); } #endif diff --git a/src/deluge/gui/ui/menus.h b/src/deluge/gui/ui/menus.h index 220b6d3fba..2320d0e0e2 100644 --- a/src/deluge/gui/ui/menus.h +++ b/src/deluge/gui/ui/menus.h @@ -13,24 +13,24 @@ #include "gui/menu_item/sequence/direction.h" #include "gui/menu_item/submenu.h" -extern menu_item::dev_var::AMenu devVarAMenu; +extern deluge::gui::menu_item::dev_var::AMenu devVarAMenu; -extern menu_item::patched_param::IntegerNonFM noiseMenu; -extern menu_item::osc::Sync oscSyncMenu; -extern menu_item::osc::source::WaveIndex sourceWaveIndexMenu; +extern deluge::gui::menu_item::patched_param::IntegerNonFM noiseMenu; +extern deluge::gui::menu_item::osc::Sync oscSyncMenu; +extern deluge::gui::menu_item::osc::source::WaveIndex sourceWaveIndexMenu; -extern menu_item::sample::Start sampleStartMenu; -extern menu_item::sample::End sampleEndMenu; -extern menu_item::audio_clip::SampleMarkerEditor audioClipSampleMarkerEditorMenuStart; -extern menu_item::audio_clip::SampleMarkerEditor audioClipSampleMarkerEditorMenuEnd; +extern deluge::gui::menu_item::sample::Start sampleStartMenu; +extern deluge::gui::menu_item::sample::End sampleEndMenu; +extern deluge::gui::menu_item::audio_clip::SampleMarkerEditor audioClipSampleMarkerEditorMenuStart; +extern deluge::gui::menu_item::audio_clip::SampleMarkerEditor audioClipSampleMarkerEditorMenuEnd; extern DrumName drumNameMenu; -extern menu_item::firmware::Version firmwareVersionMenu; -extern menu_item::sequence::Direction sequenceDirectionMenu; -extern menu_item::Submenu soundEditorRootMenuMIDIOrCV; -extern menu_item::Submenu soundEditorRootMenuAudioClip; -extern menu_item::Submenu soundEditorRootMenu; -extern menu_item::Submenu settingsRootMenu; +extern deluge::gui::menu_item::firmware::Version firmwareVersionMenu; +extern deluge::gui::menu_item::sequence::Direction sequenceDirectionMenu; +extern deluge::gui::menu_item::Submenu<6> soundEditorRootMenuMIDIOrCV; +extern deluge::gui::menu_item::Submenu<10> soundEditorRootMenuAudioClip; +extern deluge::gui::menu_item::Submenu<23> soundEditorRootMenu; +extern deluge::gui::menu_item::Submenu<12> settingsRootMenu; extern MenuItem* midiOrCVParamShortcuts[8]; extern MenuItem* paramShortcutsForSounds[15][8]; @@ -39,4 +39,3 @@ extern MenuItem* paramShortcutsForAudioClips[15][8]; void setOscillatorNumberForTitles(int32_t); void setModulatorNumberForTitles(int32_t); void setEnvelopeNumberForTitles(int32_t); -void init_menu_titles(); diff --git a/src/deluge/gui/ui/sound_editor.cpp b/src/deluge/gui/ui/sound_editor.cpp index a41d06b4d0..e02d92a1b7 100644 --- a/src/deluge/gui/ui/sound_editor.cpp +++ b/src/deluge/gui/ui/sound_editor.cpp @@ -61,7 +61,8 @@ extern "C" { #include "menus.h" using namespace deluge; -using namespace menu_item; +using namespace deluge::gui; +using namespace deluge::gui::menu_item; #define comingSoonMenu (MenuItem*)0xFFFFFFFF @@ -135,10 +136,6 @@ SoundEditor::SoundEditor() { memset(sourceShortcutBlinkFrequencies, 255, sizeof(sourceShortcutBlinkFrequencies)); timeLastAttemptedAutomatedParamEdit = 0; shouldGoUpOneLevelOnBegin = false; - -#if HAVE_OLED - init_menu_titles(); -#endif } bool SoundEditor::editingKit() { @@ -1036,14 +1033,14 @@ bool SoundEditor::setup(Clip* clip, const MenuItem* item, int32_t sourceIndex) { if (clip->type == CLIP_TYPE_INSTRUMENT) { if (currentSong->currentClip->output->type == InstrumentType::MIDI_OUT) { #if HAVE_OLED - soundEditorRootMenuMIDIOrCV.basicTitle = "MIDI inst."; + soundEditorRootMenuMIDIOrCV.title = "MIDI inst."; #endif doMIDIOrCV: newItem = &soundEditorRootMenuMIDIOrCV; } else if (currentSong->currentClip->output->type == InstrumentType::CV) { #if HAVE_OLED - soundEditorRootMenuMIDIOrCV.basicTitle = "CV instrument"; + soundEditorRootMenuMIDIOrCV.title = "CV instrument"; #endif goto doMIDIOrCV; } diff --git a/src/deluge/gui/ui/sound_editor.h b/src/deluge/gui/ui/sound_editor.h index 787f1ca871..3c013146b0 100644 --- a/src/deluge/gui/ui/sound_editor.h +++ b/src/deluge/gui/ui/sound_editor.h @@ -45,7 +45,7 @@ class ModControllableAudio; class ModelStackWithThreeMainThings; class AudioFileHolder; class MIDIDevice; -namespace menu_item { +namespace deluge::gui::menu_item { enum class RangeEdit : uint8_t; } @@ -67,7 +67,7 @@ class SoundEditor final : public UI { VoicePriority* currentPriority; int16_t currentMultiRangeIndex; MIDIDevice* currentMIDIDevice; - menu_item::RangeEdit editingRangeEdge; + deluge::gui::menu_item::RangeEdit editingRangeEdge; ActionResult buttonAction(hid::Button b, bool on, bool inCardRoutine); ActionResult padAction(int32_t x, int32_t y, int32_t velocity); @@ -78,7 +78,6 @@ class SoundEditor final : public UI { void setupShortcutBlink(int32_t x, int32_t y, int32_t frequency); - int32_t currentValue; int32_t menuCurrentScroll; uint8_t navigationDepth; @@ -100,8 +99,6 @@ class SoundEditor final : public UI { MenuItem* menuItemNavigationRecord[16]; - MenuItem** currentSubmenuItem; - bool shouldGoUpOneLevelOnBegin; bool midiCCReceived(MIDIDevice* fromDevice, uint8_t channel, uint8_t ccNumber, uint8_t value); diff --git a/src/deluge/gui/views/clip_view.cpp b/src/deluge/gui/views/clip_view.cpp index ad26937216..a5a09d4540 100644 --- a/src/deluge/gui/views/clip_view.cpp +++ b/src/deluge/gui/views/clip_view.cpp @@ -134,7 +134,7 @@ Action* ClipView::shortenClip(int32_t newLength) { currentSong->setClipLength( getCurrentClip(), newLength, action); // Subsequently shortening by more squares won't cause additional Consequences to be added to the same - // Action - it checks, and only stores the data (snapshots and original length) once + // Action - it checks, and only stores the data (snapshots and original length) once return action; } diff --git a/src/deluge/gui/views/instrument_clip_view.cpp b/src/deluge/gui/views/instrument_clip_view.cpp index 72954b02e7..039b6a269e 100644 --- a/src/deluge/gui/views/instrument_clip_view.cpp +++ b/src/deluge/gui/views/instrument_clip_view.cpp @@ -89,6 +89,8 @@ extern "C" { #include "util/cfunctions.h" } +using namespace deluge::gui; + InstrumentClipView instrumentClipView{}; InstrumentClipView::InstrumentClipView() { diff --git a/src/deluge/gui/waveform/waveform_basic_navigator.cpp b/src/deluge/gui/waveform/waveform_basic_navigator.cpp index 121ef6ab79..e95f3fc1c0 100644 --- a/src/deluge/gui/waveform/waveform_basic_navigator.cpp +++ b/src/deluge/gui/waveform/waveform_basic_navigator.cpp @@ -198,7 +198,7 @@ bool WaveformBasicNavigator::zoom(int32_t offset, bool shouldAllowExtraScrollRig PadLEDs::clearTickSquares( false); // We were mostly fine without this here, but putting it here fixed weird problem where tick squares would - // appear when zooming into waveform in SampleBrowser + // appear when zooming into waveform in SampleBrowser waveformRenderer.renderFullScreen(sample, xScroll, xZoom, &PadLEDs::imageStore[storeOffset], &renderData); diff --git a/src/deluge/hid/led/pad_leds.cpp b/src/deluge/hid/led/pad_leds.cpp index adf4a63d64..2cb51d3984 100644 --- a/src/deluge/hid/led/pad_leds.cpp +++ b/src/deluge/hid/led/pad_leds.cpp @@ -41,6 +41,8 @@ extern "C" { #include "RZA1/uart/sio_char.h" } +using namespace deluge; + namespace PadLEDs { uint8_t image[kDisplayHeight][kDisplayWidth + kSideBarWidth][3]; // 255 = full brightness uint8_t occupancyMask[kDisplayHeight][kDisplayWidth + kSideBarWidth]; // 64 = full occupancy @@ -177,7 +179,7 @@ void setTickSquares(const uint8_t* squares, const uint8_t* colours) { int32_t colour = 0; if (colours[y] == 1) { // "Muted" colour uint8_t mutedColour[3]; - menu_item::mutedColourMenu.getRGB(mutedColour); + gui::menu_item::mutedColourMenu.getRGB(mutedColour); for (int32_t c = 0; c < 3; c++) { if (mutedColour[c] >= 64) { colour += (1 << c); @@ -258,7 +260,7 @@ void sendRGBForOnePadFast(int32_t x, int32_t y, const uint8_t* colourSource) { if (flashCursor == FLASH_CURSOR_SLOW && slowFlashSquares[y] == x && currentUIMode != UI_MODE_HORIZONTAL_SCROLL) { if (slowFlashColours[y] == 1) { // If it's to be the "muted" colour, get that - menu_item::mutedColourMenu.getRGB(temp); + gui::menu_item::mutedColourMenu.getRGB(temp); colourSource = temp; } else { // Otherwise, pull from a referenced table line diff --git a/src/deluge/memory/fallback_allocator.h b/src/deluge/memory/fallback_allocator.h index fca8a065f5..1535961787 100644 --- a/src/deluge/memory/fallback_allocator.h +++ b/src/deluge/memory/fallback_allocator.h @@ -24,11 +24,10 @@ class fallback_allocator { if (n == 0) { return nullptr; } - return static_cast( - GeneralMemoryAllocator::get().alloc(n * sizeof(T), nullptr, false, true, false, nullptr, false)); + return static_cast(delugeAlloc(n * sizeof(T))); } - void deallocate(T* p, std::size_t n) { GeneralMemoryAllocator::get().dealloc(p); } + void deallocate(T* p, std::size_t n) { delugeDealloc(p); } template bool operator==(const deluge::memory::fallback_allocator& o) { diff --git a/src/deluge/memory/general_memory_allocator.cpp b/src/deluge/memory/general_memory_allocator.cpp index 0404c41033..3356332b24 100644 --- a/src/deluge/memory/general_memory_allocator.cpp +++ b/src/deluge/memory/general_memory_allocator.cpp @@ -76,7 +76,7 @@ uint32_t totalMallocTime = 0; int32_t numMallocTimes = 0; #endif -extern "C" void* delugeAlloc(int32_t requiredSize) { +extern "C" void* delugeAlloc(unsigned int requiredSize) { return GeneralMemoryAllocator::get().alloc(requiredSize, NULL, false, true); } diff --git a/src/deluge/memory/general_memory_allocator.h b/src/deluge/memory/general_memory_allocator.h index bbef9a0a20..3640025f65 100644 --- a/src/deluge/memory/general_memory_allocator.h +++ b/src/deluge/memory/general_memory_allocator.h @@ -89,3 +89,8 @@ class GeneralMemoryAllocator { private: void checkEverythingOk(char const* errorString); }; + +extern "C" { +void* delugeAlloc(unsigned int requiredSize); +void delugeDealloc(void* address); +} diff --git a/src/deluge/memory/operators.cpp b/src/deluge/memory/operators.cpp new file mode 100644 index 0000000000..547754005d --- /dev/null +++ b/src/deluge/memory/operators.cpp @@ -0,0 +1,10 @@ +#include "memory/general_memory_allocator.h" +#include + +void* operator new(std::size_t n) noexcept(false) { + delugeAlloc(n); +} + +void operator delete(void* p) { + delugeDealloc(p); +} diff --git a/src/deluge/model/clip/clip.cpp b/src/deluge/model/clip/clip.cpp index 3824cb23e8..7c124c0136 100644 --- a/src/deluge/model/clip/clip.cpp +++ b/src/deluge/model/clip/clip.cpp @@ -371,7 +371,7 @@ bool Clip::opportunityToBeginSessionLinearRecording(ModelStackWithTimelineCounte Action* action = actionLogger.getNewAction( ACTION_RECORD, true); // Allow addition to existing Action - one might have already been created because - // note recorded slightly early just before end of count-in + // note recorded slightly early just before end of count-in if (isPendingOverdub) { *newOutputCreated = cloneOutput(modelStack); diff --git a/src/deluge/model/clip/instrument_clip.cpp b/src/deluge/model/clip/instrument_clip.cpp index 26c31974dd..8f69d09282 100644 --- a/src/deluge/model/clip/instrument_clip.cpp +++ b/src/deluge/model/clip/instrument_clip.cpp @@ -390,7 +390,7 @@ void InstrumentClip::setPos(ModelStackWithTimelineCounter* modelStack, int32_t n Clip::setPosForParamManagers( modelStack, useActualPosForParamManagers); // Call on Clip:: only - below in this function, we're going to do the equivalent - // of our own setPosForParamManagers(). + // of our own setPosForParamManagers(). uint32_t posForParamManagers = useActualPosForParamManagers ? getLivePos() : lastProcessedPos; @@ -2377,7 +2377,9 @@ int32_t InstrumentClip::readFromFile(Song* song) { } else if (!strcmp(tagName, "keyboardLayout")) { - keyboardState.currentLayout = (keyboard::KeyboardLayoutType)storageManager.readTagOrAttributeValueInt(); + // TODO: Unscope this once namespacing is complete + keyboardState.currentLayout = + (deluge::gui::ui::keyboard::KeyboardLayoutType)storageManager.readTagOrAttributeValueInt(); } else if (!strcmp(tagName, "yScrollKeyboard")) { diff --git a/src/deluge/model/clip/instrument_clip.h b/src/deluge/model/clip/instrument_clip.h index d70756b74b..f06a77f5b2 100644 --- a/src/deluge/model/clip/instrument_clip.h +++ b/src/deluge/model/clip/instrument_clip.h @@ -114,7 +114,8 @@ class InstrumentClip final : public Clip { int32_t yScroll; - keyboard::KeyboardState keyboardState; + // TODO: Unscope this once namespacing is done + deluge::gui::ui::keyboard::KeyboardState keyboardState; int32_t ticksTilNextNoteRowEvent; int32_t noteRowsNumTicksBehindClip; diff --git a/src/deluge/model/sample/sample.cpp b/src/deluge/model/sample/sample.cpp index 9f57a60437..96ce982597 100644 --- a/src/deluge/model/sample/sample.cpp +++ b/src/deluge/model/sample/sample.cpp @@ -450,7 +450,7 @@ int32_t Sample::fillPercCache(TimeStretcher* timeStretcher, int32_t startPosSamp error = percCacheZones[reversed].insertAtIndex( i, 1, this); // Tell it not to steal other perc cache zones from this Sample, which would result in modification of the same array during operation. - // Fortunately it also has a lock to alert if that actually somehow happened, too. + // Fortunately it also has a lock to alert if that actually somehow happened, too. if (error) { LOCK_EXIT return error; diff --git a/src/deluge/model/sample/sample_playback_guide.h b/src/deluge/model/sample/sample_playback_guide.h index 87742bc8c5..75dd04a203 100644 --- a/src/deluge/model/sample/sample_playback_guide.h +++ b/src/deluge/model/sample/sample_playback_guide.h @@ -17,6 +17,7 @@ #pragma once +#include #include class SampleHolder; @@ -27,7 +28,7 @@ class AudioFileHolder; class SamplePlaybackGuide { public: SamplePlaybackGuide(); - int32_t getFinalClusterIndex(Sample* sample, bool obeyMarkers, int32_t* getEndPlaybackAtByte = NULL); + int32_t getFinalClusterIndex(Sample* sample, bool obeyMarkers, int32_t* getEndPlaybackAtByte = nullptr); virtual int32_t getBytePosToStartPlayback(bool justLooped) { return startPlaybackAtByte; } virtual int32_t getBytePosToEndOrLoopPlayback() { return endPlaybackAtByte; diff --git a/src/deluge/model/settings/runtime_feature_settings.cpp b/src/deluge/model/settings/runtime_feature_settings.cpp index dc6cc35497..0aad055194 100644 --- a/src/deluge/model/settings/runtime_feature_settings.cpp +++ b/src/deluge/model/settings/runtime_feature_settings.cpp @@ -16,10 +16,10 @@ */ #include "runtime_feature_settings.h" +#include "util/d_string.h" +#include #include #include -#include -#include #include "hid/display/numeric_driver.h" #include "storage/storage_manager.h" @@ -32,7 +32,7 @@ /// Unknown Settings container struct UnknownSetting { - String name; + deluge::string name; uint32_t value; }; @@ -41,25 +41,21 @@ RuntimeFeatureSettings runtimeFeatureSettings{}; RuntimeFeatureSettings::RuntimeFeatureSettings() : unknownSettings(sizeof(UnknownSetting)) { } -static void SetupOnOffSetting(RuntimeFeatureSetting& setting, char const* const displayName, char const* const xmlName, - RuntimeFeatureStateToggle def) { +static void SetupOnOffSetting(RuntimeFeatureSetting& setting, const deluge::string& displayName, + const deluge::string& xmlName, RuntimeFeatureStateToggle def) { setting.displayName = displayName; setting.xmlName = xmlName; setting.value = static_cast(def); - setting.options[0] = { - .displayName = "Off", - .value = RuntimeFeatureStateToggle::Off, - }; - - setting.options[1] = { - .displayName = "On", - .value = RuntimeFeatureStateToggle::On, - }; - - setting.options[2] = { - .displayName = NULL, - .value = 0, + setting.options = { + { + .displayName = "Off", + .value = RuntimeFeatureStateToggle::Off, + }, + { + .displayName = "On", + .value = RuntimeFeatureStateToggle::On, + }, }; } @@ -101,14 +97,14 @@ void RuntimeFeatureSettings::readSettingsFromFile() { String currentName; int32_t currentValue = 0; - char const* currentTag; + char const* currentTag = nullptr; while (*(currentTag = storageManager.readNextTagOrAttributeName())) { if (strcmp(currentTag, TAG_RUNTIME_FEATURE_SETTING) == 0) { // Read name currentTag = storageManager.readNextTagOrAttributeName(); if (strcmp(currentTag, TAG_RUNTIME_FEATURE_SETTING_ATTR_NAME) != 0) { numericDriver.displayPopup("Community file err"); - goto readEnd; + break; } storageManager.readTagOrAttributeValueString(¤tName); storageManager.exitTag(); @@ -117,16 +113,16 @@ void RuntimeFeatureSettings::readSettingsFromFile() { currentTag = storageManager.readNextTagOrAttributeName(); if (strcmp(currentTag, TAG_RUNTIME_FEATURE_SETTING_ATTR_VALUE) != 0) { numericDriver.displayPopup("Community file err"); - goto readEnd; + break; } currentValue = storageManager.readTagOrAttributeValueInt(); storageManager.exitTag(); bool found = false; - for (uint32_t idxSetting = 0; idxSetting < RuntimeFeatureSettingType::MaxElement; ++idxSetting) { - if (strcmp(settings[idxSetting].xmlName, currentName.get()) == 0) { + for (auto& setting : settings) { + if (strcmp(setting.xmlName.c_str(), currentName.get()) == 0) { found = true; - settings[idxSetting].value = currentValue; + setting.value = currentValue; } } @@ -138,8 +134,8 @@ void RuntimeFeatureSettings::readSettingsFromFile() { return; } void* address = unknownSettings.getElementAddress(idx); - UnknownSetting* unknownSetting = new (address) UnknownSetting(); - unknownSetting->name.set(¤tName); + auto* unknownSetting = new (address) UnknownSetting(); + unknownSetting->name = deluge::string(currentName.get()); unknownSetting->value = currentValue; } } @@ -147,7 +143,6 @@ void RuntimeFeatureSettings::readSettingsFromFile() { storageManager.exitTag(); } -readEnd: storageManager.closeFile(); } @@ -164,19 +159,19 @@ void RuntimeFeatureSettings::writeSettingsToFile() { storageManager.writeEarliestCompatibleFirmwareVersion("4.1.3"); storageManager.writeOpeningTagEnd(); - for (uint32_t idxSetting = 0; idxSetting < RuntimeFeatureSettingType::MaxElement; ++idxSetting) { + for (auto& setting : settings) { storageManager.writeOpeningTagBeginning(TAG_RUNTIME_FEATURE_SETTING); - storageManager.writeAttribute(TAG_RUNTIME_FEATURE_SETTING_ATTR_NAME, settings[idxSetting].xmlName, false); - storageManager.writeAttribute(TAG_RUNTIME_FEATURE_SETTING_ATTR_VALUE, settings[idxSetting].value, false); + storageManager.writeAttribute(TAG_RUNTIME_FEATURE_SETTING_ATTR_NAME, setting.xmlName.c_str(), false); + storageManager.writeAttribute(TAG_RUNTIME_FEATURE_SETTING_ATTR_VALUE, setting.value, false); storageManager.writeOpeningTagEnd(false); storageManager.writeClosingTag(TAG_RUNTIME_FEATURE_SETTING, false); } // Write unknown elements - for (uint32_t idxUnknownSetting; idxUnknownSetting < unknownSettings.getNumElements(); idxUnknownSetting++) { + for (uint32_t idxUnknownSetting = 0; idxUnknownSetting < unknownSettings.getNumElements(); idxUnknownSetting++) { UnknownSetting* unknownSetting = (UnknownSetting*)unknownSettings.getElementAddress(idxUnknownSetting); storageManager.writeOpeningTagBeginning(TAG_RUNTIME_FEATURE_SETTING); - storageManager.writeAttribute(TAG_RUNTIME_FEATURE_SETTING_ATTR_NAME, unknownSetting->name.get(), false); + storageManager.writeAttribute(TAG_RUNTIME_FEATURE_SETTING_ATTR_NAME, unknownSetting->name.c_str(), false); storageManager.writeAttribute(TAG_RUNTIME_FEATURE_SETTING_ATTR_VALUE, unknownSetting->value, false); storageManager.writeOpeningTagEnd(false); storageManager.writeClosingTag(TAG_RUNTIME_FEATURE_SETTING, false); diff --git a/src/deluge/model/settings/runtime_feature_settings.h b/src/deluge/model/settings/runtime_feature_settings.h index 4f0f51ab30..0ad1edc5e6 100644 --- a/src/deluge/model/settings/runtime_feature_settings.h +++ b/src/deluge/model/settings/runtime_feature_settings.h @@ -18,15 +18,14 @@ #pragma once #include "util/container/array/resizeable_array.h" -#include "util/d_string.h" +#include "util/container/static_vector.hpp" +#include "util/string.h" #include -#define RUNTIME_FEATURE_SETTING_MAX_OPTIONS 8 - -namespace menu_item::runtime_feature { +namespace deluge::gui::menu_item::runtime_feature { class Setting; class Settings; -} // namespace menu_item::runtime_feature +} // namespace deluge::gui::menu_item::runtime_feature // State declarations enum RuntimeFeatureStateToggle : uint32_t { Off = 0, On = 1 }; @@ -47,16 +46,18 @@ enum RuntimeFeatureSettingType : uint32_t { /// Definition for selectable options struct RuntimeFeatureSettingOption { - const char* displayName; + deluge::string displayName; uint32_t value; // Value to be defined as typed Enum above }; /// Every setting keeps its metadata and value in here struct RuntimeFeatureSetting { - const char* displayName; - const char* xmlName; + deluge::string displayName; + deluge::string xmlName; uint32_t value; - RuntimeFeatureSettingOption options[RUNTIME_FEATURE_SETTING_MAX_OPTIONS]; // Limited to safe memory + + // Limited to safe memory + deluge::static_vector options; }; /// Encapsulating class @@ -72,14 +73,14 @@ class RuntimeFeatureSettings { void writeSettingsToFile(); protected: - RuntimeFeatureSetting settings[RuntimeFeatureSettingType::MaxElement] = {}; + std::array settings = {}; private: ResizeableArray unknownSettings; public: - friend class menu_item::runtime_feature::Setting; - friend class menu_item::runtime_feature::Settings; + friend class deluge::gui::menu_item::runtime_feature::Setting; + friend class deluge::gui::menu_item::runtime_feature::Settings; }; /// Static instance for external access diff --git a/src/deluge/model/song/song.cpp b/src/deluge/model/song/song.cpp index eeaac5dff1..c79c34cef5 100644 --- a/src/deluge/model/song/song.cpp +++ b/src/deluge/model/song/song.cpp @@ -72,6 +72,8 @@ extern "C" { #include "RZA1/uart/sio_char.h" } +using namespace deluge; + Song::Song() : backedUpParamManagers(sizeof(BackedUpParamManager)) { outputClipInstanceListIsCurrentlyInvalid = false; insideWorldTickMagnitude = FlashStorage::defaultMagnitude; @@ -177,9 +179,9 @@ Song::~Song() { #include "gui/menu_item/integer_range.h" #include "gui/menu_item/key_range.h" -extern menu_item::IntegerRange defaultTempoMenu; -extern menu_item::IntegerRange defaultSwingMenu; -extern menu_item::KeyRange defaultKeyMenu; +extern gui::menu_item::IntegerRange defaultTempoMenu; +extern gui::menu_item::IntegerRange defaultSwingMenu; +extern gui::menu_item::KeyRange defaultKeyMenu; void Song::setupDefault() { inClipMinderViewOnLoad = true; diff --git a/src/deluge/modulation/automation/copied_param_automation.cpp b/src/deluge/modulation/automation/copied_param_automation.cpp deleted file mode 100644 index 94a0e14f6a..0000000000 --- a/src/deluge/modulation/automation/copied_param_automation.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Copyright © 2018-2023 Synthstrom Audible Limited - * - * This file is part of The Synthstrom Audible Deluge Firmware. - * - * The Synthstrom Audible Deluge Firmware is free software: you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free Software Foundation, - * either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with this program. - * If not, see . -*/ - -#include "modulation/automation/copied_param_automation.h" - -CopiedParamAutomation::CopiedParamAutomation() { - nodes = NULL; - numNodes = 0; -} - -CopiedParamAutomation::~CopiedParamAutomation() { -} diff --git a/src/deluge/modulation/automation/copied_param_automation.h b/src/deluge/modulation/automation/copied_param_automation.h index 3fbc712d6e..0e3c302bb8 100644 --- a/src/deluge/modulation/automation/copied_param_automation.h +++ b/src/deluge/modulation/automation/copied_param_automation.h @@ -23,10 +23,10 @@ class ParamNode; class CopiedParamAutomation { public: - CopiedParamAutomation(); - virtual ~CopiedParamAutomation(); + CopiedParamAutomation() = default; + virtual ~CopiedParamAutomation() = default; int32_t width; - ParamNode* nodes; - int32_t numNodes; + ParamNode* nodes = nullptr; + int32_t numNodes = 0; }; diff --git a/src/deluge/modulation/params/param_descriptor.h b/src/deluge/modulation/params/param_descriptor.h index 40d668aa2b..f0bcd2b644 100644 --- a/src/deluge/modulation/params/param_descriptor.h +++ b/src/deluge/modulation/params/param_descriptor.h @@ -23,38 +23,38 @@ class ParamDescriptor { public: - inline void setToHaveParamOnly(int32_t p) { data = p | 0xFFFFFF00; } + ParamDescriptor() = default; + constexpr void setToHaveParamOnly(int32_t p) { data = p | 0xFFFFFF00; } - inline void setToHaveParamAndSource(int32_t p, PatchSource s) { + constexpr void setToHaveParamAndSource(int32_t p, PatchSource s) { data = p | (util::to_underlying(s) << 8) | 0xFFFF0000; } - inline void setToHaveParamAndTwoSources(int32_t p, PatchSource s, PatchSource sLowestLevel) { + constexpr void setToHaveParamAndTwoSources(int32_t p, PatchSource s, PatchSource sLowestLevel) { data = p | (util::to_underlying(s) << 8) | (util::to_underlying(sLowestLevel) << 16) | 0xFF000000; } - inline bool isSetToParamWithNoSource(int32_t p) { return (data == (p | 0xFFFFFF00)); } + [[nodiscard]] constexpr bool isSetToParamWithNoSource(int32_t p) const { return (data == (p | 0xFFFFFF00)); } - inline bool isSetToParamAndSource(int32_t p, PatchSource s) { + [[nodiscard]] constexpr inline bool isSetToParamAndSource(int32_t p, PatchSource s) const { return (data == (p | (util::to_underlying(s) << 8) | 0xFFFF0000)); } - inline bool isJustAParam() { return (data & 0x0000FF00) == 0x0000FF00; } + [[nodiscard]] constexpr bool isJustAParam() const { return (data & 0x0000FF00) == 0x0000FF00; } - inline int32_t getJustTheParam() { return data & 0xFF; } + [[nodiscard]] constexpr int32_t getJustTheParam() const { return data & 0xFF; } - inline void changeParam(int32_t newParam) { data = (data & 0xFFFFFF00) | newParam; } + constexpr void changeParam(int32_t newParam) { data = (data & 0xFFFFFF00) | newParam; } - inline PatchSource getBottomLevelSource() { // As in, the one furthest away from the param. + [[nodiscard]] constexpr PatchSource getBottomLevelSource() const { // As in, the one furthest away from the param. if ((data & 0x00FF0000) == 0x00FF0000) { return static_cast((data >> 8) & 0xFF); } - else { - return static_cast((data >> 16) & 0xFF); - } + + return static_cast((data >> 16) & 0xFF); } - inline void addSource(PatchSource newSource) { + constexpr void addSource(PatchSource newSource) { uint8_t newSourceUnderlying = util::to_underlying(newSource); if ((data & 0x0000FF00) == 0x0000FF00) { data = (data & 0xFFFF00FF) | (newSourceUnderlying << 8); @@ -67,8 +67,8 @@ class ParamDescriptor { } } - inline ParamDescriptor getDestination() { - ParamDescriptor newParamDescriptor; + [[nodiscard]] constexpr ParamDescriptor getDestination() const { + ParamDescriptor newParamDescriptor{}; if ((data & 0x00FF0000) == 0x00FF0000) { newParamDescriptor.data = data | 0x0000FF00; } @@ -78,28 +78,30 @@ class ParamDescriptor { return newParamDescriptor; } - inline bool hasJustOneSource() { + [[nodiscard]] constexpr bool hasJustOneSource() const { return ((data & 0xFFFF0000) == 0xFFFF0000) && ((data & 0x0000FF00) != 0x0000FF00); } - inline PatchSource getTopLevelSource() { // As in, the one, nearest the param. + [[nodiscard]] constexpr PatchSource getTopLevelSource() const { // As in, the one, nearest the param. return static_cast((data & 0x0000FF00) >> 8); } - inline PatchSource getSecondSourceFromTop() { return static_cast((data & 0x00FF0000) >> 16); } + [[nodiscard]] constexpr PatchSource getSecondSourceFromTop() const { + return static_cast((data & 0x00FF0000) >> 16); + } - inline bool hasSecondSource() { return ((data & 0x00FF0000) != 0x00FF0000); } + [[nodiscard]] constexpr bool hasSecondSource() const { return ((data & 0x00FF0000) != 0x00FF0000); } - inline void setToNull() { data = 0xFFFFFFFF; } + constexpr void setToNull() { data = 0xFFFFFFFF; } - inline bool isNull() { return (data == 0xFFFFFFFF); } + [[nodiscard]] constexpr bool isNull() const { return (data == 0xFFFFFFFF); } - uint32_t data; + uint32_t data{0}; }; -inline bool operator==(const ParamDescriptor& lhs, const ParamDescriptor& rhs) { +constexpr bool operator==(const ParamDescriptor& lhs, const ParamDescriptor& rhs) { return (lhs.data == rhs.data); } -inline bool operator!=(const ParamDescriptor& lhs, const ParamDescriptor& rhs) { +constexpr bool operator!=(const ParamDescriptor& lhs, const ParamDescriptor& rhs) { return !(lhs == rhs); } diff --git a/src/deluge/modulation/patch/patch_cable_set.cpp b/src/deluge/modulation/patch/patch_cable_set.cpp index 83cc5fb834..ee301180b8 100644 --- a/src/deluge/modulation/patch/patch_cable_set.cpp +++ b/src/deluge/modulation/patch/patch_cable_set.cpp @@ -274,8 +274,8 @@ void PatchCableSet::setupPatching(ModelStackWithParamCollection const* modelStac sizeof(Destination), 32, destinations [globality]); // Pretty sure 32 is right? Was previously 16, which I guess worked because we - // currently only have "destinations" containing up to one source and one param - // (i.e. the destination is another cable, whose range/depth we're controlling). + // currently only have "destinations" containing up to one source and one param + // (i.e. the destination is another cable, whose range/depth we're controlling). quickSorter.sort(numDestinations[globality]); } diff --git a/src/deluge/playback/mode/arrangement.h b/src/deluge/playback/mode/arrangement.h index 9c069d9c7f..d0e3d55412 100644 --- a/src/deluge/playback/mode/arrangement.h +++ b/src/deluge/playback/mode/arrangement.h @@ -49,7 +49,7 @@ class Arrangement final : public PlaybackMode { ClipInstance* clipInstanceAdded); int32_t doUniqueCloneOnClipInstance(ClipInstance* clipInstance, int32_t newLength = -1, bool shouldCloneRepeats = false); - int32_t getLivePos(uint32_t* timeRemainder = NULL); + int32_t getLivePos(uint32_t* timeRemainder = nullptr); void endAnyLinearRecording(); int32_t lastProcessedPos; diff --git a/src/deluge/storage/flash_storage.cpp b/src/deluge/storage/flash_storage.cpp index 6c949ce05a..0f18236fec 100644 --- a/src/deluge/storage/flash_storage.cpp +++ b/src/deluge/storage/flash_storage.cpp @@ -33,9 +33,12 @@ extern "C" { #include "gui/menu_item/integer_range.h" #include "gui/menu_item/key_range.h" -extern menu_item::IntegerRange defaultTempoMenu; -extern menu_item::IntegerRange defaultSwingMenu; -extern menu_item::KeyRange defaultKeyMenu; + +using namespace deluge; + +extern gui::menu_item::IntegerRange defaultTempoMenu; +extern gui::menu_item::IntegerRange defaultSwingMenu; +extern gui::menu_item::KeyRange defaultKeyMenu; namespace FlashStorage { @@ -176,10 +179,10 @@ void resetSettings() { defaultVelocity = 64; - menu_item::activeColourMenu.value = 1; // Green - menu_item::stoppedColourMenu.value = 0; // Red - menu_item::mutedColourMenu.value = 3; // Yellow - menu_item::soloColourMenu.value = 2; // Blue + gui::menu_item::activeColourMenu.value = 1; // Green + gui::menu_item::stoppedColourMenu.value = 0; // Red + gui::menu_item::mutedColourMenu.value = 3; // Yellow + gui::menu_item::soloColourMenu.value = 2; // Blue defaultMagnitude = 2; @@ -324,34 +327,34 @@ void readSettings() { } if (previouslySavedByFirmwareVersion < FIRMWARE_3P1P0_ALPHA) { - menu_item::activeColourMenu.value = 1; // Green - menu_item::stoppedColourMenu.value = 0; // Red - menu_item::mutedColourMenu.value = 3; // Yellow - menu_item::soloColourMenu.value = 2; // Blue + gui::menu_item::activeColourMenu.value = 1; // Green + gui::menu_item::stoppedColourMenu.value = 0; // Red + gui::menu_item::mutedColourMenu.value = 3; // Yellow + gui::menu_item::soloColourMenu.value = 2; // Blue defaultMagnitude = 2; MIDIDeviceManager::differentiatingInputsByDevice = false; } else { - menu_item::activeColourMenu.value = buffer[74]; - menu_item::stoppedColourMenu.value = buffer[75]; - menu_item::mutedColourMenu.value = buffer[76]; - menu_item::soloColourMenu.value = buffer[77]; + gui::menu_item::activeColourMenu.value = buffer[74]; + gui::menu_item::stoppedColourMenu.value = buffer[75]; + gui::menu_item::mutedColourMenu.value = buffer[76]; + gui::menu_item::soloColourMenu.value = buffer[77]; defaultMagnitude = buffer[78]; MIDIDeviceManager::differentiatingInputsByDevice = buffer[79]; if (previouslySavedByFirmwareVersion == FIRMWARE_3P1P0_ALPHA) { // Could surely delete this code? - if (!menu_item::activeColourMenu.value) { - menu_item::activeColourMenu.value = 1; + if (!gui::menu_item::activeColourMenu.value) { + gui::menu_item::activeColourMenu.value = 1; } - if (!menu_item::mutedColourMenu.value) { - menu_item::mutedColourMenu.value = 3; + if (!gui::menu_item::mutedColourMenu.value) { + gui::menu_item::mutedColourMenu.value = 3; } - if (!menu_item::soloColourMenu.value) { - menu_item::soloColourMenu.value = 2; + if (!gui::menu_item::soloColourMenu.value) { + gui::menu_item::soloColourMenu.value = 2; } if (!defaultMagnitude) { @@ -456,10 +459,10 @@ void writeSettings() { buffer[73] = defaultVelocity; - buffer[74] = menu_item::activeColourMenu.value; - buffer[75] = menu_item::stoppedColourMenu.value; - buffer[76] = menu_item::mutedColourMenu.value; - buffer[77] = menu_item::soloColourMenu.value; + buffer[74] = gui::menu_item::activeColourMenu.value; + buffer[75] = gui::menu_item::stoppedColourMenu.value; + buffer[76] = gui::menu_item::mutedColourMenu.value; + buffer[77] = gui::menu_item::soloColourMenu.value; buffer[78] = defaultMagnitude; buffer[79] = MIDIDeviceManager::differentiatingInputsByDevice; diff --git a/src/deluge/storage/wave_table/wave_table_band_data.h b/src/deluge/storage/wave_table/wave_table_band_data.h index 9ae4190452..ce2b08aac7 100644 --- a/src/deluge/storage/wave_table/wave_table_band_data.h +++ b/src/deluge/storage/wave_table/wave_table_band_data.h @@ -25,7 +25,7 @@ class WaveTableBandData final : public Stealable { public: WaveTableBandData(WaveTable* newWaveTable); - bool mayBeStolen(void* thingNotToStealFrom = NULL); + bool mayBeStolen(void* thingNotToStealFrom = nullptr); void steal(char const* errorCode); int32_t getAppropriateQueue(); diff --git a/src/deluge/testing/automated_tester.h b/src/deluge/testing/automated_tester.h index ab9e6b7a55..af64df8e38 100644 --- a/src/deluge/testing/automated_tester.h +++ b/src/deluge/testing/automated_tester.h @@ -16,6 +16,7 @@ */ #pragma once +#include namespace AutomatedTester { void init(); diff --git a/src/deluge/util/container/hashtable/open_addressing_hash_table.h b/src/deluge/util/container/hashtable/open_addressing_hash_table.h index 1e4ea21195..3d610b6290 100644 --- a/src/deluge/util/container/hashtable/open_addressing_hash_table.h +++ b/src/deluge/util/container/hashtable/open_addressing_hash_table.h @@ -29,7 +29,7 @@ class OpenAddressingHashTable { int32_t getBucketIndex(uint32_t key); void* getBucketAddress(int32_t b); void* secondaryMemoryGetBucketAddress(int32_t b); - void* insert(uint32_t key, bool* onlyIfNotAlreadyPresent = NULL); + void* insert(uint32_t key, bool* onlyIfNotAlreadyPresent = nullptr); void* lookup(uint32_t key); bool remove(uint32_t key); void test(); diff --git a/src/deluge/util/container/static_vector.hpp b/src/deluge/util/container/static_vector.hpp new file mode 100644 index 0000000000..030d828a79 --- /dev/null +++ b/src/deluge/util/container/static_vector.hpp @@ -0,0 +1,965 @@ +#pragma once +/// \file +/// +/// Dynamically-resizable vector with fixed-capacity. +/// +/// Copyright Gonzalo Brito Gadeschi 2015-2017 +/// Copyright Eric Niebler 2013-2014 +/// Copyright Casey Carter 2016 +/// +/// This file is released under the Boost Software License: +// +// Boost Software License - Version 1.0 - August 17th, 2003 +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// +// Some of the code has been adapted from the range-v3 library: +// +// https://github.com/ericniebler/range-v3/ +// +// which is also under the Boost Software license. +// +// Some of the code has been adapted from libc++: +// +// and is annotated with "adapted from libc++" below, and is thus under the +// following license: +// +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +#include +#include // for size_t +#include // for fixed-width integer types +#include // for assertion diagnostics +#include // for less and equal_to +#include // for reverse_iterator and iterator traits +#include // for numeric_limits +#include // for length_error +#include // for aligned_storage and all meta-functions + +/// Optimizer allowed to assume that EXPR evaluates to true +#define SV_ASSUME(EXPR) static_cast((EXPR) ? void(0) : __builtin_unreachable()) + +/// Assert pretty printer +#define SV_ASSERT(...) \ + static_cast((__VA_ARGS__) \ + ? void(0) \ + : ::deluge::sv_detail::assert_failure(static_cast(__FILE__), __LINE__, \ + "assertion failed: " #__VA_ARGS__)) + +/// Expect asserts the condition in debug builds and assumes the condition to be +/// true in release builds. +#if defined(NDEBUG) || 1 +#define SV_EXPECT(EXPR) SV_ASSUME(EXPR) +#else +#define SV_EXPECT(EXPR) SV_ASSERT(EXPR) +#endif + +namespace deluge { +// Private utilites (each std lib should already have this) +namespace sv_detail { +/// \name Utilities +///@{ + +template +[[noreturn]] void assert_failure(char const* file, int line, char const* msg) { + fprintf(stderr, "%s(%d): %s\n", file, line, msg); + abort(); +} + +template +using range_iterator_t = decltype(std::begin(std::declval())); + +template +using iterator_reference_t = typename std::iterator_traits::reference; + +// clang-format off + +/// Smallest fixed-width unsigned integer type that can represent +/// values in the range [0, N]. +template +using smallest_size_t + = std::conditional_t<(N < std::numeric_limits::max()), uint8_t, + std::conditional_t<(N < std::numeric_limits::max()), uint16_t, + std::conditional_t<(N < std::numeric_limits::max()), uint32_t, + std::conditional_t<(N < std::numeric_limits::max()), uint64_t, + size_t>>>>; +// clang-format on + +///@} // Utilities + +/// Types implementing the `fixed_capactiy_vector`'s storage +namespace storage { +/// Storage for zero elements. +template +struct zero_sized { + using size_type = uint8_t; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using const_pointer = T const*; + + /// Pointer to the data in the storage. + static constexpr pointer data() noexcept { return nullptr; } + /// Number of elements currently stored. + static constexpr size_type size() noexcept { return 0; } + /// Capacity of the storage. + static constexpr size_type capacity() noexcept { return 0; } + /// Is the storage empty? + static constexpr bool empty() noexcept { return true; } + /// Is the storage full? + static constexpr bool full() noexcept { return true; } + + /// Constructs a new element at the end of the storage + /// in-place. + /// + /// Increases size of the storage by one. + /// Always fails for empty storage. + template + requires std::constructible_from + static constexpr void emplace_back(Args&&...) noexcept { + SV_EXPECT(false && "tried to emplace_back on empty storage"); + } + /// Removes the last element of the storage. + /// Always fails for empty storage. + static constexpr void pop_back() noexcept { SV_EXPECT(false && "tried to pop_back on empty storage"); } + /// Changes the size of the storage without adding or + /// removing elements (unsafe). + /// + /// The size of an empty storage can only be changed to 0. + static constexpr void unsafe_set_size(size_t new_size) noexcept { + SV_EXPECT(new_size == 0 + && "tried to change size of empty storage to " + "non-zero value"); + } + + /// Destroys all elements of the storage in range [begin, + /// end) without changings its size (unsafe). + /// + /// Nothing to destroy since the storage is empty. + template + static constexpr void unsafe_destroy(InputIt /* begin */, InputIt /* end */) noexcept {} + + /// Destroys all elements of the storage without changing + /// its size (unsafe). + /// + /// Nothing to destroy since the storage is empty. + static constexpr void unsafe_destroy_all() noexcept {} + + constexpr zero_sized() = default; + constexpr zero_sized(zero_sized const&) = default; + constexpr zero_sized& operator=(zero_sized const&) = default; + constexpr zero_sized(zero_sized&&) = default; + constexpr zero_sized& operator=(zero_sized&&) = default; + ~zero_sized() = default; + + /// Constructs an empty storage from an initializer list of + /// zero elements. + template + requires std::convertible_to + constexpr zero_sized(std::initializer_list il) noexcept { + SV_EXPECT(il.size() == 0 + && "tried to construct storage::empty from a " + "non-empty initializer list"); + } +}; + +/// Storage for trivial types. +template +struct trivial { + static_assert(std::is_trivial_v, "storage::trivial requires std::is_trivial_v"); + static_assert(Capacity != size_t{0}, "Capacity must be greater " + "than zero (use " + "storage::zero_sized instead)"); + + using size_type = smallest_size_t; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using const_pointer = T const*; + +private: + // If the value_type is const, make a const array of + // non-const elements: + using data_t = std::conditional_t, std::array, + const std::array, Capacity>>; + alignas(alignof(T)) data_t data_{}; + + /// Number of elements allocated in the storage: + size_type size_ = 0; + +public: + /// Direct access to the underlying storage. + /// + /// Complexity: O(1) in time and space. + constexpr const_pointer data() const noexcept { return data_.data(); } + + /// Direct access to the underlying storage. + /// + /// Complexity: O(1) in time and space. + constexpr pointer data() noexcept { return data_.data(); } + + /// Number of elements in the storage. + /// + /// Complexity: O(1) in time and space. + constexpr size_type size() const noexcept { return size_; } + + /// Maximum number of elements that can be allocated in the + /// storage. + /// + /// Complexity: O(1) in time and space. + static constexpr size_type capacity() noexcept { return Capacity; } + + /// Is the storage empty? + constexpr bool empty() const noexcept { return size() == size_type{0}; } + + /// Is the storage full? + constexpr bool full() const noexcept { return size() == Capacity; } + + /// Constructs an element in-place at the end of the + /// storage. + /// + /// Complexity: O(1) in time and space. + /// Contract: the storage is not full. + template + requires std::constructible_from && std::assignable_from + constexpr void emplace_back(Args&&... args) noexcept { + SV_EXPECT(!full() && "tried to emplace_back on full storage!"); + data_[size_++] = T(std::forward(args)...); + } + + /// Remove the last element from the container. + /// + /// Complexity: O(1) in time and space. + /// Contract: the storage is not empty. + constexpr void pop_back() noexcept { + SV_EXPECT(!empty() && "tried to pop_back from empty storage!"); + --size_; + } + + /// (unsafe) Changes the container size to \p new_size. + /// + /// Contract: `new_size <= capacity()`. + /// \warning No elements are constructed or destroyed. + constexpr void unsafe_set_size(size_t new_size) noexcept { + SV_EXPECT(new_size <= Capacity && "new_size out-of-bounds [0, Capacity]"); + size_ = size_type(new_size); + } + + /// (unsafe) Destroy elements in the range [begin, end). + /// + /// \warning: The size of the storage is not changed. + template + constexpr void unsafe_destroy(InputIt, InputIt) noexcept {} + + /// (unsafe) Destroys all elements of the storage. + /// + /// \warning: The size of the storage is not changed. + static constexpr void unsafe_destroy_all() noexcept {} + + constexpr trivial() noexcept = default; + constexpr trivial(trivial const&) noexcept = default; + constexpr trivial& operator=(trivial const&) noexcept = default; + constexpr trivial(trivial&&) noexcept = default; + constexpr trivial& operator=(trivial&&) noexcept = default; + ~trivial() = default; + +private: + template U> + static constexpr std::array, Capacity> + unsafe_recast_init_list(std::initializer_list& il) noexcept { + SV_EXPECT(il.size() <= capacity() + && "trying to construct storage from an " + "initializer_list " + "whose size exceeds the storage capacity"); + std::array, Capacity> d_{}; + for (size_t i = 0, e = il.size(); i < e; ++i) { + d_[i] = std::begin(il)[i]; + } + return d_; + } + +public: + /// Constructor from initializer list. + /// + /// Contract: `il.size() <= capacity()`. + template U> + constexpr trivial(std::initializer_list il) noexcept : data_(unsafe_recast_init_list(il)) { + unsafe_set_size(il.size()); + } +}; + +/// Storage for non-trivial elements. +template +struct non_trivial { + static_assert(!std::is_trivial_v, "use storage::trivial for std::is_trivial_v elements"); + static_assert(Capacity != size_t{0}, "Capacity must be greater than zero!"); + + /// Smallest size_type that can represent Capacity: + using size_type = smallest_size_t; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using const_pointer = T const*; + +private: + /// Number of elements allocated in the embedded storage: + size_type size_ = 0; + + //using aligned_storage_t = std::aligned_storage_t), alignof(std::remove_const_t)>; + //using data_t = std::conditional_t, aligned_storage_t, const aligned_storage_t>; + //alignas(alignof(T)) data_t data_[Capacity]{}; + // FIXME: ^ this won't work for types with "broken" alignof + // like SIMD types (one would also need to provide an + // overload of operator new to make heap allocations of this + // type work for these types). + + // Kate's solution to deal with badly aligned members + std::array data_{}; + +public: + /// Direct access to the underlying storage. + /// + /// Complexity: O(1) in time and space. + const_pointer data() const noexcept { return data_.data(); } + + /// Direct access to the underlying storage. + /// + /// Complexity: O(1) in time and space. + pointer data() noexcept { return data_.data(); } + + /// Pointer to one-past-the-end. + const_pointer end() const noexcept { return data() + size(); } + + /// Pointer to one-past-the-end. + pointer end() noexcept { return data() + size(); } + + /// Number of elements in the storage. + /// + /// Complexity: O(1) in time and space. + constexpr size_type size() const noexcept { return size_; } + + /// Maximum number of elements that can be allocated in the + /// storage. + /// + /// Complexity: O(1) in time and space. + static constexpr size_type capacity() noexcept { return Capacity; } + + /// Is the storage empty? + [[nodiscard]] constexpr bool empty() const noexcept { return size() == size_type{0}; } + + /// Is the storage full? + [[nodiscard]] constexpr bool full() const noexcept { return size() == Capacity; } + + /// Constructs an element in-place at the end of the + /// embedded storage. + /// + /// Complexity: O(1) in time and space. + /// Contract: the storage is not full. + template + requires std::constructible_from + void emplace_back(Args&&... args) noexcept(noexcept(new (end()) T(std::forward(args)...))) { + SV_EXPECT(!full() && "tried to emplace_back on full storage"); + //new (end()) T(std::forward(args)...); + //unsafe_set_size(size() + 1); + + // NOTE: (Kate) Faster somehow... + void* end = &data_[size_++]; + new (end) T(std::forward(args)...); + } + + /// Remove the last element from the container. + /// + /// Complexity: O(1) in time and space. + /// Contract: the storage is not empty. + void pop_back() noexcept(std::is_nothrow_destructible_v) { + SV_EXPECT(!empty() && "tried to pop_back from empty storage!"); + auto ptr = end() - 1; + ptr->~T(); + unsafe_set_size(size() - 1); + } + + /// (unsafe) Changes the container size to \p new_size. + /// + /// Contract: `new_size <= capacity()`. + /// \warning No elements are constructed or destroyed. + constexpr void unsafe_set_size(size_t new_size) noexcept { + SV_EXPECT(new_size <= Capacity && "new_size out-of-bounds [0, Capacity)"); + size_ = size_type(new_size); + } + + /// (unsafe) Destroy elements in the range [begin, end). + /// + /// \warning: The size of the storage is not changed. + template + void unsafe_destroy(InputIt first, InputIt last) noexcept(std::is_nothrow_destructible_v) { + SV_EXPECT(first >= data() && first <= end() && "first is out-of-bounds"); + SV_EXPECT(last >= data() && last <= end() && "last is out-of-bounds"); + for (; first != last; ++first) { + first->~T(); + } + } + + /// (unsafe) Destroys all elements of the storage. + /// + /// \warning: The size of the storage is not changed. + void unsafe_destroy_all() noexcept(std::is_nothrow_destructible_v) { unsafe_destroy(data(), end()); } + + constexpr non_trivial() = default; + constexpr non_trivial(non_trivial const&) = default; + constexpr non_trivial& operator=(non_trivial const&) = default; + constexpr non_trivial(non_trivial&&) = default; + constexpr non_trivial& operator=(non_trivial&&) = default; + ~non_trivial() noexcept(std::is_nothrow_destructible_v) { unsafe_destroy_all(); } + + /// Constructor from initializer list. + /// + /// Contract: `il.size() <= capacity()`. + template U> + constexpr non_trivial(std::initializer_list il) { + SV_EXPECT(il.size() <= capacity() + && "trying to construct storage from an " + "initializer_list " + "whose size exceeds the storage capacity"); + std::copy(il.begin(), il.end(), data_.begin()); + unsafe_set_size(il.size()); + } +}; + +/// Selects the vector storage. +template +using _t = std::conditional_t, + std::conditional_t, trivial, non_trivial>>; + +} // namespace storage + +} // namespace sv_detail + +/// Dynamically-resizable fixed-capacity vector. +template +struct static_vector : private sv_detail::storage::_t { +private: + static_assert(std::is_nothrow_destructible_v, "T must be nothrow destructible"); + using base_t = sv_detail::storage::_t; + using self = static_vector; + + using base_t::unsafe_destroy; + using base_t::unsafe_destroy_all; + using base_t::unsafe_set_size; + +public: + using value_type = typename base_t::value_type; + using difference_type = ptrdiff_t; + using reference = value_type&; + using const_reference = value_type const&; + using pointer = typename base_t::pointer; + using const_pointer = typename base_t::const_pointer; + using iterator = typename base_t::pointer; + using const_iterator = typename base_t::const_pointer; + using size_type = size_t; + using reverse_iterator = ::std::reverse_iterator; + using const_reverse_iterator = ::std::reverse_iterator; + + /// \name Size / capacity + ///@{ + using base_t::empty; + using base_t::full; + + /// Number of elements in the vector + [[nodiscard]] constexpr size_type size() const noexcept { return base_t::size(); } + + /// Maximum number of elements that can be allocated in the vector + static constexpr size_type capacity() noexcept { return base_t::capacity(); } + + /// Maximum number of elements that can be allocated in the vector + static constexpr size_type max_size() noexcept { return capacity(); } + + ///@} // Size / capacity + + /// \name Data access + ///@{ + + using base_t::data; + + ///@} // Data access + + /// \name Iterators + ///@{ + + constexpr iterator begin() noexcept { return data(); } + constexpr const_iterator begin() const noexcept { return data(); } + constexpr iterator end() noexcept { return data() + size(); } + constexpr const_iterator end() const noexcept { return data() + size(); } + + reverse_iterator rbegin() noexcept { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + reverse_iterator rend() noexcept { return reverse_iterator(begin()); } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + + constexpr const_iterator cbegin() noexcept { return begin(); } + constexpr const_iterator cbegin() const noexcept { return begin(); } + constexpr const_iterator cend() noexcept { return end(); } + constexpr const_iterator cend() const noexcept { return end(); } + + ///@} // Iterators + +private: + /// \name Iterator bound-check utilites + ///@{ + + template + constexpr void assert_iterator_in_range(It it) noexcept { + static_assert(std::is_pointer_v); + SV_EXPECT(begin() <= it && "iterator not in range"); + SV_EXPECT(it <= end() && "iterator not in range"); + } + + template + constexpr void assert_valid_iterator_pair(It0 first, It1 last) noexcept { + static_assert(std::is_pointer_v); + static_assert(std::is_pointer_v); + SV_EXPECT(first <= last && "invalid iterator pair"); + } + + template + constexpr void assert_iterator_pair_in_range(It0 first, It1 last) noexcept { + assert_iterator_in_range(first); + assert_iterator_in_range(last); + assert_valid_iterator_pair(first, last); + } + + ///@} +public: + /// \name Element access + /// + ///@{ + + /// Unchecked access to element at index \p pos (UB if index not in + /// range) + constexpr reference operator[](size_type pos) noexcept { return std::begin(*this)[pos]; } + + /// Unchecked access to element at index \p pos (UB if index not in + /// range) + constexpr const_reference operator[](size_type pos) const noexcept { return std::begin(*this)[pos]; } + + /// Checked access to element at index \p pos (throws `out_of_range` + /// if index not in range) + constexpr reference at(size_type pos) noexcept { return std::begin(*this)[pos]; } + + /// Checked access to element at index \p pos (throws `out_of_range` + /// if index not in range) + constexpr const_reference at(size_type pos) const noexcept { return std::begin(*this)[pos]; } + + /// + constexpr reference front() noexcept { return std::begin(*this)[0]; } + constexpr const_reference front() const noexcept { return std::begin(*this)[0]; } + + constexpr reference back() noexcept { + SV_EXPECT(!empty() && "calling back on an empty vector"); + return std::begin(*this)[size() - 1]; + } + constexpr const_reference back() const noexcept { + SV_EXPECT(!empty() && "calling back on an empty vector"); + return std::begin(*this)[size() - 1]; + } + + ///@} // Element access + + /// \name Modifiers + ///@{ + + using base_t::emplace_back; + using base_t::pop_back; + + /// Clears the vector. + constexpr void clear() noexcept { + unsafe_destroy_all(); + unsafe_set_size(0); + } + + /// Appends \p value at the end of the vector. + template + requires std::constructible_from && std::assignable_from + constexpr void push_back(U&& value) noexcept(noexcept(emplace_back(std::forward(value)))) { + SV_EXPECT(!full() && "vector is full!"); + emplace_back(std::forward(value)); + } + + /// Appends a default constructed `T` at the end of the vector. + + void push_back() noexcept( + noexcept(emplace_back(T{}))) requires std::constructible_from && std::assignable_from { + SV_EXPECT(!full() && "vector is full!"); + emplace_back(T{}); + } + + template + requires std::constructible_from + constexpr iterator emplace(const_iterator position, + Args&&... args) noexcept(noexcept(move_insert(position, std::declval(), + std::declval()))) { + SV_EXPECT(!full() && "tried emplace on full static_vector!"); + assert_iterator_in_range(position); + value_type a(std::forward(args)...); + return move_insert(position, &a, &a + 1); + } + + constexpr iterator insert(const_iterator position, + const_reference x) noexcept(noexcept(insert(position, size_type(1), + x))) requires std::copy_constructible { + SV_EXPECT(!full() && "tried insert on full static_vector!"); + assert_iterator_in_range(position); + return insert(position, size_type(1), x); + } + + constexpr iterator + insert(const_iterator position, + value_type&& x) noexcept(noexcept(move_insert(position, &x, &x + 1))) requires std::move_constructible { + SV_EXPECT(!full() && "tried insert on full static_vector!"); + assert_iterator_in_range(position); + return move_insert(position, &x, &x + 1); + } + + constexpr iterator insert(const_iterator position, size_type n, + const T& x) noexcept(noexcept(push_back(x))) requires std::copy_constructible + + { + assert_iterator_in_range(position); + const auto new_size = size() + n; + SV_EXPECT(new_size <= capacity() && "trying to insert beyond capacity!"); + auto b = end(); + while (n != 0) { + push_back(x); + --n; + } + + auto writable_position = begin() + (position - begin()); + std::rotate(writable_position, b, end()); + return writable_position; + } + + template + requires std::input_iterator && std::constructible_from> + constexpr iterator insert(const_iterator position, InputIt first, + InputIt last) noexcept(noexcept(emplace_back(*first))) { + assert_iterator_in_range(position); + assert_valid_iterator_pair(first, last); + if constexpr (std::random_access_iterator) { + SV_EXPECT(size() + static_cast(last - first) <= capacity() + && "trying to insert beyond capacity!"); + } + auto b = end(); + + // insert at the end and then just rotate: + // cannot use try in constexpr function + // try { // if copy_constructor throws you get basic-guarantee? + for (; first != last; ++first) { + emplace_back(*first); + } + // } catch (...) { + // erase(b, end()); + // throw; + // } + + auto writable_position = begin() + (position - begin()); + std::rotate(writable_position, b, end()); + return writable_position; + } + + template + constexpr iterator move_insert(const_iterator position, InputIt first, + InputIt last) noexcept(noexcept(emplace_back(std::move(*first)))) { + assert_iterator_in_range(position); + assert_valid_iterator_pair(first, last); + if constexpr (std::random_access_iterator) { + SV_EXPECT(size() + static_cast(last - first) <= capacity() + && "trying to insert beyond capacity!"); + } + iterator b = end(); + + // we insert at the end and then just rotate: + for (; first != last; ++first) { + emplace_back(std::move(*first)); + } + auto writable_position = begin() + (position - begin()); + std::rotate(writable_position, b, end()); + return writable_position; + } + + constexpr iterator insert(const_iterator position, std::initializer_list il) noexcept( + noexcept(insert(position, il.begin(), il.end()))) requires std::copy_constructible { + assert_iterator_in_range(position); + return insert(position, il.begin(), il.end()); + } + + constexpr iterator erase(const_iterator position) noexcept requires std::movable { + assert_iterator_in_range(position); + return erase(position, position + 1); + } + + constexpr iterator erase(const_iterator first, const_iterator last) noexcept requires std::movable { + assert_iterator_pair_in_range(first, last); + iterator p = begin() + (first - begin()); + if (first != last) { + unsafe_destroy(std::move(p + (last - first), end(), p), end()); + unsafe_set_size(size() - static_cast(last - first)); + } + + return p; + } + + constexpr void + swap(static_vector& other) noexcept(std::is_nothrow_swappable_v) requires std::assignable_from { + static_vector tmp = move(other); + other = move(*this); + (*this) = move(tmp); + } + + /// Resizes the container to contain \p sz elements. If elements + /// need to be appended, these are copy-constructed from \p value. + /// + constexpr void + resize(size_type sz, + T const& value) noexcept(std::is_nothrow_copy_constructible_v) requires std::copy_constructible { + if (sz == size()) { + return; + } + if (sz > size()) { + SV_EXPECT(sz <= capacity() + && "static_vector cannot be resized to " + "a size greater than capacity"); + insert(end(), sz - size(), value); + } + else { + erase(end() - (size() - sz), end()); + } + } + +private: + constexpr void + emplace_n(size_type n) noexcept((std::move_constructible && std::is_nothrow_move_constructible_v) + || (std::copy_constructible && std::is_nothrow_copy_constructible_v)) requires + std::move_constructible || std::copy_constructible { + SV_EXPECT(n <= capacity() + && "static_vector cannot be " + "resized to a size greater than " + "capacity"); + while (n != size()) { + emplace_back(T{}); + } + } + +public: + /// Resizes the container to contain \p sz elements. If elements + /// need to be appended, these are move-constructed from `T{}` (or + /// copy-constructed if `T` is not `std::move_constructible`). + constexpr void resize(size_type sz) noexcept( + (std::move_constructible && std::is_nothrow_move_constructible_v) + || (std::copy_constructible && std::is_nothrow_copy_constructible_v)) requires std::movable { + if (sz == size()) { + return; + } + + if (sz > size()) { + emplace_n(sz); + } + else { + erase(end() - (size() - sz), end()); + } + } + + ///@} // Modifiers + + /// \name Construct/copy/move/destroy + ///@{ + + /// Default constructor. + constexpr static_vector() = default; + + /// Copy constructor. + constexpr static_vector(static_vector const& other) noexcept( + noexcept(insert(begin(), other.begin(), other.end()))) requires std::copy_constructible { + // nothin to assert: size of other cannot exceed capacity + // because both vectors have the same type + insert(begin(), other.begin(), other.end()); + } + + /// Move constructor. + constexpr static_vector(static_vector&& other) noexcept( + noexcept(move_insert(begin(), other.begin(), other.end()))) requires std::move_constructible { + // nothin to assert: size of other cannot exceed capacity + // because both vectors have the same type + move_insert(begin(), other.begin(), other.end()); + } + + /// Copy assignment. + constexpr static_vector& operator=(static_vector const& other) noexcept(noexcept(clear()) && noexcept( + insert(begin(), other.begin(), other.end()))) requires std::assignable_from { + // nothin to assert: size of other cannot exceed capacity + // because both vectors have the same type + clear(); + insert(this->begin(), other.begin(), other.end()); + return *this; + } + + /// Move assignment. + constexpr static_vector& operator=(static_vector&& other) noexcept(noexcept(clear()) and noexcept( + move_insert(begin(), other.begin(), other.end()))) requires std::move_constructible { + // nothin to assert: size of other cannot exceed capacity + // because both vectors have the same type + clear(); + move_insert(this->begin(), other.begin(), other.end()); + return *this; + } + + /// Initializes vector with \p n default-constructed elements. + explicit constexpr static_vector(size_type n) noexcept( + noexcept(emplace_n(n))) requires std::copy_constructible || std::move_constructible { + SV_EXPECT(n <= capacity() && "size exceeds capacity"); + emplace_n(n); + } + + /// Initializes vector with \p n with \p value. + constexpr static_vector(size_type n, + T const& value) noexcept(noexcept(insert(begin(), n, + value))) requires std::copy_constructible { + SV_EXPECT(n <= capacity() && "size exceeds capacity"); + insert(begin(), n, value); + } + + /// Initialize vector from range [first, last). + template + constexpr static_vector(InputIt first, InputIt last) { + if constexpr (std::random_access_iterator) { + SV_EXPECT(last - first >= 0); + SV_EXPECT(static_cast(last - first) <= capacity() && "range size exceeds capacity"); + } + insert(begin(), first, last); + } + + template U> + constexpr static_vector(std::initializer_list il) noexcept(noexcept(base_t(std::move(il)))) + : base_t(std::move(il)) { // assert happens in base_t constructor + } + + constexpr static_vector(std::initializer_list il) noexcept(noexcept(base_t(std::move(il)))) + : base_t(std::move(il)) { // assert happens in base_t constructor + } + + template + constexpr void assign(InputIt first, + InputIt last) noexcept(noexcept(clear()) and noexcept(insert(begin(), first, last))) { + if constexpr (std::random_access_iterator) { + SV_EXPECT(last - first >= 0); + SV_EXPECT(static_cast(last - first) <= capacity() && "range size exceeds capacity"); + } + clear(); + insert(begin(), first, last); + } + + constexpr void assign(size_type n, const T& u) requires std::copy_constructible { + SV_EXPECT(n <= capacity() && "size exceeds capacity"); + clear(); + insert(begin(), n, u); + } + + constexpr void assign(std::initializer_list const& il) requires std::copy_constructible { + SV_EXPECT(il.size() <= capacity() && "initializer_list size exceeds capacity"); + clear(); + insert(this->begin(), il.begin(), il.end()); + } + + constexpr void assign(std::initializer_list&& il) requires std::copy_constructible { + SV_EXPECT(il.size() <= capacity() && "initializer_list size exceeds capacity"); + clear(); + insert(this->begin(), il.begin(), il.end()); + } + + ///@} // Construct/copy/move/destroy/assign +}; + +template +constexpr bool operator==(static_vector const& a, static_vector const& b) noexcept { + return a.size() == b.size() and std::equal(a.begin(), a.end(), b.begin(), b.end(), std::equal_to<>{}); +} + +template +constexpr bool operator<(static_vector const& a, static_vector const& b) noexcept { + return std::equal(a.begin(), a.end(), b.begin(), b.end(), std::less<>{}); +} + +template +constexpr bool operator!=(static_vector const& a, static_vector const& b) noexcept { + return not(a == b); +} + +template +constexpr bool operator<=(static_vector const& a, static_vector const& b) noexcept { + return std::equal(a.begin(), a.end(), b.begin(), b.end(), std::less_equal<>{}); +} + +template +constexpr bool operator>(static_vector const& a, static_vector const& b) noexcept { + return std::equal(a.begin(), a.end(), b.begin(), b.end(), std::greater<>{}); +} + +template +constexpr bool operator>=(static_vector const& a, static_vector const& b) noexcept { + return std::equal(a.begin(), a.end(), b.begin(), b.end(), std::greater_equal<>{}); +} + +namespace sv_detail { +template +constexpr static_vector, N> to_static_vector_impl(T (&a)[N], std::index_sequence) { + return {{a[I]...}}; +} + +template +constexpr static_vector, N> to_static_vector_impl(T (&&a)[N], std::index_sequence) { + return {{std::move(a[I])...}}; +} +} // namespace sv_detail + +template +constexpr static_vector, N> to_static_vector(T (&a)[N]) { + return sv_detail::to_static_vector_impl(a, std::make_index_sequence{}); +} + +template +constexpr static_vector, N> to_static_vector(T (&&a)[N]) { + return sv_detail::to_static_vector_impl(std::move(a), std::make_index_sequence{}); +} + +} // namespace deluge + +// undefine all the internal macros +#undef SV_ASSUME +#undef SV_ASSERT +#undef SV_EXPECT diff --git a/src/deluge/util/lookuptables/lookuptables.cpp b/src/deluge/util/lookuptables/lookuptables.cpp index 9015c0c6d5..6991d04fde 100644 --- a/src/deluge/util/lookuptables/lookuptables.cpp +++ b/src/deluge/util/lookuptables/lookuptables.cpp @@ -182,7 +182,7 @@ const int16_t tanHSmall[] = { 32767, }; -const char* presetScaleNames[] = {"MAJOR", "MINOR", "DORIAN", "PHRYGIAN", "LYDIAN", "MIXOLYDIAN", "LOCRIAN", "RANDOM", "NONE", NULL}; +std::array presetScaleNames = {"MAJOR", "MINOR", "DORIAN", "PHRYGIAN", "LYDIAN", "MIXOLYDIAN", "LOCRIAN", "RANDOM", "NONE"}; #if HAVE_OLED const char* presetReverbNames[] = {"Small room reverb", "Medium room reverb", "Large room reverb", NULL}; diff --git a/src/deluge/util/lookuptables/lookuptables.h b/src/deluge/util/lookuptables/lookuptables.h index 33d75f156b..ac8e0d9265 100644 --- a/src/deluge/util/lookuptables/lookuptables.h +++ b/src/deluge/util/lookuptables/lookuptables.h @@ -17,6 +17,7 @@ #pragma once +#include #include extern const uint16_t centAdjustTableSmall[]; @@ -129,7 +130,7 @@ extern const int16_t windowedSincKernelBasicForWavetableBetweenCycles[]; #define NUM_PRESET_SCALES 7 extern const uint8_t presetScaleNotes[NUM_PRESET_SCALES][7]; -extern const char* presetScaleNames[]; +extern std::array presetScaleNames; #define PRESET_SCALE_RANDOM 7 #define PRESET_SCALE_NONE 8 diff --git a/src/deluge/util/misc.h b/src/deluge/util/misc.h index 6b4f85e44b..735ab218a9 100644 --- a/src/deluge/util/misc.h +++ b/src/deluge/util/misc.h @@ -9,6 +9,9 @@ constexpr std::underlying_type_t to_underlying(Enum e) noexcept { return static_cast>(e); } +template +concept enumeration = std::is_enum_v; + template constexpr T bit = T{1} << n; diff --git a/src/preinclude_cxx.h b/src/preinclude_cxx.h deleted file mode 100644 index f360fa1a6c..0000000000 --- a/src/preinclude_cxx.h +++ /dev/null @@ -1,20 +0,0 @@ -// This file is included as a first include in all cpp files -#include -#include - -inline void* operator new(std::size_t) { - extern void* DO_NOT_USE_UNARY_NEW(); - return DO_NOT_USE_UNARY_NEW(); -} -inline void* operator new(std::size_t, const std::nothrow_t&) noexcept { - extern void* DO_NOT_USE_UNARY_NEW(); - return DO_NOT_USE_UNARY_NEW(); -} -inline void* operator new[](std::size_t) { - extern void* DO_NOT_USE_UNARY_NEW(); - return DO_NOT_USE_UNARY_NEW(); -} -inline void* operator new[](std::size_t, const std::nothrow_t&) noexcept { - extern void* DO_NOT_USE_UNARY_NEW(); - return DO_NOT_USE_UNARY_NEW(); -};