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.

2489 lines
83KB

  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. // FIXME
  29. // #ifndef CLAP_WINDOW_API_NATIVE
  30. // #define CLAP_WINDOW_API_NATIVE ""
  31. // #define HAVE_X11 1
  32. // #endif
  33. CARLA_BACKEND_START_NAMESPACE
  34. // --------------------------------------------------------------------------------------------------------------------
  35. struct ClapEventData {
  36. uint16_t clapPortIndex;
  37. CarlaEngineEventPort* port;
  38. };
  39. struct CarlaPluginClapEventData {
  40. uint32_t portCount;
  41. ClapEventData* portData;
  42. ClapEventData* defaultPort; // either this->portData[x] or pData->portIn/Out
  43. CarlaPluginClapEventData() noexcept
  44. : portCount(0),
  45. portData(nullptr),
  46. defaultPort(nullptr) {}
  47. ~CarlaPluginClapEventData() noexcept
  48. {
  49. CARLA_SAFE_ASSERT_INT(portCount == 0, portCount);
  50. CARLA_SAFE_ASSERT(portData == nullptr);
  51. CARLA_SAFE_ASSERT(defaultPort == nullptr);
  52. }
  53. void createNew(const uint32_t newCount)
  54. {
  55. CARLA_SAFE_ASSERT_INT(portCount == 0, portCount);
  56. CARLA_SAFE_ASSERT_RETURN(portData == nullptr,);
  57. CARLA_SAFE_ASSERT_RETURN(defaultPort == nullptr,);
  58. CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
  59. portData = new ClapEventData[newCount];
  60. portCount = newCount;
  61. defaultPort = nullptr;
  62. }
  63. void clear(CarlaEngineEventPort* const portToIgnore) noexcept
  64. {
  65. if (portData != nullptr)
  66. {
  67. for (uint32_t i=0; i < portCount; ++i)
  68. {
  69. if (portData[i].port != nullptr)
  70. {
  71. if (portData[i].port != portToIgnore)
  72. delete portData[i].port;
  73. portData[i].port = nullptr;
  74. }
  75. }
  76. delete[] portData;
  77. portData = nullptr;
  78. }
  79. portCount = 0;
  80. defaultPort = nullptr;
  81. }
  82. void initBuffers() const noexcept
  83. {
  84. for (uint32_t i=0; i < portCount; ++i)
  85. {
  86. if (portData[i].port != nullptr && (defaultPort == nullptr || portData[i].port != defaultPort->port))
  87. portData[i].port->initBuffer();
  88. }
  89. }
  90. CARLA_DECLARE_NON_COPYABLE(CarlaPluginClapEventData)
  91. };
  92. // --------------------------------------------------------------------------------------------------------------------
  93. struct carla_clap_host : clap_host_t {
  94. class Callback {
  95. public:
  96. virtual ~Callback() {}
  97. virtual void hostRequestResize(uint width, uint height) = 0;
  98. };
  99. Callback* const uiCallback;
  100. clap_host_gui_t gui;
  101. clap_host_timer_support_t timer;
  102. // TESTING
  103. clap_id inUseTimerId;
  104. carla_clap_host(Callback* const uiCb)
  105. : uiCallback(uiCb)
  106. {
  107. clap_version = CLAP_VERSION;
  108. host_data = this;
  109. name = "Carla";
  110. vendor = "falkTX";
  111. url = "https://kx.studio/carla";
  112. version = CARLA_VERSION_STRING;
  113. get_extension = carla_get_extension;
  114. request_restart = carla_request_restart;
  115. request_process = carla_request_process;
  116. request_callback = carla_request_callback;
  117. gui.resize_hints_changed = carla_resize_hints_changed;
  118. gui.request_resize = carla_request_resize;
  119. gui.request_show = carla_request_show;
  120. gui.request_hide = carla_request_hide;
  121. gui.closed = carla_closed;
  122. timer.register_timer = carla_register_timer;
  123. timer.unregister_timer = carla_unregister_timer;
  124. // TESTING
  125. inUseTimerId = CLAP_INVALID_ID;
  126. }
  127. static const void* carla_get_extension(const clap_host_t* const host, const char* const extension_id)
  128. {
  129. const carla_clap_host* const self = static_cast<const carla_clap_host*>(host->host_data);
  130. if (std::strcmp(extension_id, CLAP_EXT_GUI) == 0)
  131. return &self->gui;
  132. if (std::strcmp(extension_id, CLAP_EXT_TIMER_SUPPORT) == 0)
  133. return &self->timer;
  134. return nullptr;
  135. }
  136. static void carla_request_restart(const clap_host_t*) {}
  137. static void carla_request_process(const clap_host_t*) {}
  138. static void carla_request_callback(const clap_host_t*) {}
  139. static void carla_resize_hints_changed(const clap_host_t *host) {}
  140. static bool carla_request_resize(const clap_host_t* const host, const uint32_t width, const uint32_t height)
  141. {
  142. const carla_clap_host* const self = static_cast<const carla_clap_host*>(host->host_data);
  143. self->uiCallback->hostRequestResize(width, height);
  144. return true;
  145. }
  146. static bool carla_request_show(const clap_host_t *host) { return false; }
  147. static bool carla_request_hide(const clap_host_t *host) { return false; }
  148. static void carla_closed(const clap_host_t *host, bool was_destroyed) {}
  149. static bool carla_register_timer(const clap_host_t* const host, uint32_t /*period_ms*/, clap_id* const timer_id)
  150. {
  151. carla_clap_host* const self = static_cast<carla_clap_host*>(host->host_data);
  152. if (self->inUseTimerId != CLAP_INVALID_ID)
  153. return false;
  154. self->inUseTimerId = *timer_id = 1;
  155. return true;
  156. }
  157. static bool carla_unregister_timer(const clap_host_t* const host, const clap_id timer_id)
  158. {
  159. carla_clap_host* const self = static_cast<carla_clap_host*>(host->host_data);
  160. if (self->inUseTimerId == CLAP_INVALID_ID)
  161. return false;
  162. if (self->inUseTimerId != timer_id)
  163. return false;
  164. self->inUseTimerId = CLAP_INVALID_ID;
  165. return true;
  166. }
  167. };
  168. // --------------------------------------------------------------------------------------------------------------------
  169. struct carla_clap_input_audio_buffers {
  170. clap_audio_buffer_const_with_offset_t* buffers;
  171. uint32_t count;
  172. carla_clap_input_audio_buffers() noexcept
  173. : buffers(nullptr),
  174. count(0) {}
  175. ~carla_clap_input_audio_buffers()
  176. {
  177. delete[] buffers;
  178. }
  179. void realloc(const uint32_t portCount)
  180. {
  181. delete[] buffers;
  182. count = portCount;
  183. if (portCount != 0)
  184. {
  185. buffers = new clap_audio_buffer_const_with_offset_t[portCount];
  186. carla_zeroStructs(buffers, portCount);
  187. }
  188. else
  189. {
  190. buffers = nullptr;
  191. }
  192. }
  193. const clap_audio_buffer_t* cast() const noexcept
  194. {
  195. return static_cast<const clap_audio_buffer_t*>(static_cast<const void*>(buffers));
  196. }
  197. };
  198. struct carla_clap_output_audio_buffers {
  199. clap_audio_buffer_with_offset_t* buffers;
  200. uint32_t count;
  201. carla_clap_output_audio_buffers() noexcept
  202. : buffers(nullptr),
  203. count(0) {}
  204. ~carla_clap_output_audio_buffers()
  205. {
  206. delete[] buffers;
  207. }
  208. void realloc(const uint32_t portCount)
  209. {
  210. delete[] buffers;
  211. count = portCount;
  212. if (portCount != 0)
  213. {
  214. buffers = new clap_audio_buffer_with_offset_t[portCount];
  215. carla_zeroStructs(buffers, portCount);
  216. }
  217. else
  218. {
  219. buffers = nullptr;
  220. }
  221. }
  222. clap_audio_buffer_t* cast() noexcept
  223. {
  224. return static_cast<clap_audio_buffer_t*>(static_cast<void*>(buffers));
  225. }
  226. };
  227. // --------------------------------------------------------------------------------------------------------------------
  228. struct carla_clap_input_events : clap_input_events_t, CarlaPluginClapEventData {
  229. union Event {
  230. clap_event_header_t header;
  231. clap_event_param_value_t param;
  232. clap_event_param_gesture_t gesture;
  233. clap_event_midi_t midi;
  234. clap_event_midi_sysex_t sysex;
  235. };
  236. struct ScheduledParameterUpdate {
  237. bool updated;
  238. double value;
  239. clap_id clapId;
  240. void* cookie;
  241. ScheduledParameterUpdate()
  242. : updated(false),
  243. value(0.f),
  244. clapId(0),
  245. cookie(0) {}
  246. };
  247. Event* events;
  248. ScheduledParameterUpdate* updatedParams;
  249. uint32_t numEventsAllocated;
  250. uint32_t numEventsUsed;
  251. uint32_t numParams;
  252. carla_clap_input_events()
  253. : CarlaPluginClapEventData(),
  254. events(nullptr),
  255. updatedParams(nullptr),
  256. numEventsAllocated(0),
  257. numEventsUsed(0),
  258. numParams(0)
  259. {
  260. ctx = this;
  261. size = carla_size;
  262. get = carla_get;
  263. }
  264. ~carla_clap_input_events()
  265. {
  266. delete[] events;
  267. delete[] updatedParams;
  268. }
  269. // called on plugin reload
  270. // NOTE: clapId and cookie must be separately set outside this function
  271. void realloc(CarlaEngineEventPort* const defPortIn, const uint32_t portCount, const uint32_t paramCount)
  272. {
  273. numEventsUsed = 0;
  274. numParams = paramCount;
  275. delete[] events;
  276. delete[] updatedParams;
  277. if (paramCount != 0)
  278. {
  279. static_assert(kPluginMaxMidiEvents > MAX_MIDI_NOTE, "Enough space for input events");
  280. numEventsAllocated = paramCount * 2 + kPluginMaxMidiEvents * std::max(1u, portCount);
  281. events = new Event[numEventsAllocated];
  282. updatedParams = new ScheduledParameterUpdate[paramCount];
  283. }
  284. else
  285. {
  286. numEventsAllocated = 0;
  287. events = nullptr;
  288. updatedParams = nullptr;
  289. }
  290. CarlaPluginClapEventData::clear(defPortIn);
  291. if (portCount != 0)
  292. CarlaPluginClapEventData::createNew(portCount);
  293. }
  294. // called just before plugin processing
  295. void handleScheduledParameterUpdates()
  296. {
  297. uint32_t count = 0;
  298. for (uint32_t i=0; i<numParams; ++i)
  299. {
  300. if (updatedParams[i].updated)
  301. {
  302. events[count++].param = {
  303. { sizeof(clap_event_param_value_t), 0, 0, CLAP_EVENT_PARAM_VALUE, 0 },
  304. updatedParams[i].clapId,
  305. updatedParams[i].cookie,
  306. -1, -1, -1, -1,
  307. updatedParams[i].value
  308. };
  309. updatedParams[i].updated = false;
  310. }
  311. }
  312. numEventsUsed = count;
  313. }
  314. // called when a parameter is set from non-rt thread
  315. void setParamValue(const uint32_t index, const float value) noexcept
  316. {
  317. CARLA_SAFE_ASSERT_RETURN(index < numParams,);
  318. updatedParams[index].value = value;
  319. updatedParams[index].updated = true;
  320. }
  321. // called when a parameter is set from rt thread
  322. void setParamValueRT(const uint32_t index, const float value, const uint32_t frameOffset) noexcept
  323. {
  324. CARLA_SAFE_ASSERT_RETURN(index < numParams,);
  325. if (numEventsUsed == numEventsAllocated)
  326. return;
  327. events[numEventsUsed++].param = {
  328. { sizeof(clap_event_param_value_t), frameOffset, 0, CLAP_EVENT_PARAM_VALUE, CLAP_EVENT_IS_LIVE },
  329. updatedParams[index].clapId,
  330. updatedParams[index].cookie,
  331. -1, -1, -1, -1,
  332. value
  333. };
  334. }
  335. void addSimpleMidiEvent(const bool isLive, const uint16_t port, const uint32_t frameOffset, const uint8_t data[3])
  336. {
  337. if (numEventsUsed == numEventsAllocated)
  338. return;
  339. events[numEventsUsed++].midi = {
  340. { sizeof(clap_event_midi_t), frameOffset, 0, CLAP_EVENT_MIDI, isLive ? (uint32_t)CLAP_EVENT_IS_LIVE : 0u },
  341. port,
  342. { data[0], data[1], data[2] }
  343. };
  344. }
  345. static uint32_t carla_size(const clap_input_events_t* const list) noexcept
  346. {
  347. return static_cast<const carla_clap_input_events*>(list->ctx)->numEventsUsed;
  348. }
  349. static const clap_event_header_t* carla_get(const clap_input_events_t* const list, const uint32_t index) noexcept
  350. {
  351. return &static_cast<const carla_clap_input_events*>(list->ctx)->events[index].header;
  352. }
  353. };
  354. // --------------------------------------------------------------------------------------------------------------------
  355. struct carla_clap_output_events : clap_output_events_t, CarlaPluginClapEventData {
  356. union Event {
  357. clap_event_header_t header;
  358. clap_event_param_value_t param;
  359. clap_event_midi_t midi;
  360. };
  361. Event* events;
  362. uint32_t numEventsAllocated;
  363. uint32_t numEventsUsed;
  364. carla_clap_output_events()
  365. : events(nullptr),
  366. numEventsAllocated(0),
  367. numEventsUsed(0)
  368. {
  369. ctx = this;
  370. try_push = carla_try_push;
  371. }
  372. ~carla_clap_output_events()
  373. {
  374. delete[] events;
  375. }
  376. // called on plugin reload
  377. void realloc(CarlaEngineEventPort* const defPortOut, const uint32_t portCount, const uint32_t paramCount)
  378. {
  379. numEventsUsed = 0;
  380. delete[] events;
  381. if (paramCount != 0)
  382. {
  383. numEventsAllocated = paramCount + kPluginMaxMidiEvents * std::max(1u, portCount);
  384. events = new Event[numEventsAllocated];
  385. }
  386. else
  387. {
  388. numEventsAllocated = 0;
  389. events = nullptr;
  390. }
  391. CarlaPluginClapEventData::clear(defPortOut);
  392. if (portCount != 0)
  393. CarlaPluginClapEventData::createNew(portCount);
  394. }
  395. bool tryPush(const clap_event_header_t* const event)
  396. {
  397. if (numEventsUsed == numEventsAllocated)
  398. return false;
  399. Event e;
  400. switch (event->type)
  401. {
  402. case CLAP_EVENT_PARAM_VALUE:
  403. e.param = *static_cast<const clap_event_param_value_t*>(static_cast<const void*>(event));
  404. break;
  405. case CLAP_EVENT_MIDI:
  406. e.midi = *static_cast<const clap_event_midi_t*>(static_cast<const void*>(event));
  407. break;
  408. default:
  409. return false;
  410. }
  411. events[numEventsUsed++] = e;
  412. return true;
  413. }
  414. static bool carla_try_push(const clap_output_events_t* const list, const clap_event_header_t* const event)
  415. {
  416. return static_cast<carla_clap_output_events*>(list->ctx)->tryPush(event);
  417. }
  418. };
  419. // --------------------------------------------------------------------------------------------------------------------
  420. class CarlaPluginCLAP : public CarlaPlugin,
  421. private CarlaPluginUI::Callback,
  422. private carla_clap_host::Callback
  423. {
  424. public:
  425. CarlaPluginCLAP(CarlaEngine* const engine, const uint id)
  426. : CarlaPlugin(engine, id),
  427. fPlugin(nullptr),
  428. fPluginDescriptor(nullptr),
  429. fPluginEntry(nullptr),
  430. fHost(this),
  431. fExtensions(),
  432. fInputAudioBuffers(),
  433. fOutputAudioBuffers(),
  434. fInputEvents(),
  435. fOutputEvents()
  436. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  437. , fAudioOutBuffers(nullptr)
  438. #endif
  439. {
  440. carla_debug("CarlaPluginCLAP::CarlaPluginCLAP(%p, %i)", engine, id);
  441. }
  442. ~CarlaPluginCLAP() override
  443. {
  444. carla_debug("CarlaPluginCLAP::~CarlaPluginCLAP()");
  445. #ifdef CLAP_WINDOW_API_NATIVE
  446. // close UI
  447. if (fUI.isCreated)
  448. showCustomUI(false);
  449. #endif
  450. pData->singleMutex.lock();
  451. pData->masterMutex.lock();
  452. if (pData->client != nullptr && pData->client->isActive())
  453. pData->client->deactivate(true);
  454. if (pData->active)
  455. {
  456. deactivate();
  457. pData->active = false;
  458. }
  459. if (fPlugin != nullptr)
  460. {
  461. fPlugin->destroy(fPlugin);
  462. fPlugin = nullptr;
  463. }
  464. clearBuffers();
  465. if (fPluginEntry != nullptr)
  466. {
  467. fPluginEntry->deinit();
  468. fPluginEntry = nullptr;
  469. }
  470. }
  471. // -------------------------------------------------------------------
  472. // Information (base)
  473. PluginType getType() const noexcept override
  474. {
  475. return PLUGIN_CLAP;
  476. }
  477. PluginCategory getCategory() const noexcept override
  478. {
  479. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, PLUGIN_CATEGORY_NONE);
  480. if (fPluginDescriptor->features == nullptr)
  481. return PLUGIN_CATEGORY_NONE;
  482. return getPluginCategoryFromClapFeatures(fPluginDescriptor->features);
  483. }
  484. /*
  485. uint32_t getLatencyInFrames() const noexcept override
  486. {
  487. }
  488. */
  489. // -------------------------------------------------------------------
  490. // Information (count)
  491. uint32_t getMidiInCount() const noexcept override
  492. {
  493. return fInputEvents.portCount;
  494. }
  495. uint32_t getMidiOutCount() const noexcept override
  496. {
  497. return fOutputEvents.portCount;
  498. }
  499. // -------------------------------------------------------------------
  500. // Information (current data)
  501. uint getAudioPortHints(const bool isOutput, const uint32_t portIndex) const noexcept override
  502. {
  503. uint hints = 0x0;
  504. if (isOutput)
  505. {
  506. for (uint32_t i=0, j=0; i<fOutputAudioBuffers.count; ++i, j+=fOutputAudioBuffers.buffers[i].channel_count)
  507. {
  508. if (j != portIndex)
  509. continue;
  510. if (!fOutputAudioBuffers.buffers[i].isMain)
  511. hints |= AUDIO_PORT_IS_SIDECHAIN;
  512. }
  513. }
  514. else
  515. {
  516. for (uint32_t i=0, j=0; i<fInputAudioBuffers.count; ++i, j+=fInputAudioBuffers.buffers[i].channel_count)
  517. {
  518. if (j != portIndex)
  519. continue;
  520. if (!fInputAudioBuffers.buffers[i].isMain)
  521. hints |= AUDIO_PORT_IS_SIDECHAIN;
  522. }
  523. }
  524. return hints;
  525. }
  526. /*
  527. std::size_t getChunkData(void** const dataPtr) noexcept override
  528. {
  529. }
  530. */
  531. // -------------------------------------------------------------------
  532. // Information (per-plugin data)
  533. uint getOptionsAvailable() const noexcept override
  534. {
  535. uint options = PLUGIN_OPTION_USE_CHUNKS;
  536. if (fInputEvents.portCount != 0)
  537. {
  538. options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  539. options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  540. options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  541. options |= PLUGIN_OPTION_SEND_PITCHBEND;
  542. options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  543. options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
  544. options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
  545. }
  546. return options;
  547. }
  548. float getParameterValue(const uint32_t parameterId) const noexcept override
  549. {
  550. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, 0.f);
  551. CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, 0.f);
  552. const clap_id clapId = pData->param.data[parameterId].rindex;
  553. double value;
  554. CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_value(fPlugin, clapId, &value), 0.f);
  555. return value;
  556. }
  557. bool getLabel(char* const strBuf) const noexcept override
  558. {
  559. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, false);
  560. std::strncpy(strBuf, fPluginDescriptor->id, STR_MAX);
  561. return true;
  562. }
  563. bool getMaker(char* const strBuf) const noexcept override
  564. {
  565. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, false);
  566. std::strncpy(strBuf, fPluginDescriptor->vendor, STR_MAX);
  567. return true;
  568. }
  569. bool getCopyright(char* const strBuf) const noexcept override
  570. {
  571. return getMaker(strBuf);
  572. }
  573. bool getRealName(char* const strBuf) const noexcept override
  574. {
  575. CARLA_SAFE_ASSERT_RETURN(fPluginDescriptor != nullptr, false);
  576. std::strncpy(strBuf, fPluginDescriptor->name, STR_MAX);
  577. return true;
  578. }
  579. bool getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override
  580. {
  581. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, false);
  582. CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, false);
  583. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  584. const clap_id clapId = pData->param.data[parameterId].rindex;
  585. clap_param_info_t paramInfo = {};
  586. CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_info(fPlugin, clapId, &paramInfo), false);
  587. std::strncpy(strBuf, paramInfo.name, STR_MAX);
  588. return true;
  589. }
  590. bool getParameterSymbol(const uint32_t parameterId, char* const strBuf) const noexcept override
  591. {
  592. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  593. const clap_id clapId = pData->param.data[parameterId].rindex;
  594. std::snprintf(strBuf, STR_MAX, "%u", clapId);
  595. return true;
  596. }
  597. bool getParameterText(const uint32_t parameterId, char* const strBuf) noexcept override
  598. {
  599. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, false);
  600. CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, false);
  601. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  602. const clap_id clapId = pData->param.data[parameterId].rindex;
  603. double value;
  604. CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_value(fPlugin, clapId, &value), false);
  605. return fExtensions.params->value_to_text(fPlugin, clapId, value, strBuf, STR_MAX);
  606. }
  607. bool getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept override
  608. {
  609. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr, false);
  610. CARLA_SAFE_ASSERT_RETURN(fExtensions.params != nullptr, false);
  611. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  612. const clap_id clapId = pData->param.data[parameterId].rindex;
  613. clap_param_info_t paramInfo = {};
  614. CARLA_SAFE_ASSERT_RETURN(fExtensions.params->get_info(fPlugin, clapId, &paramInfo), false);
  615. if (paramInfo.module[0] == '\0')
  616. return false;
  617. if (char* const sep = std::strrchr(paramInfo.module, '/'))
  618. {
  619. paramInfo.module[STR_MAX/2-2] = sep[0] = '\0';
  620. std::snprintf(strBuf, STR_MAX, "%s:%s", paramInfo.module, paramInfo.module);
  621. return true;
  622. }
  623. return false;
  624. }
  625. // -------------------------------------------------------------------
  626. // Set data (state)
  627. // nothing
  628. // -------------------------------------------------------------------
  629. // Set data (internal stuff)
  630. #ifdef CLAP_WINDOW_API_NATIVE
  631. void setName(const char* const newName) override
  632. {
  633. CarlaPlugin::setName(newName);
  634. if (fUI.isCreated && pData->uiTitle.isEmpty())
  635. setWindowTitle(nullptr);
  636. }
  637. #endif
  638. // -------------------------------------------------------------------
  639. // Set data (plugin-specific stuff)
  640. void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
  641. {
  642. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  643. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  644. const float fixedValue = pData->param.getFixedValue(parameterId, value);
  645. fInputEvents.setParamValue(parameterId, fixedValue);
  646. CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
  647. }
  648. void setParameterValueRT(const uint32_t parameterId, const float value, const uint32_t frameOffset, const bool sendCallbackLater) noexcept override
  649. {
  650. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  651. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  652. const float fixedValue = pData->param.getFixedValue(parameterId, value);
  653. fInputEvents.setParamValueRT(parameterId, fixedValue, frameOffset);
  654. CarlaPlugin::setParameterValueRT(parameterId, fixedValue, frameOffset, sendCallbackLater);
  655. }
  656. /*
  657. void setChunkData(const void* const data, const std::size_t dataSize) override
  658. {
  659. }
  660. void setProgram(const int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback, const bool doingInit) noexcept override
  661. {
  662. }
  663. void setProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept override
  664. {
  665. }
  666. */
  667. // -------------------------------------------------------------------
  668. // Set ui stuff
  669. #ifdef CLAP_WINDOW_API_NATIVE
  670. void setWindowTitle(const char* const title) noexcept
  671. {
  672. if (!fUI.isCreated)
  673. return;
  674. CarlaString uiTitle;
  675. if (title != nullptr)
  676. {
  677. uiTitle = title;
  678. }
  679. else
  680. {
  681. uiTitle = pData->name;
  682. uiTitle += " (GUI)";
  683. }
  684. if (fUI.isEmbed)
  685. {
  686. if (fUI.window != nullptr)
  687. fUI.window->setTitle(uiTitle.buffer());
  688. }
  689. else
  690. {
  691. fExtensions.gui->suggest_title(fPlugin, uiTitle.buffer());
  692. }
  693. }
  694. void setCustomUITitle(const char* const title) noexcept override
  695. {
  696. setWindowTitle(title);
  697. CarlaPlugin::setCustomUITitle(title);
  698. }
  699. void showCustomUI(const bool yesNo) override
  700. {
  701. CARLA_SAFE_ASSERT_RETURN(fExtensions.gui != nullptr,);
  702. if (yesNo)
  703. {
  704. if (fUI.isVisible)
  705. {
  706. fExtensions.gui->show(fPlugin);
  707. if (fUI.isEmbed)
  708. {
  709. CARLA_SAFE_ASSERT_RETURN(fUI.window != nullptr,);
  710. fUI.window->show();
  711. fUI.window->focus();
  712. }
  713. return;
  714. }
  715. const EngineOptions& opts(pData->engine->getOptions());
  716. if (!fUI.initalized)
  717. {
  718. fUI.isEmbed = fExtensions.gui->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, false);
  719. fUI.initalized = true;
  720. }
  721. if (!fUI.isCreated)
  722. {
  723. if (!fExtensions.gui->create(fPlugin, CLAP_WINDOW_API_NATIVE, !fUI.isEmbed))
  724. {
  725. pData->engine->callback(true, true,
  726. ENGINE_CALLBACK_UI_STATE_CHANGED,
  727. pData->id,
  728. -1,
  729. 0, 0, 0.0f,
  730. "Plugin refused to open its own UI");
  731. return;
  732. }
  733. fUI.isCreated = true;
  734. }
  735. const bool resizable = fExtensions.gui->can_resize(fPlugin);
  736. #if defined(CARLA_OS_WIN)
  737. fUI.window = CarlaPluginUI::newWindows(this, opts.frontendWinId, opts.pluginsAreStandalone, resizable);
  738. #elif defined(CARLA_OS_MAC)
  739. fUI.window = CarlaPluginUI::newCocoa(this, opts.frontendWinId, opts.pluginsAreStandalone, resizable);
  740. #elif defined(HAVE_X11)
  741. fUI.window = CarlaPluginUI::newX11(this, opts.frontendWinId, opts.pluginsAreStandalone, resizable, false);
  742. #else
  743. #error why is CLAP_WINDOW_API_NATIVE defined??
  744. #endif
  745. if (carla_isNotZero(opts.uiScale))
  746. fExtensions.gui->set_scale(fPlugin, opts.uiScale);
  747. setWindowTitle(nullptr);
  748. if (fUI.isEmbed)
  749. {
  750. clap_window_t win = { CLAP_WINDOW_API_NATIVE, {} };
  751. win.ptr = fUI.window->getPtr();
  752. fExtensions.gui->set_parent(fPlugin, &win);
  753. fExtensions.gui->show(fPlugin);
  754. fUI.window->show();
  755. }
  756. else
  757. {
  758. clap_window_t win = { CLAP_WINDOW_API_NATIVE, {} };
  759. win.uptr = opts.frontendWinId;
  760. fExtensions.gui->set_transient(fPlugin, &win);
  761. fExtensions.gui->show(fPlugin);
  762. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  763. pData->tryTransient();
  764. #endif
  765. }
  766. fUI.isVisible = true;
  767. }
  768. else
  769. {
  770. fUI.isVisible = false;
  771. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  772. pData->transientTryCounter = 0;
  773. #endif
  774. if (fUI.window != nullptr)
  775. fUI.window->hide();
  776. fExtensions.gui->hide(fPlugin);
  777. if (fUI.isCreated)
  778. {
  779. fExtensions.gui->destroy(fPlugin);
  780. fUI.isCreated = false;
  781. }
  782. if (fUI.window != nullptr)
  783. {
  784. delete fUI.window;
  785. fUI.window = nullptr;
  786. }
  787. }
  788. }
  789. #endif
  790. /*
  791. void* embedCustomUI(void* const ptr) override
  792. {
  793. }
  794. */
  795. void idle() override
  796. {
  797. CarlaPlugin::idle();
  798. }
  799. void uiIdle() override
  800. {
  801. if (fHost.inUseTimerId != CLAP_INVALID_ID && fExtensions.timer != nullptr)
  802. fExtensions.timer->on_timer(fPlugin, fHost.inUseTimerId);
  803. CarlaPlugin::uiIdle();
  804. }
  805. // -------------------------------------------------------------------
  806. // Plugin state
  807. void reload() override
  808. {
  809. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
  810. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  811. carla_debug("CarlaPluginCLAP::reload() - start");
  812. // Safely disable plugin for reload
  813. const ScopedDisabler sd(this);
  814. if (pData->active)
  815. deactivate();
  816. clearBuffers();
  817. const clap_plugin_audio_ports_t* audioPortsExt = static_cast<const clap_plugin_audio_ports_t*>(
  818. fPlugin->get_extension(fPlugin, CLAP_EXT_AUDIO_PORTS));
  819. const clap_plugin_note_ports_t* notePortsExt = static_cast<const clap_plugin_note_ports_t*>(
  820. fPlugin->get_extension(fPlugin, CLAP_EXT_NOTE_PORTS));
  821. const clap_plugin_params_t* paramsExt = static_cast<const clap_plugin_params_t*>(
  822. fPlugin->get_extension(fPlugin, CLAP_EXT_PARAMS));
  823. const clap_plugin_timer_support_t* timerExt = static_cast<const clap_plugin_timer_support_t*>(
  824. fPlugin->get_extension(fPlugin, CLAP_EXT_TIMER_SUPPORT));
  825. if (audioPortsExt != nullptr && (audioPortsExt->count == nullptr || audioPortsExt->get == nullptr))
  826. audioPortsExt = nullptr;
  827. if (notePortsExt != nullptr && (notePortsExt->count == nullptr || notePortsExt->get == nullptr))
  828. notePortsExt = nullptr;
  829. if (paramsExt != nullptr && (paramsExt->count == nullptr || paramsExt->get_info == nullptr))
  830. paramsExt = nullptr;
  831. if (timerExt != nullptr && (timerExt->on_timer == nullptr))
  832. timerExt = nullptr;
  833. fExtensions.params = paramsExt;
  834. fExtensions.timer = timerExt;
  835. #ifdef CLAP_WINDOW_API_NATIVE
  836. const clap_plugin_gui_t* guiExt = static_cast<const clap_plugin_gui_t*>(
  837. fPlugin->get_extension(fPlugin, CLAP_EXT_GUI));
  838. if (guiExt != nullptr && (guiExt->is_api_supported == nullptr
  839. || guiExt->create == nullptr
  840. || guiExt->destroy == nullptr
  841. || guiExt->set_scale == nullptr
  842. || guiExt->get_size == nullptr
  843. || guiExt->can_resize == nullptr
  844. || guiExt->get_resize_hints == nullptr
  845. || guiExt->adjust_size == nullptr
  846. || guiExt->set_size == nullptr
  847. || guiExt->set_parent == nullptr
  848. || guiExt->set_transient == nullptr
  849. || guiExt->suggest_title == nullptr
  850. || guiExt->show == nullptr
  851. || guiExt->hide == nullptr))
  852. guiExt = nullptr;
  853. fExtensions.gui = guiExt;
  854. #endif
  855. const uint32_t numAudioInputPorts = audioPortsExt != nullptr ? audioPortsExt->count(fPlugin, true) : 0;
  856. const uint32_t numAudioOutputPorts = audioPortsExt != nullptr ? audioPortsExt->count(fPlugin, false) : 0;
  857. const uint32_t numNoteInputPorts = notePortsExt != nullptr ? notePortsExt->count(fPlugin, true) : 0;
  858. const uint32_t numNoteOutputPorts = notePortsExt != nullptr ? notePortsExt->count(fPlugin, true) : 0;
  859. const uint32_t numParameters = paramsExt != nullptr ? paramsExt->count(fPlugin) : 0;
  860. uint32_t aIns, aOuts, mIns, mOuts, params;
  861. aIns = aOuts = mIns = mOuts = params = 0;
  862. bool needsCtrlIn, needsCtrlOut;
  863. needsCtrlIn = needsCtrlOut = false;
  864. fInputAudioBuffers.realloc(numAudioInputPorts);
  865. fOutputAudioBuffers.realloc(numAudioOutputPorts);
  866. for (uint32_t i=0; i<numAudioInputPorts; ++i)
  867. {
  868. clap_audio_port_info_t portInfo = {};
  869. CARLA_SAFE_ASSERT_BREAK(audioPortsExt->get(fPlugin, i, true, &portInfo));
  870. fInputAudioBuffers.buffers[i].channel_count = portInfo.channel_count;
  871. fInputAudioBuffers.buffers[i].offset = aIns;
  872. fInputAudioBuffers.buffers[i].isMain = portInfo.flags & CLAP_AUDIO_PORT_IS_MAIN;
  873. aIns += portInfo.channel_count;
  874. }
  875. for (uint32_t i=0; i<numAudioOutputPorts; ++i)
  876. {
  877. clap_audio_port_info_t portInfo = {};
  878. CARLA_SAFE_ASSERT_BREAK(audioPortsExt->get(fPlugin, i, false, &portInfo));
  879. fOutputAudioBuffers.buffers[i].channel_count = portInfo.channel_count;
  880. fOutputAudioBuffers.buffers[i].offset = aOuts;
  881. fOutputAudioBuffers.buffers[i].isMain = portInfo.flags & CLAP_AUDIO_PORT_IS_MAIN;
  882. for (uint32_t j=0; j<portInfo.channel_count; ++j)
  883. fOutputAudioBuffers.buffers[i].constant_mask |= (1 << j);
  884. aOuts += portInfo.channel_count;
  885. }
  886. for (uint32_t i=0; i<numNoteInputPorts; ++i)
  887. {
  888. clap_note_port_info_t portInfo = {};
  889. CARLA_SAFE_ASSERT_BREAK(notePortsExt->get(fPlugin, i, true, &portInfo));
  890. if (portInfo.supported_dialects & CLAP_NOTE_DIALECT_MIDI)
  891. ++mIns;
  892. }
  893. for (uint32_t i=0; i<numNoteOutputPorts; ++i)
  894. {
  895. clap_note_port_info_t portInfo = {};
  896. CARLA_SAFE_ASSERT_BREAK(notePortsExt->get(fPlugin, i, false, &portInfo));
  897. if (portInfo.supported_dialects & CLAP_NOTE_DIALECT_MIDI)
  898. ++mOuts;
  899. }
  900. for (uint32_t i=0; i<numParameters; ++i)
  901. {
  902. clap_param_info_t paramInfo = {};
  903. CARLA_SAFE_ASSERT_BREAK(paramsExt->get_info(fPlugin, i, &paramInfo));
  904. if ((paramInfo.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS)) == 0x0)
  905. ++params;
  906. }
  907. if (aIns > 0)
  908. {
  909. pData->audioIn.createNew(aIns);
  910. }
  911. if (aOuts > 0)
  912. {
  913. pData->audioOut.createNew(aOuts);
  914. needsCtrlIn = true;
  915. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  916. fAudioOutBuffers = new float*[aOuts];
  917. for (uint32_t i=0; i < aOuts; ++i)
  918. fAudioOutBuffers[i] = nullptr;
  919. #endif
  920. }
  921. if (mIns == 1)
  922. needsCtrlIn = true;
  923. if (mOuts == 1)
  924. needsCtrlOut = true;
  925. if (params > 0)
  926. {
  927. pData->param.createNew(params, false);
  928. needsCtrlIn = true;
  929. }
  930. fInputEvents.realloc(pData->event.portIn, mIns, params);
  931. fOutputEvents.realloc(pData->event.portOut, mOuts, params);
  932. const EngineProcessMode processMode = pData->engine->getProccessMode();
  933. const uint portNameSize = pData->engine->getMaxPortNameSize();
  934. CarlaString portName;
  935. // Audio Ins
  936. for (uint32_t j=0; j < aIns; ++j)
  937. {
  938. portName.clear();
  939. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  940. {
  941. portName = pData->name;
  942. portName += ":";
  943. }
  944. if (aIns > 1)
  945. {
  946. portName += "input_";
  947. portName += CarlaString(j+1);
  948. }
  949. else
  950. portName += "input";
  951. portName.truncate(portNameSize);
  952. pData->audioIn.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j);
  953. pData->audioIn.ports[j].rindex = j;
  954. }
  955. // Audio Outs
  956. for (uint32_t j=0; j < aOuts; ++j)
  957. {
  958. portName.clear();
  959. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  960. {
  961. portName = pData->name;
  962. portName += ":";
  963. }
  964. if (aOuts > 1)
  965. {
  966. portName += "output_";
  967. portName += CarlaString(j+1);
  968. }
  969. else
  970. portName += "output";
  971. portName.truncate(portNameSize);
  972. pData->audioOut.ports[j].port = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j);
  973. pData->audioOut.ports[j].rindex = j;
  974. }
  975. // MIDI Ins
  976. for (uint32_t i=0, j=0; i<numNoteInputPorts; ++i)
  977. {
  978. clap_note_port_info_t portInfo = {};
  979. CARLA_SAFE_ASSERT_BREAK(notePortsExt->get(fPlugin, i, true, &portInfo));
  980. CARLA_SAFE_ASSERT_BREAK(j < mIns);
  981. if ((portInfo.supported_dialects & CLAP_NOTE_DIALECT_MIDI) == 0x0)
  982. continue;
  983. fInputEvents.portData[j].clapPortIndex = i;
  984. if (mIns > 1)
  985. {
  986. portName.clear();
  987. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  988. {
  989. portName = pData->name;
  990. portName += ":";
  991. }
  992. portName += portInfo.name;
  993. portName.truncate(portNameSize);
  994. fInputEvents.portData[j].port = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, j);
  995. }
  996. else
  997. {
  998. fInputEvents.portData[j].port = nullptr;
  999. fInputEvents.defaultPort = &fInputEvents.portData[0];
  1000. }
  1001. ++j;
  1002. }
  1003. // MIDI Outs
  1004. for (uint32_t i=0, j=0; i<numNoteOutputPorts; ++i)
  1005. {
  1006. clap_note_port_info_t portInfo = {};
  1007. CARLA_SAFE_ASSERT_BREAK(notePortsExt->get(fPlugin, i, false, &portInfo));
  1008. CARLA_SAFE_ASSERT_BREAK(j < mOuts);
  1009. if ((portInfo.supported_dialects & CLAP_NOTE_DIALECT_MIDI) == 0x0)
  1010. continue;
  1011. fOutputEvents.portData[j].clapPortIndex = i;
  1012. if (mOuts > 1)
  1013. {
  1014. portName.clear();
  1015. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1016. {
  1017. portName = pData->name;
  1018. portName += ":";
  1019. }
  1020. portName += portInfo.name;
  1021. portName.truncate(portNameSize);
  1022. fOutputEvents.portData[j].port = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, j);
  1023. }
  1024. else
  1025. {
  1026. fOutputEvents.portData[j].port = nullptr;
  1027. fOutputEvents.defaultPort = &fOutputEvents.portData[0];
  1028. }
  1029. ++j;
  1030. }
  1031. // Parameters
  1032. for (uint32_t i=0, j=0; i<numParameters; ++i)
  1033. {
  1034. clap_param_info_t paramInfo = {};
  1035. CARLA_SAFE_ASSERT_BREAK(paramsExt->get_info(fPlugin, i, &paramInfo));
  1036. CARLA_SAFE_ASSERT_BREAK(j < params);
  1037. if (paramInfo.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS))
  1038. continue;
  1039. pData->param.data[j].index = j;
  1040. pData->param.data[j].rindex = paramInfo.id;
  1041. double min, max, def, step, stepSmall, stepLarge;
  1042. min = paramInfo.min_value;
  1043. max = paramInfo.max_value;
  1044. def = paramInfo.default_value;
  1045. if (min >= max)
  1046. max = min + 0.1;
  1047. if (def < min)
  1048. def = min;
  1049. else if (def > max)
  1050. def = max;
  1051. if (paramInfo.flags & CLAP_PARAM_IS_READONLY)
  1052. {
  1053. pData->param.data[j].type = PARAMETER_OUTPUT;
  1054. needsCtrlOut = true;
  1055. }
  1056. else
  1057. {
  1058. pData->param.data[j].type = PARAMETER_INPUT;
  1059. }
  1060. if (paramInfo.flags & CLAP_PARAM_IS_STEPPED)
  1061. {
  1062. if (carla_isEqual(max - min, 1.0))
  1063. {
  1064. step = stepSmall = stepLarge = 1.0;
  1065. pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN;
  1066. }
  1067. else
  1068. {
  1069. step = 1.0;
  1070. stepSmall = 1.0;
  1071. stepLarge = std::min(max - min, 10.0);
  1072. }
  1073. pData->param.data[j].hints |= PARAMETER_IS_INTEGER;
  1074. }
  1075. else
  1076. {
  1077. double range = max - min;
  1078. step = range/100.0;
  1079. stepSmall = range/1000.0;
  1080. stepLarge = range/10.0;
  1081. }
  1082. pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
  1083. pData->param.data[j].hints |= PARAMETER_USES_CUSTOM_TEXT;
  1084. if (paramInfo.flags & CLAP_PARAM_IS_AUTOMATABLE)
  1085. {
  1086. pData->param.data[j].hints |= PARAMETER_IS_AUTOMATABLE;
  1087. if ((paramInfo.flags & CLAP_PARAM_IS_STEPPED) == 0x0)
  1088. pData->param.data[j].hints |= PARAMETER_CAN_BE_CV_CONTROLLED;
  1089. }
  1090. pData->param.ranges[j].min = min;
  1091. pData->param.ranges[j].max = max;
  1092. pData->param.ranges[j].def = def;
  1093. pData->param.ranges[j].step = step;
  1094. pData->param.ranges[j].stepSmall = stepSmall;
  1095. pData->param.ranges[j].stepLarge = stepLarge;
  1096. fInputEvents.updatedParams[j].clapId = paramInfo.id;
  1097. fInputEvents.updatedParams[j].cookie = paramInfo.cookie;
  1098. ++j;
  1099. }
  1100. if (needsCtrlIn)
  1101. {
  1102. portName.clear();
  1103. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1104. {
  1105. portName = pData->name;
  1106. portName += ":";
  1107. }
  1108. portName += "events-in";
  1109. portName.truncate(portNameSize);
  1110. pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
  1111. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1112. pData->event.cvSourcePorts = pData->client->createCVSourcePorts();
  1113. #endif
  1114. if (mIns == 1)
  1115. fInputEvents.portData[0].port = pData->event.portIn;
  1116. }
  1117. if (needsCtrlOut)
  1118. {
  1119. portName.clear();
  1120. if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
  1121. {
  1122. portName = pData->name;
  1123. portName += ":";
  1124. }
  1125. portName += "events-out";
  1126. portName.truncate(portNameSize);
  1127. pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
  1128. if (mOuts == 1)
  1129. fOutputEvents.portData[0].port = pData->event.portOut;
  1130. }
  1131. // plugin hints
  1132. pData->hints = 0x0;
  1133. if (clapFeaturesContainInstrument(fPluginDescriptor->features))
  1134. pData->hints |= PLUGIN_IS_SYNTH;
  1135. #ifdef CLAP_WINDOW_API_NATIVE
  1136. if (guiExt != nullptr)
  1137. {
  1138. if (guiExt->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, false))
  1139. {
  1140. pData->hints |= PLUGIN_HAS_CUSTOM_UI;
  1141. pData->hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
  1142. pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
  1143. }
  1144. else if (guiExt->is_api_supported(fPlugin, CLAP_WINDOW_API_NATIVE, true))
  1145. {
  1146. pData->hints |= PLUGIN_HAS_CUSTOM_UI;
  1147. pData->hints |= PLUGIN_NEEDS_UI_MAIN_THREAD;
  1148. }
  1149. }
  1150. #endif
  1151. if (aOuts > 0 && (aIns == aOuts || aIns == 1))
  1152. pData->hints |= PLUGIN_CAN_DRYWET;
  1153. if (aOuts > 0)
  1154. pData->hints |= PLUGIN_CAN_VOLUME;
  1155. if (aOuts >= 2 && aOuts % 2 == 0)
  1156. pData->hints |= PLUGIN_CAN_BALANCE;
  1157. // extra plugin hints
  1158. pData->extraHints = 0x0;
  1159. if (numNoteInputPorts > 0)
  1160. pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN;
  1161. if (numNoteOutputPorts > 0)
  1162. pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_OUT;
  1163. bufferSizeChanged(pData->engine->getBufferSize());
  1164. reloadPrograms(true);
  1165. if (pData->active)
  1166. activate();
  1167. carla_debug("CarlaPluginCLAP::reload() - end");
  1168. }
  1169. void reloadPrograms(const bool doInit) override
  1170. {
  1171. carla_debug("CarlaPluginCLAP::reloadPrograms(%s)", bool2str(doInit));
  1172. }
  1173. // -------------------------------------------------------------------
  1174. // Plugin processing
  1175. void activate() noexcept override
  1176. {
  1177. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  1178. // FIXME check return status
  1179. fPlugin->activate(fPlugin, pData->engine->getSampleRate(), 1, pData->engine->getBufferSize());
  1180. fPlugin->start_processing(fPlugin);
  1181. }
  1182. void deactivate() noexcept override
  1183. {
  1184. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  1185. // FIXME check return status
  1186. fPlugin->stop_processing(fPlugin);
  1187. fPlugin->deactivate(fPlugin);
  1188. }
  1189. void process(const float* const* const audioIn,
  1190. float** const audioOut,
  1191. const float* const* const cvIn,
  1192. float** const,
  1193. const uint32_t frames) override
  1194. {
  1195. // --------------------------------------------------------------------------------------------------------
  1196. // Check if active
  1197. if (! pData->active)
  1198. {
  1199. // disable any output sound
  1200. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1201. carla_zeroFloats(audioOut[i], frames);
  1202. return;
  1203. }
  1204. // --------------------------------------------------------------------------------------------------------
  1205. // Check buffers
  1206. CARLA_SAFE_ASSERT_RETURN(frames > 0,);
  1207. if (pData->audioIn.count > 0)
  1208. {
  1209. CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr,);
  1210. }
  1211. if (pData->audioOut.count > 0)
  1212. {
  1213. CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr,);
  1214. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1215. CARLA_SAFE_ASSERT_RETURN(fAudioOutBuffers != nullptr,);
  1216. #endif
  1217. }
  1218. // --------------------------------------------------------------------------------------------------------
  1219. // Set audio buffers
  1220. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1221. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1222. carla_zeroFloats(fAudioOutBuffers[i], frames);
  1223. #endif
  1224. // --------------------------------------------------------------------------------------------------------
  1225. // Try lock, silence otherwise
  1226. if (pData->engine->isOffline())
  1227. {
  1228. pData->singleMutex.lock();
  1229. }
  1230. else if (! pData->singleMutex.tryLock())
  1231. {
  1232. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1233. carla_zeroFloats(audioOut[i], frames);
  1234. return;
  1235. }
  1236. // --------------------------------------------------------------------------------------------------------
  1237. fInputEvents.handleScheduledParameterUpdates();
  1238. // --------------------------------------------------------------------------------------------------------
  1239. // Check if needs reset
  1240. if (pData->needsReset)
  1241. {
  1242. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1243. {
  1244. for (uint32_t p=0; p<fInputEvents.portCount; ++p)
  1245. {
  1246. const uint16_t port = fInputEvents.portData[p].clapPortIndex;
  1247. for (uint8_t i=0, k=fInputEvents.numEventsUsed; i < MAX_MIDI_CHANNELS; ++i)
  1248. {
  1249. fInputEvents.events[k + i].midi = {
  1250. { sizeof(clap_event_midi_t), 0, 0, CLAP_EVENT_MIDI, 0 },
  1251. port,
  1252. {
  1253. uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)),
  1254. MIDI_CONTROL_ALL_NOTES_OFF, 0
  1255. }
  1256. };
  1257. fInputEvents.events[k + MAX_MIDI_CHANNELS + i].midi = {
  1258. { sizeof(clap_event_midi_t), 0, 0, CLAP_EVENT_MIDI, 0 },
  1259. port,
  1260. {
  1261. uint8_t(MIDI_STATUS_CONTROL_CHANGE | (i & MIDI_CHANNEL_BIT)),
  1262. MIDI_CONTROL_ALL_SOUND_OFF, 0
  1263. }
  1264. };
  1265. }
  1266. fInputEvents.numEventsUsed += MAX_MIDI_CHANNELS * 2;
  1267. }
  1268. }
  1269. else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
  1270. {
  1271. for (uint32_t p=0; p<fInputEvents.portCount; ++p)
  1272. {
  1273. const uint16_t port = fInputEvents.portData[p].clapPortIndex;
  1274. for (uint8_t i=0, k=fInputEvents.numEventsUsed; i < MAX_MIDI_NOTE; ++i)
  1275. {
  1276. fInputEvents.events[k + i].midi = {
  1277. { sizeof(clap_event_midi_t), 0, 0, CLAP_EVENT_MIDI, 0 },
  1278. port,
  1279. {
  1280. uint8_t(MIDI_STATUS_NOTE_OFF | (pData->ctrlChannel & MIDI_CHANNEL_BIT)),
  1281. i, 0
  1282. }
  1283. };
  1284. }
  1285. fInputEvents.numEventsUsed += MAX_MIDI_NOTE;
  1286. }
  1287. }
  1288. pData->needsReset = false;
  1289. }
  1290. // --------------------------------------------------------------------------------------------------------
  1291. // Set TimeInfo
  1292. const EngineTimeInfo timeInfo(pData->engine->getTimeInfo());
  1293. clap_event_transport_t clapTransport = {
  1294. { sizeof(clap_event_transport_t), 0, 0, CLAP_EVENT_TRANSPORT, 0 },
  1295. 0x0, // flags
  1296. 0, // song_pos_beats, position in beats
  1297. 0, // song_pos_seconds, position in seconds
  1298. 0.0, // tempo, in bpm
  1299. 0.0, // tempo_inc, tempo increment for each samples and until the next time info event
  1300. 0, // loop_start_beats;
  1301. 0, // loop_end_beats;
  1302. 0, // loop_start_seconds;
  1303. 0, // loop_end_seconds;
  1304. 0, // bar_start, start pos of the current bar
  1305. 0, // bar_number, bar at song pos 0 has the number 0
  1306. 0, // tsig_num, time signature numerator
  1307. 0, // tsig_denom, time signature denominator
  1308. };
  1309. if (timeInfo.playing)
  1310. clapTransport.flags |= CLAP_TRANSPORT_IS_PLAYING;
  1311. // TODO song_pos_seconds (based on frame and sample rate)
  1312. if (timeInfo.bbt.valid)
  1313. {
  1314. // TODO song_pos_beats
  1315. // Tempo
  1316. clapTransport.tempo = timeInfo.bbt.beatsPerMinute;
  1317. clapTransport.flags |= CLAP_TRANSPORT_HAS_TEMPO;
  1318. // Bar
  1319. // TODO bar_start
  1320. clapTransport.bar_number = timeInfo.bbt.bar - 1;
  1321. // Time Signature
  1322. clapTransport.tsig_num = static_cast<uint16_t>(timeInfo.bbt.beatsPerBar + 0.5f);
  1323. clapTransport.tsig_denom = static_cast<uint16_t>(timeInfo.bbt.beatType + 0.5f);
  1324. clapTransport.flags |= CLAP_TRANSPORT_HAS_TIME_SIGNATURE;
  1325. }
  1326. else
  1327. {
  1328. // Tempo
  1329. clapTransport.tempo = 120.0;
  1330. clapTransport.flags |= CLAP_TRANSPORT_HAS_TEMPO;
  1331. // Time Signature
  1332. clapTransport.tsig_num = 4;
  1333. clapTransport.tsig_denom = 4;
  1334. clapTransport.flags |= CLAP_TRANSPORT_HAS_TIME_SIGNATURE;
  1335. }
  1336. // --------------------------------------------------------------------------------------------------------
  1337. // Event Input (main port)
  1338. if (pData->event.portIn != nullptr)
  1339. {
  1340. // ----------------------------------------------------------------------------------------------------
  1341. // MIDI Input (External)
  1342. if (pData->extNotes.mutex.tryLock())
  1343. {
  1344. if (fInputEvents.portCount == 0)
  1345. {
  1346. // does not handle MIDI
  1347. pData->extNotes.data.clear();
  1348. }
  1349. else
  1350. {
  1351. ExternalMidiNote note = { -1, 0, 0 };
  1352. const uint16_t p = fInputEvents.portData[0].clapPortIndex;
  1353. for (; fInputEvents.numEventsUsed < fInputEvents.numEventsAllocated && ! pData->extNotes.data.isEmpty();)
  1354. {
  1355. note = pData->extNotes.data.getFirst(note, true);
  1356. CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);
  1357. const uint8_t data[3] = {
  1358. uint8_t((note.velo > 0 ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (note.channel & MIDI_CHANNEL_BIT)),
  1359. note.note,
  1360. note.velo
  1361. };
  1362. fInputEvents.addSimpleMidiEvent(true, p, 0, data);
  1363. }
  1364. }
  1365. pData->extNotes.mutex.unlock();
  1366. } // End of MIDI Input (External)
  1367. // ----------------------------------------------------------------------------------------------------
  1368. // Event Input (System)
  1369. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1370. bool allNotesOffSent = false;
  1371. #endif
  1372. uint32_t previousEventTime = 0;
  1373. uint32_t nextBankId;
  1374. if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
  1375. nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
  1376. else
  1377. nextBankId = 0;
  1378. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1379. if (cvIn != nullptr && pData->event.cvSourcePorts != nullptr)
  1380. pData->event.cvSourcePorts->initPortBuffers(cvIn + pData->cvIn.count, frames, true, pData->event.portIn);
  1381. #endif
  1382. const uint32_t numSysEvents = pData->event.portIn->getEventCount();
  1383. for (uint32_t i=0; i < numSysEvents; ++i)
  1384. {
  1385. EngineEvent& event(fInputEvents.defaultPort->port->getEvent(i));
  1386. uint32_t eventTime = event.time;
  1387. CARLA_SAFE_ASSERT_UINT2_CONTINUE(eventTime < frames, eventTime, frames);
  1388. if (eventTime < previousEventTime)
  1389. {
  1390. carla_stderr2("Timing error, eventTime:%u < previousEventTime:%u for '%s'",
  1391. eventTime, previousEventTime, pData->name);
  1392. eventTime = previousEventTime;
  1393. }
  1394. previousEventTime = eventTime;
  1395. switch (event.type)
  1396. {
  1397. case kEngineEventTypeNull:
  1398. break;
  1399. case kEngineEventTypeControl: {
  1400. EngineControlEvent& ctrlEvent(event.ctrl);
  1401. switch (ctrlEvent.type)
  1402. {
  1403. case kEngineControlEventTypeNull:
  1404. break;
  1405. case kEngineControlEventTypeParameter: {
  1406. float value;
  1407. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1408. // non-midi
  1409. if (event.channel == kEngineEventNonMidiChannel)
  1410. {
  1411. const uint32_t k = ctrlEvent.param;
  1412. CARLA_SAFE_ASSERT_CONTINUE(k < pData->param.count);
  1413. ctrlEvent.handled = true;
  1414. value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
  1415. setParameterValueRT(k, value, event.time, true);
  1416. continue;
  1417. }
  1418. // Control backend stuff
  1419. if (event.channel == pData->ctrlChannel)
  1420. {
  1421. if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_DRYWET) != 0)
  1422. {
  1423. ctrlEvent.handled = true;
  1424. value = ctrlEvent.normalizedValue;
  1425. setDryWetRT(value, true);
  1426. }
  1427. else if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_VOLUME) != 0)
  1428. {
  1429. ctrlEvent.handled = true;
  1430. value = ctrlEvent.normalizedValue*127.0f/100.0f;
  1431. setVolumeRT(value, true);
  1432. }
  1433. else if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_BALANCE) != 0)
  1434. {
  1435. float left, right;
  1436. value = ctrlEvent.normalizedValue/0.5f - 1.0f;
  1437. if (value < 0.0f)
  1438. {
  1439. left = -1.0f;
  1440. right = (value*2.0f)+1.0f;
  1441. }
  1442. else if (value > 0.0f)
  1443. {
  1444. left = (value*2.0f)-1.0f;
  1445. right = 1.0f;
  1446. }
  1447. else
  1448. {
  1449. left = -1.0f;
  1450. right = 1.0f;
  1451. }
  1452. ctrlEvent.handled = true;
  1453. setBalanceLeftRT(left, true);
  1454. setBalanceRightRT(right, true);
  1455. }
  1456. }
  1457. #endif
  1458. // Control plugin parameters
  1459. uint32_t k;
  1460. for (k=0; k < pData->param.count; ++k)
  1461. {
  1462. if (pData->param.data[k].midiChannel != event.channel)
  1463. continue;
  1464. if (pData->param.data[k].mappedControlIndex != ctrlEvent.param)
  1465. continue;
  1466. if (pData->param.data[k].type != PARAMETER_INPUT)
  1467. continue;
  1468. if ((pData->param.data[k].hints & PARAMETER_IS_AUTOMATABLE) == 0)
  1469. continue;
  1470. ctrlEvent.handled = true;
  1471. value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
  1472. setParameterValueRT(k, value, event.time, true);
  1473. }
  1474. if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_VALUE)
  1475. {
  1476. uint8_t midiData[3];
  1477. midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1478. midiData[1] = uint8_t(ctrlEvent.param);
  1479. midiData[2] = uint8_t(ctrlEvent.normalizedValue*127.0f + 0.5f);
  1480. fInputEvents.addSimpleMidiEvent(true, 0, eventTime, midiData);
  1481. }
  1482. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1483. if (! ctrlEvent.handled)
  1484. checkForMidiLearn(event);
  1485. #endif
  1486. break;
  1487. } // case kEngineControlEventTypeParameter
  1488. case kEngineControlEventTypeMidiBank:
  1489. if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
  1490. {
  1491. if (event.channel == pData->ctrlChannel)
  1492. nextBankId = ctrlEvent.param;
  1493. }
  1494. else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
  1495. {
  1496. uint8_t midiData[3];
  1497. midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1498. midiData[1] = MIDI_CONTROL_BANK_SELECT;
  1499. midiData[2] = uint8_t(ctrlEvent.param);
  1500. fInputEvents.addSimpleMidiEvent(true, 0, eventTime, midiData);
  1501. }
  1502. break;
  1503. case kEngineControlEventTypeMidiProgram:
  1504. if (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES)
  1505. {
  1506. if (event.channel == pData->ctrlChannel)
  1507. {
  1508. const uint32_t nextProgramId(ctrlEvent.param);
  1509. for (uint32_t k=0; k < pData->midiprog.count; ++k)
  1510. {
  1511. if (pData->midiprog.data[k].bank == nextBankId && pData->midiprog.data[k].program == nextProgramId)
  1512. {
  1513. setMidiProgramRT(k, true);
  1514. break;
  1515. }
  1516. }
  1517. }
  1518. }
  1519. else if (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES)
  1520. {
  1521. uint8_t midiData[3];
  1522. midiData[0] = uint8_t(MIDI_STATUS_PROGRAM_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1523. midiData[1] = uint8_t(ctrlEvent.param);
  1524. midiData[2] = 0;
  1525. fInputEvents.addSimpleMidiEvent(true, 0, eventTime, midiData);
  1526. }
  1527. break;
  1528. case kEngineControlEventTypeAllSoundOff:
  1529. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1530. {
  1531. uint8_t midiData[3];
  1532. midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1533. midiData[1] = MIDI_CONTROL_ALL_SOUND_OFF;
  1534. midiData[2] = 0;
  1535. fInputEvents.addSimpleMidiEvent(true, 0, eventTime, midiData);
  1536. }
  1537. break;
  1538. case kEngineControlEventTypeAllNotesOff:
  1539. if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
  1540. {
  1541. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1542. if (event.channel == pData->ctrlChannel && ! allNotesOffSent)
  1543. {
  1544. allNotesOffSent = true;
  1545. postponeRtAllNotesOff();
  1546. }
  1547. #endif
  1548. uint8_t midiData[3];
  1549. midiData[0] = uint8_t(MIDI_STATUS_CONTROL_CHANGE | (event.channel & MIDI_CHANNEL_BIT));
  1550. midiData[1] = MIDI_CONTROL_ALL_NOTES_OFF;
  1551. midiData[2] = 0;
  1552. fInputEvents.addSimpleMidiEvent(true, 0, eventTime, midiData);
  1553. }
  1554. break;
  1555. } // switch (ctrlEvent.type)
  1556. break;
  1557. } // case kEngineEventTypeControl
  1558. case kEngineEventTypeMidi: {
  1559. const EngineMidiEvent& midiEvent(event.midi);
  1560. if (midiEvent.size > sizeof(clap_event_midi::data)/sizeof(clap_event_midi::data[0]))
  1561. continue;
  1562. const uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
  1563. if ((status == MIDI_STATUS_NOTE_OFF || status == MIDI_STATUS_NOTE_ON) && (pData->options & PLUGIN_OPTION_SKIP_SENDING_NOTES))
  1564. continue;
  1565. if (status == MIDI_STATUS_CHANNEL_PRESSURE && (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE) == 0)
  1566. continue;
  1567. if (status == MIDI_STATUS_CONTROL_CHANGE && (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) == 0)
  1568. continue;
  1569. if (status == MIDI_STATUS_POLYPHONIC_AFTERTOUCH && (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH) == 0)
  1570. continue;
  1571. if (status == MIDI_STATUS_PITCH_WHEEL_CONTROL && (pData->options & PLUGIN_OPTION_SEND_PITCHBEND) == 0)
  1572. continue;
  1573. // put back channel in data
  1574. uint8_t midiData[3] = { uint8_t(status | (event.channel & MIDI_CHANNEL_BIT)), 0, 0 };
  1575. switch (midiEvent.size)
  1576. {
  1577. case 3:
  1578. midiData[2] = midiEvent.data[2];
  1579. // fall through
  1580. case 2:
  1581. midiData[1] = midiEvent.data[1];
  1582. break;
  1583. }
  1584. fInputEvents.addSimpleMidiEvent(true, midiEvent.port, eventTime, midiData);
  1585. switch (status)
  1586. {
  1587. case MIDI_STATUS_NOTE_ON:
  1588. if (midiEvent.data[2] != 0)
  1589. {
  1590. pData->postponeNoteOnRtEvent(true, event.channel, midiEvent.data[1], midiEvent.data[2]);
  1591. break;
  1592. }
  1593. // fall through
  1594. case MIDI_STATUS_NOTE_OFF:
  1595. pData->postponeNoteOffRtEvent(true, event.channel, midiEvent.data[1]);
  1596. break;
  1597. }
  1598. } break;
  1599. } // switch (event.type)
  1600. }
  1601. pData->postRtEvents.trySplice();
  1602. } // End of Event Input (main port)
  1603. // --------------------------------------------------------------------------------------------------------
  1604. // Event input (multi MIDI port)
  1605. if (fInputEvents.portCount > 1)
  1606. {
  1607. // TODO
  1608. }
  1609. // --------------------------------------------------------------------------------------------------------
  1610. // Plugin processing
  1611. for (uint32_t i=0; i<fInputAudioBuffers.count; ++i)
  1612. fInputAudioBuffers.buffers[i].data32 = audioIn + fInputAudioBuffers.buffers[i].offset;
  1613. for (uint32_t i=0; i<fOutputAudioBuffers.count; ++i)
  1614. {
  1615. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1616. fOutputAudioBuffers.buffers[i].data32 = fAudioOutBuffers + fOutputAudioBuffers.buffers[i].offset;
  1617. #else
  1618. fOutputAudioBuffers.buffers[i].data32 = audioOut + fOutputAudioBuffers.buffers[i].offset;
  1619. #endif
  1620. }
  1621. const clap_process_t process = {
  1622. static_cast<int64_t>(timeInfo.frame),
  1623. frames,
  1624. &clapTransport,
  1625. fInputAudioBuffers.cast(),
  1626. fOutputAudioBuffers.cast(), // audio_outputs
  1627. fInputAudioBuffers.count, // audio_inputs_count
  1628. fOutputAudioBuffers.count, // audio_outputs_count
  1629. &fInputEvents, // in_events
  1630. &fOutputEvents // out_events
  1631. };
  1632. fOutputEvents.numEventsUsed = 0;
  1633. fPlugin->process(fPlugin, &process);
  1634. fInputEvents.numEventsUsed = 0;
  1635. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1636. // --------------------------------------------------------------------------------------------------------
  1637. // Post-processing (dry/wet, volume and balance)
  1638. {
  1639. const bool doDryWet = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f);
  1640. const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f));
  1641. const bool isMono = (pData->audioIn.count == 1);
  1642. bool isPair;
  1643. float bufValue, oldBufLeft[doBalance ? frames : 1];
  1644. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1645. {
  1646. // Dry/Wet
  1647. if (doDryWet)
  1648. {
  1649. const uint32_t c = isMono ? 0 : i;
  1650. for (uint32_t k=0; k < frames; ++k)
  1651. {
  1652. bufValue = audioIn[c][k];
  1653. fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet));
  1654. }
  1655. }
  1656. // Balance
  1657. if (doBalance)
  1658. {
  1659. isPair = (i % 2 == 0);
  1660. if (isPair)
  1661. {
  1662. CARLA_ASSERT(i+1 < pData->audioOut.count);
  1663. carla_copyFloats(oldBufLeft, fAudioOutBuffers[i], frames);
  1664. }
  1665. float balRangeL = (pData->postProc.balanceLeft + 1.0f)/2.0f;
  1666. float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f;
  1667. for (uint32_t k=0; k < frames; ++k)
  1668. {
  1669. if (isPair)
  1670. {
  1671. // left
  1672. fAudioOutBuffers[i][k] = oldBufLeft[k] * (1.0f - balRangeL);
  1673. fAudioOutBuffers[i][k] += fAudioOutBuffers[i+1][k] * (1.0f - balRangeR);
  1674. }
  1675. else
  1676. {
  1677. // right
  1678. fAudioOutBuffers[i][k] = fAudioOutBuffers[i][k] * balRangeR;
  1679. fAudioOutBuffers[i][k] += oldBufLeft[k] * balRangeL;
  1680. }
  1681. }
  1682. }
  1683. // Volume (and buffer copy)
  1684. {
  1685. for (uint32_t k=0; k < frames; ++k)
  1686. audioOut[i][k] = fAudioOutBuffers[i][k] * pData->postProc.volume;
  1687. }
  1688. }
  1689. } // End of Post-processing
  1690. #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH
  1691. // --------------------------------------------------------------------------------------------------------
  1692. pData->singleMutex.unlock();
  1693. // --------------------------------------------------------------------------------------------------------
  1694. // MIDI Output
  1695. if (pData->event.portOut != nullptr)
  1696. {
  1697. } // End of MIDI Output
  1698. // --------------------------------------------------------------------------------------------------------
  1699. #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1700. return;
  1701. // unused
  1702. (void)cvIn;
  1703. #endif
  1704. }
  1705. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1706. void bufferSizeChanged(const uint32_t newBufferSize) override
  1707. {
  1708. CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize);
  1709. carla_debug("CarlaPluginCLAP::bufferSizeChanged(%i)", newBufferSize);
  1710. if (pData->active)
  1711. deactivate();
  1712. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1713. {
  1714. if (fAudioOutBuffers[i] != nullptr)
  1715. delete[] fAudioOutBuffers[i];
  1716. fAudioOutBuffers[i] = new float[newBufferSize];
  1717. }
  1718. if (pData->active)
  1719. activate();
  1720. }
  1721. #endif
  1722. // -------------------------------------------------------------------
  1723. // Plugin buffers
  1724. void initBuffers() const noexcept override
  1725. {
  1726. fInputEvents.initBuffers();
  1727. fOutputEvents.initBuffers();
  1728. CarlaPlugin::initBuffers();
  1729. }
  1730. void clearBuffers() noexcept override
  1731. {
  1732. carla_debug("CarlaPluginCLAP::clearBuffers() - start");
  1733. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1734. if (fAudioOutBuffers != nullptr)
  1735. {
  1736. for (uint32_t i=0; i < pData->audioOut.count; ++i)
  1737. {
  1738. if (fAudioOutBuffers[i] != nullptr)
  1739. {
  1740. delete[] fAudioOutBuffers[i];
  1741. fAudioOutBuffers[i] = nullptr;
  1742. }
  1743. }
  1744. delete[] fAudioOutBuffers;
  1745. fAudioOutBuffers = nullptr;
  1746. }
  1747. #endif
  1748. fInputEvents.clear(pData->event.portIn);
  1749. fOutputEvents.clear(pData->event.portOut);
  1750. CarlaPlugin::clearBuffers();
  1751. carla_debug("CarlaPluginCLAP::clearBuffers() - end");
  1752. }
  1753. // -------------------------------------------------------------------
  1754. // Post-poned UI Stuff
  1755. // nothing
  1756. // -------------------------------------------------------------------
  1757. protected:
  1758. #ifdef CLAP_WINDOW_API_NATIVE
  1759. void handlePluginUIClosed() override
  1760. {
  1761. CARLA_SAFE_ASSERT_RETURN(fUI.window != nullptr,);
  1762. carla_debug("CarlaPluginCLAP::handlePluginUIClosed()");
  1763. showCustomUI(false);
  1764. pData->engine->callback(true, true,
  1765. ENGINE_CALLBACK_UI_STATE_CHANGED,
  1766. pData->id,
  1767. 0,
  1768. 0, 0, 0.0f, nullptr);
  1769. }
  1770. void handlePluginUIResized(const uint width, const uint height) override
  1771. {
  1772. CARLA_SAFE_ASSERT_RETURN(fUI.window != nullptr,);
  1773. carla_debug("CarlaPluginCLAP::handlePluginUIResized(%u, %u)", width, height);
  1774. if (fExtensions.gui != nullptr)
  1775. fExtensions.gui->set_size(fPlugin, width, height);
  1776. }
  1777. void hostRequestResize(const uint width, const uint height) override
  1778. {
  1779. CARLA_SAFE_ASSERT_RETURN(fUI.window != nullptr,);
  1780. carla_debug("CarlaPluginCLAP::hostRequestResize(%u, %u)", width, height);
  1781. fUI.window->setSize(width, height, true);
  1782. }
  1783. #endif
  1784. // -------------------------------------------------------------------
  1785. public:
  1786. bool init(const CarlaPluginPtr plugin,
  1787. const char* const filename, const char* const name, const char* const id, const uint options)
  1788. {
  1789. CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
  1790. // ---------------------------------------------------------------
  1791. // first checks
  1792. if (pData->client != nullptr)
  1793. {
  1794. pData->engine->setLastError("Plugin client is already registered");
  1795. return false;
  1796. }
  1797. if (filename == nullptr || filename[0] == '\0')
  1798. {
  1799. pData->engine->setLastError("null filename");
  1800. return false;
  1801. }
  1802. if (id == nullptr || id[0] == '\0')
  1803. {
  1804. pData->engine->setLastError("null label/id");
  1805. return false;
  1806. }
  1807. // ---------------------------------------------------------------
  1808. const clap_plugin_entry_t* entry;
  1809. #ifdef CARLA_OS_MAC
  1810. if (!water::File(filename).existsAsFile())
  1811. {
  1812. if (! fBundleLoader.load(filename))
  1813. {
  1814. pData->engine->setLastError("Failed to load CLAP bundle executable");
  1815. return false;
  1816. }
  1817. entry = fBundleLoader.getSymbol<const clap_plugin_entry_t*>(CFSTR("clap_entry"));
  1818. }
  1819. else
  1820. #endif
  1821. {
  1822. if (! pData->libOpen(filename))
  1823. {
  1824. pData->engine->setLastError(pData->libError(filename));
  1825. return false;
  1826. }
  1827. entry = pData->libSymbol<const clap_plugin_entry_t*>("clap_entry");
  1828. }
  1829. if (entry == nullptr)
  1830. {
  1831. pData->engine->setLastError("Could not find the CLAP entry in the plugin library");
  1832. return false;
  1833. }
  1834. if (entry->init == nullptr || entry->deinit == nullptr || entry->get_factory == nullptr)
  1835. {
  1836. pData->engine->setLastError("CLAP factory entries are null");
  1837. return false;
  1838. }
  1839. if (!clap_version_is_compatible(entry->clap_version))
  1840. {
  1841. pData->engine->setLastError("Incompatible CLAP plugin");
  1842. return false;
  1843. }
  1844. // ---------------------------------------------------------------
  1845. const water::String pluginPath(water::File(filename).getParentDirectory().getFullPathName());
  1846. if (!entry->init(pluginPath.toRawUTF8()))
  1847. {
  1848. pData->engine->setLastError("Plugin entry failed to initialize");
  1849. return false;
  1850. }
  1851. fPluginEntry = entry;
  1852. // ---------------------------------------------------------------
  1853. const clap_plugin_factory_t* const factory = static_cast<const clap_plugin_factory_t*>(
  1854. entry->get_factory(CLAP_PLUGIN_FACTORY_ID));
  1855. if (factory == nullptr
  1856. || factory->get_plugin_count == nullptr
  1857. || factory->get_plugin_descriptor == nullptr
  1858. || factory->create_plugin == nullptr)
  1859. {
  1860. pData->engine->setLastError("Plugin is missing factory methods");
  1861. return false;
  1862. }
  1863. // ---------------------------------------------------------------
  1864. if (const uint32_t count = factory->get_plugin_count(factory))
  1865. {
  1866. for (uint32_t i=0; i<count; ++i)
  1867. {
  1868. const clap_plugin_descriptor_t* const desc = factory->get_plugin_descriptor(factory, i);
  1869. CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr);
  1870. CARLA_SAFE_ASSERT_CONTINUE(desc->id != nullptr);
  1871. if (std::strcmp(desc->id, id) == 0)
  1872. {
  1873. fPluginDescriptor = desc;
  1874. break;
  1875. }
  1876. }
  1877. }
  1878. else
  1879. {
  1880. pData->engine->setLastError("Plugin library contains no plugins");
  1881. return false;
  1882. }
  1883. if (fPluginDescriptor == nullptr)
  1884. {
  1885. pData->engine->setLastError("Plugin library does not contain the requested plugin");
  1886. return false;
  1887. }
  1888. // ---------------------------------------------------------------
  1889. fPlugin = factory->create_plugin(factory, &fHost, fPluginDescriptor->id);
  1890. if (fPlugin == nullptr)
  1891. {
  1892. pData->engine->setLastError("Failed to create CLAP plugin instance");
  1893. return false;
  1894. }
  1895. if (!fPlugin->init(fPlugin))
  1896. {
  1897. pData->engine->setLastError("Failed to initialize CLAP plugin instance");
  1898. return false;
  1899. }
  1900. // ---------------------------------------------------------------
  1901. // get info
  1902. pData->name = pData->engine->getUniquePluginName(name != nullptr && name[0] != '\0' ? name
  1903. : fPluginDescriptor->name);
  1904. pData->filename = carla_strdup(filename);
  1905. // ---------------------------------------------------------------
  1906. // register client
  1907. pData->client = pData->engine->addClient(plugin);
  1908. if (pData->client == nullptr || ! pData->client->isOk())
  1909. {
  1910. pData->engine->setLastError("Failed to register plugin client");
  1911. return false;
  1912. }
  1913. // ---------------------------------------------------------------
  1914. // set default options
  1915. pData->options = PLUGIN_OPTION_FIXED_BUFFERS;
  1916. if (isPluginOptionEnabled(options, PLUGIN_OPTION_USE_CHUNKS))
  1917. pData->options |= PLUGIN_OPTION_USE_CHUNKS;
  1918. if (fInputEvents.portCount != 0)
  1919. {
  1920. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CONTROL_CHANGES))
  1921. pData->options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
  1922. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CHANNEL_PRESSURE))
  1923. pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
  1924. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH))
  1925. pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
  1926. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PITCHBEND))
  1927. pData->options |= PLUGIN_OPTION_SEND_PITCHBEND;
  1928. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_ALL_SOUND_OFF))
  1929. pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
  1930. if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PROGRAM_CHANGES))
  1931. pData->options |= PLUGIN_OPTION_SEND_PROGRAM_CHANGES;
  1932. if (isPluginOptionInverseEnabled(options, PLUGIN_OPTION_SKIP_SENDING_NOTES))
  1933. pData->options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
  1934. }
  1935. // if (fEffect->numPrograms > 1 && (pData->options & PLUGIN_OPTION_SEND_PROGRAM_CHANGES) == 0)
  1936. // if (isPluginOptionEnabled(options, PLUGIN_OPTION_MAP_PROGRAM_CHANGES))
  1937. // pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
  1938. return true;
  1939. }
  1940. private:
  1941. const clap_plugin_t* fPlugin;
  1942. const clap_plugin_descriptor_t* fPluginDescriptor;
  1943. const clap_plugin_entry_t* fPluginEntry;
  1944. const carla_clap_host fHost;
  1945. struct Extensions {
  1946. const clap_plugin_params_t* params;
  1947. #ifdef CLAP_WINDOW_API_NATIVE
  1948. const clap_plugin_gui_t* gui;
  1949. #endif
  1950. const clap_plugin_timer_support_t* timer;
  1951. Extensions()
  1952. : params(nullptr),
  1953. #ifdef CLAP_WINDOW_API_NATIVE
  1954. gui(nullptr),
  1955. #endif
  1956. timer(nullptr) {}
  1957. CARLA_DECLARE_NON_COPYABLE(Extensions)
  1958. } fExtensions;
  1959. #ifdef CLAP_WINDOW_API_NATIVE
  1960. struct UI {
  1961. bool initalized;
  1962. bool isCreated;
  1963. bool isEmbed;
  1964. bool isVisible;
  1965. CarlaPluginUI* window;
  1966. UI()
  1967. : initalized(false),
  1968. isCreated(false),
  1969. isEmbed(false),
  1970. isVisible(false),
  1971. window(nullptr) {}
  1972. ~UI()
  1973. {
  1974. CARLA_SAFE_ASSERT(window == nullptr);
  1975. }
  1976. } fUI;
  1977. #endif
  1978. carla_clap_input_audio_buffers fInputAudioBuffers;
  1979. carla_clap_output_audio_buffers fOutputAudioBuffers;
  1980. carla_clap_input_events fInputEvents;
  1981. carla_clap_output_events fOutputEvents;
  1982. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1983. float** fAudioOutBuffers;
  1984. #endif
  1985. #ifdef CARLA_OS_MAC
  1986. BundleLoader fBundleLoader;
  1987. #endif
  1988. };
  1989. // --------------------------------------------------------------------------------------------------------------------
  1990. CarlaPluginPtr CarlaPlugin::newCLAP(const Initializer& init)
  1991. {
  1992. carla_debug("CarlaPlugin::newCLAP({%p, \"%s\", \"%s\", \"%s\"})",
  1993. init.engine, init.filename, init.name, init.label);
  1994. std::shared_ptr<CarlaPluginCLAP> plugin(new CarlaPluginCLAP(init.engine, init.id));
  1995. if (! plugin->init(plugin, init.filename, init.name, init.label, init.options))
  1996. return nullptr;
  1997. return plugin;
  1998. }
  1999. // -------------------------------------------------------------------------------------------------------------------
  2000. CARLA_BACKEND_END_NAMESPACE