From 3af971534caee4a4c63647f5a6bf5cc431b16c24 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sat, 9 Jul 2022 00:17:07 +0100 Subject: [PATCH] Allow wasm fetch patchstorage thigns, set system factory template Signed-off-by: falkTX --- include/linux-compat/ghc/filesystem.hpp | 3 + src/CardinalCommon.cpp | 4 + src/CardinalCommon.hpp | 8 ++ src/CardinalPlugin.cpp | 90 +++++++++++------ src/CardinalUI.cpp | 125 ++++++++++++++++++++++-- src/PluginContext.hpp | 13 ++- src/emscripten/patchstorage.php | 43 ++++++++ 7 files changed, 248 insertions(+), 38 deletions(-) create mode 100644 src/emscripten/patchstorage.php diff --git a/include/linux-compat/ghc/filesystem.hpp b/include/linux-compat/ghc/filesystem.hpp index 83e50ce..d7033a4 100644 --- a/include/linux-compat/ghc/filesystem.hpp +++ b/include/linux-compat/ghc/filesystem.hpp @@ -17,6 +17,9 @@ #pragma once +#ifndef __EMSCRIPTEN__ #define GHC_OS_DETECTED #define GHC_OS_LINUX +#endif + #include_next diff --git a/src/CardinalCommon.cpp b/src/CardinalCommon.cpp index 29d5f4b..7d6dc45 100644 --- a/src/CardinalCommon.cpp +++ b/src/CardinalCommon.cpp @@ -100,6 +100,10 @@ std::string getSpecialPath(const SpecialPath type) } #endif +#ifdef DISTRHO_OS_WASM +char* patchStorageSlug = nullptr; +#endif + std::string homeDir() { # ifdef ARCH_WIN diff --git a/src/CardinalCommon.hpp b/src/CardinalCommon.hpp index 16c74a9..03c305d 100644 --- a/src/CardinalCommon.hpp +++ b/src/CardinalCommon.hpp @@ -25,6 +25,10 @@ # define REMOTE_HOST_PORT "2228" #endif +#ifdef DISTRHO_OS_WASM +# define CARDINAL_IMPORTED_TEMPLATE_FILENAME "/imported.vcv" +#endif + extern const std::string CARDINAL_VERSION; namespace rack { @@ -53,6 +57,10 @@ enum SpecialPath { std::string getSpecialPath(SpecialPath type); #endif +#ifdef DISTRHO_OS_WASM +extern char* patchStorageSlug; +#endif + } // namespace rack namespace patchUtils { diff --git a/src/CardinalPlugin.cpp b/src/CardinalPlugin.cpp index 345c811..6ce52ce 100644 --- a/src/CardinalPlugin.cpp +++ b/src/CardinalPlugin.cpp @@ -34,24 +34,38 @@ # undef DEBUG #endif -#ifdef HAVE_LIBLO -# ifdef HEADLESS -# include -# include "extra/Thread.hpp" -# endif -# include "CardinalCommon.hpp" +#if defined(HAVE_LIBLO) && defined(HEADLESS) +# include +# include "extra/Thread.hpp" #endif #include +#include "CardinalCommon.hpp" #include "DistrhoPluginUtils.hpp" #include "PluginContext.hpp" #include "extra/Base64.hpp" -#ifndef DISTRHO_OS_WASM +#ifdef DISTRHO_OS_WASM +# include +#else # include "extra/SharedResourcePointer.hpp" #endif +#if CARDINAL_VARIANT_FX +# define CARDINAL_FACTORY_TEMPLATE_NAME "template-fx.vcv" +#elif CARDINAL_VARIANT_SYNTH +# define CARDINAL_FACTORY_TEMPLATE_NAME "template-synth.vcv" +#else +# define CARDINAL_FACTORY_TEMPLATE_NAME "template.vcv" +#endif + +#ifdef DISTRHO_OS_WASM +# define CARDINAL_TEMPLATE_NAME "template-wasm.vcv" +#else +# define CARDINAL_TEMPLATE_NAME CARDINAL_FACTORY_TEMPLATE_NAME +#endif + static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment #ifndef HEADLESS @@ -63,14 +77,6 @@ static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount + 2; / static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount; #endif -#if CARDINAL_VARIANT_FX -# define CARDINAL_TEMPLATE_NAME "template-fx.vcv" -#elif CARDINAL_VARIANT_SYNTH -# define CARDINAL_TEMPLATE_NAME "template-synth.vcv" -#else -# define CARDINAL_TEMPLATE_NAME "template.vcv" -#endif - namespace rack { namespace engine { void Engine_setAboutToClose(Engine*); @@ -97,6 +103,21 @@ bool d_isDiffHigherThanLimit(const T& v1, const T& v2, const T& limit) // ----------------------------------------------------------------------------------------------------------- +#ifdef DISTRHO_OS_WASM +EM_JS(char*, getPatchStorageSlug, (), { + var searchParams = new URLSearchParams(window.location.search); + var patch = searchParams.get('patchstorage'); + if (!patch) + return null; + var length = lengthBytesUTF8(patch) + 1; + var str = _malloc(length); + stringToUTF8(patch, str, length); + return str; +}); +#endif + +// ----------------------------------------------------------------------------------------------------------- + struct Initializer #if defined(HAVE_LIBLO) && defined(HEADLESS) : public Thread @@ -107,6 +128,7 @@ struct Initializer CardinalBasePlugin* oscPlugin = nullptr; #endif std::string templatePath; + std::string factoryTemplatePath; Initializer(const CardinalBasePlugin* const plugin) { @@ -158,6 +180,7 @@ struct Initializer asset::bundlePath = system::join(resourcePath, "PluginManifests"); asset::systemDir = resourcePath; templatePath = system::join(asset::systemDir, CARDINAL_TEMPLATE_NAME); + factoryTemplatePath = system::join(asset::systemDir, CARDINAL_FACTORY_TEMPLATE_NAME); } } @@ -170,6 +193,7 @@ struct Initializer if (system::exists(system::join(asset::systemDir, "res"))) { templatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR CARDINAL_TEMPLATE_NAME; + factoryTemplatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR CARDINAL_FACTORY_TEMPLATE_NAME; } // If source code dir does not exist use install target prefix as system dir else @@ -187,17 +211,20 @@ struct Initializer asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; #endif - if (! asset::systemDir.empty()) - { - asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); - templatePath = system::join(asset::systemDir, CARDINAL_TEMPLATE_NAME); - } + asset::bundlePath = system::join(asset::systemDir, "PluginManifests"); + templatePath = system::join(asset::systemDir, CARDINAL_TEMPLATE_NAME); + factoryTemplatePath = system::join(asset::systemDir, CARDINAL_FACTORY_TEMPLATE_NAME); } } asset::userDir = asset::systemDir; } + #ifdef DISTRHO_OS_WASM + if ((patchStorageSlug = getPatchStorageSlug()) != nullptr) + templatePath = CARDINAL_IMPORTED_TEMPLATE_FILENAME; + #endif + // Log environment INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str()); INFO("%s", system::getOperatingSystemInfo().c_str()); @@ -206,6 +233,7 @@ struct Initializer INFO("System directory: %s", asset::systemDir.c_str()); INFO("User directory: %s", asset::userDir.c_str()); INFO("Template patch: %s", templatePath.c_str()); + INFO("System template patch: %s", factoryTemplatePath.c_str()); // Report to user if something is wrong with the installation if (asset::systemDir.empty()) @@ -564,6 +592,7 @@ public: context->patch = new rack::patch::Manager; context->patch->autosavePath = fAutosavePath; context->patch->templatePath = fInitializer->templatePath; + context->patch->factoryTemplatePath = fInitializer->factoryTemplatePath; context->event = new rack::widget::EventState; context->scene = new rack::app::Scene; @@ -572,28 +601,33 @@ public: if (! isDummyInstance()) context->window = new rack::window::Window; - context->patch->loadTemplate(); - context->scene->rackScroll->reset(); + #ifdef DISTRHO_OS_WASM + if (rack::patchStorageSlug == nullptr) + #endif + { + context->patch->loadTemplate(); + context->scene->rackScroll->reset(); + } -#if defined(HAVE_LIBLO) && defined(HEADLESS) + #if defined(HAVE_LIBLO) && defined(HEADLESS) fInitializer->oscPlugin = this; -#endif + #endif } ~CardinalPlugin() override { -#if defined(HAVE_LIBLO) && defined(HEADLESS) + #if defined(HAVE_LIBLO) && defined(HEADLESS) fInitializer->oscPlugin = nullptr; -#endif + #endif { const ScopedContext sc(this); context->patch->clear(); // do a little dance to prevent context scene deletion from saving to temp dir -#ifndef HEADLESS + #ifndef HEADLESS const ScopedValueSetter svs(rack::settings::headless, true); -#endif + #endif Engine_setAboutToClose(context->engine); delete context; } diff --git a/src/CardinalUI.cpp b/src/CardinalUI.cpp index bcc39d1..e3d0f55 100644 --- a/src/CardinalUI.cpp +++ b/src/CardinalUI.cpp @@ -31,11 +31,12 @@ #include #ifdef DISTRHO_OS_WASM -#include -#include -#include -#include -#include "CardinalCommon.hpp" +# include +# include +# include +# include +# include "CardinalCommon.hpp" +# include #endif #ifdef NDEBUG @@ -189,6 +190,104 @@ struct WasmWelcomeDialog : rack::widget::OpaqueWidget Widget::draw(args); } }; + +struct WasmPatchStorageLoadingDialog : rack::widget::OpaqueWidget +{ + static const constexpr float margin = 10; + + rack::ui::MenuOverlay* overlay; + + WasmPatchStorageLoadingDialog() + { + using rack::ui::Label; + using rack::ui::MenuOverlay; + using rack::ui::SequentialLayout; + + box.size = rack::math::Vec(300, 50); + + SequentialLayout* const layout = new SequentialLayout; + layout->box.pos = rack::math::Vec(0, 0); + layout->box.size = box.size; + layout->orientation = SequentialLayout::VERTICAL_ORIENTATION; + layout->margin = rack::math::Vec(margin, margin); + layout->spacing = rack::math::Vec(margin, margin); + layout->wrap = false; + addChild(layout); + + Label* const label = new Label; + label->box.size.x = box.size.x - 2*margin; + label->box.size.y = box.size.y - 2*margin - 40; + label->fontSize = 16; + label->text = "Load patch from PatchStorage...\n"; + layout->addChild(label); + + overlay = new MenuOverlay; + overlay->bgColor = nvgRGBAf(0, 0, 0, 0.33); + overlay->addChild(this); + APP->scene->addChild(overlay); + } + + void step() override + { + OpaqueWidget::step(); + box.pos = parent->box.size.minus(box.size).div(2).round(); + } + + void draw(const DrawArgs& args) override + { + bndMenuBackground(args.vg, 0.0, 0.0, box.size.x, box.size.y, 0); + Widget::draw(args); + } +}; + +static void downloadPatchStorageFailed(const char* const filename) +{ + d_stdout("downloadPatchStorageFailed %s", filename); + CardinalPluginContext* const context = static_cast(APP); + CardinalBaseUI* const ui = static_cast(context->ui); + + if (ui->psDialog != nullptr) + { + ui->psDialog->overlay->requestDelete(); + asyncDialog::create("Failed to fetch patch from PatchStorage"); + } + + using namespace rack; + context->patch->templatePath = system::join(asset::systemDir, "template-synth.vcv"); // FIXME + context->patch->loadTemplate(); + context->scene->rackScroll->reset(); +} + +static void downloadPatchStorageSucceeded(const char* const filename) +{ + d_stdout("downloadPatchStorageSucceeded %s | %s", filename, APP->patch->templatePath.c_str()); + CardinalPluginContext* const context = static_cast(APP); + CardinalBaseUI* const ui = static_cast(context->ui); + + ui->psDialog->overlay->requestDelete(); + ui->psDialog = nullptr; + + if (FILE* f = fopen(filename, "r")) + { + uint8_t buf[8] = {}; + fread(buf, 8, 1, f); + d_stdout("read patch %x %x %x %x %x %x %x %x", + buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); + fclose(f); + } + + try { + context->patch->load(CARDINAL_IMPORTED_TEMPLATE_FILENAME); + } catch (rack::Exception& e) { + const std::string message = rack::string::f("Could not load patch: %s", e.what()); + asyncDialog::create(message.c_str()); + return; + } + + context->scene->rackScroll->reset(); + context->patch->path = ""; + context->history->setSaved(); +} #endif // ----------------------------------------------------------------------------------------------------------- @@ -288,7 +387,21 @@ public: } #ifdef DISTRHO_OS_WASM - new WasmWelcomeDialog(); + if (rack::patchStorageSlug != nullptr) + { + std::string url("/patchstorage.php?slug="); + url += rack::patchStorageSlug; + std::free(rack::patchStorageSlug); + rack::patchStorageSlug = nullptr; + + psDialog = new WasmPatchStorageLoadingDialog(); + emscripten_async_wget(url.c_str(), context->patch->templatePath.c_str(), + downloadPatchStorageSucceeded, downloadPatchStorageFailed); + } + else + { + new WasmWelcomeDialog(); + } #endif context->window->step(); diff --git a/src/PluginContext.hpp b/src/PluginContext.hpp index 27897f4..9874464 100644 --- a/src/PluginContext.hpp +++ b/src/PluginContext.hpp @@ -122,10 +122,6 @@ void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index, // ----------------------------------------------------------------------------------------------------------- -struct CardinalAudioDevice; -struct CardinalMidiInputDevice; -struct CardinalMidiOutputDevice; - CardinalPluginContext* getRackContextFromPlugin(void* ptr); class CardinalBasePlugin : public Plugin { @@ -139,12 +135,18 @@ public: }; #ifndef HEADLESS +struct WasmPatchStorageLoadingDialog; + class CardinalBaseUI : public UI { public: CardinalPluginContext* const context; bool saving; bool savingUncompressed; + #ifdef DISTRHO_OS_WASM + WasmPatchStorageLoadingDialog* psDialog; + #endif + // for 3rd party modules std::function filebrowseraction; FileBrowserHandle filebrowserhandle; @@ -154,6 +156,9 @@ public: context(getRackContextFromPlugin(getPluginInstancePointer())), saving(false), savingUncompressed(false), + #ifdef DISTRHO_OS_WASM + psDialog(nullptr), + #endif filebrowseraction(), filebrowserhandle(nullptr) { diff --git a/src/emscripten/patchstorage.php b/src/emscripten/patchstorage.php new file mode 100644 index 0000000..b73b6b6 --- /dev/null +++ b/src/emscripten/patchstorage.php @@ -0,0 +1,43 @@ +