From fca26eb3dfa39d9b8e694f395b25591bb49e6b22 Mon Sep 17 00:00:00 2001 From: Michael Dewberry Date: Fri, 7 Jul 2023 16:54:20 -0400 Subject: [PATCH 1/6] Remove firmware products in res/ on make clean --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 534e1da..e474137 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,9 @@ firmware-build: firmware/*.mk firmware/**/*.c firmware/**/*.h firmware/**/**/*.r firmware-clean: rm -rfv firmware/build + rm -fv res/firmware/*.so + rm -fv res/firmware/*.dll + rm -fv res/firmware/*.dylib DISTRIBUTABLES += $(wildcard res) DISTRIBUTABLES += $(wildcard LICENSE*) From 5db40d0cf3871776e66f4200f4e6de065794864a Mon Sep 17 00:00:00 2001 From: Michael Dewberry Date: Fri, 7 Jul 2023 16:54:41 -0400 Subject: [PATCH 2/6] Remove serialosc pre-init on module widget load --- src/common/core/LibAVR32ModuleWidget.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/common/core/LibAVR32ModuleWidget.cpp b/src/common/core/LibAVR32ModuleWidget.cpp index e03e42d..6619851 100644 --- a/src/common/core/LibAVR32ModuleWidget.cpp +++ b/src/common/core/LibAVR32ModuleWidget.cpp @@ -109,8 +109,6 @@ struct FirmwareSubmenuItem : MenuItem LibAVR32ModuleWidget::LibAVR32ModuleWidget() { - // make sure serialosc is fully initialized before the user opens the right-click menu - SerialOscInterface::get(); } void LibAVR32ModuleWidget::appendContextMenu(rack::Menu* menu) From e94837a081fc0e048a878df2136318925bdfd6a0 Mon Sep 17 00:00:00 2001 From: Michael Dewberry Date: Tue, 1 Aug 2023 23:37:22 -0400 Subject: [PATCH 3/6] Prototype of virtual grid mirror mode --- src/common/core/ActionQueue.hpp | 7 + .../core/GridConnection/GridConnection.hpp | 3 + .../GridConnection/GridConnectionMenu.cpp | 120 ++++++++++++++++++ .../GridConnection/GridConnectionMenu.hpp | 7 + src/common/core/LibAVR32Module.cpp | 10 ++ src/common/core/LibAVR32Module.hpp | 6 +- src/virtualgrid/VirtualGridModule.cpp | 113 +++++++++++++++++ src/virtualgrid/VirtualGridModule.hpp | 4 + src/virtualgrid/VirtualGridWidget.cpp | 3 + 9 files changed, 270 insertions(+), 3 deletions(-) create mode 100644 src/common/core/ActionQueue.hpp create mode 100644 src/common/core/GridConnection/GridConnectionMenu.cpp create mode 100644 src/common/core/GridConnection/GridConnectionMenu.hpp diff --git a/src/common/core/ActionQueue.hpp b/src/common/core/ActionQueue.hpp new file mode 100644 index 0000000..f987bdb --- /dev/null +++ b/src/common/core/ActionQueue.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include "rack.hpp" +#include + +typedef std::function Action; +typedef rack::dsp::RingBuffer ActionQueue; \ No newline at end of file diff --git a/src/common/core/GridConnection/GridConnection.hpp b/src/common/core/GridConnection/GridConnection.hpp index e0788b6..cf8b258 100644 --- a/src/common/core/GridConnection/GridConnection.hpp +++ b/src/common/core/GridConnection/GridConnection.hpp @@ -21,9 +21,12 @@ struct GridConsumer { virtual void gridConnected(Grid* grid) = 0; virtual void gridDisconnected(bool ownerChanged) = 0; + virtual std::string gridGetCurrentDeviceId() = 0; virtual std::string gridGetLastDeviceId(bool owned) = 0; virtual void gridButtonEvent(int x, int y, bool state) = 0; virtual void encDeltaEvent(int n, int d) = 0; + virtual Grid* gridGetDevice() = 0; + virtual ~GridConsumer() {}; }; struct GridConnectionManager final diff --git a/src/common/core/GridConnection/GridConnectionMenu.cpp b/src/common/core/GridConnection/GridConnectionMenu.cpp new file mode 100644 index 0000000..d4bf871 --- /dev/null +++ b/src/common/core/GridConnection/GridConnectionMenu.cpp @@ -0,0 +1,120 @@ +#include "GridConnectionMenu.hpp" +#include "SerialOscInterface.hpp" + +using namespace rack; + +struct NewConnectGridItem : rack::ui::MenuItem +{ + Grid* grid; + GridConsumer* consumer; + ActionQueue* actionQueue; + + void onAction(const rack::event::Action& e) override + { + if (actionQueue) + { + auto thisGrid = grid; + auto thisConsumer = consumer; + + actionQueue->push([thisGrid, thisConsumer]() + { GridConnectionManager::get().connect(thisGrid, thisConsumer); }); + } + } +}; + +void menuUserReacquireGrid(GridConsumer* consumer, std::string lastDeviceId, ActionQueue* actionQueue) +{ + for (Grid* grid : GridConnectionManager::get().getGrids()) + { + if (lastDeviceId == grid->getDevice().id) + { + if (actionQueue) + { + actionQueue->push([grid, consumer]() + { + GridConnectionManager::get().connect(grid, consumer); + } + ); + } + return; + } + } +} + +void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* actionQueue) +{ + std::string currentConnectedDeviceId = consumer->gridGetCurrentDeviceId(); + std::string lastConnectedDeviceId = consumer->gridGetLastDeviceId(false); + + menu->addChild(construct(&MenuLabel::text, "Device Connection")); + + if (SerialOscInterface::get()->isServiceDetected()) + { + menu->addChild( + construct( + &MenuLabel::text, + "serialosc version " + SerialOscInterface::get()->getServiceVersion())); + } + else + { + menu->addChild( + createMenuItem("└ serialosc service not detected, click here to install", "", + [=]() + { + system::openBrowser("https://monome.org/docs/serialosc/setup/"); + })); + } + + // enumerate registered grid devices + int deviceCount = 0; + bool preferredDeviceFound = false; + for (Grid* grid : GridConnectionManager::get().getGrids()) + { + auto connectItem = new NewConnectGridItem(); + connectItem->text = "└ " + grid->getDevice().type + " (" + grid->getDevice().id + ") "; + + auto rightText = ""; + if (currentConnectedDeviceId == grid->getDevice().id) + { + rightText = "✔"; + preferredDeviceFound = true; + } + else if (currentConnectedDeviceId == "" && lastConnectedDeviceId == grid->getDevice().id) + { + rightText = "⋯"; + preferredDeviceFound = true; + } + + connectItem->rightText = rightText; + connectItem->grid = grid; + connectItem->actionQueue = actionQueue; + connectItem->consumer = consumer; + + menu->addChild(connectItem); + deviceCount++; + } + + if (deviceCount == 0) + { + menu->addChild(construct(&MenuLabel::text, " (no physical or virtual devices found)")); + } + + if (currentConnectedDeviceId == "" && lastConnectedDeviceId != "") + { + if (preferredDeviceFound) + { + menu->addChild(createMenuItem("Reacquire grid", "", [=]() + { + if (lastConnectedDeviceId != "") + { + menuUserReacquireGrid(consumer, lastConnectedDeviceId, actionQueue); + } + } + )); + } + else + { + menu->addChild(construct(&MenuLabel::text, "Can't reacquire grid (" + lastConnectedDeviceId + " not found)")); + } + } +} \ No newline at end of file diff --git a/src/common/core/GridConnection/GridConnectionMenu.hpp b/src/common/core/GridConnection/GridConnectionMenu.hpp new file mode 100644 index 0000000..b5e9d27 --- /dev/null +++ b/src/common/core/GridConnection/GridConnectionMenu.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include "rack.hpp" +#include "GridConnection.hpp" +#include "ActionQueue.hpp" + +void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* queue); \ No newline at end of file diff --git a/src/common/core/LibAVR32Module.cpp b/src/common/core/LibAVR32Module.cpp index ff630f6..518de00 100644 --- a/src/common/core/LibAVR32Module.cpp +++ b/src/common/core/LibAVR32Module.cpp @@ -144,6 +144,11 @@ void LibAVR32Module::encDeltaEvent(int n, int d) } } +std::string LibAVR32Module::gridGetCurrentDeviceId() +{ + return currentConnectedDeviceId; +} + std::string LibAVR32Module::gridGetLastDeviceId(bool owned) { if (owned && !connectionOwned) @@ -154,6 +159,11 @@ std::string LibAVR32Module::gridGetLastDeviceId(bool owned) return lastConnectedDeviceId; } +Grid* LibAVR32Module::gridGetDevice() +{ + return gridConnection; +} + void LibAVR32Module::userReacquireGrid() { if (lastConnectedDeviceId != "" && gridConnection == nullptr) diff --git a/src/common/core/LibAVR32Module.hpp b/src/common/core/LibAVR32Module.hpp index ba0b954..71b2cf4 100644 --- a/src/common/core/LibAVR32Module.hpp +++ b/src/common/core/LibAVR32Module.hpp @@ -2,7 +2,7 @@ #include "GridConnection.hpp" #include "VirtualGridTheme.hpp" #include "rack.hpp" -#include +#include "ActionQueue.hpp" #pragma once @@ -52,7 +52,9 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer void gridDisconnected(bool ownerChanged) override; void gridButtonEvent(int x, int y, bool state) override; void encDeltaEvent(int n, int d) override; + std::string gridGetCurrentDeviceId() override; std::string gridGetLastDeviceId(bool owned) override; + Grid* gridGetDevice() override; void userReacquireGrid(); void userToggleGridConnection(Grid* grid); @@ -91,8 +93,6 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer // Thread-safe for single-producer, single-consumer friend struct TeletypeSceneIO; - typedef std::function Action; - typedef rack::dsp::RingBuffer ActionQueue; ActionQueue audioThreadActions; }; diff --git a/src/virtualgrid/VirtualGridModule.cpp b/src/virtualgrid/VirtualGridModule.cpp index 4f59871..fc4a1ad 100644 --- a/src/virtualgrid/VirtualGridModule.cpp +++ b/src/virtualgrid/VirtualGridModule.cpp @@ -4,6 +4,93 @@ #include #include +struct MirrorModeGridConsumer : GridConsumer +{ + std::string lastConnectedDeviceId; + std::string currentConnectedDeviceId; + bool connectionOwned; + + MirrorModeGridConsumer(VirtualGridModule* module) + : module(module) + { + } + + ~MirrorModeGridConsumer() + { + } + + void gridConnected(Grid* newConnection) override + { + if (newConnection == module) + { // don't mirror self + return; + } + + gridConnection = newConnection; + if (gridConnection) + { + std::string id = gridConnection->getDevice().id; + lastConnectedDeviceId = id; + currentConnectedDeviceId = id; + connectionOwned = true; + } + } + + void gridDisconnected(bool ownerChanged) override + { + gridConnection = nullptr; + currentConnectedDeviceId = ""; + if (ownerChanged) + { + connectionOwned = false; + } + } + + void gridButtonEvent(int x, int y, bool state) override + { + if (module) + { + int w = module->device.width; + auto param = module->getParamQuantity((x + y * w) * 2); + if (param) + { + module->audioThreadActions.push([param, state]() + { param->setImmediateValue(state ? 1 : 0); }); + } + } + } + + void encDeltaEvent(int n, int d) override + { + + } + + std::string gridGetLastDeviceId(bool owned) override + { + if (owned && !connectionOwned) + { + return ""; + } + + return lastConnectedDeviceId; + } + + std::string gridGetCurrentDeviceId() override + { + return currentConnectedDeviceId; + } + + Grid* gridGetDevice() override + { + return gridConnection; + } + +protected: + + Grid* gridConnection; + VirtualGridModule* module; +}; + std::string formatVirtualDeviceId(int64_t id) { std::ostringstream ss; @@ -52,11 +139,14 @@ VirtualGridModule::VirtualGridModule(unsigned w, unsigned h) theme = GridTheme::Yellow; + mirrorModeConsumer = new MirrorModeGridConsumer(this); + clearAll(); } VirtualGridModule::~VirtualGridModule() { + delete mirrorModeConsumer; } void VirtualGridModule::onAdd() @@ -66,6 +156,11 @@ void VirtualGridModule::onAdd() void VirtualGridModule::process(const ProcessArgs& args) { + while (audioThreadActions.size()) + { + audioThreadActions.shift()(); + } + std::vector> presses; std::vector> releases; @@ -138,6 +233,15 @@ const MonomeDevice& VirtualGridModule::getDevice() void VirtualGridModule::updateRow(int x_offset, int y, uint8_t bitfield) { + if (mirrorModeConsumer) + { + auto mirroredGrid = mirrorModeConsumer->gridGetDevice(); + if (mirroredGrid) + { + mirroredGrid->updateRow(x_offset, y, bitfield); + } + } + uint8_t* ptr = ledBuffer + y * 16 + x_offset; for (int i = 0; i < 8; i++) { @@ -147,6 +251,15 @@ void VirtualGridModule::updateRow(int x_offset, int y, uint8_t bitfield) void VirtualGridModule::updateQuadrant(int x_offset, int y_offset, uint8_t* leds) { + if (mirrorModeConsumer) + { + auto mirroredGrid = mirrorModeConsumer->gridGetDevice(); + if (mirroredGrid) + { + mirroredGrid->updateQuadrant(x_offset, y_offset, leds); + } + } + uint8_t* ptr = ledBuffer + y_offset * 16 + x_offset; for (int i = 0; i < 8; i++) { diff --git a/src/virtualgrid/VirtualGridModule.hpp b/src/virtualgrid/VirtualGridModule.hpp index 8c6c714..e8a798c 100644 --- a/src/virtualgrid/VirtualGridModule.hpp +++ b/src/virtualgrid/VirtualGridModule.hpp @@ -2,6 +2,7 @@ #include "GridConnection.hpp" #include "VirtualGridTheme.hpp" #include "rack.hpp" +#include "ActionQueue.hpp" #define GRID_MAX_SIZE 256 @@ -30,6 +31,9 @@ struct VirtualGridModule : rack::Module, Grid void updateQuadrant(int x_offset, int y_offset, uint8_t* leds) override; void updateRing(int n, uint8_t leds[64]) override {}; void clearAll() override; + + GridConsumer* mirrorModeConsumer; + ActionQueue audioThreadActions; }; template diff --git a/src/virtualgrid/VirtualGridWidget.cpp b/src/virtualgrid/VirtualGridWidget.cpp index b7a912c..774aa9c 100644 --- a/src/virtualgrid/VirtualGridWidget.cpp +++ b/src/virtualgrid/VirtualGridWidget.cpp @@ -3,6 +3,7 @@ #include "VirtualGridKey.hpp" #include "VirtualGridModule.hpp" #include "VirtualGridTheme.hpp" +#include "GridConnectionMenu.hpp" using namespace rack; @@ -218,6 +219,8 @@ void VirtualGridWidget::appendContextMenu(Menu * menu) screenshotModulePNG(this, "grid-screenshot.png"); })); + appendDeviceConnectionMenu(menu, grid->mirrorModeConsumer, &grid->audioThreadActions); + menu->addChild(new MenuSeparator()); menu->addChild(createIndexPtrSubmenuItem("Theme", { "Red", "Orange", "Yellow", "White" }, &grid->theme)); menu->addChild(createIndexSubmenuItem("Protocol", {"40h", "Series", "Mext (varibright)"}, From c5f89a2dcf028a4c7e00c0f187a280959795cf4b Mon Sep 17 00:00:00 2001 From: Michael Dewberry Date: Sun, 17 Sep 2023 13:29:51 -0400 Subject: [PATCH 4/6] null-init mirror consumer gridConnection properly --- src/virtualgrid/VirtualGridModule.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/virtualgrid/VirtualGridModule.cpp b/src/virtualgrid/VirtualGridModule.cpp index fc4a1ad..84a946f 100644 --- a/src/virtualgrid/VirtualGridModule.cpp +++ b/src/virtualgrid/VirtualGridModule.cpp @@ -12,6 +12,7 @@ struct MirrorModeGridConsumer : GridConsumer MirrorModeGridConsumer(VirtualGridModule* module) : module(module) + , gridConnection(nullptr) { } From 1c080e59776c6e3cebbef9ab11c457efb317a7e1 Mon Sep 17 00:00:00 2001 From: Michael Dewberry Date: Sun, 17 Sep 2023 14:21:15 -0400 Subject: [PATCH 5/6] Move mirror options to a submenu & only list hardware --- src/common/core/GridConnection/GridConnection.hpp | 1 + src/common/core/GridConnection/GridConnectionMenu.cpp | 10 ++++++++-- src/common/core/GridConnection/GridConnectionMenu.hpp | 2 +- src/common/core/GridConnection/SerialOscGrid.hpp | 1 + src/virtualgrid/VirtualGridModule.hpp | 1 + src/virtualgrid/VirtualGridWidget.cpp | 8 ++++++-- 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/common/core/GridConnection/GridConnection.hpp b/src/common/core/GridConnection/GridConnection.hpp index cf8b258..aa411ac 100644 --- a/src/common/core/GridConnection/GridConnection.hpp +++ b/src/common/core/GridConnection/GridConnection.hpp @@ -15,6 +15,7 @@ struct Grid virtual void updateQuadrant(int x, int y, uint8_t* leds) = 0; virtual void updateRing(int n, uint8_t leds[64]) = 0; virtual void clearAll() = 0; + virtual bool isHardware() = 0; }; struct GridConsumer diff --git a/src/common/core/GridConnection/GridConnectionMenu.cpp b/src/common/core/GridConnection/GridConnectionMenu.cpp index d4bf871..4a41ac8 100644 --- a/src/common/core/GridConnection/GridConnectionMenu.cpp +++ b/src/common/core/GridConnection/GridConnectionMenu.cpp @@ -41,7 +41,7 @@ void menuUserReacquireGrid(GridConsumer* consumer, std::string lastDeviceId, Act } } -void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* actionQueue) +void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* actionQueue, bool hardwareOnly) { std::string currentConnectedDeviceId = consumer->gridGetCurrentDeviceId(); std::string lastConnectedDeviceId = consumer->gridGetLastDeviceId(false); @@ -70,6 +70,11 @@ void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, Action bool preferredDeviceFound = false; for (Grid* grid : GridConnectionManager::get().getGrids()) { + if (hardwareOnly && !grid->isHardware()) + { + continue; + } + auto connectItem = new NewConnectGridItem(); connectItem->text = "└ " + grid->getDevice().type + " (" + grid->getDevice().id + ") "; @@ -96,7 +101,8 @@ void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, Action if (deviceCount == 0) { - menu->addChild(construct(&MenuLabel::text, " (no physical or virtual devices found)")); + std::string message = hardwareOnly ? "no hardware devices found" : "no hardware or virtual devices found"; + menu->addChild(construct(&MenuLabel::text, " (" + message + ")")); } if (currentConnectedDeviceId == "" && lastConnectedDeviceId != "") diff --git a/src/common/core/GridConnection/GridConnectionMenu.hpp b/src/common/core/GridConnection/GridConnectionMenu.hpp index b5e9d27..d4d3be1 100644 --- a/src/common/core/GridConnection/GridConnectionMenu.hpp +++ b/src/common/core/GridConnection/GridConnectionMenu.hpp @@ -4,4 +4,4 @@ #include "GridConnection.hpp" #include "ActionQueue.hpp" -void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* queue); \ No newline at end of file +void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* queue, bool hardwareOnly = false); \ No newline at end of file diff --git a/src/common/core/GridConnection/SerialOscGrid.hpp b/src/common/core/GridConnection/SerialOscGrid.hpp index 917eb4c..b810894 100644 --- a/src/common/core/GridConnection/SerialOscGrid.hpp +++ b/src/common/core/GridConnection/SerialOscGrid.hpp @@ -13,4 +13,5 @@ struct SerialOscGrid : Grid void updateQuadrant(int x, int y, uint8_t* leds) override; void updateRing(int n, uint8_t leds[64]) override; void clearAll() override; + bool isHardware() override { return true; } }; \ No newline at end of file diff --git a/src/virtualgrid/VirtualGridModule.hpp b/src/virtualgrid/VirtualGridModule.hpp index e8a798c..0419882 100644 --- a/src/virtualgrid/VirtualGridModule.hpp +++ b/src/virtualgrid/VirtualGridModule.hpp @@ -31,6 +31,7 @@ struct VirtualGridModule : rack::Module, Grid void updateQuadrant(int x_offset, int y_offset, uint8_t* leds) override; void updateRing(int n, uint8_t leds[64]) override {}; void clearAll() override; + bool isHardware() override { return false; } GridConsumer* mirrorModeConsumer; ActionQueue audioThreadActions; diff --git a/src/virtualgrid/VirtualGridWidget.cpp b/src/virtualgrid/VirtualGridWidget.cpp index b2bba2d..3a20599 100644 --- a/src/virtualgrid/VirtualGridWidget.cpp +++ b/src/virtualgrid/VirtualGridWidget.cpp @@ -214,12 +214,16 @@ void VirtualGridWidget::appendContextMenu(Menu * menu) screenshotModulePNG(this, "grid-screenshot.png"); })); - appendDeviceConnectionMenu(menu, grid->mirrorModeConsumer, &grid->audioThreadActions); + menu->addChild(createSubmenuItem("Mirror hardware grid", "", [=](Menu *childMenu) { + appendDeviceConnectionMenu(childMenu, grid->mirrorModeConsumer, &grid->audioThreadActions, true); + })); menu->addChild(new MenuSeparator()); menu->addChild(createIndexPtrSubmenuItem("Theme", { "Red", "Orange", "Yellow", "White" }, &grid->theme)); menu->addChild(createIndexSubmenuItem("Protocol", {"40h", "Series", "Mext (varibright)"}, - [=]() { return grid ? grid->device.protocol : 0; }, + [=]() { + return grid ? grid->device.protocol : 0; + }, [=](size_t index) { setProtocol(grid, static_cast(index)); })); From 2010b77f66020494f4afc1fe4451b82d91841135 Mon Sep 17 00:00:00 2001 From: Michael Dewberry Date: Sun, 17 Sep 2023 15:22:31 -0400 Subject: [PATCH 6/6] Create GridConsumerBase for shared implementation of IGridConsumer; persist virtual grid mirror settings in patch --- .../core/GridConnection/GridConnection.cpp | 18 ++- .../core/GridConnection/GridConnection.hpp | 22 ++-- .../GridConnection/GridConnectionMenu.cpp | 6 +- .../GridConnection/GridConnectionMenu.hpp | 2 +- .../core/GridConnection/GridConsumerBase.cpp | 106 ++++++++++++++++++ .../core/GridConnection/GridConsumerBase.hpp | 30 +++++ src/common/core/LibAVR32Module.cpp | 102 +++-------------- src/common/core/LibAVR32Module.hpp | 26 ++--- src/virtualgrid/VirtualGridModule.cpp | 69 ++++-------- src/virtualgrid/VirtualGridModule.hpp | 2 +- 10 files changed, 203 insertions(+), 180 deletions(-) create mode 100644 src/common/core/GridConnection/GridConsumerBase.cpp create mode 100644 src/common/core/GridConnection/GridConsumerBase.hpp diff --git a/src/common/core/GridConnection/GridConnection.cpp b/src/common/core/GridConnection/GridConnection.cpp index 09cc317..c3ad4ad 100644 --- a/src/common/core/GridConnection/GridConnection.cpp +++ b/src/common/core/GridConnection/GridConnection.cpp @@ -1,15 +1,11 @@ #include "GridConnection.hpp" -Grid::~Grid() -{ -} - void GridConnectionManager::registerGrid(Grid* grid) { grids.insert(grid); // Check if there's a consumer with a saved connection looking for this grid - GridConsumer* consumerToConnect = nullptr; + IGridConsumer* consumerToConnect = nullptr; for (auto consumer : consumers) { if (!isConnected(consumer) && grid->getDevice().id == consumer->gridGetLastDeviceId(true)) @@ -25,7 +21,7 @@ void GridConnectionManager::registerGrid(Grid* grid) } } -void GridConnectionManager::registerGridConsumer(GridConsumer* consumer) +void GridConnectionManager::registerGridConsumer(IGridConsumer* consumer) { consumers.insert(consumer); @@ -66,13 +62,13 @@ void GridConnectionManager::deregisterGrid(std::string id, bool deleteGrid) } } -void GridConnectionManager::deregisterGridConsumer(GridConsumer* consumer) +void GridConnectionManager::deregisterGridConsumer(IGridConsumer* consumer) { disconnect(consumer); consumers.erase(consumer); } -void GridConnectionManager::connect(Grid* grid, GridConsumer* consumer) +void GridConnectionManager::connect(Grid* grid, IGridConsumer* consumer) { disconnect(consumer, true); disconnect(grid, true); @@ -82,7 +78,7 @@ void GridConnectionManager::connect(Grid* grid, GridConsumer* consumer) consumer->gridConnected(grid); } -bool GridConnectionManager::isConnected(GridConsumer* consumer) +bool GridConnectionManager::isConnected(IGridConsumer* consumer) { return consumerToGridMap.find(consumer) != consumerToGridMap.end(); } @@ -100,7 +96,7 @@ void GridConnectionManager::disconnect(Grid* grid, bool ownerChanged) auto iter = idToConsumerMap.find(grid->getDevice().id); if (iter != idToConsumerMap.end()) { - GridConsumer* consumer = iter->second; + auto consumer = iter->second; consumer->gridDisconnected(ownerChanged); idToConsumerMap.erase(grid->getDevice().id); consumerToGridMap.erase(consumer); @@ -108,7 +104,7 @@ void GridConnectionManager::disconnect(Grid* grid, bool ownerChanged) } } -void GridConnectionManager::disconnect(GridConsumer* consumer, bool ownerChanged) +void GridConnectionManager::disconnect(IGridConsumer* consumer, bool ownerChanged) { if (consumer) { diff --git a/src/common/core/GridConnection/GridConnection.hpp b/src/common/core/GridConnection/GridConnection.hpp index aa411ac..d12b335 100644 --- a/src/common/core/GridConnection/GridConnection.hpp +++ b/src/common/core/GridConnection/GridConnection.hpp @@ -9,7 +9,7 @@ struct SerialOscInterface; struct Grid { - virtual ~Grid(); + virtual ~Grid() {} virtual const MonomeDevice& getDevice() = 0; virtual void updateRow(int x_offset, int y, uint8_t bitfield) = 0; virtual void updateQuadrant(int x, int y, uint8_t* leds) = 0; @@ -18,8 +18,9 @@ struct Grid virtual bool isHardware() = 0; }; -struct GridConsumer +struct IGridConsumer { + virtual ~IGridConsumer() {} virtual void gridConnected(Grid* grid) = 0; virtual void gridDisconnected(bool ownerChanged) = 0; virtual std::string gridGetCurrentDeviceId() = 0; @@ -27,22 +28,21 @@ struct GridConsumer virtual void gridButtonEvent(int x, int y, bool state) = 0; virtual void encDeltaEvent(int n, int d) = 0; virtual Grid* gridGetDevice() = 0; - virtual ~GridConsumer() {}; }; struct GridConnectionManager final { // Only call these from the UI thread void registerGrid(Grid* grid); - void registerGridConsumer(GridConsumer* consumer); + void registerGridConsumer(IGridConsumer* consumer); void deregisterGrid(std::string id, bool deleteGrid = false); - void deregisterGridConsumer(GridConsumer* consumer); + void deregisterGridConsumer(IGridConsumer* consumer); - void connect(Grid* grid, GridConsumer* consumer); - bool isConnected(GridConsumer* consumer); + void connect(Grid* grid, IGridConsumer* consumer); + bool isConnected(IGridConsumer* consumer); bool isConnected(std::string id); void disconnect(Grid* grid, bool ownerChanged = false); - void disconnect(GridConsumer* consumer, bool ownerChanged = false); + void disconnect(IGridConsumer* consumer, bool ownerChanged = false); void dispatchButtonMessage(MonomeDevice* device, int x, int y, bool state); void dispatchEncDeltaMessage(MonomeDevice* device, int n, int d); @@ -58,8 +58,8 @@ struct GridConnectionManager final GridConnectionManager(GridConnectionManager&&) = delete; GridConnectionManager&& operator=(const GridConnectionManager&&) = delete; - std::set consumers; + std::set consumers; std::set grids; - std::map idToConsumerMap; - std::map consumerToGridMap; + std::map idToConsumerMap; + std::map consumerToGridMap; }; \ No newline at end of file diff --git a/src/common/core/GridConnection/GridConnectionMenu.cpp b/src/common/core/GridConnection/GridConnectionMenu.cpp index 4a41ac8..7463f2b 100644 --- a/src/common/core/GridConnection/GridConnectionMenu.cpp +++ b/src/common/core/GridConnection/GridConnectionMenu.cpp @@ -6,7 +6,7 @@ using namespace rack; struct NewConnectGridItem : rack::ui::MenuItem { Grid* grid; - GridConsumer* consumer; + IGridConsumer* consumer; ActionQueue* actionQueue; void onAction(const rack::event::Action& e) override @@ -22,7 +22,7 @@ struct NewConnectGridItem : rack::ui::MenuItem } }; -void menuUserReacquireGrid(GridConsumer* consumer, std::string lastDeviceId, ActionQueue* actionQueue) +void menuUserReacquireGrid(IGridConsumer* consumer, std::string lastDeviceId, ActionQueue* actionQueue) { for (Grid* grid : GridConnectionManager::get().getGrids()) { @@ -41,7 +41,7 @@ void menuUserReacquireGrid(GridConsumer* consumer, std::string lastDeviceId, Act } } -void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* actionQueue, bool hardwareOnly) +void appendDeviceConnectionMenu(rack::Menu* menu, IGridConsumer* consumer, ActionQueue* actionQueue, bool hardwareOnly) { std::string currentConnectedDeviceId = consumer->gridGetCurrentDeviceId(); std::string lastConnectedDeviceId = consumer->gridGetLastDeviceId(false); diff --git a/src/common/core/GridConnection/GridConnectionMenu.hpp b/src/common/core/GridConnection/GridConnectionMenu.hpp index d4d3be1..b624214 100644 --- a/src/common/core/GridConnection/GridConnectionMenu.hpp +++ b/src/common/core/GridConnection/GridConnectionMenu.hpp @@ -4,4 +4,4 @@ #include "GridConnection.hpp" #include "ActionQueue.hpp" -void appendDeviceConnectionMenu(rack::Menu* menu, GridConsumer* consumer, ActionQueue* queue, bool hardwareOnly = false); \ No newline at end of file +void appendDeviceConnectionMenu(rack::Menu* menu, IGridConsumer* consumer, ActionQueue* queue, bool hardwareOnly = false); \ No newline at end of file diff --git a/src/common/core/GridConnection/GridConsumerBase.cpp b/src/common/core/GridConnection/GridConsumerBase.cpp new file mode 100644 index 0000000..e95e01c --- /dev/null +++ b/src/common/core/GridConnection/GridConsumerBase.cpp @@ -0,0 +1,106 @@ +#include "GridConsumerBase.hpp" + +GridConsumerBase::GridConsumerBase() + : lastConnectedDeviceId("") + , currentConnectedDeviceId("") + , gridConnection(nullptr) +{ + +} + +void GridConsumerBase::gridConnected(Grid* newConnection) +{ + gridConnection = newConnection; + if (gridConnection) + { + std::string id = gridConnection->getDevice().id; + lastConnectedDeviceId = id; + currentConnectedDeviceId = id; + connectionOwned = true; + } +} + +void GridConsumerBase::gridDisconnected(bool ownerChanged) +{ + gridConnection = nullptr; + currentConnectedDeviceId = ""; + + if (ownerChanged) + { + connectionOwned = false; + } +} + +std::string GridConsumerBase::gridGetCurrentDeviceId() +{ + return currentConnectedDeviceId; +} + +std::string GridConsumerBase::gridGetLastDeviceId(bool owned) +{ + if (owned && !connectionOwned) + { + return ""; + } + + return lastConnectedDeviceId; +} + +Grid* GridConsumerBase::gridGetDevice() +{ + return gridConnection; +} + +void GridConsumerBase::userReacquireGrid() +{ + if (lastConnectedDeviceId != "" && gridConnection == nullptr) + { + for (Grid* grid : GridConnectionManager::get().getGrids()) + { + if (gridGetLastDeviceId(false) == grid->getDevice().id) + { + GridConnectionManager::get().connect(grid, this); + return; + } + } + } +} + +void GridConsumerBase::toggleGridConnection(Grid* grid) +{ + if (gridConnection == grid) + { + GridConnectionManager::get().disconnect(this, true); + lastConnectedDeviceId = ""; + } + else + { + GridConnectionManager::get().connect(grid, this); + } +} + +void GridConsumerBase::saveGridConnectionToJson(json_t* rootJ) +{ + std::string deviceId = lastConnectedDeviceId; + if (gridConnection) + { + deviceId = gridConnection->getDevice().id; + } + json_object_set_new(rootJ, "connectedDeviceId", json_string(deviceId.c_str())); + json_object_set_new(rootJ, "connectionOwned", json_boolean(connectionOwned)); +} + +void GridConsumerBase::loadGridConnectionFromJson(json_t* rootJ) +{ + json_t* id = json_object_get(rootJ, "connectedDeviceId"); + if (id) + { + lastConnectedDeviceId = json_string_value(id); + } + + json_t* owned = json_object_get(rootJ, "connectionOwned"); + if (owned) + { + connectionOwned = json_boolean_value(owned); + } +} \ No newline at end of file diff --git a/src/common/core/GridConnection/GridConsumerBase.hpp b/src/common/core/GridConnection/GridConsumerBase.hpp new file mode 100644 index 0000000..828adbe --- /dev/null +++ b/src/common/core/GridConnection/GridConsumerBase.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include "GridConnection.hpp" +#include "rack.hpp" + +struct GridConsumerBase : public IGridConsumer +{ + // IGridConsumer partial implementation; child classes implement gridButtonEvent/encDeltaEvent + void gridConnected(Grid* grid) override; + void gridDisconnected(bool ownerChanged) override; + std::string gridGetCurrentDeviceId() override; + std::string gridGetLastDeviceId(bool owned) override; + Grid* gridGetDevice() override; + + GridConsumerBase(); + virtual ~GridConsumerBase() {}; + + void userReacquireGrid(); + + void saveGridConnectionToJson(json_t* rootJ); + void loadGridConnectionFromJson(json_t* rootJ); + + std::string lastConnectedDeviceId; + std::string currentConnectedDeviceId; + bool connectionOwned; + +protected: + void toggleGridConnection(Grid* grid); + Grid* gridConnection; +}; \ No newline at end of file diff --git a/src/common/core/LibAVR32Module.cpp b/src/common/core/LibAVR32Module.cpp index 81bf3e4..1de510a 100644 --- a/src/common/core/LibAVR32Module.cpp +++ b/src/common/core/LibAVR32Module.cpp @@ -4,16 +4,12 @@ #include LibAVR32Module::LibAVR32Module(std::string firmwarePrefix, std::string defaultFirmwareName) -: lastConnectedDeviceId("") -, currentConnectedDeviceId("") -, firmwarePrefix(firmwarePrefix) -, firmwareName(defaultFirmwareName) -, defaultFirmwareName(defaultFirmwareName) -, usbParamId(-1) -, theme(GridTheme::Yellow) + : firmwarePrefix(firmwarePrefix) + , firmwareName(defaultFirmwareName) + , defaultFirmwareName(defaultFirmwareName) + , theme(GridTheme::Yellow) + , usbParamId(-1) { - gridConnection = nullptr; - // make sure serialosc is fully initialized by the time // the user needs to interact with it SerialOscInterface::get(); @@ -44,14 +40,10 @@ void LibAVR32Module::gridConnected(Grid* newConnection) firmware.serialConnectionChange(false, 0, 0, 0, 0); } - gridConnection = newConnection; + GridConsumerBase::gridConnected(newConnection); + if (gridConnection) { - std::string id = gridConnection->getDevice().id; - lastConnectedDeviceId = id; - currentConnectedDeviceId = id; - connectionOwned = true; - auto d = gridConnection->getDevice(); if (d.type == "monome arc 2") { @@ -75,13 +67,9 @@ void LibAVR32Module::gridConnected(Grid* newConnection) void LibAVR32Module::gridDisconnected(bool ownerChanged) { - gridConnection = nullptr; - currentConnectedDeviceId = ""; + GridConsumerBase::gridDisconnected(ownerChanged); + firmware.serialConnectionChange(false, 0, 0, 0, 0); - if (ownerChanged) - { - connectionOwned = false; - } if (usbParamId >= 0) { @@ -151,59 +139,11 @@ void LibAVR32Module::encDeltaEvent(int n, int d) } } -std::string LibAVR32Module::gridGetCurrentDeviceId() -{ - return currentConnectedDeviceId; -} - -std::string LibAVR32Module::gridGetLastDeviceId(bool owned) -{ - if (owned && !connectionOwned) - { - return ""; - } - - return lastConnectedDeviceId; -} - -Grid* LibAVR32Module::gridGetDevice() -{ - return gridConnection; -} - -void LibAVR32Module::userReacquireGrid() -{ - if (lastConnectedDeviceId != "" && gridConnection == nullptr) - { - for (Grid* grid : GridConnectionManager::get().getGrids()) - { - if (gridGetLastDeviceId(false) == grid->getDevice().id) - { - GridConnectionManager::get().connect(grid, this); - return; - } - } - } -} - void LibAVR32Module::userToggleGridConnection(Grid* grid) { audioThreadActions.push([this, grid]() { this->toggleGridConnection(grid); }); } -void LibAVR32Module::toggleGridConnection(Grid* grid) -{ - if (gridConnection == grid) - { - GridConnectionManager::get().disconnect(this, true); - lastConnectedDeviceId = ""; - } - else - { - GridConnectionManager::get().connect(grid, this); - } -} - void LibAVR32Module::readSerialMessages() { uint8_t* msg; @@ -361,19 +301,13 @@ void LibAVR32Module::process(const ProcessArgs& args) json_t* LibAVR32Module::dataToJson() { - std::string deviceId = lastConnectedDeviceId; - if (gridConnection) - { - deviceId = gridConnection->getDevice().id; - } - json_t* rootJ = json_object(); json_object_set_new(rootJ, "firmwareName", json_string(firmwareName.c_str())); - json_object_set_new(rootJ, "connectedDeviceId", json_string(deviceId.c_str())); - json_object_set_new(rootJ, "connectionOwned", json_boolean(connectionOwned)); json_object_set_new(rootJ, "inputRate", json_integer(inputRate)); json_object_set_new(rootJ, "outputRate", json_integer(outputRate)); + saveGridConnectionToJson(rootJ); + void* data = 0; uint32_t size = 0; @@ -394,6 +328,8 @@ json_t* LibAVR32Module::dataToJson() void LibAVR32Module::dataFromJson(json_t* rootJ) { + loadGridConnectionFromJson(rootJ); + json_t* jsonFirmwareName = json_object_get(rootJ, "firmwareName"); std::string newFirmwareName = jsonFirmwareName ? json_string_value(jsonFirmwareName) : defaultFirmwareName; @@ -402,18 +338,6 @@ void LibAVR32Module::dataFromJson(json_t* rootJ) reloadFirmware(false, newFirmwareName); } - json_t* id = json_object_get(rootJ, "connectedDeviceId"); - if (id) - { - lastConnectedDeviceId = json_string_value(id); - } - - json_t* owned = json_object_get(rootJ, "connectionOwned"); - if (owned) - { - connectionOwned = json_boolean_value(owned); - } - void* data = 0; uint32_t size = 0; json_t* jd; diff --git a/src/common/core/LibAVR32Module.hpp b/src/common/core/LibAVR32Module.hpp index dc5186b..25813be 100644 --- a/src/common/core/LibAVR32Module.hpp +++ b/src/common/core/LibAVR32Module.hpp @@ -1,5 +1,6 @@ #include "FirmwareManager.hpp" #include "GridConnection.hpp" +#include "GridConsumerBase.hpp" #include "VirtualGridTheme.hpp" #include "rack.hpp" #include "ActionQueue.hpp" @@ -30,7 +31,7 @@ struct GridConnection; -struct LibAVR32Module : rack::engine::Module, GridConsumer +struct LibAVR32Module : rack::engine::Module, GridConsumerBase { FirmwareManager firmware; @@ -47,28 +48,21 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer virtual void processInputs(const ProcessArgs& args) = 0; virtual void processOutputs(const ProcessArgs& args) = 0; - // GridConsumer methods - void gridConnected(Grid* grid) override; - void gridDisconnected(bool ownerChanged) override; - void gridButtonEvent(int x, int y, bool state) override; - void encDeltaEvent(int n, int d) override; - std::string gridGetCurrentDeviceId() override; - std::string gridGetLastDeviceId(bool owned) override; - Grid* gridGetDevice() override; + // Override IGridConsumer methods implemented by GridConsumerBase (and call base impl) + // TODO: replace this with an event hook system + virtual void gridConnected(Grid* newConnection) override; + virtual void gridDisconnected(bool ownerChanged) override; + // Implement remaining IGridConsumer methods + virtual void gridButtonEvent(int x, int y, bool state) override; + virtual void encDeltaEvent(int n, int d) override; - void userReacquireGrid(); void userToggleGridConnection(Grid* grid); virtual void readSerialMessages(); - void requestReloadFirmware(bool preserveMemory, const std::string& firmwareName = ""); float dacToVolts(uint16_t adc); uint16_t voltsToAdc(float volts); - std::string lastConnectedDeviceId; - std::string currentConnectedDeviceId; - bool connectionOwned; - std::string firmwarePrefix; std::string firmwareName; std::string defaultFirmwareName; @@ -82,9 +76,7 @@ struct LibAVR32Module : rack::engine::Module, GridConsumer protected: void reloadFirmware(bool preserveMemory, const std::string& newFirmware = ""); - void toggleGridConnection(Grid* grid); - Grid* gridConnection; int usbParamId; void setDeviceConnectionParam(int paramId) { usbParamId = paramId; } void processDeviceConnectionParam(); diff --git a/src/virtualgrid/VirtualGridModule.cpp b/src/virtualgrid/VirtualGridModule.cpp index 84a946f..eec57d7 100644 --- a/src/virtualgrid/VirtualGridModule.cpp +++ b/src/virtualgrid/VirtualGridModule.cpp @@ -1,22 +1,18 @@ #include "VirtualGridModule.hpp" #include "LibAVR32Module.hpp" +#include "GridConsumerBase.hpp" #include #include -struct MirrorModeGridConsumer : GridConsumer +struct MirrorModeGridConsumer : GridConsumerBase { - std::string lastConnectedDeviceId; - std::string currentConnectedDeviceId; - bool connectionOwned; - MirrorModeGridConsumer(VirtualGridModule* module) : module(module) - , gridConnection(nullptr) { } - ~MirrorModeGridConsumer() + virtual ~MirrorModeGridConsumer() { } @@ -27,24 +23,7 @@ struct MirrorModeGridConsumer : GridConsumer return; } - gridConnection = newConnection; - if (gridConnection) - { - std::string id = gridConnection->getDevice().id; - lastConnectedDeviceId = id; - currentConnectedDeviceId = id; - connectionOwned = true; - } - } - - void gridDisconnected(bool ownerChanged) override - { - gridConnection = nullptr; - currentConnectedDeviceId = ""; - if (ownerChanged) - { - connectionOwned = false; - } + GridConsumerBase::gridConnected(newConnection); } void gridButtonEvent(int x, int y, bool state) override @@ -66,29 +45,7 @@ struct MirrorModeGridConsumer : GridConsumer } - std::string gridGetLastDeviceId(bool owned) override - { - if (owned && !connectionOwned) - { - return ""; - } - - return lastConnectedDeviceId; - } - - std::string gridGetCurrentDeviceId() override - { - return currentConnectedDeviceId; - } - - Grid* gridGetDevice() override - { - return gridConnection; - } - protected: - - Grid* gridConnection; VirtualGridModule* module; }; @@ -147,6 +104,7 @@ VirtualGridModule::VirtualGridModule(unsigned w, unsigned h) VirtualGridModule::~VirtualGridModule() { + GridConnectionManager::get().deregisterGridConsumer(mirrorModeConsumer); delete mirrorModeConsumer; } @@ -202,6 +160,15 @@ json_t* VirtualGridModule::dataToJson() json_t* rootJ = json_object(); json_object_set_new(rootJ, "protocol", json_integer(device.protocol)); json_object_set_new(rootJ, "theme", json_integer(theme)); + + auto consumer = dynamic_cast(mirrorModeConsumer); + if (consumer) + { + json_t* mirrorJ = json_object(); + consumer->saveGridConnectionToJson(mirrorJ); + json_object_set_new(rootJ, "mirror", mirrorJ); + } + return rootJ; } @@ -225,6 +192,14 @@ void VirtualGridModule::dataFromJson(json_t* rootJ) { theme = static_cast(json_integer_value(json_theme)); } + + auto consumer = dynamic_cast(mirrorModeConsumer); + if (consumer) + { + auto json_mirror = json_object_get(rootJ, "mirror"); + consumer->loadGridConnectionFromJson(json_mirror); + GridConnectionManager::get().registerGridConsumer(consumer); + } } const MonomeDevice& VirtualGridModule::getDevice() diff --git a/src/virtualgrid/VirtualGridModule.hpp b/src/virtualgrid/VirtualGridModule.hpp index 0419882..0a79516 100644 --- a/src/virtualgrid/VirtualGridModule.hpp +++ b/src/virtualgrid/VirtualGridModule.hpp @@ -33,7 +33,7 @@ struct VirtualGridModule : rack::Module, Grid void clearAll() override; bool isHardware() override { return false; } - GridConsumer* mirrorModeConsumer; + IGridConsumer* mirrorModeConsumer; ActionQueue audioThreadActions; };