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