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.

810 lines
25KB

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