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.

CarlaEngineGraph.cpp 41KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327
  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. #if 0
  23. using juce::AudioPluginInstance;
  24. using juce::AudioProcessor;
  25. using juce::AudioProcessorEditor;
  26. using juce::PluginDescription;
  27. #endif
  28. using juce::jmax;
  29. using juce::FloatVectorOperations;
  30. using juce::MemoryBlock;
  31. using juce::String;
  32. CARLA_BACKEND_START_NAMESPACE
  33. // -----------------------------------------------------------------------
  34. // Rack Graph stuff
  35. static inline
  36. uint getCarlaRackPortIdFromName(const char* const shortname) noexcept
  37. {
  38. if (std::strcmp(shortname, "AudioIn1") == 0 || std::strcmp(shortname, "audio-in1") == 0)
  39. return RACK_GRAPH_CARLA_PORT_AUDIO_IN1;
  40. if (std::strcmp(shortname, "AudioIn2") == 0 || std::strcmp(shortname, "audio-in2") == 0)
  41. return RACK_GRAPH_CARLA_PORT_AUDIO_IN2;
  42. if (std::strcmp(shortname, "AudioOut1") == 0 || std::strcmp(shortname, "audio-out1") == 0)
  43. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT1;
  44. if (std::strcmp(shortname, "AudioOut2") == 0 || std::strcmp(shortname, "audio-out2") == 0)
  45. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT2;
  46. if (std::strcmp(shortname, "MidiIn") == 0 || std::strcmp(shortname, "midi-in") == 0)
  47. return RACK_GRAPH_CARLA_PORT_MIDI_IN;
  48. if (std::strcmp(shortname, "MidiOut") == 0 || std::strcmp(shortname, "midi-out") == 0)
  49. return RACK_GRAPH_CARLA_PORT_MIDI_OUT;
  50. carla_stderr("CarlaBackend::getCarlaRackPortIdFromName(%s) - invalid short name", shortname);
  51. return RACK_GRAPH_CARLA_PORT_NULL;
  52. }
  53. static inline
  54. const char* getCarlaRackFullPortNameFromId(const /*RackGraphCarlaPortIds*/ uint portId)
  55. {
  56. switch (portId)
  57. {
  58. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  59. return "Carla:AudioIn1";
  60. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  61. return "Carla:AudioIn2";
  62. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  63. return "Carla:AudioOut1";
  64. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  65. return "Carla:AudioOut2";
  66. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  67. return "Carla:MidiIn";
  68. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  69. return "Carla:MidiOut";
  70. //case RACK_GRAPH_CARLA_PORT_NULL:
  71. //case RACK_GRAPH_CARLA_PORT_MAX:
  72. // break;
  73. }
  74. carla_stderr("CarlaBackend::getCarlaRackFullPortNameFromId(%i) - invalid port id", portId);
  75. return nullptr;
  76. }
  77. // -----------------------------------------------------------------------
  78. // RackGraph MIDI
  79. const char* RackGraph::MIDI::getName(const bool isInput, const uint portId) const noexcept
  80. {
  81. for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
  82. {
  83. const PortNameToId& port(it.getValue());
  84. if (port.port == portId)
  85. return port.name;
  86. }
  87. return nullptr;
  88. }
  89. uint RackGraph::MIDI::getPortId(const bool isInput, const char portName[], bool* const ok) const noexcept
  90. {
  91. for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
  92. {
  93. const PortNameToId& port(it.getValue());
  94. if (std::strcmp(port.name, portName) == 0)
  95. {
  96. if (ok != nullptr)
  97. *ok = true;
  98. return port.port;
  99. }
  100. }
  101. if (ok != nullptr)
  102. *ok = false;
  103. return 0;
  104. }
  105. // -----------------------------------------------------------------------
  106. // RackGraph
  107. RackGraph::Audio::Audio() noexcept
  108. : mutex(),
  109. connectedIn1(),
  110. connectedIn2(),
  111. connectedOut1(),
  112. connectedOut2(),
  113. inBuf{0, 0},
  114. inBufTmp{0, 0},
  115. outBuf{0, 0} {}
  116. RackGraph::MIDI::MIDI() noexcept
  117. : ins(),
  118. outs() {}
  119. RackGraph::RackGraph(const uint32_t bufferSize, const uint32_t ins, const uint32_t outs) noexcept
  120. : connections(),
  121. inputs(ins),
  122. outputs(outs),
  123. isOffline(false),
  124. retCon(),
  125. audio(),
  126. midi()
  127. {
  128. audio.inBuf[0] = audio.inBuf[1] = nullptr;
  129. audio.inBufTmp[0] = audio.inBufTmp[1] = nullptr;
  130. audio.outBuf[0] = audio.outBuf[1] = nullptr;
  131. setBufferSize(bufferSize);
  132. }
  133. RackGraph::~RackGraph() noexcept
  134. {
  135. clearConnections();
  136. }
  137. void RackGraph::setBufferSize(const uint32_t bufferSize) noexcept
  138. {
  139. const int bufferSizei(static_cast<int>(bufferSize));
  140. if (audio.inBuf[0] != nullptr) { delete[] audio.inBuf[0]; audio.inBuf[0] = nullptr; }
  141. if (audio.inBuf[1] != nullptr) { delete[] audio.inBuf[1]; audio.inBuf[1] = nullptr; }
  142. if (audio.inBufTmp[0] != nullptr) { delete[] audio.inBufTmp[0]; audio.inBufTmp[0] = nullptr; }
  143. if (audio.inBufTmp[1] != nullptr) { delete[] audio.inBufTmp[1]; audio.inBufTmp[1] = nullptr; }
  144. if (audio.outBuf[0] != nullptr) { delete[] audio.outBuf[0]; audio.outBuf[0] = nullptr; }
  145. if (audio.outBuf[1] != nullptr) { delete[] audio.outBuf[1]; audio.outBuf[1] = nullptr; }
  146. try {
  147. audio.inBufTmp[0] = new float[bufferSize];
  148. audio.inBufTmp[1] = new float[bufferSize];
  149. if (inputs > 0 || outputs > 0)
  150. {
  151. audio.inBuf[0] = new float[bufferSize];
  152. audio.inBuf[1] = new float[bufferSize];
  153. audio.outBuf[0] = new float[bufferSize];
  154. audio.outBuf[1] = new float[bufferSize];
  155. }
  156. }
  157. catch(...) {
  158. if (audio.inBufTmp[0] != nullptr) { delete[] audio.inBufTmp[0]; audio.inBufTmp[0] = nullptr; }
  159. if (audio.inBufTmp[1] != nullptr) { delete[] audio.inBufTmp[1]; audio.inBufTmp[1] = nullptr; }
  160. if (inputs > 0 || outputs > 0)
  161. {
  162. if (audio.inBuf[0] != nullptr) { delete[] audio.inBuf[0]; audio.inBuf[0] = nullptr; }
  163. if (audio.inBuf[1] != nullptr) { delete[] audio.inBuf[1]; audio.inBuf[1] = nullptr; }
  164. if (audio.outBuf[0] != nullptr) { delete[] audio.outBuf[0]; audio.outBuf[0] = nullptr; }
  165. if (audio.outBuf[1] != nullptr) { delete[] audio.outBuf[1]; audio.outBuf[1] = nullptr; }
  166. }
  167. return;
  168. }
  169. FloatVectorOperations::clear(audio.inBufTmp[0], bufferSizei);
  170. FloatVectorOperations::clear(audio.inBufTmp[1], bufferSizei);
  171. if (inputs > 0 || outputs > 0)
  172. {
  173. FloatVectorOperations::clear(audio.inBuf[0], bufferSizei);
  174. FloatVectorOperations::clear(audio.inBuf[1], bufferSizei);
  175. FloatVectorOperations::clear(audio.outBuf[0], bufferSizei);
  176. FloatVectorOperations::clear(audio.outBuf[1], bufferSizei);
  177. }
  178. }
  179. void RackGraph::setOffline(const bool offline) noexcept
  180. {
  181. isOffline = offline;
  182. }
  183. bool RackGraph::connect(CarlaEngine* const engine, const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept
  184. {
  185. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  186. uint otherGroup, otherPort, carlaPort;
  187. if (groupA == RACK_GRAPH_GROUP_CARLA)
  188. {
  189. CARLA_SAFE_ASSERT_RETURN(groupB != RACK_GRAPH_GROUP_CARLA, false);
  190. carlaPort = portA;
  191. otherGroup = groupB;
  192. otherPort = portB;
  193. }
  194. else
  195. {
  196. CARLA_SAFE_ASSERT_RETURN(groupB == RACK_GRAPH_GROUP_CARLA, false);
  197. carlaPort = portB;
  198. otherGroup = groupA;
  199. otherPort = portA;
  200. }
  201. CARLA_SAFE_ASSERT_RETURN(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX, false);
  202. CARLA_SAFE_ASSERT_RETURN(otherGroup > RACK_GRAPH_GROUP_CARLA && otherGroup < RACK_GRAPH_GROUP_MAX, false);
  203. bool makeConnection = false;
  204. switch (carlaPort)
  205. {
  206. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  207. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_IN, false);
  208. audio.mutex.lock();
  209. makeConnection = audio.connectedIn1.append(otherPort);
  210. audio.mutex.unlock();
  211. break;
  212. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  213. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_IN, false);
  214. audio.mutex.lock();
  215. makeConnection = audio.connectedIn2.append(otherPort);
  216. audio.mutex.unlock();
  217. break;
  218. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  219. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_OUT, false);
  220. audio.mutex.lock();
  221. makeConnection = audio.connectedOut1.append(otherPort);
  222. audio.mutex.unlock();
  223. break;
  224. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  225. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_AUDIO_OUT, false);
  226. audio.mutex.lock();
  227. makeConnection = audio.connectedOut2.append(otherPort);
  228. audio.mutex.unlock();
  229. break;
  230. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  231. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_MIDI_IN, false);
  232. if (const char* const portName = midi.getName(true, otherPort))
  233. makeConnection = engine->connectRackMidiInPort(portName);
  234. break;
  235. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  236. CARLA_SAFE_ASSERT_RETURN(otherGroup == RACK_GRAPH_GROUP_MIDI_OUT, false);
  237. if (const char* const portName = midi.getName(false, otherPort))
  238. makeConnection = engine->connectRackMidiOutPort(portName);
  239. break;
  240. }
  241. if (! makeConnection)
  242. {
  243. engine->setLastError("Invalid rack connection");
  244. return false;
  245. }
  246. ConnectionToId connectionToId;
  247. connectionToId.setData(++connections.lastId, groupA, portA, groupB, portB);
  248. char strBuf[STR_MAX+1];
  249. strBuf[STR_MAX] = '\0';
  250. std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB);
  251. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  252. connections.list.append(connectionToId);
  253. return true;
  254. }
  255. bool RackGraph::disconnect(CarlaEngine* const engine, const uint connectionId) noexcept
  256. {
  257. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  258. CARLA_SAFE_ASSERT_RETURN(connections.list.count() > 0, false);
  259. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  260. {
  261. const ConnectionToId& connection(it.getValue());
  262. if (connection.id != connectionId)
  263. continue;
  264. uint otherGroup, otherPort, carlaPort;
  265. if (connection.groupA == RACK_GRAPH_GROUP_CARLA)
  266. {
  267. CARLA_SAFE_ASSERT_RETURN(connection.groupB != RACK_GRAPH_GROUP_CARLA, false);
  268. carlaPort = connection.portA;
  269. otherGroup = connection.groupB;
  270. otherPort = connection.portB;
  271. }
  272. else
  273. {
  274. CARLA_SAFE_ASSERT_RETURN(connection.groupB == RACK_GRAPH_GROUP_CARLA, false);
  275. carlaPort = connection.portB;
  276. otherGroup = connection.groupA;
  277. otherPort = connection.portA;
  278. }
  279. CARLA_SAFE_ASSERT_RETURN(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX, false);
  280. CARLA_SAFE_ASSERT_RETURN(otherGroup > RACK_GRAPH_GROUP_CARLA && otherGroup < RACK_GRAPH_GROUP_MAX, false);
  281. bool makeDisconnection = false;
  282. switch (carlaPort)
  283. {
  284. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  285. audio.mutex.lock();
  286. makeDisconnection = audio.connectedIn1.removeOne(otherPort);
  287. audio.mutex.unlock();
  288. break;
  289. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  290. audio.mutex.lock();
  291. makeDisconnection = audio.connectedIn2.removeOne(otherPort);
  292. audio.mutex.unlock();
  293. break;
  294. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  295. audio.mutex.lock();
  296. makeDisconnection = audio.connectedOut1.removeOne(otherPort);
  297. audio.mutex.unlock();
  298. break;
  299. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  300. audio.mutex.lock();
  301. makeDisconnection = audio.connectedOut2.removeOne(otherPort);
  302. audio.mutex.unlock();
  303. break;
  304. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  305. if (const char* const portName = midi.getName(true, otherPort))
  306. makeDisconnection = engine->disconnectRackMidiInPort(portName);
  307. break;
  308. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  309. if (const char* const portName = midi.getName(false, otherPort))
  310. makeDisconnection = engine->disconnectRackMidiOutPort(portName);
  311. break;
  312. }
  313. if (! makeDisconnection)
  314. {
  315. engine->setLastError("Invalid rack connection");
  316. return false;
  317. }
  318. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connection.id, 0, 0, 0.0f, nullptr);
  319. connections.list.remove(it);
  320. return true;
  321. }
  322. engine->setLastError("Failed to find connection");
  323. return false;
  324. }
  325. void RackGraph::clearConnections() noexcept
  326. {
  327. connections.clear();
  328. audio.mutex.lock();
  329. audio.connectedIn1.clear();
  330. audio.connectedIn2.clear();
  331. audio.connectedOut1.clear();
  332. audio.connectedOut2.clear();
  333. audio.mutex.unlock();
  334. midi.ins.clear();
  335. midi.outs.clear();
  336. }
  337. const char* const* RackGraph::getConnections() const noexcept
  338. {
  339. if (connections.list.count() == 0)
  340. return nullptr;
  341. CarlaStringList connList;
  342. char strBuf[STR_MAX+1];
  343. strBuf[STR_MAX] = '\0';
  344. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  345. {
  346. const ConnectionToId& connection(it.getValue());
  347. uint otherGroup, otherPort, carlaPort;
  348. if (connection.groupA == RACK_GRAPH_GROUP_CARLA)
  349. {
  350. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB != RACK_GRAPH_GROUP_CARLA);
  351. carlaPort = connection.portA;
  352. otherGroup = connection.groupB;
  353. otherPort = connection.portB;
  354. }
  355. else
  356. {
  357. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB == RACK_GRAPH_GROUP_CARLA);
  358. carlaPort = connection.portB;
  359. otherGroup = connection.groupA;
  360. otherPort = connection.portA;
  361. }
  362. CARLA_SAFE_ASSERT_CONTINUE(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX);
  363. CARLA_SAFE_ASSERT_CONTINUE(otherGroup > RACK_GRAPH_GROUP_CARLA && otherGroup < RACK_GRAPH_GROUP_MAX);
  364. switch (carlaPort)
  365. {
  366. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  367. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  368. std::snprintf(strBuf, STR_MAX, "AudioIn:%i", otherPort+1);
  369. connList.append(strBuf);
  370. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  371. break;
  372. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  373. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  374. std::snprintf(strBuf, STR_MAX, "AudioOut:%i", otherPort+1);
  375. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  376. connList.append(strBuf);
  377. break;
  378. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  379. std::snprintf(strBuf, STR_MAX, "MidiIn:%s", midi.getName(true, otherPort));
  380. connList.append(strBuf);
  381. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  382. break;
  383. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  384. std::snprintf(strBuf, STR_MAX, "MidiOut:%s", midi.getName(false, otherPort));
  385. connList.append(getCarlaRackFullPortNameFromId(carlaPort));
  386. connList.append(strBuf);
  387. break;
  388. }
  389. }
  390. if (connList.count() == 0)
  391. return nullptr;
  392. retCon = connList.toCharStringListPtr();
  393. return retCon;
  394. }
  395. bool RackGraph::getGroupAndPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const noexcept
  396. {
  397. CARLA_SAFE_ASSERT_RETURN(fullPortName != nullptr && fullPortName[0] != '\0', false);
  398. if (std::strncmp(fullPortName, "Carla:", 6) == 0)
  399. {
  400. groupId = RACK_GRAPH_GROUP_CARLA;
  401. portId = getCarlaRackPortIdFromName(fullPortName+6);
  402. if (portId > RACK_GRAPH_CARLA_PORT_NULL && portId < RACK_GRAPH_CARLA_PORT_MAX)
  403. return true;
  404. }
  405. else if (std::strncmp(fullPortName, "AudioIn:", 8) == 0)
  406. {
  407. groupId = RACK_GRAPH_GROUP_AUDIO_IN;
  408. if (const int portTest = std::atoi(fullPortName+8))
  409. {
  410. portId = static_cast<uint>(portTest-1);
  411. return true;
  412. }
  413. }
  414. else if (std::strncmp(fullPortName, "AudioOut:", 9) == 0)
  415. {
  416. groupId = RACK_GRAPH_GROUP_AUDIO_OUT;
  417. if (const int portTest = std::atoi(fullPortName+9))
  418. {
  419. portId = static_cast<uint>(portTest-1);
  420. return true;
  421. }
  422. }
  423. else if (std::strncmp(fullPortName, "MidiIn:", 7) == 0)
  424. {
  425. groupId = RACK_GRAPH_GROUP_MIDI_IN;
  426. if (const char* const portName = fullPortName+7)
  427. {
  428. bool ok;
  429. portId = midi.getPortId(true, portName, &ok);
  430. return ok;
  431. }
  432. }
  433. else if (std::strncmp(fullPortName, "MidiOut:", 8) == 0)
  434. {
  435. groupId = RACK_GRAPH_GROUP_MIDI_OUT;
  436. if (const char* const portName = fullPortName+8)
  437. {
  438. bool ok;
  439. portId = midi.getPortId(false, portName, &ok);
  440. return ok;
  441. }
  442. }
  443. return false;
  444. }
  445. void RackGraph::process(CarlaEngine::ProtectedData* const data, const float* inBufReal[2], float* outBuf[2], const uint32_t frames)
  446. {
  447. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  448. CARLA_SAFE_ASSERT_RETURN(data->events.in != nullptr,);
  449. CARLA_SAFE_ASSERT_RETURN(data->events.out != nullptr,);
  450. const int iframes(static_cast<int>(frames));
  451. // safe copy
  452. float inBuf0[frames];
  453. float inBuf1[frames];
  454. float* inBuf[2] = { inBuf0, inBuf1 };
  455. // initialize audio inputs
  456. FloatVectorOperations::copy(inBuf0, inBufReal[0], iframes);
  457. FloatVectorOperations::copy(inBuf1, inBufReal[1], iframes);
  458. // initialize audio outputs (zero)
  459. FloatVectorOperations::clear(outBuf[0], iframes);
  460. FloatVectorOperations::clear(outBuf[1], iframes);
  461. // initialize event outputs (zero)
  462. carla_zeroStruct<EngineEvent>(data->events.out, kMaxEngineEventInternalCount);
  463. bool processed = false;
  464. uint32_t oldAudioInCount = 0;
  465. uint32_t oldMidiOutCount = 0;
  466. // process plugins
  467. for (uint i=0; i < data->curPluginCount; ++i)
  468. {
  469. CarlaPlugin* const plugin = data->plugins[i].plugin;
  470. if (plugin == nullptr || ! plugin->isEnabled() || ! plugin->tryLock(isOffline))
  471. continue;
  472. if (processed)
  473. {
  474. // initialize audio inputs (from previous outputs)
  475. FloatVectorOperations::copy(inBuf0, outBuf[0], iframes);
  476. FloatVectorOperations::copy(inBuf1, outBuf[1], iframes);
  477. // initialize audio outputs (zero)
  478. FloatVectorOperations::clear(outBuf[0], iframes);
  479. FloatVectorOperations::clear(outBuf[1], iframes);
  480. // if plugin has no midi out, add previous events
  481. if (oldMidiOutCount == 0 && data->events.in[0].type != kEngineEventTypeNull)
  482. {
  483. if (data->events.out[0].type != kEngineEventTypeNull)
  484. {
  485. // TODO: carefully add to input, sorted events
  486. }
  487. // else nothing needed
  488. }
  489. else
  490. {
  491. // initialize event inputs from previous outputs
  492. carla_copyStruct<EngineEvent>(data->events.in, data->events.out, kMaxEngineEventInternalCount);
  493. // initialize event outputs (zero)
  494. carla_zeroStruct<EngineEvent>(data->events.out, kMaxEngineEventInternalCount);
  495. }
  496. }
  497. oldAudioInCount = plugin->getAudioInCount();
  498. oldMidiOutCount = plugin->getMidiOutCount();
  499. // process
  500. plugin->initBuffers();
  501. plugin->process(inBuf, outBuf, frames);
  502. plugin->unlock();
  503. // if plugin has no audio inputs, add input buffer
  504. if (oldAudioInCount == 0)
  505. {
  506. FloatVectorOperations::add(outBuf[0], inBuf0, iframes);
  507. FloatVectorOperations::add(outBuf[1], inBuf1, iframes);
  508. }
  509. // set peaks
  510. {
  511. EnginePluginData& pluginData(data->plugins[i]);
  512. juce::Range<float> range;
  513. if (oldAudioInCount > 0)
  514. {
  515. range = FloatVectorOperations::findMinAndMax(inBuf0, iframes);
  516. pluginData.insPeak[0] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  517. range = FloatVectorOperations::findMinAndMax(inBuf1, iframes);
  518. pluginData.insPeak[1] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  519. }
  520. else
  521. {
  522. pluginData.insPeak[0] = 0.0f;
  523. pluginData.insPeak[1] = 0.0f;
  524. }
  525. if (plugin->getAudioOutCount() > 0)
  526. {
  527. range = FloatVectorOperations::findMinAndMax(outBuf[0], iframes);
  528. pluginData.outsPeak[0] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  529. range = FloatVectorOperations::findMinAndMax(outBuf[1], iframes);
  530. pluginData.outsPeak[1] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  531. }
  532. else
  533. {
  534. pluginData.outsPeak[0] = 0.0f;
  535. pluginData.outsPeak[1] = 0.0f;
  536. }
  537. }
  538. processed = true;
  539. }
  540. }
  541. void RackGraph::processHelper(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames)
  542. {
  543. CARLA_SAFE_ASSERT_RETURN(audio.outBuf[1] != nullptr,);
  544. const int iframes(static_cast<int>(frames));
  545. const CarlaRecursiveMutexLocker _cml(audio.mutex);
  546. if (inBuf != nullptr && inputs > 0)
  547. {
  548. bool noConnections = true;
  549. // connect input buffers
  550. for (LinkedList<uint>::Itenerator it = audio.connectedIn1.begin(); it.valid(); it.next())
  551. {
  552. const uint& port(it.getValue());
  553. CARLA_SAFE_ASSERT_CONTINUE(port < inputs);
  554. if (noConnections)
  555. {
  556. FloatVectorOperations::copy(audio.inBuf[0], inBuf[port], iframes);
  557. noConnections = false;
  558. }
  559. else
  560. {
  561. FloatVectorOperations::add(audio.inBuf[0], inBuf[port], iframes);
  562. }
  563. }
  564. if (noConnections)
  565. FloatVectorOperations::clear(audio.inBuf[0], iframes);
  566. noConnections = true;
  567. for (LinkedList<uint>::Itenerator it = audio.connectedIn2.begin(); it.valid(); it.next())
  568. {
  569. const uint& port(it.getValue());
  570. CARLA_SAFE_ASSERT_CONTINUE(port < inputs);
  571. if (noConnections)
  572. {
  573. FloatVectorOperations::copy(audio.inBuf[1], inBuf[port], iframes);
  574. noConnections = false;
  575. }
  576. else
  577. {
  578. FloatVectorOperations::add(audio.inBuf[1], inBuf[port], iframes);
  579. }
  580. }
  581. if (noConnections)
  582. FloatVectorOperations::clear(audio.inBuf[1], iframes);
  583. }
  584. else
  585. {
  586. FloatVectorOperations::clear(audio.inBuf[0], iframes);
  587. FloatVectorOperations::clear(audio.inBuf[1], iframes);
  588. }
  589. FloatVectorOperations::clear(audio.outBuf[0], iframes);
  590. FloatVectorOperations::clear(audio.outBuf[1], iframes);
  591. // process
  592. process(data, const_cast<const float**>(audio.inBuf), audio.outBuf, frames);
  593. // connect output buffers
  594. if (audio.connectedOut1.count() != 0)
  595. {
  596. for (LinkedList<uint>::Itenerator it = audio.connectedOut1.begin(); it.valid(); it.next())
  597. {
  598. const uint& port(it.getValue());
  599. CARLA_SAFE_ASSERT_CONTINUE(port < outputs);
  600. FloatVectorOperations::add(outBuf[port], audio.outBuf[0], iframes);
  601. }
  602. }
  603. if (audio.connectedOut2.count() != 0)
  604. {
  605. for (LinkedList<uint>::Itenerator it = audio.connectedOut2.begin(); it.valid(); it.next())
  606. {
  607. const uint& port(it.getValue());
  608. CARLA_SAFE_ASSERT_CONTINUE(port < outputs);
  609. FloatVectorOperations::add(outBuf[port], audio.outBuf[1], iframes);
  610. }
  611. }
  612. }
  613. #if 0
  614. // -----------------------------------------------------------------------
  615. class CarlaPluginInstance : public AudioPluginInstance
  616. {
  617. public:
  618. CarlaPluginInstance(CarlaPlugin* const plugin)
  619. : fPlugin(plugin),
  620. fGraph(nullptr) {}
  621. ~CarlaPluginInstance() override
  622. {
  623. }
  624. // -------------------------------------------------------------------
  625. AudioProcessorGraph* getParentGraph() const noexcept
  626. {
  627. return fGraph;
  628. }
  629. void setParentGraph(AudioProcessorGraph*)
  630. {
  631. }
  632. void* getPlatformSpecificData() noexcept override
  633. {
  634. return fPlugin;
  635. }
  636. void fillInPluginDescription(PluginDescription& d) const override
  637. {
  638. d.pluginFormatName = "Carla";
  639. d.category = "Carla Plugin";
  640. d.version = "1.0";
  641. CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
  642. char strBuf[STR_MAX+1];
  643. strBuf[STR_MAX] = '\0';
  644. fPlugin->getRealName(strBuf);
  645. d.name = strBuf;
  646. fPlugin->getLabel(strBuf);
  647. d.descriptiveName = strBuf;
  648. fPlugin->getMaker(strBuf);
  649. d.manufacturerName = strBuf;
  650. d.uid = d.name.hashCode();
  651. d.isInstrument = (fPlugin->getHints() & PLUGIN_IS_SYNTH);
  652. d.numInputChannels = static_cast<int>(fPlugin->getAudioInCount());
  653. d.numOutputChannels = static_cast<int>(fPlugin->getAudioOutCount());
  654. //d.hasSharedContainer = true;
  655. }
  656. // -------------------------------------------------------------------
  657. const String getName() const override
  658. {
  659. return fPlugin->getName();
  660. }
  661. void processBlock(AudioSampleBuffer& audio, MidiBuffer& midi)
  662. {
  663. if (CarlaEngineEventPort* const port = fPlugin->getDefaultEventInPort())
  664. {
  665. EngineEvent* const engineEvents(port->fBuffer);
  666. CARLA_SAFE_ASSERT_RETURN(engineEvents != nullptr,);
  667. carla_zeroStruct<EngineEvent>(engineEvents, kMaxEngineEventInternalCount);
  668. fillEngineEventsFromJuceMidiBuffer(engineEvents, midi);
  669. }
  670. const uint32_t bufferSize(static_cast<uint32_t>(audio.getNumSamples()));
  671. if (const int numChan = audio.getNumChannels())
  672. {
  673. float* audioBuffers[numChan];
  674. for (int i=0; i<numChan; ++i)
  675. audioBuffers[i] = audio.getWritePointer(i);
  676. fPlugin->process(audioBuffers, audioBuffers, bufferSize);
  677. }
  678. else
  679. {
  680. fPlugin->process(nullptr, nullptr, bufferSize);
  681. }
  682. midi.clear();
  683. if (CarlaEngineEventPort* const port = fPlugin->getDefaultEventOutPort())
  684. {
  685. const EngineEvent* const engineEvents(port->fBuffer);
  686. CARLA_SAFE_ASSERT_RETURN(engineEvents != nullptr,);
  687. fillJuceMidiBufferFromEngineEvents(midi, engineEvents);
  688. }
  689. }
  690. void prepareToPlay(double, int) override {}
  691. void releaseResources() override {}
  692. const String getInputChannelName(int) const override { return String(); }
  693. const String getOutputChannelName(int) const override { return String(); }
  694. const String getParameterName(int) override { return String(); }
  695. String getParameterName(int, int) override { return String(); }
  696. const String getParameterText(int) override { return String(); }
  697. String getParameterText(int, int) override { return String(); }
  698. const String getProgramName(int) override { return String(); }
  699. double getTailLengthSeconds() const override { return 0.0; }
  700. float getParameter(int) override { return 0.0f; }
  701. bool isInputChannelStereoPair(int) const override { return true; }
  702. bool isOutputChannelStereoPair(int) const override { return true; }
  703. bool silenceInProducesSilenceOut() const override { return true; }
  704. bool hasEditor() const override { return false; }
  705. bool acceptsMidi() const override { return fPlugin->getMidiInCount() > 0; }
  706. bool producesMidi() const override { return fPlugin->getMidiOutCount() > 0; }
  707. void setParameter(int, float) override {}
  708. void setCurrentProgram(int) override {}
  709. void changeProgramName(int, const String&) override {}
  710. void getStateInformation(MemoryBlock&) override {}
  711. void setStateInformation(const void*, int) override {}
  712. int getNumParameters() override { return 0; }
  713. int getNumPrograms() override { return 0; }
  714. int getCurrentProgram() override { return 0; }
  715. AudioProcessorEditor* createEditor() override { return nullptr; }
  716. // -------------------------------------------------------------------
  717. private:
  718. CarlaPlugin* const fPlugin;
  719. AudioProcessorGraph* fGraph;
  720. };
  721. // -----------------------------------------------------------------------
  722. // PatchbayGraph
  723. static const int kMidiInputNodeId = MAX_PATCHBAY_PLUGINS*3+1;
  724. static const int kMidiOutputNodeId = MAX_PATCHBAY_PLUGINS*3+2;
  725. PatchbayGraph::PatchbayGraph(const int bufferSize, const double sampleRate, const uint32_t ins, const uint32_t outs)
  726. : inputs(static_cast<int>(ins)),
  727. outputs(static_cast<int>(outs))
  728. {
  729. graph.setPlayConfigDetails(inputs, outputs, sampleRate, bufferSize);
  730. graph.prepareToPlay(sampleRate, bufferSize);
  731. audioBuffer.setSize(jmax(inputs, outputs), bufferSize);
  732. midiBuffer.ensureSize(kMaxEngineEventInternalCount*2);
  733. midiBuffer.clear();
  734. for (uint32_t i=0; i<ins && i<MAX_PATCHBAY_PLUGINS; ++i)
  735. {
  736. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioInputNode));
  737. graph.addNode(proc, MAX_PATCHBAY_PLUGINS + i);
  738. }
  739. for (uint32_t i=0; i<outs && i<MAX_PATCHBAY_PLUGINS; ++i)
  740. {
  741. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::audioOutputNode));
  742. graph.addNode(proc, MAX_PATCHBAY_PLUGINS*2 + i);
  743. }
  744. {
  745. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::midiInputNode));
  746. graph.addNode(proc, kMidiInputNodeId);
  747. }
  748. {
  749. AudioProcessorGraph::AudioGraphIOProcessor* const proc(new AudioProcessorGraph::AudioGraphIOProcessor(AudioProcessorGraph::AudioGraphIOProcessor::midiOutputNode));
  750. graph.addNode(proc, kMidiOutputNodeId);
  751. }
  752. }
  753. PatchbayGraph::~PatchbayGraph()
  754. {
  755. graph.releaseResources();
  756. graph.clear();
  757. audioBuffer.clear();
  758. }
  759. void PatchbayGraph::setBufferSize(const int bufferSize)
  760. {
  761. graph.releaseResources();
  762. graph.prepareToPlay(graph.getSampleRate(), bufferSize);
  763. audioBuffer.setSize(audioBuffer.getNumChannels(), bufferSize);
  764. }
  765. void PatchbayGraph::setSampleRate(const double sampleRate)
  766. {
  767. graph.releaseResources();
  768. graph.prepareToPlay(sampleRate, graph.getBlockSize());
  769. }
  770. void PatchbayGraph::setOffline(const bool offline)
  771. {
  772. graph.setNonRealtime(offline);
  773. }
  774. void PatchbayGraph::addPlugin(CarlaPlugin* const plugin)
  775. {
  776. CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
  777. CarlaPluginInstance* const instance(new CarlaPluginInstance(plugin));
  778. graph.addNode(instance, plugin->getId());
  779. }
  780. void PatchbayGraph::replacePlugin(CarlaPlugin* const oldPlugin, CarlaPlugin* const newPlugin)
  781. {
  782. CARLA_SAFE_ASSERT_RETURN(oldPlugin != nullptr,);
  783. CARLA_SAFE_ASSERT_RETURN(newPlugin != nullptr,);
  784. CARLA_SAFE_ASSERT_RETURN(oldPlugin != newPlugin,);
  785. CARLA_SAFE_ASSERT_RETURN(oldPlugin->getId() == newPlugin->getId(),);
  786. CarlaPluginInstance* const instance(new CarlaPluginInstance(newPlugin));
  787. graph.addNode(instance, newPlugin->getId());
  788. }
  789. void PatchbayGraph::removePlugin(CarlaPlugin* const plugin)
  790. {
  791. CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
  792. graph.removeNode(plugin->getId());
  793. // move all plugins 1 spot backwards
  794. for (uint i=plugin->getId(); i<MAX_PATCHBAY_PLUGINS; ++i)
  795. {
  796. if (AudioProcessorGraph::Node* const node = graph.getNodeForId(i+1))
  797. {
  798. if (AudioProcessor* const proc = node->getProcessor())
  799. graph.addNode(proc, i);
  800. continue;
  801. }
  802. break;
  803. }
  804. }
  805. void PatchbayGraph::removeAllPlugins()
  806. {
  807. graph.clear();
  808. // TODO
  809. }
  810. #if 0
  811. bool PatchbayGraph::connect(CarlaEngine* const engine, const uint /*groupA*/, const uint /*portA*/, const uint /*groupB*/, const uint /*portB*/) noexcept
  812. {
  813. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  814. return false;
  815. }
  816. bool PatchbayGraph::disconnect(CarlaEngine* const engine, const uint /*connectionId*/) noexcept
  817. {
  818. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  819. return false;
  820. }
  821. const char* const* PatchbayGraph::getConnections() const noexcept
  822. {
  823. return nullptr;
  824. }
  825. bool PatchbayGraph::getPortIdFromFullName(const char* const /*fillPortName*/, uint& /*groupId*/, uint& /*portId*/) const noexcept
  826. {
  827. return false;
  828. }
  829. #endif
  830. void PatchbayGraph::process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const int frames)
  831. {
  832. CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
  833. CARLA_SAFE_ASSERT_RETURN(data->events.in != nullptr,);
  834. CARLA_SAFE_ASSERT_RETURN(data->events.out != nullptr,);
  835. CARLA_SAFE_ASSERT_RETURN(frames > 0,);
  836. // put events in juce buffer
  837. {
  838. midiBuffer.clear();
  839. fillJuceMidiBufferFromEngineEvents(midiBuffer, data->events.in);
  840. }
  841. // put carla audio in juce buffer
  842. {
  843. int i=0;
  844. for (; i<inputs; ++i)
  845. FloatVectorOperations::copy(audioBuffer.getWritePointer(i), inBuf[i], frames);
  846. // clear remaining channels
  847. for (int count=audioBuffer.getNumChannels(); i<count; ++i)
  848. audioBuffer.clear(i, 0, frames);
  849. }
  850. graph.processBlock(audioBuffer, midiBuffer);
  851. // put juce audio in carla buffer
  852. {
  853. for (int i=0; i<outputs; ++i)
  854. FloatVectorOperations::copy(outBuf[i], audioBuffer.getReadPointer(i), frames);
  855. }
  856. // put juce events in carla buffer
  857. {
  858. carla_zeroStruct<EngineEvent>(data->events.out, kMaxEngineEventInternalCount);
  859. fillEngineEventsFromJuceMidiBuffer(data->events.out, midiBuffer);
  860. }
  861. }
  862. #endif
  863. // -----------------------------------------------------------------------
  864. // InternalGraph
  865. EngineInternalGraph::EngineInternalGraph() noexcept
  866. : fIsRack(true),
  867. fIsReady(false)
  868. {
  869. fRack = nullptr;
  870. }
  871. EngineInternalGraph::~EngineInternalGraph() noexcept
  872. {
  873. CARLA_SAFE_ASSERT(! fIsReady);
  874. CARLA_SAFE_ASSERT(fRack == nullptr);
  875. }
  876. void EngineInternalGraph::create(const bool isRack, const double sampleRate, const uint32_t bufferSize, const uint32_t inputs, const uint32_t outputs)
  877. {
  878. fIsRack = isRack;
  879. if (isRack)
  880. {
  881. CARLA_SAFE_ASSERT_RETURN(fRack == nullptr,);
  882. fRack = new RackGraph(bufferSize, inputs, outputs);
  883. }
  884. #if 0
  885. else
  886. {
  887. CARLA_SAFE_ASSERT_RETURN(fPatchbay == nullptr,);
  888. fPatchbay = new PatchbayGraph(static_cast<int>(bufferSize), sampleRate, inputs, outputs);
  889. }
  890. #endif
  891. fIsReady = true;
  892. // unused
  893. return; (void)sampleRate;
  894. }
  895. void EngineInternalGraph::destroy() noexcept
  896. {
  897. if (! fIsReady)
  898. {
  899. CARLA_SAFE_ASSERT(fRack == nullptr);
  900. return;
  901. }
  902. fIsReady = false;
  903. if (fIsRack)
  904. {
  905. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  906. delete fRack;
  907. fRack = nullptr;
  908. }
  909. #if 0
  910. else
  911. {
  912. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  913. delete fPatchbay;
  914. fPatchbay = nullptr;
  915. }
  916. #endif
  917. }
  918. void EngineInternalGraph::setBufferSize(const uint32_t bufferSize)
  919. {
  920. ScopedValueSetter<bool> svs(fIsReady, false, true);
  921. if (fIsRack)
  922. {
  923. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  924. fRack->setBufferSize(bufferSize);
  925. }
  926. #if 0
  927. else
  928. {
  929. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  930. fPatchbay->setBufferSize(static_cast<int>(bufferSize));
  931. }
  932. #endif
  933. }
  934. void EngineInternalGraph::setSampleRate(const double sampleRate)
  935. {
  936. ScopedValueSetter<bool> svs(fIsReady, false, true);
  937. if (fIsRack)
  938. {
  939. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  940. }
  941. #if 0
  942. else
  943. {
  944. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  945. fPatchbay->setSampleRate(sampleRate);
  946. }
  947. #endif
  948. // unused
  949. return; (void)sampleRate;
  950. }
  951. void EngineInternalGraph::setOffline(const bool offline)
  952. {
  953. ScopedValueSetter<bool> svs(fIsReady, false, true);
  954. if (fIsRack)
  955. {
  956. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  957. fRack->setOffline(offline);
  958. }
  959. #if 0
  960. else
  961. {
  962. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  963. fPatchbay->setOffline(offline);
  964. }
  965. #endif
  966. }
  967. bool EngineInternalGraph::isReady() const noexcept
  968. {
  969. return fIsReady;
  970. }
  971. RackGraph* EngineInternalGraph::getRackGraph() const noexcept
  972. {
  973. CARLA_SAFE_ASSERT_RETURN(fIsRack, nullptr);
  974. return fRack;
  975. }
  976. PatchbayGraph* EngineInternalGraph::getPatchbayGraph() const noexcept
  977. {
  978. CARLA_SAFE_ASSERT_RETURN(! fIsRack, nullptr);
  979. return fPatchbay;
  980. }
  981. void EngineInternalGraph::process(CarlaEngine::ProtectedData* const data, const float* const* const inBuf, float* const* const outBuf, const uint32_t frames)
  982. {
  983. if (fIsRack)
  984. {
  985. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  986. fRack->processHelper(data, inBuf, outBuf, frames);
  987. }
  988. #if 0
  989. else
  990. {
  991. CARLA_SAFE_ASSERT_RETURN(fPatchbay != nullptr,);
  992. fPatchbay->process(data, inBuf, outBuf, static_cast<int>(frames));
  993. }
  994. #endif
  995. }
  996. void EngineInternalGraph::processRack(CarlaEngine::ProtectedData* const data, const float* inBuf[2], float* outBuf[2], const uint32_t frames)
  997. {
  998. CARLA_SAFE_ASSERT_RETURN(fIsRack,);
  999. CARLA_SAFE_ASSERT_RETURN(fRack != nullptr,);
  1000. fRack->process(data, inBuf, outBuf, frames);
  1001. }
  1002. // -----------------------------------------------------------------------
  1003. // CarlaEngine Patchbay stuff
  1004. bool CarlaEngine::patchbayConnect(const uint groupA, const uint portA, const uint groupB, const uint portB)
  1005. {
  1006. CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
  1007. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);
  1008. carla_stdout("CarlaEngine::patchbayConnect(%u, %u, %u, %u)", groupA, portA, groupB, portB);
  1009. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1010. {
  1011. if (RackGraph* const graph = pData->graph.getRackGraph())
  1012. return graph->connect(this, groupA, portA, groupB, portB);
  1013. }
  1014. else
  1015. {
  1016. }
  1017. return false;
  1018. }
  1019. bool CarlaEngine::patchbayDisconnect(const uint connectionId)
  1020. {
  1021. CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
  1022. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);
  1023. carla_stdout("CarlaEngine::patchbayDisconnect(%u)", connectionId);
  1024. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1025. {
  1026. if (RackGraph* const graph = pData->graph.getRackGraph())
  1027. return graph->disconnect(this, connectionId);
  1028. }
  1029. else
  1030. {
  1031. }
  1032. return false;
  1033. }
  1034. bool CarlaEngine::patchbayRefresh()
  1035. {
  1036. setLastError("Unsupported operation");
  1037. return false;
  1038. }
  1039. // -----------------------------------------------------------------------
  1040. const char* const* CarlaEngine::getPatchbayConnections() const
  1041. {
  1042. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), nullptr);
  1043. carla_debug("CarlaEngine::getPatchbayConnections()");
  1044. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1045. {
  1046. if (RackGraph* const graph = pData->graph.getRackGraph())
  1047. return graph->getConnections();
  1048. }
  1049. else
  1050. {
  1051. }
  1052. return nullptr;
  1053. }
  1054. void CarlaEngine::restorePatchbayConnection(const char* const connSource, const char* const connTarget)
  1055. {
  1056. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(),);
  1057. CARLA_SAFE_ASSERT_RETURN(connSource != nullptr && connSource[0] != '\0',);
  1058. CARLA_SAFE_ASSERT_RETURN(connTarget != nullptr && connTarget[0] != '\0',);
  1059. carla_debug("CarlaEngine::restorePatchbayConnection(\"%s\", \"%s\")", connSource, connTarget);
  1060. uint groupA, portA;
  1061. uint groupB, portB;
  1062. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  1063. {
  1064. RackGraph* const graph = pData->graph.getRackGraph();
  1065. CARLA_SAFE_ASSERT_RETURN(graph != nullptr,);
  1066. if (! graph->getGroupAndPortIdFromFullName(connSource, groupA, portA))
  1067. return;
  1068. if (! graph->getGroupAndPortIdFromFullName(connTarget, groupB, portB))
  1069. return;
  1070. }
  1071. else
  1072. {
  1073. return;
  1074. }
  1075. patchbayConnect(groupA, portA, groupB, portB);
  1076. }
  1077. // -----------------------------------------------------------------------
  1078. CARLA_BACKEND_END_NAMESPACE