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.

760 lines
24KB

  1. /*
  2. * DISTRHO Ildaeil Plugin
  3. * Copyright (C) 2021 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the LICENSE file.
  16. */
  17. #include "CarlaNativePlugin.h"
  18. #include "DistrhoUI.hpp"
  19. #include "DistrhoPlugin.hpp"
  20. #include "PluginHostWindow.hpp"
  21. #include "extra/Thread.hpp"
  22. // IDE helper
  23. #include "DearImGui.hpp"
  24. #include <vector>
  25. START_NAMESPACE_DISTRHO
  26. // --------------------------------------------------------------------------------------------------------------------
  27. class IldaeilPlugin : public Plugin
  28. {
  29. public:
  30. const NativePluginDescriptor* fCarlaPluginDescriptor;
  31. NativePluginHandle fCarlaPluginHandle;
  32. NativeHostDescriptor fCarlaHostDescriptor;
  33. CarlaHostHandle fCarlaHostHandle;
  34. void* fUI;
  35. // ...
  36. };
  37. // --------------------------------------------------------------------------------------------------------------------
  38. void ildaeilParameterChangeForUI(void* ui, uint32_t index, float value);
  39. // --------------------------------------------------------------------------------------------------------------------
  40. using namespace CarlaBackend;
  41. // shared resource pointer
  42. // carla_juce_init();
  43. class IldaeilUI : public UI,
  44. public Thread,
  45. public PluginHostWindow::Callbacks
  46. {
  47. static constexpr const uint kInitialWidth = 1220;
  48. static constexpr const uint kInitialHeight = 640;
  49. static constexpr const uint kGenericWidth = 300;
  50. static constexpr const uint kGenericHeight = 400;
  51. static constexpr const uint kExtraHeight = 35;
  52. enum {
  53. kDrawingInit,
  54. kDrawingError,
  55. kDrawingLoading,
  56. kDrawingPluginList,
  57. kDrawingPluginEmbedUI,
  58. kDrawingPluginGenericUI,
  59. kDrawingPluginPendingFromInit
  60. } fDrawingState;
  61. struct PluginInfoCache {
  62. char* name;
  63. char* label;
  64. PluginInfoCache()
  65. : name(nullptr),
  66. label(nullptr) {}
  67. ~PluginInfoCache()
  68. {
  69. std::free(name);
  70. std::free(label);
  71. }
  72. };
  73. struct PluginGenericUI {
  74. char* title;
  75. uint parameterCount;
  76. struct Parameter {
  77. char* name;
  78. char* format;
  79. uint32_t rindex;
  80. bool boolean, bvalue;
  81. float min, max;
  82. Parameter()
  83. : name(nullptr),
  84. format(nullptr),
  85. rindex(0),
  86. boolean(false),
  87. bvalue(false),
  88. min(0.0f),
  89. max(1.0f) {}
  90. ~Parameter()
  91. {
  92. std::free(name);
  93. std::free(format);
  94. }
  95. }* parameters;
  96. float* values;
  97. PluginGenericUI()
  98. : title(nullptr),
  99. parameterCount(0),
  100. parameters(nullptr),
  101. values(nullptr) {}
  102. ~PluginGenericUI()
  103. {
  104. std::free(title);
  105. delete[] parameters;
  106. delete[] values;
  107. }
  108. };
  109. IldaeilPlugin* const fPlugin;
  110. PluginHostWindow fPluginHostWindow;
  111. uint fPluginCount;
  112. uint fPluginSelected;
  113. bool fPluginScanningFinished;
  114. bool fPluginHasCustomUI;
  115. bool fPluginHasEmbedUI;
  116. PluginInfoCache* fPlugins;
  117. ScopedPointer<PluginGenericUI> fPluginGenericUI;
  118. bool fPluginSearchActive;
  119. char fPluginSearchString[0xff];
  120. public:
  121. IldaeilUI()
  122. : UI(kInitialWidth, kInitialHeight),
  123. Thread("IldaeilScanner"),
  124. fDrawingState(kDrawingInit),
  125. fPlugin((IldaeilPlugin*)getPluginInstancePointer()),
  126. fPluginHostWindow(getWindow(), this),
  127. fPluginCount(0),
  128. fPluginSelected(0),
  129. fPluginScanningFinished(false),
  130. fPluginHasCustomUI(false),
  131. fPluginHasEmbedUI(false),
  132. fPlugins(nullptr),
  133. fPluginSearchActive(false)
  134. {
  135. if (fPlugin == nullptr || fPlugin->fCarlaHostHandle == nullptr)
  136. {
  137. fDrawingState = kDrawingError;
  138. return;
  139. }
  140. std::strcpy(fPluginSearchString, "Search...");
  141. const double scaleFactor = getScaleFactor();
  142. if (d_isNotEqual(scaleFactor, 1.0))
  143. {
  144. setSize(kInitialWidth * scaleFactor, kInitialHeight * scaleFactor);
  145. fPluginHostWindow.setPositionAndSize(0, kExtraHeight * scaleFactor,
  146. kInitialWidth * scaleFactor, (kInitialHeight - kExtraHeight) * scaleFactor);
  147. }
  148. else
  149. {
  150. fPluginHostWindow.setPositionAndSize(0, kExtraHeight, kInitialWidth, kInitialHeight-kExtraHeight);
  151. }
  152. const CarlaHostHandle handle = fPlugin->fCarlaHostHandle;
  153. char winIdStr[24];
  154. std::snprintf(winIdStr, sizeof(winIdStr), "%lx", (ulong)getWindow().getNativeWindowHandle());
  155. carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_WIN_ID, 0, winIdStr);
  156. carla_set_engine_option(handle, ENGINE_OPTION_FRONTEND_UI_SCALE, getScaleFactor()*1000, nullptr);
  157. if (carla_get_current_plugin_count(handle) != 0)
  158. {
  159. const uint hints = carla_get_plugin_info(handle, 0)->hints;
  160. fDrawingState = kDrawingPluginPendingFromInit;
  161. fPluginHasCustomUI = hints & PLUGIN_HAS_CUSTOM_UI;
  162. fPluginHasEmbedUI = hints & PLUGIN_HAS_CUSTOM_EMBED_UI;
  163. }
  164. fPlugin->fUI = this;
  165. }
  166. ~IldaeilUI() override
  167. {
  168. if (fPlugin != nullptr && fPlugin->fCarlaHostHandle != nullptr)
  169. {
  170. fPlugin->fUI = nullptr;
  171. carla_set_engine_option(fPlugin->fCarlaHostHandle, ENGINE_OPTION_FRONTEND_WIN_ID, 0, "0");
  172. }
  173. if (isThreadRunning())
  174. stopThread(-1);
  175. hidePluginUI();
  176. fPluginGenericUI = nullptr;
  177. delete[] fPlugins;
  178. }
  179. void changeParameterFromDSP(const uint32_t index, const float value)
  180. {
  181. if (PluginGenericUI* const ui = fPluginGenericUI)
  182. {
  183. for (uint32_t i=0; i < ui->parameterCount; ++i)
  184. {
  185. if (ui->parameters[i].rindex != index)
  186. continue;
  187. ui->values[i] = value;
  188. if (ui->parameters[i].boolean)
  189. ui->parameters[i].bvalue = value > ui->parameters[i].min;
  190. break;
  191. }
  192. }
  193. }
  194. void showPluginUI(const CarlaHostHandle handle)
  195. {
  196. const CarlaPluginInfo* const info = carla_get_plugin_info(handle, 0);
  197. if (info->hints & PLUGIN_HAS_CUSTOM_EMBED_UI)
  198. {
  199. fDrawingState = kDrawingPluginEmbedUI;
  200. fPluginHasCustomUI = true;
  201. fPluginHasEmbedUI = true;
  202. carla_embed_custom_ui(handle, 0, fPluginHostWindow.attachAndGetWindowHandle());
  203. }
  204. else
  205. {
  206. fDrawingState = kDrawingPluginGenericUI;
  207. fPluginHasCustomUI = info->hints & PLUGIN_HAS_CUSTOM_UI;
  208. fPluginHasEmbedUI = false;
  209. if (fPluginGenericUI == nullptr)
  210. createPluginGenericUI(handle, info);
  211. else
  212. updatePluginGenericUI(handle);
  213. const double scaleFactor = getScaleFactor();
  214. setSize(kGenericWidth * scaleFactor, (kGenericHeight + kExtraHeight) * scaleFactor);
  215. }
  216. repaint();
  217. }
  218. void hidePluginUI()
  219. {
  220. if (fPlugin == nullptr || fPlugin->fCarlaHostHandle == nullptr)
  221. return;
  222. if (fDrawingState == kDrawingPluginGenericUI || fDrawingState == kDrawingPluginEmbedUI)
  223. carla_show_custom_ui(fPlugin->fCarlaHostHandle, 0, false);
  224. fPluginHostWindow.hide();
  225. }
  226. void createPluginGenericUI(const CarlaHostHandle handle, const CarlaPluginInfo* const info)
  227. {
  228. PluginGenericUI* const ui = new PluginGenericUI;
  229. String title(info->name);
  230. title += " by ";
  231. title += info->maker;
  232. ui->title = title.getAndReleaseBuffer();
  233. const uint32_t pcount = ui->parameterCount = carla_get_parameter_count(handle, 0);
  234. // make count of valid parameters
  235. for (uint32_t i=0; i < pcount; ++i)
  236. {
  237. const ParameterData* const pdata = carla_get_parameter_data(handle, 0, i);
  238. if (pdata->type != PARAMETER_INPUT ||
  239. (pdata->hints & PARAMETER_IS_ENABLED) == 0x0 ||
  240. (pdata->hints & PARAMETER_IS_READ_ONLY) != 0x0)
  241. {
  242. --ui->parameterCount;
  243. continue;
  244. }
  245. }
  246. ui->parameters = new PluginGenericUI::Parameter[ui->parameterCount];
  247. ui->values = new float[ui->parameterCount];
  248. // now safely fill in details
  249. for (uint32_t i=0, j=0; i < pcount; ++i)
  250. {
  251. const ParameterData* const pdata = carla_get_parameter_data(handle, 0, i);
  252. if (pdata->type != PARAMETER_INPUT ||
  253. (pdata->hints & PARAMETER_IS_ENABLED) == 0x0 ||
  254. (pdata->hints & PARAMETER_IS_READ_ONLY) != 0x0)
  255. continue;
  256. const CarlaParameterInfo* const pinfo = carla_get_parameter_info(handle, 0, i);
  257. const ::ParameterRanges* const pranges = carla_get_parameter_ranges(handle, 0, i);
  258. String format;
  259. if (pdata->hints & PARAMETER_IS_INTEGER)
  260. format = "%.0f ";
  261. else
  262. format = "%.3f ";
  263. format += pinfo->unit;
  264. PluginGenericUI::Parameter& param(ui->parameters[j]);
  265. param.name = strdup(pinfo->name);
  266. param.format = format.getAndReleaseBuffer();
  267. param.rindex = i;
  268. param.boolean = pdata->hints & PARAMETER_IS_BOOLEAN;
  269. param.min = pranges->min;
  270. param.max = pranges->max;
  271. ui->values[j] = carla_get_current_parameter_value(handle, 0, i);
  272. if (param.boolean)
  273. param.bvalue = ui->values[j] > param.min;
  274. else
  275. param.bvalue = false;
  276. ++j;
  277. }
  278. fPluginGenericUI = ui;
  279. }
  280. void updatePluginGenericUI(const CarlaHostHandle handle)
  281. {
  282. PluginGenericUI* const ui = fPluginGenericUI;
  283. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  284. for (uint32_t i=0; i < ui->parameterCount; ++i)
  285. {
  286. ui->values[i] = carla_get_current_parameter_value(handle, 0, ui->parameters[i].rindex);
  287. if (ui->parameters[i].boolean)
  288. ui->parameters[i].bvalue = ui->values[i] > ui->parameters[i].min;
  289. }
  290. }
  291. bool loadPlugin(const CarlaHostHandle handle, const char* const label)
  292. {
  293. if (carla_get_current_plugin_count(handle) != 0)
  294. {
  295. hidePluginUI();
  296. carla_replace_plugin(handle, 0);
  297. }
  298. if (carla_add_plugin(handle, BINARY_NATIVE, PLUGIN_LV2, nullptr, nullptr,
  299. label, 0, 0x0, PLUGIN_OPTIONS_NULL))
  300. {
  301. fPluginGenericUI = nullptr;
  302. showPluginUI(handle);
  303. return true;
  304. }
  305. return false;
  306. }
  307. protected:
  308. void pluginWindowResized(uint width, uint height) override
  309. {
  310. setSize(width, height + kExtraHeight * getScaleFactor());
  311. }
  312. void uiIdle() override
  313. {
  314. switch (fDrawingState)
  315. {
  316. case kDrawingInit:
  317. fDrawingState = kDrawingLoading;
  318. startThread();
  319. repaint();
  320. break;
  321. case kDrawingPluginPendingFromInit:
  322. showPluginUI(fPlugin->fCarlaHostHandle);
  323. startThread();
  324. break;
  325. case kDrawingPluginEmbedUI:
  326. fPlugin->fCarlaPluginDescriptor->ui_idle(fPlugin->fCarlaPluginHandle);
  327. fPluginHostWindow.idle();
  328. break;
  329. case kDrawingPluginGenericUI:
  330. fPlugin->fCarlaPluginDescriptor->ui_idle(fPlugin->fCarlaPluginHandle);
  331. break;
  332. default:
  333. break;
  334. }
  335. }
  336. void run() override
  337. {
  338. if (const uint count = carla_get_cached_plugin_count(PLUGIN_LV2, nullptr))
  339. {
  340. fPluginCount = 0;
  341. fPlugins = new PluginInfoCache[count];
  342. if (fDrawingState == kDrawingLoading)
  343. fDrawingState = kDrawingPluginList;
  344. for (uint i=0, j; i < count && ! shouldThreadExit(); ++i)
  345. {
  346. const CarlaCachedPluginInfo* const info = carla_get_cached_plugin_info(PLUGIN_LV2, i);
  347. DISTRHO_SAFE_ASSERT_CONTINUE(info != nullptr);
  348. if (! info->valid)
  349. continue;
  350. #if DISTRHO_PLUGIN_IS_SYNTH
  351. if (info->midiIns != 1 || info->audioOuts != 2)
  352. continue;
  353. if ((info->hints & PLUGIN_IS_SYNTH) == 0x0)
  354. continue;
  355. #elif DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  356. if (info->midiIns != 1 || info->midiOuts != 1)
  357. continue;
  358. if (info->audioIns != 0 || info->audioOuts != 0)
  359. continue;
  360. #else
  361. if (info->audioIns != 2 || info->audioOuts != 2)
  362. continue;
  363. #endif
  364. j = fPluginCount;
  365. fPlugins[j].name = strdup(info->name);
  366. fPlugins[j].label = strdup(info->label);
  367. ++fPluginCount;
  368. }
  369. }
  370. if (! shouldThreadExit())
  371. fPluginScanningFinished = true;
  372. }
  373. void onImGuiDisplay() override
  374. {
  375. switch (fDrawingState)
  376. {
  377. case kDrawingInit:
  378. case kDrawingLoading:
  379. case kDrawingPluginPendingFromInit:
  380. drawLoading();
  381. break;
  382. case kDrawingPluginList:
  383. drawPluginList();
  384. break;
  385. case kDrawingError:
  386. // TODO display error message
  387. break;
  388. case kDrawingPluginGenericUI:
  389. drawGenericUI();
  390. // fall-through
  391. case kDrawingPluginEmbedUI:
  392. drawTopBar();
  393. break;
  394. }
  395. }
  396. void drawTopBar()
  397. {
  398. ImGui::SetNextWindowPos(ImVec2(0, 0));
  399. ImGui::SetNextWindowSize(ImVec2(getWidth(), kExtraHeight * getScaleFactor()));
  400. if (ImGui::Begin("Current Plugin", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize))
  401. {
  402. const CarlaHostHandle handle = fPlugin->fCarlaHostHandle;
  403. if (ImGui::Button("Pick Another..."))
  404. {
  405. hidePluginUI();
  406. fDrawingState = kDrawingPluginList;
  407. const double scaleFactor = getScaleFactor();
  408. setSize(kInitialWidth * scaleFactor, kInitialHeight * scaleFactor);
  409. }
  410. ImGui::SameLine();
  411. if (ImGui::Button("Reset"))
  412. {
  413. loadPlugin(handle, carla_get_plugin_info(handle, 0)->label);
  414. }
  415. if (fDrawingState == kDrawingPluginGenericUI && fPluginHasCustomUI)
  416. {
  417. ImGui::SameLine();
  418. if (ImGui::Button("Show Custom GUI"))
  419. {
  420. if (fPluginHasEmbedUI)
  421. {
  422. fDrawingState = kDrawingPluginEmbedUI;
  423. carla_embed_custom_ui(handle, 0, fPluginHostWindow.attachAndGetWindowHandle());
  424. }
  425. else
  426. {
  427. carla_show_custom_ui(handle, 0, true);
  428. }
  429. }
  430. }
  431. if (fDrawingState == kDrawingPluginEmbedUI)
  432. {
  433. ImGui::SameLine();
  434. if (ImGui::Button("Show Generic GUI"))
  435. {
  436. hidePluginUI();
  437. fDrawingState = kDrawingPluginGenericUI;
  438. if (fPluginGenericUI == nullptr)
  439. createPluginGenericUI(handle, carla_get_plugin_info(handle, 0));
  440. else
  441. updatePluginGenericUI(handle);
  442. const double scaleFactor = getScaleFactor();
  443. setSize(std::max(getWidth(), static_cast<uint>(kGenericWidth * scaleFactor + 0.5)),
  444. (kGenericHeight + kExtraHeight) * scaleFactor);
  445. }
  446. }
  447. }
  448. ImGui::End();
  449. }
  450. void setupMainWindowPos()
  451. {
  452. float y = 0;
  453. float height = getHeight();
  454. if (fDrawingState == kDrawingPluginGenericUI)
  455. {
  456. y = (kExtraHeight - 1) * getScaleFactor();
  457. height -= y;
  458. }
  459. ImGui::SetNextWindowPos(ImVec2(0, y));
  460. ImGui::SetNextWindowSize(ImVec2(getWidth(), height));
  461. }
  462. void drawGenericUI()
  463. {
  464. setupMainWindowPos();
  465. PluginGenericUI* const ui = fPluginGenericUI;
  466. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  467. if (ImGui::Begin(ui->title, nullptr, ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoCollapse))
  468. {
  469. const CarlaHostHandle handle = fPlugin->fCarlaHostHandle;
  470. for (uint32_t i=0; i < ui->parameterCount; ++i)
  471. {
  472. PluginGenericUI::Parameter& param(ui->parameters[i]);
  473. if (param.boolean)
  474. {
  475. if (ImGui::Checkbox(param.name, &ui->parameters[i].bvalue))
  476. {
  477. if (ImGui::IsItemActivated())
  478. {
  479. carla_set_parameter_touch(handle, 0, param.rindex, true);
  480. // editParameter(0, true);
  481. }
  482. ui->values[i] = ui->parameters[i].bvalue ? ui->parameters[i].max : ui->parameters[i].min;
  483. carla_set_parameter_value(handle, 0, param.rindex, ui->values[i]);
  484. // setParameterValue(0, ui->values[i]);
  485. }
  486. }
  487. else
  488. {
  489. if (ImGui::SliderFloat(param.name, &ui->values[i], param.min, param.max, param.format))
  490. {
  491. if (ImGui::IsItemActivated())
  492. {
  493. carla_set_parameter_touch(handle, 0, param.rindex, true);
  494. // editParameter(0, true);
  495. }
  496. carla_set_parameter_value(handle, 0, param.rindex, ui->values[i]);
  497. // setParameterValue(0, ui->values[i]);
  498. }
  499. }
  500. if (ImGui::IsItemDeactivated())
  501. {
  502. carla_set_parameter_touch(handle, 0, param.rindex, false);
  503. // editParameter(0, false);
  504. }
  505. }
  506. }
  507. ImGui::End();
  508. }
  509. void drawLoading()
  510. {
  511. setupMainWindowPos();
  512. if (ImGui::Begin("Plugin List", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize))
  513. {
  514. ImGui::TextUnformatted("Loading...", nullptr);
  515. }
  516. ImGui::End();
  517. }
  518. void drawPluginList()
  519. {
  520. setupMainWindowPos();
  521. const CarlaHostHandle handle = fPlugin->fCarlaHostHandle;
  522. if (ImGui::Begin("Plugin List", nullptr, ImGuiWindowFlags_NoTitleBar|ImGuiWindowFlags_NoResize))
  523. {
  524. if (ImGui::InputText("", fPluginSearchString, sizeof(fPluginSearchString)-1, ImGuiInputTextFlags_CharsNoBlank|ImGuiInputTextFlags_AutoSelectAll))
  525. fPluginSearchActive = true;
  526. ImGui::BeginDisabled(!fPluginScanningFinished);
  527. if (ImGui::Button("Load Plugin"))
  528. {
  529. do {
  530. const PluginInfoCache& info(fPlugins[fPluginSelected]);
  531. const char* const slash = std::strchr(info.label, DISTRHO_OS_SEP);
  532. DISTRHO_SAFE_ASSERT_BREAK(slash != nullptr);
  533. d_stdout("Loading %s...", info.name);
  534. if (loadPlugin(handle, slash+1))
  535. {
  536. ImGui::EndDisabled();
  537. ImGui::End();
  538. return;
  539. }
  540. } while (false);
  541. }
  542. if (carla_get_current_plugin_count(handle) != 0)
  543. {
  544. ImGui::SameLine();
  545. if (ImGui::Button("Cancel"))
  546. {
  547. showPluginUI(handle);
  548. }
  549. }
  550. ImGui::EndDisabled();
  551. if (ImGui::BeginChild("pluginlistwindow"))
  552. {
  553. if (ImGui::BeginTable("pluginlist", 3, ImGuiTableFlags_NoSavedSettings|ImGuiTableFlags_NoClip))
  554. {
  555. ImGui::TableSetupColumn("Name");
  556. ImGui::TableSetupColumn("Bundle");
  557. ImGui::TableSetupColumn("URI");
  558. ImGui::TableHeadersRow();
  559. const char* const search = fPluginSearchActive && fPluginSearchString[0] != '\0' ? fPluginSearchString : nullptr;
  560. for (uint i=0; i<fPluginCount; ++i)
  561. {
  562. const PluginInfoCache& info(fPlugins[i]);
  563. const char* const slash = std::strchr(info.label, DISTRHO_OS_SEP);
  564. DISTRHO_SAFE_ASSERT_CONTINUE(slash != nullptr);
  565. if (search != nullptr && strcasestr(info.name, search) == nullptr)
  566. continue;
  567. bool selected = fPluginSelected == i;
  568. ImGui::TableNextRow();
  569. ImGui::TableSetColumnIndex(0);
  570. ImGui::Selectable(info.name, &selected);
  571. ImGui::TableSetColumnIndex(1);
  572. ImGui::Selectable(slash+1, &selected);
  573. ImGui::TableSetColumnIndex(2);
  574. ImGui::TextUnformatted(info.label, slash);
  575. if (selected)
  576. fPluginSelected = i;
  577. }
  578. ImGui::EndTable();
  579. }
  580. ImGui::EndChild();
  581. }
  582. }
  583. ImGui::End();
  584. }
  585. protected:
  586. /* --------------------------------------------------------------------------------------------------------
  587. * DSP/Plugin Callbacks */
  588. void parameterChanged(uint32_t, float) override
  589. {
  590. }
  591. void stateChanged(const char* const key, const char* const) override
  592. {
  593. if (std::strcmp(key, "project") == 0)
  594. hidePluginUI();
  595. }
  596. // -------------------------------------------------------------------------------------------------------
  597. private:
  598. /**
  599. Set our UI class as non-copyable and add a leak detector just in case.
  600. */
  601. DISTRHO_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(IldaeilUI)
  602. };
  603. // --------------------------------------------------------------------------------------------------------------------
  604. void ildaeilParameterChangeForUI(void* const ui, const uint32_t index, const float value)
  605. {
  606. DISTRHO_SAFE_ASSERT_RETURN(ui != nullptr,);
  607. static_cast<IldaeilUI*>(ui)->changeParameterFromDSP(index, value);
  608. }
  609. /* --------------------------------------------------------------------------------------------------------------------
  610. * UI entry point, called by DPF to create a new UI instance. */
  611. UI* createUI()
  612. {
  613. return new IldaeilUI();
  614. }
  615. // --------------------------------------------------------------------------------------------------------------------
  616. END_NAMESPACE_DISTRHO