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.

2188 lines
74KB

  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 "CarlaPlugin.hpp"
  20. #include "CarlaMathUtils.hpp"
  21. #include "CarlaMIDI.h"
  22. using juce::AudioPluginInstance;
  23. using juce::AudioProcessor;
  24. using juce::AudioProcessorEditor;
  25. using juce::FloatVectorOperations;
  26. using juce::MemoryBlock;
  27. using juce::PluginDescription;
  28. using juce::String;
  29. using juce::jmax;
  30. CARLA_BACKEND_START_NAMESPACE
  31. // -----------------------------------------------------------------------
  32. // Graph Ports
  33. GraphPorts::GraphPorts() noexcept
  34. : ins(),
  35. outs() {}
  36. const char* GraphPorts::getName(const bool isInput, const uint portId) const noexcept
  37. {
  38. for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
  39. {
  40. static const PortNameToId portNameFallback = { 0, 0, { '\0' }, { '\0' } };
  41. const PortNameToId& portNameToId(it.getValue(portNameFallback));
  42. CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);
  43. if (portNameToId.port == portId)
  44. return portNameToId.name;
  45. }
  46. return nullptr;
  47. }
  48. uint GraphPorts::getPortId(const bool isInput, const char portName[], bool* const ok) const noexcept
  49. {
  50. for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
  51. {
  52. static const PortNameToId portNameFallback = { 0, 0, { '\0' }, { '\0' } };
  53. const PortNameToId& portNameToId(it.getValue(portNameFallback));
  54. CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);
  55. if (std::strncmp(portNameToId.name, portName, STR_MAX) == 0)
  56. {
  57. if (ok != nullptr)
  58. *ok = true;
  59. return portNameToId.port;
  60. }
  61. }
  62. if (ok != nullptr)
  63. *ok = false;
  64. return 0;
  65. }
  66. // -----------------------------------------------------------------------
  67. // Rack Graph stuff
  68. static inline
  69. uint getCarlaRackPortIdFromName(const char* const shortname) noexcept
  70. {
  71. if (std::strcmp(shortname, "AudioIn1") == 0 || std::strcmp(shortname, "audio-in1") == 0)
  72. return RACK_GRAPH_CARLA_PORT_AUDIO_IN1;
  73. if (std::strcmp(shortname, "AudioIn2") == 0 || std::strcmp(shortname, "audio-in2") == 0)
  74. return RACK_GRAPH_CARLA_PORT_AUDIO_IN2;
  75. if (std::strcmp(shortname, "AudioOut1") == 0 || std::strcmp(shortname, "audio-out1") == 0)
  76. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT1;
  77. if (std::strcmp(shortname, "AudioOut2") == 0 || std::strcmp(shortname, "audio-out2") == 0)
  78. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT2;
  79. if (std::strcmp(shortname, "MidiIn") == 0 || std::strcmp(shortname, "midi-in") == 0)
  80. return RACK_GRAPH_CARLA_PORT_MIDI_IN;
  81. if (std::strcmp(shortname, "MidiOut") == 0 || std::strcmp(shortname, "midi-out") == 0)
  82. return RACK_GRAPH_CARLA_PORT_MIDI_OUT;
  83. carla_stderr("CarlaBackend::getCarlaRackPortIdFromName(%s) - invalid short name", shortname);
  84. return RACK_GRAPH_CARLA_PORT_NULL;
  85. }
  86. static inline
  87. const char* getCarlaRackFullPortNameFromId(const /*RackGraphCarlaPortIds*/ uint portId)
  88. {
  89. switch (portId)
  90. {
  91. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  92. return "Carla:AudioIn1";
  93. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  94. return "Carla:AudioIn2";
  95. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  96. return "Carla:AudioOut1";
  97. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  98. return "Carla:AudioOut2";
  99. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  100. return "Carla:MidiIn";
  101. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  102. return "Carla:MidiOut";
  103. //case RACK_GRAPH_CARLA_PORT_NULL:
  104. //case RACK_GRAPH_CARLA_PORT_MAX:
  105. // break;
  106. }
  107. carla_stderr("CarlaBackend::getCarlaRackFullPortNameFromId(%i) - invalid port id", portId);
  108. return nullptr;
  109. }
  110. // -----------------------------------------------------------------------
  111. // RackGraph Audio Buffers
  112. RackGraph::AudioBuffers::AudioBuffers() noexcept
  113. : mutex(),
  114. connectedIn1(),
  115. connectedIn2(),
  116. connectedOut1(),
  117. connectedOut2()
  118. #ifdef CARLA_PROPER_CPP11_SUPPORT
  119. , inBuf{nullptr, nullptr},
  120. inBufTmp{nullptr, nullptr},
  121. outBuf{nullptr, nullptr} {}
  122. #else
  123. {
  124. inBuf[0] = inBuf[1] = nullptr;
  125. inBufTmp[0] = inBufTmp[1] = nullptr;
  126. outBuf[0] = outBuf[1] = nullptr;
  127. }
  128. #endif
  129. // -----------------------------------------------------------------------
  130. // RackGraph
  131. RackGraph::RackGraph(CarlaEngine* const engine, const uint32_t ins, const uint32_t outs) noexcept
  132. : connections(),
  133. inputs(ins),
  134. outputs(outs),
  135. isOffline(false),
  136. retCon(),
  137. audioBuffers(),
  138. audioPorts(),
  139. midiPorts(),
  140. kEngine(engine)
  141. {
  142. setBufferSize(engine->getBufferSize());
  143. }
  144. RackGraph::~RackGraph() noexcept
  145. {
  146. clearConnections();
  147. clearPorts();
  148. }
  149. void RackGraph::setBufferSize(const uint32_t bufferSize) noexcept
  150. {
  151. const int bufferSizei(static_cast<int>(bufferSize));
  152. if (audioBuffers.inBuf[0] != nullptr) { delete[] audioBuffers.inBuf[0]; audioBuffers.inBuf[0] = nullptr; }
  153. if (audioBuffers.inBuf[1] != nullptr) { delete[] audioBuffers.inBuf[1]; audioBuffers.inBuf[1] = nullptr; }
  154. if (audioBuffers.inBufTmp[0] != nullptr) { delete[] audioBuffers.inBufTmp[0]; audioBuffers.inBufTmp[0] = nullptr; }
  155. if (audioBuffers.inBufTmp[1] != nullptr) { delete[] audioBuffers.inBufTmp[1]; audioBuffers.inBufTmp[1] = nullptr; }
  156. if (audioBuffers.outBuf[0] != nullptr) { delete[] audioBuffers.outBuf[0]; audioBuffers.outBuf[0] = nullptr; }
  157. if (audioBuffers.outBuf[1] != nullptr) { delete[] audioBuffers.outBuf[1]; audioBuffers.outBuf[1] = nullptr; }
  158. CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);
  159. try {
  160. audioBuffers.inBufTmp[0] = new float[bufferSize];
  161. audioBuffers.inBufTmp[1] = new float[bufferSize];
  162. if (inputs > 0 || outputs > 0)
  163. {
  164. audioBuffers.inBuf[0] = new float[bufferSize];
  165. audioBuffers.inBuf[1] = new float[bufferSize];
  166. audioBuffers.outBuf[0] = new float[bufferSize];
  167. audioBuffers.outBuf[1] = new float[bufferSize];
  168. }
  169. }
  170. catch(...) {
  171. if (audioBuffers.inBufTmp[0] != nullptr) { delete[] audioBuffers.inBufTmp[0]; audioBuffers.inBufTmp[0] = nullptr; }
  172. if (audioBuffers.inBufTmp[1] != nullptr) { delete[] audioBuffers.inBufTmp[1]; audioBuffers.inBufTmp[1] = nullptr; }
  173. if (inputs > 0 || outputs > 0)
  174. {
  175. if (audioBuffers.inBuf[0] != nullptr) { delete[] audioBuffers.inBuf[0]; audioBuffers.inBuf[0] = nullptr; }
  176. if (audioBuffers.inBuf[1] != nullptr) { delete[] audioBuffers.inBuf[1]; audioBuffers.inBuf[1] = nullptr; }
  177. if (audioBuffers.outBuf[0] != nullptr) { delete[] audioBuffers.outBuf[0]; audioBuffers.outBuf[0] = nullptr; }
  178. if (audioBuffers.outBuf[1] != nullptr) { delete[] audioBuffers.outBuf[1]; audioBuffers.outBuf[1] = nullptr; }
  179. }
  180. return;
  181. }
  182. FloatVectorOperations::clear(audioBuffers.inBufTmp[0], bufferSizei);
  183. FloatVectorOperations::clear(audioBuffers.inBufTmp[1], bufferSizei);
  184. if (inputs > 0 || outputs > 0)
  185. {
  186. FloatVectorOperations::clear(audioBuffers.inBuf[0], bufferSizei);
  187. FloatVectorOperations::clear(audioBuffers.inBuf[1], bufferSizei);
  188. FloatVectorOperations::clear(audioBuffers.outBuf[0], bufferSizei);
  189. FloatVectorOperations::clear(audioBuffers.outBuf[1], bufferSizei);
  190. }
  191. }
  192. void RackGraph::setOffline(const bool offline) noexcept
  193. {
  194. isOffline = offline;
  195. }
  196. bool RackGraph::connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept
  197. {
  198. uint otherGroup, otherPort, carlaPort;
  199. if (groupA == RACK_GRAPH_GROUP_CARLA)
  200. {
  201. CARLA_SAFE_ASSERT_RETURN(groupB != RACK_GRAPH_GROUP_CARLA, false);
  202. carlaPort = portA;
  203. otherGroup = groupB;
  204. otherPort = portB;
  205. }
  206. else
  207. {
  208. CARLA_SAFE_ASSERT_RETURN(groupB == RACK_GRAPH_GROUP_CARLA, false);
  209. carlaPort = portB;
  210. otherGroup = groupA;
  211. otherPort = portA;
  212. }
  213. CARLA_SAFE_ASSERT_RETURN(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX, false);
  214. CARLA_SAFE_ASSERT_RETURN(otherGroup > RACK_GRAPH_GROUP_CARLA && otherGroup < RACK_GRAPH_GROUP_MAX, false);
  215. bool makeConnection = false;
  216. switch (carlaPort)
  217. {
  218. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  219. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_IN, false);
  220. audioBuffers.mutex.lock();
  221. makeConnection = audioBuffers.connectedIn1.append(otherPort);
  222. audioBuffers.mutex.unlock();
  223. break;
  224. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  225. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_IN, false);
  226. audioBuffers.mutex.lock();
  227. makeConnection = audioBuffers.connectedIn2.append(otherPort);
  228. audioBuffers.mutex.unlock();
  229. break;
  230. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  231. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_OUT, false);
  232. audioBuffers.mutex.lock();
  233. makeConnection = audioBuffers.connectedOut1.append(otherPort);
  234. audioBuffers.mutex.unlock();
  235. break;
  236. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  237. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_OUT, false);
  238. audioBuffers.mutex.lock();
  239. makeConnection = audioBuffers.connectedOut2.append(otherPort);
  240. audioBuffers.mutex.unlock();
  241. break;
  242. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  243. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_MIDI_IN, false);
  244. if (const char* const portName = midiPorts.getName(true, otherPort))
  245. makeConnection = kEngine->connectRackMidiInPort(portName);
  246. break;
  247. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  248. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_MIDI_OUT, false);
  249. if (const char* const portName = midiPorts.getName(false, otherPort))
  250. makeConnection = kEngine->connectRackMidiOutPort(portName);
  251. break;
  252. }
  253. if (! makeConnection)
  254. {
  255. kEngine->setLastError("Invalid rack connection");
  256. return false;
  257. }
  258. ConnectionToId connectionToId;
  259. connectionToId.setData(++connections.lastId, groupA, portA, groupB, portB);
  260. char strBuf[STR_MAX+1];
  261. strBuf[STR_MAX] = '\0';
  262. std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB);
  263. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  264. connections.list.append(connectionToId);
  265. return true;
  266. }
  267. bool RackGraph::disconnect(const uint connectionId) noexcept
  268. {
  269. CARLA_SAFE_ASSERT_RETURN(connections.list.count() > 0, false);
  270. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  271. {
  272. static const ConnectionToId fallback = { 0, 0, 0, 0, 0 };
  273. const ConnectionToId& connectionToId(it.getValue(fallback));
  274. CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
  275. if (connectionToId.id != connectionId)
  276. continue;
  277. uint otherGroup, otherPort, carlaPort;
  278. if (connectionToId.groupA == RACK_GRAPH_GROUP_CARLA)
  279. {
  280. CARLA_SAFE_ASSERT_RETURN(connectionToId.groupB != RACK_GRAPH_GROUP_CARLA, false);
  281. carlaPort = connectionToId.portA;
  282. otherGroup = connectionToId.groupB;
  283. otherPort = connectionToId.portB;
  284. }
  285. else
  286. {
  287. CARLA_SAFE_ASSERT_RETURN(connectionToId.groupB == RACK_GRAPH_GROUP_CARLA, false);
  288. carlaPort = connectionToId.portB;
  289. otherGroup = connectionToId.groupA;
  290. otherPort = connectionToId.portA;
  291. }
  292. CARLA_SAFE_ASSERT_RETURN(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX, false);
  293. CARLA_SAFE_ASSERT_RETURN(otherGroup > RACK_GRAPH_GROUP_CARLA && otherGroup < RACK_GRAPH_GROUP_MAX, false);
  294. bool makeDisconnection = false;
  295. switch (carlaPort)
  296. {
  297. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  298. audioBuffers.mutex.lock();
  299. makeDisconnection = audioBuffers.connectedIn1.removeOne(otherPort);
  300. audioBuffers.mutex.unlock();
  301. break;
  302. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  303. audioBuffers.mutex.lock();
  304. makeDisconnection = audioBuffers.connectedIn2.removeOne(otherPort);
  305. audioBuffers.mutex.unlock();
  306. break;
  307. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  308. audioBuffers.mutex.lock();
  309. makeDisconnection = audioBuffers.connectedOut1.removeOne(otherPort);
  310. audioBuffers.mutex.unlock();
  311. break;
  312. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  313. audioBuffers.mutex.lock();
  314. makeDisconnection = audioBuffers.connectedOut2.removeOne(otherPort);
  315. audioBuffers.mutex.unlock();
  316. break;
  317. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  318. if (const char* const portName = midiPorts.getName(true, otherPort))
  319. makeDisconnection = kEngine->disconnectRackMidiInPort(portName);
  320. break;
  321. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  322. if (const char* const portName = midiPorts.getName(false, otherPort))
  323. makeDisconnection = kEngine->disconnectRackMidiOutPort(portName);
  324. break;
  325. }
  326. if (! makeDisconnection)
  327. {
  328. kEngine->setLastError("Invalid rack connection");
  329. return false;
  330. }
  331. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connectionToId.id, 0, 0, 0.0f, nullptr);
  332. connections.list.remove(it);
  333. return true;
  334. }
  335. kEngine->setLastError("Failed to find connection");
  336. return false;
  337. }
  338. void RackGraph::clearPorts() noexcept
  339. {
  340. audioPorts.ins.clear();
  341. audioPorts.outs.clear();
  342. midiPorts.ins.clear();
  343. midiPorts.outs.clear();
  344. }
  345. void RackGraph::clearConnections() noexcept
  346. {
  347. connections.clear();
  348. audioBuffers.mutex.lock();
  349. audioBuffers.connectedIn1.clear();
  350. audioBuffers.connectedIn2.clear();
  351. audioBuffers.connectedOut1.clear();
  352. audioBuffers.connectedOut2.clear();
  353. audioBuffers.mutex.unlock();
  354. }
  355. void RackGraph::refresh(const char* const deviceName)
  356. {
  357. CARLA_SAFE_ASSERT_RETURN(deviceName != nullptr,);
  358. connections.clear();
  359. // Main
  360. {
  361. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_CARLA, PATCHBAY_ICON_CARLA, -1, 0.0f, kEngine->getName());
  362. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN1, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in1");
  363. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN2, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in2");
  364. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT1, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out1");
  365. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT2, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out2");
  366. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_IN, PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, "midi-in");
  367. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_OUT, PATCHBAY_PORT_TYPE_MIDI, 0.0f, "midi-out");
  368. }
  369. char strBuf[STR_MAX+1];
  370. strBuf[STR_MAX] = '\0';
  371. // Audio In
  372. {
  373. if (deviceName[0] != '\0')
  374. std::snprintf(strBuf, STR_MAX, "Capture (%s)", deviceName);
  375. else
  376. std::strncpy(strBuf, "Capture", STR_MAX);
  377. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
  378. const CarlaString groupName(strBuf);
  379. int h = 0;
  380. for (LinkedList<PortNameToId>::Itenerator it = audioPorts.ins.begin(); it.valid(); it.next())
  381. {
  382. PortNameToId& portNameToId(it.getValue());
  383. portNameToId.setFullName(groupName + portNameToId.name);
  384. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, ++h,
  385. PATCHBAY_PORT_TYPE_AUDIO, 0.0f, portNameToId.name);
  386. }
  387. }
  388. // Audio Out
  389. {
  390. if (deviceName[0] != '\0')
  391. std::snprintf(strBuf, STR_MAX, "Playback (%s)", deviceName);
  392. else
  393. std::strncpy(strBuf, "Playback", STR_MAX);
  394. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
  395. const CarlaString groupName(strBuf);
  396. int h = 0;
  397. for (LinkedList<PortNameToId>::Itenerator it = audioPorts.outs.begin(); it.valid(); it.next())
  398. {
  399. PortNameToId& portNameToId(it.getValue());
  400. portNameToId.setFullName(groupName + portNameToId.name);
  401. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, ++h,
  402. PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
  403. }
  404. }
  405. // MIDI In
  406. {
  407. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");
  408. const CarlaString groupNamePlus("Readable MIDI ports:");
  409. int h = 0;
  410. for (LinkedList<PortNameToId>::Itenerator it = midiPorts.ins.begin(); it.valid(); it.next())
  411. {
  412. PortNameToId& portNameToId(it.getValue());
  413. portNameToId.setFullName(groupNamePlus + portNameToId.name);
  414. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, ++h,
  415. PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
  416. }
  417. }
  418. // MIDI Out
  419. {
  420. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");
  421. const CarlaString groupNamePlus("Writable MIDI ports:");
  422. int h = 0;
  423. for (LinkedList<PortNameToId>::Itenerator it = midiPorts.outs.begin(); it.valid(); it.next())
  424. {
  425. PortNameToId& portNameToId(it.getValue());
  426. portNameToId.setFullName(groupNamePlus + portNameToId.name);
  427. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, ++h,
  428. PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
  429. }
  430. }
  431. // Connections
  432. audioBuffers.mutex.lock();
  433. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn1.begin(); it.valid(); it.next())
  434. {
  435. const uint& portId(it.getValue(0));
  436. CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
  437. CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.ins.count()); // FIXME <=
  438. ConnectionToId connectionToId;
  439. connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN1);
  440. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  441. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  442. connections.list.append(connectionToId);
  443. }
  444. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn2.begin(); it.valid(); it.next())
  445. {
  446. const uint& portId(it.getValue(0));
  447. CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
  448. CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.ins.count()); // FIXME <=
  449. ConnectionToId connectionToId;
  450. connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_AUDIO_IN, portId, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN2);
  451. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  452. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  453. connections.list.append(connectionToId);
  454. }
  455. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut1.begin(); it.valid(); it.next())
  456. {
  457. const uint& portId(it.getValue(0));
  458. CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
  459. CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.outs.count()); // FIXME <=
  460. ConnectionToId connectionToId;
  461. connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT1, RACK_GRAPH_GROUP_AUDIO_OUT, portId);
  462. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  463. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  464. connections.list.append(connectionToId);
  465. }
  466. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut2.begin(); it.valid(); it.next())
  467. {
  468. const uint& portId(it.getValue(0));
  469. CARLA_SAFE_ASSERT_CONTINUE(portId != 0);
  470. CARLA_SAFE_ASSERT_CONTINUE(portId <= audioPorts.outs.count()); // FIXME <=
  471. ConnectionToId connectionToId;
  472. connectionToId.setData(++(connections.lastId), RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT2, RACK_GRAPH_GROUP_AUDIO_OUT, portId);
  473. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  474. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  475. connections.list.append(connectionToId);
  476. }
  477. audioBuffers.mutex.unlock();
  478. }
  479. const char* const* RackGraph::getConnections() const noexcept
  480. {
  481. if (connections.list.count() == 0)
  482. return nullptr;
  483. CarlaStringList connList;
  484. char strBuf[STR_MAX+1];
  485. strBuf[STR_MAX] = '\0';
  486. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  487. {
  488. static const ConnectionToId fallback = { 0, 0, 0, 0, 0 };
  489. const ConnectionToId& connectionToId(it.getValue(fallback));
  490. CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
  491. uint otherGroup, otherPort, carlaPort;
  492. if (connectionToId.groupA == RACK_GRAPH_GROUP_CARLA)
  493. {
  494. CARLA_SAFE_ASSERT_CONTINUE(connectionToId.groupB != RACK_GRAPH_GROUP_CARLA);
  495. carlaPort = connectionToId.portA;
  496. otherGroup = connectionToId.groupB;
  497. otherPort = connectionToId.portB;
  498. }
  499. else
  500. {
  501. CARLA_SAFE_ASSERT_CONTINUE(connectionToId.groupB == RACK_GRAPH_GROUP_CARLA);
  502. carlaPort = connectionToId.portB;
  503. otherGroup = connectionToId.groupA;
  504. otherPort = connectionToId.portA;
  505. }
  506. CARLA_SAFE_ASSERT_CONTINUE(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX);
  507. CARLA_SAFE_ASSERT_CONTINUE(otherGroup > RACK_GRAPH_GROUP_CARLA && otherGroup < RACK_GRAPH_GROUP_MAX);
  508. switch (carlaPort)
  509. {
  510. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  511. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  512. std::snprintf(strBuf, STR_MAX, "AudioIn:%s", audioPorts.getName(true, otherPort));
  513. connList.append(strBuf);
  514. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  515. break;
  516. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  517. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  518. std::snprintf(strBuf, STR_MAX, "AudioOut:%s", audioPorts.getName(false, otherPort));
  519. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  520. connList.append(strBuf);
  521. break;
  522. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  523. std::snprintf(strBuf, STR_MAX, "MidiIn:%s", midiPorts.getName(true, otherPort));
  524. connList.append(strBuf);
  525. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  526. break;
  527. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  528. std::snprintf(strBuf, STR_MAX, "MidiOut:%s", midiPorts.getName(false, otherPort));
  529. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  530. connList.append(strBuf);
  531. break;
  532. }
  533. }
  534. if (connList.count() == 0)
  535. return nullptr;
  536. retCon = connList.toCharStringListPtr();
  537. return retCon;
  538. }
  539. bool RackGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const noexcept
  540. {
  541. CARLA_SAFE_ASSERT_RETURN(fullPortName != nullptr && fullPortName[0] != '\0', false);
  542. if (std::strncmp(fullPortName, "Carla:", 6) == 0)
  543. {
  544. groupId = RACK_GRAPH_GROUP_CARLA;
  545. portId = getCarlaRackPortIdFromName(fullPortName+6);
  546. if (portId > RACK_GRAPH_CARLA_PORT_NULL && portId < RACK_GRAPH_CARLA_PORT_MAX)
  547. return true;
  548. }
  549. else if (std::strncmp(fullPortName, "AudioIn:", 8) == 0)
  550. {
  551. groupId = RACK_GRAPH_GROUP_AUDIO_IN;
  552. if (const char* const portName = fullPortName+8)
  553. {
  554. bool ok;
  555. portId = audioPorts.getPortId(true, portName, &ok);
  556. return ok;
  557. }
  558. }
  559. else if (std::strncmp(fullPortName, "AudioOut:", 9) == 0)
  560. {
  561. groupId = RACK_GRAPH_GROUP_AUDIO_OUT;
  562. if (const char* const portName = fullPortName+9)
  563. {
  564. bool ok;
  565. portId = audioPorts.getPortId(false, portName, &ok);
  566. return ok;
  567. }
  568. }
  569. else if (std::strncmp(fullPortName, "MidiIn:", 7) == 0)
  570. {
  571. groupId = RACK_GRAPH_GROUP_MIDI_IN;
  572. if (const char* const portName = fullPortName+7)
  573. {
  574. bool ok;
  575. portId = midiPorts.getPortId(true, portName, &ok);
  576. return ok;
  577. }
  578. }
  579. else if (std::strncmp(fullPortName, "MidiOut:", 8) == 0)
  580. {
  581. groupId = RACK_GRAPH_GROUP_MIDI_OUT;
  582. if (const char* const portName = fullPortName+8)
  583. {
  584. bool ok;
  585. portId = midiPorts.getPortId(false, portName, &ok);
  586. return ok;
  587. }
  588. }
  589. return false;
  590. }
  591. void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inBufReal[2], float* outBuf[2], const uint32_t frames)
  592. {
  593. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  594. CARLA_SAFE_ASSERT_RETURN(data->events.in != nullptr,);
  595. CARLA_SAFE_ASSERT_RETURN(data->events.out != nullptr,);
  596. const int iframes(static_cast<int>(frames));
  597. // safe copy
  598. float inBuf0[frames];
  599. float inBuf1[frames];
  600. const float* inBuf[2] = { inBuf0, inBuf1 };
  601. // initialize audio inputs
  602. FloatVectorOperations::copy(inBuf0, inBufReal[0], iframes);
  603. FloatVectorOperations::copy(inBuf1, inBufReal[1], iframes);
  604. // initialize audio outputs (zero)
  605. FloatVectorOperations::clear(outBuf[0], iframes);
  606. FloatVectorOperations::clear(outBuf[1], iframes);
  607. // initialize event outputs (zero)
  608. carla_zeroStruct<EngineEvent>(data->events.out, kMaxEngineEventInternalCount);
  609. bool processed = false;
  610. uint32_t oldAudioInCount = 0;
  611. uint32_t oldMidiOutCount = 0;
  612. // process plugins
  613. for (uint i=0; i < data->curPluginCount; ++i)
  614. {
  615. CarlaPlugin* const plugin = data->plugins[i].plugin;
  616. if (plugin == nullptr || ! plugin->isEnabled() || ! plugin->tryLock(isOffline))
  617. continue;
  618. if (processed)
  619. {
  620. // initialize audio inputs (from previous outputs)
  621. FloatVectorOperations::copy(inBuf0, outBuf[0], iframes);
  622. FloatVectorOperations::copy(inBuf1, outBuf[1], iframes);
  623. // initialize audio outputs (zero)
  624. FloatVectorOperations::clear(outBuf[0], iframes);
  625. FloatVectorOperations::clear(outBuf[1], iframes);
  626. // if plugin has no midi out, add previous events
  627. if (oldMidiOutCount == 0 && data->events.in[0].type != kEngineEventTypeNull)
  628. {
  629. if (data->events.out[0].type != kEngineEventTypeNull)
  630. {
  631. // TODO: carefully add to input, sorted events
  632. }
  633. // else nothing needed
  634. }
  635. else
  636. {
  637. // initialize event inputs from previous outputs
  638. carla_copyStruct<EngineEvent>(data->events.in, data->events.out, kMaxEngineEventInternalCount);
  639. // initialize event outputs (zero)
  640. carla_zeroStruct<EngineEvent>(data->events.out, kMaxEngineEventInternalCount);
  641. }
  642. }
  643. oldAudioInCount = plugin->getAudioInCount();
  644. oldMidiOutCount = plugin->getMidiOutCount();
  645. // process
  646. plugin->initBuffers();
  647. plugin->process(inBuf, outBuf, nullptr, nullptr, frames);
  648. plugin->unlock();
  649. // if plugin has no audio inputs, add input buffer
  650. if (oldAudioInCount == 0)
  651. {
  652. FloatVectorOperations::add(outBuf[0], inBuf0, iframes);
  653. FloatVectorOperations::add(outBuf[1], inBuf1, iframes);
  654. }
  655. // set peaks
  656. {
  657. EnginePluginData& pluginData(data->plugins[i]);
  658. juce::Range<float> range;
  659. if (oldAudioInCount > 0)
  660. {
  661. range = FloatVectorOperations::findMinAndMax(inBuf0, iframes);
  662. pluginData.insPeak[0] = carla_maxLimited<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  663. range = FloatVectorOperations::findMinAndMax(inBuf1, iframes);
  664. pluginData.insPeak[1] = carla_maxLimited<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  665. }
  666. else
  667. {
  668. pluginData.insPeak[0] = 0.0f;
  669. pluginData.insPeak[1] = 0.0f;
  670. }
  671. if (plugin->getAudioOutCount() > 0)
  672. {
  673. range = FloatVectorOperations::findMinAndMax(outBuf[0], iframes);
  674. pluginData.outsPeak[0] = carla_maxLimited<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  675. range = FloatVectorOperations::findMinAndMax(outBuf[1], iframes);
  676. pluginData.outsPeak[1] = carla_maxLimited<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  677. }
  678. else
  679. {
  680. pluginData.outsPeak[0] = 0.0f;
  681. pluginData.outsPeak[1] = 0.0f;
  682. }
  683. }
  684. processed = true;
  685. }
  686. }
  687. void RackGraph::processHelper(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames)
  688. {
  689. CARLA_SAFE_ASSERT_RETURN(audioBuffers.outBuf[1] != nullptr,);
  690. const int iframes(static_cast<int>(frames));
  691. const CarlaRecursiveMutexLocker _cml(audioBuffers.mutex);
  692. if (inBuf != nullptr && inputs > 0)
  693. {
  694. bool noConnections = true;
  695. // connect input buffers
  696. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn1.begin(); it.valid(); it.next())
  697. {
  698. const uint& port(it.getValue(0));
  699. CARLA_SAFE_ASSERT_CONTINUE(port != 0);
  700. CARLA_SAFE_ASSERT_CONTINUE(port < inputs);
  701. if (noConnections)
  702. {
  703. FloatVectorOperations::copy(audioBuffers.inBuf[0], inBuf[port], iframes);
  704. noConnections = false;
  705. }
  706. else
  707. {
  708. FloatVectorOperations::add(audioBuffers.inBuf[0], inBuf[port], iframes);
  709. }
  710. }
  711. if (noConnections)
  712. FloatVectorOperations::clear(audioBuffers.inBuf[0], iframes);
  713. noConnections = true;
  714. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedIn2.begin(); it.valid(); it.next())
  715. {
  716. const uint& port(it.getValue(0));
  717. CARLA_SAFE_ASSERT_CONTINUE(port != 0);
  718. CARLA_SAFE_ASSERT_CONTINUE(port < inputs);
  719. if (noConnections)
  720. {
  721. FloatVectorOperations::copy(audioBuffers.inBuf[1], inBuf[port], iframes);
  722. noConnections = false;
  723. }
  724. else
  725. {
  726. FloatVectorOperations::add(audioBuffers.inBuf[1], inBuf[port], iframes);
  727. }
  728. }
  729. if (noConnections)
  730. FloatVectorOperations::clear(audioBuffers.inBuf[1], iframes);
  731. }
  732. else
  733. {
  734. FloatVectorOperations::clear(audioBuffers.inBuf[0], iframes);
  735. FloatVectorOperations::clear(audioBuffers.inBuf[1], iframes);
  736. }
  737. FloatVectorOperations::clear(audioBuffers.outBuf[0], iframes);
  738. FloatVectorOperations::clear(audioBuffers.outBuf[1], iframes);
  739. // process
  740. process(data, const_cast<const float**>(audioBuffers.inBuf), audioBuffers.outBuf, frames);
  741. // connect output buffers
  742. if (audioBuffers.connectedOut1.count() != 0)
  743. {
  744. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut1.begin(); it.valid(); it.next())
  745. {
  746. const uint& port(it.getValue(0));
  747. CARLA_SAFE_ASSERT_CONTINUE(port > 0);
  748. CARLA_SAFE_ASSERT_CONTINUE(port <= outputs);
  749. FloatVectorOperations::add(outBuf[port-1], audioBuffers.outBuf[0], iframes);
  750. }
  751. }
  752. if (audioBuffers.connectedOut2.count() != 0)
  753. {
  754. for (LinkedList<uint>::Itenerator it = audioBuffers.connectedOut2.begin(); it.valid(); it.next())
  755. {
  756. const uint& port(it.getValue(0));
  757. CARLA_SAFE_ASSERT_CONTINUE(port > 0);
  758. CARLA_SAFE_ASSERT_CONTINUE(port <= outputs);
  759. FloatVectorOperations::add(outBuf[port-1], audioBuffers.outBuf[1], iframes);
  760. }
  761. }
  762. }
  763. // -----------------------------------------------------------------------
  764. // Patchbay Graph stuff
  765. static const uint32_t kAudioInputPortOffset = MAX_PATCHBAY_PLUGINS*1;
  766. static const uint32_t kAudioOutputPortOffset = MAX_PATCHBAY_PLUGINS*2;
  767. static const uint32_t kMidiInputPortOffset = MAX_PATCHBAY_PLUGINS*3;
  768. static const uint32_t kMidiOutputPortOffset = MAX_PATCHBAY_PLUGINS*3+1;
  769. static const uint kMidiChannelIndex = static_cast<uint>(AudioProcessorGraph::midiChannelIndex);
  770. static inline
  771. bool adjustPatchbayPortIdForJuce(uint& portId)
  772. {
  773. CARLA_SAFE_ASSERT_RETURN(portId >= kAudioInputPortOffset, false);
  774. CARLA_SAFE_ASSERT_RETURN(portId <= kMidiOutputPortOffset, false);
  775. if (portId == kMidiInputPortOffset)
  776. {
  777. portId = kMidiChannelIndex;
  778. return true;
  779. }
  780. if (portId == kMidiOutputPortOffset)
  781. {
  782. portId = kMidiChannelIndex;
  783. return true;
  784. }
  785. if (portId >= kAudioOutputPortOffset)
  786. {
  787. portId -= kAudioOutputPortOffset;
  788. return true;
  789. }
  790. if (portId >= kAudioInputPortOffset)
  791. {
  792. portId -= kAudioInputPortOffset;
  793. return true;
  794. }
  795. return false;
  796. }
  797. static inline
  798. const String getProcessorFullPortName(AudioProcessor* const proc, const uint32_t portId)
  799. {
  800. CARLA_SAFE_ASSERT_RETURN(proc != nullptr, String());
  801. CARLA_SAFE_ASSERT_RETURN(portId >= kAudioInputPortOffset, String());
  802. CARLA_SAFE_ASSERT_RETURN(portId <= kMidiOutputPortOffset, String());
  803. String fullPortName(proc->getName());
  804. if (portId == kMidiOutputPortOffset)
  805. {
  806. fullPortName += ":events-out";
  807. }
  808. else if (portId == kMidiInputPortOffset)
  809. {
  810. fullPortName += ":events-in";
  811. }
  812. else if (portId >= kAudioOutputPortOffset)
  813. {
  814. CARLA_SAFE_ASSERT_RETURN(proc->getNumOutputChannels() > 0, String());
  815. fullPortName += ":" + proc->getOutputChannelName(static_cast<int>(portId-kAudioOutputPortOffset));
  816. }
  817. else if (portId >= kAudioInputPortOffset)
  818. {
  819. CARLA_SAFE_ASSERT_RETURN(proc->getNumInputChannels() > 0, String());
  820. fullPortName += ":" + proc->getInputChannelName(static_cast<int>(portId-kAudioInputPortOffset));
  821. }
  822. else
  823. {
  824. return String();
  825. }
  826. return fullPortName;
  827. }
  828. static inline
  829. void addNodeToPatchbay(CarlaEngine* const engine, const uint32_t groupId, const int clientId, const AudioProcessor* const proc)
  830. {
  831. CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
  832. CARLA_SAFE_ASSERT_RETURN(proc != nullptr,);
  833. const int icon((clientId >= 0) ? PATCHBAY_ICON_PLUGIN : PATCHBAY_ICON_HARDWARE);
  834. engine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, groupId, icon, clientId, 0.0f, proc->getName().toRawUTF8());
  835. for (int i=0, numInputs=proc->getNumInputChannels(); i<numInputs; ++i)
  836. {
  837. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, groupId, static_cast<int>(kAudioInputPortOffset)+i,
  838. PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, proc->getInputChannelName(i).toRawUTF8());
  839. }
  840. for (int i=0, numOutputs=proc->getNumOutputChannels(); i<numOutputs; ++i)
  841. {
  842. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, groupId, static_cast<int>(kAudioOutputPortOffset)+i,
  843. PATCHBAY_PORT_TYPE_AUDIO, 0.0f, proc->getOutputChannelName(i).toRawUTF8());
  844. }
  845. if (proc->acceptsMidi())
  846. {
  847. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, groupId, static_cast<int>(kMidiInputPortOffset),
  848. PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, "events-in");
  849. }
  850. if (proc->producesMidi())
  851. {
  852. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, groupId, static_cast<int>(kMidiOutputPortOffset),
  853. PATCHBAY_PORT_TYPE_MIDI, 0.0f, "events-out");
  854. }
  855. }
  856. static inline
  857. void removeNodeFromPatchbay(CarlaEngine* const engine, const uint32_t groupId, const AudioProcessor* const proc)
  858. {
  859. CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
  860. CARLA_SAFE_ASSERT_RETURN(proc != nullptr,);
  861. for (int i=0, numInputs=proc->getNumInputChannels(); i<numInputs; ++i)
  862. {
  863. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED, groupId, static_cast<int>(kAudioInputPortOffset)+i,
  864. 0, 0.0f, nullptr);
  865. }
  866. for (int i=0, numOutputs=proc->getNumOutputChannels(); i<numOutputs; ++i)
  867. {
  868. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED, groupId, static_cast<int>(kAudioOutputPortOffset)+i,
  869. 0, 0.0f, nullptr);
  870. }
  871. if (proc->acceptsMidi())
  872. {
  873. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED, groupId, static_cast<int>(kMidiInputPortOffset),
  874. 0, 0.0f, nullptr);
  875. }
  876. if (proc->producesMidi())
  877. {
  878. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED, groupId, static_cast<int>(kMidiOutputPortOffset),
  879. 0, 0.0f, nullptr);
  880. }
  881. engine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_REMOVED, groupId, 0, 0, 0.0f, nullptr);
  882. }
  883. // -----------------------------------------------------------------------
  884. class CarlaPluginInstance : public AudioPluginInstance
  885. {
  886. public:
  887. CarlaPluginInstance(CarlaEngine* const engine, CarlaPlugin* const plugin)
  888. : kEngine(engine),
  889. fPlugin(plugin),
  890. leakDetector_CarlaPluginInstance()
  891. {
  892. setPlayConfigDetails(static_cast<int>(fPlugin->getAudioInCount()),
  893. static_cast<int>(fPlugin->getAudioOutCount()),
  894. getSampleRate(), getBlockSize());
  895. }
  896. ~CarlaPluginInstance() override
  897. {
  898. }
  899. void invalidatePlugin() noexcept
  900. {
  901. fPlugin = nullptr;
  902. }
  903. // -------------------------------------------------------------------
  904. void* getPlatformSpecificData() noexcept override
  905. {
  906. return fPlugin;
  907. }
  908. void fillInPluginDescription(PluginDescription& d) const override
  909. {
  910. d.pluginFormatName = "Carla";
  911. d.category = "Carla Plugin";
  912. d.version = "1.0";
  913. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  914. char strBuf[STR_MAX+1];
  915. strBuf[STR_MAX] = '\0';
  916. fPlugin->getRealName(strBuf);
  917. d.name = strBuf;
  918. fPlugin->getLabel(strBuf);
  919. d.descriptiveName = strBuf;
  920. fPlugin->getMaker(strBuf);
  921. d.manufacturerName = strBuf;
  922. d.uid = d.name.hashCode();
  923. d.isInstrument = (fPlugin->getHints() & PLUGIN_IS_SYNTH);
  924. d.numInputChannels = static_cast<int>(fPlugin->getAudioInCount());
  925. d.numOutputChannels = static_cast<int>(fPlugin->getAudioOutCount());
  926. //d.hasSharedContainer = true;
  927. }
  928. // -------------------------------------------------------------------
  929. const String getName() const override
  930. {
  931. return fPlugin->getName();
  932. }
  933. void processBlock(AudioSampleBuffer& audio, MidiBuffer& midi)
  934. {
  935. if (fPlugin == nullptr || ! fPlugin->isEnabled())
  936. {
  937. audio.clear();
  938. midi.clear();
  939. return;
  940. }
  941. if (! fPlugin->tryLock(kEngine->isOffline()))
  942. {
  943. audio.clear();
  944. midi.clear();
  945. return;
  946. }
  947. fPlugin->initBuffers();
  948. if (CarlaEngineEventPort* const port = fPlugin->getDefaultEventInPort())
  949. {
  950. EngineEvent* const engineEvents(port->fBuffer);
  951. CARLA_SAFE_ASSERT_RETURN(engineEvents != nullptr,);
  952. carla_zeroStruct<EngineEvent>(engineEvents, kMaxEngineEventInternalCount);
  953. fillEngineEventsFromJuceMidiBuffer(engineEvents, midi);
  954. }
  955. midi.clear();
  956. // TODO - CV support
  957. const uint32_t bufferSize(static_cast<uint32_t>(audio.getNumSamples()));
  958. if (const int numChan = audio.getNumChannels())
  959. {
  960. if (fPlugin->getAudioInCount() == 0)
  961. audio.clear();
  962. float* audioBuffers[numChan];
  963. for (int i=0; i<numChan; ++i)
  964. audioBuffers[i] = audio.getWritePointer(i);
  965. float inPeaks[2] = { 0.0f };
  966. float outPeaks[2] = { 0.0f };
  967. for (int i=0; i<numChan; ++i)
  968. {
  969. for (uint32_t j=0; j < bufferSize; ++j)
  970. {
  971. const float absV(std::abs(audioBuffers[i][j]));
  972. if (absV > inPeaks[i])
  973. inPeaks[i] = absV;
  974. }
  975. }
  976. fPlugin->process(const_cast<const float**>(audioBuffers), audioBuffers, nullptr, nullptr, bufferSize);
  977. for (int i=0; i<numChan; ++i)
  978. {
  979. for (uint32_t j=0; j < bufferSize; ++j)
  980. {
  981. const float absV(std::abs(audioBuffers[i][j]));
  982. if (absV > outPeaks[i])
  983. outPeaks[i] = absV;
  984. }
  985. }
  986. kEngine->setPluginPeaks(fPlugin->getId(), inPeaks, outPeaks);
  987. }
  988. else
  989. {
  990. fPlugin->process(nullptr, nullptr, nullptr, nullptr, bufferSize);
  991. }
  992. midi.clear();
  993. if (CarlaEngineEventPort* const port = fPlugin->getDefaultEventOutPort())
  994. {
  995. /*const*/ EngineEvent* const engineEvents(port->fBuffer);
  996. CARLA_SAFE_ASSERT_RETURN(engineEvents != nullptr,);
  997. fillJuceMidiBufferFromEngineEvents(midi, engineEvents);
  998. carla_zeroStruct<EngineEvent>(engineEvents, kMaxEngineEventInternalCount);
  999. }
  1000. fPlugin->unlock();
  1001. }
  1002. const String getInputChannelName(int i) const override
  1003. {
  1004. CARLA_SAFE_ASSERT_RETURN(i >= 0, String());
  1005. CarlaEngineClient* const client(fPlugin->getEngineClient());
  1006. return client->getAudioPortName(true, static_cast<uint>(i));
  1007. }
  1008. const String getOutputChannelName(int i) const override
  1009. {
  1010. CARLA_SAFE_ASSERT_RETURN(i >= 0, String());
  1011. CarlaEngineClient* const client(fPlugin->getEngineClient());
  1012. return client->getAudioPortName(false, static_cast<uint>(i));
  1013. }
  1014. void prepareToPlay(double, int) override {}
  1015. void releaseResources() override {}
  1016. const String getParameterName(int) override { return String(); }
  1017. String getParameterName(int, int) override { return String(); }
  1018. const String getParameterText(int) override { return String(); }
  1019. String getParameterText(int, int) override { return String(); }
  1020. const String getProgramName(int) override { return String(); }
  1021. double getTailLengthSeconds() const override { return 0.0; }
  1022. float getParameter(int) override { return 0.0f; }
  1023. bool isInputChannelStereoPair(int) const override { return false; }
  1024. bool isOutputChannelStereoPair(int) const override { return false; }
  1025. bool silenceInProducesSilenceOut() const override { return true; }
  1026. bool acceptsMidi() const override { return fPlugin->getDefaultEventInPort() != nullptr; }
  1027. bool producesMidi() const override { return fPlugin->getDefaultEventOutPort() != nullptr; }
  1028. void setParameter(int, float) override {}
  1029. void setCurrentProgram(int) override {}
  1030. void changeProgramName(int, const String&) override {}
  1031. void getStateInformation(MemoryBlock&) override {}
  1032. void setStateInformation(const void*, int) override {}
  1033. int getNumParameters() override { return 0; }
  1034. int getNumPrograms() override { return 0; }
  1035. int getCurrentProgram() override { return 0; }
  1036. #ifndef JUCE_AUDIO_PROCESSOR_NO_GUI
  1037. bool hasEditor() const override { return false; }
  1038. AudioProcessorEditor* createEditor() override { return nullptr; }
  1039. #endif
  1040. // -------------------------------------------------------------------
  1041. private:
  1042. CarlaEngine* const kEngine;
  1043. CarlaPlugin* fPlugin;
  1044. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginInstance)
  1045. };
  1046. // -----------------------------------------------------------------------
  1047. // Patchbay Graph
  1048. PatchbayGraph::PatchbayGraph(CarlaEngine* const engine, const uint32_t ins, const uint32_t outs)
  1049. : connections(),
  1050. graph(),
  1051. audioBuffer(),
  1052. midiBuffer(),
  1053. inputs(carla_fixValue(0U, MAX_PATCHBAY_PLUGINS-2, ins)),
  1054. outputs(carla_fixValue(0U, MAX_PATCHBAY_PLUGINS-2, outs)),
  1055. ignorePathbay(false),
  1056. retCon(),
  1057. audioPorts(),
  1058. midiPorts(),
  1059. kEngine(engine)
  1060. {
  1061. const int bufferSize(static_cast<int>(engine->getBufferSize()));
  1062. const double sampleRate(engine->getSampleRate());
  1063. graph.setPlayConfigDetails(static_cast<int>(inputs), static_cast<int>(outputs), sampleRate, bufferSize);
  1064. graph.prepareToPlay(sampleRate, bufferSize);
  1065. audioBuffer.setSize(static_cast<int>(jmax(inputs, outputs)), bufferSize);
  1066. midiBuffer.ensureSize(kMaxEngineEventInternalCount*2);
  1067. midiBuffer.clear();
  1068. {
  1069. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode));
  1070. AudioProcessorGraph::Node* const node(graph.addNode(proc));
  1071. node->properties.set("isPlugin", false);
  1072. node->properties.set("isOutput", false);
  1073. node->properties.set("isAudio", true);
  1074. node->properties.set("isCV", false);
  1075. node->properties.set("isMIDI", false);
  1076. node->properties.set("isOSC", false);
  1077. }
  1078. {
  1079. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode));
  1080. AudioProcessorGraph::Node* const node(graph.addNode(proc));
  1081. node->properties.set("isPlugin", false);
  1082. node->properties.set("isOutput", false);
  1083. node->properties.set("isAudio", true);
  1084. node->properties.set("isCV", false);
  1085. node->properties.set("isMIDI", false);
  1086. node->properties.set("isOSC", false);
  1087. }
  1088. {
  1089. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode));
  1090. AudioProcessorGraph::Node* const node(graph.addNode(proc));
  1091. node->properties.set("isPlugin", false);
  1092. node->properties.set("isOutput", false);
  1093. node->properties.set("isAudio", false);
  1094. node->properties.set("isCV", false);
  1095. node->properties.set("isMIDI", true);
  1096. node->properties.set("isOSC", false);
  1097. }
  1098. {
  1099. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode));
  1100. AudioProcessorGraph::Node* const node(graph.addNode(proc));
  1101. node->properties.set("isPlugin", false);
  1102. node->properties.set("isOutput", true);
  1103. node->properties.set("isAudio", false);
  1104. node->properties.set("isCV", false);
  1105. node->properties.set("isMIDI", true);
  1106. node->properties.set("isOSC", false);
  1107. }
  1108. }
  1109. PatchbayGraph::~PatchbayGraph()
  1110. {
  1111. clearConnections();
  1112. clearPorts();
  1113. graph.releaseResources();
  1114. graph.clear();
  1115. audioBuffer.clear();
  1116. }
  1117. void PatchbayGraph::setBufferSize(const int bufferSize)
  1118. {
  1119. graph.releaseResources();
  1120. graph.prepareToPlay(kEngine->getSampleRate(), bufferSize);
  1121. audioBuffer.setSize(audioBuffer.getNumChannels(), bufferSize);
  1122. }
  1123. void PatchbayGraph::setSampleRate(const double sampleRate)
  1124. {
  1125. graph.releaseResources();
  1126. graph.prepareToPlay(sampleRate, static_cast<int>(kEngine->getBufferSize()));
  1127. }
  1128. void PatchbayGraph::setOffline(const bool offline)
  1129. {
  1130. graph.setNonRealtime(offline);
  1131. }
  1132. void PatchbayGraph::addPlugin(CarlaPlugin* const plugin)
  1133. {
  1134. CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
  1135. carla_debug("PatchbayGraph::addPlugin(%p)", plugin);
  1136. CarlaPluginInstance* const instance(new CarlaPluginInstance(kEngine, plugin));
  1137. AudioProcessorGraph::Node* const node(graph.addNode(instance));
  1138. CARLA_SAFE_ASSERT_RETURN(node != nullptr,);
  1139. plugin->setPatchbayNodeId(node->nodeId);
  1140. node->properties.set("isPlugin", true);
  1141. node->properties.set("pluginId", static_cast<int>(plugin->getId()));
  1142. if (! ignorePathbay)
  1143. addNodeToPatchbay(plugin->getEngine(), node->nodeId, static_cast<int>(plugin->getId()), instance);
  1144. }
  1145. void PatchbayGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin)
  1146. {
  1147. CARLA_SAFE_ASSERT_RETURN(oldPlugin != nullptr,);
  1148. CARLA_SAFE_ASSERT_RETURN(newPlugin != nullptr,);
  1149. CARLA_SAFE_ASSERT_RETURN(oldPlugin != newPlugin,);
  1150. CARLA_SAFE_ASSERT_RETURN(oldPlugin->getId() == newPlugin->getId(),);
  1151. AudioProcessorGraph::Node* const oldNode(graph.getNodeForId(oldPlugin->getPatchbayNodeId()));
  1152. CARLA_SAFE_ASSERT_RETURN(oldNode != nullptr,);
  1153. if (! ignorePathbay)
  1154. {
  1155. disconnectGroup(oldNode->nodeId);
  1156. removeNodeFromPatchbay(kEngine, oldNode->nodeId, oldNode->getProcessor());
  1157. }
  1158. ((CarlaPluginInstance*)oldNode->getProcessor())->invalidatePlugin();
  1159. graph.removeNode(oldNode->nodeId);
  1160. CarlaPluginInstance* const instance(new CarlaPluginInstance(kEngine, newPlugin));
  1161. AudioProcessorGraph::Node* const node(graph.addNode(instance));
  1162. CARLA_SAFE_ASSERT_RETURN(node != nullptr,);
  1163. newPlugin->setPatchbayNodeId(node->nodeId);
  1164. node->properties.set("isPlugin", true);
  1165. node->properties.set("pluginId", static_cast<int>(newPlugin->getId()));
  1166. if (! ignorePathbay)
  1167. addNodeToPatchbay(newPlugin->getEngine(), node->nodeId, static_cast<int>(newPlugin->getId()), instance);
  1168. }
  1169. void PatchbayGraph::removePlugin(CarlaPlugin* const plugin)
  1170. {
  1171. CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
  1172. carla_debug("PatchbayGraph::removePlugin(%p)", plugin);
  1173. AudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId()));
  1174. CARLA_SAFE_ASSERT_RETURN(node != nullptr,);
  1175. if (! ignorePathbay)
  1176. {
  1177. disconnectGroup(node->nodeId);
  1178. removeNodeFromPatchbay(kEngine, node->nodeId, node->getProcessor());
  1179. }
  1180. ((CarlaPluginInstance*)node->getProcessor())->invalidatePlugin();
  1181. // Fix plugin Ids properties
  1182. for (uint i=plugin->getId()+1, count=kEngine->getCurrentPluginCount(); i<count; ++i)
  1183. {
  1184. CarlaPlugin* const plugin2(kEngine->getPlugin(i));
  1185. CARLA_SAFE_ASSERT_BREAK(plugin2 != nullptr);
  1186. if (AudioProcessorGraph::Node* const node2 = graph.getNodeForId(plugin2->getPatchbayNodeId()))
  1187. {
  1188. CARLA_SAFE_ASSERT_CONTINUE(node2->properties.getWithDefault("pluginId", -1) != juce::var(-1));
  1189. node2->properties.set("pluginId", static_cast<int>(i-1));
  1190. }
  1191. }
  1192. CARLA_SAFE_ASSERT_RETURN(graph.removeNode(node->nodeId),);
  1193. }
  1194. void PatchbayGraph::removeAllPlugins()
  1195. {
  1196. carla_debug("PatchbayGraph::removeAllPlugins()");
  1197. for (uint i=0, count=kEngine->getCurrentPluginCount(); i<count; ++i)
  1198. {
  1199. CarlaPlugin* const plugin(kEngine->getPlugin(i));
  1200. CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr);
  1201. AudioProcessorGraph::Node* const node(graph.getNodeForId(plugin->getPatchbayNodeId()));
  1202. CARLA_SAFE_ASSERT_CONTINUE(node != nullptr);
  1203. if (! ignorePathbay)
  1204. {
  1205. disconnectGroup(node->nodeId);
  1206. removeNodeFromPatchbay(kEngine, node->nodeId, node->getProcessor());
  1207. }
  1208. ((CarlaPluginInstance*)node->getProcessor())->invalidatePlugin();
  1209. graph.removeNode(node->nodeId);
  1210. }
  1211. }
  1212. bool PatchbayGraph::connect(const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept
  1213. {
  1214. uint adjustedPortA = portA;
  1215. uint adjustedPortB = portB;
  1216. if (! adjustPatchbayPortIdForJuce(adjustedPortA))
  1217. return false;
  1218. if (! adjustPatchbayPortIdForJuce(adjustedPortB))
  1219. return false;
  1220. if (! graph.addConnection(groupA, static_cast<int>(adjustedPortA), groupB, static_cast<int>(adjustedPortB)))
  1221. {
  1222. kEngine->setLastError("Failed from juce");
  1223. return false;
  1224. }
  1225. ConnectionToId connectionToId;
  1226. connectionToId.setData(++connections.lastId, groupA, portA, groupB, portB);
  1227. char strBuf[STR_MAX+1];
  1228. strBuf[STR_MAX] = '\0';
  1229. std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB);
  1230. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  1231. connections.list.append(connectionToId);
  1232. return true;
  1233. }
  1234. bool PatchbayGraph::disconnect(const uint connectionId) noexcept
  1235. {
  1236. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  1237. {
  1238. static const ConnectionToId fallback = { 0, 0, 0, 0, 0 };
  1239. const ConnectionToId& connectionToId(it.getValue(fallback));
  1240. CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
  1241. if (connectionToId.id != connectionId)
  1242. continue;
  1243. uint adjustedPortA = connectionToId.portA;
  1244. uint adjustedPortB = connectionToId.portB;
  1245. if (! adjustPatchbayPortIdForJuce(adjustedPortA))
  1246. return false;
  1247. if (! adjustPatchbayPortIdForJuce(adjustedPortB))
  1248. return false;
  1249. if (! graph.removeConnection(connectionToId.groupA, static_cast<int>(adjustedPortA),
  1250. connectionToId.groupB, static_cast<int>(adjustedPortB)))
  1251. return false;
  1252. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connectionToId.id, 0, 0, 0.0f, nullptr);
  1253. connections.list.remove(it);
  1254. return true;
  1255. }
  1256. kEngine->setLastError("Failed to find connection");
  1257. return false;
  1258. }
  1259. void PatchbayGraph::disconnectGroup(const uint groupId) noexcept
  1260. {
  1261. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  1262. {
  1263. static const ConnectionToId fallback = { 0, 0, 0, 0, 0 };
  1264. const ConnectionToId& connectionToId(it.getValue(fallback));
  1265. CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
  1266. if (connectionToId.groupA != groupId && connectionToId.groupB != groupId)
  1267. continue;
  1268. /*
  1269. uint adjustedPortA = connectionToId.portA;
  1270. uint adjustedPortB = connectionToId.portB;
  1271. if (! adjustPatchbayPortIdForJuce(adjustedPortA))
  1272. return false;
  1273. if (! adjustPatchbayPortIdForJuce(adjustedPortB))
  1274. return false;
  1275. graph.removeConnection(connectionToId.groupA, static_cast<int>(adjustedPortA),
  1276. connectionToId.groupB, static_cast<int>(adjustedPortB));
  1277. */
  1278. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connectionToId.id, 0, 0, 0.0f, nullptr);
  1279. connections.list.remove(it);
  1280. }
  1281. }
  1282. void PatchbayGraph::clearPorts() noexcept
  1283. {
  1284. audioPorts.ins.clear();
  1285. audioPorts.outs.clear();
  1286. midiPorts.ins.clear();
  1287. midiPorts.outs.clear();
  1288. }
  1289. void PatchbayGraph::clearConnections()
  1290. {
  1291. connections.clear();
  1292. for (int i=0, count=graph.getNumConnections(); i<count; ++i)
  1293. graph.removeConnection(0);
  1294. }
  1295. void PatchbayGraph::refresh(const char* const deviceName)
  1296. {
  1297. CARLA_SAFE_ASSERT_RETURN(deviceName != nullptr,);
  1298. connections.clear();
  1299. graph.removeIllegalConnections();
  1300. if (! ignorePathbay)
  1301. {
  1302. for (int i=0, count=graph.getNumNodes(); i<count; ++i)
  1303. {
  1304. AudioProcessorGraph::Node* const node(graph.getNode(i));
  1305. CARLA_SAFE_ASSERT_CONTINUE(node != nullptr);
  1306. AudioProcessor* const proc(node->getProcessor());
  1307. CARLA_SAFE_ASSERT_CONTINUE(proc != nullptr);
  1308. int clientId = -1;
  1309. // plugin node
  1310. if (node->properties.getWithDefault("isPlugin", false) == juce::var(true))
  1311. {
  1312. clientId = node->properties.getWithDefault("pluginId", -1);
  1313. }
  1314. #if 0
  1315. // hardware node
  1316. else
  1317. {
  1318. // skip hardware midi nodes
  1319. if (node->properties.getWithDefault("isMIDI", false) == juce::var(true))
  1320. continue;
  1321. }
  1322. #endif
  1323. addNodeToPatchbay(kEngine, node->nodeId, clientId, proc);
  1324. }
  1325. }
  1326. #if 0
  1327. // MIDI In
  1328. {
  1329. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");
  1330. const CarlaString groupNamePlus("Readable MIDI ports:");
  1331. int h = 0;
  1332. for (LinkedList<PortNameToId>::Itenerator it = midiPorts.ins.begin(); it.valid(); it.next())
  1333. {
  1334. PortNameToId& portNameToId(it.getValue());
  1335. portNameToId.setFullName(groupNamePlus + portNameToId.name);
  1336. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, ++h,
  1337. PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
  1338. }
  1339. }
  1340. // MIDI Out
  1341. {
  1342. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");
  1343. const CarlaString groupNamePlus("Writable MIDI ports:");
  1344. int h = 0;
  1345. for (LinkedList<PortNameToId>::Itenerator it = midiPorts.outs.begin(); it.valid(); it.next())
  1346. {
  1347. PortNameToId& portNameToId(it.getValue());
  1348. portNameToId.setFullName(groupNamePlus + portNameToId.name);
  1349. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, ++h,
  1350. PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
  1351. }
  1352. }
  1353. #endif
  1354. char strBuf[STR_MAX+1];
  1355. for (int i=0, count=graph.getNumConnections(); i<count; ++i)
  1356. {
  1357. const AudioProcessorGraph::Connection* const conn(graph.getConnection(i));
  1358. CARLA_SAFE_ASSERT_CONTINUE(conn != nullptr);
  1359. CARLA_SAFE_ASSERT_CONTINUE(conn->sourceChannelIndex >= 0);
  1360. CARLA_SAFE_ASSERT_CONTINUE(conn->destChannelIndex >= 0);
  1361. const uint groupA = conn->sourceNodeId;
  1362. const uint groupB = conn->destNodeId;
  1363. uint portA = static_cast<uint>(conn->sourceChannelIndex);
  1364. uint portB = static_cast<uint>(conn->destChannelIndex);
  1365. if (portA == kMidiChannelIndex)
  1366. portA = kMidiOutputPortOffset;
  1367. else
  1368. portA += kAudioOutputPortOffset;
  1369. if (portB == kMidiChannelIndex)
  1370. portB = kMidiInputPortOffset;
  1371. else
  1372. portB += kAudioInputPortOffset;
  1373. ConnectionToId connectionToId;
  1374. connectionToId.setData(++connections.lastId, groupA, portA, groupB, portB);
  1375. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", groupA, portA, groupB, portB);
  1376. strBuf[STR_MAX] = '\0';
  1377. kEngine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  1378. connections.list.append(connectionToId);
  1379. }
  1380. }
  1381. const char* const* PatchbayGraph::getConnections(const bool external) const
  1382. {
  1383. if (connections.list.count() == 0 || external)
  1384. return nullptr;
  1385. CarlaStringList connList;
  1386. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  1387. {
  1388. static const ConnectionToId fallback = { 0, 0, 0, 0, 0 };
  1389. const ConnectionToId& connectionToId(it.getValue(fallback));
  1390. CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
  1391. AudioProcessorGraph::Node* const nodeA(graph.getNodeForId(connectionToId.groupA));
  1392. CARLA_SAFE_ASSERT_CONTINUE(nodeA != nullptr);
  1393. AudioProcessorGraph::Node* const nodeB(graph.getNodeForId(connectionToId.groupB));
  1394. CARLA_SAFE_ASSERT_CONTINUE(nodeB != nullptr);
  1395. AudioProcessor* const procA(nodeA->getProcessor());
  1396. CARLA_SAFE_ASSERT_CONTINUE(procA != nullptr);
  1397. AudioProcessor* const procB(nodeB->getProcessor());
  1398. CARLA_SAFE_ASSERT_CONTINUE(procB != nullptr);
  1399. String fullPortNameA(getProcessorFullPortName(procA, connectionToId.portA));
  1400. CARLA_SAFE_ASSERT_CONTINUE(fullPortNameA.isNotEmpty());
  1401. String fullPortNameB(getProcessorFullPortName(procB, connectionToId.portB));
  1402. CARLA_SAFE_ASSERT_CONTINUE(fullPortNameB.isNotEmpty());
  1403. connList.append(fullPortNameA.toRawUTF8());
  1404. connList.append(fullPortNameB.toRawUTF8());
  1405. }
  1406. if (connList.count() == 0)
  1407. return nullptr;
  1408. retCon = connList.toCharStringListPtr();
  1409. return retCon;
  1410. }
  1411. bool PatchbayGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const
  1412. {
  1413. String groupName(String(fullPortName).upToFirstOccurrenceOf(":", false, false));
  1414. String portName(String(fullPortName).fromFirstOccurrenceOf(":", false, false));
  1415. for (int i=0, count=graph.getNumNodes(); i<count; ++i)
  1416. {
  1417. AudioProcessorGraph::Node* const node(graph.getNode(i));
  1418. CARLA_SAFE_ASSERT_CONTINUE(node != nullptr);
  1419. AudioProcessor* const proc(node->getProcessor());
  1420. CARLA_SAFE_ASSERT_CONTINUE(proc != nullptr);
  1421. if (proc->getName() != groupName)
  1422. continue;
  1423. groupId = node->nodeId;
  1424. if (portName == "events-in")
  1425. {
  1426. portId = kMidiInputPortOffset;
  1427. return true;
  1428. }
  1429. if (portName == "events-out")
  1430. {
  1431. portId = kMidiOutputPortOffset;
  1432. return true;
  1433. }
  1434. for (int j=0, numInputs=proc->getNumInputChannels(); j<numInputs; ++j)
  1435. {
  1436. if (proc->getInputChannelName(j) != portName)
  1437. continue;
  1438. portId = kAudioInputPortOffset+static_cast<uint>(j);
  1439. return true;
  1440. }
  1441. for (int j=0, numOutputs=proc->getNumOutputChannels(); j<numOutputs; ++j)
  1442. {
  1443. if (proc->getOutputChannelName(j) != portName)
  1444. continue;
  1445. portId = kAudioOutputPortOffset+static_cast<uint>(j);
  1446. return true;
  1447. }
  1448. }
  1449. return false;
  1450. }
  1451. void PatchbayGraph::process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const int frames)
  1452. {
  1453. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  1454. CARLA_SAFE_ASSERT_RETURN(data->events.in != nullptr,);
  1455. CARLA_SAFE_ASSERT_RETURN(data->events.out != nullptr,);
  1456. CARLA_SAFE_ASSERT_RETURN(frames > 0,);
  1457. // put events in juce buffer
  1458. {
  1459. midiBuffer.clear();
  1460. fillJuceMidiBufferFromEngineEvents(midiBuffer, data->events.in);
  1461. }
  1462. // put carla audio in juce buffer
  1463. {
  1464. int i=0;
  1465. for (; i < static_cast<int>(inputs); ++i)
  1466. FloatVectorOperations::copy(audioBuffer.getWritePointer(i), inBuf[i], frames);
  1467. // clear remaining channels
  1468. for (const int count=audioBuffer.getNumChannels(); i<count; ++i)
  1469. audioBuffer.clear(i, 0, frames);
  1470. }
  1471. graph.processBlock(audioBuffer, midiBuffer);
  1472. // put juce audio in carla buffer
  1473. {
  1474. for (int i=0; i < static_cast<int>(outputs); ++i)
  1475. FloatVectorOperations::copy(outBuf[i], audioBuffer.getReadPointer(i), frames);
  1476. }
  1477. // put juce events in carla buffer
  1478. {
  1479. carla_zeroStruct<EngineEvent>(data->events.out, kMaxEngineEventInternalCount);
  1480. fillEngineEventsFromJuceMidiBuffer(data->events.out, midiBuffer);
  1481. midiBuffer.clear();
  1482. }
  1483. }
  1484. // -----------------------------------------------------------------------
  1485. // InternalGraph
  1486. EngineInternalGraph::EngineInternalGraph(CarlaEngine* const engine) noexcept
  1487. : fIsRack(true),
  1488. fIsReady(false),
  1489. kEngine(engine)
  1490. {
  1491. fRack = nullptr;
  1492. }
  1493. EngineInternalGraph::~EngineInternalGraph() noexcept
  1494. {
  1495. CARLA_SAFE_ASSERT(! fIsReady);
  1496. CARLA_SAFE_ASSERT(fRack == nullptr);
  1497. }
  1498. void EngineInternalGraph::create(const uint32_t inputs, const uint32_t outputs)
  1499. {
  1500. fIsRack = (kEngine->getOptions().processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK);
  1501. if (fIsRack)
  1502. {
  1503. CARLA_SAFE_ASSERT_RETURN(fRack == nullptr,);
  1504. fRack = new RackGraph(kEngine, inputs, outputs);
  1505. }
  1506. else
  1507. {
  1508. CARLA_SAFE_ASSERT_RETURN(fPatchbay == nullptr,);
  1509. fPatchbay = new PatchbayGraph(kEngine, inputs, outputs);
  1510. }
  1511. fIsReady = true;
  1512. }
  1513. void EngineInternalGraph::destroy() noexcept
  1514. {
  1515. if (! fIsReady)
  1516. {
  1517. CARLA_SAFE_ASSERT(fRack == nullptr);
  1518. return;
  1519. }
  1520. if (fIsRack)
  1521. {
  1522. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  1523. delete fRack;
  1524. fRack = nullptr;
  1525. }
  1526. else
  1527. {
  1528. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1529. delete fPatchbay;
  1530. fPatchbay = nullptr;
  1531. }
  1532. fIsReady = false;
  1533. }
  1534. void EngineInternalGraph::setBufferSize(const uint32_t bufferSize)
  1535. {
  1536. ScopedValueSetter<bool> svs(fIsReady, false, true);
  1537. if (fIsRack)
  1538. {
  1539. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  1540. fRack->setBufferSize(bufferSize);
  1541. }
  1542. else
  1543. {
  1544. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1545. fPatchbay->setBufferSize(static_cast<int>(bufferSize));
  1546. }
  1547. }
  1548. void EngineInternalGraph::setSampleRate(const double sampleRate)
  1549. {
  1550. ScopedValueSetter<bool> svs(fIsReady, false, true);
  1551. if (fIsRack)
  1552. {
  1553. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  1554. }
  1555. else
  1556. {
  1557. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1558. fPatchbay->setSampleRate(sampleRate);
  1559. }
  1560. }
  1561. void EngineInternalGraph::setOffline(const bool offline)
  1562. {
  1563. ScopedValueSetter<bool> svs(fIsReady, false, true);
  1564. if (fIsRack)
  1565. {
  1566. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  1567. fRack->setOffline(offline);
  1568. }
  1569. else
  1570. {
  1571. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1572. fPatchbay->setOffline(offline);
  1573. }
  1574. }
  1575. bool EngineInternalGraph::isReady() const noexcept
  1576. {
  1577. return fIsReady;
  1578. }
  1579. RackGraph* EngineInternalGraph::getRackGraph() const noexcept
  1580. {
  1581. CARLA_SAFE_ASSERT_RETURN(fIsRack, nullptr);
  1582. return fRack;
  1583. }
  1584. PatchbayGraph* EngineInternalGraph::getPatchbayGraph() const noexcept
  1585. {
  1586. CARLA_SAFE_ASSERT_RETURN(! fIsRack, nullptr);
  1587. return fPatchbay;
  1588. }
  1589. void EngineInternalGraph::process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames)
  1590. {
  1591. if (fIsRack)
  1592. {
  1593. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  1594. fRack->processHelper(data, inBuf, outBuf, frames);
  1595. }
  1596. else
  1597. {
  1598. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1599. fPatchbay->process(data, inBuf, outBuf, static_cast<int>(frames));
  1600. }
  1601. }
  1602. void EngineInternalGraph::processRack(CarlaEngine::ProtectedData* const data, const float* inBuf[2], float* outBuf[2], const uint32_t frames)
  1603. {
  1604. CARLA_SAFE_ASSERT_RETURN(fIsRack,);
  1605. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  1606. fRack->process(data, inBuf, outBuf, frames);
  1607. }
  1608. // -----------------------------------------------------------------------
  1609. // used for internal patchbay mode
  1610. void EngineInternalGraph::addPlugin(CarlaPlugin* const plugin)
  1611. {
  1612. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1613. fPatchbay->addPlugin(plugin);
  1614. }
  1615. void EngineInternalGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin)
  1616. {
  1617. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1618. fPatchbay->replacePlugin(oldPlugin, newPlugin);
  1619. }
  1620. void EngineInternalGraph::removePlugin(CarlaPlugin* const plugin)
  1621. {
  1622. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1623. fPatchbay->removePlugin(plugin);
  1624. }
  1625. void EngineInternalGraph::removeAllPlugins()
  1626. {
  1627. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1628. fPatchbay->removeAllPlugins();
  1629. }
  1630. void EngineInternalGraph::setIgnorePatchbay(const bool ignore) noexcept
  1631. {
  1632. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  1633. fPatchbay->ignorePathbay = ignore;
  1634. }
  1635. // -----------------------------------------------------------------------
  1636. // CarlaEngine Patchbay stuff
  1637. bool CarlaEngine::patchbayConnect(const uint groupA, const uint portA, const uint groupB, const uint portB)
  1638. {
  1639. CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
  1640. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);
  1641. carla_debug("CarlaEngine::patchbayConnect(%u, %u, %u, %u)", groupA, portA, groupB, portB);
  1642. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1643. {
  1644. if (RackGraph* const graph = pData->graph.getRackGraph())
  1645. return graph->connect(groupA, portA, groupB, portB);
  1646. }
  1647. else
  1648. {
  1649. if (PatchbayGraph* const graph = pData->graph.getPatchbayGraph())
  1650. return graph->connect(groupA, portA, groupB, portB);
  1651. }
  1652. return false;
  1653. }
  1654. bool CarlaEngine::patchbayDisconnect(const uint connectionId)
  1655. {
  1656. CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
  1657. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);
  1658. carla_debug("CarlaEngine::patchbayDisconnect(%u)", connectionId);
  1659. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1660. {
  1661. if (RackGraph* const graph = pData->graph.getRackGraph())
  1662. return graph->disconnect(connectionId);
  1663. }
  1664. else
  1665. {
  1666. if (PatchbayGraph* const graph = pData->graph.getPatchbayGraph())
  1667. return graph->disconnect(connectionId);
  1668. }
  1669. return false;
  1670. }
  1671. bool CarlaEngine::patchbayRefresh(const bool external)
  1672. {
  1673. // subclasses should handle this
  1674. CARLA_SAFE_ASSERT_RETURN(! external, false);
  1675. // FIXME
  1676. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1677. {
  1678. // This is implemented in engine subclasses for MIDI support
  1679. setLastError("Unsupported operation");
  1680. return false;
  1681. }
  1682. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1683. {
  1684. if (RackGraph* const graph = pData->graph.getRackGraph())
  1685. graph->refresh("");
  1686. }
  1687. else
  1688. {
  1689. if (PatchbayGraph* const graph = pData->graph.getPatchbayGraph())
  1690. {
  1691. graph->refresh("");
  1692. }
  1693. }
  1694. return true;
  1695. }
  1696. // -----------------------------------------------------------------------
  1697. const char* const* CarlaEngine::getPatchbayConnections(const bool external) const
  1698. {
  1699. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), nullptr);
  1700. carla_debug("CarlaEngine::getPatchbayConnections(%s)", bool2str(external));
  1701. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1702. {
  1703. RackGraph* const graph = pData->graph.getRackGraph();
  1704. CARLA_SAFE_ASSERT_RETURN(graph != nullptr, nullptr);
  1705. CARLA_SAFE_ASSERT_RETURN(external, nullptr);
  1706. return graph->getConnections();
  1707. }
  1708. else
  1709. {
  1710. PatchbayGraph* const graph = pData->graph.getPatchbayGraph();
  1711. CARLA_SAFE_ASSERT_RETURN(graph != nullptr, nullptr);
  1712. return graph->getConnections(external);
  1713. }
  1714. return nullptr;
  1715. }
  1716. void CarlaEngine::restorePatchbayConnection(const bool external, const char* const sourcePort, const char* const targetPort)
  1717. {
  1718. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(),);
  1719. CARLA_SAFE_ASSERT_RETURN(sourcePort != nullptr && sourcePort[0] != '\0',);
  1720. CARLA_SAFE_ASSERT_RETURN(targetPort != nullptr && targetPort[0] != '\0',);
  1721. carla_debug("CarlaEngine::restorePatchbayConnection(%s, \"%s\", \"%s\")", bool2str(external), sourcePort, targetPort);
  1722. uint groupA, portA;
  1723. uint groupB, portB;
  1724. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1725. {
  1726. RackGraph* const graph = pData->graph.getRackGraph();
  1727. CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);
  1728. CARLA_SAFE_ASSERT_RETURN(external,);
  1729. if (! graph->getGroupAndPortIdFromFullName(sourcePort, groupA, portA))
  1730. return;
  1731. if (! graph->getGroupAndPortIdFromFullName(targetPort, groupB, portB))
  1732. return;
  1733. }
  1734. else
  1735. {
  1736. PatchbayGraph* const graph = pData->graph.getPatchbayGraph();
  1737. CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);
  1738. // TODO external
  1739. if (! graph->getGroupAndPortIdFromFullName(sourcePort, groupA, portA))
  1740. return;
  1741. if (! graph->getGroupAndPortIdFromFullName(targetPort, groupB, portB))
  1742. return;
  1743. }
  1744. patchbayConnect(groupA, portA, groupB, portB);
  1745. }
  1746. // -----------------------------------------------------------------------
  1747. CARLA_BACKEND_END_NAMESPACE
  1748. // -----------------------------------------------------------------------