From e29243af60caafa10b11965f79afb95ec89b2a1a Mon Sep 17 00:00:00 2001 From: falkTX Date: Mon, 24 Jan 2022 11:28:23 +0000 Subject: [PATCH] Move all liblo stuff to the same file, add crude auto-deploy mode Signed-off-by: falkTX --- src/CardinalCommon.cpp | 26 ---- src/CardinalCommon.hpp | 17 +-- src/override/.generate-diffs.sh | 2 +- src/override/MenuBar.cpp | 54 ++------ src/override/Scene.cpp | 131 ++++++++++++++++++- src/override/diffs/MenuBar.cpp.diff | 100 +++++---------- src/override/diffs/Scene.cpp.diff | 188 ++++++++++++++++++++++++---- 7 files changed, 345 insertions(+), 173 deletions(-) diff --git a/src/CardinalCommon.cpp b/src/CardinalCommon.cpp index 6bc043f..e36d47a 100644 --- a/src/CardinalCommon.cpp +++ b/src/CardinalCommon.cpp @@ -37,17 +37,12 @@ #include #include #include -#include #include #ifdef NDEBUG # undef DEBUG #endif -#ifdef HAVE_LIBLO -# include -#endif - // for finding home dir #ifndef ARCH_WIN # include @@ -215,27 +210,6 @@ void saveAsDialog() #endif } -void deployToMOD() -{ -#ifdef HAVE_LIBLO - const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); - DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); - - APP->engine->prepareSave(); - APP->patch->saveAutosave(); - APP->patch->cleanAutosave(); - std::vector data(rack::system::archiveDirectory(APP->patch->autosavePath, 1)); - - if (const lo_blob blob = lo_blob_new(data.size(), data.data())) - { - lo_send(addr, "/load", "b", blob); - lo_blob_free(blob); - } - - lo_address_free(addr); -#endif -} - } void async_dialog_filebrowser(const bool saving, diff --git a/src/CardinalCommon.hpp b/src/CardinalCommon.hpp index 18859a6..871bcee 100644 --- a/src/CardinalCommon.hpp +++ b/src/CardinalCommon.hpp @@ -25,8 +25,7 @@ # define REMOTE_HOST_PORT "2228" #endif -namespace rack -{ +namespace rack { namespace settings { extern int rateLimit; @@ -36,10 +35,9 @@ namespace ui { struct Menu; } -} +} // namespace rack -namespace patchUtils -{ +namespace patchUtils { void loadDialog(); void loadPathDialog(const std::string& path); @@ -49,6 +47,11 @@ void revertDialog(); void saveDialog(const std::string& path); void saveAsDialog(); void appendSelectionContextMenu(rack::ui::Menu* menu); -void deployToMOD(); -} +bool connectToRemote(); +bool isRemoteConnected(); +bool isRemoteAutoDeployed(); +void setRemoteAutoDeploy(bool autoDeploy); +void deployToRemote(); + +} // namespace patchUtils diff --git a/src/override/.generate-diffs.sh b/src/override/.generate-diffs.sh index 2e97058..68b2646 100755 --- a/src/override/.generate-diffs.sh +++ b/src/override/.generate-diffs.sh @@ -1,6 +1,6 @@ #!/bin/bash -set -e +cd $(dirname ${0}) diff -U3 ../Rack/dep/oui-blendish/blendish.c blendish.c > diffs/blendish.c.diff diff -U3 ../Rack/src/common.cpp common.cpp > diffs/common.cpp.diff diff --git a/src/override/MenuBar.cpp b/src/override/MenuBar.cpp index 526eea8..427d627 100644 --- a/src/override/MenuBar.cpp +++ b/src/override/MenuBar.cpp @@ -86,27 +86,6 @@ struct MenuButton : ui::Button { struct FileButton : MenuButton { const bool isStandalone; -#ifdef HAVE_LIBLO - bool oscConnected = false; - lo_server oscServer = nullptr; - - static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) - { - d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); - - if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') { - d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); - if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) - static_cast(self)->oscConnected = true; - } - return 0; - } - - ~FileButton() { - lo_server_free(oscServer); - } -#endif - FileButton(const bool standalone) : MenuButton(), isStandalone(standalone) {} @@ -133,21 +112,19 @@ struct FileButton : MenuButton { })); #ifdef HAVE_LIBLO - if (oscServer == nullptr || !oscConnected) { - menu->addChild(createMenuItem("Connect to MOD", "", [this]() { - if (oscServer == nullptr) { - oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); - DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); - lo_server_add_method(oscServer, "/resp", nullptr, osc_handler, this); - } - const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); - DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); - lo_send(addr, "/hello", ""); - lo_address_free(addr); + if (patchUtils::isRemoteConnected()) { + menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { + patchUtils::deployToRemote(); })); + + const bool autoDeploy = patchUtils::isRemoteAutoDeployed(); + menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", + [=]() {return autoDeploy;}, + [=]() {patchUtils::setRemoteAutoDeploy(!autoDeploy);} + )); } else { - menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { - patchUtils::deployToMOD(); + menu->addChild(createMenuItem("Connect to MOD", "", [this]() { + patchUtils::connectToRemote(); })); } #endif @@ -171,15 +148,6 @@ struct FileButton : MenuButton { })); }; } - -#ifdef HAVE_LIBLO - void step() override { - MenuButton::step(); - if (oscServer != nullptr) { - while (lo_server_recv_noblock(oscServer, 0) != 0) {} - } - } -#endif }; diff --git a/src/override/Scene.cpp b/src/override/Scene.cpp index 26a0193..7740d83 100644 --- a/src/override/Scene.cpp +++ b/src/override/Scene.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -41,7 +42,16 @@ #include #include +#ifdef NDEBUG +# undef DEBUG +#endif + +#ifdef HAVE_LIBLO +# include +#endif + #include "../CardinalCommon.hpp" +#include "DistrhoUtils.hpp" namespace rack { @@ -92,12 +102,32 @@ struct Scene::Internal { ResizeHandle* resizeHandle; bool heldArrowKeys[4] = {}; -}; +#ifdef HAVE_LIBLO + double lastSceneChangeTime = 0.0; + int historyActionIndex = -1; -void hideResizeHandle(Scene* scene) { - scene->internal->resizeHandle->hide(); -} + bool oscAutoDeploy = false; + bool oscConnected = false; + lo_server oscServer = nullptr; + + static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) + { + d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); + + if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') { + d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); + if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) + static_cast(self)->oscConnected = true; + } + return 0; + } + + ~Internal() { + lo_server_free(oscServer); + } +#endif +}; Scene::Scene() { @@ -121,6 +151,11 @@ Scene::Scene() { } +void hideResizeHandle(Scene* scene) { + scene->internal->resizeHandle->hide(); +} + + Scene::~Scene() { delete internal; } @@ -167,6 +202,22 @@ void Scene::step() { rackScroll->offset += arrowDelta * arrowSpeed; } +#ifdef HAVE_LIBLO + if (internal->oscServer != nullptr) { + while (lo_server_recv_noblock(internal->oscServer, 0) != 0) {} + + if (internal->oscAutoDeploy) { + const int actionIndex = APP->history->actionIndex; + const double time = system::getTime(); + if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) { + internal->historyActionIndex = actionIndex; + internal->lastSceneChangeTime = time; + patchUtils::deployToRemote(); + } + } + } +#endif + Widget::step(); } @@ -258,7 +309,7 @@ void Scene::onHoverKey(const HoverKeyEvent& e) { e.consume(this); } if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { - patchUtils::deployToMOD(); + patchUtils::deployToRemote(); e.consume(this); } @@ -384,3 +435,73 @@ void Scene::onPathDrop(const PathDropEvent& e) { } // namespace app } // namespace rack + + +namespace patchUtils { + + +bool connectToRemote() { + rack::app::Scene::Internal* const internal = APP->scene->internal; + + if (internal->oscServer == nullptr) { + const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); + DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false); + lo_server_add_method(oscServer, "/resp", nullptr, rack::app::Scene::Internal::osc_handler, internal); + internal->oscServer = oscServer; + } + + const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr, false); + lo_send(addr, "/hello", ""); + lo_address_free(addr); + + return true; +} + + +bool isRemoteConnected() { +#ifdef HAVE_LIBLO + return APP->scene->internal->oscConnected; +#else + return false; +#endif +} + + +bool isRemoteAutoDeployed() { +#ifdef HAVE_LIBLO + return APP->scene->internal->oscAutoDeploy; +#else + return false; +#endif +} + + +void setRemoteAutoDeploy(bool autoDeploy) { +#ifdef HAVE_LIBLO + APP->scene->internal->oscAutoDeploy = autoDeploy; +#endif +} + + +void deployToRemote() { +#ifdef HAVE_LIBLO + const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); + DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); + + APP->engine->prepareSave(); + APP->patch->saveAutosave(); + APP->patch->cleanAutosave(); + std::vector data(rack::system::archiveDirectory(APP->patch->autosavePath, 1)); + + if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { + lo_send(addr, "/load", "b", blob); + lo_blob_free(blob); + } + + lo_address_free(addr); +#endif +} + + +} // namespace patchUtils diff --git a/src/override/diffs/MenuBar.cpp.diff b/src/override/diffs/MenuBar.cpp.diff index 43b1057..0a95461 100644 --- a/src/override/diffs/MenuBar.cpp.diff +++ b/src/override/diffs/MenuBar.cpp.diff @@ -1,5 +1,5 @@ --- ../Rack/src/app/MenuBar.cpp 2022-01-15 14:44:46.391280963 +0000 -+++ MenuBar.cpp 2022-01-23 17:13:16.500279828 +0000 ++++ MenuBar.cpp 2022-01-24 11:25:15.507061204 +0000 @@ -1,8 +1,33 @@ +/* + * DISTRHO Cardinal Plugin @@ -48,7 +48,7 @@ namespace rack { namespace app { -@@ -48,80 +78,108 @@ +@@ -48,79 +78,75 @@ }; @@ -73,27 +73,6 @@ struct FileButton : MenuButton { + const bool isStandalone; + -+#ifdef HAVE_LIBLO -+ bool oscConnected = false; -+ lo_server oscServer = nullptr; -+ -+ static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) -+ { -+ d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); -+ -+ if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') { -+ d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); -+ if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) -+ static_cast(self)->oscConnected = true; -+ } -+ return 0; -+ } -+ -+ ~FileButton() { -+ lo_server_free(oscServer); -+ } -+#endif -+ + FileButton(const bool standalone) + : MenuButton(), isStandalone(standalone) {} + @@ -124,10 +103,6 @@ - menu->addChild(createMenuItem("Save", RACK_MOD_CTRL_NAME "+S", []() { - APP->patch->saveDialog(); -- })); -- -- menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() { -- APP->patch->saveAsDialog(); + // NOTE: will do nothing if path is empty, intentionally + patchUtils::saveDialog(APP->patch->path); + }, APP->patch->path.empty())); @@ -136,25 +111,26 @@ + patchUtils::saveAsDialog(); })); -- menu->addChild(createMenuItem("Save a copy", "", []() { -- APP->patch->saveAsDialog(false); +- menu->addChild(createMenuItem("Save as", RACK_MOD_CTRL_NAME "+Shift+S", []() { +- APP->patch->saveAsDialog(); - })); +#ifdef HAVE_LIBLO -+ if (oscServer == nullptr || !oscConnected) { -+ menu->addChild(createMenuItem("Connect to MOD", "", [this]() { -+ if (oscServer == nullptr) { -+ oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); -+ DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr,); -+ lo_server_add_method(oscServer, "/resp", nullptr, osc_handler, this); -+ } -+ const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); -+ DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); -+ lo_send(addr, "/hello", ""); -+ lo_address_free(addr); ++ if (patchUtils::isRemoteConnected()) { ++ menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { ++ patchUtils::deployToRemote(); + })); + +- menu->addChild(createMenuItem("Save a copy", "", []() { +- APP->patch->saveAsDialog(false); +- })); ++ const bool autoDeploy = patchUtils::isRemoteAutoDeployed(); ++ menu->addChild(createCheckMenuItem("Auto deploy to MOD", "", ++ [=]() {return autoDeploy;}, ++ [=]() {patchUtils::setRemoteAutoDeploy(!autoDeploy);} ++ )); + } else { -+ menu->addChild(createMenuItem("Deploy to MOD", "F7", []() { -+ patchUtils::deployToMOD(); ++ menu->addChild(createMenuItem("Connect to MOD", "", [this]() { ++ patchUtils::connectToRemote(); + })); + } +#endif @@ -189,19 +165,9 @@ + })); + }; } -+ -+#ifdef HAVE_LIBLO -+ void step() override { -+ MenuButton::step(); -+ if (oscServer != nullptr) { -+ while (lo_server_recv_noblock(oscServer, 0) != 0) {} -+ } -+ } -+#endif }; - -@@ -166,7 +224,7 @@ +@@ -166,7 +192,7 @@ menu->addChild(new ui::MenuSeparator); @@ -210,7 +176,7 @@ } }; -@@ -256,7 +314,7 @@ +@@ -256,7 +282,7 @@ return settings::cableTension; } float getDefaultValue() override { @@ -219,7 +185,7 @@ } float getDisplayValue() override { return getValue() * 100; -@@ -421,28 +479,9 @@ +@@ -421,28 +447,9 @@ haloBrightnessSlider->box.size.x = 250.0; menu->addChild(haloBrightnessSlider); @@ -249,7 +215,7 @@ static const std::vector knobModeLabels = { "Linear", -@@ -467,6 +506,21 @@ +@@ -467,6 +474,21 @@ menu->addChild(knobScrollSensitivitySlider); menu->addChild(createBoolPtrMenuItem("Lock module positions", "", &settings::lockModules)); @@ -271,7 +237,7 @@ } }; -@@ -476,47 +530,6 @@ +@@ -476,47 +498,6 @@ //////////////////// @@ -319,7 +285,7 @@ struct EngineButton : MenuButton { void onAction(const ActionEvent& e) override { ui::Menu* menu = createMenu(); -@@ -529,269 +542,6 @@ +@@ -529,269 +510,6 @@ menu->addChild(createMenuItem("Performance meters", cpuMeterText, [=]() { settings::cpuMeter ^= true; })); @@ -589,7 +555,7 @@ } }; -@@ -802,63 +552,24 @@ +@@ -802,63 +520,24 @@ struct HelpButton : MenuButton { @@ -616,14 +582,14 @@ - menu->addChild(createMenuItem("VCVRack.com", "", [=]() { - system::openBrowser("https://vcvrack.com/"); -- })); -- -- menu->addChild(createMenuItem("Open user folder", "", [=]() { -- system::openDirectory(asset::user("")); + menu->addChild(createMenuItem("Cardinal Project page", "", [=]() { + system::openBrowser("https://github.com/DISTRHO/Cardinal/"); })); +- menu->addChild(createMenuItem("Open user folder", "", [=]() { +- system::openDirectory(asset::user("")); +- })); +- - if (library::isAppUpdateAvailable()) { - menu->addChild(new ui::MenuSeparator); - @@ -658,7 +624,7 @@ } }; -@@ -908,7 +619,9 @@ +@@ -908,7 +587,9 @@ struct MenuBar : widget::OpaqueWidget { MeterLabel* meterLabel; @@ -669,7 +635,7 @@ const float margin = 5; box.size.y = BND_WIDGET_HEIGHT + 2 * margin; -@@ -917,7 +630,7 @@ +@@ -917,7 +598,7 @@ layout->spacing = math::Vec(0, 0); addChild(layout); @@ -678,7 +644,7 @@ fileButton->text = "File"; layout->addChild(fileButton); -@@ -933,10 +646,6 @@ +@@ -933,10 +614,6 @@ engineButton->text = "Engine"; layout->addChild(engineButton); @@ -689,7 +655,7 @@ HelpButton* helpButton = new HelpButton; helpButton->text = "Help"; layout->addChild(helpButton); -@@ -971,7 +680,11 @@ +@@ -971,7 +648,11 @@ widget::Widget* createMenuBar() { diff --git a/src/override/diffs/Scene.cpp.diff b/src/override/diffs/Scene.cpp.diff index 5a29cf7..db2a1be 100644 --- a/src/override/diffs/Scene.cpp.diff +++ b/src/override/diffs/Scene.cpp.diff @@ -1,5 +1,5 @@ --- ../Rack/src/app/Scene.cpp 2021-12-14 21:35:44.414568198 +0000 -+++ Scene.cpp 2022-01-23 17:13:24.715889665 +0000 ++++ Scene.cpp 2022-01-24 11:12:33.268767988 +0000 @@ -1,3 +1,30 @@ +/* + * DISTRHO Cardinal Plugin @@ -31,11 +31,28 @@ #include #include -@@ -14,31 +41,49 @@ +@@ -7,6 +34,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -14,31 +42,58 @@ #include #include ++#ifdef NDEBUG ++# undef DEBUG ++#endif ++ ++#ifdef HAVE_LIBLO ++# include ++#endif ++ +#include "../CardinalCommon.hpp" ++#include "DistrhoUtils.hpp" + namespace rack { @@ -74,16 +91,16 @@ + nvgStroke(args.vg); + + nvgStrokeColor(args.vg, nvgRGBf(0, 0, 0)); -+ -+ nvgBeginPath(args.vg); -+ nvgMoveTo(args.vg, box.size.x+1, 0); -+ nvgLineTo(args.vg, 0, box.size.y+1); -+ nvgStroke(args.vg); - void onDragMove(const DragMoveEvent& e) override { - size = size.plus(e.mouseDelta); - APP->window->setSize(size.round()); + nvgBeginPath(args.vg); ++ nvgMoveTo(args.vg, box.size.x+1, 0); ++ nvgLineTo(args.vg, 0, box.size.y+1); ++ nvgStroke(args.vg); ++ ++ nvgBeginPath(args.vg); + nvgMoveTo(args.vg, box.size.x + 6, 0); + nvgLineTo(args.vg, 0, box.size.y + 6); + nvgStroke(args.vg); @@ -95,25 +112,42 @@ } }; -@@ -46,12 +91,15 @@ +@@ -46,9 +101,32 @@ struct Scene::Internal { ResizeHandle* resizeHandle; - double lastAutosaveTime = 0.0; - bool heldArrowKeys[4] = {}; - }; - - -+void hideResizeHandle(Scene* scene) { -+ scene->internal->resizeHandle->hide(); -+} + ++#ifdef HAVE_LIBLO ++ double lastSceneChangeTime = 0.0; ++ int historyActionIndex = -1; ++ ++ bool oscAutoDeploy = false; ++ bool oscConnected = false; ++ lo_server oscServer = nullptr; ++ ++ static int osc_handler(const char* const path, const char* const types, lo_arg** argv, const int argc, lo_message, void* const self) ++ { ++ d_stdout("osc_handler(\"%s\", \"%s\", %p, %i)", path, types, argv, argc); + - Scene::Scene() { - internal = new Internal; ++ if (std::strcmp(path, "/resp") == 0 && argc == 2 && types[0] == 's' && types[1] == 's') { ++ d_stdout("osc_handler(\"%s\", ...) - got resp | '%s' '%s'", path, &argv[0]->s, &argv[1]->s); ++ if (std::strcmp(&argv[0]->s, "hello") == 0 && std::strcmp(&argv[1]->s, "ok") == 0) ++ static_cast(self)->oscConnected = true; ++ } ++ return 0; ++ } ++ ++ ~Internal() { ++ lo_server_free(oscServer); ++ } ++#endif + }; -@@ -67,13 +115,8 @@ + +@@ -67,17 +145,17 @@ browser->hide(); addChild(browser); @@ -128,7 +162,16 @@ addChild(internal->resizeHandle); } -@@ -89,32 +132,13 @@ + ++void hideResizeHandle(Scene* scene) { ++ scene->internal->resizeHandle->hide(); ++} ++ ++ + Scene::~Scene() { + delete internal; + } +@@ -89,32 +167,13 @@ void Scene::step() { @@ -162,7 +205,30 @@ // Scroll RackScrollWidget with arrow keys math::Vec arrowDelta; if (internal->heldArrowKeys[0]) { -@@ -172,7 +196,7 @@ +@@ -143,6 +202,22 @@ + rackScroll->offset += arrowDelta * arrowSpeed; + } + ++#ifdef HAVE_LIBLO ++ if (internal->oscServer != nullptr) { ++ while (lo_server_recv_noblock(internal->oscServer, 0) != 0) {} ++ ++ if (internal->oscAutoDeploy) { ++ const int actionIndex = APP->history->actionIndex; ++ const double time = system::getTime(); ++ if (internal->historyActionIndex != actionIndex && time - internal->lastSceneChangeTime >= 5.0) { ++ internal->historyActionIndex = actionIndex; ++ internal->lastSceneChangeTime = time; ++ patchUtils::deployToRemote(); ++ } ++ } ++ } ++#endif ++ + Widget::step(); + } + +@@ -172,7 +247,7 @@ if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { // DEBUG("key '%d '%c' scancode %d '%c' keyName '%s'", e.key, e.key, e.scancode, e.scancode, e.keyName.c_str()); if (e.keyName == "n" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { @@ -171,7 +237,7 @@ e.consume(this); } if (e.keyName == "q" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -180,19 +204,20 @@ +@@ -180,19 +255,20 @@ e.consume(this); } if (e.keyName == "o" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { @@ -196,7 +262,7 @@ e.consume(this); } if (e.keyName == "z" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { -@@ -232,10 +257,8 @@ +@@ -232,10 +308,8 @@ settings::cpuMeter ^= true; e.consume(this); } @@ -205,11 +271,11 @@ - // The MenuBar will be hidden when the mouse moves over the RackScrollWidget. - // menuBar->hide(); + if (e.key == GLFW_KEY_F7 && (e.mods & RACK_MOD_MASK) == 0) { -+ patchUtils::deployToMOD(); ++ patchUtils::deployToRemote(); e.consume(this); } -@@ -326,13 +349,6 @@ +@@ -326,13 +400,6 @@ // Key commands that can be overridden by children if (e.action == GLFW_PRESS || e.action == GLFW_REPEAT) { @@ -223,7 +289,7 @@ if (e.keyName == "v" && (e.mods & RACK_MOD_MASK) == RACK_MOD_CTRL) { rack->pasteClipboardAction(); e.consume(this); -@@ -351,7 +367,7 @@ +@@ -351,7 +418,7 @@ std::string extension = system::getExtension(path); if (extension == ".vcv") { @@ -232,3 +298,77 @@ e.consume(this); return; } +@@ -368,3 +435,73 @@ + + } // namespace app + } // namespace rack ++ ++ ++namespace patchUtils { ++ ++ ++bool connectToRemote() { ++ rack::app::Scene::Internal* const internal = APP->scene->internal; ++ ++ if (internal->oscServer == nullptr) { ++ const lo_server oscServer = lo_server_new_with_proto(nullptr, LO_UDP, nullptr); ++ DISTRHO_SAFE_ASSERT_RETURN(oscServer != nullptr, false); ++ lo_server_add_method(oscServer, "/resp", nullptr, rack::app::Scene::Internal::osc_handler, internal); ++ internal->oscServer = oscServer; ++ } ++ ++ const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); ++ DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr, false); ++ lo_send(addr, "/hello", ""); ++ lo_address_free(addr); ++ ++ return true; ++} ++ ++ ++bool isRemoteConnected() { ++#ifdef HAVE_LIBLO ++ return APP->scene->internal->oscConnected; ++#else ++ return false; ++#endif ++} ++ ++ ++bool isRemoteAutoDeployed() { ++#ifdef HAVE_LIBLO ++ return APP->scene->internal->oscAutoDeploy; ++#else ++ return false; ++#endif ++} ++ ++ ++void setRemoteAutoDeploy(bool autoDeploy) { ++#ifdef HAVE_LIBLO ++ APP->scene->internal->oscAutoDeploy = autoDeploy; ++#endif ++} ++ ++ ++void deployToRemote() { ++#ifdef HAVE_LIBLO ++ const lo_address addr = lo_address_new_with_proto(LO_UDP, REMOTE_HOST, REMOTE_HOST_PORT); ++ DISTRHO_SAFE_ASSERT_RETURN(addr != nullptr,); ++ ++ APP->engine->prepareSave(); ++ APP->patch->saveAutosave(); ++ APP->patch->cleanAutosave(); ++ std::vector data(rack::system::archiveDirectory(APP->patch->autosavePath, 1)); ++ ++ if (const lo_blob blob = lo_blob_new(data.size(), data.data())) { ++ lo_send(addr, "/load", "b", blob); ++ lo_blob_free(blob); ++ } ++ ++ lo_address_free(addr); ++#endif ++} ++ ++ ++} // namespace patchUtils