DISTRHO Plugin Framework
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.

485 lines
13KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2018 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_INTERNAL_HPP_INCLUDED
  17. #define DISTRHO_UI_INTERNAL_HPP_INCLUDED
  18. #include "../DistrhoUI.hpp"
  19. #ifdef HAVE_DGL
  20. # include "../../dgl/Application.hpp"
  21. # include "../../dgl/Window.hpp"
  22. using DGL_NAMESPACE::Application;
  23. using DGL_NAMESPACE::IdleCallback;
  24. using DGL_NAMESPACE::Window;
  25. #endif
  26. START_NAMESPACE_DISTRHO
  27. // -----------------------------------------------------------------------
  28. // Static data, see DistrhoUI.cpp
  29. extern double d_lastUiSampleRate;
  30. extern void* d_lastUiDspPtr;
  31. #ifdef HAVE_DGL
  32. extern Window* d_lastUiWindow;
  33. #endif
  34. extern uintptr_t g_nextWindowId;
  35. extern const char* g_nextBundlePath;
  36. // -----------------------------------------------------------------------
  37. // UI callbacks
  38. typedef void (*editParamFunc) (void* ptr, uint32_t rindex, bool started);
  39. typedef void (*setParamFunc) (void* ptr, uint32_t rindex, float value);
  40. typedef void (*setStateFunc) (void* ptr, const char* key, const char* value);
  41. typedef void (*sendNoteFunc) (void* ptr, uint8_t channel, uint8_t note, uint8_t velo);
  42. typedef void (*setSizeFunc) (void* ptr, uint width, uint height);
  43. // -----------------------------------------------------------------------
  44. // UI private data
  45. struct UI::PrivateData {
  46. // DSP
  47. double sampleRate;
  48. uint32_t parameterOffset;
  49. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  50. void* dspPtr;
  51. #endif
  52. // Callbacks
  53. void* callbacksPtr;
  54. editParamFunc editParamCallbackFunc;
  55. setParamFunc setParamCallbackFunc;
  56. setStateFunc setStateCallbackFunc;
  57. sendNoteFunc sendNoteCallbackFunc;
  58. setSizeFunc setSizeCallbackFunc;
  59. PrivateData() noexcept
  60. : sampleRate(d_lastUiSampleRate),
  61. parameterOffset(0),
  62. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  63. dspPtr(d_lastUiDspPtr),
  64. #endif
  65. callbacksPtr(nullptr),
  66. editParamCallbackFunc(nullptr),
  67. setParamCallbackFunc(nullptr),
  68. setStateCallbackFunc(nullptr),
  69. sendNoteCallbackFunc(nullptr),
  70. setSizeCallbackFunc(nullptr)
  71. {
  72. DISTRHO_SAFE_ASSERT(d_isNotZero(sampleRate));
  73. #if defined(DISTRHO_PLUGIN_TARGET_DSSI) || defined(DISTRHO_PLUGIN_TARGET_LV2)
  74. parameterOffset += DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
  75. # if DISTRHO_PLUGIN_WANT_LATENCY
  76. parameterOffset += 1;
  77. # endif
  78. #endif
  79. #ifdef DISTRHO_PLUGIN_TARGET_LV2
  80. # if (DISTRHO_PLUGIN_IS_SYNTH || DISTRHO_PLUGIN_WANT_TIMEPOS || DISTRHO_PLUGIN_WANT_STATE)
  81. parameterOffset += 1;
  82. # if DISTRHO_PLUGIN_WANT_STATE
  83. parameterOffset += 1;
  84. # endif
  85. # endif
  86. #endif
  87. }
  88. void editParamCallback(const uint32_t rindex, const bool started)
  89. {
  90. if (editParamCallbackFunc != nullptr)
  91. editParamCallbackFunc(callbacksPtr, rindex, started);
  92. }
  93. void setParamCallback(const uint32_t rindex, const float value)
  94. {
  95. if (setParamCallbackFunc != nullptr)
  96. setParamCallbackFunc(callbacksPtr, rindex, value);
  97. }
  98. void setStateCallback(const char* const key, const char* const value)
  99. {
  100. if (setStateCallbackFunc != nullptr)
  101. setStateCallbackFunc(callbacksPtr, key, value);
  102. }
  103. void sendNoteCallback(const uint8_t channel, const uint8_t note, const uint8_t velocity)
  104. {
  105. if (sendNoteCallbackFunc != nullptr)
  106. sendNoteCallbackFunc(callbacksPtr, channel, note, velocity);
  107. }
  108. void setSizeCallback(const uint width, const uint height)
  109. {
  110. if (setSizeCallbackFunc != nullptr)
  111. setSizeCallbackFunc(callbacksPtr, width, height);
  112. }
  113. };
  114. // -----------------------------------------------------------------------
  115. // Plugin Window, needed to take care of resize properly
  116. #ifdef HAVE_DGL
  117. static inline
  118. UI* createUiWrapper(void* const dspPtr, Window* const window)
  119. {
  120. d_lastUiDspPtr = dspPtr;
  121. d_lastUiWindow = window;
  122. UI* const ret = createUI();
  123. d_lastUiDspPtr = nullptr;
  124. d_lastUiWindow = nullptr;
  125. return ret;
  126. }
  127. class UIExporterWindow : public Window
  128. {
  129. public:
  130. UIExporterWindow(Application& app, const intptr_t winId, void* const dspPtr)
  131. : Window(app, winId),
  132. fUI(createUiWrapper(dspPtr, this)),
  133. fIsReady(false)
  134. {
  135. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  136. // set window size
  137. setResizable(false);
  138. setSize(fUI->getWidth(), fUI->getHeight());
  139. }
  140. ~UIExporterWindow()
  141. {
  142. delete fUI;
  143. }
  144. UI* getUI() const noexcept
  145. {
  146. return fUI;
  147. }
  148. bool isReady() const noexcept
  149. {
  150. return fIsReady;
  151. }
  152. protected:
  153. // custom window reshape
  154. void onReshape(uint width, uint height) override
  155. {
  156. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  157. fUI->uiReshape(width, height);
  158. fIsReady = true;
  159. }
  160. #ifndef DGL_FILE_BROWSER_DISABLED
  161. // custom file-browser selected
  162. void fileBrowserSelected(const char* filename) override
  163. {
  164. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  165. fUI->uiFileBrowserSelected(filename);
  166. }
  167. #endif
  168. private:
  169. UI* const fUI;
  170. bool fIsReady;
  171. };
  172. #else
  173. static inline
  174. UI* createUiWrapper(void* const dspPtr, const uintptr_t winId, const char* const bundlePath)
  175. {
  176. d_lastUiDspPtr = dspPtr;
  177. g_nextWindowId = winId;
  178. g_nextBundlePath = bundlePath;
  179. UI* const ret = createUI();
  180. d_lastUiDspPtr = nullptr;
  181. g_nextWindowId = 0;
  182. g_nextBundlePath = nullptr;
  183. return ret;
  184. }
  185. #endif
  186. // -----------------------------------------------------------------------
  187. // UI exporter class
  188. class UIExporter
  189. {
  190. public:
  191. UIExporter(void* const callbacksPtr,
  192. const intptr_t winId,
  193. const editParamFunc editParamCall,
  194. const setParamFunc setParamCall,
  195. const setStateFunc setStateCall,
  196. const sendNoteFunc sendNoteCall,
  197. const setSizeFunc setSizeCall,
  198. void* const dspPtr = nullptr,
  199. const char* const bundlePath = nullptr)
  200. #ifdef HAVE_DGL
  201. : glApp(),
  202. glWindow(glApp, winId, dspPtr),
  203. fChangingSize(false),
  204. fUI(glWindow.getUI()),
  205. #else
  206. : fUI(createUiWrapper(dspPtr, winId, bundlePath)),
  207. #endif
  208. fData((fUI != nullptr) ? fUI->pData : nullptr)
  209. {
  210. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  211. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  212. fData->callbacksPtr = callbacksPtr;
  213. fData->editParamCallbackFunc = editParamCall;
  214. fData->setParamCallbackFunc = setParamCall;
  215. fData->setStateCallbackFunc = setStateCall;
  216. fData->sendNoteCallbackFunc = sendNoteCall;
  217. fData->setSizeCallbackFunc = setSizeCall;
  218. #ifdef HAVE_DGL
  219. // unused
  220. return; (void)bundlePath;
  221. #endif
  222. }
  223. // -------------------------------------------------------------------
  224. uint getWidth() const noexcept
  225. {
  226. #ifdef HAVE_DGL
  227. return glWindow.getWidth();
  228. #else
  229. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1);
  230. return fUI->getWidth();
  231. #endif
  232. }
  233. uint getHeight() const noexcept
  234. {
  235. #ifdef HAVE_DGL
  236. return glWindow.getHeight();
  237. #else
  238. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1);
  239. return fUI->getHeight();
  240. #endif
  241. }
  242. bool isVisible() const noexcept
  243. {
  244. #ifdef HAVE_DGL
  245. return glWindow.isVisible();
  246. #else
  247. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false);
  248. return fUI->isRunning();
  249. #endif
  250. }
  251. // -------------------------------------------------------------------
  252. intptr_t getWindowId() const noexcept
  253. {
  254. #ifdef HAVE_DGL
  255. return glWindow.getWindowId();
  256. #else
  257. return 0;
  258. #endif
  259. }
  260. // -------------------------------------------------------------------
  261. uint32_t getParameterOffset() const noexcept
  262. {
  263. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  264. return fData->parameterOffset;
  265. }
  266. // -------------------------------------------------------------------
  267. void parameterChanged(const uint32_t index, const float value)
  268. {
  269. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  270. fUI->parameterChanged(index, value);
  271. }
  272. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  273. void programLoaded(const uint32_t index)
  274. {
  275. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  276. fUI->programLoaded(index);
  277. }
  278. #endif
  279. #if DISTRHO_PLUGIN_WANT_STATE
  280. void stateChanged(const char* const key, const char* const value)
  281. {
  282. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  283. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  284. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
  285. fUI->stateChanged(key, value);
  286. }
  287. #endif
  288. // -------------------------------------------------------------------
  289. #ifdef HAVE_DGL
  290. void exec(IdleCallback* const cb)
  291. {
  292. DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
  293. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  294. glWindow.addIdleCallback(cb);
  295. glWindow.setVisible(true);
  296. glApp.exec();
  297. }
  298. void exec_idle()
  299. {
  300. if (glWindow.isReady())
  301. fUI->uiIdle();
  302. }
  303. #endif
  304. bool idle()
  305. {
  306. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false);
  307. #ifdef HAVE_DGL
  308. glApp.idle();
  309. if (glWindow.isReady())
  310. fUI->uiIdle();
  311. return ! glApp.isQuiting();
  312. #else
  313. return fUI->isRunning();
  314. #endif
  315. }
  316. void quit()
  317. {
  318. #ifdef HAVE_DGL
  319. glWindow.close();
  320. glApp.quit();
  321. #else
  322. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  323. fUI->terminateAndWaitForProcess();
  324. #endif
  325. }
  326. // -------------------------------------------------------------------
  327. void setWindowTitle(const char* const uiTitle)
  328. {
  329. #ifdef HAVE_DGL
  330. glWindow.setTitle(uiTitle);
  331. #else
  332. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  333. fUI->setTitle(uiTitle);
  334. #endif
  335. }
  336. #ifdef HAVE_DGL
  337. void setWindowSize(const uint width, const uint height, const bool updateUI = false)
  338. {
  339. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  340. DISTRHO_SAFE_ASSERT_RETURN(! fChangingSize,);
  341. fChangingSize = true;
  342. if (updateUI)
  343. fUI->setSize(width, height);
  344. glWindow.setSize(width, height);
  345. fChangingSize = false;
  346. }
  347. void setWindowTransientWinId(const uintptr_t winId)
  348. {
  349. glWindow.setTransientWinId(winId);
  350. }
  351. bool setWindowVisible(const bool yesNo)
  352. {
  353. glWindow.setVisible(yesNo);
  354. return ! glApp.isQuiting();
  355. }
  356. bool handlePluginKeyboard(const bool press, const uint key)
  357. {
  358. return glWindow.handlePluginKeyboard(press, key);
  359. }
  360. bool handlePluginSpecial(const bool press, const Key key)
  361. {
  362. return glWindow.handlePluginKeyboard(press, key);
  363. }
  364. #else
  365. void setWindowSize(const uint, const uint, const bool) {}
  366. void setWindowTransientWinId(const uintptr_t) {}
  367. bool setWindowVisible(const bool) { return true; }
  368. #endif
  369. // -------------------------------------------------------------------
  370. void setSampleRate(const double sampleRate, const bool doCallback = false)
  371. {
  372. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  373. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  374. DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
  375. if (d_isEqual(fData->sampleRate, sampleRate))
  376. return;
  377. fData->sampleRate = sampleRate;
  378. if (doCallback)
  379. fUI->sampleRateChanged(sampleRate);
  380. }
  381. private:
  382. #ifdef HAVE_DGL
  383. // -------------------------------------------------------------------
  384. // DGL Application and Window for this widget
  385. Application glApp;
  386. UIExporterWindow glWindow;
  387. // prevent recursion
  388. bool fChangingSize;
  389. #endif
  390. // -------------------------------------------------------------------
  391. // Widget and DistrhoUI data
  392. UI* const fUI;
  393. UI::PrivateData* const fData;
  394. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
  395. };
  396. // -----------------------------------------------------------------------
  397. END_NAMESPACE_DISTRHO
  398. #endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED