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.

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