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

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