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.

761 lines
23KB

  1. /*
  2. * Carla Plugin Host
  3. * Copyright (C) 2011-2014 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 "CarlaEngineInternal.hpp"
  18. #include "CarlaPlugin.hpp"
  19. #include "CarlaMIDI.h"
  20. #include "CarlaMathUtils.hpp"
  21. // -----------------------------------------------------------------------
  22. CARLA_BACKEND_START_NAMESPACE
  23. #if 0
  24. } // Fix editor indentation
  25. #endif
  26. #ifndef BUILD_BRIDGE
  27. // -----------------------------------------------------------------------
  28. // Rack Patchbay stuff
  29. static
  30. int getCarlaRackPortIdFromName(const char* const shortname) noexcept
  31. {
  32. if (std::strcmp(shortname, "AudioIn1") == 0)
  33. return RACK_GRAPH_CARLA_PORT_AUDIO_IN1;
  34. if (std::strcmp(shortname, "AudioIn2") == 0)
  35. return RACK_GRAPH_CARLA_PORT_AUDIO_IN2;
  36. if (std::strcmp(shortname, "AudioOut1") == 0)
  37. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT1;
  38. if (std::strcmp(shortname, "AudioOut2") == 0)
  39. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT2;
  40. if (std::strcmp(shortname, "MidiIn") == 0)
  41. return RACK_GRAPH_CARLA_PORT_MIDI_IN;
  42. if (std::strcmp(shortname, "MidiOut") == 0)
  43. return RACK_GRAPH_CARLA_PORT_MIDI_OUT;
  44. return RACK_GRAPH_CARLA_PORT_NULL;
  45. }
  46. // -----------------------------------------------------------------------
  47. // RackGraph
  48. bool RackGraph::connect(CarlaEngine* const engine, const int groupA, const int portA, const int groupB, const int portB) noexcept
  49. {
  50. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  51. CARLA_SAFE_ASSERT_RETURN(groupA != groupB, false);
  52. CARLA_SAFE_ASSERT_RETURN(groupA >= RACK_GRAPH_GROUP_CARLA && groupA < RACK_GRAPH_GROUP_MAX, false);
  53. CARLA_SAFE_ASSERT_RETURN(groupB >= RACK_GRAPH_GROUP_CARLA && groupB < RACK_GRAPH_GROUP_MAX, false);
  54. CARLA_SAFE_ASSERT_RETURN(portA >= 0, false);
  55. CARLA_SAFE_ASSERT_RETURN(portB >= 0, false);
  56. int carlaPort, otherPort;
  57. if (groupA == RACK_GRAPH_GROUP_CARLA)
  58. {
  59. carlaPort = portA;
  60. otherPort = portB;
  61. }
  62. else
  63. {
  64. CARLA_SAFE_ASSERT_RETURN(groupB == RACK_GRAPH_GROUP_CARLA, false);
  65. carlaPort = portB;
  66. otherPort = portA;
  67. }
  68. bool makeConnection = false;
  69. switch (carlaPort)
  70. {
  71. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  72. connectLock.lock();
  73. connectedIn1.append(otherPort);
  74. connectLock.unlock();
  75. makeConnection = true;
  76. break;
  77. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  78. connectLock.lock();
  79. connectedIn2.append(otherPort);
  80. connectLock.unlock();
  81. makeConnection = true;
  82. break;
  83. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  84. connectLock.lock();
  85. connectedOut1.append(otherPort);
  86. connectLock.unlock();
  87. makeConnection = true;
  88. break;
  89. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  90. connectLock.lock();
  91. connectedOut2.append(otherPort);
  92. connectLock.unlock();
  93. makeConnection = true;
  94. break;
  95. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  96. makeConnection = engine->connectRackMidiInPort(otherPort);
  97. break;
  98. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  99. makeConnection = engine->connectRackMidiOutPort(otherPort);
  100. break;
  101. }
  102. if (! makeConnection)
  103. {
  104. engine->setLastError("Invalid rack connection");
  105. return false;
  106. }
  107. ConnectionToId connectionToId;
  108. connectionToId.id = lastConnectionId;
  109. connectionToId.groupA = groupA;
  110. connectionToId.portA = portA;
  111. connectionToId.groupB = groupB;
  112. connectionToId.portB = portB;
  113. char strBuf[STR_MAX+1];
  114. strBuf[STR_MAX] = '\0';
  115. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", groupA, portA, groupB, portB);
  116. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  117. usedConnections.append(connectionToId);
  118. ++lastConnectionId;
  119. return true;
  120. }
  121. bool RackGraph::disconnect(CarlaEngine* const engine, const uint connectionId) noexcept
  122. {
  123. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  124. CARLA_SAFE_ASSERT_RETURN(usedConnections.count() > 0, false);
  125. for (LinkedList<ConnectionToId>::Itenerator it=usedConnections.begin(); it.valid(); it.next())
  126. {
  127. const ConnectionToId& connection(it.getValue());
  128. if (connection.id != connectionId)
  129. continue;
  130. int carlaPort, otherPort;
  131. if (connection.groupA == RACK_GRAPH_GROUP_CARLA)
  132. {
  133. carlaPort = connection.portA;
  134. otherPort = connection.portB;
  135. }
  136. else
  137. {
  138. CARLA_SAFE_ASSERT_RETURN(connection.groupB == RACK_GRAPH_GROUP_CARLA, false);
  139. carlaPort = connection.portB;
  140. otherPort = connection.portA;
  141. }
  142. switch (carlaPort)
  143. {
  144. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  145. connectLock.lock();
  146. connectedIn1.removeAll(otherPort);
  147. connectLock.unlock();
  148. break;
  149. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  150. connectLock.lock();
  151. connectedIn2.removeAll(otherPort);
  152. connectLock.unlock();
  153. break;
  154. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  155. connectLock.lock();
  156. connectedOut1.removeAll(otherPort);
  157. connectLock.unlock();
  158. break;
  159. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  160. connectLock.lock();
  161. connectedOut2.removeAll(otherPort);
  162. connectLock.unlock();
  163. break;
  164. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  165. engine->disconnectRackMidiInPort(otherPort);
  166. break;
  167. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  168. engine->disconnectRackMidiOutPort(otherPort);
  169. break;
  170. default:
  171. engine->setLastError("Invalid connection");
  172. return false;
  173. }
  174. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connection.id, 0, 0, 0.0f, nullptr);
  175. usedConnections.remove(it);
  176. return true;
  177. }
  178. engine->setLastError("Failed to find connection");
  179. return false;
  180. }
  181. const char* const* RackGraph::getConnections() const
  182. {
  183. if (usedConnections.count() == 0)
  184. return nullptr;
  185. LinkedList<const char*> connList;
  186. char strBuf[STR_MAX+1];
  187. for (LinkedList<ConnectionToId>::Itenerator it=usedConnections.begin(); it.valid(); it.next())
  188. {
  189. const ConnectionToId& connection(it.getValue());
  190. CARLA_SAFE_ASSERT_CONTINUE(connection.groupA != connection.groupB);
  191. CARLA_SAFE_ASSERT_CONTINUE(connection.groupA >= RACK_GRAPH_GROUP_CARLA && connection.groupA < RACK_GRAPH_GROUP_MAX);
  192. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB >= RACK_GRAPH_GROUP_CARLA && connection.groupB < RACK_GRAPH_GROUP_MAX);
  193. CARLA_SAFE_ASSERT_CONTINUE(connection.portA >= 0);
  194. CARLA_SAFE_ASSERT_CONTINUE(connection.portB >= 0);
  195. int carlaPort, otherPort;
  196. if (connection.groupA == RACK_GRAPH_GROUP_CARLA)
  197. {
  198. carlaPort = connection.portA;
  199. otherPort = connection.portB;
  200. }
  201. else
  202. {
  203. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB == RACK_GRAPH_GROUP_CARLA);
  204. carlaPort = connection.portB;
  205. otherPort = connection.portA;
  206. }
  207. switch (carlaPort)
  208. {
  209. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  210. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  211. std::sprintf(strBuf, "AudioIn:%i", otherPort+1);
  212. connList.append(carla_strdup(strBuf));
  213. connList.append(carla_strdup((carlaPort == RACK_GRAPH_CARLA_PORT_AUDIO_IN1) ? "Carla:AudioIn1" : "Carla:AudioIn2"));
  214. break;
  215. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  216. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  217. connList.append(carla_strdup((carlaPort == RACK_GRAPH_CARLA_PORT_AUDIO_OUT1) ? "Carla:AudioOut1" : "Carla:AudioOut2"));
  218. std::sprintf(strBuf, "AudioOut:%i", otherPort+1);
  219. connList.append(carla_strdup(strBuf));
  220. break;
  221. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  222. std::sprintf(strBuf, "MidiIn:%i", otherPort+1);
  223. connList.append(carla_strdup(strBuf));
  224. connList.append(carla_strdup("Carla:MidiIn"));
  225. break;
  226. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  227. connList.append(carla_strdup("Carla:MidiOut"));
  228. std::sprintf(strBuf, "MidiOut:%i", otherPort+1);
  229. connList.append(carla_strdup(strBuf));
  230. break;
  231. }
  232. }
  233. const size_t connCount(connList.count());
  234. if (connCount == 0)
  235. return nullptr;
  236. const char** const retConns = new const char*[connCount+1];
  237. for (size_t i=0; i < connCount; ++i)
  238. retConns[i] = connList.getAt(i, nullptr);
  239. retConns[connCount] = nullptr;
  240. connList.clear();
  241. return retConns;
  242. }
  243. bool RackGraph::getPortIdFromName(const char* const portName, int& groupId, int& portId)
  244. {
  245. if (std::strncmp(portName, "Carla:", 6) == 0)
  246. {
  247. groupId = RACK_GRAPH_GROUP_CARLA;
  248. portId = getCarlaRackPortIdFromName(portName+6);
  249. }
  250. else if (std::strncmp(portName, "AudioIn:", 8) == 0)
  251. {
  252. groupId = RACK_GRAPH_GROUP_AUDIO_IN;
  253. portId = std::atoi(portName+8) - 1;
  254. }
  255. else if (std::strncmp(portName, "AudioOut:", 9) == 0)
  256. {
  257. groupId = RACK_GRAPH_GROUP_AUDIO_OUT;
  258. portId = std::atoi(portName+9) - 1;
  259. }
  260. else if (std::strncmp(portName, "MidiIn:", 7) == 0)
  261. {
  262. groupId = RACK_GRAPH_GROUP_MIDI_IN;
  263. portId = std::atoi(portName+7) - 1;
  264. }
  265. else if (std::strncmp(portName, "MidiOut:", 8) == 0)
  266. {
  267. groupId = RACK_GRAPH_GROUP_MIDI_OUT;
  268. portId = std::atoi(portName+8) - 1;
  269. }
  270. else
  271. {
  272. return false;
  273. }
  274. return true;
  275. }
  276. // -----------------------------------------------------------------------
  277. // PatchbayGraph
  278. // TODO
  279. bool PatchbayGraph::connect(CarlaEngine* const engine, const int /*groupA*/, const int /*portA*/, const int /*groupB*/, const int /*portB*/) noexcept
  280. {
  281. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  282. return false;
  283. }
  284. bool PatchbayGraph::disconnect(CarlaEngine* const engine, const uint /*connectionId*/) noexcept
  285. {
  286. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  287. return false;
  288. }
  289. const char* const* PatchbayGraph::getConnections() const
  290. {
  291. return nullptr;
  292. }
  293. bool PatchbayGraph::getPortIdFromName(const char* const /*portName*/, int& /*groupId*/, int& /*portId*/)
  294. {
  295. return false;
  296. }
  297. #endif
  298. // -----------------------------------------------------------------------
  299. // CarlaEngine::ProtectedData
  300. CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept
  301. : osc(engine),
  302. thread(engine),
  303. oscData(nullptr),
  304. callback(nullptr),
  305. callbackPtr(nullptr),
  306. fileCallback(nullptr),
  307. fileCallbackPtr(nullptr),
  308. hints(0x0),
  309. bufferSize(0),
  310. sampleRate(0.0),
  311. aboutToClose(false),
  312. curPluginCount(0),
  313. maxPluginNumber(0),
  314. nextPluginId(0),
  315. plugins(nullptr) {}
  316. CarlaEngine::ProtectedData::~ProtectedData() noexcept
  317. {
  318. CARLA_SAFE_ASSERT(curPluginCount == 0);
  319. CARLA_SAFE_ASSERT(maxPluginNumber == 0);
  320. CARLA_SAFE_ASSERT(nextPluginId == 0);
  321. CARLA_SAFE_ASSERT(plugins == nullptr);
  322. }
  323. // -----------------------------------------------------------------------
  324. void CarlaEngine::ProtectedData::doPluginRemove() noexcept
  325. {
  326. CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
  327. CARLA_SAFE_ASSERT_RETURN(nextAction.pluginId < curPluginCount,);
  328. --curPluginCount;
  329. // move all plugins 1 spot backwards
  330. for (uint i=nextAction.pluginId; i < curPluginCount; ++i)
  331. {
  332. CarlaPlugin* const plugin(plugins[i+1].plugin);
  333. CARLA_SAFE_ASSERT_BREAK(plugin != nullptr);
  334. plugin->setId(i);
  335. plugins[i].plugin = plugin;
  336. plugins[i].insPeak[0] = 0.0f;
  337. plugins[i].insPeak[1] = 0.0f;
  338. plugins[i].outsPeak[0] = 0.0f;
  339. plugins[i].outsPeak[1] = 0.0f;
  340. }
  341. const uint id(curPluginCount);
  342. // reset last plugin (now removed)
  343. plugins[id].plugin = nullptr;
  344. plugins[id].insPeak[0] = 0.0f;
  345. plugins[id].insPeak[1] = 0.0f;
  346. plugins[id].outsPeak[0] = 0.0f;
  347. plugins[id].outsPeak[1] = 0.0f;
  348. }
  349. void CarlaEngine::ProtectedData::doPluginsSwitch() noexcept
  350. {
  351. CARLA_SAFE_ASSERT_RETURN(curPluginCount >= 2,);
  352. const uint idA(nextAction.pluginId);
  353. const uint idB(nextAction.value);
  354. CARLA_SAFE_ASSERT_RETURN(idA < curPluginCount,);
  355. CARLA_SAFE_ASSERT_RETURN(idB < curPluginCount,);
  356. CARLA_SAFE_ASSERT_RETURN(plugins[idA].plugin != nullptr,);
  357. CARLA_SAFE_ASSERT_RETURN(plugins[idB].plugin != nullptr,);
  358. #if 0
  359. std::swap(plugins[idA].plugin, plugins[idB].plugin);
  360. #else
  361. CarlaPlugin* const tmp(plugins[idA].plugin);
  362. plugins[idA].plugin = plugins[idB].plugin;
  363. plugins[idB].plugin = tmp;
  364. #endif
  365. }
  366. void CarlaEngine::ProtectedData::doNextPluginAction(const bool unlock) noexcept
  367. {
  368. switch (nextAction.opcode)
  369. {
  370. case kEnginePostActionNull:
  371. break;
  372. case kEnginePostActionZeroCount:
  373. curPluginCount = 0;
  374. break;
  375. case kEnginePostActionRemovePlugin:
  376. doPluginRemove();
  377. break;
  378. case kEnginePostActionSwitchPlugins:
  379. doPluginsSwitch();
  380. break;
  381. }
  382. nextAction.opcode = kEnginePostActionNull;
  383. nextAction.pluginId = 0;
  384. nextAction.value = 0;
  385. if (unlock)
  386. {
  387. nextAction.mutex.tryLock();
  388. nextAction.mutex.unlock();
  389. }
  390. }
  391. // -----------------------------------------------------------------------
  392. #ifndef BUILD_BRIDGE
  393. void CarlaEngine::ProtectedData::processRack(const float* inBufReal[2], float* outBuf[2], const uint32_t frames, const bool isOffline)
  394. {
  395. CARLA_SAFE_ASSERT_RETURN(events.in != nullptr,);
  396. CARLA_SAFE_ASSERT_RETURN(events.out != nullptr,);
  397. // safe copy
  398. float inBuf0[frames];
  399. float inBuf1[frames];
  400. float* inBuf[2] = { inBuf0, inBuf1 };
  401. // initialize audio inputs
  402. FLOAT_COPY(inBuf0, inBufReal[0], frames);
  403. FLOAT_COPY(inBuf1, inBufReal[1], frames);
  404. // initialize audio outputs (zero)
  405. FLOAT_CLEAR(outBuf[0], frames);
  406. FLOAT_CLEAR(outBuf[1], frames);
  407. // initialize event outputs (zero)
  408. carla_zeroStruct<EngineEvent>(events.out, kMaxEngineEventInternalCount);
  409. bool processed = false;
  410. uint32_t oldAudioInCount = 0;
  411. uint32_t oldMidiOutCount = 0;
  412. // process plugins
  413. for (uint i=0; i < curPluginCount; ++i)
  414. {
  415. CarlaPlugin* const plugin = plugins[i].plugin;
  416. if (plugin == nullptr || ! plugin->isEnabled() || ! plugin->tryLock(isOffline))
  417. continue;
  418. if (processed)
  419. {
  420. // initialize audio inputs (from previous outputs)
  421. FLOAT_COPY(inBuf0, outBuf[0], frames);
  422. FLOAT_COPY(inBuf1, outBuf[1], frames);
  423. // initialize audio outputs (zero)
  424. FLOAT_CLEAR(outBuf[0], frames);
  425. FLOAT_CLEAR(outBuf[1], frames);
  426. // if plugin has no midi out, add previous events
  427. if (oldMidiOutCount == 0 && events.in[0].type != kEngineEventTypeNull)
  428. {
  429. if (events.out[0].type != kEngineEventTypeNull)
  430. {
  431. // TODO: carefully add to input, sorted events
  432. }
  433. // else nothing needed
  434. }
  435. else
  436. {
  437. // initialize event inputs from previous outputs
  438. carla_copyStruct<EngineEvent>(events.in, events.out, kMaxEngineEventInternalCount);
  439. // initialize event outputs (zero)
  440. carla_zeroStruct<EngineEvent>(events.out, kMaxEngineEventInternalCount);
  441. }
  442. }
  443. oldAudioInCount = plugin->getAudioInCount();
  444. oldMidiOutCount = plugin->getMidiOutCount();
  445. // process
  446. plugin->initBuffers();
  447. plugin->process(inBuf, outBuf, frames);
  448. plugin->unlock();
  449. // if plugin has no audio inputs, add input buffer
  450. if (oldAudioInCount == 0)
  451. {
  452. FLOAT_ADD(outBuf[0], inBuf0, frames);
  453. FLOAT_ADD(outBuf[1], inBuf1, frames);
  454. }
  455. // set peaks
  456. {
  457. EnginePluginData& pluginData(plugins[i]);
  458. #ifdef HAVE_JUCE
  459. juce::Range<float> range;
  460. if (oldAudioInCount > 0)
  461. {
  462. range = FloatVectorOperations::findMinAndMax(inBuf0, static_cast<int>(frames));
  463. pluginData.insPeak[0] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  464. range = FloatVectorOperations::findMinAndMax(inBuf1, static_cast<int>(frames));
  465. pluginData.insPeak[1] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  466. }
  467. else
  468. {
  469. pluginData.insPeak[0] = 0.0f;
  470. pluginData.insPeak[1] = 0.0f;
  471. }
  472. if (plugin->getAudioOutCount() > 0)
  473. {
  474. range = FloatVectorOperations::findMinAndMax(outBuf[0], static_cast<int>(frames));
  475. pluginData.outsPeak[0] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  476. range = FloatVectorOperations::findMinAndMax(outBuf[1], static_cast<int>(frames));
  477. pluginData.outsPeak[1] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  478. }
  479. else
  480. {
  481. pluginData.outsPeak[0] = 0.0f;
  482. pluginData.outsPeak[1] = 0.0f;
  483. }
  484. #else
  485. float peak1, peak2;
  486. if (oldAudioInCount > 0)
  487. {
  488. peak1 = peak2 = 0.0f;
  489. for (uint32_t k=0; k < frames; ++k)
  490. {
  491. peak1 = carla_max<float>(peak1, std::fabs(inBuf0[k]), 1.0f);
  492. peak2 = carla_max<float>(peak2, std::fabs(inBuf1[k]), 1.0f);
  493. }
  494. pluginData.insPeak[0] = peak1;
  495. pluginData.insPeak[1] = peak2;
  496. }
  497. else
  498. {
  499. pluginData.insPeak[0] = 0.0f;
  500. pluginData.insPeak[1] = 0.0f;
  501. }
  502. if (plugin->getAudioOutCount() > 0)
  503. {
  504. peak1 = peak2 = 0.0f;
  505. for (uint32_t k=0; k < frames; ++k)
  506. {
  507. peak1 = carla_max<float>(peak1, std::fabs(outBuf[0][k]), 1.0f);
  508. peak2 = carla_max<float>(peak2, std::fabs(outBuf[1][k]), 1.0f);
  509. }
  510. pluginData.outsPeak[0] = peak1;
  511. pluginData.outsPeak[1] = peak2;
  512. }
  513. else
  514. {
  515. pluginData.outsPeak[0] = 0.0f;
  516. pluginData.outsPeak[1] = 0.0f;
  517. }
  518. #endif
  519. }
  520. processed = true;
  521. }
  522. }
  523. void CarlaEngine::ProtectedData::processRackFull(const float* const* const inBuf, const uint32_t inCount, float* const* const outBuf, const uint32_t outCount, const uint32_t nframes, const bool isOffline)
  524. {
  525. const CarlaMutexLocker _crml(graph.rack->connectLock); // Recursive
  526. if (inBuf != nullptr && inCount > 0)
  527. {
  528. bool noConnections = true;
  529. // connect input buffers
  530. for (LinkedList<int>::Itenerator it = graph.rack->connectedIn1.begin(); it.valid(); it.next())
  531. {
  532. const int& port(it.getValue());
  533. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(inCount));
  534. if (noConnections)
  535. {
  536. FLOAT_COPY(audio.inBuf[0], inBuf[port], nframes);
  537. noConnections = false;
  538. }
  539. else
  540. {
  541. FLOAT_ADD(audio.inBuf[0], inBuf[port], nframes);
  542. }
  543. }
  544. if (noConnections)
  545. FLOAT_CLEAR(audio.inBuf[0], nframes);
  546. noConnections = true;
  547. for (LinkedList<int>::Itenerator it = graph.rack->connectedIn2.begin(); it.valid(); it.next())
  548. {
  549. const int& port(it.getValue());
  550. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(inCount));
  551. if (noConnections)
  552. {
  553. FLOAT_COPY(audio.inBuf[1], inBuf[port], nframes);
  554. noConnections = false;
  555. }
  556. else
  557. {
  558. FLOAT_ADD(audio.inBuf[1], inBuf[port], nframes);
  559. }
  560. }
  561. if (noConnections)
  562. FLOAT_CLEAR(audio.inBuf[1], nframes);
  563. }
  564. else
  565. {
  566. FLOAT_CLEAR(audio.inBuf[0], nframes);
  567. FLOAT_CLEAR(audio.inBuf[1], nframes);
  568. }
  569. FLOAT_CLEAR(audio.outBuf[0], nframes);
  570. FLOAT_CLEAR(audio.outBuf[1], nframes);
  571. // process
  572. processRack(const_cast<const float**>(audio.inBuf), audio.outBuf, nframes, isOffline);
  573. // connect output buffers
  574. if (graph.rack->connectedOut1.count() != 0)
  575. {
  576. for (LinkedList<int>::Itenerator it = graph.rack->connectedOut1.begin(); it.valid(); it.next())
  577. {
  578. const int& port(it.getValue());
  579. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(outCount));
  580. FLOAT_ADD(outBuf[port], audio.outBuf[0], nframes);
  581. }
  582. }
  583. if (graph.rack->connectedOut2.count() != 0)
  584. {
  585. for (LinkedList<int>::Itenerator it = graph.rack->connectedOut2.begin(); it.valid(); it.next())
  586. {
  587. const int& port(it.getValue());
  588. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(outCount));
  589. FLOAT_ADD(outBuf[port], audio.outBuf[1], nframes);
  590. }
  591. }
  592. }
  593. #endif
  594. // -----------------------------------------------------------------------
  595. // ScopedActionLock
  596. ScopedActionLock::ScopedActionLock(CarlaEngine::ProtectedData* const data, const EnginePostAction action, const uint pluginId, const uint value, const bool lockWait) noexcept
  597. : fData(data)
  598. {
  599. fData->nextAction.mutex.lock();
  600. CARLA_SAFE_ASSERT_RETURN(fData->nextAction.opcode == kEnginePostActionNull,);
  601. fData->nextAction.opcode = action;
  602. fData->nextAction.pluginId = pluginId;
  603. fData->nextAction.value = value;
  604. if (lockWait)
  605. {
  606. // block wait for unlock on processing side
  607. carla_stdout("ScopedPluginAction(%i) - blocking START", pluginId);
  608. fData->nextAction.mutex.lock();
  609. carla_stdout("ScopedPluginAction(%i) - blocking DONE", pluginId);
  610. }
  611. else
  612. {
  613. fData->doNextPluginAction(false);
  614. }
  615. }
  616. ScopedActionLock::~ScopedActionLock() noexcept
  617. {
  618. fData->nextAction.mutex.unlock();
  619. }
  620. // -----------------------------------------------------------------------
  621. CARLA_BACKEND_END_NAMESPACE