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.

1187 lines
38KB

  1. /*
  2. * Carla CLAP Plugin
  3. * Copyright (C) 2022 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. #include "CarlaPluginInternal.hpp"
  18. #include "CarlaEngine.hpp"
  19. #include "CarlaBackendUtils.hpp"
  20. #include "CarlaClapUtils.hpp"
  21. #include "CarlaMathUtils.hpp"
  22. #include "CarlaPluginUI.hpp"
  23. #ifdef CARLA_OS_MAC
  24. # include "CarlaMacUtils.hpp"
  25. # import <Foundation/Foundation.h>
  26. #endif
  27. #include "water/files/File.h"
  28. CARLA_BACKEND_START_NAMESPACE
  29. // --------------------------------------------------------------------------------------------------------------------
  30. struct carla_clap_host : clap_host_t {
  31. carla_clap_host()
  32. {
  33. clap_version = CLAP_VERSION;
  34. host_data = this;
  35. name = "Carla";
  36. vendor = "falkTX";
  37. url = "https://kx.studio/carla";
  38. version = CARLA_VERSION_STRING;
  39. get_extension = carla_get_extension;
  40. request_restart = carla_request_restart;
  41. request_process = carla_request_process;
  42. request_callback = carla_request_callback;
  43. }
  44. static const void* carla_get_extension(const clap_host_t*, const char*) { return nullptr; }
  45. static void carla_request_restart(const clap_host_t*) {}
  46. static void carla_request_process(const clap_host_t*) {}
  47. static void carla_request_callback(const clap_host_t*) {}
  48. };
  49. // --------------------------------------------------------------------------------------------------------------------
  50. class CarlaPluginCLAP : public CarlaPlugin,
  51. private CarlaPluginUI::Callback
  52. {
  53. public:
  54. CarlaPluginCLAP(CarlaEngine* const engine, const uint id)
  55. : CarlaPlugin(engine, id),
  56. fPlugin(nullptr),
  57. fPluginDescriptor(nullptr),
  58. fPluginEntry(nullptr),
  59. fHost(),
  60. fExtensions()
  61. {
  62. carla_debug("CarlaPluginCLAP::CarlaPluginCLAP(%p, %i)", engine, id);
  63. }
  64. ~CarlaPluginCLAP() override
  65. {
  66. carla_debug("CarlaPluginCLAP::~CarlaPluginCLAP()");
  67. // close UI
  68. // if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
  69. // {
  70. // if (! fUI.isEmbed)
  71. // showCustomUI(false);
  72. //
  73. // if (fUI.isOpen)
  74. // {
  75. // fUI.isOpen = false;
  76. // dispatcher(effEditClose);
  77. // }
  78. // }
  79. pData->singleMutex.lock();
  80. pData->masterMutex.lock();
  81. if (pData->client != nullptr && pData->client->isActive())
  82. pData->client->deactivate(true);
  83. // CARLA_ASSERT(! fIsProcessing);
  84. if (pData->active)
  85. {
  86. deactivate();
  87. pData->active = false;
  88. }
  89. if (fPlugin != nullptr)
  90. {
  91. fPlugin->destroy(fPlugin);
  92. fPlugin = nullptr;
  93. }
  94. clearBuffers();
  95. if (fPluginEntry != nullptr)
  96. {
  97. fPluginEntry->deinit();
  98. fPluginEntry = nullptr;
  99. }
  100. }
  101. // -------------------------------------------------------------------
  102. // Information (base)
  103. PluginType getType() const noexcept override
  104. {
  105. return PLUGIN_CLAP;
  106. }
  107. PluginCategory getCategory() const noexcept override
  108. {
  109. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, PLUGIN_CATEGORY_NONE);
  110. if (fPluginDescriptor->features == nullptr)
  111. return PLUGIN_CATEGORY_NONE;
  112. return getPluginCategoryFromClapFeatures(fPluginDescriptor->features);
  113. }
  114. /*
  115. uint32_t getLatencyInFrames() const noexcept override
  116. {
  117. }
  118. */
  119. // -------------------------------------------------------------------
  120. // Information (count)
  121. // nothing
  122. // -------------------------------------------------------------------
  123. // Information (current data)
  124. /*
  125. std::size_t getChunkData(void** const dataPtr) noexcept override
  126. {
  127. }
  128. */
  129. // -------------------------------------------------------------------
  130. // Information (per-plugin data)
  131. /*
  132. uint getOptionsAvailable() const noexcept override
  133. {
  134. }
  135. */
  136. float getParameterValue(const uint32_t parameterId) const noexcept override
  137. {
  138. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.f);
  139. CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, 0.f);
  140. const clap_id clapId = pData->param.data[parameterId].rindex;
  141. double value;
  142. CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_value(fPlugin, clapId, &value), 0.f);
  143. return value;
  144. }
  145. bool getLabel(char* const strBuf) const noexcept override
  146. {
  147. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, false);
  148. std::strncpy(strBuf, fPluginDescriptor->id, STR_MAX);
  149. return true;
  150. }
  151. bool getMaker(char* const strBuf) const noexcept override
  152. {
  153. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, false);
  154. std::strncpy(strBuf, fPluginDescriptor->vendor, STR_MAX);
  155. return true;
  156. }
  157. bool getCopyright(char* const strBuf) const noexcept override
  158. {
  159. return getMaker(strBuf);
  160. }
  161. bool getRealName(char* const strBuf) const noexcept override
  162. {
  163. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, false);
  164. std::strncpy(strBuf, fPluginDescriptor->name, STR_MAX);
  165. return true;
  166. }
  167. bool getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override
  168. {
  169. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, false);
  170. CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, false);
  171. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  172. const clap_id clapId = pData->param.data[parameterId].rindex;
  173. clap_param_info_t paramInfo = {};
  174. CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_info(fPlugin, clapId, &paramInfo), false);
  175. std::strncpy(strBuf, paramInfo.name, STR_MAX);
  176. return true;
  177. }
  178. bool getParameterText(const uint32_t parameterId, char* const strBuf) noexcept override
  179. {
  180. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, false);
  181. CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, false);
  182. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  183. const clap_id clapId = pData->param.data[parameterId].rindex;
  184. double value;
  185. CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_value(fPlugin, clapId, &value), false);
  186. return fExtensions.params->value_to_text(fPlugin, clapId, value, strBuf, STR_MAX);
  187. }
  188. /*
  189. bool getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept override
  190. {
  191. }
  192. bool getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept override
  193. {
  194. }
  195. */
  196. // -------------------------------------------------------------------
  197. // Set data (state)
  198. // nothing
  199. // -------------------------------------------------------------------
  200. // Set data (internal stuff)
  201. /*
  202. void setName(const char* const newName) override
  203. {
  204. }
  205. */
  206. // -------------------------------------------------------------------
  207. // Set data (plugin-specific stuff)
  208. /*
  209. void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
  210. {
  211. }
  212. void setParameterValueRT(const uint32_t parameterId, const float value, const uint32_t frameOffset, const bool sendCallbackLater) noexcept override
  213. {
  214. }
  215. void setChunkData(const void* const data, const std::size_t dataSize) override
  216. {
  217. }
  218. void setProgram(const int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback, const bool doingInit) noexcept override
  219. {
  220. }
  221. void setProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept override
  222. {
  223. }
  224. */
  225. // -------------------------------------------------------------------
  226. // Set ui stuff
  227. /*
  228. void setCustomUITitle(const char* const title) noexcept override
  229. {
  230. }
  231. void showCustomUI(const bool yesNo) override
  232. {
  233. }
  234. void* embedCustomUI(void* const ptr) override
  235. {
  236. }
  237. */
  238. void idle() override
  239. {
  240. CarlaPlugin::idle();
  241. }
  242. void uiIdle() override
  243. {
  244. CarlaPlugin::uiIdle();
  245. }
  246. // -------------------------------------------------------------------
  247. // Plugin state
  248. void reload() override
  249. {
  250. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
  251. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  252. carla_debug("CarlaPluginCLAP::reload() - start");
  253. // Safely disable plugin for reload
  254. const ScopedDisabler sd(this);
  255. if (pData->active)
  256. deactivate();
  257. clearBuffers();
  258. const clap_plugin_audio_ports_t* audioPortsExt = static_cast<const clap_plugin_audio_ports_t*>(
  259. fPlugin->get_extension(fPlugin, CLAP_EXT_AUDIO_PORTS));
  260. const clap_plugin_note_ports_t* notePortsExt = static_cast<const clap_plugin_note_ports_t*>(
  261. fPlugin->get_extension(fPlugin, CLAP_EXT_NOTE_PORTS));
  262. const clap_plugin_params_t* paramsExt = static_cast<const clap_plugin_params_t*>(
  263. fPlugin->get_extension(fPlugin, CLAP_EXT_PARAMS));
  264. if (audioPortsExt != nullptr && (audioPortsExt->count == nullptr || audioPortsExt->get == nullptr))
  265. audioPortsExt = nullptr;
  266. if (notePortsExt != nullptr && (notePortsExt->count == nullptr || notePortsExt->get == nullptr))
  267. notePortsExt = nullptr;
  268. if (paramsExt != nullptr && (paramsExt->count == nullptr || paramsExt->get_info == nullptr))
  269. paramsExt = nullptr;
  270. fExtensions.params = paramsExt;
  271. const uint32_t numAudioInputPorts = audioPortsExt != nullptr ? audioPortsExt->count(fPlugin, true) : 0;
  272. const uint32_t numAudioOutputPorts = audioPortsExt != nullptr ? audioPortsExt->count(fPlugin, false) : 0;
  273. const uint32_t numNoteInputPorts = notePortsExt != nullptr ? notePortsExt->count(fPlugin, true) : 0;
  274. const uint32_t numNoteOutputPorts = notePortsExt != nullptr ? notePortsExt->count(fPlugin, true) : 0;
  275. const uint32_t numParameters = paramsExt != nullptr ? paramsExt->count(fPlugin) : 0;
  276. uint32_t aIns, aOuts, params;
  277. aIns = aOuts = params = 0;
  278. bool needsCtrlIn, needsCtrlOut;
  279. needsCtrlIn = needsCtrlOut = false;
  280. for (uint32_t i=0; i<numAudioInputPorts; ++i)
  281. {
  282. clap_audio_port_info_t portInfo = {};
  283. CARLA_SAFE_ASSERT_BREAK(audioPortsExt->get(fPlugin, i, true, &portInfo));
  284. aIns += portInfo.channel_count;
  285. }
  286. for (uint32_t i=0; i<numAudioOutputPorts; ++i)
  287. {
  288. clap_audio_port_info_t portInfo = {};
  289. CARLA_SAFE_ASSERT_BREAK(audioPortsExt->get(fPlugin, i, false, &portInfo));
  290. aOuts += portInfo.channel_count;
  291. }
  292. for (uint32_t i=0; i<numParameters; ++i)
  293. {
  294. clap_param_info_t paramInfo = {};
  295. CARLA_SAFE_ASSERT_BREAK(paramsExt->get_info(fPlugin, i, &paramInfo));
  296. if ((paramInfo.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS)) == 0x0)
  297. ++params;
  298. }
  299. if (aIns > 0)
  300. {
  301. pData->audioIn.createNew(aIns);
  302. }
  303. if (aOuts > 0)
  304. {
  305. pData->audioOut.createNew(aOuts);
  306. needsCtrlIn = true;
  307. }
  308. if (numNoteInputPorts > 0)
  309. needsCtrlIn = true;
  310. if (numNoteOutputPorts > 0)
  311. needsCtrlOut = true;
  312. if (params > 0)
  313. {
  314. pData->param.createNew(params, false);
  315. needsCtrlIn = true;
  316. }
  317. const EngineProcessMode processMode = pData->engine->getProccessMode();
  318. const uint portNameSize = pData->engine->getMaxPortNameSize();
  319. CarlaString portName;
  320. // Audio Ins
  321. for (uint32_t j=0; j < aIns; ++j)
  322. {
  323. portName.clear();
  324. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  325. {
  326. portName = pData->name;
  327. portName += ":";
  328. }
  329. if (aIns > 1)
  330. {
  331. portName += "input_";
  332. portName += CarlaString(j+1);
  333. }
  334. else
  335. portName += "input";
  336. portName.truncate(portNameSize);
  337. pData->audioIn.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j);
  338. pData->audioIn.ports[j].rindex = j;
  339. }
  340. // Audio Outs
  341. for (uint32_t j=0; j < aOuts; ++j)
  342. {
  343. portName.clear();
  344. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  345. {
  346. portName = pData->name;
  347. portName += ":";
  348. }
  349. if (aOuts > 1)
  350. {
  351. portName += "output_";
  352. portName += CarlaString(j+1);
  353. }
  354. else
  355. portName += "output";
  356. portName.truncate(portNameSize);
  357. pData->audioOut.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j);
  358. pData->audioOut.ports[j].rindex = j;
  359. }
  360. for (uint32_t j=0; j < params; ++j)
  361. {
  362. const int32_t ij = static_cast<int32_t>(j);
  363. pData->param.data[j].index = j;
  364. pData->param.data[j].rindex = ij;
  365. clap_param_info_t paramInfo = {};
  366. CARLA_SAFE_ASSERT_BREAK(paramsExt->get_info(fPlugin, j, &paramInfo));
  367. if (paramInfo.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS))
  368. continue;
  369. double min, max, def, step, stepSmall, stepLarge;
  370. min = paramInfo.min_value;
  371. max = paramInfo.max_value;
  372. def = paramInfo.default_value;
  373. if (min >= max)
  374. max = min + 0.1;
  375. if (def < min)
  376. def = min;
  377. else if (def > max)
  378. def = max;
  379. if (paramInfo.flags & CLAP_PARAM_IS_READONLY)
  380. pData->param.data[j].type = PARAMETER_OUTPUT;
  381. else
  382. pData->param.data[j].type = PARAMETER_INPUT;
  383. if (paramInfo.flags & CLAP_PARAM_IS_STEPPED)
  384. {
  385. if (carla_isEqual(max - min, 1.0))
  386. {
  387. step = stepSmall = stepLarge = 1.0;
  388. pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN;
  389. }
  390. else
  391. {
  392. step = 1.0;
  393. stepSmall = 1.0;
  394. stepLarge = std::min(max - min, 10.0);
  395. }
  396. pData->param.data[j].hints |= PARAMETER_IS_INTEGER;
  397. }
  398. else
  399. {
  400. double range = max - min;
  401. step = range/100.0;
  402. stepSmall = range/1000.0;
  403. stepLarge = range/10.0;
  404. }
  405. pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
  406. pData->param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT;
  407. if (paramInfo.flags & CLAP_PARAM_IS_AUTOMATABLE)
  408. {
  409. pData->param.data[j].hints |= PARAMETER_IS_AUTOMATABLE;
  410. if ((paramInfo.flags & CLAP_PARAM_IS_STEPPED) == 0x0)
  411. pData->param.data[j].hints |= PARAMETER_CAN_BE_CV_CONTROLLED;
  412. }
  413. pData->param.ranges[j].min = min;
  414. pData->param.ranges[j].max = max;
  415. pData->param.ranges[j].def = def;
  416. pData->param.ranges[j].step = step;
  417. pData->param.ranges[j].stepSmall = stepSmall;
  418. pData->param.ranges[j].stepLarge = stepLarge;
  419. }
  420. if (needsCtrlIn)
  421. {
  422. portName.clear();
  423. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  424. {
  425. portName = pData->name;
  426. portName += ":";
  427. }
  428. portName += "events-in";
  429. portName.truncate(portNameSize);
  430. pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
  431. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  432. pData->event.cvSourcePorts = pData->client->createCVSourcePorts();
  433. #endif
  434. }
  435. if (needsCtrlOut)
  436. {
  437. portName.clear();
  438. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  439. {
  440. portName = pData->name;
  441. portName += ":";
  442. }
  443. portName += "events-out";
  444. portName.truncate(portNameSize);
  445. pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
  446. }
  447. // plugin hints
  448. const PluginCategory category = fPluginDescriptor->features != nullptr ? getPluginCategoryFromClapFeatures(fPluginDescriptor->features)
  449. : PLUGIN_CATEGORY_NONE;
  450. pData->hints = 0x0;
  451. if (category == PLUGIN_CATEGORY_SYNTH)
  452. pData->hints |= PLUGIN_IS_SYNTH;
  453. #ifdef CLAP_WINDOW_API_NATIVE
  454. if (const clap_plugin_gui_t* const guiExt = static_cast<const clap_plugin_gui_t*>(fPlugin->get_extension(fPlugin, CLAP_EXT_GUI)))
  455. {
  456. if (guiExt->is_api_supported != nullptr)
  457. {
  458. if (guiExt->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, false))
  459. {
  460. pData->hints |= PLUGIN_HAS_CUSTOM_UI;
  461. pData->hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
  462. }
  463. else if (guiExt->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, false))
  464. {
  465. pData->hints |= PLUGIN_HAS_CUSTOM_UI;
  466. }
  467. }
  468. }
  469. #endif
  470. if (aOuts > 0 && (aIns == aOuts || aIns == 1))
  471. pData->hints |= PLUGIN_CAN_DRYWET;
  472. if (aOuts > 0)
  473. pData->hints |= PLUGIN_CAN_VOLUME;
  474. if (aOuts >= 2 && aOuts % 2 == 0)
  475. pData->hints |= PLUGIN_CAN_BALANCE;
  476. // extra plugin hints
  477. pData->extraHints = 0x0;
  478. if (numNoteInputPorts > 0)
  479. pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN;
  480. if (numNoteOutputPorts > 0)
  481. pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_OUT;
  482. bufferSizeChanged(pData->engine->getBufferSize());
  483. reloadPrograms(true);
  484. if (pData->active)
  485. activate();
  486. carla_debug("CarlaPluginCLAP::reload() - end");
  487. }
  488. void reloadPrograms(const bool doInit) override
  489. {
  490. carla_debug("CarlaPluginCLAP::reloadPrograms(%s)", bool2str(doInit));
  491. }
  492. // -------------------------------------------------------------------
  493. // Plugin processing
  494. void activate() noexcept override
  495. {
  496. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  497. // FIXME check return status
  498. fPlugin->activate(fPlugin, pData->engine->getSampleRate(), 1, pData->engine->getBufferSize());
  499. fPlugin->start_processing(fPlugin);
  500. }
  501. void deactivate() noexcept override
  502. {
  503. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  504. // FIXME check return status
  505. fPlugin->stop_processing(fPlugin);
  506. fPlugin->deactivate(fPlugin);
  507. }
  508. void process(const float* const* const audioIn,
  509. float** const audioOut,
  510. const float* const* const cvIn,
  511. float** const,
  512. const uint32_t frames) override
  513. {
  514. // --------------------------------------------------------------------------------------------------------
  515. // Check if active
  516. if (! pData->active)
  517. {
  518. // disable any output sound
  519. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  520. carla_zeroFloats(audioOut[i], frames);
  521. return;
  522. }
  523. // --------------------------------------------------------------------------------------------------------
  524. // Check if needs reset
  525. if (pData->needsReset)
  526. {
  527. pData->needsReset = false;
  528. }
  529. // --------------------------------------------------------------------------------------------------------
  530. // Set TimeInfo
  531. const EngineTimeInfo timeInfo(pData->engine->getTimeInfo());
  532. // --------------------------------------------------------------------------------------------------------
  533. // Event Input and Processing
  534. if (pData->event.portIn != nullptr)
  535. {
  536. // ----------------------------------------------------------------------------------------------------
  537. // MIDI Input (External)
  538. if (pData->extNotes.mutex.tryLock())
  539. {
  540. pData->extNotes.data.clear();
  541. pData->extNotes.mutex.unlock();
  542. } // End of MIDI Input (External)
  543. // ----------------------------------------------------------------------------------------------------
  544. // Event Input (System)
  545. uint32_t startTime = 0;
  546. uint32_t timeOffset = 0;
  547. pData->postRtEvents.trySplice();
  548. if (frames > timeOffset)
  549. processSingle(audioIn, audioOut, frames - timeOffset, timeOffset);
  550. } // End of Event Input and Processing
  551. // --------------------------------------------------------------------------------------------------------
  552. // Plugin processing (no events)
  553. else
  554. {
  555. processSingle(audioIn, audioOut, frames, 0);
  556. } // End of Plugin processing (no events)
  557. // --------------------------------------------------------------------------------------------------------
  558. // MIDI Output
  559. if (pData->event.portOut != nullptr)
  560. {
  561. } // End of MIDI Output
  562. // --------------------------------------------------------------------------------------------------------
  563. #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
  564. return;
  565. // unused
  566. (void)cvIn;
  567. #endif
  568. }
  569. bool processSingle(const float* const* const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t timeOffset)
  570. {
  571. CARLA_SAFE_ASSERT_RETURN(frames > 0, false);
  572. if (pData->audioIn.count > 0)
  573. {
  574. CARLA_SAFE_ASSERT_RETURN(inBuffer != nullptr, false);
  575. }
  576. if (pData->audioOut.count > 0)
  577. {
  578. CARLA_SAFE_ASSERT_RETURN(outBuffer != nullptr, false);
  579. }
  580. // --------------------------------------------------------------------------------------------------------
  581. // Try lock, silence otherwise
  582. if (pData->engine->isOffline())
  583. {
  584. pData->singleMutex.lock();
  585. }
  586. else if (! pData->singleMutex.tryLock())
  587. {
  588. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  589. {
  590. for (uint32_t k=0; k < frames; ++k)
  591. outBuffer[i][k+timeOffset] = 0.0f;
  592. }
  593. return false;
  594. }
  595. // --------------------------------------------------------------------------------------------------------
  596. // Run plugin
  597. const clap_audio_buffer_const_t inBuffers[1] = {
  598. {
  599. inBuffer, // data32
  600. nullptr, // data64
  601. 1, // channel_count
  602. 0, // latency
  603. 0 // constant_mask;
  604. }
  605. };
  606. clap_audio_buffer_t outBuffers[1] = {
  607. {
  608. outBuffer, // data32
  609. nullptr, // data64
  610. 1, // channel_count
  611. 0, // latency
  612. 0 // constant_mask;
  613. }
  614. };
  615. const clap_process_t process = {
  616. 0, // steady_time
  617. frames,
  618. nullptr, // transport
  619. static_cast<const clap_audio_buffer_t*>(static_cast<const void*>(inBuffers)), // audio_inputs
  620. outBuffers, // audio_outputs
  621. 1, // audio_inputs_count
  622. 1, // audio_outputs_count
  623. nullptr, // in_events
  624. nullptr // out_events
  625. };
  626. fPlugin->process(fPlugin, &process);
  627. // fTimeInfo.samplePos += frames;
  628. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  629. // --------------------------------------------------------------------------------------------------------
  630. // Post-processing (dry/wet, volume and balance)
  631. {
  632. const bool doVolume = (pData->hints & PLUGIN_CAN_VOLUME) != 0 && carla_isNotEqual(pData->postProc.volume, 1.0f);
  633. const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f);
  634. const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f));
  635. const bool isMono = (pData->audioIn.count == 1);
  636. bool isPair;
  637. float bufValue, oldBufLeft[doBalance ? frames : 1];
  638. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  639. {
  640. // Dry/Wet
  641. if (doDryWet)
  642. {
  643. const uint32_t c = isMono ? 0 : i;
  644. for (uint32_t k=0; k < frames; ++k)
  645. {
  646. bufValue = inBuffer[c][k];
  647. outBuffer[i][k] = (outBuffer[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet));
  648. }
  649. }
  650. // Balance
  651. if (doBalance)
  652. {
  653. isPair = (i % 2 == 0);
  654. if (isPair)
  655. {
  656. CARLA_ASSERT(i+1 < pData->audioOut.count);
  657. carla_copyFloats(oldBufLeft, outBuffer[i], frames);
  658. }
  659. float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f;
  660. float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f;
  661. for (uint32_t k=0; k < frames; ++k)
  662. {
  663. if (isPair)
  664. {
  665. // left
  666. outBuffer[i][k] = oldBufLeft[k] * (1.0f - balRangeL);
  667. outBuffer[i][k] += outBuffer[i+1][k] * (1.0f - balRangeR);
  668. }
  669. else
  670. {
  671. // right
  672. outBuffer[i][k] = outBuffer[i][k] * balRangeR;
  673. outBuffer[i][k] += oldBufLeft[k] * balRangeL;
  674. }
  675. }
  676. }
  677. // Volume
  678. if (doVolume)
  679. {
  680. for (uint32_t k=0; k < frames; ++k)
  681. outBuffer[i][k] *= pData->postProc.volume;
  682. }
  683. }
  684. } // End of Post-processing
  685. #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH
  686. // --------------------------------------------------------------------------------------------------------
  687. pData->singleMutex.unlock();
  688. return true;
  689. }
  690. void bufferSizeChanged(const uint32_t newBufferSize) override
  691. {
  692. CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize);
  693. carla_debug("CarlaPluginCLAP::bufferSizeChanged(%i)", newBufferSize);
  694. if (pData->active)
  695. deactivate();
  696. if (pData->active)
  697. activate();
  698. }
  699. void sampleRateChanged(const double newSampleRate) override
  700. {
  701. CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate);
  702. carla_debug("CarlaPluginCLAP::sampleRateChanged(%g)", newSampleRate);
  703. if (pData->active)
  704. deactivate();
  705. if (pData->active)
  706. activate();
  707. }
  708. // -------------------------------------------------------------------
  709. // Plugin buffers
  710. void clearBuffers() noexcept override
  711. {
  712. carla_debug("CarlaPluginCLAP::clearBuffers() - start");
  713. CarlaPlugin::clearBuffers();
  714. carla_debug("CarlaPluginCLAP::clearBuffers() - end");
  715. }
  716. // -------------------------------------------------------------------
  717. // Post-poned UI Stuff
  718. // nothing
  719. // -------------------------------------------------------------------
  720. protected:
  721. void handlePluginUIClosed() override
  722. {
  723. // CARLA_SAFE_ASSERT_RETURN(fUI.window != nullptr,);
  724. carla_debug("CarlaPluginCLAP::handlePluginUIClosed()");
  725. showCustomUI(false);
  726. pData->engine->callback(true, true,
  727. ENGINE_CALLBACK_UI_STATE_CHANGED,
  728. pData->id,
  729. 0,
  730. 0, 0, 0.0f, nullptr);
  731. }
  732. void handlePluginUIResized(const uint width, const uint height) override
  733. {
  734. // CARLA_SAFE_ASSERT_RETURN(fUI.window != nullptr,);
  735. carla_debug("CarlaPluginCLAP::handlePluginUIResized(%u, %u)", width, height);
  736. }
  737. // -------------------------------------------------------------------
  738. public:
  739. bool init(const CarlaPluginPtr plugin,
  740. const char* const filename, const char* const name, const char* const id, const uint options)
  741. {
  742. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
  743. // ---------------------------------------------------------------
  744. // first checks
  745. if (pData->client != nullptr)
  746. {
  747. pData->engine->setLastError("Plugin client is already registered");
  748. return false;
  749. }
  750. if (filename == nullptr || filename[0] == '\0')
  751. {
  752. pData->engine->setLastError("null filename");
  753. return false;
  754. }
  755. if (id == nullptr || id[0] == '\0')
  756. {
  757. pData->engine->setLastError("null label/id");
  758. return false;
  759. }
  760. // ---------------------------------------------------------------
  761. const clap_plugin_entry_t* entry;
  762. #ifdef CARLA_OS_MAC
  763. if (!water::File(filename).existsAsFile())
  764. {
  765. if (! fBundleLoader.load(filename))
  766. {
  767. pData->engine->setLastError("Failed to load CLAP bundle executable");
  768. return false;
  769. }
  770. entry = fBundleLoader.getSymbol<const clap_plugin_entry_t*>(CFSTR("clap_entry"));
  771. }
  772. else
  773. #endif
  774. {
  775. if (! pData->libOpen(filename))
  776. {
  777. pData->engine->setLastError(pData->libError(filename));
  778. return false;
  779. }
  780. entry = pData->libSymbol<const clap_plugin_entry_t*>("clap_entry");
  781. }
  782. if (entry == nullptr)
  783. {
  784. pData->engine->setLastError("Could not find the CLAP entry in the plugin library");
  785. return false;
  786. }
  787. if (entry->init == nullptr || entry->deinit == nullptr || entry->get_factory == nullptr)
  788. {
  789. pData->engine->setLastError("CLAP factory entries are null");
  790. return false;
  791. }
  792. if (!clap_version_is_compatible(entry->clap_version))
  793. {
  794. pData->engine->setLastError("Incompatible CLAP plugin");
  795. return false;
  796. }
  797. // ---------------------------------------------------------------
  798. const water::String pluginPath(water::File(filename).getParentDirectory().getFullPathName());
  799. if (!entry->init(pluginPath.toRawUTF8()))
  800. {
  801. pData->engine->setLastError("Plugin entry failed to initialize");
  802. return false;
  803. }
  804. fPluginEntry = entry;
  805. // ---------------------------------------------------------------
  806. const clap_plugin_factory_t* const factory = static_cast<const clap_plugin_factory_t*>(
  807. entry->get_factory(CLAP_PLUGIN_FACTORY_ID));
  808. if (factory == nullptr
  809. || factory->get_plugin_count == nullptr
  810. || factory->get_plugin_descriptor == nullptr
  811. || factory->create_plugin == nullptr)
  812. {
  813. pData->engine->setLastError("Plugin is missing factory methods");
  814. return false;
  815. }
  816. // ---------------------------------------------------------------
  817. if (const uint32_t count = factory->get_plugin_count(factory))
  818. {
  819. for (uint32_t i=0; i<count; ++i)
  820. {
  821. const clap_plugin_descriptor_t* const desc = factory->get_plugin_descriptor(factory, i);
  822. CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr);
  823. CARLA_SAFE_ASSERT_CONTINUE(desc->id != nullptr);
  824. if (std::strcmp(desc->id, id) == 0)
  825. {
  826. fPluginDescriptor = desc;
  827. break;
  828. }
  829. }
  830. }
  831. else
  832. {
  833. pData->engine->setLastError("Plugin library contains no plugins");
  834. return false;
  835. }
  836. if (fPluginDescriptor == nullptr)
  837. {
  838. pData->engine->setLastError("Plugin library does not contain the requested plugin");
  839. return false;
  840. }
  841. // ---------------------------------------------------------------
  842. fPlugin = factory->create_plugin(factory, &fHost, fPluginDescriptor->id);
  843. if (fPlugin == nullptr)
  844. {
  845. pData->engine->setLastError("Failed to create CLAP plugin instance");
  846. return false;
  847. }
  848. if (!fPlugin->init(fPlugin))
  849. {
  850. pData->engine->setLastError("Failed to initialize CLAP plugin instance");
  851. return false;
  852. }
  853. // ---------------------------------------------------------------
  854. // get info
  855. pData->name = pData->engine->getUniquePluginName(name != nullptr && name[0] != '\0'
  856. ? name
  857. : fPluginDescriptor->name);
  858. pData->filename = carla_strdup(filename);
  859. // ---------------------------------------------------------------
  860. // register client
  861. pData->client = pData->engine->addClient(plugin);
  862. if (pData->client == nullptr || ! pData->client->isOk())
  863. {
  864. pData->engine->setLastError("Failed to register plugin client");
  865. return false;
  866. }
  867. // ---------------------------------------------------------------
  868. // set default options
  869. pData->options = 0x0;
  870. // if (fEffect->initialDelay > 0 || hasMidiOutput() || isPluginOptionEnabled(options, PLUGIN_OPTION_FIXED_BUFFERS))
  871. // pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
  872. //
  873. // if (fEffect->flags & effFlagsProgramChunks)
  874. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_USE_CHUNKS))
  875. // pData->options |= PLUGIN_OPTION_USE_CHUNKS;
  876. //
  877. // if (hasMidiInput())
  878. // {
  879. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CONTROL_CHANGES))
  880. // pData->options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  881. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CHANNEL_PRESSURE))
  882. // pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  883. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH))
  884. // pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  885. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PITCHBEND))
  886. // pData->options |= PLUGIN_OPTION_SEND_PITCHBEND;
  887. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_ALL_SOUND_OFF))
  888. // pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  889. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PROGRAM_CHANGES))
  890. // pData->options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
  891. // if (isPluginOptionInverseEnabled(options, PLUGIN_OPTION_SKIP_SENDING_NOTES))
  892. // pData->options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
  893. // }
  894. //
  895. // if (fEffect->numPrograms > 1 && (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES) == 0)
  896. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_MAP_PROGRAM_CHANGES))
  897. // pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
  898. return true;
  899. }
  900. private:
  901. const clap_plugin_t* fPlugin;
  902. const clap_plugin_descriptor_t* fPluginDescriptor;
  903. const clap_plugin_entry_t* fPluginEntry;
  904. const carla_clap_host fHost;
  905. struct Extensions {
  906. const clap_plugin_params_t* params;
  907. Extensions()
  908. : params(nullptr) {}
  909. CARLA_DECLARE_NON_COPYABLE(Extensions)
  910. } fExtensions;
  911. #ifdef CARLA_OS_MAC
  912. BundleLoader fBundleLoader;
  913. #endif
  914. };
  915. // --------------------------------------------------------------------------------------------------------------------
  916. CarlaPluginPtr CarlaPlugin::newCLAP(const Initializer& init)
  917. {
  918. carla_debug("CarlaPlugin::newCLAP({%p, \"%s\", \"%s\", \"%s\"})",
  919. init.engine, init.filename, init.name, init.label);
  920. std::shared_ptr<CarlaPluginCLAP> plugin(new CarlaPluginCLAP(init.engine, init.id));
  921. if (! plugin->init(plugin, init.filename, init.name, init.label, init.options))
  922. return nullptr;
  923. return plugin;
  924. }
  925. // -------------------------------------------------------------------------------------------------------------------
  926. CARLA_BACKEND_END_NAMESPACE