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.

830 lines
26KB

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