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.

329 lines
9.6KB

  1. // SPDX-FileCopyrightText: 2011-2025 Filipe Coelho <falktx@falktx.com>
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "CarlaEngineClient.hpp"
  4. #include "CarlaEngineUtils.hpp"
  5. CARLA_BACKEND_START_NAMESPACE
  6. // -----------------------------------------------------------------------
  7. static void _getUniquePortName(String& sname, const CarlaStringList& list)
  8. {
  9. for (CarlaStringList::Itenerator it = list.begin2(); it.valid(); it.next())
  10. {
  11. const char* const portName(it.getValue(nullptr));
  12. CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0');
  13. // Check if unique name doesn't exist
  14. if (sname != portName)
  15. continue;
  16. // Check if string has already been modified
  17. {
  18. const std::size_t len(sname.length());
  19. // 1 digit, ex: " (2)"
  20. if (sname[len-4] == ' ' && sname[len-3] == '(' && sname.isDigit(len-2) && sname[len-1] == ')')
  21. {
  22. const int number = sname[len-2] - '0';
  23. if (number == 9)
  24. {
  25. // next number is 10, 2 digits
  26. sname.truncate(len-4);
  27. sname += " (10)";
  28. //sname.replace(" (9)", " (10)");
  29. }
  30. else
  31. sname[len-2] = char('0' + number + 1);
  32. continue;
  33. }
  34. // 2 digits, ex: " (11)"
  35. if (sname[len-5] == ' ' && sname[len-4] == '(' && sname.isDigit(len-3) && sname.isDigit(len-2) && sname[len-1] == ')')
  36. {
  37. char n2 = sname[len-2];
  38. char n3 = sname[len-3];
  39. if (n2 == '9')
  40. {
  41. n2 = '0';
  42. n3 = static_cast<char>(n3 + 1);
  43. }
  44. else
  45. n2 = static_cast<char>(n2 + 1);
  46. sname[len-2] = n2;
  47. sname[len-3] = n3;
  48. continue;
  49. }
  50. }
  51. // Modify string if not
  52. sname += " (2)";
  53. }
  54. }
  55. // -----------------------------------------------------------------------
  56. // Carla Engine Client
  57. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  58. CarlaEngineClient::ProtectedData::ProtectedData(const CarlaEngine& eng,
  59. EngineInternalGraph& eg,
  60. const CarlaPluginPtr p) noexcept
  61. #else
  62. CarlaEngineClient::ProtectedData::ProtectedData(const CarlaEngine& eng) noexcept
  63. #endif
  64. : engine(eng),
  65. active(false),
  66. latency(0),
  67. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  68. cvSourcePorts(),
  69. egraph(eg),
  70. plugin(p),
  71. #endif
  72. audioInList(),
  73. audioOutList(),
  74. cvInList(),
  75. cvOutList(),
  76. eventInList(),
  77. eventOutList() {}
  78. CarlaEngineClient::ProtectedData::~ProtectedData()
  79. {
  80. carla_debug("CarlaEngineClient::ProtectedData::~ProtectedData()");
  81. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  82. CARLA_SAFE_ASSERT(plugin.get() == nullptr);
  83. #endif
  84. }
  85. void CarlaEngineClient::ProtectedData::addAudioPortName(const bool isInput, const char* const name)
  86. {
  87. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
  88. CarlaStringList& portList(isInput ? audioInList : audioOutList);
  89. portList.append(name);
  90. }
  91. void CarlaEngineClient::ProtectedData::addCVPortName(const bool isInput, const char* const name)
  92. {
  93. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
  94. CarlaStringList& portList(isInput ? cvInList : cvOutList);
  95. portList.append(name);
  96. }
  97. void CarlaEngineClient::ProtectedData::addEventPortName(const bool isInput, const char* const name)
  98. {
  99. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
  100. CarlaStringList& portList(isInput ? eventInList : eventOutList);
  101. portList.append(name);
  102. }
  103. const char* CarlaEngineClient::ProtectedData::getUniquePortName(const char* const name)
  104. {
  105. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr);
  106. String sname;
  107. sname = name;
  108. _getUniquePortName(sname, audioInList);
  109. _getUniquePortName(sname, audioOutList);
  110. _getUniquePortName(sname, cvInList);
  111. _getUniquePortName(sname, cvOutList);
  112. _getUniquePortName(sname, eventInList);
  113. _getUniquePortName(sname, eventOutList);
  114. return carla_strdup(sname);
  115. }
  116. void CarlaEngineClient::ProtectedData::clearPorts()
  117. {
  118. audioInList.clear();
  119. audioOutList.clear();
  120. cvInList.clear();
  121. cvOutList.clear();
  122. eventInList.clear();
  123. eventOutList.clear();
  124. }
  125. // -----------------------------------------------------------------------
  126. CarlaEngineClient::CarlaEngineClient(ProtectedData* const p)
  127. : pData(p)
  128. {
  129. carla_debug("CarlaEngineClient::CarlaEngineClient()");
  130. }
  131. CarlaEngineClient::~CarlaEngineClient() noexcept
  132. {
  133. carla_debug("CarlaEngineClient::~CarlaEngineClient()");
  134. }
  135. void CarlaEngineClient::activate() noexcept
  136. {
  137. CARLA_SAFE_ASSERT(! pData->active);
  138. carla_debug("CarlaEngineClient::activate()");
  139. pData->active = true;
  140. }
  141. void CarlaEngineClient::deactivate(const bool willClose) noexcept
  142. {
  143. CARLA_SAFE_ASSERT(pData->active || willClose);
  144. carla_debug("CarlaEngineClient::deactivate(%s)", bool2str(willClose));
  145. pData->active = false;
  146. if (willClose)
  147. {
  148. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  149. pData->cvSourcePorts.resetGraphAndPlugin();
  150. pData->plugin.reset();
  151. #endif
  152. }
  153. }
  154. bool CarlaEngineClient::isActive() const noexcept
  155. {
  156. return pData->active;
  157. }
  158. bool CarlaEngineClient::isOk() const noexcept
  159. {
  160. return true;
  161. }
  162. uint32_t CarlaEngineClient::getLatency() const noexcept
  163. {
  164. return pData->latency;
  165. }
  166. void CarlaEngineClient::setLatency(const uint32_t samples) noexcept
  167. {
  168. pData->latency = samples;
  169. }
  170. CarlaEnginePort* CarlaEngineClient::addPort(const EnginePortType portType, const char* const name, const bool isInput, const uint32_t indexOffset)
  171. {
  172. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', nullptr);
  173. carla_debug("CarlaEngineClient::addPort(%i:%s, \"%s\", %s, %u)", portType, EnginePortType2Str(portType), name, bool2str(isInput), indexOffset);
  174. switch (portType)
  175. {
  176. case kEnginePortTypeNull:
  177. break;
  178. case kEnginePortTypeAudio:
  179. pData->addAudioPortName(isInput, name);
  180. return new CarlaEngineAudioPort(*this, isInput, indexOffset);
  181. case kEnginePortTypeCV:
  182. pData->addCVPortName(isInput, name);
  183. return new CarlaEngineCVPort(*this, isInput, indexOffset);
  184. case kEnginePortTypeEvent:
  185. pData->addEventPortName(isInput, name);
  186. return new CarlaEngineEventPort(*this, isInput, indexOffset);
  187. }
  188. carla_stderr("CarlaEngineClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput));
  189. return nullptr;
  190. }
  191. bool CarlaEngineClient::removePort(const EnginePortType portType, const char* const name, const bool isInput)
  192. {
  193. CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0', false);
  194. carla_debug("CarlaEngineClient::removePort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput));
  195. switch (portType)
  196. {
  197. case kEnginePortTypeNull:
  198. break;
  199. case kEnginePortTypeAudio: {
  200. CarlaStringList& portList(isInput ? pData->audioInList : pData->audioOutList);
  201. portList.append(name);
  202. return portList.removeOne(name);
  203. }
  204. case kEnginePortTypeCV: {
  205. CarlaStringList& portList(isInput ? pData->cvInList : pData->cvOutList);
  206. return portList.removeOne(name);
  207. }
  208. case kEnginePortTypeEvent: {
  209. CarlaStringList& portList(isInput ? pData->eventInList : pData->eventOutList);
  210. return portList.removeOne(name);
  211. }
  212. }
  213. return false;
  214. }
  215. #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
  216. CarlaEngineCVSourcePorts* CarlaEngineClient::createCVSourcePorts()
  217. {
  218. pData->cvSourcePorts.setGraphAndPlugin(pData->egraph.getPatchbayGraphOrNull(), pData->plugin);
  219. return &pData->cvSourcePorts;
  220. }
  221. #endif
  222. const CarlaEngine& CarlaEngineClient::getEngine() const noexcept
  223. {
  224. return pData->engine;
  225. }
  226. EngineProcessMode CarlaEngineClient::getProcessMode() const noexcept
  227. {
  228. return pData->engine.getProccessMode();
  229. }
  230. uint CarlaEngineClient::getPortCount(const EnginePortType portType, const bool isInput) const noexcept
  231. {
  232. size_t ret = 0;
  233. switch (portType)
  234. {
  235. case kEnginePortTypeNull:
  236. break;
  237. case kEnginePortTypeAudio:
  238. ret = isInput ? pData->audioInList.count() : pData->audioOutList.count();
  239. break;
  240. case kEnginePortTypeCV:
  241. ret = isInput ? pData->cvInList.count() : pData->cvOutList.count();
  242. break;
  243. case kEnginePortTypeEvent:
  244. ret = isInput ? pData->eventInList.count() : pData->eventOutList.count();
  245. break;
  246. }
  247. return static_cast<uint>(ret);
  248. }
  249. const char* CarlaEngineClient::getAudioPortName(const bool isInput, const uint index) const noexcept
  250. {
  251. CarlaStringList& portList(isInput ? pData->audioInList : pData->audioOutList);
  252. CARLA_SAFE_ASSERT_RETURN(index < portList.count(), nullptr);
  253. return portList.getAt(index);
  254. }
  255. const char* CarlaEngineClient::getCVPortName(const bool isInput, const uint index) const noexcept
  256. {
  257. CarlaStringList& portList(isInput ? pData->cvInList : pData->cvOutList);
  258. CARLA_SAFE_ASSERT_RETURN(index < portList.count(), nullptr);
  259. return portList.getAt(index);
  260. }
  261. const char* CarlaEngineClient::getEventPortName(const bool isInput, const uint index) const noexcept
  262. {
  263. CarlaStringList& portList(isInput ? pData->eventInList : pData->eventOutList);
  264. CARLA_SAFE_ASSERT_RETURN(index < portList.count(), nullptr);
  265. return portList.getAt(index);
  266. }
  267. // -----------------------------------------------------------------------
  268. CARLA_BACKEND_END_NAMESPACE