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