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.

412 lines
12KB

  1. --- ../Rack/src/plugin.cpp 2022-11-23 23:11:38.000000000 +0000
  2. +++ plugin.cpp 2022-11-25 23:27:58.000000000 +0000
  3. @@ -1,342 +1,41 @@
  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. -
  70. -static void* getSymbol(void* handle, const char* name) {
  71. - if (!handle)
  72. - return NULL;
  73. -
  74. -#if defined ARCH_WIN
  75. - return (void*) GetProcAddress((HMODULE) handle, name);
  76. -#else
  77. - return dlsym(handle, name);
  78. -#endif
  79. -}
  80. -
  81. -/** Returns library handle */
  82. -static void* loadLibrary(std::string libraryPath) {
  83. -#if defined ARCH_WIN
  84. - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
  85. - std::wstring libraryFilenameW = string::UTF8toUTF16(libraryPath);
  86. - HINSTANCE handle = LoadLibraryW(libraryFilenameW.c_str());
  87. - SetErrorMode(0);
  88. - if (!handle) {
  89. - int error = GetLastError();
  90. - throw Exception("Failed to load library %s: code %d", libraryPath.c_str(), error);
  91. - }
  92. -#else
  93. - // Since Rack 2, plugins on Linux/Mac link to the absolute path /tmp/Rack2/libRack.<ext>
  94. - // Create a symlink at /tmp/Rack2 to the system dir containting libRack.
  95. - std::string systemDir = system::getAbsolute(asset::systemDir);
  96. - std::string linkPath = "/tmp/Rack2";
  97. - if (!settings::devMode) {
  98. - // Clean up old symbolic link in case a different edition was run earlier
  99. - system::remove(linkPath);
  100. - system::createSymbolicLink(systemDir, linkPath);
  101. - }
  102. - // Load library with dlopen
  103. - void* handle = NULL;
  104. - #if defined ARCH_LIN
  105. - handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
  106. - #elif defined ARCH_MAC
  107. - handle = dlopen(libraryPath.c_str(), RTLD_NOW | RTLD_LOCAL);
  108. - #endif
  109. - if (!settings::devMode) {
  110. - system::remove(linkPath);
  111. - }
  112. - if (!handle)
  113. - throw Exception("Failed to load library %s: %s", libraryPath.c_str(), dlerror());
  114. -#endif
  115. - return handle;
  116. -}
  117. -
  118. -typedef void (*InitCallback)(Plugin*);
  119. -
  120. -static InitCallback loadPluginCallback(Plugin* plugin) {
  121. - // Load plugin library
  122. - std::string libraryExt;
  123. -#if defined ARCH_LIN
  124. - libraryExt = "so";
  125. -#elif defined ARCH_WIN
  126. - libraryExt = "dll";
  127. -#elif ARCH_MAC
  128. - libraryExt = "dylib";
  129. -#endif
  130. - std::string libraryPath = system::join(plugin->path, "plugin." + libraryExt);
  131. -
  132. - // Check file existence
  133. - if (!system::isFile(libraryPath))
  134. - throw Exception("Plugin binary not found at %s", libraryPath.c_str());
  135. -
  136. - // Load dynamic/shared library
  137. - plugin->handle = loadLibrary(libraryPath);
  138. -
  139. - // Get plugin's init() function
  140. - InitCallback initCallback = (InitCallback) getSymbol(plugin->handle, "init");
  141. - if (!initCallback)
  142. - throw Exception("Failed to read init() symbol in %s", libraryPath.c_str());
  143. -
  144. - return initCallback;
  145. -}
  146. -
  147. -
  148. -/** If path is blank, loads Core */
  149. -static Plugin* loadPlugin(std::string path) {
  150. - if (path == "")
  151. - INFO("Loading Core plugin");
  152. - else
  153. - INFO("Loading plugin from %s", path.c_str());
  154. -
  155. - Plugin* plugin = new Plugin;
  156. - try {
  157. - // Set plugin path
  158. - plugin->path = (path == "") ? asset::systemDir : path;
  159. -
  160. - // Get modified timestamp
  161. - if (path != "") {
  162. - struct stat statbuf;
  163. - if (!stat(path.c_str(), &statbuf)) {
  164. -#if defined ARCH_MAC
  165. - plugin->modifiedTimestamp = (double) statbuf.st_mtimespec.tv_sec + statbuf.st_mtimespec.tv_nsec * 1e-9;
  166. -#elif defined ARCH_WIN
  167. - plugin->modifiedTimestamp = (double) statbuf.st_mtime;
  168. -#elif defined ARCH_LIN
  169. - plugin->modifiedTimestamp = (double) statbuf.st_mtim.tv_sec + statbuf.st_mtim.tv_nsec * 1e-9;
  170. -#endif
  171. - }
  172. - }
  173. -
  174. - // Load plugin.json
  175. - std::string manifestFilename = (path == "") ? asset::system("Core.json") : system::join(path, "plugin.json");
  176. - FILE* file = std::fopen(manifestFilename.c_str(), "r");
  177. - if (!file)
  178. - throw Exception("Manifest file %s does not exist", manifestFilename.c_str());
  179. - DEFER({std::fclose(file);});
  180. -
  181. - json_error_t error;
  182. - json_t* rootJ = json_loadf(file, 0, &error);
  183. - if (!rootJ)
  184. - throw Exception("JSON parsing error at %s %d:%d %s", manifestFilename.c_str(), error.line, error.column, error.text);
  185. - DEFER({json_decref(rootJ);});
  186. -
  187. - // Load manifest
  188. - plugin->fromJson(rootJ);
  189. -
  190. - // Reject plugin if slug already exists
  191. - Plugin* existingPlugin = getPlugin(plugin->slug);
  192. - if (existingPlugin)
  193. - throw Exception("Plugin %s is already loaded, not attempting to load it again", plugin->slug.c_str());
  194. -
  195. - // Call init callback
  196. - InitCallback initCallback;
  197. - if (path == "") {
  198. - initCallback = core::init;
  199. - }
  200. - else {
  201. - initCallback = loadPluginCallback(plugin);
  202. - }
  203. - initCallback(plugin);
  204. -
  205. - // Load modules manifest
  206. - json_t* modulesJ = json_object_get(rootJ, "modules");
  207. - plugin->modulesFromJson(modulesJ);
  208. -
  209. - // Call settingsFromJson() if exists
  210. - // Returns NULL for Core.
  211. - auto settingsFromJson = (decltype(&::settingsFromJson)) getSymbol(plugin->handle, "settingsFromJson");
  212. - if (settingsFromJson) {
  213. - json_t* settingsJ = json_object_get(settings::pluginSettingsJ, plugin->slug.c_str());
  214. - if (settingsJ)
  215. - settingsFromJson(settingsJ);
  216. - }
  217. - }
  218. - catch (Exception& e) {
  219. - WARN("Could not load plugin %s: %s", path.c_str(), e.what());
  220. - delete plugin;
  221. - return NULL;
  222. - }
  223. -
  224. - INFO("Loaded %s v%s", plugin->slug.c_str(), plugin->version.c_str());
  225. - plugins.push_back(plugin);
  226. - return plugin;
  227. -}
  228. -
  229. -
  230. -static void loadPlugins(std::string path) {
  231. - for (std::string pluginPath : system::getEntries(path)) {
  232. - if (!system::isDirectory(pluginPath))
  233. - continue;
  234. - if (!loadPlugin(pluginPath)) {
  235. - // Ignore bad plugins. They are reported in the log.
  236. - }
  237. - }
  238. -}
  239. -
  240. -
  241. -static void extractPackages(std::string path) {
  242. - std::string message;
  243. -
  244. - for (std::string packagePath : system::getEntries(path)) {
  245. - if (!system::isFile(packagePath))
  246. - continue;
  247. - if (system::getExtension(packagePath) != ".vcvplugin")
  248. - continue;
  249. -
  250. - // Extract package
  251. - INFO("Extracting package %s", packagePath.c_str());
  252. - try {
  253. - system::unarchiveToDirectory(packagePath, path);
  254. - }
  255. - catch (Exception& e) {
  256. - WARN("Plugin package %s failed to extract: %s", packagePath.c_str(), e.what());
  257. - message += string::f("Could not extract plugin package %s\n", packagePath.c_str());
  258. - continue;
  259. - }
  260. - // Remove package
  261. - system::remove(packagePath.c_str());
  262. - }
  263. - if (!message.empty()) {
  264. - osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK, message.c_str());
  265. - }
  266. -}
  267. -
  268. -////////////////////
  269. -// public API
  270. -////////////////////
  271. -
  272. -void init() {
  273. - // Don't re-initialize
  274. - assert(plugins.empty());
  275. -
  276. - // Load Core
  277. - loadPlugin("");
  278. -
  279. - pluginsPath = asset::user("plugins");
  280. -
  281. - // Get user plugins directory
  282. - system::createDirectory(pluginsPath);
  283. -
  284. - // Don't load plugins if safe mode is enabled
  285. - if (settings::safeMode)
  286. - return;
  287. -
  288. - // Extract packages and load plugins
  289. - extractPackages(pluginsPath);
  290. - loadPlugins(pluginsPath);
  291. -
  292. - // If Fundamental wasn't loaded, copy the bundled Fundamental package and load it
  293. - if (!settings::devMode && !getPlugin("Fundamental")) {
  294. - std::string fundamentalSrc = asset::system("Fundamental.vcvplugin");
  295. - std::string fundamentalDir = system::join(pluginsPath, "Fundamental");
  296. - if (system::isFile(fundamentalSrc)) {
  297. - INFO("Extracting bundled Fundamental package");
  298. - try {
  299. - system::unarchiveToDirectory(fundamentalSrc.c_str(), pluginsPath.c_str());
  300. - loadPlugin(fundamentalDir);
  301. - }
  302. - catch (Exception& e) {
  303. - WARN("Could not extract Fundamental package: %s", e.what());
  304. - }
  305. - }
  306. - }
  307. -}
  308. -
  309. -
  310. -static void destroyPlugin(Plugin* plugin) {
  311. - void* handle = plugin->handle;
  312. -
  313. - // Call destroy() if defined in the plugin library
  314. - typedef void (*DestroyCallback)();
  315. - DestroyCallback destroyCallback = NULL;
  316. - if (handle) {
  317. - destroyCallback = (DestroyCallback) getSymbol(handle, "destroy");
  318. - }
  319. - if (destroyCallback) {
  320. - try {
  321. - destroyCallback();
  322. - }
  323. - catch (Exception& e) {
  324. - WARN("Could not destroy plugin %s", plugin->slug.c_str());
  325. - }
  326. - }
  327. -
  328. - // 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.
  329. - delete plugin;
  330. -
  331. - // Free library handle
  332. - if (handle) {
  333. -#if defined ARCH_WIN
  334. - FreeLibrary((HINSTANCE) handle);
  335. -#else
  336. - dlclose(handle);
  337. -#endif
  338. - }
  339. -}
  340. -
  341. -
  342. -void destroy() {
  343. - while (!plugins.empty()) {
  344. - Plugin* plugin = plugins.back();
  345. - INFO("Destroying plugin %s", plugin->name.c_str());
  346. - destroyPlugin(plugin);
  347. - plugins.pop_back();
  348. - }
  349. - assert(plugins.empty());
  350. -}
  351. -
  352. -
  353. -void settingsMergeJson(json_t* rootJ) {
  354. - for (Plugin* plugin : plugins) {
  355. - auto settingsToJson = (decltype(&::settingsToJson)) getSymbol(plugin->handle, "settingsToJson");
  356. - if (settingsToJson) {
  357. - json_t* settingsJ = settingsToJson();
  358. - json_object_set_new(rootJ, plugin->slug.c_str(), settingsJ);
  359. - }
  360. - else {
  361. - json_object_del(rootJ, plugin->slug.c_str());
  362. - }
  363. - }
  364. -}
  365. +void settingsMergeJson(json_t*) {}
  366. /** Given slug => fallback slug.
  367. @@ -348,6 +47,7 @@
  368. {"VultModules", "VultModulesFree"},
  369. {"AudibleInstrumentsPreview", "AudibleInstruments"},
  370. {"SequelSequencers", "DanielDavies"},
  371. + {"DelexanderVol1", "DelexandraVol1"},
  372. // {"", ""},
  373. };
  374. @@ -389,8 +89,19 @@
  375. */
  376. using PluginModuleSlug = std::tuple<std::string, std::string>;
  377. static const std::map<PluginModuleSlug, PluginModuleSlug> moduleSlugFallbacks = {
  378. + {{"Core", "AudioInterface2"}, {"Cardinal", "HostAudio2"}},
  379. + {{"Core", "AudioInterface"}, {"Cardinal", "HostAudio8"}},
  380. + {{"Core", "AudioInterface16"}, {"Cardinal", "HostAudio8"}},
  381. + {{"Core", "MIDIToCVInterface"}, {"Cardinal", "HostMIDI"}},
  382. + {{"Core", "MIDICCToCVInterface"}, {"Cardinal", "HostMIDICC"}},
  383. + {{"Core", "MIDITriggerToCVInterface"}, {"Cardinal", "HostMIDIGate"}},
  384. + {{"Core", "CV-MIDI"}, {"Cardinal", "HostMIDI"}},
  385. + {{"Core", "CV-CC"}, {"Cardinal", "HostMIDICC"}},
  386. + {{"Core", "CV-Gate"}, {"Cardinal", "HostMIDIGate"}},
  387. + {{"Core", "MIDI-Map"}, {"Cardinal", "HostMIDIMap"}},
  388. + {{"Core", "Notes"}, {"Cardinal", "TextEditor"}},
  389. + {{"Core", "Blank"}, {"Cardinal", "Blank"}},
  390. {{"MindMeld-ShapeMasterPro", "ShapeMasterPro"}, {"MindMeldModular", "ShapeMaster"}},
  391. - {{"MindMeldModular", "ShapeMaster"}, {"MindMeld-ShapeMasterPro", "ShapeMasterPro"}},
  392. // {{"", ""}, {"", ""}},
  393. };
  394. @@ -478,7 +189,6 @@
  395. }
  396. -std::string pluginsPath;
  397. std::vector<Plugin*> plugins;