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

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