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.

580 lines
15KB

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