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.

2502 lines
81KB

  1. /*
  2. * Carla Plugin
  3. * Copyright (C) 2011-2019 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 "CarlaBase64Utils.hpp"
  21. #include "CarlaMathUtils.hpp"
  22. #include "CarlaPluginUI.hpp"
  23. #include "CarlaStringList.hpp"
  24. #include <ctime>
  25. #include "water/files/File.h"
  26. #include "water/streams/MemoryOutputStream.h"
  27. #include "water/xml/XmlDocument.h"
  28. #include "water/xml/XmlElement.h"
  29. using water::CharPointer_UTF8;
  30. using water::File;
  31. using water::MemoryOutputStream;
  32. using water::Result;
  33. using water::String;
  34. using water::XmlDocument;
  35. using water::XmlElement;
  36. CARLA_BACKEND_START_NAMESPACE
  37. // -------------------------------------------------------------------
  38. // Fallback data
  39. static const ParameterData kParameterDataNull = { PARAMETER_UNKNOWN, 0x0, PARAMETER_NULL, -1, -1, 0 };
  40. static const ParameterRanges kParameterRangesNull = { 0.0f, 0.0f, 1.0f, 0.01f, 0.0001f, 0.1f };
  41. static const MidiProgramData kMidiProgramDataNull = { 0, 0, nullptr };
  42. static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr };
  43. static /* */ CustomData kCustomDataFallbackNC = { nullptr, nullptr, nullptr };
  44. static const PluginPostRtEvent kPluginPostRtEventFallback = { kPluginPostRtEventNull, false, 0, 0, 0, 0.0f };
  45. // -------------------------------------------------------------------
  46. // ParamSymbol struct, needed for CarlaPlugin::loadStateSave()
  47. struct ParamSymbol {
  48. int32_t index;
  49. const char* symbol;
  50. ParamSymbol(const uint32_t i, const char* const s)
  51. : index(static_cast<int32_t>(i)),
  52. symbol(carla_strdup(s)) {}
  53. ~ParamSymbol() noexcept
  54. {
  55. CARLA_SAFE_ASSERT_RETURN(symbol != nullptr,)
  56. delete[] symbol;
  57. symbol = nullptr;
  58. }
  59. #ifdef CARLA_PROPER_CPP11_SUPPORT
  60. ParamSymbol() = delete;
  61. CARLA_DECLARE_NON_COPY_STRUCT(ParamSymbol)
  62. #endif
  63. };
  64. // -------------------------------------------------------------------
  65. // Constructor and destructor
  66. CarlaPlugin::CarlaPlugin(CarlaEngine* const engine, const uint id)
  67. : pData(new ProtectedData(engine, id))
  68. {
  69. CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
  70. CARLA_SAFE_ASSERT(id < engine->getMaxPluginNumber());
  71. carla_debug("CarlaPlugin::CarlaPlugin(%p, %i)", engine, id);
  72. switch (engine->getProccessMode())
  73. {
  74. case ENGINE_PROCESS_MODE_SINGLE_CLIENT:
  75. case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
  76. CARLA_SAFE_ASSERT(id < MAX_DEFAULT_PLUGINS);
  77. break;
  78. case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
  79. CARLA_SAFE_ASSERT(id < MAX_RACK_PLUGINS);
  80. break;
  81. case ENGINE_PROCESS_MODE_PATCHBAY:
  82. CARLA_SAFE_ASSERT(id < MAX_PATCHBAY_PLUGINS);
  83. break;
  84. case ENGINE_PROCESS_MODE_BRIDGE:
  85. CARLA_SAFE_ASSERT(id == 0);
  86. break;
  87. }
  88. }
  89. CarlaPlugin::~CarlaPlugin()
  90. {
  91. carla_debug("CarlaPlugin::~CarlaPlugin()");
  92. delete pData;
  93. }
  94. // -------------------------------------------------------------------
  95. // Information (base)
  96. uint CarlaPlugin::getId() const noexcept
  97. {
  98. return pData->id;
  99. }
  100. uint CarlaPlugin::getHints() const noexcept
  101. {
  102. return pData->hints;
  103. }
  104. uint CarlaPlugin::getOptionsEnabled() const noexcept
  105. {
  106. return pData->options;
  107. }
  108. bool CarlaPlugin::isEnabled() const noexcept
  109. {
  110. return pData->enabled;
  111. }
  112. const char* CarlaPlugin::getName() const noexcept
  113. {
  114. return pData->name;
  115. }
  116. const char* CarlaPlugin::getFilename() const noexcept
  117. {
  118. return pData->filename;
  119. }
  120. const char* CarlaPlugin::getIconName() const noexcept
  121. {
  122. return pData->iconName;
  123. }
  124. PluginCategory CarlaPlugin::getCategory() const noexcept
  125. {
  126. return getPluginCategoryFromName(pData->name);
  127. }
  128. int64_t CarlaPlugin::getUniqueId() const noexcept
  129. {
  130. return 0;
  131. }
  132. uint32_t CarlaPlugin::getLatencyInFrames() const noexcept
  133. {
  134. return 0;
  135. }
  136. // -------------------------------------------------------------------
  137. // Information (count)
  138. uint32_t CarlaPlugin::getAudioInCount() const noexcept
  139. {
  140. return pData->audioIn.count;
  141. }
  142. uint32_t CarlaPlugin::getAudioOutCount() const noexcept
  143. {
  144. return pData->audioOut.count;
  145. }
  146. uint32_t CarlaPlugin::getCVInCount() const noexcept
  147. {
  148. return pData->cvIn.count;
  149. }
  150. uint32_t CarlaPlugin::getCVOutCount() const noexcept
  151. {
  152. return pData->cvOut.count;
  153. }
  154. uint32_t CarlaPlugin::getMidiInCount() const noexcept
  155. {
  156. return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_IN) ? 1 : 0;
  157. }
  158. uint32_t CarlaPlugin::getMidiOutCount() const noexcept
  159. {
  160. return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_OUT) ? 1 : 0;
  161. }
  162. uint32_t CarlaPlugin::getParameterCount() const noexcept
  163. {
  164. return pData->param.count;
  165. }
  166. uint32_t CarlaPlugin::getParameterScalePointCount(const uint32_t parameterId) const noexcept
  167. {
  168. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0);
  169. return 0;
  170. }
  171. uint32_t CarlaPlugin::getProgramCount() const noexcept
  172. {
  173. return pData->prog.count;
  174. }
  175. uint32_t CarlaPlugin::getMidiProgramCount() const noexcept
  176. {
  177. return pData->midiprog.count;
  178. }
  179. uint32_t CarlaPlugin::getCustomDataCount() const noexcept
  180. {
  181. return static_cast<uint32_t>(pData->custom.count());
  182. }
  183. // -------------------------------------------------------------------
  184. // Information (current data)
  185. int32_t CarlaPlugin::getCurrentProgram() const noexcept
  186. {
  187. return pData->prog.current;
  188. }
  189. int32_t CarlaPlugin::getCurrentMidiProgram() const noexcept
  190. {
  191. return pData->midiprog.current;
  192. }
  193. const ParameterData& CarlaPlugin::getParameterData(const uint32_t parameterId) const noexcept
  194. {
  195. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterDataNull);
  196. return pData->param.data[parameterId];
  197. }
  198. const ParameterRanges& CarlaPlugin::getParameterRanges(const uint32_t parameterId) const noexcept
  199. {
  200. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterRangesNull);
  201. return pData->param.ranges[parameterId];
  202. }
  203. bool CarlaPlugin::isParameterOutput(const uint32_t parameterId) const noexcept
  204. {
  205. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
  206. return (pData->param.data[parameterId].type == PARAMETER_OUTPUT);
  207. }
  208. const MidiProgramData& CarlaPlugin::getMidiProgramData(const uint32_t index) const noexcept
  209. {
  210. CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, kMidiProgramDataNull);
  211. return pData->midiprog.data[index];
  212. }
  213. const CustomData& CarlaPlugin::getCustomData(const uint32_t index) const noexcept
  214. {
  215. return pData->custom.getAt(index, kCustomDataFallback);
  216. }
  217. std::size_t CarlaPlugin::getChunkData(void** const dataPtr) noexcept
  218. {
  219. CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0);
  220. CARLA_SAFE_ASSERT(false); // this should never happen
  221. return 0;
  222. }
  223. // -------------------------------------------------------------------
  224. // Information (per-plugin data)
  225. uint CarlaPlugin::getOptionsAvailable() const noexcept
  226. {
  227. CARLA_SAFE_ASSERT(false); // this should never happen
  228. return 0x0;
  229. }
  230. float CarlaPlugin::getParameterValue(const uint32_t parameterId) const noexcept
  231. {
  232. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
  233. CARLA_SAFE_ASSERT(false); // this should never happen
  234. return 0.0f;
  235. }
  236. float CarlaPlugin::getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) const noexcept
  237. {
  238. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
  239. CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), 0.0f);
  240. CARLA_SAFE_ASSERT(false); // this should never happen
  241. return 0.0f;
  242. }
  243. bool CarlaPlugin::getLabel(char* const strBuf) const noexcept
  244. {
  245. strBuf[0] = '\0';
  246. return false;
  247. }
  248. bool CarlaPlugin::getMaker(char* const strBuf) const noexcept
  249. {
  250. strBuf[0] = '\0';
  251. return false;
  252. }
  253. bool CarlaPlugin::getCopyright(char* const strBuf) const noexcept
  254. {
  255. strBuf[0] = '\0';
  256. return false;
  257. }
  258. bool CarlaPlugin::getRealName(char* const strBuf) const noexcept
  259. {
  260. strBuf[0] = '\0';
  261. return false;
  262. }
  263. bool CarlaPlugin::getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept
  264. {
  265. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  266. CARLA_SAFE_ASSERT(false); // this should never happen
  267. strBuf[0] = '\0';
  268. return false;
  269. }
  270. bool CarlaPlugin::getParameterSymbol(const uint32_t parameterId, char* const strBuf) const noexcept
  271. {
  272. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  273. strBuf[0] = '\0';
  274. return false;
  275. }
  276. bool CarlaPlugin::getParameterText(const uint32_t parameterId, char* const strBuf) noexcept
  277. {
  278. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  279. CARLA_SAFE_ASSERT(false); // this should never happen
  280. strBuf[0] = '\0';
  281. return false;
  282. }
  283. bool CarlaPlugin::getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept
  284. {
  285. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  286. strBuf[0] = '\0';
  287. return false;
  288. }
  289. bool CarlaPlugin::getParameterComment(const uint32_t parameterId, char* const strBuf) const noexcept
  290. {
  291. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  292. strBuf[0] = '\0';
  293. return false;
  294. }
  295. bool CarlaPlugin::getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept
  296. {
  297. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  298. strBuf[0] = '\0';
  299. return false;
  300. }
  301. bool CarlaPlugin::getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) const noexcept
  302. {
  303. CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
  304. CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), false);
  305. CARLA_SAFE_ASSERT(false); // this should never happen
  306. strBuf[0] = '\0';
  307. return false;
  308. }
  309. float CarlaPlugin::getInternalParameterValue(const int32_t parameterId) const noexcept
  310. {
  311. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  312. CARLA_SAFE_ASSERT_RETURN(parameterId != PARAMETER_NULL && parameterId > PARAMETER_MAX, 0.0f);
  313. switch (parameterId)
  314. {
  315. case PARAMETER_ACTIVE:
  316. return pData->active;
  317. case PARAMETER_CTRL_CHANNEL:
  318. return pData->ctrlChannel;
  319. case PARAMETER_DRYWET:
  320. return pData->postProc.dryWet;
  321. case PARAMETER_VOLUME:
  322. return pData->postProc.volume;
  323. case PARAMETER_BALANCE_LEFT:
  324. return pData->postProc.balanceLeft;
  325. case PARAMETER_BALANCE_RIGHT:
  326. return pData->postProc.balanceRight;
  327. case PARAMETER_PANNING:
  328. return pData->postProc.panning;
  329. };
  330. #endif
  331. CARLA_SAFE_ASSERT_RETURN(parameterId >= 0, 0.0f);
  332. return getParameterValue(static_cast<uint32_t>(parameterId));
  333. }
  334. bool CarlaPlugin::getProgramName(const uint32_t index, char* const strBuf) const noexcept
  335. {
  336. CARLA_SAFE_ASSERT_RETURN(index < pData->prog.count, false);
  337. CARLA_SAFE_ASSERT_RETURN(pData->prog.names[index] != nullptr, false);
  338. std::strncpy(strBuf, pData->prog.names[index], STR_MAX);
  339. return false;
  340. }
  341. bool CarlaPlugin::getMidiProgramName(const uint32_t index, char* const strBuf) const noexcept
  342. {
  343. CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, false);
  344. CARLA_SAFE_ASSERT_RETURN(pData->midiprog.data[index].name != nullptr, false);
  345. std::strncpy(strBuf, pData->midiprog.data[index].name, STR_MAX);
  346. return false;
  347. }
  348. void CarlaPlugin::getParameterCountInfo(uint32_t& ins, uint32_t& outs) const noexcept
  349. {
  350. ins = 0;
  351. outs = 0;
  352. for (uint32_t i=0; i < pData->param.count; ++i)
  353. {
  354. if (pData->param.data[i].type == PARAMETER_INPUT)
  355. ++ins;
  356. else if (pData->param.data[i].type == PARAMETER_OUTPUT)
  357. ++outs;
  358. }
  359. }
  360. // -------------------------------------------------------------------
  361. // Set data (state)
  362. void CarlaPlugin::prepareForSave()
  363. {
  364. }
  365. void CarlaPlugin::resetParameters() noexcept
  366. {
  367. for (uint i=0; i < pData->param.count; ++i)
  368. {
  369. const ParameterData& paramData(pData->param.data[i]);
  370. const ParameterRanges& paramRanges(pData->param.ranges[i]);
  371. if (paramData.type != PARAMETER_INPUT)
  372. continue;
  373. if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
  374. continue;
  375. setParameterValue(i, paramRanges.def, true, true, true);
  376. }
  377. }
  378. void CarlaPlugin::randomizeParameters() noexcept
  379. {
  380. float value, random;
  381. char strBuf[STR_MAX+1];
  382. strBuf[STR_MAX] = '\0';
  383. std::srand(static_cast<uint>(std::time(nullptr)));
  384. for (uint i=0; i < pData->param.count; ++i)
  385. {
  386. const ParameterData& paramData(pData->param.data[i]);
  387. if (paramData.type != PARAMETER_INPUT)
  388. continue;
  389. if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
  390. continue;
  391. if (! getParameterName(i, strBuf))
  392. strBuf[0] = '\0';
  393. if (std::strstr(strBuf, "olume") != nullptr)
  394. continue;
  395. if (std::strstr(strBuf, "Master") != nullptr)
  396. continue;
  397. const ParameterRanges& paramRanges(pData->param.ranges[i]);
  398. if (paramData.hints & PARAMETER_IS_BOOLEAN)
  399. {
  400. random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
  401. value = random > 0.5f ? paramRanges.max : paramRanges.min;
  402. }
  403. else
  404. {
  405. random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
  406. value = random * (paramRanges.max - paramRanges.min) + paramRanges.min;
  407. if (paramData.hints & PARAMETER_IS_INTEGER)
  408. value = std::rint(value);
  409. }
  410. setParameterValue(i, value, true, true, true);
  411. }
  412. }
  413. const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave)
  414. {
  415. if (callPrepareForSave)
  416. prepareForSave();
  417. pData->stateSave.clear();
  418. const PluginType pluginType(getType());
  419. char strBuf[STR_MAX+1];
  420. carla_zeroChars(strBuf, STR_MAX+1);
  421. // ---------------------------------------------------------------
  422. // Basic info
  423. if (! getLabel(strBuf))
  424. strBuf[0] = '\0';
  425. pData->stateSave.type = carla_strdup(getPluginTypeAsString(pluginType));
  426. pData->stateSave.name = carla_strdup(pData->name);
  427. pData->stateSave.label = carla_strdup(strBuf);
  428. pData->stateSave.uniqueId = getUniqueId();
  429. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  430. pData->stateSave.options = pData->options;
  431. #endif
  432. if (pData->filename != nullptr)
  433. pData->stateSave.binary = carla_strdup(pData->filename);
  434. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  435. // ---------------------------------------------------------------
  436. // Internals
  437. pData->stateSave.active = pData->active;
  438. pData->stateSave.dryWet = pData->postProc.dryWet;
  439. pData->stateSave.volume = pData->postProc.volume;
  440. pData->stateSave.balanceLeft = pData->postProc.balanceLeft;
  441. pData->stateSave.balanceRight = pData->postProc.balanceRight;
  442. pData->stateSave.panning = pData->postProc.panning;
  443. pData->stateSave.ctrlChannel = pData->ctrlChannel;
  444. #endif
  445. bool usingChunk = false;
  446. // ---------------------------------------------------------------
  447. // Chunk
  448. if (pData->options & PLUGIN_OPTION_USE_CHUNKS)
  449. {
  450. void* data = nullptr;
  451. const std::size_t dataSize(getChunkData(&data));
  452. if (data != nullptr && dataSize > 0)
  453. {
  454. pData->stateSave.chunk = CarlaString::asBase64(data, dataSize).dup();
  455. if (pluginType != PLUGIN_INTERNAL)
  456. usingChunk = true;
  457. }
  458. }
  459. // ---------------------------------------------------------------
  460. // Current Program
  461. if (pData->prog.current >= 0 && pluginType != PLUGIN_LV2)
  462. {
  463. pData->stateSave.currentProgramIndex = pData->prog.current;
  464. pData->stateSave.currentProgramName = carla_strdup(pData->prog.names[pData->prog.current]);
  465. }
  466. // ---------------------------------------------------------------
  467. // Current MIDI Program
  468. if (pData->midiprog.current >= 0 && pluginType != PLUGIN_LV2 && pluginType != PLUGIN_SF2)
  469. {
  470. const MidiProgramData& mpData(pData->midiprog.getCurrent());
  471. pData->stateSave.currentMidiBank = static_cast<int32_t>(mpData.bank);
  472. pData->stateSave.currentMidiProgram = static_cast<int32_t>(mpData.program);
  473. }
  474. // ---------------------------------------------------------------
  475. // Parameters
  476. const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
  477. for (uint32_t i=0; i < pData->param.count; ++i)
  478. {
  479. const ParameterData& paramData(pData->param.data[i]);
  480. if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
  481. continue;
  482. const bool dummy = paramData.type != PARAMETER_INPUT || usingChunk;
  483. if (dummy && paramData.midiCC <= -1)
  484. continue;
  485. CarlaStateSave::Parameter* const stateParameter(new CarlaStateSave::Parameter());
  486. stateParameter->dummy = dummy;
  487. stateParameter->index = paramData.index;
  488. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  489. stateParameter->midiCC = paramData.midiCC;
  490. stateParameter->midiChannel = paramData.midiChannel;
  491. #endif
  492. if (! getParameterName(i, strBuf))
  493. strBuf[0] = '\0';
  494. stateParameter->name = carla_strdup(strBuf);
  495. if (! getParameterSymbol(i, strBuf))
  496. strBuf[0] = '\0';
  497. stateParameter->symbol = carla_strdup(strBuf);;
  498. if (! dummy)
  499. {
  500. stateParameter->value = getParameterValue(i);
  501. if (paramData.hints & PARAMETER_USES_SAMPLERATE)
  502. stateParameter->value /= sampleRate;
  503. }
  504. pData->stateSave.parameters.append(stateParameter);
  505. }
  506. // ---------------------------------------------------------------
  507. // Custom Data
  508. if (pData->hints & PLUGIN_IS_BRIDGE)
  509. waitForBridgeSaveSignal();
  510. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  511. {
  512. const CustomData& cData(it.getValue(kCustomDataFallback));
  513. CARLA_SAFE_ASSERT_CONTINUE(cData.isValid());
  514. CarlaStateSave::CustomData* stateCustomData(new CarlaStateSave::CustomData());
  515. stateCustomData->type = carla_strdup(cData.type);
  516. stateCustomData->key = carla_strdup(cData.key);
  517. stateCustomData->value = carla_strdup(cData.value);
  518. pData->stateSave.customData.append(stateCustomData);
  519. }
  520. return pData->stateSave;
  521. }
  522. void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave)
  523. {
  524. const bool usesMultiProgs(pData->hints & PLUGIN_USES_MULTI_PROGS);
  525. const PluginType pluginType(getType());
  526. char strBuf[STR_MAX+1];
  527. carla_zeroChars(strBuf, STR_MAX+1);
  528. // ---------------------------------------------------------------
  529. // Part 1 - PRE-set custom data (only those which reload programs)
  530. for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
  531. {
  532. const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
  533. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
  534. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
  535. const char* const key(stateCustomData->key);
  536. /**/ if (pluginType == PLUGIN_DSSI && (std::strcmp (key, "reloadprograms") == 0 ||
  537. std::strcmp (key, "load" ) == 0 ||
  538. std::strncmp(key, "patches", 7) == 0 ))
  539. pass();
  540. else if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0)
  541. pass();
  542. else
  543. continue;
  544. setCustomData(stateCustomData->type, key, stateCustomData->value, true);
  545. }
  546. // ---------------------------------------------------------------
  547. // Part 2 - set program
  548. if (stateSave.currentProgramIndex >= 0 && stateSave.currentProgramName != nullptr)
  549. {
  550. int32_t programId = -1;
  551. // index < count
  552. if (stateSave.currentProgramIndex < static_cast<int32_t>(pData->prog.count))
  553. {
  554. programId = stateSave.currentProgramIndex;
  555. }
  556. // index not valid, try to find by name
  557. else
  558. {
  559. for (uint32_t i=0; i < pData->prog.count; ++i)
  560. {
  561. if (getProgramName(i, strBuf) && std::strcmp(stateSave.currentProgramName, strBuf) == 0)
  562. {
  563. programId = static_cast<int32_t>(i);
  564. break;
  565. }
  566. }
  567. }
  568. // set program now, if valid
  569. if (programId >= 0)
  570. setProgram(programId, true, true, true);
  571. }
  572. // ---------------------------------------------------------------
  573. // Part 3 - set midi program
  574. if (stateSave.currentMidiBank >= 0 && stateSave.currentMidiProgram >= 0 && ! usesMultiProgs)
  575. setMidiProgramById(static_cast<uint32_t>(stateSave.currentMidiBank), static_cast<uint32_t>(stateSave.currentMidiProgram), true, true, true);
  576. // ---------------------------------------------------------------
  577. // Part 4a - get plugin parameter symbols
  578. LinkedList<ParamSymbol*> paramSymbols;
  579. if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2)
  580. {
  581. for (uint32_t i=0; i < pData->param.count; ++i)
  582. {
  583. if (getParameterSymbol(i, strBuf))
  584. {
  585. ParamSymbol* const paramSymbol(new ParamSymbol(i, strBuf));
  586. paramSymbols.append(paramSymbol);
  587. }
  588. }
  589. }
  590. // ---------------------------------------------------------------
  591. // Part 4b - set parameter values (carefully)
  592. const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
  593. for (CarlaStateSave::ParameterItenerator it = stateSave.parameters.begin2(); it.valid(); it.next())
  594. {
  595. CarlaStateSave::Parameter* const stateParameter(it.getValue(nullptr));
  596. CARLA_SAFE_ASSERT_CONTINUE(stateParameter != nullptr);
  597. int32_t index = -1;
  598. if (pluginType == PLUGIN_LADSPA)
  599. {
  600. // Try to set by symbol, otherwise use index
  601. if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
  602. {
  603. for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
  604. {
  605. ParamSymbol* const paramSymbol(it2.getValue(nullptr));
  606. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
  607. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
  608. if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
  609. {
  610. index = paramSymbol->index;
  611. break;
  612. }
  613. }
  614. if (index == -1)
  615. index = stateParameter->index;
  616. }
  617. else
  618. {
  619. index = stateParameter->index;
  620. }
  621. }
  622. else if (pluginType == PLUGIN_LV2)
  623. {
  624. // Symbol only
  625. if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
  626. {
  627. for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
  628. {
  629. ParamSymbol* const paramSymbol(it2.getValue(nullptr));
  630. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
  631. CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
  632. if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
  633. {
  634. index = paramSymbol->index;
  635. break;
  636. }
  637. }
  638. if (index == -1)
  639. carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'",
  640. stateParameter->symbol, pData->name);
  641. }
  642. else
  643. {
  644. carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name);
  645. }
  646. }
  647. else
  648. {
  649. // Index only
  650. index = stateParameter->index;
  651. }
  652. // Now set parameter
  653. if (index >= 0 && index < static_cast<int32_t>(pData->param.count))
  654. {
  655. //CARLA_SAFE_ASSERT(stateParameter->isInput == (pData
  656. if (! stateParameter->dummy)
  657. {
  658. if (pData->param.data[index].hints & PARAMETER_USES_SAMPLERATE)
  659. stateParameter->value *= sampleRate;
  660. setParameterValue(static_cast<uint32_t>(index), stateParameter->value, true, true, true);
  661. }
  662. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  663. setParameterMidiCC(static_cast<uint32_t>(index), stateParameter->midiCC, true, true);
  664. setParameterMidiChannel(static_cast<uint32_t>(index), stateParameter->midiChannel, true, true);
  665. #endif
  666. }
  667. else
  668. carla_stderr("Could not set parameter '%s' value for '%s'",
  669. stateParameter->name, pData->name);
  670. }
  671. // ---------------------------------------------------------------
  672. // Part 4c - clear
  673. for (LinkedList<ParamSymbol*>::Itenerator it = paramSymbols.begin2(); it.valid(); it.next())
  674. {
  675. ParamSymbol* const paramSymbol(it.getValue(nullptr));
  676. delete paramSymbol;
  677. }
  678. paramSymbols.clear();
  679. // ---------------------------------------------------------------
  680. // Part 5 - set custom data
  681. for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
  682. {
  683. const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
  684. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
  685. CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
  686. const char* const key(stateCustomData->key);
  687. if (pluginType == PLUGIN_DSSI && (std::strcmp (key, "reloadprograms") == 0 ||
  688. std::strcmp (key, "load" ) == 0 ||
  689. std::strncmp(key, "patches", 7) == 0 ))
  690. continue;
  691. if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0)
  692. continue;
  693. setCustomData(stateCustomData->type, key, stateCustomData->value, true);
  694. }
  695. // ---------------------------------------------------------------
  696. // Part 5x - set lv2 state
  697. if (pluginType == PLUGIN_LV2)
  698. {
  699. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  700. {
  701. const CustomData& customData(it.getValue(kCustomDataFallback));
  702. CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
  703. if (std::strcmp(customData.type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
  704. continue;
  705. restoreLV2State();
  706. break;
  707. }
  708. }
  709. // ---------------------------------------------------------------
  710. // Part 6 - set chunk
  711. if (stateSave.chunk != nullptr && (pData->options & PLUGIN_OPTION_USE_CHUNKS) != 0)
  712. {
  713. std::vector<uint8_t> chunk(carla_getChunkFromBase64String(stateSave.chunk));
  714. #ifdef CARLA_PROPER_CPP11_SUPPORT
  715. setChunkData(chunk.data(), chunk.size());
  716. #else
  717. setChunkData(&chunk.front(), chunk.size());
  718. #endif
  719. }
  720. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  721. // ---------------------------------------------------------------
  722. // Part 6 - set internal stuff
  723. const uint availOptions(getOptionsAvailable());
  724. for (uint i=0; i<10; ++i) // FIXME - get this value somehow...
  725. {
  726. const uint option(1u << i);
  727. if (availOptions & option)
  728. setOption(option, (stateSave.options & option) != 0, true);
  729. }
  730. setDryWet(stateSave.dryWet, true, true);
  731. setVolume(stateSave.volume, true, true);
  732. setBalanceLeft(stateSave.balanceLeft, true, true);
  733. setBalanceRight(stateSave.balanceRight, true, true);
  734. setPanning(stateSave.panning, true, true);
  735. setCtrlChannel(stateSave.ctrlChannel, true, true);
  736. setActive(stateSave.active, true, true);
  737. if (! pData->engine->isLoadingProject())
  738. pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0, 0.0f, nullptr);
  739. #endif
  740. }
  741. bool CarlaPlugin::saveStateToFile(const char* const filename)
  742. {
  743. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
  744. carla_debug("CarlaPlugin::saveStateToFile(\"%s\")", filename);
  745. MemoryOutputStream out, streamState;
  746. getStateSave().dumpToMemoryStream(streamState);
  747. out << "<?xml version='1.0' encoding='UTF-8'?>\n";
  748. out << "<!DOCTYPE CARLA-PRESET>\n";
  749. out << "<CARLA-PRESET VERSION='2.0'>\n";
  750. out << streamState;
  751. out << "</CARLA-PRESET>\n";
  752. const String jfilename = String(CharPointer_UTF8(filename));
  753. File file(jfilename);
  754. if (file.replaceWithData(out.getData(), out.getDataSize()))
  755. return true;
  756. pData->engine->setLastError("Failed to write file");
  757. return false;
  758. }
  759. bool CarlaPlugin::loadStateFromFile(const char* const filename)
  760. {
  761. // TODO set errors
  762. CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
  763. carla_debug("CarlaPlugin::loadStateFromFile(\"%s\")", filename);
  764. const String jfilename = String(CharPointer_UTF8(filename));
  765. File file(jfilename);
  766. CARLA_SAFE_ASSERT_RETURN(file.existsAsFile(), false);
  767. XmlDocument xml(file);
  768. ScopedPointer<XmlElement> xmlElement(xml.getDocumentElement(true));
  769. CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
  770. CARLA_SAFE_ASSERT_RETURN(xmlElement->getTagName().equalsIgnoreCase("carla-preset"), false);
  771. // completely load file
  772. xmlElement = xml.getDocumentElement(false);
  773. CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
  774. if (pData->stateSave.fillFromXmlElement(xmlElement))
  775. {
  776. loadStateSave(pData->stateSave);
  777. return true;
  778. }
  779. return false;
  780. }
  781. bool CarlaPlugin::exportAsLV2(const char* const lv2path)
  782. {
  783. CARLA_SAFE_ASSERT_RETURN(lv2path != nullptr && lv2path[0] != '\0', false);
  784. carla_debug("CarlaPlugin::exportAsLV2(\"%s\")", lv2path);
  785. CarlaString bundlepath(lv2path);
  786. if (! bundlepath.endsWith(".lv2"))
  787. bundlepath += ".lv2";
  788. const File bundlefolder(bundlepath.buffer());
  789. if (bundlefolder.existsAsFile())
  790. {
  791. pData->engine->setLastError("Requested filename already exists as file, use a folder instead");
  792. return false;
  793. }
  794. if (! bundlefolder.exists())
  795. {
  796. const Result res(bundlefolder.createDirectory());
  797. if (res.failed())
  798. {
  799. pData->engine->setLastError(res.getErrorMessage().toRawUTF8());
  800. return false;
  801. }
  802. }
  803. CarlaString symbol(pData->name);
  804. symbol.toBasic();
  805. {
  806. const CarlaString pluginFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".xml");
  807. if (! saveStateToFile(pluginFilename))
  808. return false;
  809. }
  810. {
  811. MemoryOutputStream manifestStream;
  812. manifestStream << "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
  813. manifestStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
  814. manifestStream << "@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n";
  815. manifestStream << "\n";
  816. manifestStream << "<" << symbol.buffer() << ".ttl>\n";
  817. manifestStream << " a lv2:Plugin ;\n";
  818. manifestStream << " lv2:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
  819. manifestStream << " rdfs:seeAlso <" << symbol.buffer() << ".ttl> .\n";
  820. manifestStream << "\n";
  821. manifestStream << "<ext-ui>\n";
  822. manifestStream << " a <http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget> ;\n";
  823. manifestStream << " ui:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
  824. manifestStream << " lv2:extensionData <http://lv2plug.in/ns/extensions/ui#idleInterface> ,\n";
  825. manifestStream << " <http://lv2plug.in/ns/extensions/ui#showInterface> ;\n";
  826. manifestStream << " lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> .\n";
  827. manifestStream << "\n";
  828. const CarlaString manifestFilename(bundlepath + CARLA_OS_SEP_STR "manifest.ttl");
  829. const File manifestFile(manifestFilename.buffer());
  830. if (! manifestFile.replaceWithData(manifestStream.getData(), manifestStream.getDataSize()))
  831. {
  832. pData->engine->setLastError("Failed to write manifest.ttl file");
  833. return false;
  834. }
  835. }
  836. {
  837. MemoryOutputStream mainStream;
  838. mainStream << "@prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n";
  839. mainStream << "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
  840. mainStream << "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
  841. mainStream << "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
  842. mainStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
  843. mainStream << "@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n";
  844. mainStream << "\n";
  845. mainStream << "<>\n";
  846. mainStream << " a lv2:Plugin ;\n";
  847. mainStream << "\n";
  848. mainStream << " lv2:requiredFeature <http://lv2plug.in/ns/ext/buf-size#boundedBlockLength> ,\n";
  849. mainStream << " <http://lv2plug.in/ns/ext/options#options> ,\n";
  850. mainStream << " <http://lv2plug.in/ns/ext/urid#map> ;\n";
  851. mainStream << "\n";
  852. if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
  853. {
  854. mainStream << " ui:ui <ext-ui> ;\n";
  855. mainStream << "\n";
  856. }
  857. const uint32_t midiIns = getMidiInCount();
  858. const uint32_t midiOuts = getMidiOutCount();
  859. int portIndex = 0;
  860. if (midiIns > 0)
  861. {
  862. mainStream << " lv2:port [\n";
  863. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  864. mainStream << " lv2:index 0 ;\n";
  865. mainStream << " lv2:symbol \"clv2_events_in\" ;\n";
  866. mainStream << " lv2:name \"Events Input\" ;\n";
  867. mainStream << " atom:bufferType atom:Sequence ;\n";
  868. mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ,\n";
  869. mainStream << " <http://lv2plug.in/ns/ext/time#Position> ;\n";
  870. mainStream << " ] ;\n";
  871. ++portIndex;
  872. for (uint32_t i=1; i<midiIns; ++i)
  873. {
  874. const String portIndexNum(portIndex++);
  875. const String portIndexLabel(portIndex);
  876. mainStream << " lv2:port [\n";
  877. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  878. mainStream << " lv2:index " << portIndexNum << " ;\n";
  879. mainStream << " lv2:symbol \"clv2_midi_in_" << portIndexLabel << "\" ;\n";
  880. mainStream << " lv2:name \"MIDI Input " << portIndexLabel << "\" ;\n";
  881. mainStream << " ] ;\n";
  882. }
  883. }
  884. else
  885. {
  886. mainStream << " lv2:port [\n";
  887. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  888. mainStream << " lv2:index 0 ;\n";
  889. mainStream << " lv2:symbol \"clv2_time_info\" ;\n";
  890. mainStream << " lv2:name \"Time Info\" ;\n";
  891. mainStream << " atom:bufferType atom:Sequence ;\n";
  892. mainStream << " atom:supports <http://lv2plug.in/ns/ext/time#Position> ;\n";
  893. mainStream << " ] ;\n";
  894. ++portIndex;
  895. }
  896. for (uint32_t i=0; i<midiOuts; ++i)
  897. {
  898. const String portIndexNum(portIndex++);
  899. const String portIndexLabel(portIndex);
  900. mainStream << " lv2:port [\n";
  901. mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
  902. mainStream << " lv2:index " << portIndexNum << " ;\n";
  903. mainStream << " lv2:symbol \"clv2_midi_out_" << portIndexLabel << "\" ;\n";
  904. mainStream << " lv2:name \"MIDI Output " << portIndexLabel << "\" ;\n";
  905. mainStream << " atom:bufferType atom:Sequence ;\n";
  906. mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n";
  907. mainStream << " ] ;\n";
  908. }
  909. mainStream << " lv2:port [\n";
  910. mainStream << " a lv2:InputPort, lv2:ControlPort ;\n";
  911. mainStream << " lv2:index " << String(portIndex++) << " ;\n";
  912. mainStream << " lv2:name \"freewheel\" ;\n";
  913. mainStream << " lv2:symbol \"clv2_freewheel\" ;\n";
  914. mainStream << " lv2:default 0 ;\n";
  915. mainStream << " lv2:minimum 0 ;\n";
  916. mainStream << " lv2:maximum 1 ;\n";
  917. mainStream << " lv2:designation lv2:freeWheeling ;\n";
  918. mainStream << " lv2:portProperty lv2:toggled , lv2:integer ;\n";
  919. mainStream << " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#notOnGUI> ;\n";
  920. mainStream << " ] ;\n";
  921. for (uint32_t i=0; i<pData->audioIn.count; ++i)
  922. {
  923. const String portIndexNum(portIndex++);
  924. const String portIndexLabel(i+1);
  925. mainStream << " lv2:port [\n";
  926. mainStream << " a lv2:InputPort, lv2:AudioPort ;\n";
  927. mainStream << " lv2:index " << portIndexNum << " ;\n";
  928. mainStream << " lv2:symbol \"clv2_audio_in_" << portIndexLabel << "\" ;\n";
  929. mainStream << " lv2:name \"Audio Input " << portIndexLabel << "\" ;\n";
  930. mainStream << " ] ;\n";
  931. }
  932. for (uint32_t i=0; i<pData->audioOut.count; ++i)
  933. {
  934. const String portIndexNum(portIndex++);
  935. const String portIndexLabel(i+1);
  936. mainStream << " lv2:port [\n";
  937. mainStream << " a lv2:OutputPort, lv2:AudioPort ;\n";
  938. mainStream << " lv2:index " << portIndexNum << " ;\n";
  939. mainStream << " lv2:symbol \"clv2_audio_out_" << portIndexLabel << "\" ;\n";
  940. mainStream << " lv2:name \"Audio Output " << portIndexLabel << "\" ;\n";
  941. mainStream << " ] ;\n";
  942. }
  943. CarlaStringList uniqueSymbolNames;
  944. char strBufName[STR_MAX+1];
  945. char strBufSymbol[STR_MAX+1];
  946. carla_zeroChars(strBufName, STR_MAX+1);
  947. carla_zeroChars(strBufSymbol, STR_MAX+1);
  948. for (uint32_t i=0; i<pData->param.count; ++i)
  949. {
  950. const ParameterData& paramData(pData->param.data[i]);
  951. const ParameterRanges& paramRanges(pData->param.ranges[i]);
  952. const String portIndexNum(portIndex++);
  953. mainStream << " lv2:port [\n";
  954. if (paramData.type == PARAMETER_INPUT)
  955. mainStream << " a lv2:InputPort, lv2:ControlPort ;\n";
  956. else
  957. mainStream << " a lv2:OutputPort, lv2:ControlPort ;\n";
  958. if (paramData.hints & PARAMETER_IS_BOOLEAN)
  959. mainStream << " lv2:portProperty lv2:toggled ;\n";
  960. if (paramData.hints & PARAMETER_IS_INTEGER)
  961. mainStream << " lv2:portProperty lv2:integer ;\n";
  962. // TODO logarithmic, enabled (not on gui), automable, samplerate, scalepoints
  963. if (! getParameterName(i, strBufName))
  964. strBufName[0] = '\0';
  965. if (! getParameterSymbol(i, strBufSymbol))
  966. strBufSymbol[0] = '\0';
  967. if (strBufSymbol[0] == '\0')
  968. {
  969. CarlaString s(strBufName);
  970. s.toBasic();
  971. std::memcpy(strBufSymbol, s.buffer(), s.length()+1);
  972. if (strBufSymbol[0] >= '0' && strBufSymbol[0] <= '9')
  973. {
  974. const size_t len(std::strlen(strBufSymbol));
  975. std::memmove(strBufSymbol+1, strBufSymbol, len);
  976. strBufSymbol[0] = '_';
  977. strBufSymbol[len+1] = '\0';
  978. }
  979. }
  980. if (uniqueSymbolNames.contains(strBufSymbol))
  981. std::snprintf(strBufSymbol, STR_MAX, "clv2_param_%d", i+1);
  982. mainStream << " lv2:index " << portIndexNum << " ;\n";
  983. mainStream << " lv2:symbol \"" << strBufSymbol << "\" ;\n";
  984. mainStream << " lv2:name \"\"\"" << strBufName << "\"\"\" ;\n";
  985. mainStream << " lv2:default " << String(paramRanges.def) << " ;\n";
  986. mainStream << " lv2:minimum " << String(paramRanges.min) << " ;\n";
  987. mainStream << " lv2:maximum " << String(paramRanges.max) << " ;\n";
  988. // TODO midiCC, midiChannel
  989. mainStream << " ] ;\n";
  990. }
  991. char strBuf[STR_MAX+1];
  992. carla_zeroChars(strBuf, STR_MAX+1);
  993. if (! getMaker(strBuf))
  994. strBuf[0] = '\0';
  995. mainStream << " rdfs:comment \"Plugin generated using Carla LV2 export.\" ;\n";
  996. mainStream << " doap:name \"\"\"" << getName() << "\"\"\" ;\n";
  997. mainStream << " doap:maintainer [ foaf:name \"\"\"" << strBuf << "\"\"\" ] .\n";
  998. mainStream << "\n";
  999. const CarlaString mainFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".ttl");
  1000. const File mainFile(mainFilename.buffer());
  1001. if (! mainFile.replaceWithData(mainStream.getData(), mainStream.getDataSize()))
  1002. {
  1003. pData->engine->setLastError("Failed to write main plugin ttl file");
  1004. return false;
  1005. }
  1006. }
  1007. const CarlaString binaryFilename(bundlepath + CARLA_OS_SEP_STR + symbol + CARLA_LIB_EXT);
  1008. const File binaryFileSource(File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("carla-bridge-lv2" CARLA_LIB_EXT));
  1009. const File binaryFileTarget(binaryFilename.buffer());
  1010. const EngineOptions& opts(pData->engine->getOptions());
  1011. const CarlaString binFolderTarget(bundlepath + CARLA_OS_SEP_STR + "bin");
  1012. const CarlaString resFolderTarget(bundlepath + CARLA_OS_SEP_STR + "res");
  1013. if (! binaryFileSource.copyFileTo(binaryFileTarget))
  1014. {
  1015. pData->engine->setLastError("Failed to copy plugin binary");
  1016. return false;
  1017. }
  1018. #ifdef CARLA_OS_WIN
  1019. File(opts.resourceDir).copyDirectoryTo(File(resFolderTarget.buffer()));
  1020. // Copying all the binaries is pointless, just go through the expected needed bits
  1021. const File binFolder1(opts.binaryDir);
  1022. const File binFolder2(binFolderTarget.buffer());
  1023. binFolder2.createDirectory();
  1024. static const char* files[] = {
  1025. "carla-bridge-native.exe",
  1026. "carla-bridge-win32.exe",
  1027. "carla-discovery-win32.exe",
  1028. "carla-discovery-win64.exe",
  1029. "libcarla_utils.dll"
  1030. };
  1031. for (int i=0; i<5; ++i)
  1032. binFolder1.getChildFile(files[i]).copyFileTo(binFolder2.getChildFile(files[i]));;
  1033. #else
  1034. File(opts.binaryDir).createSymbolicLink(File(binFolderTarget.buffer()), true);
  1035. File(opts.resourceDir).createSymbolicLink(File(resFolderTarget.buffer()), true);
  1036. #endif
  1037. return true;
  1038. }
  1039. // -------------------------------------------------------------------
  1040. // Set data (internal stuff)
  1041. void CarlaPlugin::setId(const uint newId) noexcept
  1042. {
  1043. pData->id = newId;
  1044. }
  1045. void CarlaPlugin::setName(const char* const newName)
  1046. {
  1047. CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0',);
  1048. if (pData->name != nullptr)
  1049. delete[] pData->name;
  1050. pData->name = carla_strdup(newName);
  1051. }
  1052. void CarlaPlugin::setOption(const uint option, const bool yesNo, const bool sendCallback)
  1053. {
  1054. CARLA_SAFE_ASSERT_RETURN(getOptionsAvailable() & option,);
  1055. if (yesNo)
  1056. pData->options |= option;
  1057. else
  1058. pData->options &= ~option;
  1059. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1060. if (sendCallback)
  1061. pData->engine->callback(true, true,
  1062. ENGINE_CALLBACK_OPTION_CHANGED,
  1063. pData->id,
  1064. static_cast<int>(option),
  1065. yesNo ? 1 : 0,
  1066. 0, 0.0f, nullptr);
  1067. #else
  1068. // unused
  1069. return; (void)sendCallback;
  1070. #endif
  1071. }
  1072. void CarlaPlugin::setEnabled(const bool yesNo) noexcept
  1073. {
  1074. if (pData->enabled == yesNo)
  1075. return;
  1076. pData->masterMutex.lock();
  1077. pData->enabled = yesNo;
  1078. if (yesNo && ! pData->client->isActive())
  1079. pData->client->activate();
  1080. pData->masterMutex.unlock();
  1081. }
  1082. void CarlaPlugin::setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept
  1083. {
  1084. if (pData->engineBridged) {
  1085. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1086. } else if (pData->enginePlugin) {
  1087. // nothing here
  1088. } else {
  1089. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1090. }
  1091. if (pData->active == active)
  1092. return;
  1093. {
  1094. const ScopedSingleProcessLocker spl(this, true);
  1095. if (active)
  1096. activate();
  1097. else
  1098. deactivate();
  1099. }
  1100. pData->active = active;
  1101. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1102. const float value = active ? 1.0f : 0.0f;
  1103. pData->engine->callback(sendCallback, sendOsc,
  1104. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1105. pData->id,
  1106. PARAMETER_ACTIVE,
  1107. 0, 0,
  1108. value,
  1109. nullptr);
  1110. #endif
  1111. }
  1112. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1113. void CarlaPlugin::setDryWet(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1114. {
  1115. if (pData->engineBridged) {
  1116. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1117. } else {
  1118. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1119. }
  1120. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
  1121. const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
  1122. if (carla_isEqual(pData->postProc.dryWet, fixedValue))
  1123. return;
  1124. pData->postProc.dryWet = fixedValue;
  1125. pData->engine->callback(sendCallback, sendOsc,
  1126. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1127. pData->id,
  1128. PARAMETER_DRYWET,
  1129. 0, 0,
  1130. fixedValue,
  1131. nullptr);
  1132. }
  1133. void CarlaPlugin::setVolume(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1134. {
  1135. if (pData->engineBridged) {
  1136. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1137. } else {
  1138. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1139. }
  1140. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
  1141. const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
  1142. if (carla_isEqual(pData->postProc.volume, fixedValue))
  1143. return;
  1144. pData->postProc.volume = fixedValue;
  1145. pData->engine->callback(sendCallback, sendOsc,
  1146. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1147. pData->id,
  1148. PARAMETER_VOLUME,
  1149. 0, 0,
  1150. fixedValue,
  1151. nullptr);
  1152. }
  1153. void CarlaPlugin::setBalanceLeft(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1154. {
  1155. if (pData->engineBridged) {
  1156. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1157. } else {
  1158. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1159. }
  1160. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1161. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1162. if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
  1163. return;
  1164. pData->postProc.balanceLeft = fixedValue;
  1165. pData->engine->callback(sendCallback, sendOsc,
  1166. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1167. pData->id,
  1168. PARAMETER_BALANCE_LEFT,
  1169. 0, 0,
  1170. fixedValue,
  1171. nullptr);
  1172. }
  1173. void CarlaPlugin::setBalanceRight(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1174. {
  1175. if (pData->engineBridged) {
  1176. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1177. } else {
  1178. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1179. }
  1180. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1181. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1182. if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
  1183. return;
  1184. pData->postProc.balanceRight = fixedValue;
  1185. pData->engine->callback(sendCallback, sendOsc,
  1186. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1187. pData->id,
  1188. PARAMETER_BALANCE_RIGHT,
  1189. 0, 0,
  1190. fixedValue,
  1191. nullptr);
  1192. }
  1193. void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool sendCallback) noexcept
  1194. {
  1195. if (pData->engineBridged) {
  1196. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1197. } else {
  1198. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1199. }
  1200. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1201. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1202. if (carla_isEqual(pData->postProc.panning, fixedValue))
  1203. return;
  1204. pData->postProc.panning = fixedValue;
  1205. pData->engine->callback(sendCallback, sendOsc,
  1206. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1207. pData->id,
  1208. PARAMETER_PANNING,
  1209. 0, 0,
  1210. fixedValue,
  1211. nullptr);
  1212. }
  1213. void CarlaPlugin::setDryWetRT(const float value, const bool sendCallbackLater) noexcept
  1214. {
  1215. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
  1216. const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
  1217. if (carla_isEqual(pData->postProc.dryWet, fixedValue))
  1218. return;
  1219. pData->postProc.dryWet = fixedValue;
  1220. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_DRYWET, 0, 0, fixedValue);
  1221. }
  1222. void CarlaPlugin::setVolumeRT(const float value, const bool sendCallbackLater) noexcept
  1223. {
  1224. CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
  1225. const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
  1226. if (carla_isEqual(pData->postProc.volume, fixedValue))
  1227. return;
  1228. pData->postProc.volume = fixedValue;
  1229. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_VOLUME, 0, 0, fixedValue);
  1230. }
  1231. void CarlaPlugin::setBalanceLeftRT(const float value, const bool sendCallbackLater) noexcept
  1232. {
  1233. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1234. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1235. if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
  1236. return;
  1237. pData->postProc.balanceLeft = fixedValue;
  1238. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_BALANCE_LEFT, 0, 0, fixedValue);
  1239. }
  1240. void CarlaPlugin::setBalanceRightRT(const float value, const bool sendCallbackLater) noexcept
  1241. {
  1242. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1243. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1244. if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
  1245. return;
  1246. pData->postProc.balanceRight = fixedValue;
  1247. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_BALANCE_RIGHT, 0, 0, fixedValue);
  1248. }
  1249. void CarlaPlugin::setPanningRT(const float value, const bool sendCallbackLater) noexcept
  1250. {
  1251. CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
  1252. const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
  1253. if (carla_isEqual(pData->postProc.panning, fixedValue))
  1254. return;
  1255. pData->postProc.panning = fixedValue;
  1256. pData->postponeRtEvent(kPluginPostRtEventParameterChange, sendCallbackLater, PARAMETER_PANNING, 0, 0, fixedValue);
  1257. }
  1258. #endif // ! BUILD_BRIDGE_ALTERNATIVE_ARCH
  1259. void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept
  1260. {
  1261. if (pData->engineBridged) {
  1262. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1263. } else {
  1264. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1265. }
  1266. CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,);
  1267. if (pData->ctrlChannel == channel)
  1268. return;
  1269. pData->ctrlChannel = channel;
  1270. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1271. const float channelf = static_cast<float>(channel);
  1272. pData->engine->callback(sendCallback, sendOsc,
  1273. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1274. pData->id,
  1275. PARAMETER_CTRL_CHANNEL,
  1276. 0, 0,
  1277. channelf, nullptr);
  1278. #endif
  1279. }
  1280. // -------------------------------------------------------------------
  1281. // Set data (plugin-specific stuff)
  1282. void CarlaPlugin::setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
  1283. {
  1284. if (pData->engineBridged) {
  1285. // NOTE: some LV2 plugins feedback messages to UI on purpose
  1286. CARLA_SAFE_ASSERT_RETURN(getType() == PLUGIN_LV2 || !sendGui,);
  1287. } else if (pData->enginePlugin) {
  1288. // nothing here
  1289. } else {
  1290. CARLA_SAFE_ASSERT_RETURN(sendGui || sendOsc || sendCallback,); // never call this from RT
  1291. }
  1292. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  1293. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1294. uiParameterChange(parameterId, value);
  1295. pData->engine->callback(sendCallback, sendOsc,
  1296. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1297. pData->id,
  1298. static_cast<int>(parameterId),
  1299. 0, 0,
  1300. value,
  1301. nullptr);
  1302. }
  1303. void CarlaPlugin::setParameterValueRT(const uint32_t parameterId, const float value, const bool sendCallbackLater) noexcept
  1304. {
  1305. pData->postponeRtEvent(kPluginPostRtEventParameterChange,
  1306. sendCallbackLater, static_cast<int32_t>(parameterId), 0, 0, value);
  1307. }
  1308. void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
  1309. {
  1310. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1311. CARLA_SAFE_ASSERT_RETURN(rindex > PARAMETER_MAX && rindex != PARAMETER_NULL,);
  1312. switch (rindex)
  1313. {
  1314. case PARAMETER_ACTIVE:
  1315. return setActive((value > 0.0f), sendOsc, sendCallback);
  1316. case PARAMETER_CTRL_CHANNEL:
  1317. return setCtrlChannel(int8_t(value), sendOsc, sendCallback);
  1318. case PARAMETER_DRYWET:
  1319. return setDryWet(value, sendOsc, sendCallback);
  1320. case PARAMETER_VOLUME:
  1321. return setVolume(value, sendOsc, sendCallback);
  1322. case PARAMETER_BALANCE_LEFT:
  1323. return setBalanceLeft(value, sendOsc, sendCallback);
  1324. case PARAMETER_BALANCE_RIGHT:
  1325. return setBalanceRight(value, sendOsc, sendCallback);
  1326. case PARAMETER_PANNING:
  1327. return setPanning(value, sendOsc, sendCallback);
  1328. }
  1329. #endif
  1330. CARLA_SAFE_ASSERT_RETURN(rindex >= 0,);
  1331. for (uint32_t i=0; i < pData->param.count; ++i)
  1332. {
  1333. if (pData->param.data[i].rindex == rindex)
  1334. {
  1335. //if (carla_isNotEqual(getParameterValue(i), value))
  1336. setParameterValue(i, value, sendGui, sendOsc, sendCallback);
  1337. break;
  1338. }
  1339. }
  1340. }
  1341. void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint8_t channel, const bool sendOsc, const bool sendCallback) noexcept
  1342. {
  1343. if (pData->engineBridged) {
  1344. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1345. } else {
  1346. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1347. }
  1348. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  1349. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  1350. pData->param.data[parameterId].midiChannel = channel;
  1351. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1352. pData->engine->callback(sendCallback, sendOsc,
  1353. ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED,
  1354. pData->id,
  1355. static_cast<int>(parameterId),
  1356. channel,
  1357. 0, 0.0f, nullptr);
  1358. #endif
  1359. }
  1360. void CarlaPlugin::setParameterMidiCC(const uint32_t parameterId, const int16_t cc, const bool sendOsc, const bool sendCallback) noexcept
  1361. {
  1362. if (pData->engineBridged) {
  1363. CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
  1364. } else {
  1365. CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
  1366. }
  1367. CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
  1368. CARLA_SAFE_ASSERT_RETURN(cc >= -1 && cc < MAX_MIDI_CONTROL,);
  1369. pData->param.data[parameterId].midiCC = cc;
  1370. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1371. pData->engine->callback(sendCallback, sendOsc,
  1372. ENGINE_CALLBACK_PARAMETER_MIDI_CC_CHANGED,
  1373. pData->id,
  1374. static_cast<int>(parameterId),
  1375. cc,
  1376. 0, 0.0f, nullptr);
  1377. #endif
  1378. }
  1379. void CarlaPlugin::setCustomData(const char* const type, const char* const key, const char* const value, const bool)
  1380. {
  1381. CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
  1382. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
  1383. CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
  1384. // Ignore some keys
  1385. if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) == 0)
  1386. {
  1387. const PluginType ptype = getType();
  1388. if ((ptype == PLUGIN_INTERNAL && std::strncmp(key, "CarlaAlternateFile", 18) == 0) ||
  1389. (ptype == PLUGIN_DSSI && std::strcmp (key, "guiVisible") == 0) ||
  1390. (ptype == PLUGIN_LV2 && std::strncmp(key, "OSC:", 4) == 0))
  1391. return;
  1392. }
  1393. // Check if we already have this key
  1394. for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
  1395. {
  1396. CustomData& customData(it.getValue(kCustomDataFallbackNC));
  1397. CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
  1398. if (std::strcmp(customData.key, key) == 0)
  1399. {
  1400. if (customData.value != nullptr)
  1401. delete[] customData.value;
  1402. customData.value = carla_strdup(value);
  1403. return;
  1404. }
  1405. }
  1406. // Otherwise store it
  1407. CustomData customData;
  1408. customData.type = carla_strdup(type);
  1409. customData.key = carla_strdup(key);
  1410. customData.value = carla_strdup(value);
  1411. pData->custom.append(customData);
  1412. }
  1413. void CarlaPlugin::setChunkData(const void* const data, const std::size_t dataSize)
  1414. {
  1415. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  1416. CARLA_SAFE_ASSERT_RETURN(dataSize > 0,);
  1417. CARLA_SAFE_ASSERT(false); // this should never happen
  1418. }
  1419. void CarlaPlugin::setProgram(const int32_t index,
  1420. const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
  1421. {
  1422. CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->prog.count),);
  1423. pData->prog.current = index;
  1424. pData->engine->callback(sendCallback, sendOsc,
  1425. ENGINE_CALLBACK_PROGRAM_CHANGED,
  1426. pData->id,
  1427. index,
  1428. 0, 0, 0.0f, nullptr);
  1429. // Change default parameter values
  1430. if (index >= 0)
  1431. {
  1432. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1433. uiProgramChange(static_cast<uint32_t>(index));
  1434. switch (getType())
  1435. {
  1436. case PLUGIN_SF2:
  1437. case PLUGIN_SFZ:
  1438. break;
  1439. default:
  1440. pData->updateParameterValues(this, sendCallback, sendOsc, true);
  1441. break;
  1442. }
  1443. }
  1444. }
  1445. void CarlaPlugin::setMidiProgram(const int32_t index,
  1446. const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
  1447. {
  1448. CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
  1449. pData->midiprog.current = index;
  1450. pData->engine->callback(sendCallback, sendOsc,
  1451. ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
  1452. pData->id,
  1453. index,
  1454. 0, 0, 0.0f, nullptr);
  1455. // Change default parameter values
  1456. if (index >= 0)
  1457. {
  1458. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1459. uiMidiProgramChange(static_cast<uint32_t>(index));
  1460. switch (getType())
  1461. {
  1462. case PLUGIN_SF2:
  1463. case PLUGIN_SFZ:
  1464. break;
  1465. default:
  1466. pData->updateParameterValues(this, sendCallback, sendOsc, true);
  1467. break;
  1468. }
  1469. }
  1470. }
  1471. void CarlaPlugin::setMidiProgramById(const uint32_t bank, const uint32_t program, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
  1472. {
  1473. for (uint32_t i=0; i < pData->midiprog.count; ++i)
  1474. {
  1475. if (pData->midiprog.data[i].bank == bank && pData->midiprog.data[i].program == program)
  1476. return setMidiProgram(static_cast<int32_t>(i), sendGui, sendOsc, sendCallback);
  1477. }
  1478. }
  1479. void CarlaPlugin::setProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
  1480. {
  1481. CARLA_SAFE_ASSERT_RETURN(uindex < pData->prog.count,);
  1482. const int32_t index = static_cast<int32_t>(uindex);
  1483. pData->prog.current = index;
  1484. // Change default parameter values
  1485. switch (getType())
  1486. {
  1487. case PLUGIN_SF2:
  1488. case PLUGIN_SFZ:
  1489. break;
  1490. default:
  1491. pData->updateDefaultParameterValues(this);
  1492. break;
  1493. }
  1494. pData->postponeRtEvent(kPluginPostRtEventProgramChange, sendCallbackLater, index, 0, 0, 0.0f);
  1495. }
  1496. void CarlaPlugin::setMidiProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
  1497. {
  1498. CARLA_SAFE_ASSERT_RETURN(uindex < pData->midiprog.count,);
  1499. const int32_t index = static_cast<int32_t>(uindex);
  1500. pData->midiprog.current = index;
  1501. // Change default parameter values
  1502. switch (getType())
  1503. {
  1504. case PLUGIN_SF2:
  1505. case PLUGIN_SFZ:
  1506. break;
  1507. default:
  1508. pData->updateDefaultParameterValues(this);
  1509. break;
  1510. }
  1511. pData->postponeRtEvent(kPluginPostRtEventMidiProgramChange, sendCallbackLater, index, 0, 0, 0.0f);
  1512. }
  1513. // -------------------------------------------------------------------
  1514. // Plugin state
  1515. void CarlaPlugin::reloadPrograms(const bool)
  1516. {
  1517. }
  1518. // -------------------------------------------------------------------
  1519. // Plugin processing
  1520. void CarlaPlugin::activate() noexcept
  1521. {
  1522. CARLA_SAFE_ASSERT(! pData->active);
  1523. }
  1524. void CarlaPlugin::deactivate() noexcept
  1525. {
  1526. CARLA_SAFE_ASSERT(pData->active);
  1527. }
  1528. void CarlaPlugin::bufferSizeChanged(const uint32_t)
  1529. {
  1530. }
  1531. void CarlaPlugin::sampleRateChanged(const double)
  1532. {
  1533. }
  1534. void CarlaPlugin::offlineModeChanged(const bool)
  1535. {
  1536. }
  1537. // -------------------------------------------------------------------
  1538. // Misc
  1539. void CarlaPlugin::idle()
  1540. {
  1541. if (! pData->enabled)
  1542. return;
  1543. const bool hasUI(pData->hints & PLUGIN_HAS_CUSTOM_UI);
  1544. const bool needsUiMainThread(pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD);
  1545. const uint32_t latency(getLatencyInFrames());
  1546. if (pData->latency.frames != latency)
  1547. {
  1548. carla_stdout("latency changed to %i samples", latency);
  1549. const ScopedSingleProcessLocker sspl(this, true);
  1550. pData->client->setLatency(latency);
  1551. #ifndef BUILD_BRIDGE
  1552. pData->latency.recreateBuffers(pData->latency.channels, latency);
  1553. #else
  1554. pData->latency.frames = latency;
  1555. #endif
  1556. }
  1557. const CarlaMutexLocker sl(pData->postRtEvents.getDataMutex());
  1558. for (RtLinkedList<PluginPostRtEvent>::Itenerator it = pData->postRtEvents.getDataIterator(); it.valid(); it.next())
  1559. {
  1560. const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
  1561. CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
  1562. switch (event.type)
  1563. {
  1564. case kPluginPostRtEventNull: {
  1565. } break;
  1566. case kPluginPostRtEventDebug: {
  1567. pData->engine->callback(true, true,
  1568. ENGINE_CALLBACK_DEBUG, pData->id,
  1569. event.value1, event.value2, event.value3, event.valuef, nullptr);
  1570. } break;
  1571. case kPluginPostRtEventParameterChange: {
  1572. // Update UI
  1573. if (event.value1 >= 0 && hasUI)
  1574. {
  1575. if (needsUiMainThread)
  1576. pData->postUiEvents.append(event);
  1577. else
  1578. uiParameterChange(static_cast<uint32_t>(event.value1), event.valuef);
  1579. }
  1580. if (event.sendCallback)
  1581. {
  1582. // Update Host
  1583. pData->engine->callback(true, true,
  1584. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1585. pData->id,
  1586. event.value1,
  1587. 0, 0,
  1588. event.valuef,
  1589. nullptr);
  1590. }
  1591. } break;
  1592. case kPluginPostRtEventProgramChange: {
  1593. // Update UI
  1594. if (event.value1 >= 0 && hasUI)
  1595. {
  1596. if (needsUiMainThread)
  1597. pData->postUiEvents.append(event);
  1598. else
  1599. uiProgramChange(static_cast<uint32_t>(event.value1));
  1600. }
  1601. // Update param values
  1602. for (uint32_t j=0; j < pData->param.count; ++j)
  1603. {
  1604. const float paramDefault(pData->param.ranges[j].def);
  1605. const float paramValue(getParameterValue(j));
  1606. pData->engine->callback(true, true,
  1607. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1608. pData->id,
  1609. static_cast<int>(j),
  1610. 0, 0,
  1611. paramValue,
  1612. nullptr);
  1613. pData->engine->callback(true, true,
  1614. ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
  1615. pData->id,
  1616. static_cast<int>(j),
  1617. 0, 0,
  1618. paramDefault,
  1619. nullptr);
  1620. }
  1621. if (event.sendCallback)
  1622. {
  1623. // Update Host
  1624. pData->engine->callback(true, true,
  1625. ENGINE_CALLBACK_PROGRAM_CHANGED,
  1626. pData->id,
  1627. event.value1,
  1628. 0, 0, 0.0f, nullptr);
  1629. }
  1630. } break;
  1631. case kPluginPostRtEventMidiProgramChange: {
  1632. // Update UI
  1633. if (event.value1 >= 0 && hasUI)
  1634. {
  1635. if (needsUiMainThread)
  1636. pData->postUiEvents.append(event);
  1637. else
  1638. uiMidiProgramChange(static_cast<uint32_t>(event.value1));
  1639. }
  1640. // Update param values
  1641. for (uint32_t j=0; j < pData->param.count; ++j)
  1642. {
  1643. const float paramDefault(pData->param.ranges[j].def);
  1644. const float paramValue(getParameterValue(j));
  1645. pData->engine->callback(true, true,
  1646. ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
  1647. pData->id,
  1648. static_cast<int>(j),
  1649. 0, 0,
  1650. paramValue,
  1651. nullptr);
  1652. pData->engine->callback(true, true,
  1653. ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
  1654. pData->id,
  1655. static_cast<int>(j),
  1656. 0, 0,
  1657. paramDefault,
  1658. nullptr);
  1659. }
  1660. if (event.sendCallback)
  1661. {
  1662. // Update Host
  1663. pData->engine->callback(true, true,
  1664. ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
  1665. pData->id,
  1666. event.value1,
  1667. 0, 0, 0.0f, nullptr);
  1668. }
  1669. } break;
  1670. case kPluginPostRtEventNoteOn: {
  1671. CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
  1672. CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);
  1673. CARLA_SAFE_ASSERT_BREAK(event.value3 >= 0 && event.value3 < MAX_MIDI_VALUE);
  1674. const uint8_t channel = static_cast<uint8_t>(event.value1);
  1675. const uint8_t note = static_cast<uint8_t>(event.value2);
  1676. const uint8_t velocity = static_cast<uint8_t>(event.value3);
  1677. // Update UI
  1678. if (hasUI)
  1679. {
  1680. if (needsUiMainThread)
  1681. pData->postUiEvents.append(event);
  1682. else
  1683. uiNoteOn(channel, note, velocity);
  1684. }
  1685. if (event.sendCallback)
  1686. {
  1687. // Update Host
  1688. pData->engine->callback(true, true,
  1689. ENGINE_CALLBACK_NOTE_ON,
  1690. pData->id,
  1691. event.value1,
  1692. event.value2,
  1693. event.value3,
  1694. 0.0f, nullptr);
  1695. }
  1696. } break;
  1697. case kPluginPostRtEventNoteOff: {
  1698. CARLA_SAFE_ASSERT_BREAK(event.value1 >= 0 && event.value1 < MAX_MIDI_CHANNELS);
  1699. CARLA_SAFE_ASSERT_BREAK(event.value2 >= 0 && event.value2 < MAX_MIDI_NOTE);
  1700. const uint8_t channel = static_cast<uint8_t>(event.value1);
  1701. const uint8_t note = static_cast<uint8_t>(event.value2);
  1702. // Update UI
  1703. if (hasUI)
  1704. {
  1705. if (needsUiMainThread)
  1706. pData->postUiEvents.append(event);
  1707. else
  1708. uiNoteOff(channel, note);
  1709. }
  1710. if (event.sendCallback)
  1711. {
  1712. // Update Host
  1713. pData->engine->callback(true, true,
  1714. ENGINE_CALLBACK_NOTE_OFF,
  1715. pData->id,
  1716. event.value1,
  1717. event.value2,
  1718. 0, 0.0f, nullptr);
  1719. }
  1720. } break;
  1721. }
  1722. }
  1723. pData->postRtEvents.clearData();
  1724. }
  1725. bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept
  1726. {
  1727. if (forcedOffline)
  1728. {
  1729. #ifndef STOAT_TEST_BUILD
  1730. pData->masterMutex.lock();
  1731. return true;
  1732. #endif
  1733. }
  1734. return pData->masterMutex.tryLock();
  1735. }
  1736. void CarlaPlugin::unlock() noexcept
  1737. {
  1738. pData->masterMutex.unlock();
  1739. }
  1740. // -------------------------------------------------------------------
  1741. // Plugin buffers
  1742. void CarlaPlugin::initBuffers() const noexcept
  1743. {
  1744. pData->audioIn.initBuffers();
  1745. pData->audioOut.initBuffers();
  1746. pData->cvIn.initBuffers();
  1747. pData->cvOut.initBuffers();
  1748. pData->event.initBuffers();
  1749. }
  1750. void CarlaPlugin::clearBuffers() noexcept
  1751. {
  1752. pData->clearBuffers();
  1753. }
  1754. // -------------------------------------------------------------------
  1755. // OSC stuff
  1756. // FIXME
  1757. void CarlaPlugin::handleOscMessage(const char* const, const int, const void* const, const char* const, const lo_message)
  1758. {
  1759. // do nothing
  1760. }
  1761. // -------------------------------------------------------------------
  1762. // MIDI events
  1763. void CarlaPlugin::sendMidiSingleNote(const uint8_t channel, const uint8_t note, const uint8_t velo, const bool sendGui, const bool sendOsc, const bool sendCallback)
  1764. {
  1765. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  1766. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  1767. CARLA_SAFE_ASSERT_RETURN(velo < MAX_MIDI_VALUE,);
  1768. if (! pData->active)
  1769. return;
  1770. ExternalMidiNote extNote;
  1771. extNote.channel = static_cast<int8_t>(channel);
  1772. extNote.note = note;
  1773. extNote.velo = velo;
  1774. pData->extNotes.appendNonRT(extNote);
  1775. if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
  1776. {
  1777. if (velo > 0)
  1778. uiNoteOn(channel, note, velo);
  1779. else
  1780. uiNoteOff(channel, note);
  1781. }
  1782. pData->engine->callback(sendCallback, sendOsc,
  1783. (velo > 0) ? ENGINE_CALLBACK_NOTE_ON : ENGINE_CALLBACK_NOTE_OFF,
  1784. pData->id,
  1785. channel,
  1786. note,
  1787. velo,
  1788. 0.0f, nullptr);
  1789. }
  1790. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1791. void CarlaPlugin::postponeRtAllNotesOff()
  1792. {
  1793. if (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS)
  1794. return;
  1795. PluginPostRtEvent postEvent = {
  1796. kPluginPostRtEventNoteOff,
  1797. true,
  1798. pData->ctrlChannel,
  1799. 0, 0, 0.0f
  1800. };
  1801. for (int32_t i=0; i < MAX_MIDI_NOTE; ++i)
  1802. {
  1803. postEvent.value2 = i;
  1804. pData->postRtEvents.appendRT(postEvent);
  1805. }
  1806. }
  1807. #endif
  1808. // -------------------------------------------------------------------
  1809. // UI Stuff
  1810. void CarlaPlugin::showCustomUI(const bool yesNo)
  1811. {
  1812. if (yesNo) {
  1813. CARLA_SAFE_ASSERT(false);
  1814. }
  1815. }
  1816. void CarlaPlugin::uiIdle()
  1817. {
  1818. if (pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD)
  1819. {
  1820. // Update parameter outputs
  1821. for (uint32_t i=0; i < pData->param.count; ++i)
  1822. {
  1823. if (pData->param.data[i].type == PARAMETER_OUTPUT)
  1824. uiParameterChange(i, getParameterValue(i));
  1825. }
  1826. const CarlaMutexLocker sl(pData->postUiEvents.mutex);
  1827. for (LinkedList<PluginPostRtEvent>::Itenerator it = pData->postUiEvents.data.begin2(); it.valid(); it.next())
  1828. {
  1829. const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
  1830. CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
  1831. switch (event.type)
  1832. {
  1833. case kPluginPostRtEventNull:
  1834. case kPluginPostRtEventDebug:
  1835. break;
  1836. case kPluginPostRtEventParameterChange:
  1837. uiParameterChange(static_cast<uint32_t>(event.value1), event.valuef);
  1838. break;
  1839. case kPluginPostRtEventProgramChange:
  1840. uiProgramChange(static_cast<uint32_t>(event.value1));
  1841. break;
  1842. case kPluginPostRtEventMidiProgramChange:
  1843. uiMidiProgramChange(static_cast<uint32_t>(event.value1));
  1844. break;
  1845. case kPluginPostRtEventNoteOn:
  1846. uiNoteOn(static_cast<uint8_t>(event.value1),
  1847. static_cast<uint8_t>(event.value2),
  1848. static_cast<uint8_t>(event.value3));
  1849. break;
  1850. case kPluginPostRtEventNoteOff:
  1851. uiNoteOff(static_cast<uint8_t>(event.value1),
  1852. static_cast<uint8_t>(event.value2));
  1853. break;
  1854. }
  1855. }
  1856. pData->postUiEvents.data.clear();
  1857. }
  1858. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  1859. if (pData->transientTryCounter == 0)
  1860. return;
  1861. if (++pData->transientTryCounter % 10 != 0)
  1862. return;
  1863. if (pData->transientTryCounter >= 200)
  1864. return;
  1865. carla_stdout("Trying to get window...");
  1866. CarlaString uiTitle(pData->name);
  1867. uiTitle += " (GUI)";
  1868. if (CarlaPluginUI::tryTransientWinIdMatch(getUiBridgeProcessId(), uiTitle,
  1869. pData->engine->getOptions().frontendWinId, pData->transientFirstTry))
  1870. {
  1871. pData->transientTryCounter = 0;
  1872. pData->transientFirstTry = false;
  1873. }
  1874. #endif
  1875. }
  1876. void CarlaPlugin::uiParameterChange(const uint32_t index, const float value) noexcept
  1877. {
  1878. CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
  1879. return;
  1880. // unused
  1881. (void)value;
  1882. }
  1883. void CarlaPlugin::uiProgramChange(const uint32_t index) noexcept
  1884. {
  1885. CARLA_SAFE_ASSERT_RETURN(index < getProgramCount(),);
  1886. }
  1887. void CarlaPlugin::uiMidiProgramChange(const uint32_t index) noexcept
  1888. {
  1889. CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(),);
  1890. }
  1891. void CarlaPlugin::uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept
  1892. {
  1893. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  1894. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  1895. CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
  1896. }
  1897. void CarlaPlugin::uiNoteOff(const uint8_t channel, const uint8_t note) noexcept
  1898. {
  1899. CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
  1900. CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
  1901. }
  1902. CarlaEngine* CarlaPlugin::getEngine() const noexcept
  1903. {
  1904. return pData->engine;
  1905. }
  1906. CarlaEngineClient* CarlaPlugin::getEngineClient() const noexcept
  1907. {
  1908. return pData->client;
  1909. }
  1910. CarlaEngineAudioPort* CarlaPlugin::getAudioInPort(const uint32_t index) const noexcept
  1911. {
  1912. return pData->audioIn.ports[index].port;
  1913. }
  1914. CarlaEngineAudioPort* CarlaPlugin::getAudioOutPort(const uint32_t index) const noexcept
  1915. {
  1916. return pData->audioOut.ports[index].port;
  1917. }
  1918. CarlaEngineCVPort* CarlaPlugin::getCVInPort(const uint32_t index) const noexcept
  1919. {
  1920. return pData->cvIn.ports[index].port;
  1921. }
  1922. CarlaEngineCVPort* CarlaPlugin::getCVOutPort(const uint32_t index) const noexcept
  1923. {
  1924. return pData->cvOut.ports[index].port;
  1925. }
  1926. CarlaEngineEventPort* CarlaPlugin::getDefaultEventInPort() const noexcept
  1927. {
  1928. return pData->event.portIn;
  1929. }
  1930. CarlaEngineEventPort* CarlaPlugin::getDefaultEventOutPort() const noexcept
  1931. {
  1932. return pData->event.portOut;
  1933. }
  1934. void* CarlaPlugin::getNativeHandle() const noexcept
  1935. {
  1936. return nullptr;
  1937. }
  1938. const void* CarlaPlugin::getNativeDescriptor() const noexcept
  1939. {
  1940. return nullptr;
  1941. }
  1942. uintptr_t CarlaPlugin::getUiBridgeProcessId() const noexcept
  1943. {
  1944. return 0;
  1945. }
  1946. // -------------------------------------------------------------------
  1947. uint32_t CarlaPlugin::getPatchbayNodeId() const noexcept
  1948. {
  1949. return pData->nodeId;
  1950. }
  1951. void CarlaPlugin::setPatchbayNodeId(const uint32_t nodeId) noexcept
  1952. {
  1953. pData->nodeId = nodeId;
  1954. }
  1955. // -------------------------------------------------------------------
  1956. void CarlaPlugin::restoreLV2State() noexcept
  1957. {
  1958. carla_stderr2("Warning: restoreLV2State() called for non-implemented type");
  1959. }
  1960. void CarlaPlugin::waitForBridgeSaveSignal() noexcept
  1961. {
  1962. }
  1963. // -------------------------------------------------------------------
  1964. // Scoped Disabler
  1965. CarlaPlugin::ScopedDisabler::ScopedDisabler(CarlaPlugin* const plugin) noexcept
  1966. : fPlugin(plugin),
  1967. fWasEnabled(false)
  1968. {
  1969. CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
  1970. CARLA_SAFE_ASSERT_RETURN(plugin->pData != nullptr,);
  1971. CARLA_SAFE_ASSERT_RETURN(plugin->pData->client != nullptr,);
  1972. carla_debug("CarlaPlugin::ScopedDisabler(%p)", plugin);
  1973. plugin->pData->masterMutex.lock();
  1974. if (plugin->pData->enabled)
  1975. {
  1976. fWasEnabled = true;
  1977. plugin->pData->enabled = false;
  1978. if (plugin->pData->client->isActive())
  1979. plugin->pData->client->deactivate();
  1980. }
  1981. }
  1982. CarlaPlugin::ScopedDisabler::~ScopedDisabler() noexcept
  1983. {
  1984. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  1985. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
  1986. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData->client != nullptr,);
  1987. carla_debug("CarlaPlugin::~ScopedDisabler()");
  1988. if (fWasEnabled)
  1989. {
  1990. fPlugin->pData->enabled = true;
  1991. fPlugin->pData->client->activate();
  1992. }
  1993. fPlugin->pData->masterMutex.unlock();
  1994. }
  1995. // -------------------------------------------------------------------
  1996. // Scoped Process Locker
  1997. CarlaPlugin::ScopedSingleProcessLocker::ScopedSingleProcessLocker(CarlaPlugin* const plugin, const bool block) noexcept
  1998. : fPlugin(plugin),
  1999. fBlock(block)
  2000. {
  2001. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  2002. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
  2003. carla_debug("CarlaPlugin::ScopedSingleProcessLocker(%p, %s)", plugin, bool2str(block));
  2004. if (! fBlock)
  2005. return;
  2006. plugin->pData->singleMutex.lock();
  2007. }
  2008. CarlaPlugin::ScopedSingleProcessLocker::~ScopedSingleProcessLocker() noexcept
  2009. {
  2010. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  2011. CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
  2012. carla_debug("CarlaPlugin::~ScopedSingleProcessLocker()");
  2013. if (! fBlock)
  2014. return;
  2015. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  2016. if (fPlugin->pData->singleMutex.wasTryLockCalled())
  2017. fPlugin->pData->needsReset = true;
  2018. #endif
  2019. fPlugin->pData->singleMutex.unlock();
  2020. }
  2021. // -------------------------------------------------------------------
  2022. CARLA_BACKEND_END_NAMESPACE