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 76KB

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