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.

CarlaEngineInternal.cpp 26KB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822
  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 "CarlaEngineInternal.hpp"
  18. #include "CarlaPlugin.hpp"
  19. #include "CarlaMIDI.h"
  20. #include "CarlaMathUtils.hpp"
  21. // -----------------------------------------------------------------------
  22. CARLA_BACKEND_START_NAMESPACE
  23. #if 0
  24. } // Fix editor indentation
  25. #endif
  26. #ifndef BUILD_BRIDGE
  27. // -----------------------------------------------------------------------
  28. // Rack Patchbay stuff
  29. static uint getCarlaRackPortIdFromName(const char* const shortname) noexcept
  30. {
  31. if (std::strcmp(shortname, "AudioIn1") == 0 || std::strcmp(shortname, "audio-in1") == 0)
  32. return RACK_GRAPH_CARLA_PORT_AUDIO_IN1;
  33. if (std::strcmp(shortname, "AudioIn2") == 0 || std::strcmp(shortname, "audio-in2") == 0)
  34. return RACK_GRAPH_CARLA_PORT_AUDIO_IN2;
  35. if (std::strcmp(shortname, "AudioOut1") == 0 || std::strcmp(shortname, "audio-out1") == 0)
  36. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT1;
  37. if (std::strcmp(shortname, "AudioOut2") == 0 || std::strcmp(shortname, "audio-out2") == 0)
  38. return RACK_GRAPH_CARLA_PORT_AUDIO_OUT2;
  39. if (std::strcmp(shortname, "MidiIn") == 0 || std::strcmp(shortname, "midi-in") == 0)
  40. return RACK_GRAPH_CARLA_PORT_MIDI_IN;
  41. if (std::strcmp(shortname, "MidiOut") == 0 || std::strcmp(shortname, "midi-out") == 0)
  42. return RACK_GRAPH_CARLA_PORT_MIDI_OUT;
  43. carla_stderr("CarlaBackend::getCarlaRackPortIdFromName(%s) - invalid short name", shortname);
  44. return RACK_GRAPH_CARLA_PORT_NULL;
  45. }
  46. // -----------------------------------------------------------------------
  47. // RackGraph
  48. const char* RackGraph::MIDI::getName(const bool isInput, const uint index) const noexcept
  49. {
  50. for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
  51. {
  52. const PortNameToId& port(it.getValue());
  53. if (port.port == index)
  54. return port.name;
  55. }
  56. return nullptr;
  57. }
  58. uint RackGraph::MIDI::getPortId(const bool isInput, const char portName[]) const noexcept
  59. {
  60. for (LinkedList<PortNameToId>::Itenerator it = isInput ? ins.begin() : outs.begin(); it.valid(); it.next())
  61. {
  62. const PortNameToId& port(it.getValue());
  63. if (std::strcmp(port.name, portName) == 0)
  64. return port.port;
  65. }
  66. return 0;
  67. }
  68. bool RackGraph::connect(CarlaEngine* const engine, const uint groupA, const uint portA, const uint groupB, const uint portB) noexcept
  69. {
  70. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  71. uint carlaPort;
  72. GroupPort otherPort;
  73. if (groupA == RACK_GRAPH_GROUP_CARLA)
  74. {
  75. CARLA_SAFE_ASSERT_RETURN(groupB != RACK_GRAPH_GROUP_CARLA, false);
  76. carlaPort = portA;
  77. otherPort.group = groupB;
  78. otherPort.port = portB;
  79. }
  80. else
  81. {
  82. CARLA_SAFE_ASSERT_RETURN(groupB == RACK_GRAPH_GROUP_CARLA, false);
  83. carlaPort = portB;
  84. otherPort.group = groupA;
  85. otherPort.port = portA;
  86. }
  87. CARLA_SAFE_ASSERT_RETURN(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX, false);
  88. CARLA_SAFE_ASSERT_RETURN(otherPort.group > RACK_GRAPH_GROUP_CARLA && otherPort.group < RACK_GRAPH_GROUP_MAX, false);
  89. bool makeConnection = false;
  90. switch (carlaPort)
  91. {
  92. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  93. CARLA_SAFE_ASSERT_RETURN(otherPort.group == RACK_GRAPH_GROUP_AUDIO_IN, false);
  94. audio.mutex.lock();
  95. makeConnection = audio.connectedIn1.append(otherPort.port);
  96. audio.mutex.unlock();
  97. break;
  98. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  99. CARLA_SAFE_ASSERT_RETURN(otherPort.group == RACK_GRAPH_GROUP_AUDIO_IN, false);
  100. audio.mutex.lock();
  101. makeConnection = audio.connectedIn2.append(otherPort.port);
  102. audio.mutex.unlock();
  103. break;
  104. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  105. CARLA_SAFE_ASSERT_RETURN(otherPort.group == RACK_GRAPH_GROUP_AUDIO_OUT, false);
  106. audio.mutex.lock();
  107. makeConnection = audio.connectedOut1.append(otherPort.port);
  108. audio.mutex.unlock();
  109. break;
  110. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  111. CARLA_SAFE_ASSERT_RETURN(otherPort.group == RACK_GRAPH_GROUP_AUDIO_OUT, false);
  112. audio.mutex.lock();
  113. makeConnection = audio.connectedOut2.append(otherPort.port);
  114. audio.mutex.unlock();
  115. break;
  116. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  117. CARLA_SAFE_ASSERT_RETURN(otherPort.group == RACK_GRAPH_GROUP_MIDI_IN, false);
  118. if (const char* const portName = midi.getName(true, otherPort.port))
  119. makeConnection = engine->connectRackMidiInPort(portName);
  120. break;
  121. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  122. CARLA_SAFE_ASSERT_RETURN(otherPort.group == RACK_GRAPH_GROUP_MIDI_OUT, false);
  123. if (const char* const portName = midi.getName(false, otherPort.port))
  124. makeConnection = engine->connectRackMidiOutPort(portName);
  125. break;
  126. }
  127. if (! makeConnection)
  128. {
  129. engine->setLastError("Invalid rack connection");
  130. return false;
  131. }
  132. ConnectionToId connectionToId;
  133. connectionToId.setData(++connections.lastId, groupA, portA, groupB, portB);
  134. char strBuf[STR_MAX+1];
  135. strBuf[STR_MAX] = '\0';
  136. std::snprintf(strBuf, STR_MAX, "%u:%u:%u:%u", groupA, portA, groupB, portB);
  137. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, connectionToId.id, 0, 0, 0.0f, strBuf);
  138. connections.list.append(connectionToId);
  139. return true;
  140. }
  141. bool RackGraph::disconnect(CarlaEngine* const engine, const uint connectionId) noexcept
  142. {
  143. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  144. CARLA_SAFE_ASSERT_RETURN(connections.list.count() > 0, false);
  145. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  146. {
  147. const ConnectionToId& connection(it.getValue());
  148. if (connection.id != connectionId)
  149. continue;
  150. uint carlaPort;
  151. GroupPort otherPort;
  152. if (connection.groupA == RACK_GRAPH_GROUP_CARLA)
  153. {
  154. CARLA_SAFE_ASSERT_RETURN(connection.groupB != RACK_GRAPH_GROUP_CARLA, false);
  155. carlaPort = connection.portA;
  156. otherPort.group = connection.groupB;
  157. otherPort.port = connection.portB;
  158. }
  159. else
  160. {
  161. CARLA_SAFE_ASSERT_RETURN(connection.groupB == RACK_GRAPH_GROUP_CARLA, false);
  162. carlaPort = connection.portB;
  163. otherPort.group = connection.groupA;
  164. otherPort.port = connection.portA;
  165. }
  166. CARLA_SAFE_ASSERT_RETURN(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX, false);
  167. CARLA_SAFE_ASSERT_RETURN(otherPort.group > RACK_GRAPH_GROUP_CARLA && otherPort.group < RACK_GRAPH_GROUP_MAX, false);
  168. bool makeDisconnection = false;
  169. switch (carlaPort)
  170. {
  171. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  172. audio.mutex.lock();
  173. makeDisconnection = audio.connectedIn1.removeOne(otherPort.port);
  174. audio.mutex.unlock();
  175. break;
  176. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  177. audio.mutex.lock();
  178. makeDisconnection = audio.connectedIn2.removeOne(otherPort.port);
  179. audio.mutex.unlock();
  180. break;
  181. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  182. audio.mutex.lock();
  183. makeDisconnection = audio.connectedOut1.removeOne(otherPort.port);
  184. audio.mutex.unlock();
  185. break;
  186. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  187. audio.mutex.lock();
  188. makeDisconnection = audio.connectedOut2.removeOne(otherPort.port);
  189. audio.mutex.unlock();
  190. break;
  191. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  192. if (const char* const portName = midi.getName(true, otherPort.port))
  193. makeDisconnection = engine->disconnectRackMidiInPort(portName);
  194. break;
  195. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  196. if (const char* const portName = midi.getName(false, otherPort.port))
  197. makeDisconnection = engine->disconnectRackMidiOutPort(portName);
  198. break;
  199. }
  200. if (! makeDisconnection)
  201. {
  202. engine->setLastError("Invalid rack connection");
  203. return false;
  204. }
  205. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connection.id, 0, 0, 0.0f, nullptr);
  206. connections.list.remove(it);
  207. return true;
  208. }
  209. engine->setLastError("Failed to find connection");
  210. return false;
  211. }
  212. const char* const* RackGraph::getConnections() const
  213. {
  214. if (connections.list.count() == 0)
  215. return nullptr;
  216. LinkedList<const char*> connList;
  217. char strBuf[STR_MAX+1];
  218. strBuf[STR_MAX] = '\0';
  219. for (LinkedList<ConnectionToId>::Itenerator it=connections.list.begin(); it.valid(); it.next())
  220. {
  221. const ConnectionToId& connection(it.getValue());
  222. uint carlaPort;
  223. GroupPort otherPort;
  224. if (connection.groupA == RACK_GRAPH_GROUP_CARLA)
  225. {
  226. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB != RACK_GRAPH_GROUP_CARLA);
  227. carlaPort = connection.portA;
  228. otherPort.group = connection.groupB;
  229. otherPort.port = connection.portB;
  230. }
  231. else
  232. {
  233. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB == RACK_GRAPH_GROUP_CARLA);
  234. carlaPort = connection.portB;
  235. otherPort.group = connection.groupA;
  236. otherPort.port = connection.portA;
  237. }
  238. CARLA_SAFE_ASSERT_CONTINUE(carlaPort > RACK_GRAPH_CARLA_PORT_NULL && carlaPort < RACK_GRAPH_CARLA_PORT_MAX);
  239. CARLA_SAFE_ASSERT_CONTINUE(otherPort.group > RACK_GRAPH_GROUP_CARLA && otherPort.group < RACK_GRAPH_GROUP_MAX);
  240. switch (carlaPort)
  241. {
  242. case RACK_GRAPH_CARLA_PORT_AUDIO_IN1:
  243. case RACK_GRAPH_CARLA_PORT_AUDIO_IN2:
  244. std::snprintf(strBuf, STR_MAX, "AudioIn:%i", otherPort.port+1);
  245. connList.append(carla_strdup(strBuf));
  246. connList.append(carla_strdup((carlaPort == RACK_GRAPH_CARLA_PORT_AUDIO_IN1) ? "Carla:AudioIn1" : "Carla:AudioIn2"));
  247. break;
  248. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT1:
  249. case RACK_GRAPH_CARLA_PORT_AUDIO_OUT2:
  250. std::snprintf(strBuf, STR_MAX, "AudioOut:%i", otherPort.port+1);
  251. connList.append(carla_strdup((carlaPort == RACK_GRAPH_CARLA_PORT_AUDIO_OUT1) ? "Carla:AudioOut1" : "Carla:AudioOut2"));
  252. connList.append(carla_strdup(strBuf));
  253. break;
  254. case RACK_GRAPH_CARLA_PORT_MIDI_IN:
  255. std::snprintf(strBuf, STR_MAX, "MidiIn:%s", midi.getName(true, otherPort.port));
  256. connList.append(carla_strdup(strBuf));
  257. connList.append(carla_strdup("Carla:MidiIn"));
  258. break;
  259. case RACK_GRAPH_CARLA_PORT_MIDI_OUT:
  260. std::snprintf(strBuf, STR_MAX, "MidiOut:%s", midi.getName(false, otherPort.port));
  261. connList.append(carla_strdup("Carla:MidiOut"));
  262. connList.append(carla_strdup(strBuf));
  263. break;
  264. }
  265. }
  266. const size_t connCount(connList.count());
  267. if (connCount == 0)
  268. return nullptr;
  269. const char** const retConns = new const char*[connCount+1];
  270. for (size_t i=0; i < connCount; ++i)
  271. {
  272. retConns[i] = connList.getAt(i, nullptr);
  273. if (retConns[i] == nullptr)
  274. retConns[i] = carla_strdup("(unknown)");
  275. }
  276. retConns[connCount] = nullptr;
  277. connList.clear();
  278. return retConns;
  279. }
  280. bool RackGraph::getPortIdFromFullName(const char* const fullPortName, uint& groupId, uint& portId) const
  281. {
  282. CARLA_SAFE_ASSERT_RETURN(fullPortName != nullptr && fullPortName[0] != '\0', false);
  283. int portTest;
  284. if (std::strncmp(fullPortName, "Carla:", 6) == 0)
  285. {
  286. groupId = RACK_GRAPH_GROUP_CARLA;
  287. portId = getCarlaRackPortIdFromName(fullPortName+6);
  288. CARLA_SAFE_ASSERT_RETURN(portId > RACK_GRAPH_CARLA_PORT_NULL && portId < RACK_GRAPH_CARLA_PORT_MAX, false);
  289. }
  290. else if (std::strncmp(fullPortName, "AudioIn:", 8) == 0)
  291. {
  292. groupId = RACK_GRAPH_GROUP_AUDIO_IN;
  293. portTest = std::atoi(fullPortName+8) - 1;
  294. CARLA_SAFE_ASSERT_RETURN(portTest >= 0, false);
  295. portId = static_cast<uint>(portTest);
  296. }
  297. else if (std::strncmp(fullPortName, "AudioOut:", 9) == 0)
  298. {
  299. groupId = RACK_GRAPH_GROUP_AUDIO_OUT;
  300. portTest = std::atoi(fullPortName+9) - 1;
  301. CARLA_SAFE_ASSERT_RETURN(portTest >= 0, false);
  302. portId = static_cast<uint>(portTest);
  303. }
  304. else if (std::strncmp(fullPortName, "MidiIn:", 7) == 0)
  305. {
  306. groupId = RACK_GRAPH_GROUP_MIDI_IN;
  307. //portId = std::atoi(fullPortName+7) - 1;
  308. }
  309. else if (std::strncmp(fullPortName, "MidiOut:", 8) == 0)
  310. {
  311. groupId = RACK_GRAPH_GROUP_MIDI_OUT;
  312. //portId = std::atoi(fullPortName+8) - 1;
  313. }
  314. else
  315. {
  316. return false;
  317. }
  318. return true;
  319. }
  320. // -----------------------------------------------------------------------
  321. // PatchbayGraph
  322. // TODO
  323. bool PatchbayGraph::connect(CarlaEngine* const engine, const uint /*groupA*/, const uint /*portA*/, const uint /*groupB*/, const uint /*portB*/) noexcept
  324. {
  325. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  326. return false;
  327. }
  328. bool PatchbayGraph::disconnect(CarlaEngine* const engine, const uint /*connectionId*/) noexcept
  329. {
  330. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  331. return false;
  332. }
  333. const char* const* PatchbayGraph::getConnections() const
  334. {
  335. return nullptr;
  336. }
  337. bool PatchbayGraph::getPortIdFromFullName(const char* const /*fillPortName*/, uint& /*groupId*/, uint& /*portId*/) const
  338. {
  339. return false;
  340. }
  341. #endif
  342. // -----------------------------------------------------------------------
  343. // CarlaEngine::ProtectedData
  344. CarlaEngine::ProtectedData::ProtectedData(CarlaEngine* const engine) noexcept
  345. : osc(engine),
  346. thread(engine),
  347. oscData(nullptr),
  348. callback(nullptr),
  349. callbackPtr(nullptr),
  350. fileCallback(nullptr),
  351. fileCallbackPtr(nullptr),
  352. hints(0x0),
  353. bufferSize(0),
  354. sampleRate(0.0),
  355. aboutToClose(false),
  356. curPluginCount(0),
  357. maxPluginNumber(0),
  358. nextPluginId(0),
  359. plugins(nullptr) {}
  360. CarlaEngine::ProtectedData::~ProtectedData() noexcept
  361. {
  362. CARLA_SAFE_ASSERT(curPluginCount == 0);
  363. CARLA_SAFE_ASSERT(maxPluginNumber == 0);
  364. CARLA_SAFE_ASSERT(nextPluginId == 0);
  365. CARLA_SAFE_ASSERT(plugins == nullptr);
  366. }
  367. // -----------------------------------------------------------------------
  368. void CarlaEngine::ProtectedData::doPluginRemove() noexcept
  369. {
  370. CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
  371. CARLA_SAFE_ASSERT_RETURN(nextAction.pluginId < curPluginCount,);
  372. --curPluginCount;
  373. // move all plugins 1 spot backwards
  374. for (uint i=nextAction.pluginId; i < curPluginCount; ++i)
  375. {
  376. CarlaPlugin* const plugin(plugins[i+1].plugin);
  377. CARLA_SAFE_ASSERT_BREAK(plugin != nullptr);
  378. plugin->setId(i);
  379. plugins[i].plugin = plugin;
  380. plugins[i].insPeak[0] = 0.0f;
  381. plugins[i].insPeak[1] = 0.0f;
  382. plugins[i].outsPeak[0] = 0.0f;
  383. plugins[i].outsPeak[1] = 0.0f;
  384. }
  385. const uint id(curPluginCount);
  386. // reset last plugin (now removed)
  387. plugins[id].plugin = nullptr;
  388. plugins[id].insPeak[0] = 0.0f;
  389. plugins[id].insPeak[1] = 0.0f;
  390. plugins[id].outsPeak[0] = 0.0f;
  391. plugins[id].outsPeak[1] = 0.0f;
  392. }
  393. void CarlaEngine::ProtectedData::doPluginsSwitch() noexcept
  394. {
  395. CARLA_SAFE_ASSERT_RETURN(curPluginCount >= 2,);
  396. const uint idA(nextAction.pluginId);
  397. const uint idB(nextAction.value);
  398. CARLA_SAFE_ASSERT_RETURN(idA < curPluginCount,);
  399. CARLA_SAFE_ASSERT_RETURN(idB < curPluginCount,);
  400. CARLA_SAFE_ASSERT_RETURN(plugins[idA].plugin != nullptr,);
  401. CARLA_SAFE_ASSERT_RETURN(plugins[idB].plugin != nullptr,);
  402. #if 0
  403. std::swap(plugins[idA].plugin, plugins[idB].plugin);
  404. #else
  405. CarlaPlugin* const tmp(plugins[idA].plugin);
  406. plugins[idA].plugin = plugins[idB].plugin;
  407. plugins[idB].plugin = tmp;
  408. #endif
  409. }
  410. void CarlaEngine::ProtectedData::doNextPluginAction(const bool unlock) noexcept
  411. {
  412. switch (nextAction.opcode)
  413. {
  414. case kEnginePostActionNull:
  415. break;
  416. case kEnginePostActionZeroCount:
  417. curPluginCount = 0;
  418. break;
  419. case kEnginePostActionRemovePlugin:
  420. doPluginRemove();
  421. break;
  422. case kEnginePostActionSwitchPlugins:
  423. doPluginsSwitch();
  424. break;
  425. }
  426. nextAction.opcode = kEnginePostActionNull;
  427. nextAction.pluginId = 0;
  428. nextAction.value = 0;
  429. if (unlock)
  430. {
  431. nextAction.mutex.tryLock();
  432. nextAction.mutex.unlock();
  433. }
  434. }
  435. // -----------------------------------------------------------------------
  436. #ifndef BUILD_BRIDGE
  437. void CarlaEngine::ProtectedData::processRack(const float* inBufReal[2], float* outBuf[2], const uint32_t frames, const bool isOffline)
  438. {
  439. CARLA_SAFE_ASSERT_RETURN(events.in != nullptr,);
  440. CARLA_SAFE_ASSERT_RETURN(events.out != nullptr,);
  441. // safe copy
  442. float inBuf0[frames];
  443. float inBuf1[frames];
  444. float* inBuf[2] = { inBuf0, inBuf1 };
  445. // initialize audio inputs
  446. FLOAT_COPY(inBuf0, inBufReal[0], frames);
  447. FLOAT_COPY(inBuf1, inBufReal[1], frames);
  448. // initialize audio outputs (zero)
  449. FLOAT_CLEAR(outBuf[0], frames);
  450. FLOAT_CLEAR(outBuf[1], frames);
  451. // initialize event outputs (zero)
  452. carla_zeroStruct<EngineEvent>(events.out, kMaxEngineEventInternalCount);
  453. bool processed = false;
  454. uint32_t oldAudioInCount = 0;
  455. uint32_t oldMidiOutCount = 0;
  456. // process plugins
  457. for (uint i=0; i < curPluginCount; ++i)
  458. {
  459. CarlaPlugin* const plugin = plugins[i].plugin;
  460. if (plugin == nullptr || ! plugin->isEnabled() || ! plugin->tryLock(isOffline))
  461. continue;
  462. if (processed)
  463. {
  464. // initialize audio inputs (from previous outputs)
  465. FLOAT_COPY(inBuf0, outBuf[0], frames);
  466. FLOAT_COPY(inBuf1, outBuf[1], frames);
  467. // initialize audio outputs (zero)
  468. FLOAT_CLEAR(outBuf[0], frames);
  469. FLOAT_CLEAR(outBuf[1], frames);
  470. // if plugin has no midi out, add previous events
  471. if (oldMidiOutCount == 0 && events.in[0].type != kEngineEventTypeNull)
  472. {
  473. if (events.out[0].type != kEngineEventTypeNull)
  474. {
  475. // TODO: carefully add to input, sorted events
  476. }
  477. // else nothing needed
  478. }
  479. else
  480. {
  481. // initialize event inputs from previous outputs
  482. carla_copyStruct<EngineEvent>(events.in, events.out, kMaxEngineEventInternalCount);
  483. // initialize event outputs (zero)
  484. carla_zeroStruct<EngineEvent>(events.out, kMaxEngineEventInternalCount);
  485. }
  486. }
  487. oldAudioInCount = plugin->getAudioInCount();
  488. oldMidiOutCount = plugin->getMidiOutCount();
  489. // process
  490. plugin->initBuffers();
  491. plugin->process(inBuf, outBuf, frames);
  492. plugin->unlock();
  493. // if plugin has no audio inputs, add input buffer
  494. if (oldAudioInCount == 0)
  495. {
  496. FLOAT_ADD(outBuf[0], inBuf0, frames);
  497. FLOAT_ADD(outBuf[1], inBuf1, frames);
  498. }
  499. // set peaks
  500. {
  501. EnginePluginData& pluginData(plugins[i]);
  502. #ifdef HAVE_JUCE
  503. juce::Range<float> range;
  504. if (oldAudioInCount > 0)
  505. {
  506. range = FloatVectorOperations::findMinAndMax(inBuf0, static_cast<int>(frames));
  507. pluginData.insPeak[0] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  508. range = FloatVectorOperations::findMinAndMax(inBuf1, static_cast<int>(frames));
  509. pluginData.insPeak[1] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  510. }
  511. else
  512. {
  513. pluginData.insPeak[0] = 0.0f;
  514. pluginData.insPeak[1] = 0.0f;
  515. }
  516. if (plugin->getAudioOutCount() > 0)
  517. {
  518. range = FloatVectorOperations::findMinAndMax(outBuf[0], static_cast<int>(frames));
  519. pluginData.outsPeak[0] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  520. range = FloatVectorOperations::findMinAndMax(outBuf[1], static_cast<int>(frames));
  521. pluginData.outsPeak[1] = carla_max<float>(std::abs(range.getStart()), std::abs(range.getEnd()), 1.0f);
  522. }
  523. else
  524. {
  525. pluginData.outsPeak[0] = 0.0f;
  526. pluginData.outsPeak[1] = 0.0f;
  527. }
  528. #else
  529. float peak1, peak2;
  530. if (oldAudioInCount > 0)
  531. {
  532. peak1 = peak2 = 0.0f;
  533. for (uint32_t k=0; k < frames; ++k)
  534. {
  535. peak1 = carla_max<float>(peak1, std::fabs(inBuf0[k]), 1.0f);
  536. peak2 = carla_max<float>(peak2, std::fabs(inBuf1[k]), 1.0f);
  537. }
  538. pluginData.insPeak[0] = peak1;
  539. pluginData.insPeak[1] = peak2;
  540. }
  541. else
  542. {
  543. pluginData.insPeak[0] = 0.0f;
  544. pluginData.insPeak[1] = 0.0f;
  545. }
  546. if (plugin->getAudioOutCount() > 0)
  547. {
  548. peak1 = peak2 = 0.0f;
  549. for (uint32_t k=0; k < frames; ++k)
  550. {
  551. peak1 = carla_max<float>(peak1, std::fabs(outBuf[0][k]), 1.0f);
  552. peak2 = carla_max<float>(peak2, std::fabs(outBuf[1][k]), 1.0f);
  553. }
  554. pluginData.outsPeak[0] = peak1;
  555. pluginData.outsPeak[1] = peak2;
  556. }
  557. else
  558. {
  559. pluginData.outsPeak[0] = 0.0f;
  560. pluginData.outsPeak[1] = 0.0f;
  561. }
  562. #endif
  563. }
  564. processed = true;
  565. }
  566. }
  567. void CarlaEngine::ProtectedData::processRackFull(const float* const* const inBuf, const uint32_t inCount, float* const* const outBuf, const uint32_t outCount, const uint32_t nframes, const bool isOffline)
  568. {
  569. RackGraph::Audio& rackAudio(graph.rack->audio);
  570. const CarlaMutexLocker _cml(rackAudio.mutex);
  571. if (inBuf != nullptr && inCount > 0)
  572. {
  573. bool noConnections = true;
  574. // connect input buffers
  575. for (LinkedList<uint>::Itenerator it = rackAudio.connectedIn1.begin(); it.valid(); it.next())
  576. {
  577. const uint& port(it.getValue());
  578. CARLA_SAFE_ASSERT_CONTINUE(port < inCount);
  579. if (noConnections)
  580. {
  581. FLOAT_COPY(audio.inBuf[0], inBuf[port], nframes);
  582. noConnections = false;
  583. }
  584. else
  585. {
  586. FLOAT_ADD(audio.inBuf[0], inBuf[port], nframes);
  587. }
  588. }
  589. if (noConnections)
  590. FLOAT_CLEAR(audio.inBuf[0], nframes);
  591. noConnections = true;
  592. for (LinkedList<uint>::Itenerator it = rackAudio.connectedIn2.begin(); it.valid(); it.next())
  593. {
  594. const uint& port(it.getValue());
  595. CARLA_SAFE_ASSERT_CONTINUE(port < inCount);
  596. if (noConnections)
  597. {
  598. FLOAT_COPY(audio.inBuf[1], inBuf[port], nframes);
  599. noConnections = false;
  600. }
  601. else
  602. {
  603. FLOAT_ADD(audio.inBuf[1], inBuf[port], nframes);
  604. }
  605. }
  606. if (noConnections)
  607. FLOAT_CLEAR(audio.inBuf[1], nframes);
  608. }
  609. else
  610. {
  611. FLOAT_CLEAR(audio.inBuf[0], nframes);
  612. FLOAT_CLEAR(audio.inBuf[1], nframes);
  613. }
  614. FLOAT_CLEAR(audio.outBuf[0], nframes);
  615. FLOAT_CLEAR(audio.outBuf[1], nframes);
  616. // process
  617. processRack(const_cast<const float**>(audio.inBuf), audio.outBuf, nframes, isOffline);
  618. // connect output buffers
  619. if (rackAudio.connectedOut1.count() != 0)
  620. {
  621. for (LinkedList<uint>::Itenerator it = rackAudio.connectedOut1.begin(); it.valid(); it.next())
  622. {
  623. const uint& port(it.getValue());
  624. CARLA_SAFE_ASSERT_CONTINUE(port < outCount);
  625. FLOAT_ADD(outBuf[port], audio.outBuf[0], nframes);
  626. }
  627. }
  628. if (rackAudio.connectedOut2.count() != 0)
  629. {
  630. for (LinkedList<uint>::Itenerator it = rackAudio.connectedOut2.begin(); it.valid(); it.next())
  631. {
  632. const uint& port(it.getValue());
  633. CARLA_SAFE_ASSERT_CONTINUE(port < outCount);
  634. FLOAT_ADD(outBuf[port], audio.outBuf[1], nframes);
  635. }
  636. }
  637. }
  638. #endif
  639. // -----------------------------------------------------------------------
  640. // ScopedActionLock
  641. ScopedActionLock::ScopedActionLock(CarlaEngine::ProtectedData* const data, const EnginePostAction action, const uint pluginId, const uint value, const bool lockWait) noexcept
  642. : fData(data)
  643. {
  644. fData->nextAction.mutex.lock();
  645. CARLA_SAFE_ASSERT_RETURN(fData->nextAction.opcode == kEnginePostActionNull,);
  646. fData->nextAction.opcode = action;
  647. fData->nextAction.pluginId = pluginId;
  648. fData->nextAction.value = value;
  649. if (lockWait)
  650. {
  651. // block wait for unlock on processing side
  652. carla_stdout("ScopedPluginAction(%i) - blocking START", pluginId);
  653. fData->nextAction.mutex.lock();
  654. carla_stdout("ScopedPluginAction(%i) - blocking DONE", pluginId);
  655. }
  656. else
  657. {
  658. fData->doNextPluginAction(false);
  659. }
  660. }
  661. ScopedActionLock::~ScopedActionLock() noexcept
  662. {
  663. fData->nextAction.mutex.unlock();
  664. }
  665. // -----------------------------------------------------------------------
  666. CARLA_BACKEND_END_NAMESPACE