|
- --- ../Rack/src/plugin.cpp 2022-11-23 23:11:38.000000000 +0000
- +++ plugin.cpp 2022-11-25 23:27:58.000000000 +0000
- @@ -1,342 +1,41 @@
- -#include <thread>
- -#include <map>
- -#include <stdexcept>
- -#include <tuple>
- -
- -#include <sys/types.h>
- -#include <sys/stat.h>
- -#include <unistd.h>
- -#include <sys/param.h> // for MAXPATHLEN
- -#include <fcntl.h>
- -#if defined ARCH_WIN
- - #include <windows.h>
- - #include <direct.h>
- -#else
- - #include <dlfcn.h> // for dlopen
- -#endif
- -#include <dirent.h>
- +/*
- + * DISTRHO Cardinal Plugin
- + * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License as
- + * published by the Free Software Foundation; either version 3 of
- + * the License, or any later version.
- + *
- + * This program is distributed in the hope that it will be useful,
- + * but WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- + * GNU General Public License for more details.
- + *
- + * For a full copy of the GNU General Public License see the LICENSE file.
- + */
- +
- +/**
- + * This file is an edited version of VCVRack's plugin.cpp
- + * Copyright (C) 2016-2021 VCV.
- + *
- + * This program is free software: you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License as
- + * published by the Free Software Foundation; either version 3 of
- + * the License, or (at your option) any later version.
- + */
-
- -#include <osdialog.h>
- -#include <jansson.h>
- +#include <algorithm>
- +#include <map>
-
- #include <plugin.hpp>
- -#include <system.hpp>
- -#include <asset.hpp>
- -#include <string.hpp>
- -#include <context.hpp>
- -#include <plugin/callbacks.hpp>
- -#include <settings.hpp>
-
-
- namespace rack {
- -
- -namespace core {
- -void init(rack::plugin::Plugin* plugin);
- -} // namespace core
- -
- namespace plugin {
-
-
- -////////////////////
- -// private API
- -////////////////////
- -
- -
- -static void* getSymbol(void* handle, const char* name) {
- - if (!handle)
- - return NULL;
- -
- -#if defined ARCH_WIN
- - return (void*) GetProcAddress((HMODULE) handle, name);
- -#else
- - return dlsym(handle, name);
- -#endif
- -}
- -
- -/** Returns library handle */
- -static void* loadLibrary(std::string libraryPath) {
- -#if defined ARCH_WIN
- - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
- - std::wstring libraryFilenameW = string::UTF8toUTF16(libraryPath);
- - HINSTANCE handle = LoadLibraryW(libraryFilenameW.c_str());
- - SetErrorMode(0);
- - if (!handle) {
- - int error = GetLastError();
- - throw Exception("Failed to load library %s: code %d", libraryPath.c_str(), error);
- - }
- -#else
- - // Since Rack 2, plugins on Linux/Mac link to the absolute path /tmp/Rack2/libRack.<ext>
- - // Create a symlink at /tmp/Rack2 to the system dir containting libRack.
- - std::string systemDir = system::getAbsolute(asset::systemDir);
- - std::string linkPath = "/tmp/Rack2";
- - if (!settings::devMode) {
- - // Clean up old symbolic link in case a different edition was run earlier
- - system::remove(linkPath);
- - system::createSymbolicLink(systemDir, linkPath);
- - }
- - // Load library with dlopen
- - void* handle = NULL;
- - #if defined ARCH_LIN
- - handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
- - #elif defined ARCH_MAC
- - handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
- - #endif
- - if (!settings::devMode) {
- - system::remove(linkPath);
- - }
- - if (!handle)
- - throw Exception("Failed to load library %s: %s", libraryPath.c_str(), dlerror());
- -#endif
- - return handle;
- -}
- -
- -typedef void (*InitCallback)(Plugin*);
- -
- -static InitCallback loadPluginCallback(Plugin* plugin) {
- - // Load plugin library
- - std::string libraryExt;
- -#if defined ARCH_LIN
- - libraryExt = "so";
- -#elif defined ARCH_WIN
- - libraryExt = "dll";
- -#elif ARCH_MAC
- - libraryExt = "dylib";
- -#endif
- - std::string libraryPath = system::join(plugin->path, "plugin." + libraryExt);
- -
- - // Check file existence
- - if (!system::isFile(libraryPath))
- - throw Exception("Plugin binary not found at %s", libraryPath.c_str());
- -
- - // Load dynamic/shared library
- - plugin->handle = loadLibrary(libraryPath);
- -
- - // Get plugin's init() function
- - InitCallback initCallback = (InitCallback) getSymbol(plugin->handle, "init");
- - if (!initCallback)
- - throw Exception("Failed to read init() symbol in %s", libraryPath.c_str());
- -
- - return initCallback;
- -}
- -
- -
- -/** If path is blank, loads Core */
- -static Plugin* loadPlugin(std::string path) {
- - if (path == "")
- - INFO("Loading Core plugin");
- - else
- - INFO("Loading plugin from %s", path.c_str());
- -
- - Plugin* plugin = new Plugin;
- - try {
- - // Set plugin path
- - plugin->path = (path == "") ? asset::systemDir : path;
- -
- - // Get modified timestamp
- - if (path != "") {
- - struct stat statbuf;
- - if (!stat(path.c_str(), &statbuf)) {
- -#if defined ARCH_MAC
- - plugin->modifiedTimestamp = (double) statbuf.st_mtimespec.tv_sec + statbuf.st_mtimespec.tv_nsec * 1e-9;
- -#elif defined ARCH_WIN
- - plugin->modifiedTimestamp = (double) statbuf.st_mtime;
- -#elif defined ARCH_LIN
- - plugin->modifiedTimestamp = (double) statbuf.st_mtim.tv_sec + statbuf.st_mtim.tv_nsec * 1e-9;
- -#endif
- - }
- - }
- -
- - // Load plugin.json
- - std::string manifestFilename = (path == "") ? asset::system("Core.json") : system::join(path, "plugin.json");
- - FILE* file = std::fopen(manifestFilename.c_str(), "r");
- - if (!file)
- - throw Exception("Manifest file %s does not exist", manifestFilename.c_str());
- - DEFER({std::fclose(file);});
- -
- - json_error_t error;
- - json_t* rootJ = json_loadf(file, 0, &error);
- - if (!rootJ)
- - throw Exception("JSON parsing error at %s %d:%d %s", manifestFilename.c_str(), error.line, error.column, error.text);
- - DEFER({json_decref(rootJ);});
- -
- - // Load manifest
- - plugin->fromJson(rootJ);
- -
- - // Reject plugin if slug already exists
- - Plugin* existingPlugin = getPlugin(plugin->slug);
- - if (existingPlugin)
- - throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str());
- -
- - // Call init callback
- - InitCallback initCallback;
- - if (path == "") {
- - initCallback = core::init;
- - }
- - else {
- - initCallback = loadPluginCallback(plugin);
- - }
- - initCallback(plugin);
- -
- - // Load modules manifest
- - json_t* modulesJ = json_object_get(rootJ, "modules");
- - plugin->modulesFromJson(modulesJ);
- -
- - // Call settingsFromJson() if exists
- - // Returns NULL for Core.
- - auto settingsFromJson = (decltype(&::settingsFromJson)) getSymbol(plugin->handle, "settingsFromJson");
- - if (settingsFromJson) {
- - json_t* settingsJ = json_object_get(settings::pluginSettingsJ, plugin->slug.c_str());
- - if (settingsJ)
- - settingsFromJson(settingsJ);
- - }
- - }
- - catch (Exception& e) {
- - WARN("Could not load plugin %s: %s", path.c_str(), e.what());
- - delete plugin;
- - return NULL;
- - }
- -
- - INFO("Loaded %s v%s", plugin->slug.c_str(), plugin->version.c_str());
- - plugins.push_back(plugin);
- - return plugin;
- -}
- -
- -
- -static void loadPlugins(std::string path) {
- - for (std::string pluginPath : system::getEntries(path)) {
- - if (!system::isDirectory(pluginPath))
- - continue;
- - if (!loadPlugin(pluginPath)) {
- - // Ignore bad plugins. They are reported in the log.
- - }
- - }
- -}
- -
- -
- -static void extractPackages(std::string path) {
- - std::string message;
- -
- - for (std::string packagePath : system::getEntries(path)) {
- - if (!system::isFile(packagePath))
- - continue;
- - if (system::getExtension(packagePath) != ".vcvplugin")
- - continue;
- -
- - // Extract package
- - INFO("Extracting package %s", packagePath.c_str());
- - try {
- - system::unarchiveToDirectory(packagePath, path);
- - }
- - catch (Exception& e) {
- - WARN("Plugin package %s failed to extract: %s", packagePath.c_str(), e.what());
- - message += string::f("Could not extract plugin package %s\n", packagePath.c_str());
- - continue;
- - }
- - // Remove package
- - system::remove(packagePath.c_str());
- - }
- - if (!message.empty()) {
- - osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
- - }
- -}
- -
- -////////////////////
- -// public API
- -////////////////////
- -
- -void init() {
- - // Don't re-initialize
- - assert(plugins.empty());
- -
- - // Load Core
- - loadPlugin("");
- -
- - pluginsPath = asset::user("plugins");
- -
- - // Get user plugins directory
- - system::createDirectory(pluginsPath);
- -
- - // Don't load plugins if safe mode is enabled
- - if (settings::safeMode)
- - return;
- -
- - // Extract packages and load plugins
- - extractPackages(pluginsPath);
- - loadPlugins(pluginsPath);
- -
- - // If Fundamental wasn't loaded, copy the bundled Fundamental package and load it
- - if (!settings::devMode && !getPlugin("Fundamental")) {
- - std::string fundamentalSrc = asset::system("Fundamental.vcvplugin");
- - std::string fundamentalDir = system::join(pluginsPath, "Fundamental");
- - if (system::isFile(fundamentalSrc)) {
- - INFO("Extracting bundled Fundamental package");
- - try {
- - system::unarchiveToDirectory(fundamentalSrc.c_str(), pluginsPath.c_str());
- - loadPlugin(fundamentalDir);
- - }
- - catch (Exception& e) {
- - WARN("Could not extract Fundamental package: %s", e.what());
- - }
- - }
- - }
- -}
- -
- -
- -static void destroyPlugin(Plugin* plugin) {
- - void* handle = plugin->handle;
- -
- - // Call destroy() if defined in the plugin library
- - typedef void (*DestroyCallback)();
- - DestroyCallback destroyCallback = NULL;
- - if (handle) {
- - destroyCallback = (DestroyCallback) getSymbol(handle, "destroy");
- - }
- - if (destroyCallback) {
- - try {
- - destroyCallback();
- - }
- - catch (Exception& e) {
- - WARN("Could not destroy plugin %s", plugin->slug.c_str());
- - }
- - }
- -
- - // We must delete the Plugin instance *before* freeing the library, because the vtables of Model subclasses are defined in the library, which are needed in the Plugin destructor.
- - delete plugin;
- -
- - // Free library handle
- - if (handle) {
- -#if defined ARCH_WIN
- - FreeLibrary((HINSTANCE) handle);
- -#else
- - dlclose(handle);
- -#endif
- - }
- -}
- -
- -
- -void destroy() {
- - while (!plugins.empty()) {
- - Plugin* plugin = plugins.back();
- - INFO("Destroying plugin %s", plugin->name.c_str());
- - destroyPlugin(plugin);
- - plugins.pop_back();
- - }
- - assert(plugins.empty());
- -}
- -
- -
- -void settingsMergeJson(json_t* rootJ) {
- - for (Plugin* plugin : plugins) {
- - auto settingsToJson = (decltype(&::settingsToJson)) getSymbol(plugin->handle, "settingsToJson");
- - if (settingsToJson) {
- - json_t* settingsJ = settingsToJson();
- - json_object_set_new(rootJ, plugin->slug.c_str(), settingsJ);
- - }
- - else {
- - json_object_del(rootJ, plugin->slug.c_str());
- - }
- - }
- -}
- +void settingsMergeJson(json_t*) {}
-
-
- /** Given slug => fallback slug.
- @@ -348,6 +47,7 @@
- {"VultModules", "VultModulesFree"},
- {"AudibleInstrumentsPreview", "AudibleInstruments"},
- {"SequelSequencers", "DanielDavies"},
- + {"DelexanderVol1", "DelexandraVol1"},
- // {"", ""},
- };
-
- @@ -389,8 +89,19 @@
- */
- using PluginModuleSlug = std::tuple<std::string, std::string>;
- static const std::map<PluginModuleSlug, PluginModuleSlug> moduleSlugFallbacks = {
- + {{"Core", "AudioInterface2"}, {"Cardinal", "HostAudio2"}},
- + {{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}},
- + {{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}},
- + {{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}},
- + {{"Core", "MIDICCToCVInterface"}, {"Cardinal", "HostMIDICC"}},
- + {{"Core", "MIDITriggerToCVInterface"}, {"Cardinal", "HostMIDIGate"}},
- + {{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}},
- + {{"Core", "CV-CC"}, {"Cardinal", "HostMIDICC"}},
- + {{"Core", "CV-Gate"}, {"Cardinal", "HostMIDIGate"}},
- + {{"Core", "MIDI-Map"}, {"Cardinal", "HostMIDIMap"}},
- + {{"Core", "Notes"}, {"Cardinal", "TextEditor"}},
- + {{"Core", "Blank"}, {"Cardinal", "Blank"}},
- {{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}},
- - {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}},
- // {{"", ""}, {"", ""}},
- };
-
- @@ -478,7 +189,6 @@
- }
-
-
- -std::string pluginsPath;
- std::vector<Plugin*> plugins;
-
-
|