Browse Source

Allow wasm fetch patchstorage thigns, set system factory template

Signed-off-by: falkTX <falktx@falktx.com>
tags/22.07
falkTX 2 years ago
parent
commit
3af971534c
Signed by: falkTX <falktx@falktx.com> GPG Key ID: CDBAA37ABC74FBA0
7 changed files with 248 additions and 38 deletions
  1. +3
    -0
      include/linux-compat/ghc/filesystem.hpp
  2. +4
    -0
      src/CardinalCommon.cpp
  3. +8
    -0
      src/CardinalCommon.hpp
  4. +62
    -28
      src/CardinalPlugin.cpp
  5. +119
    -6
      src/CardinalUI.cpp
  6. +9
    -4
      src/PluginContext.hpp
  7. +43
    -0
      src/emscripten/patchstorage.php

+ 3
- 0
include/linux-compat/ghc/filesystem.hpp View File

@@ -17,6 +17,9 @@


#pragma once #pragma once


#ifndef __EMSCRIPTEN__
#define GHC_OS_DETECTED #define GHC_OS_DETECTED
#define GHC_OS_LINUX #define GHC_OS_LINUX
#endif

#include_next <ghc/filesystem.hpp> #include_next <ghc/filesystem.hpp>

+ 4
- 0
src/CardinalCommon.cpp View File

@@ -100,6 +100,10 @@ std::string getSpecialPath(const SpecialPath type)
} }
#endif #endif


#ifdef DISTRHO_OS_WASM
char* patchStorageSlug = nullptr;
#endif

