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.

453 lines
12KB

  1. /*
  2. * DISTRHO Cardinal Plugin
  3. * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 3 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. #include <asset.hpp>
  18. #include <audio.hpp>
  19. #include <context.hpp>
  20. #include <library.hpp>
  21. #include <midi.hpp>
  22. #include <patch.hpp>
  23. #include <plugin.hpp>
  24. #include <random.hpp>
  25. // #include <rtaudio.hpp>
  26. #include <settings.hpp>
  27. #include <system.hpp>
  28. #include <app/Scene.hpp>
  29. #include <engine/Engine.hpp>
  30. #include <ui/common.hpp>
  31. #include <window/Window.hpp>
  32. #include <osdialog.h>
  33. #ifdef NDEBUG
  34. # undef DEBUG
  35. #endif
  36. #include "DistrhoPlugin.hpp"
  37. namespace rack {
  38. namespace plugin {
  39. void initStaticPlugins();
  40. void destroyStaticPlugins();
  41. }
  42. }
  43. START_NAMESPACE_DISTRHO
  44. // -----------------------------------------------------------------------------------------------------------
  45. // The following code was based from VCVRack adapters/standalone.cpp
  46. /*
  47. Copyright (C) 2016-2021 VCV
  48. This program is free software: you can redistribute it and/or modify it under the terms of the
  49. GNU General Public License as published by the Free Software Foundation, either version 3 of the
  50. License, or (at your option) any later version.
  51. */
  52. struct Initializer {
  53. Initializer()
  54. {
  55. using namespace rack;
  56. settings::autoCheckUpdates = false;
  57. settings::autosaveInterval = 0;
  58. settings::discordUpdateActivity = false;
  59. settings::isPlugin = true;
  60. settings::skipLoadOnLaunch = true;
  61. settings::showTipsOnLaunch = false;
  62. settings::threadCount = 1;
  63. system::init();
  64. asset::init();
  65. logger::init();
  66. random::init();
  67. // Make system dir point to source code location. It is good enough for now
  68. asset::systemDir = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "Rack";
  69. // Log environment
  70. INFO("%s %s v%s", APP_NAME.c_str(), APP_EDITION.c_str(), APP_VERSION.c_str());
  71. INFO("%s", system::getOperatingSystemInfo().c_str());
  72. INFO("System directory: %s", asset::systemDir.c_str());
  73. INFO("User directory: %s", asset::userDir.c_str());
  74. INFO("System time: %s", string::formatTimeISO(system::getUnixTime()).c_str());
  75. // Check existence of the system res/ directory
  76. const std::string resDir = asset::system("res");
  77. if (! system::isDirectory(resDir))
  78. {
  79. d_stderr2("Resource directory \"%s\" does not exist.\n"
  80. "Make sure Cardinal was downloaded and installed correctly.", resDir.c_str());
  81. }
  82. INFO("Initializing environment");
  83. audio::init(); // does nothing
  84. midi::init(); // does nothing
  85. // rtaudioInit();
  86. plugin::initStaticPlugins();
  87. ui::init();
  88. }
  89. ~Initializer()
  90. {
  91. using namespace rack;
  92. ui::destroy(); // does nothing
  93. INFO("Destroying plugins");
  94. plugin::destroyStaticPlugins();
  95. midi::destroy();
  96. audio::destroy();
  97. INFO("Destroying logger");
  98. logger::destroy();
  99. }
  100. };
  101. static const Initializer& getInitializerInstance()
  102. {
  103. static const Initializer init;
  104. return init;
  105. }
  106. // -----------------------------------------------------------------------------------------------------------
  107. struct CardinalAudioDevice : rack::audio::Device {
  108. Plugin* const fPlugin;
  109. CardinalAudioDevice(Plugin* const plugin)
  110. : fPlugin(plugin) {}
  111. std::string getName() override
  112. {
  113. return "Plugin Device";
  114. }
  115. int getNumInputs() override
  116. {
  117. return DISTRHO_PLUGIN_NUM_INPUTS;
  118. }
  119. int getNumOutputs() override
  120. {
  121. return DISTRHO_PLUGIN_NUM_OUTPUTS;
  122. }
  123. std::set<float> getSampleRates() override
  124. {
  125. return { getSampleRate() };
  126. }
  127. float getSampleRate() override
  128. {
  129. return fPlugin->getSampleRate();
  130. }
  131. void setSampleRate(float) override {}
  132. std::set<int> getBlockSizes() override
  133. {
  134. return { getBlockSize() };
  135. }
  136. int getBlockSize() override
  137. {
  138. return fPlugin->getBufferSize();
  139. }
  140. void setBlockSize(int) override {}
  141. };
  142. // -----------------------------------------------------------------------------------------------------------
  143. struct CardinalAudioDriver : rack::audio::Driver {
  144. Plugin* const fPlugin;
  145. CardinalAudioDevice fDevice;
  146. CardinalAudioDriver(Plugin* const plugin)
  147. : fPlugin(plugin),
  148. fDevice(plugin) {}
  149. std::string getName() override
  150. {
  151. return "Plugin Driver";
  152. }
  153. std::vector<int> getDeviceIds() override
  154. {
  155. return { 0 };
  156. }
  157. std::string getDeviceName(int) override
  158. {
  159. return "Plugin Driver Device";
  160. }
  161. int getDeviceNumInputs(int) override
  162. {
  163. return DISTRHO_PLUGIN_NUM_INPUTS;
  164. }
  165. int getDeviceNumOutputs(int) override
  166. {
  167. return DISTRHO_PLUGIN_NUM_OUTPUTS;
  168. }
  169. rack::audio::Device* subscribe(int, rack::audio::Port* const port) override
  170. {
  171. fDevice.subscribe(port);
  172. fDevice.onStartStream();
  173. return &fDevice;
  174. }
  175. void unsubscribe(int, rack::audio::Port* const port) override
  176. {
  177. fDevice.onStopStream();
  178. fDevice.unsubscribe(port);
  179. }
  180. };
  181. // -----------------------------------------------------------------------------------------------------------
  182. class CardinalPlugin : public Plugin
  183. {
  184. rack::Context* const fContext;
  185. CardinalAudioDriver* const fAudioDriver;
  186. float* fAudioBufferIn;
  187. float* fAudioBufferOut;
  188. std::string fAutosavePath;
  189. struct ScopedContext {
  190. ScopedContext(CardinalPlugin* const plugin)
  191. {
  192. rack::contextSet(plugin->fContext);
  193. }
  194. ~ScopedContext()
  195. {
  196. rack::contextSet(nullptr);
  197. }
  198. };
  199. public:
  200. CardinalPlugin()
  201. : Plugin(0, 0, 0),
  202. fContext(new rack::Context),
  203. fAudioDriver(new CardinalAudioDriver(this)),
  204. fAudioBufferIn(nullptr),
  205. fAudioBufferOut(nullptr)
  206. {
  207. // create unique temporary path for this instance
  208. try {
  209. char uidBuf[24];
  210. const std::string tmp = rack::system::getTempDirectory();
  211. for (int i=1;; ++i)
  212. {
  213. std::snprintf(uidBuf, sizeof(uidBuf), "Cardinal.%04d", i);
  214. const std::string trypath = rack::system::join(tmp, uidBuf);
  215. if (! rack::system::exists(trypath))
  216. {
  217. if (rack::system::createDirectories(trypath))
  218. fAutosavePath = trypath;
  219. break;
  220. }
  221. }
  222. } DISTRHO_SAFE_EXCEPTION("create unique temporary path");
  223. const ScopedContext sc(this);
  224. rack::audio::addDriver(0, fAudioDriver);
  225. fContext->engine = new rack::engine::Engine;
  226. fContext->history = new rack::history::State;
  227. fContext->patch = new rack::patch::Manager;
  228. fContext->patch->autosavePath = fAutosavePath;
  229. fContext->patch->templatePath = CARDINAL_PLUGIN_SOURCE_DIR DISTRHO_OS_SEP_STR "template.vcv";
  230. fContext->engine->startFallbackThread();
  231. }
  232. ~CardinalPlugin() override
  233. {
  234. {
  235. const ScopedContext sc(this);
  236. delete fContext;
  237. // rack::audio::destroy();
  238. }
  239. if (! fAutosavePath.empty())
  240. rack::system::removeRecursively(fAutosavePath);
  241. }
  242. rack::Context* getRackContext() const noexcept
  243. {
  244. return fContext;
  245. }
  246. protected:
  247. /* --------------------------------------------------------------------------------------------------------
  248. * Information */
  249. /**
  250. Get the plugin label.
  251. A plugin label follows the same rules as Parameter::symbol, with the exception that it can start with numbers.
  252. */
  253. const char* getLabel() const override
  254. {
  255. return "Cardinal";
  256. }
  257. /**
  258. Get an extensive comment/description about the plugin.
  259. */
  260. const char* getDescription() const override
  261. {
  262. return "...";
  263. }
  264. /**
  265. Get the plugin author/maker.
  266. */
  267. const char* getMaker() const override
  268. {
  269. return "DISTRHO";
  270. }
  271. /**
  272. Get the plugin homepage.
  273. */
  274. const char* getHomePage() const override
  275. {
  276. return "https://github.com/DISTRHO/Cardinal";
  277. }
  278. /**
  279. Get the plugin license name (a single line of text).
  280. For commercial plugins this should return some short copyright information.
  281. */
  282. const char* getLicense() const override
  283. {
  284. return "ISC";
  285. }
  286. /**
  287. Get the plugin version, in hexadecimal.
  288. */
  289. uint32_t getVersion() const override
  290. {
  291. return d_version(1, 0, 0);
  292. }
  293. /**
  294. Get the plugin unique Id.
  295. This value is used by LADSPA, DSSI and VST plugin formats.
  296. */
  297. int64_t getUniqueId() const override
  298. {
  299. return d_cconst('d', 'C', 'd', 'n');
  300. }
  301. /* --------------------------------------------------------------------------------------------------------
  302. * Init */
  303. /* --------------------------------------------------------------------------------------------------------
  304. * Internal data */
  305. /* --------------------------------------------------------------------------------------------------------
  306. * Process */
  307. void activate() override
  308. {
  309. const uint32_t bufferSize = getBufferSize() * DISTRHO_PLUGIN_NUM_OUTPUTS;
  310. fAudioBufferIn = new float[bufferSize];
  311. fAudioBufferOut = new float[bufferSize];
  312. std::memset(fAudioBufferIn, 0, sizeof(float)*bufferSize);
  313. }
  314. void deactivate() override
  315. {
  316. fAudioDriver->fDevice.onStopStream();
  317. delete[] fAudioBufferIn;
  318. delete[] fAudioBufferOut;
  319. fAudioBufferIn = fAudioBufferOut = nullptr;
  320. }
  321. /**
  322. Run/process function for plugins without MIDI input.
  323. */
  324. void run(const float** const inputs, float** const outputs, const uint32_t frames) override
  325. {
  326. /*
  327. fContext->engine->setFrame(getTimePosition().frame);
  328. fContext->engine->stepBlock(frames);
  329. */
  330. for (uint32_t i=0, j=0; i<frames; ++i)
  331. {
  332. fAudioBufferIn[j++] = inputs[0][i];
  333. fAudioBufferIn[j++] = inputs[1][i];
  334. }
  335. std::memset(fAudioBufferOut, 0, sizeof(float)*frames*DISTRHO_PLUGIN_NUM_OUTPUTS);
  336. fAudioDriver->fDevice.processBuffer(fAudioBufferIn, DISTRHO_PLUGIN_NUM_INPUTS,
  337. fAudioBufferOut, DISTRHO_PLUGIN_NUM_OUTPUTS, frames);
  338. for (uint32_t i=0, j=0; i<frames; ++i)
  339. {
  340. outputs[0][i] = fAudioBufferOut[j++];
  341. outputs[1][i] = fAudioBufferOut[j++];
  342. }
  343. }
  344. /*
  345. void sampleRateChanged(const double newSampleRate) override
  346. {
  347. fContext->engine->setSampleRate(newSampleRate);
  348. }
  349. */
  350. // -------------------------------------------------------------------------------------------------------
  351. private:
  352. /**
  353. Set our plugin class as non-copyable and add a leak detector just in case.
  354. */
  355. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CardinalPlugin)
  356. };
  357. rack::Context* getRackContextFromPlugin(void* const ptr)
  358. {
  359. return static_cast<CardinalPlugin*>(ptr)->getRackContext();
  360. }
  361. /* ------------------------------------------------------------------------------------------------------------
  362. * Plugin entry point, called by DPF to create a new plugin instance. */
  363. Plugin* createPlugin()
  364. {
  365. getInitializerInstance();
  366. return new CardinalPlugin();
  367. }
  368. // -----------------------------------------------------------------------------------------------------------
  369. END_NAMESPACE_DISTRHO