Audio plugin host https://kx.studio/carla
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.

766 lines
21KB

  1. /*
  2. * Carla LV2 Single Plugin
  3. * Copyright (C) 2017 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 doc/GPL.txt file.
  16. */
  17. #ifndef BUILD_BRIDGE
  18. # error This file should not be compiled if not building bridge
  19. #endif
  20. #include "engine/CarlaEngineInternal.hpp"
  21. #include "CarlaPlugin.hpp"
  22. #include "CarlaBackendUtils.hpp"
  23. #include "CarlaEngineUtils.hpp"
  24. #include "CarlaLv2Utils.hpp"
  25. #include "CarlaUtils.h"
  26. #include "water/files/File.h"
  27. // ---------------------------------------------------------------------------------------------------------------------
  28. CARLA_BACKEND_START_NAMESPACE
  29. class CarlaEngineLV2Single : public CarlaEngine,
  30. public Lv2PluginBaseClass
  31. {
  32. public:
  33. CarlaEngineLV2Single(const double sampleRate,
  34. const char* const bundlePath,
  35. const LV2_Feature* const* const features)
  36. : Lv2PluginBaseClass(sampleRate, features),
  37. fPlugin(nullptr),
  38. fIsActive(false),
  39. fIsOffline(false),
  40. fPorts(),
  41. fUI()
  42. {
  43. CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount == 0,)
  44. CARLA_SAFE_ASSERT_RETURN(pData->plugins[0].plugin == nullptr,);
  45. if (! loadedInProperHost())
  46. return;
  47. // xxxxx
  48. CarlaString binaryDir(bundlePath);
  49. binaryDir += CARLA_OS_SEP_STR "bin" CARLA_OS_SEP_STR;
  50. CarlaString resourceDir(bundlePath);
  51. resourceDir += CARLA_OS_SEP_STR "res" CARLA_OS_SEP_STR;
  52. pData->bufferSize = fBufferSize;
  53. pData->sampleRate = sampleRate;
  54. pData->initTime(nullptr);
  55. pData->options.processMode = ENGINE_PROCESS_MODE_BRIDGE;
  56. pData->options.transportMode = ENGINE_TRANSPORT_MODE_PLUGIN;
  57. pData->options.forceStereo = false;
  58. pData->options.preferPluginBridges = false;
  59. pData->options.preferUiBridges = false;
  60. init("LV2-Export");
  61. if (pData->options.resourceDir != nullptr)
  62. delete[] pData->options.resourceDir;
  63. if (pData->options.binaryDir != nullptr)
  64. delete[] pData->options.binaryDir;
  65. pData->options.binaryDir = binaryDir.dup();
  66. pData->options.resourceDir = resourceDir.dup();
  67. setCallback(_engine_callback, this);
  68. using water::File;
  69. const File pluginFile(File::getSpecialLocation(File::currentExecutableFile).withFileExtension("xml"));
  70. if (! loadProject(pluginFile.getFullPathName().toRawUTF8()))
  71. {
  72. carla_stderr2("Failed to init plugin, possible reasons: %s", getLastError());
  73. return;
  74. }
  75. CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount == 1,)
  76. fPlugin = pData->plugins[0].plugin;
  77. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  78. CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),);
  79. fPorts.init(fPlugin);
  80. }
  81. ~CarlaEngineLV2Single()
  82. {
  83. if (fPlugin != nullptr && fIsActive)
  84. fPlugin->setActive(false, false, false);
  85. close();
  86. }
  87. bool hasPlugin() noexcept
  88. {
  89. return fPlugin != nullptr;
  90. }
  91. // -----------------------------------------------------------------------------------------------------------------
  92. // LV2 functions
  93. void lv2_connect_port(const uint32_t port, void* const dataLocation) noexcept
  94. {
  95. fPorts.connectPort(port, dataLocation);
  96. }
  97. void lv2_activate() noexcept
  98. {
  99. CARLA_SAFE_ASSERT_RETURN(! fIsActive,);
  100. fPlugin->setActive(true, false, false);
  101. fIsActive = true;
  102. }
  103. void lv2_deactivate() noexcept
  104. {
  105. CARLA_SAFE_ASSERT_RETURN(fIsActive,);
  106. fIsActive = false;
  107. fPlugin->setActive(false, false, false);
  108. }
  109. void lv2_run(const uint32_t frames)
  110. {
  111. fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f);
  112. // Check for updated parameters
  113. float curValue;
  114. for (uint32_t i=0; i < fPorts.numParams; ++i)
  115. {
  116. if (fPorts.paramsOut[i])
  117. continue;
  118. CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)
  119. curValue = *fPorts.paramsPtr[i];
  120. if (carla_isEqual(fPorts.paramsLast[i], curValue))
  121. continue;
  122. fPorts.paramsLast[i] = curValue;
  123. fPlugin->setParameterValue(i, curValue, false, false, false);
  124. }
  125. if (frames == 0)
  126. return fPorts.updateOutputs();
  127. if (fPlugin->tryLock(fIsOffline))
  128. {
  129. fPlugin->initBuffers();
  130. fPlugin->process(fPorts.audioIns, fPorts.audioOuts, nullptr, nullptr, frames);
  131. fPlugin->unlock();
  132. }
  133. else
  134. {
  135. for (uint32_t i=0; i<fPorts.numAudioOuts; ++i)
  136. carla_zeroFloats(fPorts.audioOuts[i], frames);
  137. }
  138. fPorts.updateOutputs();
  139. }
  140. // -----------------------------------------------------------------------------------------------------------------
  141. void lv2ui_instantiate(LV2UI_Write_Function writeFunction, LV2UI_Controller controller,
  142. LV2UI_Widget* widget, const LV2_Feature* const* features)
  143. {
  144. fUI.writeFunction = writeFunction;
  145. fUI.controller = controller;
  146. const LV2_URID_Map* uridMap = nullptr;
  147. // -------------------------------------------------------------------------------------------------------------
  148. // see if the host supports external-ui, get uridMap
  149. for (int i=0; features[i] != nullptr; ++i)
  150. {
  151. if (std::strcmp(features[i]->URI, LV2_EXTERNAL_UI__Host) == 0 ||
  152. std::strcmp(features[i]->URI, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0)
  153. {
  154. fUI.host = (const LV2_External_UI_Host*)features[i]->data;
  155. }
  156. else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
  157. {
  158. uridMap = (const LV2_URID_Map*)features[i]->data;
  159. }
  160. }
  161. if (fUI.host != nullptr)
  162. {
  163. fUI.name = fUI.host->plugin_human_id;
  164. *widget = (LV2_External_UI_Widget*)this;
  165. return;
  166. }
  167. // -------------------------------------------------------------------------------------------------------------
  168. // no external-ui support, use showInterface
  169. for (int i=0; features[i] != nullptr; ++i)
  170. {
  171. if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
  172. {
  173. const LV2_Options_Option* const options((const LV2_Options_Option*)features[i]->data);
  174. for (int j=0; options[j].key != 0; ++j)
  175. {
  176. if (options[j].key == uridMap->map(uridMap->handle, LV2_UI__windowTitle))
  177. {
  178. fUI.name = (const char*)options[j].value;
  179. break;
  180. }
  181. }
  182. break;
  183. }
  184. }
  185. if (fUI.name.isEmpty())
  186. fUI.name = fPlugin->getName();
  187. *widget = nullptr;
  188. }
  189. void lv2ui_port_event(uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer) const
  190. {
  191. if (format != 0 || bufferSize != sizeof(float) || buffer == nullptr)
  192. return;
  193. if (portIndex >= fPorts.indexOffset || ! fUI.visible)
  194. return;
  195. const float value(*(const float*)buffer);
  196. fPlugin->uiParameterChange(portIndex-fPorts.indexOffset, value);
  197. }
  198. void lv2ui_cleanup()
  199. {
  200. if (fUI.visible)
  201. handleUiHide();
  202. fUI.writeFunction = nullptr;
  203. fUI.controller = nullptr;
  204. fUI.host = nullptr;
  205. }
  206. // -----------------------------------------------------------------------------------------------------------------
  207. int lv2ui_idle() const
  208. {
  209. if (! fUI.visible)
  210. return 1;
  211. handleUiRun();
  212. return 0;
  213. }
  214. int lv2ui_show()
  215. {
  216. handleUiShow();
  217. return 0;
  218. }
  219. int lv2ui_hide()
  220. {
  221. handleUiHide();
  222. return 0;
  223. }
  224. protected:
  225. // -----------------------------------------------------------------------------------------------------------------
  226. // CarlaEngine virtual calls
  227. bool init(const char* const clientName) override
  228. {
  229. carla_stdout("CarlaEngineNative::init(\"%s\")", clientName);
  230. if (! pData->init(clientName))
  231. {
  232. close();
  233. setLastError("Failed to init internal data");
  234. return false;
  235. }
  236. return true;
  237. }
  238. bool isRunning() const noexcept override
  239. {
  240. return fIsActive;
  241. }
  242. bool isOffline() const noexcept override
  243. {
  244. return fIsOffline;
  245. }
  246. bool usesConstantBufferSize() const noexcept override
  247. {
  248. return false;
  249. }
  250. EngineType getType() const noexcept override
  251. {
  252. return kEngineTypePlugin;
  253. }
  254. const char* getCurrentDriverName() const noexcept override
  255. {
  256. return "LV2 Plugin";
  257. }
  258. void engineCallback(const EngineCallbackOpcode action, const uint pluginId, const int value1, const int value2, const float value3, const char* const valueStr)
  259. {
  260. switch (action)
  261. {
  262. case ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED:
  263. CARLA_SAFE_ASSERT_RETURN(value1 >= 0,);
  264. if (fUI.writeFunction != nullptr && fUI.controller != nullptr && fUI.visible)
  265. {
  266. fUI.writeFunction(fUI.controller,
  267. static_cast<uint32_t>(value1)+fPorts.indexOffset,
  268. sizeof(float), 0, &value3);
  269. }
  270. break;
  271. case ENGINE_CALLBACK_UI_STATE_CHANGED:
  272. fUI.visible = value1 == 1;
  273. if (fUI.host != nullptr)
  274. fUI.host->ui_closed(fUI.controller);
  275. break;
  276. case ENGINE_CALLBACK_IDLE:
  277. break;
  278. default:
  279. carla_stdout("engineCallback(%i:%s, %u, %i, %i, %f, %s)",
  280. action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valueStr);
  281. break;
  282. }
  283. }
  284. // -----------------------------------------------------------------------------------------------------------------
  285. void handleUiRun() const override
  286. {
  287. try {
  288. fPlugin->uiIdle();
  289. } CARLA_SAFE_EXCEPTION("fPlugin->uiIdle()")
  290. }
  291. void handleUiShow() override
  292. {
  293. fPlugin->showCustomUI(true);
  294. fUI.visible = true;
  295. }
  296. void handleUiHide() override
  297. {
  298. fUI.visible = false;
  299. fPlugin->showCustomUI(false);
  300. }
  301. // -----------------------------------------------------------------------------------------------------------------
  302. private:
  303. CarlaPlugin* fPlugin;
  304. // Lv2 host data
  305. bool fIsActive;
  306. bool fIsOffline;
  307. struct Ports {
  308. uint32_t numAudioIns;
  309. uint32_t numAudioOuts;
  310. uint32_t numParams;
  311. const float** audioIns;
  312. /* */ float** audioOuts;
  313. float* freewheel;
  314. float* paramsLast;
  315. float** paramsPtr;
  316. bool* paramsOut;
  317. uint32_t indexOffset;
  318. const CarlaPlugin* plugin;
  319. Ports()
  320. : numAudioIns(0),
  321. numAudioOuts(0),
  322. numParams(0),
  323. audioIns(nullptr),
  324. audioOuts(nullptr),
  325. freewheel(nullptr),
  326. paramsLast(nullptr),
  327. paramsPtr(nullptr),
  328. paramsOut(nullptr),
  329. indexOffset(1),
  330. plugin(nullptr) {}
  331. ~Ports()
  332. {
  333. if (audioIns != nullptr)
  334. {
  335. delete[] audioIns;
  336. audioIns = nullptr;
  337. }
  338. if (audioOuts != nullptr)
  339. {
  340. delete[] audioOuts;
  341. audioOuts = nullptr;
  342. }
  343. if (paramsLast != nullptr)
  344. {
  345. delete[] paramsLast;
  346. paramsLast = nullptr;
  347. }
  348. if (paramsPtr != nullptr)
  349. {
  350. delete[] paramsPtr;
  351. paramsPtr = nullptr;
  352. }
  353. if (paramsOut != nullptr)
  354. {
  355. delete[] paramsOut;
  356. paramsOut = nullptr;
  357. }
  358. }
  359. void init(const CarlaPlugin* const pl)
  360. {
  361. plugin = pl;
  362. if ((numAudioIns = plugin->getAudioInCount()) > 0)
  363. {
  364. audioIns = new const float*[numAudioIns];
  365. for (uint32_t i=0; i < numAudioIns; ++i)
  366. audioIns[i] = nullptr;
  367. }
  368. if ((numAudioOuts = plugin->getAudioOutCount()) > 0)
  369. {
  370. audioOuts = new float*[numAudioOuts];
  371. for (uint32_t i=0; i < numAudioOuts; ++i)
  372. audioOuts[i] = nullptr;
  373. }
  374. if ((numParams = plugin->getParameterCount()) > 0)
  375. {
  376. paramsLast = new float[numParams];
  377. paramsPtr = new float*[numParams];
  378. paramsOut = new bool[numParams];
  379. for (uint32_t i=0; i < numParams; ++i)
  380. {
  381. paramsLast[i] = plugin->getParameterValue(i);
  382. paramsPtr [i] = nullptr;
  383. paramsOut [i] = plugin->isParameterOutput(i);
  384. }
  385. }
  386. indexOffset = numAudioIns + numAudioOuts + 1;
  387. }
  388. void connectPort(const uint32_t port, void* const dataLocation) noexcept
  389. {
  390. uint32_t index = 0;
  391. for (uint32_t i=0; i < numAudioIns; ++i)
  392. {
  393. if (port == index++)
  394. {
  395. audioIns[i] = (float*)dataLocation;
  396. return;
  397. }
  398. }
  399. for (uint32_t i=0; i < numAudioOuts; ++i)
  400. {
  401. if (port == index++)
  402. {
  403. audioOuts[i] = (float*)dataLocation;
  404. return;
  405. }
  406. }
  407. if (port == index++)
  408. {
  409. freewheel = (float*)dataLocation;
  410. return;
  411. }
  412. for (uint32_t i=0; i < numParams; ++i)
  413. {
  414. if (port == index++)
  415. {
  416. paramsPtr[i] = (float*)dataLocation;
  417. return;
  418. }
  419. }
  420. }
  421. void updateOutputs() noexcept
  422. {
  423. for (uint32_t i=0; i < numParams; ++i)
  424. {
  425. if (! paramsOut[i])
  426. continue;
  427. paramsLast[i] = plugin->getParameterValue(i);
  428. if (paramsPtr[i] != nullptr)
  429. *paramsPtr[i] = paramsLast[i];
  430. }
  431. }
  432. CARLA_DECLARE_NON_COPY_STRUCT(Ports);
  433. } fPorts;
  434. struct UI {
  435. LV2UI_Write_Function writeFunction;
  436. LV2UI_Controller controller;
  437. const LV2_External_UI_Host* host;
  438. CarlaString name;
  439. bool visible;
  440. UI()
  441. : writeFunction(nullptr),
  442. controller(nullptr),
  443. host(nullptr),
  444. name(),
  445. visible(false) {}
  446. CARLA_DECLARE_NON_COPY_STRUCT(UI)
  447. } fUI;
  448. // -------------------------------------------------------------------
  449. #define handlePtr ((CarlaEngineLV2Single*)handle)
  450. static void _engine_callback(void* handle, EngineCallbackOpcode action, uint pluginId, int value1, int value2, float value3, const char* valueStr)
  451. {
  452. handlePtr->engineCallback(action, pluginId, value1, value2, value3, valueStr);
  453. }
  454. #undef handlePtr
  455. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineLV2Single)
  456. };
  457. CARLA_BACKEND_END_NAMESPACE
  458. using CarlaBackend::CarlaEngineLV2Single;
  459. // ---------------------------------------------------------------------------------------------------------------------
  460. // LV2 DSP functions
  461. static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  462. {
  463. carla_stdout("lv2_instantiate(%p, %g, %s, %p)", lv2Descriptor, sampleRate, bundlePath, features);
  464. CarlaEngineLV2Single* const instance(new CarlaEngineLV2Single(sampleRate, bundlePath, features));
  465. if (instance->hasPlugin())
  466. return (LV2_Handle)instance;
  467. delete instance;
  468. return nullptr;
  469. }
  470. #define instancePtr ((CarlaEngineLV2Single*)instance)
  471. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  472. {
  473. instancePtr->lv2_connect_port(port, dataLocation);
  474. }
  475. static void lv2_activate(LV2_Handle instance)
  476. {
  477. carla_stdout("lv2_activate(%p)", instance);
  478. instancePtr->lv2_activate();
  479. }
  480. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  481. {
  482. instancePtr->lv2_run(sampleCount);
  483. }
  484. static void lv2_deactivate(LV2_Handle instance)
  485. {
  486. carla_stdout("lv2_deactivate(%p)", instance);
  487. instancePtr->lv2_deactivate();
  488. }
  489. static void lv2_cleanup(LV2_Handle instance)
  490. {
  491. carla_stdout("lv2_cleanup(%p)", instance);
  492. delete instancePtr;
  493. }
  494. static const void* lv2_extension_data(const char* uri)
  495. {
  496. carla_stdout("lv2_extension_data(\"%s\")", uri);
  497. return nullptr;
  498. }
  499. #undef instancePtr
  500. // ---------------------------------------------------------------------------------------------------------------------
  501. // LV2 UI functions
  502. static LV2UI_Handle lv2ui_instantiate(const LV2UI_Descriptor*, const char*, const char*,
  503. LV2UI_Write_Function writeFunction, LV2UI_Controller controller,
  504. LV2UI_Widget* widget, const LV2_Feature* const* features)
  505. {
  506. carla_debug("lv2ui_instantiate(..., %p, %p, %p)", writeFunction, controller, widget, features);
  507. CarlaEngineLV2Single* engine = nullptr;
  508. for (int i=0; features[i] != nullptr; ++i)
  509. {
  510. if (std::strcmp(features[i]->URI, LV2_INSTANCE_ACCESS_URI) == 0)
  511. {
  512. engine = (CarlaEngineLV2Single*)features[i]->data;
  513. break;
  514. }
  515. }
  516. if (engine == nullptr)
  517. {
  518. carla_stderr("Host doesn't support instance-access, cannot show UI");
  519. return nullptr;
  520. }
  521. engine->lv2ui_instantiate(writeFunction, controller, widget, features);
  522. return (LV2UI_Handle)engine;
  523. }
  524. #define uiPtr ((CarlaEngineLV2Single*)ui)
  525. static void lv2ui_port_event(LV2UI_Handle ui, uint32_t portIndex, uint32_t bufferSize, uint32_t format, const void* buffer)
  526. {
  527. carla_debug("lv2ui_port_event(%p, %i, %i, %i, %p)", ui, portIndex, bufferSize, format, buffer);
  528. uiPtr->lv2ui_port_event(portIndex, bufferSize, format, buffer);
  529. }
  530. static void lv2ui_cleanup(LV2UI_Handle ui)
  531. {
  532. carla_debug("lv2ui_cleanup(%p)", ui);
  533. uiPtr->lv2ui_cleanup();
  534. }
  535. static int lv2ui_idle(LV2UI_Handle ui)
  536. {
  537. return uiPtr->lv2ui_idle();
  538. }
  539. static int lv2ui_show(LV2UI_Handle ui)
  540. {
  541. carla_debug("lv2ui_show(%p)", ui);
  542. return uiPtr->lv2ui_show();
  543. }
  544. static int lv2ui_hide(LV2UI_Handle ui)
  545. {
  546. carla_debug("lv2ui_hide(%p)", ui);
  547. return uiPtr->lv2ui_hide();
  548. }
  549. static const void* lv2ui_extension_data(const char* uri)
  550. {
  551. carla_stdout("lv2ui_extension_data(\"%s\")", uri);
  552. static const LV2UI_Idle_Interface uiidle = { lv2ui_idle };
  553. static const LV2UI_Show_Interface uishow = { lv2ui_show, lv2ui_hide };
  554. if (std::strcmp(uri, LV2_UI__idleInterface) == 0)
  555. return &uiidle;
  556. if (std::strcmp(uri, LV2_UI__showInterface) == 0)
  557. return &uishow;
  558. return nullptr;
  559. }
  560. #undef uiPtr
  561. // ---------------------------------------------------------------------------------------------------------------------
  562. // Startup code
  563. CARLA_EXPORT
  564. const LV2_Descriptor* lv2_descriptor(uint32_t index)
  565. {
  566. carla_stdout("lv2_descriptor(%i)", index);
  567. if (index != 0)
  568. return nullptr;
  569. static CarlaString ret;
  570. if (ret.isEmpty())
  571. {
  572. using namespace water;
  573. const File file(File::getSpecialLocation(File::currentExecutableFile).withFileExtension("ttl"));
  574. ret = String("file://" + file.getFullPathName()).toRawUTF8();
  575. }
  576. static const LV2_Descriptor desc = {
  577. /* URI */ ret.buffer(),
  578. /* instantiate */ lv2_instantiate,
  579. /* connect_port */ lv2_connect_port,
  580. /* activate */ lv2_activate,
  581. /* run */ lv2_run,
  582. /* deactivate */ lv2_deactivate,
  583. /* cleanup */ lv2_cleanup,
  584. /* extension_data */ lv2_extension_data
  585. };
  586. return &desc;
  587. }
  588. CARLA_EXPORT
  589. const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
  590. {
  591. carla_stdout("lv2ui_descriptor(%i)", index);
  592. static CarlaString ret;
  593. if (ret.isEmpty())
  594. {
  595. using namespace water;
  596. const File file(File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("ext-ui"));
  597. ret = String("file://" + file.getFullPathName()).toRawUTF8();
  598. }
  599. static const LV2UI_Descriptor lv2UiExtDesc = {
  600. /* URI */ ret.buffer(),
  601. /* instantiate */ lv2ui_instantiate,
  602. /* cleanup */ lv2ui_cleanup,
  603. /* port_event */ lv2ui_port_event,
  604. /* extension_data */ lv2ui_extension_data
  605. };
  606. return (index == 0) ? &lv2UiExtDesc : nullptr;
  607. }
  608. // ---------------------------------------------------------------------------------------------------------------------