You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

369 lines
11KB

  1. --- ../Rack/src/plugin.cpp 2022-02-05 22:30:09.265393248 +0000
  2. +++ plugin.cpp 2022-01-30 00:24:49.375329910 +0000
  3. @@ -1,308 +1,40 @@
  4. -#include <thread>
  5. -#include <map>
  6. -#include <stdexcept>
  7. -#include <tuple>
  8. -
  9. -#include <sys/types.h>
  10. -#include <sys/stat.h>
  11. -#include <unistd.h>
  12. -#include <sys/param.h> // for MAXPATHLEN
  13. -#include <fcntl.h>
  14. -#if defined ARCH_WIN
  15. - #include <windows.h>
  16. - #include <direct.h>
  17. -#else
  18. - #include <dlfcn.h> // for dlopen
  19. -#endif
  20. -#include <dirent.h>
  21. +/*
  22. + * DISTRHO Cardinal Plugin
  23. + * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
  24. + *
  25. + * This program is free software; you can redistribute it and/or
  26. + * modify it under the terms of the GNU General Public License as
  27. + * published by the Free Software Foundation; either version 3 of
  28. + * the License, or any later version.
  29. + *
  30. + * This program is distributed in the hope that it will be useful,
  31. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  32. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  33. + * GNU General Public License for more details.
  34. + *
  35. + * For a full copy of the GNU General Public License see the LICENSE file.
  36. + */
  37. +
  38. +/**
  39. + * This file is an edited version of VCVRack's plugin.cpp
  40. + * Copyright (C) 2016-2021 VCV.
  41. + *
  42. + * This program is free software: you can redistribute it and/or
  43. + * modify it under the terms of the GNU General Public License as
  44. + * published by the Free Software Foundation; either version 3 of
  45. + * the License, or (at your option) any later version.
  46. + */
  47. -#include <osdialog.h>
  48. -#include <jansson.h>
  49. +#include <algorithm>
  50. +#include <map>
  51. #include <plugin.hpp>
  52. -#include <system.hpp>
  53. -#include <asset.hpp>
  54. -#include <string.hpp>
  55. -#include <context.hpp>
  56. -#include <plugin/callbacks.hpp>
  57. -#include <settings.hpp>
  58. namespace rack {
  59. -
  60. -namespace core {
  61. -void init(rack::plugin::Plugin* plugin);
  62. -} // namespace core
  63. -
  64. namespace plugin {
  65. -////////////////////
  66. -// private API
  67. -////////////////////
  68. -
  69. -/** Returns library handle */
  70. -static void* loadLibrary(std::string libraryPath) {
  71. -#if defined ARCH_WIN
  72. - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  73. - std::wstring libraryFilenameW = string::UTF8toUTF16(libraryPath);
  74. - HINSTANCE handle = LoadLibraryW(libraryFilenameW.c_str());
  75. - SetErrorMode(0);
  76. - if (!handle) {
  77. - int error = GetLastError();
  78. - throw Exception("Failed to load library %s: code %d", libraryPath.c_str(), error);
  79. - }
  80. -#else
  81. - // Since Rack 2, plugins on Linux/Mac link to the absolute path /tmp/Rack2/libRack.<ext>
  82. - // Create a symlink at /tmp/Rack2 to the system dir containting libRack.
  83. - std::string systemDir = system::getAbsolute(asset::systemDir);
  84. - std::string linkPath = "/tmp/Rack2";
  85. - if (!settings::devMode) {
  86. - // Clean up old symbolic link in case a different edition was run earlier
  87. - system::remove(linkPath);
  88. - system::createSymbolicLink(systemDir, linkPath);
  89. - }
  90. - // Load library with dlopen
  91. - void* handle = NULL;
  92. - #if defined ARCH_LIN
  93. - handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
  94. - #elif defined ARCH_MAC
  95. - handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
  96. - #endif
  97. - if (!settings::devMode) {
  98. - system::remove(linkPath);
  99. - }
  100. - if (!handle)
  101. - throw Exception("Failed to load library %s: %s", libraryPath.c_str(), dlerror());
  102. -#endif
  103. - return handle;
  104. -}
  105. -
  106. -typedef void (*InitCallback)(Plugin*);
  107. -
  108. -static InitCallback loadPluginCallback(Plugin* plugin) {
  109. - // Load plugin library
  110. - std::string libraryExt;
  111. -#if defined ARCH_LIN
  112. - libraryExt = "so";
  113. -#elif defined ARCH_WIN
  114. - libraryExt = "dll";
  115. -#elif ARCH_MAC
  116. - libraryExt = "dylib";
  117. -#endif
  118. - std::string libraryPath = system::join(plugin->path, "plugin." + libraryExt);
  119. -
  120. - // Check file existence
  121. - if (!system::isFile(libraryPath))
  122. - throw Exception("Plugin binary not found at %s", libraryPath.c_str());
  123. -
  124. - // Load dynamic/shared library
  125. - plugin->handle = loadLibrary(libraryPath);
  126. -
  127. - // Get plugin's init() function
  128. - InitCallback initCallback;
  129. -#if defined ARCH_WIN
  130. - initCallback = (InitCallback) GetProcAddress((HMODULE) plugin->handle, "init");
  131. -#else
  132. - initCallback = (InitCallback) dlsym(plugin->handle, "init");
  133. -#endif
  134. - if (!initCallback)
  135. - throw Exception("Failed to read init() symbol in %s", libraryPath.c_str());
  136. -
  137. - return initCallback;
  138. -}
  139. -
  140. -
  141. -/** If path is blank, loads Core */
  142. -static Plugin* loadPlugin(std::string path) {
  143. - if (path == "")
  144. - INFO("Loading Core plugin");
  145. - else
  146. - INFO("Loading plugin from %s", path.c_str());
  147. -
  148. - Plugin* plugin = new Plugin;
  149. - try {
  150. - // Set plugin path
  151. - plugin->path = (path == "") ? asset::systemDir : path;
  152. -
  153. - // Get modified timestamp
  154. - if (path != "") {
  155. - struct stat statbuf;
  156. - if (!stat(path.c_str(), &statbuf)) {
  157. -#if defined ARCH_MAC
  158. - plugin->modifiedTimestamp = (double) statbuf.st_mtimespec.tv_sec + statbuf.st_mtimespec.tv_nsec * 1e-9;
  159. -#elif defined ARCH_WIN
  160. - plugin->modifiedTimestamp = (double) statbuf.st_mtime;
  161. -#elif defined ARCH_LIN
  162. - plugin->modifiedTimestamp = (double) statbuf.st_mtim.tv_sec + statbuf.st_mtim.tv_nsec * 1e-9;
  163. -#endif
  164. - }
  165. - }
  166. -
  167. - // Load plugin.json
  168. - std::string manifestFilename = (path == "") ? asset::system("Core.json") : system::join(path, "plugin.json");
  169. - FILE* file = std::fopen(manifestFilename.c_str(), "r");
  170. - if (!file)
  171. - throw Exception("Manifest file %s does not exist", manifestFilename.c_str());
  172. - DEFER({std::fclose(file);});
  173. -
  174. - json_error_t error;
  175. - json_t* rootJ = json_loadf(file, 0, &error);
  176. - if (!rootJ)
  177. - throw Exception("JSON parsing error at %s %d:%d %s", manifestFilename.c_str(), error.line, error.column, error.text);
  178. - DEFER({json_decref(rootJ);});
  179. -
  180. - // Call init callback
  181. - InitCallback initCallback;
  182. - if (path == "") {
  183. - initCallback = core::init;
  184. - }
  185. - else {
  186. - initCallback = loadPluginCallback(plugin);
  187. - }
  188. - initCallback(plugin);
  189. -
  190. - // Load manifest
  191. - plugin->fromJson(rootJ);
  192. -
  193. - // Reject plugin if slug already exists
  194. - Plugin* existingPlugin = getPlugin(plugin->slug);
  195. - if (existingPlugin)
  196. - throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str());
  197. - }
  198. - catch (Exception& e) {
  199. - WARN("Could not load plugin %s: %s", path.c_str(), e.what());
  200. - delete plugin;
  201. - return NULL;
  202. - }
  203. -
  204. - INFO("Loaded %s v%s", plugin->slug.c_str(), plugin->version.c_str());
  205. - plugins.push_back(plugin);
  206. - return plugin;
  207. -}
  208. -
  209. -
  210. -static void loadPlugins(std::string path) {
  211. - for (std::string pluginPath : system::getEntries(path)) {
  212. - if (!system::isDirectory(pluginPath))
  213. - continue;
  214. - if (!loadPlugin(pluginPath)) {
  215. - // Ignore bad plugins. They are reported in the log.
  216. - }
  217. - }
  218. -}
  219. -
  220. -
  221. -static void extractPackages(std::string path) {
  222. - std::string message;
  223. -
  224. - for (std::string packagePath : system::getEntries(path)) {
  225. - if (!system::isFile(packagePath))
  226. - continue;
  227. - if (system::getExtension(packagePath) != ".vcvplugin")
  228. - continue;
  229. -
  230. - // Extract package
  231. - INFO("Extracting package %s", packagePath.c_str());
  232. - try {
  233. - system::unarchiveToDirectory(packagePath, path);
  234. - }
  235. - catch (Exception& e) {
  236. - WARN("Plugin package %s failed to extract: %s", packagePath.c_str(), e.what());
  237. - message += string::f("Could not extract plugin package %s\n", packagePath.c_str());
  238. - continue;
  239. - }
  240. - // Remove package
  241. - system::remove(packagePath.c_str());
  242. - }
  243. - if (!message.empty()) {
  244. - osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  245. - }
  246. -}
  247. -
  248. -////////////////////
  249. -// public API
  250. -////////////////////
  251. -
  252. -void init() {
  253. - // Don't re-initialize
  254. - assert(plugins.empty());
  255. -
  256. - // Load Core
  257. - loadPlugin("");
  258. -
  259. - pluginsPath = asset::user("plugins");
  260. -
  261. - // Get user plugins directory
  262. - system::createDirectory(pluginsPath);
  263. -
  264. - // Extract packages and load plugins
  265. - extractPackages(pluginsPath);
  266. - loadPlugins(pluginsPath);
  267. -
  268. - // If Fundamental wasn't loaded, copy the bundled Fundamental package and load it
  269. - if (!settings::devMode && !getPlugin("Fundamental")) {
  270. - std::string fundamentalSrc = asset::system("Fundamental.vcvplugin");
  271. - std::string fundamentalDir = system::join(pluginsPath, "Fundamental");
  272. - if (system::isFile(fundamentalSrc)) {
  273. - INFO("Extracting bundled Fundamental package");
  274. - try {
  275. - system::unarchiveToDirectory(fundamentalSrc.c_str(), pluginsPath.c_str());
  276. - loadPlugin(fundamentalDir);
  277. - }
  278. - catch (Exception& e) {
  279. - WARN("Could not extract Fundamental package: %s", e.what());
  280. - }
  281. - }
  282. - }
  283. -}
  284. -
  285. -
  286. -static void destroyPlugin(Plugin* plugin) {
  287. - void* handle = plugin->handle;
  288. -
  289. - // Call destroy() if defined in the plugin library
  290. - typedef void (*DestroyCallback)();
  291. - DestroyCallback destroyCallback = NULL;
  292. - if (handle) {
  293. -#if defined ARCH_WIN
  294. - destroyCallback = (DestroyCallback) GetProcAddress((HMODULE) handle, "destroy");
  295. -#else
  296. - destroyCallback = (DestroyCallback) dlsym(handle, "destroy");
  297. -#endif
  298. - }
  299. - if (destroyCallback) {
  300. - try {
  301. - destroyCallback();
  302. - }
  303. - catch (Exception& e) {
  304. - WARN("Could not destroy plugin %s", plugin->slug.c_str());
  305. - }
  306. - }
  307. -
  308. - // 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.
  309. - delete plugin;
  310. -
  311. - // Free library handle
  312. - if (handle) {
  313. -#if defined ARCH_WIN
  314. - FreeLibrary((HINSTANCE) handle);
  315. -#else
  316. - dlclose(handle);
  317. -#endif
  318. - }
  319. -}
  320. -
  321. -
  322. -void destroy() {
  323. - for (Plugin* plugin : plugins) {
  324. - INFO("Destroying plugin %s", plugin->name.c_str());
  325. - destroyPlugin(plugin);
  326. - }
  327. - plugins.clear();
  328. -}
  329. -
  330. -
  331. /** Given slug => fallback slug.
  332. Correctly handles bidirectional fallbacks.
  333. To request fallback slugs to be added to this list, open a GitHub issue.
  334. @@ -352,8 +84,19 @@
  335. */
  336. using PluginModuleSlug = std::tuple<std::string, std::string>;
  337. static const std::map<PluginModuleSlug, PluginModuleSlug> moduleSlugFallbacks = {
  338. + {{"Core", "AudioInterface2"}, {"Cardinal", "HostAudio2"}},
  339. + {{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}},
  340. + {{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}},
  341. + {{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}},
  342. + {{"Core", "MIDICCToCVInterface"}, {"Cardinal", "HostMIDICC"}},
  343. + {{"Core", "MIDITriggerToCVInterface"}, {"Cardinal", "HostMIDIGate"}},
  344. + {{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}},
  345. + {{"Core", "CV-CC"}, {"Cardinal", "HostMIDICC"}},
  346. + {{"Core", "CV-Gate"}, {"Cardinal", "HostMIDIGate"}},
  347. + {{"Core", "MIDI-Map"}, {"Cardinal", "HostMIDIMap"}},
  348. + {{"Core", "Notes"}, {"Cardinal", "TextEditor"}},
  349. + {{"Core", "Blank"}, {"Cardinal", "Blank"}},
  350. {{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}},
  351. - {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}},
  352. // {{"", ""}, {"", ""}},
  353. };
  354. @@ -441,7 +184,6 @@
  355. }
  356. -std::string pluginsPath;
  357. std::vector<Plugin*> plugins;