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

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