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.

480 lines
13KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2016 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::Application;
  23. using DGL::IdleCallback;
  24. using DGL::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. editParamFunc editParamCallbackFunc;
  54. setParamFunc setParamCallbackFunc;
  55. setStateFunc setStateCallbackFunc;
  56. sendNoteFunc sendNoteCallbackFunc;
  57. setSizeFunc setSizeCallbackFunc;
  58. void* ptr;
  59. PrivateData() noexcept
  60. : sampleRate(d_lastUiSampleRate),
  61. parameterOffset(0),
  62. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  63. dspPtr(d_lastUiDspPtr),
  64. #endif
  65. editParamCallbackFunc(nullptr),
  66. setParamCallbackFunc(nullptr),
  67. setStateCallbackFunc(nullptr),
  68. sendNoteCallbackFunc(nullptr),
  69. setSizeCallbackFunc(nullptr),
  70. ptr(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(ptr, rindex, started);
  92. }
  93. void setParamCallback(const uint32_t rindex, const float value)
  94. {
  95. if (setParamCallbackFunc != nullptr)
  96. setParamCallbackFunc(ptr, rindex, value);
  97. }
  98. void setStateCallback(const char* const key, const char* const value)
  99. {
  100. if (setStateCallbackFunc != nullptr)
  101. setStateCallbackFunc(ptr, 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(ptr, channel, note, velocity);
  107. }
  108. void setSizeCallback(const uint width, const uint height)
  109. {
  110. if (setSizeCallbackFunc != nullptr)
  111. setSizeCallbackFunc(ptr, 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 ptr, const intptr_t winId,
  192. const editParamFunc editParamCall, const setParamFunc setParamCall, const setStateFunc setStateCall, const sendNoteFunc sendNoteCall, const setSizeFunc setSizeCall,
  193. void* const dspPtr = nullptr,
  194. const char* const bundlePath = nullptr)
  195. #ifdef HAVE_DGL
  196. : glApp(),
  197. glWindow(glApp, winId, dspPtr),
  198. fChangingSize(false),
  199. fUI(glWindow.getUI()),
  200. #else
  201. : fUI(createUiWrapper(dspPtr, winId, bundlePath)),
  202. #endif
  203. fData((fUI != nullptr) ? fUI->pData : nullptr)
  204. {
  205. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  206. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  207. fData->ptr = ptr;
  208. fData->editParamCallbackFunc = editParamCall;
  209. fData->setParamCallbackFunc = setParamCall;
  210. fData->setStateCallbackFunc = setStateCall;
  211. fData->sendNoteCallbackFunc = sendNoteCall;
  212. fData->setSizeCallbackFunc = setSizeCall;
  213. #ifdef HAVE_DGL
  214. // unused
  215. return; (void)bundlePath;
  216. #endif
  217. }
  218. // -------------------------------------------------------------------
  219. uint getWidth() const noexcept
  220. {
  221. #ifdef HAVE_DGL
  222. return glWindow.getWidth();
  223. #else
  224. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1);
  225. return fUI->getWidth();
  226. #endif
  227. }
  228. uint getHeight() const noexcept
  229. {
  230. #ifdef HAVE_DGL
  231. return glWindow.getHeight();
  232. #else
  233. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, 1);
  234. return fUI->getHeight();
  235. #endif
  236. }
  237. bool isVisible() const noexcept
  238. {
  239. #ifdef HAVE_DGL
  240. return glWindow.isVisible();
  241. #else
  242. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false);
  243. return fUI->isRunning();
  244. #endif
  245. }
  246. // -------------------------------------------------------------------
  247. intptr_t getWindowId() const noexcept
  248. {
  249. #ifdef HAVE_DGL
  250. return glWindow.getWindowId();
  251. #else
  252. return 0;
  253. #endif
  254. }
  255. // -------------------------------------------------------------------
  256. uint32_t getParameterOffset() const noexcept
  257. {
  258. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr, 0);
  259. return fData->parameterOffset;
  260. }
  261. // -------------------------------------------------------------------
  262. void parameterChanged(const uint32_t index, const float value)
  263. {
  264. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  265. fUI->parameterChanged(index, value);
  266. }
  267. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  268. void programLoaded(const uint32_t index)
  269. {
  270. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  271. fUI->programLoaded(index);
  272. }
  273. #endif
  274. #if DISTRHO_PLUGIN_WANT_STATE
  275. void stateChanged(const char* const key, const char* const value)
  276. {
  277. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  278. DISTRHO_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  279. DISTRHO_SAFE_ASSERT_RETURN(value != nullptr,);
  280. fUI->stateChanged(key, value);
  281. }
  282. #endif
  283. // -------------------------------------------------------------------
  284. #ifdef HAVE_DGL
  285. void exec(IdleCallback* const cb)
  286. {
  287. DISTRHO_SAFE_ASSERT_RETURN(cb != nullptr,);
  288. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  289. glWindow.addIdleCallback(cb);
  290. glWindow.setVisible(true);
  291. glApp.exec();
  292. }
  293. void exec_idle()
  294. {
  295. if (glWindow.isReady())
  296. fUI->uiIdle();
  297. }
  298. #endif
  299. bool idle()
  300. {
  301. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr, false);
  302. #ifdef HAVE_DGL
  303. glApp.idle();
  304. if (glWindow.isReady())
  305. fUI->uiIdle();
  306. return ! glApp.isQuiting();
  307. #else
  308. return fUI->isRunning();
  309. #endif
  310. }
  311. void quit()
  312. {
  313. #ifdef HAVE_DGL
  314. glWindow.close();
  315. glApp.quit();
  316. #else
  317. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  318. fUI->terminateAndWaitForProcess();
  319. #endif
  320. }
  321. // -------------------------------------------------------------------
  322. void setWindowTitle(const char* const uiTitle)
  323. {
  324. #ifdef HAVE_DGL
  325. glWindow.setTitle(uiTitle);
  326. #else
  327. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  328. fUI->setTitle(uiTitle);
  329. #endif
  330. }
  331. #ifdef HAVE_DGL
  332. void setWindowSize(const uint width, const uint height, const bool updateUI = false)
  333. {
  334. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  335. DISTRHO_SAFE_ASSERT_RETURN(! fChangingSize,);
  336. fChangingSize = true;
  337. if (updateUI)
  338. fUI->setSize(width, height);
  339. glWindow.setSize(width, height);
  340. fChangingSize = false;
  341. }
  342. void setWindowTransientWinId(const uintptr_t winId)
  343. {
  344. glWindow.setTransientWinId(winId);
  345. }
  346. bool setWindowVisible(const bool yesNo)
  347. {
  348. glWindow.setVisible(yesNo);
  349. return ! glApp.isQuiting();
  350. }
  351. bool handlePluginKeyboard(const bool press, const uint key)
  352. {
  353. return glWindow.handlePluginKeyboard(press, key);
  354. }
  355. bool handlePluginSpecial(const bool press, const Key key)
  356. {
  357. return glWindow.handlePluginKeyboard(press, key);
  358. }
  359. #else
  360. void setWindowSize(const uint width, const uint height, const bool updateUI = false) {}
  361. void setWindowTransientWinId(const uintptr_t winId) {}
  362. bool setWindowVisible(const bool yesNo) { return true; }
  363. #endif
  364. // -------------------------------------------------------------------
  365. void setSampleRate(const double sampleRate, const bool doCallback = false)
  366. {
  367. DISTRHO_SAFE_ASSERT_RETURN(fData != nullptr,);
  368. DISTRHO_SAFE_ASSERT_RETURN(fUI != nullptr,);
  369. DISTRHO_SAFE_ASSERT(sampleRate > 0.0);
  370. if (d_isEqual(fData->sampleRate, sampleRate))
  371. return;
  372. fData->sampleRate = sampleRate;
  373. if (doCallback)
  374. fUI->sampleRateChanged(sampleRate);
  375. }
  376. private:
  377. #ifdef HAVE_DGL
  378. // -------------------------------------------------------------------
  379. // DGL Application and Window for this widget
  380. Application glApp;
  381. UIExporterWindow glWindow;
  382. // prevent recursion
  383. bool fChangingSize;
  384. #endif
  385. // -------------------------------------------------------------------
  386. // Widget and DistrhoUI data
  387. UI* const fUI;
  388. UI::PrivateData* const fData;
  389. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(UIExporter)
  390. };
  391. // -----------------------------------------------------------------------
  392. END_NAMESPACE_DISTRHO
  393. #endif // DISTRHO_UI_INTERNAL_HPP_INCLUDED