Skip to content

Commit

Permalink
Revamp faderbank MIDI config UI; support 14-bit CC mode (#208)
Browse files Browse the repository at this point in the history
* basic 14-bit CC support

* Per-fader 14-bit setting, better autodetect, fader settings menu

* Implement writing 16n sysex

* Fix 7-bit MIDI CC range

* Restrict 14-bit CCs to 0-31

* fix second mapping of LSB CC shadowing 14-bit fader; make interval sample rate dependent

* Leave menus up while editing fader config
  • Loading branch information
Dewb authored Dec 30, 2024
1 parent 2efca39 commit a3f300f
Show file tree
Hide file tree
Showing 5 changed files with 606 additions and 74 deletions.
12 changes: 11 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@
"__node_handle": "cpp",
"mock_hardware_api_private.h": "c",
"__functional_03": "cpp",
"mutex": "cpp"
"mutex": "cpp",
"__config": "cpp",
"__hash_table": "cpp",
"__split_buffer": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"__verbose_abort": "cpp",
"cfenv": "cpp",
"charconv": "cpp",
"execution": "cpp",
"stack": "cpp"
}
}
151 changes: 151 additions & 0 deletions src/common/widgets/CustomMenuTemplates.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
#pragma once

#include "rack.hpp"
using namespace rack;

template <class TMenuItem = ui::MenuItem>
TMenuItem* createUnconsumingIndexSubmenuItem(std::string text, std::vector<std::string> labels, std::function<size_t()> getter, std::function<void(size_t val)> setter, bool disabled = false)
{
struct IndexItem : ui::MenuItem
{
std::function<size_t()> getter;
std::function<void(size_t)> setter;
size_t index;

void step() override
{
size_t currIndex = getter();
this->rightText = CHECKMARK(currIndex == index);
MenuItem::step();
}
void onAction(const event::Action& e) override
{
setter(index);
e.unconsume();
}
};

struct Item : TMenuItem
{
std::function<size_t()> getter;
std::function<void(size_t)> setter;
std::vector<std::string> labels;

void step() override
{
size_t currIndex = getter();
std::string label = (currIndex < labels.size()) ? labels[currIndex] : "";
this->rightText = label + " " + RIGHT_ARROW;
TMenuItem::step();
}
ui::Menu* createChildMenu() override
{
ui::Menu* menu = new ui::Menu;
for (size_t i = 0; i < labels.size(); i++)
{
IndexItem* item = createMenuItem<IndexItem>(labels[i]);
item->getter = getter;
item->setter = setter;
item->index = i;
menu->addChild(item);
}
return menu;
}
};

Item* item = createMenuItem<Item>(text);
item->getter = getter;
item->setter = setter;
item->labels = labels;
item->disabled = disabled;
return item;
}

template <class TMenuItem = ui::MenuItem>
TMenuItem* createUnconsumingIndexSubmenuItemWithDynamicLabels(std::string text, std::function<std::vector<std::string>()> getLabels, std::function<size_t()> getter, std::function<void(size_t val)> setter, bool disabled = false)
{
struct IndexItem : ui::MenuItem
{
std::function<size_t()> getter;
std::function<void(size_t)> setter;
size_t index;

void step() override
{
size_t currIndex = getter();
this->rightText = CHECKMARK(currIndex == index);
MenuItem::step();
}
void onAction(const event::Action& e) override
{
setter(index);
e.unconsume();
}
};

struct Item : TMenuItem
{
std::function<std::vector<std::string>()> getLabels;
std::function<size_t()> getter;
std::function<void(size_t)> setter;

void step() override
{
size_t currIndex = getter();
auto labels = getLabels();
std::string label = (currIndex < labels.size()) ? labels[currIndex] : "";
this->rightText = label + " " + RIGHT_ARROW;
TMenuItem::step();
}
ui::Menu* createChildMenu() override
{
ui::Menu* menu = new ui::Menu;
auto labels = getLabels();
for (size_t i = 0; i < labels.size(); i++)
{
IndexItem* item = createMenuItem<IndexItem>(labels[i]);
item->getter = getter;
item->setter = setter;
item->index = i;
menu->addChild(item);
}
return menu;
}
};

Item* item = createMenuItem<Item>(text);
item->getter = getter;
item->setter = setter;
item->getLabels = getLabels;
item->disabled = disabled;
return item;
}

template <class TMenuItem = ui::MenuItem>
TMenuItem* createSubmenuItemWithDynamicRightText(std::string text, std::function<std::string(void)> getRightText, std::function<void(ui::Menu* menu)> createMenu, bool disabled = false)
{
struct Item : TMenuItem
{
std::function<std::string(void)> getRightText;
std::function<void(ui::Menu* menu)> createMenu;

void step() override
{
this->rightText = getRightText() + " " + RIGHT_ARROW;
TMenuItem::step();
}

ui::Menu* createChildMenu() override
{
ui::Menu* menu = new ui::Menu;
createMenu(menu);
return menu;
}
};

Item* item = createMenuItem<Item>(text, getRightText() + " " + RIGHT_ARROW);
item->getRightText = getRightText;
item->createMenu = createMenu;
item->disabled = disabled;
return item;
}
Loading

0 comments on commit a3f300f

Please sign in to comment.