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.

963 lines
33KB

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