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.

694 lines
22KB

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