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.

562 lines
16KB

  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. // #define BUILD_BRIDGE
  18. #include "engine/CarlaEngineInternal.hpp"
  19. #include "CarlaPlugin.hpp"
  20. #include "CarlaBackendUtils.hpp"
  21. #include "CarlaEngineUtils.hpp"
  22. #include "CarlaLv2Utils.hpp"
  23. #include "CarlaUtils.h"
  24. // ---------------------------------------------------------------------------------------------------------------------
  25. CARLA_BACKEND_START_NAMESPACE
  26. class CarlaEngineLV2Single : public CarlaEngine
  27. {
  28. public:
  29. CarlaEngineLV2Single(const uint32_t bufferSize, const double sampleRate, const char* const bundlePath, const LV2_URID_Map* uridMap)
  30. : fPlugin(nullptr),
  31. fIsRunning(false),
  32. fIsOffline(false)
  33. {
  34. // xxxxx
  35. CarlaString binaryDir(bundlePath);
  36. binaryDir += CARLA_OS_SEP_STR "bin" CARLA_OS_SEP_STR;
  37. CarlaString resourceDir(bundlePath);
  38. resourceDir += CARLA_OS_SEP_STR "res" CARLA_OS_SEP_STR;
  39. pData->bufferSize = bufferSize;
  40. pData->sampleRate = sampleRate;
  41. pData->initTime(nullptr);
  42. pData->options.processMode = ENGINE_PROCESS_MODE_BRIDGE;
  43. pData->options.transportMode = ENGINE_TRANSPORT_MODE_PLUGIN;
  44. pData->options.forceStereo = false;
  45. pData->options.preferPluginBridges = false;
  46. pData->options.preferUiBridges = false;
  47. init("LV2-Export");
  48. if (pData->options.resourceDir != nullptr)
  49. delete[] pData->options.resourceDir;
  50. if (pData->options.binaryDir != nullptr)
  51. delete[] pData->options.binaryDir;
  52. pData->options.binaryDir = binaryDir.dup();
  53. pData->options.resourceDir = resourceDir.dup();
  54. setCallback(_engine_callback, this);
  55. using juce::File;
  56. const File pluginFile(File::getSpecialLocation(File::currentExecutableFile).withFileExtension("xml"));
  57. if (! loadProject(pluginFile.getFullPathName().toRawUTF8()))
  58. {
  59. carla_stderr2("Failed to init plugin, possible reasons: %s", getLastError());
  60. return;
  61. }
  62. CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount == 1,)
  63. fPlugin = pData->plugins[0].plugin;
  64. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  65. CARLA_SAFE_ASSERT_RETURN(fPlugin->isEnabled(),);
  66. fPorts.init(fPlugin);
  67. }
  68. ~CarlaEngineLV2Single()
  69. {
  70. close();
  71. }
  72. bool hasPlugin()
  73. {
  74. return fPlugin != nullptr;
  75. }
  76. // -----------------------------------------------------------------------------------------------------------------
  77. // LV2 functions
  78. void lv2_connect_port(const uint32_t port, void* const dataLocation)
  79. {
  80. fPorts.connectPort(port, dataLocation);
  81. }
  82. void lv2_activate()
  83. {
  84. CARLA_SAFE_ASSERT_RETURN(! fIsRunning,);
  85. fPlugin->activate();
  86. fIsRunning = true;
  87. }
  88. void lv2_deactivate()
  89. {
  90. CARLA_SAFE_ASSERT_RETURN(fIsRunning,);
  91. fIsRunning = false;
  92. fPlugin->deactivate();
  93. }
  94. void lv2_run(const uint32_t frames)
  95. {
  96. fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f);
  97. // Check for updated parameters
  98. float curValue;
  99. for (uint32_t i=0; i < fPorts.numParams; ++i)
  100. {
  101. if (fPorts.paramsOut[i])
  102. continue;
  103. CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)
  104. curValue = *fPorts.paramsPtr[i];
  105. if (carla_isEqual(fPorts.paramsLast[i], curValue))
  106. continue;
  107. fPorts.paramsLast[i] = curValue;
  108. fPlugin->setParameterValue(i, curValue, false, false, false);
  109. }
  110. if (frames == 0)
  111. return fPorts.updateOutputs();
  112. if (fPlugin->tryLock(fIsOffline))
  113. {
  114. fPlugin->initBuffers();
  115. fPlugin->process(fPorts.audioIns, fPorts.audioOuts, nullptr, nullptr, frames);
  116. fPlugin->unlock();
  117. }
  118. else
  119. {
  120. for (uint32_t i=0; i<fPorts.numAudioOuts; ++i)
  121. carla_zeroFloats(fPorts.audioOuts[i], frames);
  122. }
  123. fPorts.updateOutputs();
  124. }
  125. protected:
  126. // -----------------------------------------------------------------------------------------------------------------
  127. // CarlaEngine virtual calls
  128. bool init(const char* const clientName) override
  129. {
  130. carla_stdout("CarlaEngineNative::init(\"%s\")", clientName);
  131. if (! pData->init(clientName))
  132. {
  133. close();
  134. setLastError("Failed to init internal data");
  135. return false;
  136. }
  137. return true;
  138. }
  139. bool close() override
  140. {
  141. fIsRunning = false;
  142. CarlaEngine::close();
  143. return true;
  144. }
  145. bool isRunning() const noexcept override
  146. {
  147. return fIsRunning;
  148. }
  149. bool isOffline() const noexcept override
  150. {
  151. return fIsOffline;
  152. }
  153. bool usesConstantBufferSize() const noexcept override
  154. {
  155. return true;
  156. }
  157. EngineType getType() const noexcept override
  158. {
  159. return kEngineTypePlugin;
  160. }
  161. const char* getCurrentDriverName() const noexcept override
  162. {
  163. return "LV2 Plugin";
  164. }
  165. void callback(const EngineCallbackOpcode action, const uint pluginId, const int value1, const int value2, const float value3, const char* const valueStr) noexcept override
  166. {
  167. CarlaEngine::callback(action, pluginId, value1, value2, value3, valueStr);
  168. //if (action == ENGINE_CALLBACK_IDLE && ! pData->aboutToClose)
  169. // pHost->dispatcher(pHost->handle, NATIVE_HOST_OPCODE_HOST_IDLE, 0, 0, nullptr, 0.0f);
  170. }
  171. void engineCallback(const EngineCallbackOpcode action, const uint pluginId, const int value1, const int value2, const float value3, const char* const valueStr)
  172. {
  173. carla_stdout("engineCallback(%i:%s, %u, %i, %i, %f, %s)", action, EngineCallbackOpcode2Str(action), pluginId, value1, value2, value3, valueStr);
  174. }
  175. // -----------------------------------------------------------------------------------------------------------------
  176. private:
  177. CarlaPlugin* fPlugin;
  178. bool fIsRunning;
  179. // Lv2 host data
  180. bool fIsOffline;
  181. struct Ports {
  182. uint32_t numAudioIns;
  183. uint32_t numAudioOuts;
  184. uint32_t numParams;
  185. const float** audioIns;
  186. /* */ float** audioOuts;
  187. float* freewheel;
  188. float* paramsLast;
  189. float** paramsPtr;
  190. bool* paramsOut;
  191. const CarlaPlugin* plugin;
  192. Ports()
  193. : numAudioIns(0),
  194. numAudioOuts(0),
  195. numParams(0),
  196. audioIns(nullptr),
  197. audioOuts(nullptr),
  198. freewheel(nullptr),
  199. paramsLast(nullptr),
  200. paramsPtr(nullptr),
  201. paramsOut(nullptr),
  202. plugin(nullptr) {}
  203. ~Ports()
  204. {
  205. if (audioIns != nullptr)
  206. {
  207. delete[] audioIns;
  208. audioIns = nullptr;
  209. }
  210. if (audioOuts != nullptr)
  211. {
  212. delete[] audioOuts;
  213. audioOuts = nullptr;
  214. }
  215. if (paramsLast != nullptr)
  216. {
  217. delete[] paramsLast;
  218. paramsLast = nullptr;
  219. }
  220. if (paramsPtr != nullptr)
  221. {
  222. delete[] paramsPtr;
  223. paramsPtr = nullptr;
  224. }
  225. if (paramsOut != nullptr)
  226. {
  227. delete[] paramsOut;
  228. paramsOut = nullptr;
  229. }
  230. }
  231. void init(const CarlaPlugin* const pl)
  232. {
  233. plugin = pl;
  234. if ((numAudioIns = plugin->getAudioInCount()) > 0)
  235. {
  236. audioIns = new const float*[numAudioIns];
  237. for (uint32_t i=0; i < numAudioIns; ++i)
  238. audioIns[i] = nullptr;
  239. }
  240. if ((numAudioOuts = plugin->getAudioOutCount()) > 0)
  241. {
  242. audioOuts = new float*[numAudioOuts];
  243. for (uint32_t i=0; i < numAudioOuts; ++i)
  244. audioOuts[i] = nullptr;
  245. }
  246. if ((numParams = plugin->getParameterCount()) > 0)
  247. {
  248. paramsLast = new float[numParams];
  249. paramsPtr = new float*[numParams];
  250. paramsOut = new bool[numParams];
  251. for (uint32_t i=0; i < numParams; ++i)
  252. {
  253. paramsLast[i] = plugin->getParameterValue(i);
  254. paramsPtr [i] = nullptr;
  255. paramsOut [i] = plugin->isParameterOutput(i);
  256. }
  257. }
  258. }
  259. void connectPort(const uint32_t port, void* const dataLocation) noexcept
  260. {
  261. uint32_t index = 0;
  262. for (uint32_t i=0; i < numAudioIns; ++i)
  263. {
  264. if (port == index++)
  265. {
  266. audioIns[i] = (float*)dataLocation;
  267. return;
  268. }
  269. }
  270. for (uint32_t i=0; i < numAudioOuts; ++i)
  271. {
  272. if (port == index++)
  273. {
  274. audioOuts[i] = (float*)dataLocation;
  275. return;
  276. }
  277. }
  278. if (port == index++)
  279. {
  280. freewheel = (float*)dataLocation;
  281. return;
  282. }
  283. for (uint32_t i=0; i < numParams; ++i)
  284. {
  285. if (port == index++)
  286. {
  287. paramsPtr[i] = (float*)dataLocation;
  288. return;
  289. }
  290. }
  291. }
  292. void updateOutputs() noexcept
  293. {
  294. for (uint32_t i=0; i < numParams; ++i)
  295. {
  296. if (! paramsOut[i])
  297. continue;
  298. paramsLast[i] = plugin->getParameterValue(i);
  299. if (paramsPtr[i] != nullptr)
  300. *paramsPtr[i] = paramsLast[i];
  301. }
  302. }
  303. CARLA_DECLARE_NON_COPY_STRUCT(Ports);
  304. } fPorts;
  305. #define handlePtr ((CarlaEngineLV2Single*)handle)
  306. static void _engine_callback(void* handle, EngineCallbackOpcode action, uint pluginId, int value1, int value2, float value3, const char* valueStr)
  307. {
  308. handlePtr->engineCallback(action, pluginId, value1, value2, value3, valueStr);
  309. }
  310. #undef handlePtr
  311. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineLV2Single)
  312. };
  313. CARLA_BACKEND_END_NAMESPACE
  314. // ---------------------------------------------------------------------------------------------------------------------
  315. // LV2 plugin descriptor functions
  316. CARLA_BACKEND_USE_NAMESPACE
  317. static LV2_Handle lv2_instantiate(const LV2_Descriptor* lv2Descriptor, double sampleRate, const char* bundlePath, const LV2_Feature* const* features)
  318. {
  319. carla_stdout("lv2_instantiate(%p, %g, %s, %p)", lv2Descriptor, sampleRate, bundlePath, features);
  320. const LV2_Options_Option* options = nullptr;
  321. const LV2_URID_Map* uridMap = nullptr;
  322. const LV2_URID_Unmap* uridUnmap = nullptr;
  323. for (int i=0; features[i] != nullptr; ++i)
  324. {
  325. if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
  326. options = (const LV2_Options_Option*)features[i]->data;
  327. else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
  328. uridMap = (const LV2_URID_Map*)features[i]->data;
  329. else if (std::strcmp(features[i]->URI, LV2_URID__unmap) == 0)
  330. uridUnmap = (const LV2_URID_Unmap*)features[i]->data;
  331. }
  332. if (options == nullptr || uridMap == nullptr)
  333. {
  334. carla_stderr("Host doesn't provide option or urid-map features");
  335. return nullptr;
  336. }
  337. uint32_t bufferSize = 0;
  338. for (int i=0; options[i].key != 0; ++i)
  339. {
  340. if (uridUnmap != nullptr) {
  341. carla_stdout("Host option %i:\"%s\"", i, uridUnmap->unmap(uridUnmap->handle, options[i].key));
  342. }
  343. if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__nominalBlockLength))
  344. {
  345. if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
  346. {
  347. const int value(*(const int*)options[i].value);
  348. CARLA_SAFE_ASSERT_CONTINUE(value > 0);
  349. bufferSize = static_cast<uint32_t>(value);
  350. }
  351. else
  352. {
  353. carla_stderr("Host provides nominalBlockLength but has wrong value type");
  354. }
  355. break;
  356. }
  357. if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength))
  358. {
  359. if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
  360. {
  361. const int value(*(const int*)options[i].value);
  362. CARLA_SAFE_ASSERT_CONTINUE(value > 0);
  363. bufferSize = static_cast<uint32_t>(value);
  364. }
  365. else
  366. {
  367. carla_stderr("Host provides maxBlockLength but has wrong value type");
  368. }
  369. // no break, continue in case host supports nominalBlockLength
  370. }
  371. }
  372. if (bufferSize == 0)
  373. {
  374. carla_stderr("Host doesn't provide bufferSize feature");
  375. return nullptr;
  376. }
  377. CarlaEngineLV2Single* const instance(new CarlaEngineLV2Single(bufferSize, sampleRate, bundlePath, uridMap));
  378. if (instance->hasPlugin())
  379. return (LV2_Handle)instance;
  380. delete instance;
  381. return nullptr;
  382. }
  383. #define instancePtr ((CarlaEngineLV2Single*)instance)
  384. static void lv2_connect_port(LV2_Handle instance, uint32_t port, void* dataLocation)
  385. {
  386. instancePtr->lv2_connect_port(port, dataLocation);
  387. }
  388. static void lv2_activate(LV2_Handle instance)
  389. {
  390. carla_stdout("lv2_activate(%p)", instance);
  391. instancePtr->lv2_activate();
  392. }
  393. static void lv2_run(LV2_Handle instance, uint32_t sampleCount)
  394. {
  395. instancePtr->lv2_run(sampleCount);
  396. }
  397. static void lv2_deactivate(LV2_Handle instance)
  398. {
  399. carla_stdout("lv2_deactivate(%p)", instance);
  400. instancePtr->lv2_deactivate();
  401. }
  402. static void lv2_cleanup(LV2_Handle instance)
  403. {
  404. carla_stdout("lv2_cleanup(%p)", instance);
  405. delete instancePtr;
  406. }
  407. static const void* lv2_extension_data(const char* uri)
  408. {
  409. carla_stdout("lv2_extension_data(\"%s\")", uri);
  410. return nullptr;
  411. }
  412. #undef instancePtr
  413. // ---------------------------------------------------------------------------------------------------------------------
  414. // Startup code
  415. CARLA_EXPORT
  416. const LV2_Descriptor* lv2_descriptor(uint32_t index)
  417. {
  418. carla_stdout("lv2_descriptor(%i)", index);
  419. if (index != 0)
  420. return nullptr;
  421. static CarlaString ret;
  422. if (ret.isEmpty())
  423. {
  424. using namespace juce;
  425. const File file(File::getSpecialLocation(File::currentExecutableFile).withFileExtension("ttl"));
  426. ret = String("file://" + file.getFullPathName()).toRawUTF8();
  427. }
  428. static const LV2_Descriptor desc = {
  429. /* URI */ ret.buffer(),
  430. /* instantiate */ lv2_instantiate,
  431. /* connect_port */ lv2_connect_port,
  432. /* activate */ lv2_activate,
  433. /* run */ lv2_run,
  434. /* deactivate */ lv2_deactivate,
  435. /* cleanup */ lv2_cleanup,
  436. /* extension_data */ lv2_extension_data
  437. };
  438. return &desc;
  439. }
  440. CARLA_EXPORT
  441. const LV2UI_Descriptor* lv2ui_descriptor(uint32_t index)
  442. {
  443. carla_stdout("lv2ui_descriptor(%i)", index);
  444. return nullptr;
  445. }
  446. // ---------------------------------------------------------------------------------------------------------------------