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.

698 lines
22KB

  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. #define DISTRHO_UI_IS_STANDALONE false
  17. #include "DistrhoUIInternal.hpp"
  18. #include "../extra/String.hpp"
  19. #include "lv2/atom.h"
  20. #include "lv2/atom-util.h"
  21. #include "lv2/data-access.h"
  22. #include "lv2/instance-access.h"
  23. #include "lv2/midi.h"
  24. #include "lv2/options.h"
  25. #include "lv2/parameters.h"
  26. #include "lv2/patch.h"
  27. #include "lv2/ui.h"
  28. #include "lv2/urid.h"
  29. #include "lv2/lv2_kxstudio_properties.h"
  30. #include "lv2/lv2_programs.h"
  31. #ifndef DISTRHO_PLUGIN_LV2_STATE_PREFIX
  32. # define DISTRHO_PLUGIN_LV2_STATE_PREFIX "urn:distrho:"
  33. #endif
  34. START_NAMESPACE_DISTRHO
  35. typedef struct _LV2_Atom_MidiEvent {
  36. LV2_Atom atom; /**< Atom header. */
  37. uint8_t data[3]; /**< MIDI data (body). */
  38. } LV2_Atom_MidiEvent;
  39. #if ! DISTRHO_PLUGIN_WANT_MIDI_INPUT
  40. static const sendNoteFunc sendNoteCallback = nullptr;
  41. #endif
  42. // -----------------------------------------------------------------------
  43. template <class LV2F>
  44. static const LV2F* getLv2Feature(const LV2_Feature* const* features, const char* const uri)
  45. {
  46. for (int i=0; features[i] != nullptr; ++i)
  47. {
  48. if (std::strcmp(features[i]->URI, uri) == 0)
  49. return (const LV2F*)features[i]->data;
  50. }
  51. return nullptr;
  52. }
  53. class UiLv2
  54. {
  55. public:
  56. UiLv2(const char* const bundlePath,
  57. const intptr_t winId,
  58. const LV2_Options_Option* options,
  59. const LV2_URID_Map* const uridMap,
  60. const LV2_Feature* const* const features,
  61. const LV2UI_Controller controller,
  62. const LV2UI_Write_Function writeFunc,
  63. LV2UI_Widget* const widget,
  64. void* const dspPtr,
  65. const float scaleFactor,
  66. const uint32_t bgColor,
  67. const uint32_t fgColor)
  68. : fUI(this, winId,
  69. editParameterCallback,
  70. setParameterCallback,
  71. setStateCallback,
  72. sendNoteCallback,
  73. setSizeCallback,
  74. fileRequestCallback,
  75. bundlePath,
  76. dspPtr,
  77. scaleFactor,
  78. bgColor,
  79. fgColor),
  80. fUridMap(uridMap),
  81. fUiRequestValue(getLv2Feature<LV2UI_Request_Value>(features, LV2_UI__requestValue)),
  82. fUiResize(getLv2Feature<LV2UI_Resize>(features, LV2_UI__resize)),
  83. fUiTouch(getLv2Feature<LV2UI_Touch>(features, LV2_UI__touch)),
  84. fController(controller),
  85. fWriteFunction(writeFunc),
  86. fURIDs(uridMap),
  87. fWinIdWasNull(winId == 0)
  88. {
  89. if (fUiResize != nullptr && winId != 0)
  90. fUiResize->ui_resize(fUiResize->handle, fUI.getWidth(), fUI.getHeight());
  91. if (widget != nullptr)
  92. *widget = (LV2UI_Widget)fUI.getNativeWindowHandle();
  93. #if DISTRHO_PLUGIN_WANT_STATE
  94. // tell the DSP we're ready to receive msgs
  95. setState("__dpf_ui_data__", "");
  96. #endif
  97. if (winId != 0)
  98. return;
  99. // if winId == 0 then options must not be null
  100. DISTRHO_SAFE_ASSERT_RETURN(options != nullptr,);
  101. const LV2_URID uridWindowTitle = uridMap->map(uridMap->handle, LV2_UI__windowTitle);
  102. const LV2_URID uridTransientWinId = uridMap->map(uridMap->handle, LV2_KXSTUDIO_PROPERTIES__TransientWindowId);
  103. bool hasTitle = false;
  104. for (int i=0; options[i].key != 0; ++i)
  105. {
  106. if (options[i].key == uridTransientWinId)
  107. {
  108. if (options[i].type == fURIDs.atomLong)
  109. {
  110. if (const int64_t transientWinId = *(const int64_t*)options[i].value)
  111. fUI.setWindowTransientWinId(static_cast<intptr_t>(transientWinId));
  112. }
  113. else
  114. d_stderr("Host provides transientWinId but has wrong value type");
  115. }
  116. else if (options[i].key == uridWindowTitle)
  117. {
  118. if (options[i].type == fURIDs.atomString)
  119. {
  120. if (const char* const windowTitle = (const char*)options[i].value)
  121. {
  122. hasTitle = true;
  123. fUI.setWindowTitle(windowTitle);
  124. }
  125. }
  126. else
  127. d_stderr("Host provides windowTitle but has wrong value type");
  128. }
  129. }
  130. if (! hasTitle)
  131. fUI.setWindowTitle(DISTRHO_PLUGIN_NAME);
  132. }
  133. // -------------------------------------------------------------------
  134. void lv2ui_port_event(const uint32_t rindex, const uint32_t bufferSize, const uint32_t format, const void* const buffer)
  135. {
  136. if (format == 0)
  137. {
  138. const uint32_t parameterOffset = fUI.getParameterOffset();
  139. if (rindex < parameterOffset)
  140. return;
  141. DISTRHO_SAFE_ASSERT_RETURN(bufferSize == sizeof(float),)
  142. const float value = *(const float*)buffer;
  143. fUI.parameterChanged(rindex-parameterOffset, value);
  144. }
  145. #if DISTRHO_PLUGIN_WANT_STATE
  146. else if (format == fURIDs.atomEventTransfer)
  147. {
  148. const LV2_Atom* const atom = (const LV2_Atom*)buffer;
  149. if (atom->type == fURIDs.dpfKeyValue)
  150. {
  151. const char* const key = (const char*)LV2_ATOM_BODY_CONST(atom);
  152. const char* const value = key+(std::strlen(key)+1);
  153. fUI.stateChanged(key, value);
  154. }
  155. else
  156. {
  157. d_stdout("received atom not dpfKeyValue");
  158. }
  159. }
  160. #endif
  161. }
  162. // -------------------------------------------------------------------
  163. int lv2ui_idle()
  164. {
  165. if (fWinIdWasNull)
  166. return (fUI.idle() && fUI.isVisible()) ? 0 : 1;
  167. return fUI.idle() ? 0 : 1;
  168. }
  169. int lv2ui_show()
  170. {
  171. return fUI.setWindowVisible(true) ? 0 : 1;
  172. }
  173. int lv2ui_hide()
  174. {
  175. return fUI.setWindowVisible(false) ? 0 : 1;
  176. }
  177. int lv2ui_resize(uint width, uint height)
  178. {
  179. fUI.setWindowSize(width, height, true);
  180. return 0;
  181. }
  182. // -------------------------------------------------------------------
  183. uint32_t lv2_get_options(LV2_Options_Option* const /*options*/)
  184. {
  185. // currently unused
  186. return LV2_OPTIONS_ERR_UNKNOWN;
  187. }
  188. uint32_t lv2_set_options(const LV2_Options_Option* const options)
  189. {
  190. for (int i=0; options[i].key != 0; ++i)
  191. {
  192. if (options[i].key == fURIDs.paramSampleRate)
  193. {
  194. if (options[i].type == fURIDs.atomFloat)
  195. {
  196. const float sampleRate = *(const float*)options[i].value;
  197. fUI.setSampleRate(sampleRate);
  198. continue;
  199. }
  200. else
  201. {
  202. d_stderr("Host changed UI sample-rate but with wrong value type");
  203. continue;
  204. }
  205. }
  206. }
  207. return LV2_OPTIONS_SUCCESS;
  208. }
  209. // -------------------------------------------------------------------
  210. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  211. void lv2ui_select_program(const uint32_t bank, const uint32_t program)
  212. {
  213. const uint32_t realProgram = bank * 128 + program;
  214. fUI.programLoaded(realProgram);
  215. }
  216. #endif
  217. // -------------------------------------------------------------------
  218. protected:
  219. void editParameterValue(const uint32_t rindex, const bool started)
  220. {
  221. if (fUiTouch != nullptr && fUiTouch->touch != nullptr)
  222. fUiTouch->touch(fUiTouch->handle, rindex, started);
  223. }
  224. void setParameterValue(const uint32_t rindex, const float value)
  225. {
  226. DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,);
  227. fWriteFunction(fController, rindex, sizeof(float), 0, &value);
  228. }
  229. void setState(const char* const key, const char* const value)
  230. {
  231. DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,);
  232. const uint32_t eventInPortIndex = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
  233. // join key and value
  234. String tmpStr;
  235. tmpStr += key;
  236. tmpStr += "\xff";
  237. tmpStr += value;
  238. tmpStr[std::strlen(key)] = '\0';
  239. // set msg size (key + separator + value + null terminator)
  240. const size_t msgSize = tmpStr.length() + 1U;
  241. // reserve atom space
  242. const size_t atomSize = sizeof(LV2_Atom) + msgSize;
  243. char* const atomBuf = (char*)malloc(atomSize);
  244. std::memset(atomBuf, 0, atomSize);
  245. // set atom info
  246. LV2_Atom* const atom = (LV2_Atom*)atomBuf;
  247. atom->size = msgSize;
  248. atom->type = fURIDs.dpfKeyValue;
  249. // set atom data
  250. std::memcpy(atomBuf + sizeof(LV2_Atom), tmpStr.buffer(), msgSize);
  251. // send to DSP side
  252. fWriteFunction(fController, eventInPortIndex, atomSize, fURIDs.atomEventTransfer, atom);
  253. // free atom space
  254. free(atomBuf);
  255. }
  256. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  257. void sendNote(const uint8_t channel, const uint8_t note, const uint8_t velocity)
  258. {
  259. DISTRHO_SAFE_ASSERT_RETURN(fWriteFunction != nullptr,);
  260. if (channel > 0xF)
  261. return;
  262. const uint32_t eventInPortIndex = DISTRHO_PLUGIN_NUM_INPUTS + DISTRHO_PLUGIN_NUM_OUTPUTS;
  263. LV2_Atom_MidiEvent atomMidiEvent;
  264. atomMidiEvent.atom.size = 3;
  265. atomMidiEvent.atom.type = fURIDs.midiEvent;
  266. atomMidiEvent.data[0] = channel + (velocity != 0 ? 0x90 : 0x80);
  267. atomMidiEvent.data[1] = note;
  268. atomMidiEvent.data[2] = velocity;
  269. // send to DSP side
  270. fWriteFunction(fController, eventInPortIndex, lv2_atom_total_size(&atomMidiEvent.atom),
  271. fURIDs.atomEventTransfer, &atomMidiEvent);
  272. }
  273. #endif
  274. void setSize(const uint width, const uint height)
  275. {
  276. fUI.setWindowSize(width, height);
  277. if (fUiResize != nullptr && ! fWinIdWasNull)
  278. fUiResize->ui_resize(fUiResize->handle, width, height);
  279. }
  280. bool fileRequest(const char* const key)
  281. {
  282. d_stdout("UI file request %s %p", key, fUiRequestValue);
  283. if (fUiRequestValue == nullptr)
  284. return false;
  285. String dpf_lv2_key(DISTRHO_PLUGIN_URI "#");
  286. dpf_lv2_key += key;
  287. const int r = fUiRequestValue->request(fUiRequestValue->handle,
  288. fUridMap->map(fUridMap->handle, dpf_lv2_key.buffer()),
  289. fURIDs.atomPath,
  290. nullptr);
  291. d_stdout("UI file request %s %p => %s %i", key, fUiRequestValue, dpf_lv2_key.buffer(), r);
  292. return r == LV2UI_REQUEST_VALUE_SUCCESS;
  293. }
  294. private:
  295. UIExporter fUI;
  296. // LV2 features
  297. const LV2_URID_Map* const fUridMap;
  298. const LV2UI_Request_Value* const fUiRequestValue;
  299. const LV2UI_Resize* const fUiResize;
  300. const LV2UI_Touch* const fUiTouch;
  301. // LV2 UI stuff
  302. const LV2UI_Controller fController;
  303. const LV2UI_Write_Function fWriteFunction;
  304. // LV2 URIDs
  305. const struct URIDs {
  306. const LV2_URID_Map* _uridMap;
  307. LV2_URID dpfKeyValue;
  308. LV2_URID atomEventTransfer;
  309. LV2_URID atomFloat;
  310. LV2_URID atomLong;
  311. LV2_URID atomPath;
  312. LV2_URID atomString;
  313. LV2_URID midiEvent;
  314. LV2_URID paramSampleRate;
  315. LV2_URID patchSet;
  316. URIDs(const LV2_URID_Map* const uridMap)
  317. : _uridMap(uridMap),
  318. dpfKeyValue(map(DISTRHO_PLUGIN_LV2_STATE_PREFIX "KeyValueState")),
  319. atomEventTransfer(map(LV2_ATOM__eventTransfer)),
  320. atomFloat(map(LV2_ATOM__Float)),
  321. atomLong(map(LV2_ATOM__Long)),
  322. atomPath(map(LV2_ATOM__Path)),
  323. atomString(map(LV2_ATOM__String)),
  324. midiEvent(map(LV2_MIDI__MidiEvent)),
  325. paramSampleRate(map(LV2_PARAMETERS__sampleRate)),
  326. patchSet(map(LV2_PATCH__Set)) {}
  327. inline LV2_URID map(const char* const uri) const
  328. {
  329. return _uridMap->map(_uridMap->handle, uri);
  330. }
  331. } fURIDs;
  332. // using ui:showInterface if true
  333. bool fWinIdWasNull;
  334. // -------------------------------------------------------------------
  335. // Callbacks
  336. #define uiPtr ((UiLv2*)ptr)
  337. static void editParameterCallback(void* ptr, uint32_t rindex, bool started)
  338. {
  339. uiPtr->editParameterValue(rindex, started);
  340. }
  341. static void setParameterCallback(void* ptr, uint32_t rindex, float value)
  342. {
  343. uiPtr->setParameterValue(rindex, value);
  344. }
  345. static void setStateCallback(void* ptr, const char* key, const char* value)
  346. {
  347. uiPtr->setState(key, value);
  348. }
  349. #if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  350. static void sendNoteCallback(void* ptr, uint8_t channel, uint8_t note, uint8_t velocity)
  351. {
  352. uiPtr->sendNote(channel, note, velocity);
  353. }
  354. #endif
  355. static void setSizeCallback(void* ptr, uint width, uint height)
  356. {
  357. uiPtr->setSize(width, height);
  358. }
  359. static bool fileRequestCallback(void* ptr, const char* key)
  360. {
  361. return uiPtr->fileRequest(key);
  362. }
  363. #undef uiPtr
  364. };
  365. // -----------------------------------------------------------------------
  366. static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*,
  367. const char* const uri,
  368. const char* const bundlePath,
  369. const LV2UI_Write_Function writeFunction,
  370. const LV2UI_Controller controller,
  371. LV2UI_Widget* const widget,
  372. const LV2_Feature* const* const features)
  373. {
  374. if (uri == nullptr || std::strcmp(uri, DISTRHO_PLUGIN_URI) != 0)
  375. {
  376. d_stderr("Invalid plugin URI");
  377. return nullptr;
  378. }
  379. const LV2_Options_Option* options = nullptr;
  380. const LV2_URID_Map* uridMap = nullptr;
  381. void* parentId = nullptr;
  382. void* instance = nullptr;
  383. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  384. struct LV2_DirectAccess_Interface {
  385. void* (*get_instance_pointer)(LV2_Handle handle);
  386. };
  387. const LV2_Extension_Data_Feature* extData = nullptr;
  388. #endif
  389. for (int i=0; features[i] != nullptr; ++i)
  390. {
  391. /**/ if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
  392. options = (const LV2_Options_Option*)features[i]->data;
  393. else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
  394. uridMap = (const LV2_URID_Map*)features[i]->data;
  395. else if (std::strcmp(features[i]->URI, LV2_UI__parent) == 0)
  396. parentId = features[i]->data;
  397. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  398. else if (std::strcmp(features[i]->URI, LV2_DATA_ACCESS_URI) == 0)
  399. extData = (const LV2_Extension_Data_Feature*)features[i]->data;
  400. else if (std::strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0)
  401. instance = features[i]->data;
  402. #endif
  403. }
  404. if (options == nullptr && parentId == nullptr)
  405. {
  406. d_stderr("Options feature missing (needed for show-interface), cannot continue!");
  407. return nullptr;
  408. }
  409. if (uridMap == nullptr)
  410. {
  411. d_stderr("URID Map feature missing, cannot continue!");
  412. return nullptr;
  413. }
  414. if (parentId == nullptr)
  415. {
  416. d_stdout("Parent Window Id missing, host should be using ui:showInterface...");
  417. }
  418. #if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  419. if (extData == nullptr || instance == nullptr)
  420. {
  421. d_stderr("Data or instance access missing, cannot continue!");
  422. return nullptr;
  423. }
  424. if (const LV2_DirectAccess_Interface* const directAccess = (const LV2_DirectAccess_Interface*)extData->data_access(DISTRHO_PLUGIN_LV2_STATE_PREFIX "direct-access"))
  425. instance = directAccess->get_instance_pointer(instance);
  426. else
  427. instance = nullptr;
  428. if (instance == nullptr)
  429. {
  430. d_stderr("Failed to get direct access, cannot continue!");
  431. return nullptr;
  432. }
  433. #endif
  434. const intptr_t winId = (intptr_t)parentId;
  435. float scaleFactor = 1.0f;
  436. uint32_t bgColor = 0;
  437. uint32_t fgColor = 0xffffffff;
  438. if (options != nullptr)
  439. {
  440. const LV2_URID uridAtomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int);
  441. const LV2_URID uridAtomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float);
  442. const LV2_URID uridSampleRate = uridMap->map(uridMap->handle, LV2_PARAMETERS__sampleRate);
  443. const LV2_URID uridBgColor = uridMap->map(uridMap->handle, LV2_UI__backgroundColor);
  444. const LV2_URID uridFgColor = uridMap->map(uridMap->handle, LV2_UI__foregroundColor);
  445. const LV2_URID uridScaleFactor = uridMap->map(uridMap->handle, LV2_UI__scaleFactor);
  446. for (int i=0; options[i].key != 0; ++i)
  447. {
  448. /**/ if (options[i].key == uridSampleRate)
  449. {
  450. if (options[i].type == uridAtomFloat)
  451. d_lastUiSampleRate = *(const float*)options[i].value;
  452. else
  453. d_stderr("Host provides UI sample-rate but has wrong value type");
  454. }
  455. else if (options[i].key == uridScaleFactor)
  456. {
  457. if (options[i].type == uridAtomFloat)
  458. scaleFactor = *(const float*)options[i].value;
  459. else
  460. d_stderr("Host provides UI scale factor but has wrong value type");
  461. }
  462. else if (options[i].key == uridBgColor)
  463. {
  464. if (options[i].type == uridAtomInt)
  465. bgColor = (uint32_t)*(const int32_t*)options[i].value;
  466. else
  467. d_stderr("Host provides UI background color but has wrong value type");
  468. }
  469. else if (options[i].key == uridFgColor)
  470. {
  471. if (options[i].type == uridAtomInt)
  472. fgColor = (uint32_t)*(const int32_t*)options[i].value;
  473. else
  474. d_stderr("Host provides UI foreground color but has wrong value type");
  475. }
  476. }
  477. }
  478. if (d_lastUiSampleRate < 1.0)
  479. {
  480. d_stdout("WARNING: this host does not send sample-rate information for LV2 UIs, using 44100 as fallback (this could be wrong)");
  481. d_lastUiSampleRate = 44100.0;
  482. }
  483. return new UiLv2(bundlePath, winId, options, uridMap, features,
  484. controller, writeFunction, widget, instance,
  485. scaleFactor, bgColor, fgColor);
  486. }
  487. #define uiPtr ((UiLv2*)ui)
  488. static void lv2ui_cleanup(LV2UI_Handle ui)
  489. {
  490. delete uiPtr;
  491. }
  492. static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
  493. {
  494. uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer);
  495. }
  496. // -----------------------------------------------------------------------
  497. static int lv2ui_idle(LV2UI_Handle ui)
  498. {
  499. return uiPtr->lv2ui_idle();
  500. }
  501. static int lv2ui_show(LV2UI_Handle ui)
  502. {
  503. return uiPtr->lv2ui_show();
  504. }
  505. static int lv2ui_hide(LV2UI_Handle ui)
  506. {
  507. return uiPtr->lv2ui_hide();
  508. }
  509. static int lv2ui_resize(LV2UI_Handle ui, int width, int height)
  510. {
  511. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr, 1);
  512. DISTRHO_SAFE_ASSERT_RETURN(width > 0, 1);
  513. DISTRHO_SAFE_ASSERT_RETURN(height > 0, 1);
  514. return 1; // This needs more testing
  515. //return uiPtr->lv2ui_resize(width, height);
  516. }
  517. // -----------------------------------------------------------------------
  518. static uint32_t lv2_get_options(LV2UI_Handle ui, LV2_Options_Option* options)
  519. {
  520. return uiPtr->lv2_get_options(options);
  521. }
  522. static uint32_t lv2_set_options(LV2UI_Handle ui, const LV2_Options_Option* options)
  523. {
  524. return uiPtr->lv2_set_options(options);
  525. }
  526. // -----------------------------------------------------------------------
  527. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  528. static void lv2ui_select_program(LV2UI_Handle ui, uint32_t bank, uint32_t program)
  529. {
  530. uiPtr->lv2ui_select_program(bank, program);
  531. }
  532. #endif
  533. // -----------------------------------------------------------------------
  534. static const void* lv2ui_extension_data(const char* uri)
  535. {
  536. static const LV2_Options_Interface options = { lv2_get_options, lv2_set_options };
  537. static const LV2UI_Idle_Interface uiIdle = { lv2ui_idle };
  538. static const LV2UI_Show_Interface uiShow = { lv2ui_show, lv2ui_hide };
  539. static const LV2UI_Resize uiResz = { nullptr, lv2ui_resize };
  540. if (std::strcmp(uri, LV2_OPTIONS__interface) == 0)
  541. return &options;
  542. if (std::strcmp(uri, LV2_UI__idleInterface) == 0)
  543. return &uiIdle;
  544. if (std::strcmp(uri, LV2_UI__showInterface) == 0)
  545. return &uiShow;
  546. if (std::strcmp(uri, LV2_UI__resize) == 0)
  547. return &uiResz;
  548. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  549. static const LV2_Programs_UI_Interface uiPrograms = { lv2ui_select_program };
  550. if (std::strcmp(uri, LV2_PROGRAMS__UIInterface) == 0)
  551. return &uiPrograms;
  552. #endif
  553. return nullptr;
  554. }
  555. #undef instancePtr
  556. // -----------------------------------------------------------------------
  557. static const LV2UI_Descriptor sLv2UiDescriptor = {
  558. DISTRHO_UI_URI,
  559. lv2ui_instantiate,
  560. lv2ui_cleanup,
  561. lv2ui_port_event,
  562. lv2ui_extension_data
  563. };
  564. // -----------------------------------------------------------------------
  565. END_NAMESPACE_DISTRHO
  566. DISTRHO_PLUGIN_EXPORT
  567. const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
  568. {
  569. USE_NAMESPACE_DISTRHO
  570. return (index == 0) ? &sLv2UiDescriptor : nullptr;
  571. }
  572. // -----------------------------------------------------------------------