--- ../Rack/src/plugin.cpp	2023-12-17 12:57:01.138429358 +0100
+++ plugin.cpp	2023-05-20 18:43:27.496323540 +0200
@@ -1,363 +1,46 @@
-#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-2023 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-2023 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 libraryFilename = "plugin." + libraryExt;
-	std::string libraryPath = system::join(plugin->path, libraryFilename);
-
-	// 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 %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("");
-
-	// Get user plugins directory
-	if (settings::devMode) {
-		pluginsPath = asset::user("plugins");
-	}
-	else {
-		pluginsPath = asset::user("plugins-" + APP_OS + "-" + APP_CPU);
-	}
-
-	// In Rack <2.4.0, plugins dir was "plugins" regardless of arch.
-	// Rename old dir if running x64.
-#if defined ARCH_X64
-	std::string oldPluginsPath = asset::user("plugins");
-	if (system::isDirectory(oldPluginsPath)) {
-		system::rename(oldPluginsPath, pluginsPath);
-	}
-#endif
-
-	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.
 Supports bidirectional fallbacks.
-To request fallback slugs to be added to this list, contact VCV support.
+To request fallback slugs to be added to this list, open a GitHub issue.
 */
 static const std::map<std::string, std::string> pluginSlugFallbacks = {
 	{"VultModulesFree", "VultModules"},
@@ -365,7 +48,6 @@
 	{"AudibleInstrumentsPreview", "AudibleInstruments"},
 	{"SequelSequencers", "DanielDavies"},
 	{"DelexanderVol1", "DelexandraVol1"},
-	{"VCV-Pro", "Fundamental"},
 	// {"", ""},
 };
 
@@ -407,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"}},
 	// {{"", ""}, {"", ""}},
 };
 
@@ -496,7 +189,6 @@
 }
 
 
-std::string pluginsPath;
 std::vector<Plugin*> plugins;
 
 
