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.

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