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.

459 lines
14KB

  1. /*
  2. * Carla Plugin Host
  3. * Copyright (C) 2011-2022 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 "CarlaEngineGraph.hpp"
  18. #include "CarlaEngineInit.hpp"
  19. #include "CarlaEngineInternal.hpp"
  20. #include "CarlaStringList.hpp"
  21. #include "CarlaBackendUtils.hpp"
  22. #include <SDL.h>
  23. #ifndef HAVE_SDL2
  24. typedef Uint32 SDL_AudioDeviceID;
  25. #endif
  26. #ifndef SDL_HINT_AUDIO_DEVICE_APP_NAME
  27. # define SDL_HINT_AUDIO_DEVICE_APP_NAME "SDL_AUDIO_DEVICE_APP_NAME"
  28. #endif
  29. #ifndef SDL_HINT_AUDIO_DEVICE_STREAM_NAME
  30. # define SDL_HINT_AUDIO_DEVICE_STREAM_NAME "SDL_AUDIO_DEVICE_STREAM_NAME"
  31. #endif
  32. CARLA_BACKEND_START_NAMESPACE
  33. // -------------------------------------------------------------------------------------------------------------------
  34. // Global static data
  35. static CarlaStringList gDeviceNames;
  36. // -------------------------------------------------------------------------------------------------------------------
  37. static void initAudioDevicesIfNeeded()
  38. {
  39. static bool needsInit = true;
  40. if (! needsInit)
  41. return;
  42. needsInit = false;
  43. #ifdef HAVE_SDL2
  44. SDL_InitSubSystem(SDL_INIT_AUDIO);
  45. const int numDevices = SDL_GetNumAudioDevices(0);
  46. for (int i=0; i<numDevices; ++i)
  47. gDeviceNames.append(SDL_GetAudioDeviceName(i, 0));
  48. #else
  49. SDL_Init(SDL_INIT_AUDIO);
  50. #endif
  51. }
  52. // -------------------------------------------------------------------------------------------------------------------
  53. // RtAudio Engine
  54. class CarlaEngineSDL : public CarlaEngine
  55. {
  56. public:
  57. CarlaEngineSDL()
  58. : CarlaEngine(),
  59. fDeviceId(0),
  60. fDeviceName(),
  61. fAudioOutCount(0),
  62. fAudioIntBufOut(nullptr)
  63. {
  64. carla_debug("CarlaEngineSDL::CarlaEngineSDL()");
  65. // just to make sure
  66. pData->options.transportMode = ENGINE_TRANSPORT_MODE_INTERNAL;
  67. }
  68. ~CarlaEngineSDL() override
  69. {
  70. CARLA_SAFE_ASSERT(fAudioOutCount == 0);
  71. carla_debug("CarlaEngineSDL::~CarlaEngineSDL()");
  72. }
  73. // -------------------------------------
  74. bool init(const char* const clientName) override
  75. {
  76. CARLA_SAFE_ASSERT_RETURN(fDeviceId == 0, false);
  77. CARLA_SAFE_ASSERT_RETURN(fAudioOutCount == 0, false);
  78. CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false);
  79. carla_debug("CarlaEngineSDL::init(\"%s\")", clientName);
  80. if (pData->options.processMode != ENGINE_PROCESS_MODE_CONTINUOUS_RACK && pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY)
  81. {
  82. setLastError("Invalid process mode");
  83. return false;
  84. }
  85. SDL_AudioSpec requested, received;
  86. carla_zeroStruct(requested);
  87. #ifdef HAVE_SDL2
  88. requested.format = AUDIO_F32SYS;
  89. #else
  90. requested.format = AUDIO_S16SYS;
  91. #endif
  92. requested.channels = 2;
  93. requested.freq = static_cast<int>(pData->options.audioSampleRate);
  94. requested.samples = static_cast<Uint16>(pData->options.audioBufferSize);
  95. requested.callback = carla_sdl_process_callback;
  96. requested.userdata = this;
  97. #ifdef HAVE_SDL2
  98. SDL_SetHint(SDL_HINT_AUDIO_DEVICE_APP_NAME, clientName);
  99. // SDL_SetHint(SDL_HINT_AUDIO_DEVICE_STREAM_NAME, );
  100. SDL_SetHint(SDL_HINT_AUDIO_RESAMPLING_MODE, "2");
  101. const char* const deviceName = pData->options.audioDevice != nullptr && pData->options.audioDevice[0] != '\0'
  102. ? pData->options.audioDevice
  103. : nullptr;
  104. int flags = SDL_AUDIO_ALLOW_FREQUENCY_CHANGE;
  105. if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
  106. flags |= SDL_AUDIO_ALLOW_CHANNELS_CHANGE;
  107. fDeviceId = SDL_OpenAudioDevice(deviceName, 0, &requested, &received, flags);
  108. #else
  109. fDeviceId = SDL_OpenAudio(&requested, &received) == 0 ? 1 : 0;
  110. #endif
  111. if (fDeviceId == 0)
  112. {
  113. setLastError(SDL_GetError());
  114. return false;
  115. }
  116. if (received.channels == 0)
  117. {
  118. #ifdef HAVE_SDL2
  119. SDL_CloseAudioDevice(fDeviceId);
  120. #else
  121. SDL_CloseAudio();
  122. #endif
  123. fDeviceId = 0;
  124. setLastError("No output channels available");
  125. return false;
  126. }
  127. if (! pData->init(clientName))
  128. {
  129. close();
  130. setLastError("Failed to init internal data");
  131. return false;
  132. }
  133. pData->bufferSize = received.samples;
  134. pData->sampleRate = received.freq;
  135. pData->initTime(pData->options.transportExtra);
  136. fAudioOutCount = received.channels;
  137. fAudioIntBufOut = new float*[fAudioOutCount];
  138. for (uint i=0; i<fAudioOutCount; ++i)
  139. fAudioIntBufOut[i] = new float[received.samples];
  140. pData->graph.create(0, fAudioOutCount, 0, 0);
  141. #ifdef HAVE_SDL2
  142. SDL_PauseAudioDevice(fDeviceId, 0);
  143. #else
  144. SDL_PauseAudio(0);
  145. #endif
  146. carla_stdout("open fAudioOutCount %d %d %d | %d vs %d",
  147. fAudioOutCount, received.samples, received.freq,
  148. received.format, requested.format);
  149. patchbayRefresh(true, false, false);
  150. if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
  151. refreshExternalGraphPorts<PatchbayGraph>(pData->graph.getPatchbayGraph(), false, false);
  152. callback(true, true,
  153. ENGINE_CALLBACK_ENGINE_STARTED,
  154. 0,
  155. pData->options.processMode,
  156. pData->options.transportMode,
  157. static_cast<int>(pData->bufferSize),
  158. static_cast<float>(pData->sampleRate),
  159. getCurrentDriverName());
  160. return true;
  161. }
  162. bool close() override
  163. {
  164. carla_debug("CarlaEngineSDL::close()");
  165. // close device
  166. if (fDeviceId != 0)
  167. {
  168. // SDL_PauseAudioDevice(fDeviceId, 1);
  169. #ifdef HAVE_SDL2
  170. SDL_CloseAudioDevice(fDeviceId);
  171. #else
  172. SDL_CloseAudio();
  173. #endif
  174. fDeviceId = 0;
  175. }
  176. // clear engine data
  177. CarlaEngine::close();
  178. pData->graph.destroy();
  179. // cleanup
  180. if (fAudioIntBufOut != nullptr)
  181. {
  182. for (uint i=0; i<fAudioOutCount; ++i)
  183. delete[] fAudioIntBufOut[i];
  184. delete[] fAudioIntBufOut;
  185. fAudioIntBufOut = nullptr;
  186. }
  187. fAudioOutCount = 0;
  188. fDeviceName.clear();
  189. return false;
  190. }
  191. bool isRunning() const noexcept override
  192. {
  193. return fDeviceId != 0 /*&& SDL_GetAudioDeviceStatus(fDeviceId) == SDL_AUDIO_PLAYING*/;
  194. }
  195. bool isOffline() const noexcept override
  196. {
  197. return false;
  198. }
  199. EngineType getType() const noexcept override
  200. {
  201. return kEngineTypeSDL;
  202. }
  203. const char* getCurrentDriverName() const noexcept override
  204. {
  205. return "SDL";
  206. }
  207. // -------------------------------------------------------------------
  208. // Patchbay
  209. template<class Graph>
  210. bool refreshExternalGraphPorts(Graph* const graph, const bool sendHost, const bool sendOSC)
  211. {
  212. CARLA_SAFE_ASSERT_RETURN(graph != nullptr, false);
  213. char strBuf[STR_MAX+1U];
  214. strBuf[STR_MAX] = '\0';
  215. ExternalGraph& extGraph(graph->extGraph);
  216. // ---------------------------------------------------------------
  217. // clear last ports
  218. extGraph.clear();
  219. // ---------------------------------------------------------------
  220. // fill in new ones
  221. // Audio Out
  222. for (uint i=0; i < fAudioOutCount; ++i)
  223. {
  224. std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);
  225. PortNameToId portNameToId;
  226. portNameToId.setData(kExternalGraphGroupAudioOut, i+1, strBuf, "");
  227. extGraph.audioPorts.outs.append(portNameToId);
  228. }
  229. // ---------------------------------------------------------------
  230. // now refresh
  231. if (sendHost || sendOSC)
  232. graph->refresh(sendHost, sendOSC, true, fDeviceName.buffer());
  233. return true;
  234. }
  235. bool patchbayRefresh(const bool sendHost, const bool sendOSC, const bool external) override
  236. {
  237. CARLA_SAFE_ASSERT_RETURN(pData->graph.isReady(), false);
  238. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  239. return refreshExternalGraphPorts<RackGraph>(pData->graph.getRackGraph(), sendHost, sendOSC);
  240. if (sendHost)
  241. pData->graph.setUsingExternalHost(external);
  242. if (sendOSC)
  243. pData->graph.setUsingExternalOSC(external);
  244. if (external)
  245. return refreshExternalGraphPorts<PatchbayGraph>(pData->graph.getPatchbayGraph(), sendHost, sendOSC);
  246. return CarlaEngine::patchbayRefresh(sendHost, sendOSC, false);
  247. }
  248. // -------------------------------------------------------------------
  249. protected:
  250. void handleAudioProcessCallback(uchar* const stream, const int len)
  251. {
  252. // safety checks
  253. CARLA_SAFE_ASSERT_RETURN(stream != nullptr,);
  254. CARLA_SAFE_ASSERT_RETURN(len > 0,);
  255. #ifdef HAVE_SDL2
  256. // direct float type
  257. float* const fstream = (float*)stream;
  258. const uint ulen = static_cast<uint>(static_cast<uint>(len) / sizeof(float) / fAudioOutCount);
  259. #else
  260. // signed 16bit int
  261. int16_t* const istream = (int16_t*)stream;
  262. const uint ulen = static_cast<uint>(static_cast<uint>(len) / sizeof(int16_t) / fAudioOutCount);
  263. #endif
  264. const PendingRtEventsRunner prt(this, ulen, true);
  265. // init our deinterleaved audio buffers
  266. for (uint i=0, count=fAudioOutCount; i<count; ++i)
  267. carla_zeroFloats(fAudioIntBufOut[i], ulen);
  268. // initialize events
  269. carla_zeroStructs(pData->events.in, kMaxEngineEventInternalCount);
  270. carla_zeroStructs(pData->events.out, kMaxEngineEventInternalCount);
  271. pData->graph.process(pData, nullptr, fAudioIntBufOut, ulen);
  272. // interleave audio back
  273. for (uint i=0; i < fAudioOutCount; ++i)
  274. {
  275. for (uint j=0; j < ulen; ++j)
  276. {
  277. #ifdef HAVE_SDL2
  278. // direct float type
  279. fstream[j * fAudioOutCount + i] = fAudioIntBufOut[i][j];
  280. #else
  281. // signed 16bit int
  282. istream[j * fAudioOutCount + i] = lrintf(carla_fixedValue(-1.0f, 1.0f, fAudioIntBufOut[i][j]) * 32767.0f);
  283. #endif
  284. }
  285. }
  286. }
  287. // -------------------------------------------------------------------
  288. bool connectExternalGraphPort(const uint connectionType, const uint portId, const char* const portName) override
  289. {
  290. CARLA_SAFE_ASSERT_RETURN(connectionType != 0 || (portName != nullptr && portName[0] != '\0'), false);
  291. carla_debug("CarlaEngineSDL::connectExternalGraphPort(%u, %u, \"%s\")", connectionType, portId, portName);
  292. switch (connectionType)
  293. {
  294. case kExternalGraphConnectionAudioIn1:
  295. case kExternalGraphConnectionAudioIn2:
  296. case kExternalGraphConnectionAudioOut1:
  297. case kExternalGraphConnectionAudioOut2:
  298. return CarlaEngine::connectExternalGraphPort(connectionType, portId, portName);
  299. case kExternalGraphConnectionMidiInput:
  300. case kExternalGraphConnectionMidiOutput:
  301. break;
  302. }
  303. return false;
  304. }
  305. bool disconnectExternalGraphPort(const uint connectionType, const uint portId, const char* const portName) override
  306. {
  307. CARLA_SAFE_ASSERT_RETURN(connectionType != 0 || (portName != nullptr && portName[0] != '\0'), false);
  308. carla_debug("CarlaEngineSDL::disconnectExternalGraphPort(%u, %u, \"%s\")", connectionType, portId, portName);
  309. switch (connectionType)
  310. {
  311. case kExternalGraphConnectionAudioIn1:
  312. case kExternalGraphConnectionAudioIn2:
  313. case kExternalGraphConnectionAudioOut1:
  314. case kExternalGraphConnectionAudioOut2:
  315. return CarlaEngine::disconnectExternalGraphPort(connectionType, portId, portName);
  316. case kExternalGraphConnectionMidiInput:
  317. case kExternalGraphConnectionMidiOutput:
  318. break;
  319. }
  320. return false;
  321. }
  322. // -------------------------------------------------------------------
  323. private:
  324. SDL_AudioDeviceID fDeviceId;
  325. // current device name
  326. CarlaString fDeviceName;
  327. // deinterleaved buffers
  328. uint fAudioOutCount;
  329. float** fAudioIntBufOut;
  330. #define handlePtr ((CarlaEngineSDL*)userData)
  331. static void carla_sdl_process_callback(void* userData, uchar* stream, int len)
  332. {
  333. handlePtr->handleAudioProcessCallback(stream, len);
  334. }
  335. #undef handlePtr
  336. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineSDL)
  337. };
  338. // -----------------------------------------
  339. namespace EngineInit {
  340. CarlaEngine* newSDL()
  341. {
  342. initAudioDevicesIfNeeded();
  343. return new CarlaEngineSDL();
  344. }
  345. const char* const* getSDLDeviceNames()
  346. {
  347. initAudioDevicesIfNeeded();
  348. if (gDeviceNames.count() == 0)
  349. {
  350. static const char* deviceNames[] = { "Default", nullptr };
  351. return deviceNames;
  352. }
  353. static const CharStringListPtr deviceNames = gDeviceNames.toCharStringListPtr();
  354. return deviceNames;
  355. }
  356. }
  357. // -----------------------------------------
  358. CARLA_BACKEND_END_NAMESPACE