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.

434 lines
12KB

  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. struct PortNameToId {
  45. int portId;
  46. char name[STR_MAX+1];
  47. };
  48. struct ConnectionToId {
  49. uint id;
  50. int groupA;
  51. int portA;
  52. int groupB;
  53. int portB;
  54. };
  55. static inline
  56. int getCarlaRackPortIdFromName(const char* const shortname) noexcept
  57. {
  58. if (std::strcmp(shortname, "AudioIn1") == 0)
  59. return RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1;
  60. if (std::strcmp(shortname, "AudioIn2") == 0)
  61. return RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2;
  62. if (std::strcmp(shortname, "AudioOut1") == 0)
  63. return RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1;
  64. if (std::strcmp(shortname, "AudioOut2") == 0)
  65. return RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2;
  66. if (std::strcmp(shortname, "MidiIn") == 0)
  67. return RACK_PATCHBAY_CARLA_PORT_MIDI_IN;
  68. if (std::strcmp(shortname, "MidiOut") == 0)
  69. return RACK_PATCHBAY_CARLA_PORT_MIDI_OUT;
  70. return RACK_PATCHBAY_CARLA_PORT_NULL;
  71. }
  72. // -----------------------------------------------------------------------
  73. // EngineRackBuffers
  74. struct EngineRackBuffers {
  75. float* in[2];
  76. float* out[2];
  77. // connections stuff
  78. LinkedList<int> connectedIn1;
  79. LinkedList<int> connectedIn2;
  80. LinkedList<int> connectedOut1;
  81. LinkedList<int> connectedOut2;
  82. CarlaCriticalSection connectLock;
  83. uint lastConnectionId;
  84. LinkedList<ConnectionToId> usedConnections;
  85. EngineRackBuffers(const uint32_t bufferSize);
  86. ~EngineRackBuffers() noexcept;
  87. void clear() noexcept;
  88. void resize(const uint32_t bufferSize);
  89. bool connect(CarlaEngine* const engine, const int groupA, const int portA, const int groupB, const int port) noexcept;
  90. bool disconnect(const uint connectionId);
  91. const char* const* getConnections() const;
  92. CARLA_DECLARE_NON_COPY_STRUCT(EngineRackBuffers)
  93. };
  94. // -----------------------------------------------------------------------
  95. // EnginePatchbayBuffers
  96. struct EnginePatchbayBuffers {
  97. // TODO
  98. EnginePatchbayBuffers(const uint32_t bufferSize);
  99. ~EnginePatchbayBuffers() noexcept;
  100. void clear() noexcept;
  101. void resize(const uint32_t bufferSize);
  102. bool connect(CarlaEngine* const engine, const int groupA, const int portA, const int groupB, const int port) noexcept;
  103. const char* const* getConnections() const;
  104. CARLA_DECLARE_NON_COPY_STRUCT(EnginePatchbayBuffers)
  105. };
  106. // -----------------------------------------------------------------------
  107. // EngineRackBuffers
  108. EngineRackBuffers::EngineRackBuffers(const uint32_t bufferSize)
  109. : lastConnectionId(0)
  110. {
  111. resize(bufferSize);
  112. }
  113. EngineRackBuffers::~EngineRackBuffers() noexcept
  114. {
  115. clear();
  116. }
  117. void EngineRackBuffers::clear() noexcept
  118. {
  119. lastConnectionId = 0;
  120. if (in[0] != nullptr)
  121. {
  122. delete[] in[0];
  123. in[0] = nullptr;
  124. }
  125. if (in[1] != nullptr)
  126. {
  127. delete[] in[1];
  128. in[1] = nullptr;
  129. }
  130. if (out[0] != nullptr)
  131. {
  132. delete[] out[0];
  133. out[0] = nullptr;
  134. }
  135. if (out[1] != nullptr)
  136. {
  137. delete[] out[1];
  138. out[1] = nullptr;
  139. }
  140. connectedIn1.clear();
  141. connectedIn2.clear();
  142. connectedOut1.clear();
  143. connectedOut2.clear();
  144. usedConnections.clear();
  145. }
  146. void EngineRackBuffers::resize(const uint32_t bufferSize)
  147. {
  148. if (bufferSize > 0)
  149. {
  150. in[0] = new float[bufferSize];
  151. in[1] = new float[bufferSize];
  152. out[0] = new float[bufferSize];
  153. out[1] = new float[bufferSize];
  154. }
  155. else
  156. {
  157. in[0] = nullptr;
  158. in[1] = nullptr;
  159. out[0] = nullptr;
  160. out[1] = nullptr;
  161. }
  162. }
  163. bool EngineRackBuffers::connect(CarlaEngine* const engine, const int groupA, const int portA, const int groupB, const int portB) noexcept
  164. {
  165. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  166. CARLA_SAFE_ASSERT_RETURN(groupA != groupB, false);
  167. CARLA_SAFE_ASSERT_RETURN(groupA >= RACK_PATCHBAY_GROUP_CARLA && groupA < RACK_PATCHBAY_GROUP_MAX, false);
  168. CARLA_SAFE_ASSERT_RETURN(groupB >= RACK_PATCHBAY_GROUP_CARLA && groupB < RACK_PATCHBAY_GROUP_MAX, false);
  169. CARLA_SAFE_ASSERT_RETURN(portA >= 0, false);
  170. CARLA_SAFE_ASSERT_RETURN(portB >= 0, false);
  171. int carlaPort, otherPort;
  172. if (groupA == RACK_PATCHBAY_GROUP_CARLA)
  173. {
  174. carlaPort = portA;
  175. otherPort = portB;
  176. }
  177. else
  178. {
  179. CARLA_SAFE_ASSERT_RETURN(groupB == RACK_PATCHBAY_GROUP_CARLA, false);
  180. carlaPort = portB;
  181. otherPort = portA;
  182. }
  183. bool makeConnection = false;
  184. switch (carlaPort)
  185. {
  186. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1:
  187. connectLock.enter();
  188. connectedIn1.append(otherPort);
  189. connectLock.leave();
  190. makeConnection = true;
  191. break;
  192. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2:
  193. connectLock.enter();
  194. connectedIn2.append(otherPort);
  195. connectLock.leave();
  196. makeConnection = true;
  197. break;
  198. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1:
  199. connectLock.enter();
  200. connectedOut1.append(otherPort);
  201. connectLock.leave();
  202. makeConnection = true;
  203. break;
  204. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2:
  205. connectLock.enter();
  206. connectedOut2.append(otherPort);
  207. connectLock.leave();
  208. makeConnection = true;
  209. break;
  210. case RACK_PATCHBAY_CARLA_PORT_MIDI_IN:
  211. makeConnection = engine->connectRackMidiInPort(otherPort);
  212. break;
  213. case RACK_PATCHBAY_CARLA_PORT_MIDI_OUT:
  214. makeConnection = engine->connectRackMidiOutPort(otherPort);
  215. break;
  216. }
  217. if (! makeConnection)
  218. {
  219. engine->setLastError("Invalid rack connection");
  220. return false;
  221. }
  222. ConnectionToId connectionToId;
  223. connectionToId.id = lastConnectionId;
  224. connectionToId.groupA = groupA;
  225. connectionToId.portA = portA;
  226. connectionToId.groupB = groupB;
  227. connectionToId.portB = portB;
  228. char strBuf[STR_MAX+1];
  229. strBuf[STR_MAX] = '\0';
  230. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", groupA, portA, groupB, portB);
  231. engine->callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, lastConnectionId, 0, 0, 0.0f, strBuf);
  232. usedConnections.append(connectionToId);
  233. ++lastConnectionId;
  234. return true;
  235. }
  236. const char* const* EngineRackBuffers::getConnections() const
  237. {
  238. if (usedConnections.count() == 0)
  239. return nullptr;
  240. LinkedList<const char*> connList;
  241. char strBuf[STR_MAX+1];
  242. for (LinkedList<ConnectionToId>::Itenerator it=usedConnections.begin(); it.valid(); it.next())
  243. {
  244. const ConnectionToId& connection(it.getValue());
  245. CARLA_SAFE_ASSERT_CONTINUE(connection.groupA != connection.groupB);
  246. CARLA_SAFE_ASSERT_CONTINUE(connection.groupA >= RACK_PATCHBAY_GROUP_CARLA && connection.groupA < RACK_PATCHBAY_GROUP_MAX);
  247. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB >= RACK_PATCHBAY_GROUP_CARLA && connection.groupB < RACK_PATCHBAY_GROUP_MAX);
  248. CARLA_SAFE_ASSERT_CONTINUE(connection.portA >= 0);
  249. CARLA_SAFE_ASSERT_CONTINUE(connection.portB >= 0);
  250. int carlaPort, otherPort;
  251. if (connection.groupA == RACK_PATCHBAY_GROUP_CARLA)
  252. {
  253. carlaPort = connection.portA;
  254. otherPort = connection.portB;
  255. }
  256. else
  257. {
  258. CARLA_SAFE_ASSERT_CONTINUE(connection.groupB == RACK_PATCHBAY_GROUP_CARLA);
  259. carlaPort = connection.portB;
  260. otherPort = connection.portA;
  261. }
  262. switch (carlaPort)
  263. {
  264. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1:
  265. case RACK_PATCHBAY_CARLA_PORT_AUDIO_IN2:
  266. std::sprintf(strBuf, "AudioIn:%i", otherPort+1);
  267. connList.append(carla_strdup(strBuf));
  268. connList.append(carla_strdup((carlaPort == RACK_PATCHBAY_CARLA_PORT_AUDIO_IN1) ? "Carla:AudioIn1" : "Carla:AudioIn2"));
  269. break;
  270. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1:
  271. case RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT2:
  272. connList.append(carla_strdup((carlaPort == RACK_PATCHBAY_CARLA_PORT_AUDIO_OUT1) ? "Carla:AudioOut1" : "Carla:AudioOut2"));
  273. std::sprintf(strBuf, "AudioOut:%i", otherPort+1);
  274. connList.append(carla_strdup(strBuf));
  275. break;
  276. case RACK_PATCHBAY_CARLA_PORT_MIDI_IN:
  277. std::sprintf(strBuf, "MidiIn:%i", otherPort+1);
  278. connList.append(carla_strdup(strBuf));
  279. connList.append(carla_strdup("Carla:MidiIn"));
  280. break;
  281. case RACK_PATCHBAY_CARLA_PORT_MIDI_OUT:
  282. connList.append(carla_strdup("Carla:MidiOut"));
  283. std::sprintf(strBuf, "MidiOut:%i", otherPort+1);
  284. connList.append(carla_strdup(strBuf));
  285. break;
  286. }
  287. }
  288. const size_t connCount(connList.count());
  289. if (connCount == 0)
  290. return nullptr;
  291. const char** const retConns = new const char*[connCount+1];
  292. for (size_t i=0; i < connCount; ++i)
  293. retConns[i] = connList.getAt(i);
  294. retConns[connCount] = nullptr;
  295. connList.clear();
  296. return retConns;
  297. }
  298. // -----------------------------------------------------------------------
  299. // EnginePatchbayBuffers
  300. EnginePatchbayBuffers::EnginePatchbayBuffers(const uint32_t bufferSize)
  301. {
  302. resize(bufferSize);
  303. }
  304. EnginePatchbayBuffers::~EnginePatchbayBuffers() noexcept
  305. {
  306. clear();
  307. }
  308. void EnginePatchbayBuffers::clear() noexcept
  309. {
  310. }
  311. void EnginePatchbayBuffers::resize(const uint32_t /*bufferSize*/)
  312. {
  313. }
  314. bool EnginePatchbayBuffers::connect(CarlaEngine* const engine, const int, const int, const int, const int) noexcept
  315. {
  316. CARLA_SAFE_ASSERT_RETURN(engine != nullptr, false);
  317. return false;
  318. }
  319. const char* const* EnginePatchbayBuffers::getConnections() const
  320. {
  321. return nullptr;
  322. }
  323. // -----------------------------------------------------------------------
  324. // EnginePatchbayBuffers
  325. EngineInternalAudio::create(const uint32_t bufferSize)
  326. {
  327. CARLA_SAFE_ASSERT_RETURN(buffer == nullptr,);
  328. if (usePatchbay)
  329. buffer = new EnginePatchbayBuffers(bufferSize);
  330. else
  331. buffer = new EngineRackBuffers(bufferSize);
  332. isReady = true;
  333. }
  334. EngineInternalAudio::initPatchbay() noexcept
  335. {
  336. if (usePatchbay)
  337. {
  338. CARLA_SAFE_ASSERT_RETURN(patchbay != nullptr,);
  339. // TODO
  340. }
  341. else
  342. {
  343. CARLA_SAFE_ASSERT_RETURN(rack != nullptr,);
  344. rack->lastConnectionId = 0;
  345. rack->usedConnections.clear();
  346. }
  347. }
  348. // -----------------------------------------------------------------------
  349. CARLA_BACKEND_END_NAMESPACE