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.

823 lines
26KB

  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