From c4609cba064b9d73aea542431bb4890c5f178c73 Mon Sep 17 00:00:00 2001 From: falkTX Date: Sun, 23 Jan 2022 22:57:11 +0000 Subject: [PATCH] Stop building Rack core audio and midi, setup Cardinal replacements Signed-off-by: falkTX --- plugins/Core.json | 54 ----- plugins/plugins.cpp | 10 - src/Makefile | 5 + src/override/.generate-diffs.sh | 1 + src/override/diffs/plugin.cpp.diff | 359 +++++++++++++++++++++++++++++ src/override/plugin.cpp | 185 +++++++++++++++ src/template.vcv | 7 - 7 files changed, 550 insertions(+), 71 deletions(-) create mode 100644 src/override/diffs/plugin.cpp.diff create mode 100644 src/override/plugin.cpp diff --git a/plugins/Core.json b/plugins/Core.json index c5d0eec..e3a4c94 100644 --- a/plugins/Core.json +++ b/plugins/Core.json @@ -12,48 +12,6 @@ "changelogUrl": "https://github.com/VCVRack/Rack/blob/v2/CHANGELOG.md", "description": "Necessary modules built into Cardinal", "modules": [ - { - "slug": "AudioInterface2", - "name": "Audio 2", - "description": "Sends audio and CV to/from an audio device", - "manualUrl": "https://vcvrack.com/manual/Core#Audio", - "tags": [ - "External" - ], - "hidden": true - }, - { - "slug": "AudioInterface", - "name": "Audio 8", - "description": "Sends audio and CV to/from an audio device", - "manualUrl": "https://vcvrack.com/manual/Core#Audio", - "tags": [ - "External" - ], - "hidden": true - }, - { - "slug": "AudioInterface16", - "name": "Audio 16", - "description": "Sends audio and CV to/from an audio device", - "manualUrl": "https://vcvrack.com/manual/Core#Audio", - "tags": [ - "External" - ], - "hidden": true - }, - { - "slug": "MIDIToCVInterface", - "name": "MIDI to CV", - "description": "Converts MIDI from an external device to CV and gates", - "manualUrl": "https://vcvrack.com/manual/Core#MIDI-CV", - "tags": [ - "External", - "MIDI", - "Polyphonic" - ], - "hidden": true - }, { "slug": "MIDICCToCVInterface", "name": "MIDI CC to CV", @@ -84,18 +42,6 @@ "MIDI" ] }, - { - "slug": "CV-MIDI", - "name": "CV to MIDI", - "description": "Converts CV to MIDI and sends to an external device", - "manualUrl": "https://vcvrack.com/manual/Core#CV-MIDI", - "tags": [ - "External", - "MIDI", - "Polyphonic" - ], - "hidden": true - }, { "slug": "CV-CC", "name": "CV to MIDI CC", diff --git a/plugins/plugins.cpp b/plugins/plugins.cpp index 0b96306..e09b36a 100644 --- a/plugins/plugins.cpp +++ b/plugins/plugins.cpp @@ -567,14 +567,9 @@ std::string pluginPath(const std::string& dirname); // core plugins namespace core { -extern Model* modelAudio2; -extern Model* modelAudio8; -extern Model* modelAudio16; -extern Model* modelMIDI_CV; extern Model* modelMIDICC_CV; extern Model* modelMIDI_Gate; extern Model* modelMIDIMap; -extern Model* modelCV_MIDI; extern Model* modelCV_MIDICC; extern Model* modelGate_MIDI; extern Model* modelBlank; @@ -670,14 +665,9 @@ static void initStatic__Core() const StaticPluginLoader spl(p, "Core"); if (spl.ok()) { - p->addModel(rack::core::modelAudio2); - p->addModel(rack::core::modelAudio8); - p->addModel(rack::core::modelAudio16); - p->addModel(rack::core::modelMIDI_CV); p->addModel(rack::core::modelMIDICC_CV); p->addModel(rack::core::modelMIDI_Gate); p->addModel(rack::core::modelMIDIMap); - p->addModel(rack::core::modelCV_MIDI); p->addModel(rack::core::modelCV_MIDICC); p->addModel(rack::core::modelGate_MIDI); p->addModel(rack::core::modelBlank); diff --git a/src/Makefile b/src/Makefile index 5a058aa..5934c60 100644 --- a/src/Makefile +++ b/src/Makefile @@ -102,6 +102,7 @@ RACK_FILES += custom/network.cpp RACK_FILES += custom/osdialog.cpp RACK_FILES += override/blendish.c RACK_FILES += override/context.cpp +RACK_FILES += override/plugin.cpp RACK_FILES += override/Engine.cpp RACK_FILES += override/MenuBar.cpp RACK_FILES += override/Model.cpp @@ -120,11 +121,15 @@ IGNORED_FILES += Rack/src/gamepad.cpp IGNORED_FILES += Rack/src/keyboard.cpp IGNORED_FILES += Rack/src/library.cpp IGNORED_FILES += Rack/src/network.cpp +IGNORED_FILES += Rack/src/plugin.cpp IGNORED_FILES += Rack/src/rtaudio.cpp IGNORED_FILES += Rack/src/rtmidi.cpp IGNORED_FILES += Rack/src/app/MenuBar.cpp IGNORED_FILES += Rack/src/app/Scene.cpp IGNORED_FILES += Rack/src/app/TipWindow.cpp +IGNORED_FILES += Rack/src/core/Audio.cpp +IGNORED_FILES += Rack/src/core/CV_MIDI.cpp +IGNORED_FILES += Rack/src/core/MIDI_CV.cpp IGNORED_FILES += Rack/src/engine/Engine.cpp IGNORED_FILES += Rack/src/plugin/Model.cpp IGNORED_FILES += Rack/src/window/Window.cpp diff --git a/src/override/.generate-diffs.sh b/src/override/.generate-diffs.sh index e86b20d..2e97058 100755 --- a/src/override/.generate-diffs.sh +++ b/src/override/.generate-diffs.sh @@ -5,6 +5,7 @@ set -e 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 -U3 ../Rack/src/context.cpp context.cpp > diffs/context.cpp.diff +diff -U3 ../Rack/src/plugin.cpp plugin.cpp > diffs/plugin.cpp.diff diff -U3 ../Rack/src/app/MenuBar.cpp MenuBar.cpp > diffs/MenuBar.cpp.diff diff -U3 ../Rack/src/app/Scene.cpp Scene.cpp > diffs/Scene.cpp.diff diff -U3 ../Rack/src/engine/Engine.cpp Engine.cpp > diffs/Engine.cpp.diff diff --git a/src/override/diffs/plugin.cpp.diff b/src/override/diffs/plugin.cpp.diff new file mode 100644 index 0000000..7b673af --- /dev/null +++ b/src/override/diffs/plugin.cpp.diff @@ -0,0 +1,359 @@ +--- ../Rack/src/plugin.cpp 2022-01-15 14:44:46.395281005 +0000 ++++ plugin.cpp 2022-01-23 22:59:41.770256440 +0000 +@@ -1,308 +1,40 @@ +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +-#include // for MAXPATHLEN +-#include +-#if defined ARCH_WIN +- #include +- #include +-#else +- #include // for dlopen +-#endif +-#include ++/* ++ * DISTRHO Cardinal Plugin ++ * Copyright (C) 2021-2022 Filipe Coelho ++ * ++ * 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 +-#include ++#include ++#include + + #include +-#include +-#include +-#include +-#include +-#include +-#include + + + namespace rack { +- +-namespace core { +-void init(rack::plugin::Plugin* plugin); +-} // namespace core +- + namespace plugin { + + +-//////////////////// +-// private API +-//////////////////// +- +-/** 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. +- // 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; +-#if defined ARCH_WIN +- initCallback = (InitCallback) GetProcAddress((HMODULE) plugin->handle, "init"); +-#else +- initCallback = (InitCallback) dlsym(plugin->handle, "init"); +-#endif +- 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);}); +- +- // Call init callback +- InitCallback initCallback; +- if (path == "") { +- initCallback = core::init; +- } +- else { +- initCallback = loadPluginCallback(plugin); +- } +- initCallback(plugin); +- +- // 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()); +- } +- 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); +- +- // 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) { +-#if defined ARCH_WIN +- destroyCallback = (DestroyCallback) GetProcAddress((HMODULE) handle, "destroy"); +-#else +- destroyCallback = (DestroyCallback) dlsym(handle, "destroy"); +-#endif +- } +- 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() { +- for (Plugin* plugin : plugins) { +- INFO("Destroying plugin %s", plugin->name.c_str()); +- destroyPlugin(plugin); +- } +- plugins.clear(); +-} +- +- + /** Given slug => fallback slug. + Correctly handles bidirectional fallbacks. + To request fallback slugs to be added to this list, open a GitHub issue. +@@ -352,6 +84,11 @@ + */ + using PluginModuleSlug = std::tuple; + static const std::map moduleSlugFallbacks = { ++ {{"Core", "AudioInterface2"}, {"Cardinal", "HostAudio2"}}, ++ {{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}}, ++ {{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}}, ++ {{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}}, ++ {{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}}, + {{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}}, + {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}}, + // {{"", ""}, {"", ""}}, +@@ -441,7 +178,6 @@ + } + + +-std::string pluginsPath; + std::vector plugins; + + diff --git a/src/override/plugin.cpp b/src/override/plugin.cpp new file mode 100644 index 0000000..1173b91 --- /dev/null +++ b/src/override/plugin.cpp @@ -0,0 +1,185 @@ +/* + * DISTRHO Cardinal Plugin + * Copyright (C) 2021-2022 Filipe Coelho + * + * 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 +#include + +#include + + +namespace rack { +namespace plugin { + + +/** Given slug => fallback slug. +Correctly handles bidirectional fallbacks. +To request fallback slugs to be added to this list, open a GitHub issue. +*/ +static const std::map pluginSlugFallbacks = { + {"VultModulesFree", "VultModules"}, + {"VultModules", "VultModulesFree"}, + {"AudibleInstrumentsPreview", "AudibleInstruments"}, + // {"", ""}, +}; + + +Plugin* getPlugin(const std::string& pluginSlug) { + if (pluginSlug.empty()) + return NULL; + + auto it = std::find_if(plugins.begin(), plugins.end(), [=](Plugin* p) { + return p->slug == pluginSlug; + }); + if (it != plugins.end()) + return *it; + return NULL; +} + + +Plugin* getPluginFallback(const std::string& pluginSlug) { + if (pluginSlug.empty()) + return NULL; + + // Attempt example plugin + Plugin* p = getPlugin(pluginSlug); + if (p) + return p; + + // Attempt fallback plugin slug + auto it = pluginSlugFallbacks.find(pluginSlug); + if (it != pluginSlugFallbacks.end()) + return getPlugin(it->second); + + return NULL; +} + + +/** Given slug => fallback slug. +Correctly handles bidirectional fallbacks. +To request fallback slugs to be added to this list, open a GitHub issue. +*/ +using PluginModuleSlug = std::tuple; +static const std::map moduleSlugFallbacks = { + {{"Core", "AudioInterface2"}, {"Cardinal", "HostAudio2"}}, + {{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}}, + {{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}}, + {{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}}, + {{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}}, + {{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}}, + {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}}, + // {{"", ""}, {"", ""}}, +}; + + +Model* getModel(const std::string& pluginSlug, const std::string& modelSlug) { + if (pluginSlug.empty() || modelSlug.empty()) + return NULL; + + Plugin* p = getPlugin(pluginSlug); + if (!p) + return NULL; + + return p->getModel(modelSlug); +} + + +Model* getModelFallback(const std::string& pluginSlug, const std::string& modelSlug) { + if (pluginSlug.empty() || modelSlug.empty()) + return NULL; + + // Attempt exact plugin and model + Model* m = getModel(pluginSlug, modelSlug); + if (m) + return m; + + // Attempt fallback module + auto it = moduleSlugFallbacks.find(std::make_tuple(pluginSlug, modelSlug)); + if (it != moduleSlugFallbacks.end()) { + Model* m = getModel(std::get<0>(it->second), std::get<1>(it->second)); + if (m) + return m; + } + + // Attempt fallback plugin + auto it2 = pluginSlugFallbacks.find(pluginSlug); + if (it2 != pluginSlugFallbacks.end()) { + Model* m = getModel(it2->second, modelSlug); + if (m) + return m; + } + + return NULL; +} + + +Model* modelFromJson(json_t* moduleJ) { + // Get slugs + json_t* pluginSlugJ = json_object_get(moduleJ, "plugin"); + if (!pluginSlugJ) + throw Exception("\"plugin\" property not found in module JSON"); + std::string pluginSlug = json_string_value(pluginSlugJ); + pluginSlug = normalizeSlug(pluginSlug); + + json_t* modelSlugJ = json_object_get(moduleJ, "model"); + if (!modelSlugJ) + throw Exception("\"model\" property not found in module JSON"); + std::string modelSlug = json_string_value(modelSlugJ); + modelSlug = normalizeSlug(modelSlug); + + // Get Model + Model* model = getModelFallback(pluginSlug, modelSlug); + if (!model) + throw Exception("Could not find module %s/%s", pluginSlug.c_str(), modelSlug.c_str()); + return model; +} + + +bool isSlugValid(const std::string& slug) { + for (char c : slug) { + if (!(std::isalnum(c) || c == '-' || c == '_')) + return false; + } + return true; +} + + +std::string normalizeSlug(const std::string& slug) { + std::string s; + for (char c : slug) { + if (!(std::isalnum(c) || c == '-' || c == '_')) + continue; + s += c; + } + return s; +} + + +std::vector plugins; + + +} // namespace plugin +} // namespace rack diff --git a/src/template.vcv b/src/template.vcv index 1005f01..589cded 100644 --- a/src/template.vcv +++ b/src/template.vcv @@ -30,13 +30,6 @@ "params": [], "leftModuleId": 1, "rightModuleId": 3, - "data": { - "channels": 1, - "polyMode": 0, - "clockDivision": 24, - "lastPitch": 8192, - "lastMod": 0 - }, "pos": [ 5, 0