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.

849 lines
27KB

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