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

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