std::string homeDir() std::string homeDir()
{ {
# ifdef ARCH_WIN # ifdef ARCH_WIN


+ 8
- 0
src/CardinalCommon.hpp View File

@@ -25,6 +25,10 @@
# define REMOTE_HOST_PORT "2228" # define REMOTE_HOST_PORT "2228"
#endif #endif


#ifdef DISTRHO_OS_WASM
# define CARDINAL_IMPORTED_TEMPLATE_FILENAME "/imported.vcv"
#endif

extern const std::string CARDINAL_VERSION; extern const std::string CARDINAL_VERSION;


namespace rack { namespace rack {
@@ -53,6 +57,10 @@ enum SpecialPath {
std::string getSpecialPath(SpecialPath type); std::string getSpecialPath(SpecialPath type);
#endif #endif


#ifdef DISTRHO_OS_WASM
extern char* patchStorageSlug;
#endif

} // namespace rack } // namespace rack


namespace patchUtils { namespace patchUtils {


+ 62
- 28
src/CardinalPlugin.cpp View File

@@ -34,24 +34,38 @@
# undef DEBUG # undef DEBUG
#endif #endif
#ifdef HAVE_LIBLO
# ifdef HEADLESS
# include <lo/lo.h>
# include "extra/Thread.hpp"
# endif
# include "CardinalCommon.hpp"
#if defined(HAVE_LIBLO) && defined(HEADLESS)
# include <lo/lo.h>
# include "extra/Thread.hpp"
#endif #endif
#include <list> #include <list>
#include "CardinalCommon.hpp"
#include "DistrhoPluginUtils.hpp" #include "DistrhoPluginUtils.hpp"
#include "PluginContext.hpp" #include "PluginContext.hpp"
#include "extra/Base64.hpp" #include "extra/Base64.hpp"
#ifndef DISTRHO_OS_WASM
#ifdef DISTRHO_OS_WASM
# include <emscripten/emscripten.h>
#else
# include "extra/SharedResourcePointer.hpp" # include "extra/SharedResourcePointer.hpp"
#endif #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 static const constexpr uint kCardinalStateBaseCount = 3; // patch, screenshot, comment
#ifndef HEADLESS #ifndef HEADLESS
@@ -63,14 +77,6 @@ static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount + 2; /
static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount; static const constexpr uint kCardinalStateCount = kCardinalStateBaseCount;
#endif #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 rack {
namespace engine { namespace engine {
void Engine_setAboutToClose(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 struct Initializer
#if defined(HAVE_LIBLO) && defined(HEADLESS) #if defined(HAVE_LIBLO) && defined(HEADLESS)
: public Thread : public Thread
@@ -107,6 +128,7 @@ struct Initializer
CardinalBasePlugin* oscPlugin = nullptr; CardinalBasePlugin* oscPlugin = nullptr;
#endif #endif
std::string templatePath; std::string templatePath;
std::string factoryTemplatePath;
Initializer(const CardinalBasePlugin* const plugin) Initializer(const CardinalBasePlugin* const plugin)
{ {
@@ -158,6 +180,7 @@ struct Initializer
asset::bundlePath = system::join(resourcePath, "PluginManifests"); asset::bundlePath = system::join(resourcePath, "PluginManifests");
asset::systemDir = resourcePath; asset::systemDir = resourcePath;
templatePath = system::join(asset::systemDir, CARDINAL_TEMPLATE_NAME); 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"))) if (system::exists(system::join(asset::systemDir, "res")))
{ {
templatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR CARDINAL_TEMPLATE_NAME; 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 // If source code dir does not exist use install target prefix as system dir
else else
@@ -187,17 +211,20 @@ struct Initializer
asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal"; asset::systemDir = CARDINAL_PLUGIN_PREFIX "/share/cardinal";
#endif #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; asset::userDir = asset::systemDir;
} }
#ifdef DISTRHO_OS_WASM
if ((patchStorageSlug = getPatchStorageSlug()) != nullptr)
templatePath = CARDINAL_IMPORTED_TEMPLATE_FILENAME;
#endif
// Log environment // Log environment
INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str()); INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str());
INFO("%s", system::getOperatingSystemInfo().c_str()); INFO("%s", system::getOperatingSystemInfo().c_str());
@@ -206,6 +233,7 @@ struct Initializer
INFO("System directory: %s", asset::systemDir.c_str()); INFO("System directory: %s", asset::systemDir.c_str());
INFO("User directory: %s", asset::userDir.c_str()); INFO("User directory: %s", asset::userDir.c_str());
INFO("Template patch: %s", templatePath.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 // Report to user if something is wrong with the installation
if (asset::systemDir.empty()) if (asset::systemDir.empty())
@@ -564,6 +592,7 @@ public:
context->patch = new rack::patch::Manager; context->patch = new rack::patch::Manager;
context->patch->autosavePath = fAutosavePath; context->patch->autosavePath = fAutosavePath;
context->patch->templatePath = fInitializer->templatePath; context->patch->templatePath = fInitializer->templatePath;
context->patch->factoryTemplatePath = fInitializer->factoryTemplatePath;
context->event = new rack::widget::EventState; context->event = new rack::widget::EventState;
context->scene = new rack::app::Scene; context->scene = new rack::app::Scene;
@@ -572,28 +601,33 @@ public:
if (! isDummyInstance()) if (! isDummyInstance())
context->window = new rack::window::Window; 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; fInitializer->oscPlugin = this;
#endif
#endif
} }
~CardinalPlugin() override ~CardinalPlugin() override
{ {
#if defined(HAVE_LIBLO) && defined(HEADLESS)
#if defined(HAVE_LIBLO) && defined(HEADLESS)
fInitializer->oscPlugin = nullptr; fInitializer->oscPlugin = nullptr;
#endif
#endif
{ {
const ScopedContext sc(this); const ScopedContext sc(this);
context->patch->clear(); context->patch->clear();
// do a little dance to prevent context scene deletion from saving to temp dir // do a little dance to prevent context scene deletion from saving to temp dir
#ifndef HEADLESS
#ifndef HEADLESS
const ScopedValueSetter<bool> svs(rack::settings::headless, true); const ScopedValueSetter<bool> svs(rack::settings::headless, true);
#endif
#endif
Engine_setAboutToClose(context->engine); Engine_setAboutToClose(context->engine);
delete context; delete context;
} }


+ 119
- 6
src/CardinalUI.cpp View File

@@ -31,11 +31,12 @@
#include <window/Window.hpp> #include <window/Window.hpp>


#ifdef DISTRHO_OS_WASM #ifdef DISTRHO_OS_WASM
#include <ui/Button.hpp>
#include <ui/Label.hpp>
#include <ui/MenuOverlay.hpp>
#include <ui/SequentialLayout.hpp>
#include "CardinalCommon.hpp"
# include <ui/Button.hpp>
# include <ui/Label.hpp>
# include <ui/MenuOverlay.hpp>
# include <ui/SequentialLayout.hpp>
# include "CardinalCommon.hpp"
# include <emscripten/emscripten.h>
#endif #endif


#ifdef NDEBUG #ifdef NDEBUG
@@ -189,6 +190,104 @@ struct WasmWelcomeDialog : rack::widget::OpaqueWidget
Widget::draw(args); 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<CardinalPluginContext*>(APP);
CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(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<CardinalPluginContext*>(APP);
CardinalBaseUI* const ui = static_cast<CardinalBaseUI*>(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 #endif


// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------
@@ -288,7 +387,21 @@ public:
} }


#ifdef DISTRHO_OS_WASM #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 #endif


context->window->step(); context->window->step();


+ 9
- 4
src/PluginContext.hpp View File

@@ -122,10 +122,6 @@ void handleHostParameterDrag(const CardinalPluginContext* pcontext, uint index,


// ----------------------------------------------------------------------------------------------------------- // -----------------------------------------------------------------------------------------------------------


struct CardinalAudioDevice;
struct CardinalMidiInputDevice;
struct CardinalMidiOutputDevice;

CardinalPluginContext* getRackContextFromPlugin(void* ptr); CardinalPluginContext* getRackContextFromPlugin(void* ptr);


class CardinalBasePlugin : public Plugin { class CardinalBasePlugin : public Plugin {
@@ -139,12 +135,18 @@ public:
}; };


#ifndef HEADLESS #ifndef HEADLESS
struct WasmPatchStorageLoadingDialog;

class CardinalBaseUI : public UI { class CardinalBaseUI : public UI {
public: public:
CardinalPluginContext* const context; CardinalPluginContext* const context;
bool saving; bool saving;
bool savingUncompressed; bool savingUncompressed;


#ifdef DISTRHO_OS_WASM
WasmPatchStorageLoadingDialog* psDialog;
#endif

// for 3rd party modules // for 3rd party modules
std::function<void(char* path)> filebrowseraction; std::function<void(char* path)> filebrowseraction;
FileBrowserHandle filebrowserhandle; FileBrowserHandle filebrowserhandle;
@@ -154,6 +156,9 @@ public:
context(getRackContextFromPlugin(getPluginInstancePointer())), context(getRackContextFromPlugin(getPluginInstancePointer())),
saving(false), saving(false),
savingUncompressed(false), savingUncompressed(false),
#ifdef DISTRHO_OS_WASM
psDialog(nullptr),
#endif
filebrowseraction(), filebrowseraction(),
filebrowserhandle(nullptr) filebrowserhandle(nullptr)
{ {


+ 43
- 0
src/emscripten/patchstorage.php View File

@@ -0,0 +1,43 @@
<?php
$slug = filter_input(INPUT_GET, 'slug', FILTER_SANITIZE_ENCODED);
if (!$slug) { http_response_code(404); die(); }

$api = 'https://patchstorage.com/api/alpha';

$search = file_get_contents($api.'/patches?platform=7834&slug='.$slug);
if (!$search) { http_response_code(404); die(); }

$searchJ = json_decode($search, true);
if (!$searchJ) { http_response_code(404); die(); }
if (!$searchJ[0]) { http_response_code(404); die(); }

$patchId = $searchJ[0]['id'];
if (!$patchId) { http_response_code(404); die(); }

$patchDetails = file_get_contents($api.'/patches/'.$patchId);
if (!$patchDetails) { http_response_code(404); die(); }

$patchDetailsJ = json_decode($patchDetails, true);
if (!$patchDetailsJ) { http_response_code(404); die(); }

$patchFiles = $patchDetailsJ['files'];
if (!$patchFiles) { http_response_code(404); die(); }

$patchFileDetails = $patchFiles[0];
if (!$patchFileDetails) { http_response_code(404); die(); }
if (!$patchFileDetails['filename']) { http_response_code(404); die(); }
if (!$patchFileDetails['url']) { http_response_code(404); die(); }

$contents = file_get_contents($patchFileDetails['url']);
if (!$contents) { http_response_code(404); die(); }

header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="'.$patchFileDetails['filename'].'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . strlen($contents));
flush();
die($contents);
?>

Loading…
Cancel
Save