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.

528 lines
15KB

  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. #ifdef BUILD_BRIDGE
  18. # error This file should not be compiled if building bridge
  19. #endif
  20. #include "CarlaEngineInternal.hpp"
  21. #include "LinkedList.hpp"
  22. #ifdef HAVE_JUCE
  23. # include "juce_audio_basics.h"
  24. using juce::FloatVectorOperations;
  25. #endif
  26. // -----------------------------------------------------------------------
  27. CARLA_BACKEND_START_NAMESPACE
  28. #if 0
  29. } // Fix editor indentation
  30. #endif
  31. // -----------------------------------------------------------------------
  32. struct EngineRackBuffers {
  33. float* in[2];
  34. float* out[2];
  35. // connections stuff
  36. LinkedList<uint> connectedIns[2];
  37. LinkedList<uint> connectedOuts[2];
  38. CarlaMutex connectLock;
  39. int lastConnectionId;
  40. LinkedList<ConnectionToId> usedConnections;
  41. EngineRackBuffers(const uint32_t bufferSize);
  42. ~EngineRackBuffers();
  43. void clear();
  44. void resize(const uint32_t bufferSize);
  45. };
  46. // -----------------------------------------------------------------------
  47. struct EnginePatchbayBuffers {
  48. // TODO
  49. EnginePatchbayBuffers(const uint32_t bufferSize);
  50. ~EnginePatchbayBuffers();
  51. void clear();
  52. void resize(const uint32_t bufferSize);
  53. };
  54. // -----------------------------------------------------------------------
  55. // EngineRackBuffers
  56. EngineRackBuffers::EngineRackBuffers(const uint32_t bufferSize)
  57. : lastConnectionId(0)
  58. {
  59. resize(bufferSize);
  60. }
  61. EngineRackBuffers::~EngineRackBuffers()
  62. {
  63. clear();
  64. }
  65. void EngineRackBuffers::clear()
  66. {
  67. lastConnectionId = 0;
  68. if (in[0] != nullptr)
  69. {
  70. delete[] in[0];
  71. in[0] = nullptr;
  72. }
  73. if (in[1] != nullptr)
  74. {
  75. delete[] in[1];
  76. in[1] = nullptr;
  77. }
  78. if (out[0] != nullptr)
  79. {
  80. delete[] out[0];
  81. out[0] = nullptr;
  82. }
  83. if (out[1] != nullptr)
  84. {
  85. delete[] out[1];
  86. out[1] = nullptr;
  87. }
  88. connectedIns[0].clear();
  89. connectedIns[1].clear();
  90. connectedOuts[0].clear();
  91. connectedOuts[1].clear();
  92. usedConnections.clear();
  93. }
  94. void EngineRackBuffers::resize(const uint32_t bufferSize)
  95. {
  96. if (bufferSize > 0)
  97. {
  98. in[0] = new float[bufferSize];
  99. in[1] = new float[bufferSize];
  100. out[0] = new float[bufferSize];
  101. out[1] = new float[bufferSize];
  102. }
  103. else
  104. {
  105. in[0] = nullptr;
  106. in[1] = nullptr;
  107. out[0] = nullptr;
  108. out[1] = nullptr;
  109. }
  110. }
  111. // -----------------------------------------------------------------------
  112. // EnginePatchbayBuffers
  113. EnginePatchbayBuffers::EnginePatchbayBuffers(const uint32_t bufferSize)
  114. {
  115. resize(bufferSize);
  116. }
  117. EnginePatchbayBuffers::~EnginePatchbayBuffers()
  118. {
  119. clear();
  120. }
  121. void EnginePatchbayBuffers::clear()
  122. {
  123. }
  124. void EnginePatchbayBuffers::resize(const uint32_t /*bufferSize*/)
  125. {
  126. }
  127. // -----------------------------------------------------------------------
  128. // InternalAudio
  129. InternalAudio::InternalAudio() noexcept
  130. : isReady(false),
  131. usePatchbay(false),
  132. inCount(0),
  133. outCount(0)
  134. {
  135. rack = nullptr;
  136. }
  137. InternalAudio::~InternalAudio() noexcept
  138. {
  139. CARLA_ASSERT(! isReady);
  140. CARLA_ASSERT(rack == nullptr);
  141. }
  142. void InternalAudio::initPatchbay() noexcept
  143. {
  144. if (usePatchbay)
  145. {
  146. CARLA_SAFE_ASSERT_RETURN(patchbay != nullptr,);
  147. }
  148. else
  149. {
  150. CARLA_SAFE_ASSERT_RETURN(rack != nullptr,);
  151. rack->lastConnectionId = 0;
  152. rack->usedConnections.clear();
  153. }
  154. }
  155. void InternalAudio::clear()
  156. {
  157. isReady = false;
  158. inCount = 0;
  159. outCount = 0;
  160. if (usePatchbay)
  161. {
  162. CARLA_SAFE_ASSERT_RETURN(patchbay != nullptr,);
  163. delete patchbay;
  164. patchbay = nullptr;
  165. }
  166. else
  167. {
  168. CARLA_SAFE_ASSERT_RETURN(rack != nullptr,);
  169. delete rack;
  170. rack = nullptr;
  171. }
  172. }
  173. void InternalAudio::create(const uint32_t bufferSize)
  174. {
  175. if (usePatchbay)
  176. {
  177. CARLA_SAFE_ASSERT_RETURN(patchbay == nullptr,);
  178. patchbay = new EnginePatchbayBuffers(bufferSize);
  179. }
  180. else
  181. {
  182. CARLA_SAFE_ASSERT_RETURN(rack == nullptr,);
  183. rack = new EngineRackBuffers(bufferSize);
  184. }
  185. isReady = true;
  186. }
  187. void InternalAudio::resize(const uint32_t bufferSize)
  188. {
  189. if (usePatchbay)
  190. {
  191. CARLA_SAFE_ASSERT_RETURN(patchbay != nullptr,);
  192. patchbay->resize(bufferSize);
  193. }
  194. else
  195. {
  196. CARLA_SAFE_ASSERT_RETURN(rack != nullptr,);
  197. rack->resize(bufferSize);
  198. }
  199. }
  200. void CarlaEngineProtectedData::processRackFull(float** const inBuf, const uint32_t inCount, float** const outBuf, const uint32_t outCount, const uint32_t nframes, const bool isOffline)
  201. {
  202. EngineRackBuffers* const rack(bufAudio.rack);
  203. const CarlaMutex::ScopedLocker sl(rack->connectLock);
  204. // connect input buffers
  205. if (rack->connectedIns[0].count() == 0)
  206. {
  207. FLOAT_CLEAR(rack->in[0], nframes);
  208. }
  209. else
  210. {
  211. bool first = true;
  212. for (LinkedList<uint>::Itenerator it = rack->connectedIns[0].begin(); it.valid(); it.next())
  213. {
  214. const uint& port(it.getValue());
  215. CARLA_SAFE_ASSERT_CONTINUE(port < inCount);
  216. if (first)
  217. {
  218. FLOAT_COPY(rack->in[0], inBuf[port], nframes);
  219. first = false;
  220. }
  221. else
  222. {
  223. FLOAT_ADD(rack->in[0], inBuf[port], nframes);
  224. }
  225. }
  226. if (first)
  227. FLOAT_CLEAR(rack->in[0], nframes);
  228. }
  229. if (rack->connectedIns[1].count() == 0)
  230. {
  231. FLOAT_CLEAR(rack->in[1], nframes);
  232. }
  233. else
  234. {
  235. bool first = true;
  236. for (LinkedList<uint>::Itenerator it = rack->connectedIns[1].begin(); it.valid(); it.next())
  237. {
  238. const uint& port(it.getValue());
  239. CARLA_SAFE_ASSERT_CONTINUE(port < inCount);
  240. if (first)
  241. {
  242. FLOAT_COPY(rack->in[1], inBuf[port], nframes);
  243. first = false;
  244. }
  245. else
  246. {
  247. FLOAT_ADD(rack->in[1], inBuf[port], nframes);
  248. }
  249. }
  250. if (first)
  251. FLOAT_CLEAR(rack->in[1], nframes);
  252. }
  253. FLOAT_CLEAR(rack->out[0], nframes);
  254. FLOAT_CLEAR(rack->out[1], nframes);
  255. // process
  256. processRack(rack->in, rack->out, nframes, isOffline);
  257. // connect output buffers
  258. if (rack->connectedOuts[0].count() != 0)
  259. {
  260. for (LinkedList<uint>::Itenerator it = rack->connectedOuts[0].begin(); it.valid(); it.next())
  261. {
  262. const uint& port(it.getValue());
  263. CARLA_SAFE_ASSERT_CONTINUE(port < outCount);
  264. FLOAT_ADD(outBuf[port], rack->out[0], nframes);
  265. }
  266. }
  267. if (rack->connectedOuts[1].count() != 0)
  268. {
  269. for (LinkedList<uint>::Itenerator it = rack->connectedOuts[1].begin(); it.valid(); it.next())
  270. {
  271. const uint& port(it.getValue());
  272. CARLA_SAFE_ASSERT_CONTINUE(port < outCount);
  273. FLOAT_ADD(outBuf[port], rack->out[1], nframes);
  274. }
  275. }
  276. }
  277. // -----------------------------------------------------------------------
  278. // Patchbay
  279. bool CarlaEngine::patchbayConnect(const int portA, const int portB)
  280. {
  281. CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
  282. CARLA_SAFE_ASSERT_RETURN(pData->bufAudio.isReady, false);
  283. carla_debug("CarlaEngineRtAudio::patchbayConnect(%i, %i)", portA, portB);
  284. if (pData->bufAudio.usePatchbay)
  285. {
  286. // not implemented yet
  287. return false;
  288. }
  289. EngineRackBuffers* const rack(pData->bufAudio.rack);
  290. CARLA_SAFE_ASSERT_RETURN_ERR(portA > RACK_PATCHBAY_PORT_MAX, "Invalid output port");
  291. CARLA_SAFE_ASSERT_RETURN_ERR(portB > RACK_PATCHBAY_PORT_MAX, "Invalid input port");
  292. // only allow connections between Carla and other ports
  293. if (portA < 0 && portB < 0)
  294. {
  295. setLastError("Invalid connection (1)");
  296. return false;
  297. }
  298. if (portA >= 0 && portB >= 0)
  299. {
  300. setLastError("Invalid connection (2)");
  301. return false;
  302. }
  303. const int carlaPort = (portA < 0) ? portA : portB;
  304. const int targetPort = (carlaPort == portA) ? portB : portA;
  305. bool makeConnection = false;
  306. switch (carlaPort)
  307. {
  308. case RACK_PATCHBAY_PORT_AUDIO_IN1:
  309. CARLA_SAFE_ASSERT_BREAK(targetPort >= RACK_PATCHBAY_GROUP_AUDIO_IN*1000);
  310. CARLA_SAFE_ASSERT_BREAK(targetPort <= RACK_PATCHBAY_GROUP_AUDIO_IN*1000+999);
  311. rack->connectLock.lock();
  312. rack->connectedIns[0].append(targetPort - RACK_PATCHBAY_GROUP_AUDIO_IN*1000);
  313. rack->connectLock.unlock();
  314. makeConnection = true;
  315. break;
  316. case RACK_PATCHBAY_PORT_AUDIO_IN2:
  317. CARLA_SAFE_ASSERT_BREAK(targetPort >= RACK_PATCHBAY_GROUP_AUDIO_IN*1000);
  318. CARLA_SAFE_ASSERT_BREAK(targetPort <= RACK_PATCHBAY_GROUP_AUDIO_IN*1000+999);
  319. rack->connectLock.lock();
  320. rack->connectedIns[1].append(targetPort - RACK_PATCHBAY_GROUP_AUDIO_IN*1000);
  321. rack->connectLock.unlock();
  322. makeConnection = true;
  323. break;
  324. case RACK_PATCHBAY_PORT_AUDIO_OUT1:
  325. CARLA_SAFE_ASSERT_BREAK(targetPort >= RACK_PATCHBAY_GROUP_AUDIO_OUT*1000);
  326. CARLA_SAFE_ASSERT_BREAK(targetPort <= RACK_PATCHBAY_GROUP_AUDIO_OUT*1000+999);
  327. rack->connectLock.lock();
  328. rack->connectedOuts[0].append(targetPort - RACK_PATCHBAY_GROUP_AUDIO_OUT*1000);
  329. rack->connectLock.unlock();
  330. makeConnection = true;
  331. break;
  332. case RACK_PATCHBAY_PORT_AUDIO_OUT2:
  333. CARLA_SAFE_ASSERT_BREAK(targetPort >= RACK_PATCHBAY_GROUP_AUDIO_OUT*1000);
  334. CARLA_SAFE_ASSERT_BREAK(targetPort <= RACK_PATCHBAY_GROUP_AUDIO_OUT*1000+999);
  335. rack->connectLock.lock();
  336. rack->connectedOuts[1].append(targetPort - RACK_PATCHBAY_GROUP_AUDIO_OUT*1000);
  337. rack->connectLock.unlock();
  338. makeConnection = true;
  339. break;
  340. case RACK_PATCHBAY_PORT_MIDI_IN:
  341. CARLA_SAFE_ASSERT_BREAK(targetPort >= RACK_PATCHBAY_GROUP_MIDI_IN*1000);
  342. CARLA_SAFE_ASSERT_BREAK(targetPort <= RACK_PATCHBAY_GROUP_MIDI_IN*1000+999);
  343. makeConnection = connectRackMidiInPort(targetPort - RACK_PATCHBAY_GROUP_MIDI_IN*1000);
  344. break;
  345. case RACK_PATCHBAY_PORT_MIDI_OUT:
  346. CARLA_SAFE_ASSERT_BREAK(targetPort >= RACK_PATCHBAY_GROUP_MIDI_OUT*1000);
  347. CARLA_SAFE_ASSERT_BREAK(targetPort <= RACK_PATCHBAY_GROUP_MIDI_OUT*1000+999);
  348. makeConnection = connectRackMidiOutPort(targetPort - RACK_PATCHBAY_GROUP_MIDI_OUT*1000);
  349. break;
  350. }
  351. if (! makeConnection)
  352. {
  353. setLastError("Invalid connection (3)");
  354. return false;
  355. }
  356. ConnectionToId connectionToId;
  357. connectionToId.id = rack->lastConnectionId;
  358. connectionToId.portOut = portA;
  359. connectionToId.portIn = portB;
  360. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, rack->lastConnectionId, portA, portB, 0.0f, nullptr);
  361. rack->usedConnections.append(connectionToId);
  362. rack->lastConnectionId++;
  363. return true;
  364. }
  365. bool CarlaEngine::patchbayDisconnect(const int connectionId)
  366. {
  367. CARLA_SAFE_ASSERT_RETURN(pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY, false);
  368. CARLA_SAFE_ASSERT_RETURN(pData->bufAudio.isReady, false);
  369. carla_debug("CarlaEngineRtAudio::patchbayDisconnect(%i)", connectionId);
  370. if (pData->bufAudio.usePatchbay)
  371. {
  372. // not implemented yet
  373. return false;
  374. }
  375. EngineRackBuffers* const rack(pData->bufAudio.rack);
  376. CARLA_SAFE_ASSERT_RETURN_ERR(rack->usedConnections.count() > 0, "No connections available");
  377. for (LinkedList<ConnectionToId>::Itenerator it=rack->usedConnections.begin(); it.valid(); it.next())
  378. {
  379. const ConnectionToId& connection(it.getValue());
  380. if (connection.id == connectionId)
  381. {
  382. const int targetPort((connection.portOut >= 0) ? connection.portOut : connection.portIn);
  383. const int carlaPort((targetPort == connection.portOut) ? connection.portIn : connection.portOut);
  384. if (targetPort >= RACK_PATCHBAY_GROUP_MIDI_OUT*1000)
  385. {
  386. const int portId(targetPort-RACK_PATCHBAY_GROUP_MIDI_OUT*1000);
  387. disconnectRackMidiInPort(portId);
  388. }
  389. else if (targetPort >= RACK_PATCHBAY_GROUP_MIDI_IN*1000)
  390. {
  391. const int portId(targetPort-RACK_PATCHBAY_GROUP_MIDI_IN*1000);
  392. disconnectRackMidiOutPort(portId);
  393. }
  394. else if (targetPort >= RACK_PATCHBAY_GROUP_AUDIO_OUT*1000)
  395. {
  396. CARLA_SAFE_ASSERT_RETURN(carlaPort == RACK_PATCHBAY_PORT_AUDIO_OUT1 || carlaPort == RACK_PATCHBAY_PORT_AUDIO_OUT2, false);
  397. const int portId(targetPort-RACK_PATCHBAY_GROUP_AUDIO_OUT*1000);
  398. rack->connectLock.lock();
  399. if (carlaPort == RACK_PATCHBAY_PORT_AUDIO_OUT1)
  400. rack->connectedOuts[0].removeAll(portId);
  401. else
  402. rack->connectedOuts[1].removeAll(portId);
  403. rack->connectLock.unlock();
  404. }
  405. else if (targetPort >= RACK_PATCHBAY_GROUP_AUDIO_IN*1000)
  406. {
  407. CARLA_SAFE_ASSERT_RETURN(carlaPort == RACK_PATCHBAY_PORT_AUDIO_IN1 || carlaPort == RACK_PATCHBAY_PORT_AUDIO_IN2, false);
  408. const int portId(targetPort-RACK_PATCHBAY_GROUP_AUDIO_IN*1000);
  409. rack->connectLock.lock();
  410. if (carlaPort == RACK_PATCHBAY_PORT_AUDIO_IN1)
  411. rack->connectedIns[0].removeAll(portId);
  412. else
  413. rack->connectedIns[1].removeAll(portId);
  414. rack->connectLock.unlock();
  415. }
  416. else
  417. {
  418. CARLA_SAFE_ASSERT_RETURN(false, false);
  419. }
  420. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED, connection.id, connection.portOut, connection.portIn, 0.0f, nullptr);
  421. rack->usedConnections.remove(it);
  422. break;
  423. }
  424. }
  425. return true;
  426. }
  427. bool CarlaEngine::patchbayRefresh()
  428. {
  429. setLastError("Unsupported operation");
  430. return false;
  431. }
  432. // -----------------------------------------------------------------------
  433. CARLA_BACKEND_END_NAMESPACE