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.

291 lines
8.3KB

  1. /*
  2. * Carla Plugin Host
  3. * Copyright (C) 2011-2023 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 GPL.txt file
  16. */
  17. #include "CarlaEngineGraph.hpp"
  18. #include "CarlaEngineInit.hpp"
  19. #include "CarlaEngineInternal.hpp"
  20. #include "CarlaTimeUtils.hpp"
  21. CARLA_BACKEND_START_NAMESPACE
  22. // -------------------------------------------------------------------------------------------------------------------
  23. // Dummy Engine
  24. class CarlaEngineDummy : public CarlaEngine,
  25. public CarlaThread
  26. {
  27. public:
  28. CarlaEngineDummy()
  29. : CarlaEngine(),
  30. CarlaThread("CarlaEngineDummy"),
  31. fRunning(false)
  32. {
  33. carla_debug("CarlaEngineDummy::CarlaEngineDummy()");
  34. // just to make sure
  35. pData->options.transportMode = ENGINE_TRANSPORT_MODE_INTERNAL;
  36. }
  37. ~CarlaEngineDummy() override
  38. {
  39. carla_debug("CarlaEngineDummy::~CarlaEngineDummy()");
  40. }
  41. // -------------------------------------
  42. bool init(const char* const clientName) override
  43. {
  44. CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false);
  45. carla_debug("CarlaEngineDummy::init(\"%s\")", clientName);
  46. if (pData->options.processMode != ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  47. {
  48. setLastError("Invalid process mode");
  49. return false;
  50. }
  51. fRunning = true;
  52. if (! pData->init(clientName))
  53. {
  54. close();
  55. setLastError("Failed to init internal data");
  56. return false;
  57. }
  58. pData->bufferSize = pData->options.audioBufferSize;
  59. pData->sampleRate = pData->options.audioSampleRate;
  60. pData->initTime(pData->options.transportExtra);
  61. pData->graph.create(2, 2, 0, 0);
  62. if (! startThread())
  63. {
  64. close();
  65. setLastError("Failed to start dummy audio thread");
  66. return false;
  67. }
  68. patchbayRefresh(true, false, false);
  69. callback(true, true,
  70. ENGINE_CALLBACK_ENGINE_STARTED,
  71. 0,
  72. pData->options.processMode,
  73. pData->options.transportMode,
  74. static_cast<int>(pData->bufferSize),
  75. static_cast<float>(pData->sampleRate),
  76. getCurrentDriverName());
  77. return true;
  78. }
  79. bool close() override
  80. {
  81. carla_debug("CarlaEngineDummy::close()");
  82. fRunning = false;
  83. stopThread(-1);
  84. CarlaEngine::close();
  85. pData->graph.destroy();
  86. return true;
  87. }
  88. bool hasIdleOnMainThread() const noexcept override
  89. {
  90. return true;
  91. }
  92. bool isRunning() const noexcept override
  93. {
  94. return fRunning;
  95. }
  96. bool isOffline() const noexcept override
  97. {
  98. return false;
  99. }
  100. EngineType getType() const noexcept override
  101. {
  102. return kEngineTypeDummy;
  103. }
  104. const char* getCurrentDriverName() const noexcept override
  105. {
  106. return "Dummy";
  107. }
  108. // -------------------------------------------------------------------
  109. // Patchbay
  110. bool patchbayRefresh(const bool sendHost, const bool sendOSC, const bool) override
  111. {
  112. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);
  113. RackGraph* const graph = pData->graph.getRackGraph();
  114. CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
  115. ExternalGraph& extGraph(graph->extGraph);
  116. // ---------------------------------------------------------------
  117. // clear last ports
  118. extGraph.clear();
  119. // ---------------------------------------------------------------
  120. // fill in new ones
  121. {
  122. PortNameToId portNameToId;
  123. portNameToId.setData(kExternalGraphGroupAudioIn, 1, "capture_1", "");
  124. extGraph.audioPorts.ins.append(portNameToId);
  125. }
  126. {
  127. PortNameToId portNameToId;
  128. portNameToId.setData(kExternalGraphGroupAudioIn, 2, "capture_2", "");
  129. extGraph.audioPorts.ins.append(portNameToId);
  130. }
  131. {
  132. PortNameToId portNameToId;
  133. portNameToId.setData(kExternalGraphGroupAudioOut, 1, "playback_1", "");
  134. extGraph.audioPorts.outs.append(portNameToId);
  135. }
  136. {
  137. PortNameToId portNameToId;
  138. portNameToId.setData(kExternalGraphGroupAudioOut, 2, "playback_2", "");
  139. extGraph.audioPorts.outs.append(portNameToId);
  140. }
  141. // ---------------------------------------------------------------
  142. // now refresh
  143. if (sendHost || sendOSC)
  144. graph->refresh(sendHost, sendOSC, false, "Dummy");
  145. return true;
  146. }
  147. // -------------------------------------------------------------------
  148. protected:
  149. void run() override
  150. {
  151. const uint32_t bufferSize = pData->bufferSize;
  152. const int64_t cycleTime = static_cast<int64_t>(
  153. static_cast<double>(bufferSize) / pData->sampleRate * 1000000 + 0.5);
  154. int delay = 0;
  155. if (const char* const delaystr = std::getenv("CARLA_BRIDGE_DUMMY"))
  156. if ((delay = atoi(delaystr)) == 1)
  157. delay = 0;
  158. carla_stdout("CarlaEngineDummy audio thread started, cycle time: " P_INT64 "ms, delay %ds",
  159. cycleTime / 1000, delay);
  160. float* audioIns[2] = {
  161. (float*)std::malloc(sizeof(float)*bufferSize),
  162. (float*)std::malloc(sizeof(float)*bufferSize),
  163. };
  164. CARLA_SAFE_ASSERT_RETURN(audioIns[0] != nullptr,);
  165. CARLA_SAFE_ASSERT_RETURN(audioIns[1] != nullptr,);
  166. float* audioOuts[2] = {
  167. (float*)std::malloc(sizeof(float)*bufferSize),
  168. (float*)std::malloc(sizeof(float)*bufferSize),
  169. };
  170. CARLA_SAFE_ASSERT_RETURN(audioOuts[0] != nullptr,);
  171. CARLA_SAFE_ASSERT_RETURN(audioOuts[1] != nullptr,);
  172. carla_zeroFloats(audioIns[0], bufferSize);
  173. carla_zeroFloats(audioIns[1], bufferSize);
  174. carla_zeroStructs(pData->events.in, kMaxEngineEventInternalCount);
  175. int64_t oldTime, newTime;
  176. while (! shouldThreadExit())
  177. {
  178. if (delay > 0)
  179. carla_sleep(static_cast<uint>(delay));
  180. oldTime = carla_gettime_us();
  181. const PendingRtEventsRunner prt(this, bufferSize, true);
  182. carla_zeroFloats(audioOuts[0], bufferSize);
  183. carla_zeroFloats(audioOuts[1], bufferSize);
  184. carla_zeroStructs(pData->events.out, kMaxEngineEventInternalCount);
  185. pData->graph.process(pData, audioIns, audioOuts, bufferSize);
  186. newTime = carla_gettime_us();
  187. CARLA_SAFE_ASSERT_CONTINUE(newTime >= oldTime);
  188. const int64_t remainingTime = cycleTime - (newTime - oldTime);
  189. if (remainingTime <= 0)
  190. {
  191. ++pData->xruns;
  192. carla_stdout("XRUN! remaining time: " P_INT64 ", old: " P_INT64 ", new: " P_INT64 ")",
  193. remainingTime, oldTime, newTime);
  194. }
  195. else if (remainingTime >= 1000)
  196. {
  197. CARLA_SAFE_ASSERT_CONTINUE(remainingTime < 1000000); // 1 sec
  198. carla_msleep(static_cast<uint>(remainingTime / 1000));
  199. }
  200. }
  201. std::free(audioIns[0]);
  202. std::free(audioIns[1]);
  203. std::free(audioOuts[0]);
  204. std::free(audioOuts[1]);
  205. carla_stdout("CarlaEngineDummy audio thread finished with %u Xruns", pData->xruns);
  206. }
  207. // -------------------------------------------------------------------
  208. private:
  209. bool fRunning;
  210. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineDummy)
  211. };
  212. // -----------------------------------------
  213. namespace EngineInit {
  214. CarlaEngine* newDummy()
  215. {
  216. carla_debug("EngineInit::newDummy()");
  217. return new CarlaEngineDummy();
  218. }
  219. }
  220. // -----------------------------------------
  221. CARLA_BACKEND_END_NAMESPACE