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.

951 lines
32KB

  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. // -----------------------------------------------------------------------
  27. // Rack Patchbay stuff
  28. enum RackPatchbayGroupIds {
  29. RACK_PATCHBAY_GROUP_CARLA = 0,
  30. RACK_PATCHBAY_GROUP_AUDIO = 1,
  31. RACK_PATCHBAY_GROUP_MIDI = 2,
  32. RACK_PATCHBAY_GROUP_MAX = 3
  33. };
  34. enum RackPatchbayCarlaPortIds {
  35. RACK_PATCHBAY_CARLA_PORT_NULL = 0,
  36. RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1 = 1,
  37. RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2 = 2,
  38. RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1 = 3,
  39. RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2 = 4,
  40. RACK_PATCHBAY_CARLA_PORT_MIDI_IN = 5,
  41. RACK_PATCHBAY_CARLA_PORT_MIDI_OUT = 6,
  42. RACK_PATCHBAY_CARLA_PORT_MAX = 7
  43. };
  44. static inline
  45. int getCarlaRackPortIdFromName(const char* const shortname) noexcept
  46. {
  47. if (std::strcmp(shortname, "AudioIn1") == 0)
  48. return RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1;
  49. if (std::strcmp(shortname, "AudioIn2") == 0)
  50. return RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2;
  51. if (std::strcmp(shortname, "AudioOut1") == 0)
  52. return RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1;
  53. if (std::strcmp(shortname, "AudioOut2") == 0)
  54. return RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2;
  55. if (std::strcmp(shortname, "MidiIn") == 0)
  56. return RACK_PATCHBAY_CARLA_PORT_MIDI_IN;
  57. if (std::strcmp(shortname, "MidiOut") == 0)
  58. return RACK_PATCHBAY_CARLA_PORT_MIDI_OUT;
  59. return RACK_PATCHBAY_CARLA_PORT_NULL;
  60. }
  61. // -----------------------------------------------------------------------
  62. // RackGraph
  63. bool RackGraph::connect(CarlaEngine* const engine, const int groupA, const int portA, const int groupB, const int portB) noexcept
  64. {
  65. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  66. CARLA_SAFE_ASSERT_RETURN(groupA != groupB, false);
  67. CARLA_SAFE_ASSERT_RETURN(groupA >= RACK_PATCHBAY_GROUP_CARLA && groupA < RACK_PATCHBAY_GROUP_MAX, false);
  68. CARLA_SAFE_ASSERT_RETURN(groupB >= RACK_PATCHBAY_GROUP_CARLA && groupB < RACK_PATCHBAY_GROUP_MAX, false);
  69. CARLA_SAFE_ASSERT_RETURN(portA >= 0, false);
  70. CARLA_SAFE_ASSERT_RETURN(portB >= 0, false);
  71. int carlaPort, otherPort;
  72. if (groupA == RACK_PATCHBAY_GROUP_CARLA)
  73. {
  74. carlaPort = portA;
  75. otherPort = portB;
  76. }
  77. else
  78. {
  79. CARLA_SAFE_ASSERT_RETURN(groupB == RACK_PATCHBAY_GROUP_CARLA, false);
  80. carlaPort = portB;
  81. otherPort = portA;
  82. }
  83. bool makeConnection = false;
  84. switch (carlaPort)
  85. {
  86. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1:
  87. connectLock.enter();
  88. connectedIn1.append(otherPort);
  89. connectLock.leave();
  90. makeConnection = true;
  91. break;
  92. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2:
  93. connectLock.enter();
  94. connectedIn2.append(otherPort);
  95. connectLock.leave();
  96. makeConnection = true;
  97. break;
  98. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1:
  99. connectLock.enter();
  100. connectedOut1.append(otherPort);
  101. connectLock.leave();
  102. makeConnection = true;
  103. break;
  104. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2:
  105. connectLock.enter();
  106. connectedOut2.append(otherPort);
  107. connectLock.leave();
  108. makeConnection = true;
  109. break;
  110. case RACK_PATCHBAY_CARLA_PORT_MIDI_IN:
  111. makeConnection = engine->connectRackMidiInPort(otherPort);
  112. break;
  113. case RACK_PATCHBAY_CARLA_PORT_MIDI_OUT:
  114. makeConnection = engine->connectRackMidiOutPort(otherPort);
  115. break;
  116. }
  117. if (! makeConnection)
  118. {
  119. engine->setLastError("Invalid rack connection");
  120. return false;
  121. }
  122. ConnectionToId connectionToId;
  123. connectionToId.id = lastConnectionId;
  124. connectionToId.groupA = groupA;
  125. connectionToId.portA = portA;
  126. connectionToId.groupB = groupB;
  127. connectionToId.portB = portB;
  128. char strBuf[STR_MAX+1];
  129. strBuf[STR_MAX] = '\0';
  130. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", groupA, portA, groupB, portB);
  131. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  132. usedConnections.append(connectionToId);
  133. ++lastConnectionId;
  134. return true;
  135. }
  136. bool RackGraph::disconnect(CarlaEngine* const engine, const uint connectionId) noexcept
  137. {
  138. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  139. CARLA_SAFE_ASSERT_RETURN(usedConnections.count() > 0, false);
  140. for (LinkedList<ConnectionToId>::Itenerator it=usedConnections.begin(); it.valid(); it.next())
  141. {
  142. const ConnectionToId& connection(it.getValue());
  143. if (connection.id == connectionId)
  144. {
  145. int carlaPort, otherPort;
  146. if (connection.groupA == RACK_PATCHBAY_GROUP_CARLA)
  147. {
  148. carlaPort = connection.portA;
  149. otherPort = connection.portB;
  150. }
  151. else
  152. {
  153. CARLA_SAFE_ASSERT_RETURN(connection.groupB == RACK_PATCHBAY_GROUP_CARLA, false);
  154. carlaPort = connection.portB;
  155. otherPort = connection.portA;
  156. }
  157. switch (carlaPort)
  158. {
  159. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1:
  160. connectLock.enter();
  161. connectedIn1.removeAll(otherPort);
  162. connectLock.leave();
  163. break;
  164. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2:
  165. connectLock.enter();
  166. connectedIn2.removeAll(otherPort);
  167. connectLock.leave();
  168. break;
  169. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1:
  170. connectLock.enter();
  171. connectedOut1.removeAll(otherPort);
  172. connectLock.leave();
  173. break;
  174. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2:
  175. connectLock.enter();
  176. connectedOut2.removeAll(otherPort);
  177. connectLock.leave();
  178. break;
  179. case RACK_PATCHBAY_CARLA_PORT_MIDI_IN:
  180. engine->disconnectRackMidiInPort(otherPort);
  181. break;
  182. case RACK_PATCHBAY_CARLA_PORT_MIDI_OUT:
  183. engine->disconnectRackMidiOutPort(otherPort);
  184. break;
  185. default:
  186. engine->setLastError("Invalid connection");
  187. return false;
  188. }
  189. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connection.id, 0, 0, 0.0f, nullptr);
  190. usedConnections.remove(it);
  191. return true;
  192. }
  193. }
  194. engine->setLastError("Failed to find connection");
  195. return false;
  196. }
  197. void RackGraph::refresh(CarlaEngine* const engine, const char* const deviceName, const LinkedList<PortNameToId>& /*midiIns*/, const LinkedList<PortNameToId>& /*midiOuts*/) noexcept
  198. {
  199. CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
  200. lastConnectionId = 0;
  201. usedConnections.clear();
  202. char strBuf[STR_MAX+1];
  203. strBuf[STR_MAX] = '\0';
  204. // Main
  205. {
  206. engine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_CARLA, PATCHBAY_ICON_CARLA, -1, 0.0f, engine->getName());
  207. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_CARLA, RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in1");
  208. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_CARLA, RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in2");
  209. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_CARLA, RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out1");
  210. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_CARLA, RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out2");
  211. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_CARLA, RACK_PATCHBAY_CARLA_PORT_MIDI_IN, PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, "midi-in");
  212. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_CARLA, RACK_PATCHBAY_CARLA_PORT_MIDI_OUT, PATCHBAY_PORT_TYPE_MIDI, 0.0f, "midi-out");
  213. }
  214. // Audio In
  215. {
  216. if (deviceName != nullptr)
  217. std::snprintf(strBuf, STR_MAX, "Capture (%s)", deviceName);
  218. else
  219. std::strncpy(strBuf, "Capture", STR_MAX);
  220. engine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_AUDIO, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
  221. for (uint i=0; i < pData->audio.inCount; ++i)
  222. {
  223. std::snprintf(strBuf, STR_MAX, "capture_%i", i+1);
  224. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_AUDIO, static_cast<int>(i), PATCHBAY_PORT_TYPE_AUDIO, 0.0f, strBuf);
  225. }
  226. }
  227. // Audio Out
  228. {
  229. if (deviceName != nullptr)
  230. std::snprintf(strBuf, STR_MAX, "Playback (%s)", deviceName);
  231. else
  232. std::strncpy(strBuf, "Playback", STR_MAX);
  233. engine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_AUDIO, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
  234. for (uint i=0; i < pData->audio.outCount; ++i)
  235. {
  236. std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);
  237. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_AUDIO, static_cast<int>(i), PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, strBuf);
  238. }
  239. }
  240. // MIDI In
  241. {
  242. engine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_MIDI, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");
  243. for (uint i=0, count=fDummyMidiIn.getPortCount(); i < count; ++i)
  244. {
  245. PortNameToId portNameToId;
  246. portNameToId.portId = static_cast<int>(i);
  247. std::strncpy(portNameToId.name, fDummyMidiIn.getPortName(i).c_str(), STR_MAX);
  248. portNameToId.name[STR_MAX] = '\0';
  249. fUsedMidiIns.append(portNameToId);
  250. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_MIDI, portNameToId.portId, PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
  251. }
  252. }
  253. // MIDI Out
  254. {
  255. engine->callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_PATCHBAY_GROUP_MIDI, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");
  256. for (uint i=0, count=fDummyMidiOut.getPortCount(); i < count; ++i)
  257. {
  258. PortNameToId portNameToId;
  259. portNameToId.portId = static_cast<int>(i);
  260. std::strncpy(portNameToId.name, fDummyMidiOut.getPortName(i).c_str(), STR_MAX);
  261. portNameToId.name[STR_MAX] = '\0';
  262. fUsedMidiOuts.append(portNameToId);
  263. engine->callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_PATCHBAY_GROUP_MIDI, portNameToId.portId, PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
  264. }
  265. }
  266. // Connections
  267. connectLock.enter();
  268. for (LinkedList<int>::Itenerator it = connectedIn1.begin(); it.valid(); it.next())
  269. {
  270. const int& port(it.getValue());
  271. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(pData->audio.inCount));
  272. ConnectionToId connectionToId;
  273. connectionToId.id = lastConnectionId;
  274. connectionToId.groupOut = RACK_PATCHBAY_GROUP_AUDIO;
  275. connectionToId.portOut = port;
  276. connectionToId.groupIn = RACK_PATCHBAY_GROUP_CARLA;
  277. connectionToId.portIn = RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1;
  278. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupOut, connectionToId.portOut, connectionToId.groupIn, connectionToId.portIn);
  279. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  280. usedConnections.append(connectionToId);
  281. ++lastConnectionId;
  282. }
  283. for (LinkedList<int>::Itenerator it = connectedIn2.begin(); it.valid(); it.next())
  284. {
  285. const int& port(it.getValue());
  286. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(pData->audio.inCount));
  287. ConnectionToId connectionToId;
  288. connectionToId.id = lastConnectionId;
  289. connectionToId.groupOut = RACK_PATCHBAY_GROUP_AUDIO;
  290. connectionToId.portOut = port;
  291. connectionToId.groupIn = RACK_PATCHBAY_GROUP_CARLA;
  292. connectionToId.portIn = RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2;
  293. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupOut, connectionToId.portOut, connectionToId.groupIn, connectionToId.portIn);
  294. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  295. usedConnections.append(connectionToId);
  296. ++lastConnectionId;
  297. }
  298. for (LinkedList<int>::Itenerator it = connectedOut1.begin(); it.valid(); it.next())
  299. {
  300. const int& port(it.getValue());
  301. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(pData->audio.outCount));
  302. ConnectionToId connectionToId;
  303. connectionToId.id = lastConnectionId;
  304. connectionToId.groupOut = RACK_PATCHBAY_GROUP_CARLA;
  305. connectionToId.portOut = RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1;
  306. connectionToId.groupIn = RACK_PATCHBAY_GROUP_AUDIO;
  307. connectionToId.portIn = port;
  308. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupOut, connectionToId.portOut, connectionToId.groupIn, connectionToId.portIn);
  309. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  310. usedConnections.append(connectionToId);
  311. ++lastConnectionId;
  312. }
  313. for (LinkedList<int>::Itenerator it = connectedOut2.begin(); it.valid(); it.next())
  314. {
  315. const int& port(it.getValue());
  316. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(pData->audio.outCount));
  317. ConnectionToId connectionToId;
  318. connectionToId.id = lastConnectionId;
  319. connectionToId.groupOut = RACK_PATCHBAY_GROUP_CARLA;
  320. connectionToId.portOut = RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2;
  321. connectionToId.groupIn = RACK_PATCHBAY_GROUP_AUDIO;
  322. connectionToId.portIn = port;
  323. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupOut, connectionToId.portOut, connectionToId.groupIn, connectionToId.portIn);
  324. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  325. usedConnections.append(connectionToId);
  326. ++lastConnectionId;
  327. }
  328. connectLock.leave();
  329. for (LinkedList<MidiPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
  330. {
  331. const MidiPort& midiPort(it.getValue());
  332. ConnectionToId connectionToId;
  333. connectionToId.id = lastConnectionId;
  334. connectionToId.groupOut = RACK_PATCHBAY_GROUP_MIDI;
  335. connectionToId.portOut = midiPort.portId;
  336. connectionToId.groupIn = RACK_PATCHBAY_GROUP_CARLA;
  337. connectionToId.portIn = RACK_PATCHBAY_CARLA_PORT_MIDI_IN;
  338. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupOut, connectionToId.portOut, connectionToId.groupIn, connectionToId.portIn);
  339. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  340. usedConnections.append(connectionToId);
  341. ++lastConnectionId;
  342. }
  343. for (LinkedList<MidiPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
  344. {
  345. const MidiPort& midiPort(it.getValue());
  346. ConnectionToId connectionToId;
  347. connectionToId.id = lastConnectionId;
  348. connectionToId.groupOut = RACK_PATCHBAY_GROUP_CARLA;
  349. connectionToId.portOut = RACK_PATCHBAY_CARLA_PORT_MIDI_OUT;
  350. connectionToId.groupIn = RACK_PATCHBAY_GROUP_MIDI;
  351. connectionToId.portIn = midiPort.portId;
  352. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupOut, connectionToId.portOut, connectionToId.groupIn, connectionToId.portIn);
  353. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  354. usedConnections.append(connectionToId);
  355. ++lastConnectionId;
  356. }
  357. #if 0
  358. #endif
  359. }
  360. const char* const* RackGraph::getConnections() const
  361. {
  362. if (usedConnections.count() == 0)
  363. return nullptr;
  364. LinkedList<const char*> connList;
  365. char strBuf[STR_MAX+1];
  366. for (LinkedList<ConnectionToId>::Itenerator it=usedConnections.begin(); it.valid(); it.next())
  367. {
  368. const ConnectionToId& connection(it.getValue());
  369. CARLA_SAFE_ASSERT_CONTINUE(connection.groupA != connection.groupB);
  370. CARLA_SAFE_ASSERT_CONTINUE(connection.groupA >= RACK_PATCHBAY_GROUP_CARLA && connection.groupA < RACK_PATCHBAY_GROUP_MAX);
  371. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB >= RACK_PATCHBAY_GROUP_CARLA && connection.groupB < RACK_PATCHBAY_GROUP_MAX);
  372. CARLA_SAFE_ASSERT_CONTINUE(connection.portA >= 0);
  373. CARLA_SAFE_ASSERT_CONTINUE(connection.portB >= 0);
  374. int carlaPort, otherPort;
  375. if (connection.groupA == RACK_PATCHBAY_GROUP_CARLA)
  376. {
  377. carlaPort = connection.portA;
  378. otherPort = connection.portB;
  379. }
  380. else
  381. {
  382. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB == RACK_PATCHBAY_GROUP_CARLA);
  383. carlaPort = connection.portB;
  384. otherPort = connection.portA;
  385. }
  386. switch (carlaPort)
  387. {
  388. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1:
  389. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2:
  390. std::sprintf(strBuf, "AudioIn:%i", otherPort+1);
  391. connList.append(carla_strdup(strBuf));
  392. connList.append(carla_strdup((carlaPort == RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1) ? "Carla:AudioIn1" : "Carla:AudioIn2"));
  393. break;
  394. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1:
  395. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2:
  396. connList.append(carla_strdup((carlaPort == RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1) ? "Carla:AudioOut1" : "Carla:AudioOut2"));
  397. std::sprintf(strBuf, "AudioOut:%i", otherPort+1);
  398. connList.append(carla_strdup(strBuf));
  399. break;
  400. case RACK_PATCHBAY_CARLA_PORT_MIDI_IN:
  401. std::sprintf(strBuf, "MidiIn:%i", otherPort+1);
  402. connList.append(carla_strdup(strBuf));
  403. connList.append(carla_strdup("Carla:MidiIn"));
  404. break;
  405. case RACK_PATCHBAY_CARLA_PORT_MIDI_OUT:
  406. connList.append(carla_strdup("Carla:MidiOut"));
  407. std::sprintf(strBuf, "MidiOut:%i", otherPort+1);
  408. connList.append(carla_strdup(strBuf));
  409. break;
  410. }
  411. }
  412. const size_t connCount(connList.count());
  413. if (connCount == 0)
  414. return nullptr;
  415. const char** const retConns = new const char*[connCount+1];
  416. for (size_t i=0; i < connCount; ++i)
  417. retConns[i] = connList.getAt(i);
  418. retConns[connCount] = nullptr;
  419. connList.clear();
  420. return retConns;
  421. }
  422. // -----------------------------------------------------------------------
  423. // PatchbayGraph
  424. // TODO
  425. bool PatchbayGraph::connect(CarlaEngine* const engine, const int /*groupA*/, const int /*portA*/, const int /*groupB*/, const int /*portB*/) noexcept
  426. {
  427. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  428. return false;
  429. }
  430. bool PatchbayGraph::disconnect(CarlaEngine* const engine, const uint /*connectionId*/) noexcept
  431. {
  432. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  433. return false;
  434. }
  435. void PatchbayGraph::refresh(CarlaEngine* const engine, const LinkedList<PortNameToId>& /*midiIns*/, const LinkedList<PortNameToId>& /*midiOuts*/) noexcept
  436. {
  437. CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
  438. }
  439. const char* const* PatchbayGraph::getConnections() const
  440. {
  441. return nullptr;
  442. }
  443. // -----------------------------------------------------------------------
  444. // CarlaEngineProtectedData
  445. CarlaEngineProtectedData::CarlaEngineProtectedData(CarlaEngine* const engine) noexcept
  446. : osc(engine),
  447. thread(engine),
  448. oscData(nullptr),
  449. callback(nullptr),
  450. callbackPtr(nullptr),
  451. fileCallback(nullptr),
  452. fileCallbackPtr(nullptr),
  453. hints(0x0),
  454. bufferSize(0),
  455. sampleRate(0.0),
  456. aboutToClose(false),
  457. curPluginCount(0),
  458. maxPluginNumber(0),
  459. nextPluginId(0),
  460. plugins(nullptr) {}
  461. CarlaEngineProtectedData::~CarlaEngineProtectedData() noexcept
  462. {
  463. CARLA_SAFE_ASSERT(curPluginCount == 0);
  464. CARLA_SAFE_ASSERT(maxPluginNumber == 0);
  465. CARLA_SAFE_ASSERT(nextPluginId == 0);
  466. CARLA_SAFE_ASSERT(plugins == nullptr);
  467. }
  468. // -----------------------------------------------------------------------
  469. void CarlaEngineProtectedData::doPluginRemove() noexcept
  470. {
  471. CARLA_SAFE_ASSERT_RETURN(curPluginCount > 0,);
  472. CARLA_SAFE_ASSERT_RETURN(nextAction.pluginId < curPluginCount,);
  473. --curPluginCount;
  474. // move all plugins 1 spot backwards
  475. for (unsigned int i=nextAction.pluginId; i < curPluginCount; ++i)
  476. {
  477. CarlaPlugin* const plugin(plugins[i+1].plugin);
  478. CARLA_SAFE_ASSERT_BREAK(plugin != nullptr);
  479. plugin->setId(i);
  480. plugins[i].plugin = plugin;
  481. plugins[i].insPeak[0] = 0.0f;
  482. plugins[i].insPeak[1] = 0.0f;
  483. plugins[i].outsPeak[0] = 0.0f;
  484. plugins[i].outsPeak[1] = 0.0f;
  485. }
  486. const unsigned int id(curPluginCount);
  487. // reset last plugin (now removed)
  488. plugins[id].plugin = nullptr;
  489. plugins[id].insPeak[0] = 0.0f;
  490. plugins[id].insPeak[1] = 0.0f;
  491. plugins[id].outsPeak[0] = 0.0f;
  492. plugins[id].outsPeak[1] = 0.0f;
  493. }
  494. void CarlaEngineProtectedData::doPluginsSwitch() noexcept
  495. {
  496. CARLA_SAFE_ASSERT_RETURN(curPluginCount >= 2,);
  497. const unsigned int idA(nextAction.pluginId);
  498. const unsigned int idB(nextAction.value);
  499. CARLA_SAFE_ASSERT_RETURN(idA < curPluginCount,);
  500. CARLA_SAFE_ASSERT_RETURN(idB < curPluginCount,);
  501. CARLA_SAFE_ASSERT_RETURN(plugins[idA].plugin != nullptr,);
  502. CARLA_SAFE_ASSERT_RETURN(plugins[idB].plugin != nullptr,);
  503. #if 0
  504. std::swap(plugins[idA].plugin, plugins[idB].plugin);
  505. #else
  506. CarlaPlugin* const tmp(plugins[idA].plugin);
  507. plugins[idA].plugin = plugins[idB].plugin;
  508. plugins[idB].plugin = tmp;
  509. #endif
  510. }
  511. void CarlaEngineProtectedData::doNextPluginAction(const bool unlock) noexcept
  512. {
  513. switch (nextAction.opcode)
  514. {
  515. case kEnginePostActionNull:
  516. break;
  517. case kEnginePostActionZeroCount:
  518. curPluginCount = 0;
  519. break;
  520. case kEnginePostActionRemovePlugin:
  521. doPluginRemove();
  522. break;
  523. case kEnginePostActionSwitchPlugins:
  524. doPluginsSwitch();
  525. break;
  526. }
  527. nextAction.opcode = kEnginePostActionNull;
  528. nextAction.pluginId = 0;
  529. nextAction.value = 0;
  530. if (unlock)
  531. nextAction.mutex.unlock();
  532. }
  533. // -----------------------------------------------------------------------
  534. #ifndef BUILD_BRIDGE
  535. void CarlaEngineProtectedData::processRack(float* inBufReal[2], float* outBuf[2], const uint32_t frames, const bool isOffline)
  536. {
  537. CARLA_SAFE_ASSERT_RETURN(events.in != nullptr,);
  538. CARLA_SAFE_ASSERT_RETURN(events.out != nullptr,);
  539. // safe copy
  540. float inBuf0[frames];
  541. float inBuf1[frames];
  542. float* inBuf[2] = { inBuf0, inBuf1 };
  543. // initialize audio inputs
  544. FLOAT_COPY(inBuf0, inBufReal[0], frames);
  545. FLOAT_COPY(inBuf1, inBufReal[1], frames);
  546. // initialize audio outputs (zero)
  547. FLOAT_CLEAR(outBuf[0], frames);
  548. FLOAT_CLEAR(outBuf[1], frames);
  549. // initialize event outputs (zero)
  550. carla_zeroStruct<EngineEvent>(events.out, kMaxEngineEventInternalCount);
  551. bool processed = false;
  552. uint32_t oldAudioInCount = 0;
  553. uint32_t oldMidiOutCount = 0;
  554. // process plugins
  555. for (unsigned int i=0; i < curPluginCount; ++i)
  556. {
  557. CarlaPlugin* const plugin = plugins[i].plugin;
  558. if (plugin == nullptr || ! plugin->isEnabled() || ! plugin->tryLock(isOffline))
  559. continue;
  560. if (processed)
  561. {
  562. // initialize audio inputs (from previous outputs)
  563. FLOAT_COPY(inBuf0, outBuf[0], frames);
  564. FLOAT_COPY(inBuf1, outBuf[1], frames);
  565. // initialize audio outputs (zero)
  566. FLOAT_CLEAR(outBuf[0], frames);
  567. FLOAT_CLEAR(outBuf[1], frames);
  568. // if plugin has no midi out, add previous events
  569. if (oldMidiOutCount == 0 && events.in[0].type != kEngineEventTypeNull)
  570. {
  571. if (events.out[0].type != kEngineEventTypeNull)
  572. {
  573. // TODO: carefully add to input, sorted events
  574. }
  575. // else nothing needed
  576. }
  577. else
  578. {
  579. // initialize event inputs from previous outputs
  580. carla_copyStruct<EngineEvent>(events.in, events.out, kMaxEngineEventInternalCount);
  581. // initialize event outputs (zero)
  582. carla_zeroStruct<EngineEvent>(events.out, kMaxEngineEventInternalCount);
  583. }
  584. }
  585. oldAudioInCount = plugin->getAudioInCount();
  586. oldMidiOutCount = plugin->getMidiOutCount();
  587. // process
  588. plugin->initBuffers();
  589. plugin->process(inBuf, outBuf, frames);
  590. plugin->unlock();
  591. // if plugin has no audio inputs, add input buffer
  592. if (oldAudioInCount == 0)
  593. {
  594. FLOAT_ADD(outBuf[0], inBuf0, frames);
  595. FLOAT_ADD(outBuf[1], inBuf1, frames);
  596. }
  597. // set peaks
  598. {
  599. EnginePluginData& pluginData(plugins[i]);
  600. #ifdef HAVE_JUCE
  601. float tmpMin, tmpMax;
  602. if (oldAudioInCount > 0)
  603. {
  604. FloatVectorOperations::findMinAndMax(inBuf0, static_cast<int>(frames), tmpMin, tmpMax);
  605. pluginData.insPeak[0] = carla_max<float>(std::abs(tmpMin), std::abs(tmpMax), 1.0f);
  606. FloatVectorOperations::findMinAndMax(inBuf1, static_cast<int>(frames), tmpMin, tmpMax);
  607. pluginData.insPeak[1] = carla_max<float>(std::abs(tmpMin), std::abs(tmpMax), 1.0f);
  608. }
  609. else
  610. {
  611. pluginData.insPeak[0] = 0.0f;
  612. pluginData.insPeak[1] = 0.0f;
  613. }
  614. if (plugin->getAudioOutCount() > 0)
  615. {
  616. FloatVectorOperations::findMinAndMax(outBuf[0], static_cast<int>(frames), tmpMin, tmpMax);
  617. pluginData.outsPeak[0] = carla_max<float>(std::abs(tmpMin), std::abs(tmpMax), 1.0f);
  618. FloatVectorOperations::findMinAndMax(outBuf[1], static_cast<int>(frames), tmpMin, tmpMax);
  619. pluginData.outsPeak[1] = carla_max<float>(std::abs(tmpMin), std::abs(tmpMax), 1.0f);
  620. }
  621. else
  622. {
  623. pluginData.outsPeak[0] = 0.0f;
  624. pluginData.outsPeak[1] = 0.0f;
  625. }
  626. #else
  627. float peak1, peak2;
  628. if (oldAudioInCount > 0)
  629. {
  630. peak1 = peak2 = 0.0f;
  631. for (uint32_t k=0; k < frames; ++k)
  632. {
  633. peak1 = carla_max<float>(peak1, std::fabs(inBuf0[k]), 1.0f);
  634. peak2 = carla_max<float>(peak2, std::fabs(inBuf1[k]), 1.0f);
  635. }
  636. pluginData.insPeak[0] = peak1;
  637. pluginData.insPeak[1] = peak2;
  638. }
  639. else
  640. {
  641. pluginData.insPeak[0] = 0.0f;
  642. pluginData.insPeak[1] = 0.0f;
  643. }
  644. if (plugin->getAudioOutCount() > 0)
  645. {
  646. peak1 = peak2 = 0.0f;
  647. for (uint32_t k=0; k < frames; ++k)
  648. {
  649. peak1 = carla_max<float>(peak1, std::fabs(outBuf[0][k]), 1.0f);
  650. peak2 = carla_max<float>(peak2, std::fabs(outBuf[1][k]), 1.0f);
  651. }
  652. pluginData.outsPeak[0] = peak1;
  653. pluginData.outsPeak[1] = peak2;
  654. }
  655. else
  656. {
  657. pluginData.outsPeak[0] = 0.0f;
  658. pluginData.outsPeak[1] = 0.0f;
  659. }
  660. #endif
  661. }
  662. processed = true;
  663. }
  664. }
  665. void CarlaEngineProtectedData::processRackFull(float** const inBuf, const uint32_t inCount, float** const outBuf, const uint32_t outCount, const uint32_t nframes, const bool isOffline)
  666. {
  667. const CarlaCriticalSectionScope _cs(graph.rack->connectLock);
  668. // connect input buffers
  669. if (graph.rack->connectedIn1.count() == 0)
  670. {
  671. FLOAT_CLEAR(audio.inBuf[0], nframes);
  672. }
  673. else
  674. {
  675. bool first = true;
  676. for (LinkedList<int>::Itenerator it = graph.rack->connectedIn1.begin(); it.valid(); it.next())
  677. {
  678. const int& port(it.getValue());
  679. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(inCount));
  680. if (first)
  681. {
  682. FLOAT_COPY(audio.inBuf[0], inBuf[port], nframes);
  683. first = false;
  684. }
  685. else
  686. {
  687. FLOAT_ADD(audio.inBuf[0], inBuf[port], nframes);
  688. }
  689. }
  690. if (first)
  691. FLOAT_CLEAR(audio.inBuf[0], nframes);
  692. }
  693. if (graph.rack->connectedIn2.count() == 0)
  694. {
  695. FLOAT_CLEAR(audio.inBuf[1], nframes);
  696. }
  697. else
  698. {
  699. bool first = true;
  700. for (LinkedList<int>::Itenerator it = graph.rack->connectedIn2.begin(); it.valid(); it.next())
  701. {
  702. const int& port(it.getValue());
  703. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(inCount));
  704. if (first)
  705. {
  706. FLOAT_COPY(audio.inBuf[1], inBuf[port], nframes);
  707. first = false;
  708. }
  709. else
  710. {
  711. FLOAT_ADD(audio.inBuf[1], inBuf[port], nframes);
  712. }
  713. }
  714. if (first)
  715. FLOAT_CLEAR(audio.inBuf[1], nframes);
  716. }
  717. FLOAT_CLEAR(audio.outBuf[0], nframes);
  718. FLOAT_CLEAR(audio.outBuf[1], nframes);
  719. // process
  720. processRack(audio.inBuf, audio.outBuf, nframes, isOffline);
  721. // connect output buffers
  722. if (graph.rack->connectedOut1.count() != 0)
  723. {
  724. for (LinkedList<int>::Itenerator it = graph.rack->connectedOut1.begin(); it.valid(); it.next())
  725. {
  726. const int& port(it.getValue());
  727. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(outCount));
  728. FLOAT_ADD(outBuf[port], audio.outBuf[0], nframes);
  729. }
  730. }
  731. if (graph.rack->connectedOut2.count() != 0)
  732. {
  733. for (LinkedList<int>::Itenerator it = graph.rack->connectedOut2.begin(); it.valid(); it.next())
  734. {
  735. const int& port(it.getValue());
  736. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(outCount));
  737. FLOAT_ADD(outBuf[port], audio.outBuf[1], nframes);
  738. }
  739. }
  740. }
  741. #endif
  742. // -----------------------------------------------------------------------
  743. // ScopedActionLock
  744. ScopedActionLock::ScopedActionLock(CarlaEngineProtectedData* const data, const EnginePostAction action, const uint pluginId, const uint value, const bool lockWait) noexcept
  745. : fData(data)
  746. {
  747. fData->nextAction.mutex.lock();
  748. CARLA_SAFE_ASSERT_RETURN(fData->nextAction.opcode == kEnginePostActionNull,);
  749. fData->nextAction.opcode = action;
  750. fData->nextAction.pluginId = pluginId;
  751. fData->nextAction.value = value;
  752. if (lockWait)
  753. {
  754. // block wait for unlock on processing side
  755. carla_stdout("ScopedPluginAction(%i) - blocking START", pluginId);
  756. fData->nextAction.mutex.lock();
  757. carla_stdout("ScopedPluginAction(%i) - blocking DONE", pluginId);
  758. }
  759. else
  760. {
  761. fData->doNextPluginAction(false);
  762. }
  763. }
  764. ScopedActionLock::~ScopedActionLock() noexcept
  765. {
  766. fData->nextAction.mutex.unlock();
  767. }
  768. // -----------------------------------------------------------------------
  769. CARLA_BACKEND_END_NAMESPACE