Collection of DPF-based plugins for packaging
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.

481 lines
14KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #ifndef DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
  17. #define DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED
  18. #include "../DistrhoUI.hpp"
  19. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  20. # include "../extra/Sleep.hpp"
  21. #else
  22. # include "../../dgl/src/ApplicationPrivateData.hpp"
  23. # include "../../dgl/src/WindowPrivateData.hpp"
  24. # include "../../dgl/src/pugl.hpp"
  25. #endif
  26. #if defined(DISTRHO_PLUGIN_TARGET_JACK) || defined(DISTRHO_PLUGIN_TARGET_DSSI)
  27. # define DISTRHO_UI_IS_STANDALONE 1
  28. #else
  29. # define DISTRHO_UI_IS_STANDALONE 0
  30. #endif
  31. #if defined(DISTRHO_PLUGIN_TARGET_VST2)
  32. # undef DISTRHO_UI_USER_RESIZABLE
  33. # define DISTRHO_UI_USER_RESIZABLE 0
  34. #endif
  35. // -----------------------------------------------------------------------
  36. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  37. START_NAMESPACE_DISTRHO
  38. #else
  39. START_NAMESPACE_DGL
  40. #endif
  41. // -----------------------------------------------------------------------
  42. // Plugin Application, will set class name based on plugin details
  43. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  44. struct PluginApplication
  45. {
  46. DGL_NAMESPACE::IdleCallback* idleCallback;
  47. UI* ui;
  48. explicit PluginApplication()
  49. : idleCallback(nullptr),
  50. ui(nullptr) {}
  51. void addIdleCallback(DGL_NAMESPACE::IdleCallback* const cb)
  52. {
  53. DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
  54. DISTRHO_SAFE_ASSERT_RETURN(idleCallback == nullptr,);
  55. idleCallback = cb;
  56. }
  57. bool isQuitting() const noexcept
  58. {
  59. return ui->isQuitting();
  60. }
  61. bool isStandalone() const noexcept
  62. {
  63. return DISTRHO_UI_IS_STANDALONE;
  64. }
  65. void exec()
  66. {
  67. while (ui->isRunning())
  68. {
  69. d_msleep(30);
  70. idleCallback->idleCallback();
  71. }
  72. if (! ui->isQuitting())
  73. ui->close();
  74. }
  75. // these are not needed
  76. void idle() {}
  77. void quit() {}
  78. void triggerIdleCallbacks() {}
  79. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
  80. };
  81. #else
  82. class PluginApplication : public Application
  83. {
  84. public:
  85. explicit PluginApplication()
  86. : Application(DISTRHO_UI_IS_STANDALONE)
  87. {
  88. const char* const className = (
  89. #ifdef DISTRHO_PLUGIN_BRAND
  90. DISTRHO_PLUGIN_BRAND
  91. #else
  92. DISTRHO_MACRO_AS_STRING(DISTRHO_NAMESPACE)
  93. #endif
  94. "-" DISTRHO_PLUGIN_NAME
  95. );
  96. setClassName(className);
  97. }
  98. void triggerIdleCallbacks()
  99. {
  100. pData->triggerIdleCallbacks();
  101. }
  102. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginApplication)
  103. };
  104. #endif
  105. // -----------------------------------------------------------------------
  106. // Plugin Window, will pass some Window events to UI
  107. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  108. class PluginWindow
  109. {
  110. UI* const ui;
  111. public:
  112. explicit PluginWindow(UI* const uiPtr, PluginApplication& app)
  113. : ui(uiPtr)
  114. {
  115. app.ui = ui;
  116. }
  117. // fetch cached data
  118. uint getWidth() const noexcept { return ui->pData.width; }
  119. uint getHeight() const noexcept { return ui->pData.height; }
  120. double getScaleFactor() const noexcept { return ui->pData.scaleFactor; }
  121. // direct mappings
  122. void close() { ui->close(); }
  123. void focus() { ui->focus(); }
  124. void show() { ui->show(); }
  125. bool isResizable() const noexcept { return ui->isResizable(); }
  126. bool isVisible() const noexcept { return ui->isVisible(); }
  127. void setTitle(const char* const title) { ui->setTitle(title); }
  128. void setVisible(const bool visible) { ui->setVisible(visible); }
  129. uintptr_t getNativeWindowHandle() const noexcept { return ui->getNativeWindowHandle(); }
  130. void getGeometryConstraints(uint& minimumWidth, uint& minimumHeight, bool& keepAspectRatio) const noexcept
  131. {
  132. minimumWidth = ui->pData.minWidth;
  133. minimumHeight = ui->pData.minHeight;
  134. keepAspectRatio = ui->pData.keepAspectRatio;
  135. }
  136. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
  137. };
  138. #else // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  139. class PluginWindow : public Window
  140. {
  141. DISTRHO_NAMESPACE::UI* const ui;
  142. bool initializing;
  143. bool receivedReshapeDuringInit;
  144. public:
  145. explicit PluginWindow(DISTRHO_NAMESPACE::UI* const uiPtr,
  146. PluginApplication& app,
  147. const uintptr_t parentWindowHandle,
  148. const uint width,
  149. const uint height,
  150. const double scaleFactor)
  151. : Window(app, parentWindowHandle, width, height, scaleFactor, DISTRHO_UI_USER_RESIZABLE, false),
  152. ui(uiPtr),
  153. initializing(true),
  154. receivedReshapeDuringInit(false)
  155. {
  156. if (pData->view == nullptr)
  157. return;
  158. // this is called just before creating UI, ensuring proper context to it
  159. if (pData->initPost())
  160. puglBackendEnter(pData->view);
  161. }
  162. ~PluginWindow()
  163. {
  164. if (pData->view != nullptr)
  165. puglBackendLeave(pData->view);
  166. }
  167. // called after creating UI, restoring proper context
  168. void leaveContext()
  169. {
  170. if (pData->view == nullptr)
  171. return;
  172. if (receivedReshapeDuringInit)
  173. ui->uiReshape(getWidth(), getHeight());
  174. initializing = false;
  175. puglBackendLeave(pData->view);
  176. }
  177. // used for temporary windows (VST2/3 get size without active/visible view)
  178. void setIgnoreIdleCallbacks(const bool ignore = true)
  179. {
  180. pData->ignoreIdleCallbacks = ignore;
  181. }
  182. // called right before deleting UI, ensuring correct context
  183. void enterContextForDeletion()
  184. {
  185. if (pData->view != nullptr)
  186. puglBackendEnter(pData->view);
  187. }
  188. protected:
  189. void onFocus(const bool focus, const DGL_NAMESPACE::CrossingMode mode) override
  190. {
  191. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  192. if (initializing)
  193. return;
  194. ui->uiFocus(focus, mode);
  195. }
  196. void onReshape(const uint width, const uint height) override
  197. {
  198. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  199. if (initializing)
  200. {
  201. receivedReshapeDuringInit = true;
  202. return;
  203. }
  204. ui->uiReshape(width, height);
  205. }
  206. void onScaleFactorChanged(const double scaleFactor) override
  207. {
  208. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  209. if (initializing)
  210. return;
  211. ui->uiScaleFactorChanged(scaleFactor);
  212. }
  213. # ifndef DGL_FILE_BROWSER_DISABLED
  214. void onFileSelected(const char* filename) override;
  215. # endif
  216. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(PluginWindow)
  217. };
  218. #endif // DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  219. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  220. END_NAMESPACE_DISTRHO
  221. #else
  222. END_NAMESPACE_DGL
  223. #endif
  224. // -----------------------------------------------------------------------
  225. START_NAMESPACE_DISTRHO
  226. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  227. using DGL_NAMESPACE::PluginApplication;
  228. using DGL_NAMESPACE::PluginWindow;
  229. #endif
  230. // -----------------------------------------------------------------------
  231. // UI callbacks
  232. typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started);
  233. typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value);
  234. typedef void (*setStateFunc) (void* ptr, const char* key, const char* value);
  235. typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo);
  236. typedef void (*setSizeFunc) (void* ptr, uint width, uint height);
  237. typedef bool (*fileRequestFunc) (void* ptr, const char* key);
  238. // -----------------------------------------------------------------------
  239. // UI private data
  240. struct UI::PrivateData {
  241. // DGL
  242. PluginApplication app;
  243. ScopedPointer<PluginWindow> window;
  244. // DSP
  245. double sampleRate;
  246. uint32_t parameterOffset;
  247. void* dspPtr;
  248. // UI
  249. uint bgColor;
  250. uint fgColor;
  251. double scaleFactor;
  252. uintptr_t winId;
  253. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
  254. char* uiStateFileKeyRequest;
  255. #endif
  256. // Callbacks
  257. void* callbacksPtr;
  258. editParamFunc editParamCallbackFunc;
  259. setParamFunc setParamCallbackFunc;
  260. setStateFunc setStateCallbackFunc;
  261. sendNoteFunc sendNoteCallbackFunc;
  262. setSizeFunc setSizeCallbackFunc;
  263. fileRequestFunc fileRequestCallbackFunc;
  264. PrivateData() noexcept
  265. : app(),
  266. window(nullptr),
  267. sampleRate(0),
  268. parameterOffset(0),
  269. dspPtr(nullptr),
  270. bgColor(0),
  271. fgColor(0xffffffff),
  272. scaleFactor(1.0),
  273. winId(0),
  274. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
  275. uiStateFileKeyRequest(nullptr),
  276. #endif
  277. callbacksPtr(nullptr),
  278. editParamCallbackFunc(nullptr),
  279. setParamCallbackFunc(nullptr),
  280. setStateCallbackFunc(nullptr),
  281. sendNoteCallbackFunc(nullptr),
  282. setSizeCallbackFunc(nullptr),
  283. fileRequestCallbackFunc(nullptr)
  284. {
  285. #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
  286. parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
  287. # if DISTRHO_PLUGIN_WANT_LATENCY
  288. parameterOffset += 1;
  289. # endif
  290. #endif
  291. #ifdef DISTRHO_PLUGIN_TARGET_LV2
  292. # if (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
  293. parameterOffset += 1;
  294. # endif
  295. # if (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || DISTRHO_PLUGIN_WANT_STATE)
  296. parameterOffset += 1;
  297. # endif
  298. #endif
  299. #ifdef DISTRHO_PLUGIN_TARGET_VST3
  300. # if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  301. parameterOffset += 130 * 16; // all MIDI CCs plus aftertouch and pitchbend
  302. # endif
  303. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  304. parameterOffset += 1;
  305. # endif
  306. #endif
  307. }
  308. ~PrivateData() noexcept
  309. {
  310. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
  311. std::free(uiStateFileKeyRequest);
  312. #endif
  313. }
  314. void editParamCallback(const uint32_t rindex, const bool started)
  315. {
  316. if (editParamCallbackFunc != nullptr)
  317. editParamCallbackFunc(callbacksPtr, rindex, started);
  318. }
  319. void setParamCallback(const uint32_t rindex, const float value)
  320. {
  321. if (setParamCallbackFunc != nullptr)
  322. setParamCallbackFunc(callbacksPtr, rindex, value);
  323. }
  324. void setStateCallback(const char* const key, const char* const value)
  325. {
  326. if (setStateCallbackFunc != nullptr)
  327. setStateCallbackFunc(callbacksPtr, key, value);
  328. }
  329. void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity)
  330. {
  331. if (sendNoteCallbackFunc != nullptr)
  332. sendNoteCallbackFunc(callbacksPtr, channel, note, velocity);
  333. }
  334. void setSizeCallback(const uint width, const uint height)
  335. {
  336. if (setSizeCallbackFunc != nullptr)
  337. setSizeCallbackFunc(callbacksPtr, width, height);
  338. }
  339. // implemented below, after PluginWindow
  340. bool fileRequestCallback(const char* const key);
  341. static UI::PrivateData* s_nextPrivateData;
  342. #if DISTRHO_PLUGIN_HAS_EXTERNAL_UI
  343. static ExternalWindow::PrivateData createNextWindow(UI* ui, uint width, uint height);
  344. #else
  345. static PluginWindow& createNextWindow(UI* ui, uint width, uint height);
  346. #endif
  347. };
  348. // -----------------------------------------------------------------------
  349. // UI private data fileRequestCallback, which requires PluginWindow definitions
  350. inline bool UI::PrivateData::fileRequestCallback(const char* const key)
  351. {
  352. if (fileRequestCallbackFunc != nullptr)
  353. return fileRequestCallbackFunc(callbacksPtr, key);
  354. #if DISTRHO_PLUGIN_WANT_STATEFILES && !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
  355. std::free(uiStateFileKeyRequest);
  356. uiStateFileKeyRequest = strdup(key);
  357. DISTRHO_SAFE_ASSERT_RETURN(uiStateFileKeyRequest != nullptr, false);
  358. char title[0xff];
  359. snprintf(title, sizeof(title)-1u, DISTRHO_PLUGIN_NAME ": %s", key);
  360. title[sizeof(title)-1u] = '\0';
  361. DGL_NAMESPACE::Window::FileBrowserOptions opts;
  362. opts.title = title;
  363. return window->openFileBrowser(opts);
  364. #endif
  365. return false;
  366. }
  367. END_NAMESPACE_DISTRHO
  368. // -----------------------------------------------------------------------
  369. // PluginWindow onFileSelected that require UI::PrivateData definitions
  370. #if !DISTRHO_PLUGIN_HAS_EXTERNAL_UI && !defined(DGL_FILE_BROWSER_DISABLED)
  371. START_NAMESPACE_DGL
  372. inline void PluginWindow::onFileSelected(const char* const filename)
  373. {
  374. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  375. if (initializing)
  376. return;
  377. # if DISTRHO_PLUGIN_WANT_STATEFILES
  378. if (char* const key = ui->uiData->uiStateFileKeyRequest)
  379. {
  380. ui->uiData->uiStateFileKeyRequest = nullptr;
  381. if (filename != nullptr)
  382. {
  383. // notify DSP
  384. ui->setState(key, filename);
  385. // notify UI
  386. ui->stateChanged(key, filename);
  387. }
  388. std::free(key);
  389. return;
  390. }
  391. # endif
  392. ui->uiFileBrowserSelected(filename);
  393. }
  394. END_NAMESPACE_DGL
  395. #endif
  396. // -----------------------------------------------------------------------
  397. #endif // DISTRHO_UI_PRIVATE_DATA_HPP_INCLUDED