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.

CarlaEngineRtAudio.cpp 37KB

10 years ago
10 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
10 years ago
11 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
10 years ago
11 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204
  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 "CarlaBackendUtils.hpp"
  19. #include "CarlaMathUtils.hpp"
  20. #include "RtLinkedList.hpp"
  21. #include "rtaudio/RtAudio.h"
  22. #include "rtmidi/RtMidi.h"
  23. CARLA_BACKEND_START_NAMESPACE
  24. #if 0
  25. } // Fix editor indentation
  26. #endif
  27. // -------------------------------------------------------------------------------------------------------------------
  28. static const char** gRetNames = nullptr;
  29. static std::vector<RtAudio::Api> gRtAudioApis;
  30. static void initRtApis()
  31. {
  32. if (gRtAudioApis.size() == 0)
  33. {
  34. RtAudio::getCompiledApi(gRtAudioApis);
  35. #if 0//def HAVE_JUCE
  36. // prefer juce to handle some APIs
  37. std::vector<RtAudio::Api>::iterator it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::LINUX_ALSA);
  38. if (it != gRtAudioApis.end()) gRtAudioApis.erase(it);
  39. it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::MACOSX_CORE);
  40. if (it != gRtAudioApis.end()) gRtAudioApis.erase(it);
  41. it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::WINDOWS_ASIO);
  42. if (it != gRtAudioApis.end()) gRtAudioApis.erase(it);
  43. it = std::find(gRtAudioApis.begin(), gRtAudioApis.end(), RtAudio::WINDOWS_DS);
  44. if (it != gRtAudioApis.end()) gRtAudioApis.erase(it);
  45. #endif
  46. // in case rtaudio has no apis, add dummy one so that size() != 0
  47. if (gRtAudioApis.size() == 0)
  48. gRtAudioApis.push_back(RtAudio::RTAUDIO_DUMMY);
  49. }
  50. }
  51. static const char* getRtAudioApiName(const RtAudio::Api api) noexcept
  52. {
  53. switch (api)
  54. {
  55. case RtAudio::UNSPECIFIED:
  56. return "Unspecified";
  57. case RtAudio::LINUX_ALSA:
  58. return "ALSA";
  59. case RtAudio::LINUX_PULSE:
  60. return "PulseAudio";
  61. case RtAudio::LINUX_OSS:
  62. return "OSS";
  63. case RtAudio::UNIX_JACK:
  64. #if defined(CARLA_OS_WIN)
  65. return "JACK with WinMM";
  66. #elif defined(CARLA_OS_MAC)
  67. return "JACK with CoreMidi";
  68. #elif defined(CARLA_OS_LINUX)
  69. return "JACK with ALSA-MIDI";
  70. #else
  71. return "JACK (RtAudio)";
  72. #endif
  73. case RtAudio::MACOSX_CORE:
  74. return "CoreAudio";
  75. case RtAudio::WINDOWS_ASIO:
  76. return "ASIO";
  77. case RtAudio::WINDOWS_DS:
  78. return "DirectSound";
  79. case RtAudio::RTAUDIO_DUMMY:
  80. return "Dummy";
  81. }
  82. carla_stderr("CarlaBackend::getRtAudioApiName(%i) - invalid API", api);
  83. return nullptr;
  84. }
  85. static RtMidi::Api getMatchedAudioMidiAPi(const RtAudio::Api rtApi) noexcept
  86. {
  87. switch (rtApi)
  88. {
  89. case RtAudio::UNSPECIFIED:
  90. return RtMidi::UNSPECIFIED;
  91. case RtAudio::LINUX_ALSA:
  92. case RtAudio::LINUX_OSS:
  93. case RtAudio::LINUX_PULSE:
  94. return RtMidi::LINUX_ALSA;
  95. case RtAudio::UNIX_JACK:
  96. #if defined(CARLA_OS_WIN)
  97. return RtMidi::WINDOWS_MM;
  98. #elif defined(CARLA_OS_MAC)
  99. return RtMidi::MACOSX_CORE;
  100. #elif defined(CARLA_OS_LINUX)
  101. return RtMidi::LINUX_ALSA;
  102. #else
  103. return RtMidi::UNIX_JACK;
  104. #endif
  105. case RtAudio::MACOSX_CORE:
  106. return RtMidi::MACOSX_CORE;
  107. case RtAudio::WINDOWS_ASIO:
  108. case RtAudio::WINDOWS_DS:
  109. return RtMidi::WINDOWS_MM;
  110. case RtAudio::RTAUDIO_DUMMY:
  111. return RtMidi::RTMIDI_DUMMY;
  112. }
  113. return RtMidi::UNSPECIFIED;
  114. }
  115. // -------------------------------------------------------------------------------------------------------------------
  116. // Cleanup
  117. static const struct RtAudioCleanup {
  118. RtAudioCleanup() {}
  119. ~RtAudioCleanup() {
  120. if (gRetNames != nullptr)
  121. {
  122. delete[] gRetNames;
  123. gRetNames = nullptr;
  124. }
  125. gRtAudioApis.clear();
  126. }
  127. } sRtAudioCleanup;
  128. // -------------------------------------------------------------------------------------------------------------------
  129. // RtAudio Engine
  130. class CarlaEngineRtAudio : public CarlaEngine
  131. {
  132. public:
  133. CarlaEngineRtAudio(const RtAudio::Api api)
  134. : CarlaEngine(),
  135. fAudio(api),
  136. fAudioInBuf(nullptr),
  137. fAudioInCount(0),
  138. fAudioOutBuf(nullptr),
  139. fAudioOutCount(0),
  140. fLastEventTime(0),
  141. fDummyMidiIn(getMatchedAudioMidiAPi(api), "Carla"),
  142. fDummyMidiOut(getMatchedAudioMidiAPi(api), "Carla")
  143. {
  144. carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);
  145. // just to make sure
  146. pData->options.transportMode = ENGINE_TRANSPORT_MODE_INTERNAL;
  147. }
  148. ~CarlaEngineRtAudio() override
  149. {
  150. CARLA_SAFE_ASSERT(fAudioInBuf == nullptr);
  151. CARLA_SAFE_ASSERT(fAudioInCount == 0);
  152. CARLA_SAFE_ASSERT(fAudioOutBuf == nullptr);
  153. CARLA_SAFE_ASSERT(fAudioOutCount == 0);
  154. carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
  155. fUsedMidiIns.clear();
  156. fUsedMidiOuts.clear();
  157. }
  158. // -------------------------------------
  159. bool init(const char* const clientName) override
  160. {
  161. CARLA_SAFE_ASSERT_RETURN(fAudioInBuf == nullptr, false);
  162. CARLA_SAFE_ASSERT_RETURN(fAudioInCount == 0, false);
  163. CARLA_SAFE_ASSERT_RETURN(fAudioOutBuf == nullptr, false);
  164. CARLA_SAFE_ASSERT_RETURN(fAudioOutCount == 0, false);
  165. CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0', false);
  166. carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName);
  167. if (pData->options.processMode != ENGINE_PROCESS_MODE_CONTINUOUS_RACK && pData->options.processMode != ENGINE_PROCESS_MODE_PATCHBAY)
  168. {
  169. setLastError("Invalid process mode");
  170. return false;
  171. }
  172. const uint devCount(fAudio.getDeviceCount());
  173. if (devCount == 0)
  174. {
  175. setLastError("No audio devices available for this driver");
  176. return false;
  177. }
  178. RtAudio::StreamParameters iParams, oParams;
  179. bool deviceSet = false;
  180. if (pData->options.audioDevice != nullptr && pData->options.audioDevice[0] != '\0')
  181. {
  182. for (uint i=0; i < devCount; ++i)
  183. {
  184. RtAudio::DeviceInfo devInfo(fAudio.getDeviceInfo(i));
  185. if (devInfo.probed && devInfo.outputChannels > 0 && devInfo.name == pData->options.audioDevice)
  186. {
  187. deviceSet = true;
  188. fDeviceName = devInfo.name.c_str();
  189. iParams.deviceId = i;
  190. oParams.deviceId = i;
  191. iParams.nChannels = devInfo.inputChannels;
  192. oParams.nChannels = devInfo.outputChannels;
  193. break;
  194. }
  195. }
  196. }
  197. if (! deviceSet)
  198. {
  199. iParams.deviceId = fAudio.getDefaultInputDevice();
  200. oParams.deviceId = fAudio.getDefaultOutputDevice();
  201. iParams.nChannels = fAudio.getDeviceInfo(iParams.deviceId).inputChannels;
  202. oParams.nChannels = fAudio.getDeviceInfo(oParams.deviceId).outputChannels;
  203. carla_stdout("No device set, using %i inputs and %i outputs", iParams.nChannels, oParams.nChannels);
  204. }
  205. if (oParams.nChannels == 0)
  206. {
  207. setLastError("Current audio setup has no outputs, cannot continue");
  208. return false;
  209. }
  210. RtAudio::StreamOptions rtOptions;
  211. rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_NONINTERLEAVED;
  212. rtOptions.streamName = clientName;
  213. rtOptions.priority = 85;
  214. if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA && ! deviceSet)
  215. rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
  216. uint bufferFrames = pData->options.audioBufferSize;
  217. try {
  218. fAudio.openStream(&oParams, (iParams.nChannels > 0) ? &iParams : nullptr, RTAUDIO_FLOAT32, pData->options.audioSampleRate, &bufferFrames, carla_rtaudio_process_callback, this, &rtOptions);
  219. }
  220. catch (const RtError& e) {
  221. setLastError(e.what());
  222. return false;
  223. }
  224. pData->bufferSize = bufferFrames;
  225. pData->sampleRate = fAudio.getStreamSampleRate();
  226. fAudioInCount = iParams.nChannels;
  227. if (fAudioInCount > 0)
  228. {
  229. fAudioInBuf = new float*[fAudioInCount];
  230. // set as null first
  231. for (uint i=0; i < fAudioInCount; ++i)
  232. fAudioInBuf[i] = nullptr;
  233. for (uint i=0; i < fAudioInCount; ++i)
  234. {
  235. fAudioInBuf[i] = new float[pData->bufferSize];
  236. FLOAT_CLEAR(fAudioInBuf[i], pData->bufferSize);
  237. }
  238. }
  239. fAudioOutCount = oParams.nChannels;
  240. if (fAudioOutCount > 0)
  241. {
  242. fAudioOutBuf = new float*[fAudioOutCount];
  243. // set as null first
  244. for (uint i=0; i < fAudioOutCount; ++i)
  245. fAudioOutBuf[i] = nullptr;
  246. for (uint i=0; i < fAudioOutCount; ++i)
  247. {
  248. fAudioOutBuf[i] = new float[pData->bufferSize];
  249. FLOAT_CLEAR(fAudioOutBuf[i], pData->bufferSize);
  250. }
  251. }
  252. if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
  253. {
  254. pData->audio.inCount = 2;
  255. pData->audio.outCount = 2;
  256. }
  257. else
  258. {
  259. pData->audio.inCount = 0;
  260. pData->audio.outCount = 0;
  261. }
  262. pData->audio.create(pData->bufferSize);
  263. try {
  264. fAudio.startStream();
  265. }
  266. catch (const RtError& e)
  267. {
  268. close();
  269. setLastError(e.what());
  270. return false;
  271. }
  272. CarlaEngine::init(clientName);
  273. pData->audio.isReady = true;
  274. patchbayRefresh();
  275. return true;
  276. }
  277. bool close() override
  278. {
  279. CARLA_SAFE_ASSERT(fAudioOutBuf != nullptr);
  280. CARLA_SAFE_ASSERT(fAudioOutCount != 0);
  281. carla_debug("CarlaEngineRtAudio::close()");
  282. pData->audio.isReady = false;
  283. bool hasError = !CarlaEngine::close();
  284. if (fAudio.isStreamOpen())
  285. {
  286. if (fAudio.isStreamRunning())
  287. {
  288. try {
  289. fAudio.stopStream();
  290. }
  291. catch (const RtError& e)
  292. {
  293. if (! hasError)
  294. {
  295. setLastError(e.what());
  296. hasError = true;
  297. }
  298. }
  299. }
  300. fAudio.closeStream();
  301. }
  302. if (fAudioInBuf != nullptr)
  303. {
  304. for (uint i=0; i < fAudioInCount; ++i)
  305. {
  306. if (fAudioInBuf[i] != nullptr)
  307. {
  308. delete[] fAudioInBuf[i];
  309. fAudioInBuf[i] = nullptr;
  310. }
  311. }
  312. delete[] fAudioInBuf;
  313. fAudioInBuf = nullptr;
  314. }
  315. fAudioInCount = 0;
  316. if (fAudioOutBuf != nullptr)
  317. {
  318. for (uint i=0; i < fAudioOutCount; ++i)
  319. {
  320. if (fAudioOutBuf[i] != nullptr)
  321. {
  322. delete[] fAudioOutBuf[i];
  323. fAudioOutBuf[i] = nullptr;
  324. }
  325. }
  326. delete[] fAudioOutBuf;
  327. fAudioOutBuf = nullptr;
  328. }
  329. fAudioOutCount = 0;
  330. for (LinkedList<MidiPort>::Itenerator it = fMidiIns.begin(); it.valid(); it.next())
  331. {
  332. MidiPort& port(it.getValue());
  333. RtMidiIn* const midiInPort((RtMidiIn*)port.rtmidi);
  334. midiInPort->cancelCallback();
  335. delete midiInPort;
  336. }
  337. for (LinkedList<MidiPort>::Itenerator it = fMidiOuts.begin(); it.valid(); it.next())
  338. {
  339. MidiPort& port(it.getValue());
  340. RtMidiOut* const midiOutPort((RtMidiOut*)port.rtmidi);
  341. delete midiOutPort;
  342. }
  343. fLastEventTime = 0;
  344. fDeviceName.clear();
  345. fMidiIns.clear();
  346. fMidiOuts.clear();
  347. fMidiInEvents.clear();
  348. //fMidiOutEvents.clear();
  349. return !hasError;
  350. }
  351. bool isRunning() const noexcept override
  352. {
  353. return fAudio.isStreamRunning();
  354. }
  355. bool isOffline() const noexcept override
  356. {
  357. return false;
  358. }
  359. EngineType getType() const noexcept override
  360. {
  361. return kEngineTypeRtAudio;
  362. }
  363. const char* getCurrentDriverName() const noexcept override
  364. {
  365. return CarlaBackend::getRtAudioApiName(fAudio.getCurrentApi());
  366. }
  367. // -------------------------------------------------------------------
  368. // Patchbay
  369. bool patchbayRefresh() noexcept override
  370. {
  371. CARLA_SAFE_ASSERT_RETURN(pData->audio.isReady, false);
  372. fUsedMidiIns.clear();
  373. fUsedMidiOuts.clear();
  374. if (pData->graph.isRack)
  375. patchbayRefreshRack();
  376. else
  377. patchbayRefreshPatchbay();
  378. return true;
  379. }
  380. void patchbayRefreshRack() noexcept
  381. {
  382. RackGraph* const rack(pData->graph.rack);
  383. rack->lastConnectionId = 0;
  384. rack->usedConnections.clear();
  385. char strBuf[STR_MAX+1];
  386. strBuf[STR_MAX] = '\0';
  387. // Main
  388. {
  389. callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_CARLA, PATCHBAY_ICON_CARLA, -1, 0.0f, getName());
  390. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN1, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in1");
  391. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_IN2, PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, "audio-in2");
  392. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT1, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out1");
  393. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_AUDIO_OUT2, PATCHBAY_PORT_TYPE_AUDIO, 0.0f, "audio-out2");
  394. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_IN, PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, "midi-in");
  395. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_CARLA, RACK_GRAPH_CARLA_PORT_MIDI_OUT, PATCHBAY_PORT_TYPE_MIDI, 0.0f, "midi-out");
  396. }
  397. // Audio In
  398. {
  399. if (fDeviceName.isNotEmpty())
  400. std::snprintf(strBuf, STR_MAX, "Capture (%s)", fDeviceName.buffer());
  401. else
  402. std::strncpy(strBuf, "Capture", STR_MAX);
  403. callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
  404. for (uint i=0; i < fAudioInCount; ++i)
  405. {
  406. std::snprintf(strBuf, STR_MAX, "capture_%i", i+1);
  407. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_IN, static_cast<int>(i), PATCHBAY_PORT_TYPE_AUDIO, 0.0f, strBuf);
  408. }
  409. }
  410. // Audio Out
  411. {
  412. if (fDeviceName.isNotEmpty())
  413. std::snprintf(strBuf, STR_MAX, "Playback (%s)", fDeviceName.buffer());
  414. else
  415. std::strncpy(strBuf, "Playback", STR_MAX);
  416. callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, strBuf);
  417. for (uint i=0; i < fAudioOutCount; ++i)
  418. {
  419. std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);
  420. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_AUDIO_OUT, static_cast<int>(i), PATCHBAY_PORT_TYPE_AUDIO|PATCHBAY_PORT_IS_INPUT, 0.0f, strBuf);
  421. }
  422. }
  423. // MIDI In
  424. {
  425. callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Readable MIDI ports");
  426. for (uint i=0, count=fDummyMidiIn.getPortCount(); i < count; ++i)
  427. {
  428. PortNameToId portNameToId;
  429. portNameToId.port = static_cast<int>(i);
  430. std::strncpy(portNameToId.name, fDummyMidiIn.getPortName(i).c_str(), STR_MAX);
  431. portNameToId.name[STR_MAX] = '\0';
  432. fUsedMidiIns.append(portNameToId);
  433. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_IN, portNameToId.port, PATCHBAY_PORT_TYPE_MIDI, 0.0f, portNameToId.name);
  434. }
  435. }
  436. // MIDI Out
  437. {
  438. callback(ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, PATCHBAY_ICON_HARDWARE, -1, 0.0f, "Writable MIDI ports");
  439. for (uint i=0, count=fDummyMidiOut.getPortCount(); i < count; ++i)
  440. {
  441. PortNameToId portNameToId;
  442. portNameToId.port = static_cast<int>(i);
  443. std::strncpy(portNameToId.name, fDummyMidiOut.getPortName(i).c_str(), STR_MAX);
  444. portNameToId.name[STR_MAX] = '\0';
  445. fUsedMidiOuts.append(portNameToId);
  446. callback(ENGINE_CALLBACK_PATCHBAY_PORT_ADDED, RACK_GRAPH_GROUP_MIDI_OUT, portNameToId.port, PATCHBAY_PORT_TYPE_MIDI|PATCHBAY_PORT_IS_INPUT, 0.0f, portNameToId.name);
  447. }
  448. }
  449. // Connections
  450. rack->connectLock.lock();
  451. for (LinkedList<int>::Itenerator it = rack->connectedIn1.begin(); it.valid(); it.next())
  452. {
  453. const int& port(it.getValue());
  454. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(fAudioInCount));
  455. ConnectionToId connectionToId;
  456. connectionToId.id = rack->lastConnectionId;
  457. connectionToId.groupA = RACK_GRAPH_GROUP_AUDIO_IN;
  458. connectionToId.portA = port;
  459. connectionToId.groupB = RACK_GRAPH_GROUP_CARLA;
  460. connectionToId.portB = RACK_GRAPH_CARLA_PORT_AUDIO_IN1;
  461. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  462. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, rack->lastConnectionId, 0, 0, 0.0f, strBuf);
  463. rack->usedConnections.append(connectionToId);
  464. ++rack->lastConnectionId;
  465. }
  466. for (LinkedList<int>::Itenerator it = rack->connectedIn2.begin(); it.valid(); it.next())
  467. {
  468. const int& port(it.getValue());
  469. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(fAudioInCount));
  470. ConnectionToId connectionToId;
  471. connectionToId.id = rack->lastConnectionId;
  472. connectionToId.groupA = RACK_GRAPH_GROUP_AUDIO_IN;
  473. connectionToId.portA = port;
  474. connectionToId.groupB = RACK_GRAPH_GROUP_CARLA;
  475. connectionToId.portB = RACK_GRAPH_CARLA_PORT_AUDIO_IN2;
  476. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  477. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, rack->lastConnectionId, 0, 0, 0.0f, strBuf);
  478. rack->usedConnections.append(connectionToId);
  479. ++rack->lastConnectionId;
  480. }
  481. for (LinkedList<int>::Itenerator it = rack->connectedOut1.begin(); it.valid(); it.next())
  482. {
  483. const int& port(it.getValue());
  484. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(fAudioOutCount));
  485. ConnectionToId connectionToId;
  486. connectionToId.id = rack->lastConnectionId;
  487. connectionToId.groupA = RACK_GRAPH_GROUP_CARLA;
  488. connectionToId.portA = RACK_GRAPH_CARLA_PORT_AUDIO_OUT1;
  489. connectionToId.groupB = RACK_GRAPH_GROUP_AUDIO_OUT;
  490. connectionToId.portB = port;
  491. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  492. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, rack->lastConnectionId, 0, 0, 0.0f, strBuf);
  493. rack->usedConnections.append(connectionToId);
  494. ++rack->lastConnectionId;
  495. }
  496. for (LinkedList<int>::Itenerator it = rack->connectedOut2.begin(); it.valid(); it.next())
  497. {
  498. const int& port(it.getValue());
  499. CARLA_SAFE_ASSERT_CONTINUE(port >= 0 && port < static_cast<int>(fAudioOutCount));
  500. ConnectionToId connectionToId;
  501. connectionToId.id = rack->lastConnectionId;
  502. connectionToId.groupA = RACK_GRAPH_GROUP_CARLA;
  503. connectionToId.portA = RACK_GRAPH_CARLA_PORT_AUDIO_OUT2;
  504. connectionToId.groupB = RACK_GRAPH_GROUP_AUDIO_OUT;
  505. connectionToId.portB = port;
  506. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  507. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, rack->lastConnectionId, 0, 0, 0.0f, strBuf);
  508. rack->usedConnections.append(connectionToId);
  509. ++rack->lastConnectionId;
  510. }
  511. rack->connectLock.unlock();
  512. for (LinkedList<MidiPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
  513. {
  514. const MidiPort& midiPort(it.getValue());
  515. ConnectionToId connectionToId;
  516. connectionToId.id = rack->lastConnectionId;
  517. connectionToId.groupA = RACK_GRAPH_GROUP_MIDI_IN;
  518. connectionToId.portA = midiPort.portId;
  519. connectionToId.groupB = RACK_GRAPH_GROUP_CARLA;
  520. connectionToId.portB = RACK_GRAPH_CARLA_PORT_MIDI_IN;
  521. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  522. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, rack->lastConnectionId, 0, 0, 0.0f, strBuf);
  523. rack->usedConnections.append(connectionToId);
  524. ++rack->lastConnectionId;
  525. }
  526. for (LinkedList<MidiPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
  527. {
  528. const MidiPort& midiPort(it.getValue());
  529. ConnectionToId connectionToId;
  530. connectionToId.id = rack->lastConnectionId;
  531. connectionToId.groupA = RACK_GRAPH_GROUP_CARLA;
  532. connectionToId.portA = RACK_GRAPH_CARLA_PORT_MIDI_OUT;
  533. connectionToId.groupB = RACK_GRAPH_GROUP_MIDI_OUT;
  534. connectionToId.portB = midiPort.portId;
  535. std::snprintf(strBuf, STR_MAX, "%i:%i:%i:%i", connectionToId.groupA, connectionToId.portA, connectionToId.groupB, connectionToId.portB);
  536. callback(ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED, rack->lastConnectionId, 0, 0, 0.0f, strBuf);
  537. rack->usedConnections.append(connectionToId);
  538. ++rack->lastConnectionId;
  539. }
  540. }
  541. void patchbayRefreshPatchbay() noexcept
  542. {
  543. }
  544. // -------------------------------------------------------------------
  545. protected:
  546. void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, uint nframes, double streamTime, RtAudioStreamStatus status)
  547. {
  548. // get buffers from RtAudio
  549. float* const insPtr = (float*)inputBuffer;
  550. float* const outsPtr = (float*)outputBuffer;
  551. // assert rtaudio buffers
  552. CARLA_SAFE_ASSERT_RETURN(outputBuffer != nullptr,);
  553. CARLA_SAFE_ASSERT_RETURN(nframes == pData->bufferSize,);
  554. if (! pData->audio.isReady)
  555. return runPendingRtEvents();
  556. // initialize rtaudio input
  557. for (uint i=0; i < fAudioInCount; ++i)
  558. FLOAT_COPY(fAudioInBuf[i], insPtr+(nframes*i), nframes);
  559. // initialize rtaudio output
  560. for (uint i=0; i < fAudioOutCount; ++i)
  561. FLOAT_CLEAR(fAudioOutBuf[i], nframes);
  562. // initialize input events
  563. carla_zeroStruct<EngineEvent>(pData->events.in, kMaxEngineEventInternalCount);
  564. if (fMidiInEvents.mutex.tryLock())
  565. {
  566. uint32_t engineEventIndex = 0;
  567. fMidiInEvents.splice();
  568. while (! fMidiInEvents.data.isEmpty())
  569. {
  570. const RtMidiEvent& midiEvent(fMidiInEvents.data.getFirst(true));
  571. EngineEvent& engineEvent(pData->events.in[engineEventIndex++]);
  572. if (midiEvent.time < pData->timeInfo.frame)
  573. {
  574. engineEvent.time = 0;
  575. }
  576. else if (midiEvent.time >= pData->timeInfo.frame + nframes)
  577. {
  578. carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent.time, pData->timeInfo.frame);
  579. engineEvent.time = static_cast<uint32_t>(pData->timeInfo.frame) + nframes - 1;
  580. }
  581. else
  582. engineEvent.time = static_cast<uint32_t>(midiEvent.time - pData->timeInfo.frame);
  583. engineEvent.fillFromMidiData(midiEvent.size, midiEvent.data);
  584. if (engineEventIndex >= kMaxEngineEventInternalCount)
  585. break;
  586. }
  587. fMidiInEvents.mutex.unlock();
  588. }
  589. if (pData->graph.isRack)
  590. {
  591. pData->processRackFull(fAudioInBuf, fAudioInCount, fAudioOutBuf, fAudioOutCount, nframes, false);
  592. }
  593. else
  594. {
  595. }
  596. // output audio
  597. for (uint i=0; i < fAudioOutCount; ++i)
  598. FLOAT_COPY(outsPtr+(nframes*i), fAudioOutBuf[i], nframes);
  599. // output events
  600. {
  601. // TODO
  602. //fMidiOutEvents...
  603. }
  604. runPendingRtEvents();
  605. return;
  606. // unused
  607. (void)streamTime;
  608. (void)status;
  609. }
  610. void handleMidiCallback(double timeStamp, std::vector<uchar>* const message)
  611. {
  612. if (! pData->audio.isReady)
  613. return;
  614. const size_t messageSize(message->size());
  615. if (messageSize == 0 || messageSize > EngineMidiEvent::kDataSize)
  616. return;
  617. timeStamp /= 2;
  618. if (timeStamp > 0.95)
  619. timeStamp = 0.95;
  620. else if (timeStamp < 0.0)
  621. timeStamp = 0.0;
  622. RtMidiEvent midiEvent;
  623. midiEvent.time = pData->timeInfo.frame + uint64_t(timeStamp * (double)pData->bufferSize);
  624. if (midiEvent.time < fLastEventTime)
  625. midiEvent.time = fLastEventTime;
  626. else
  627. fLastEventTime = midiEvent.time;
  628. midiEvent.size = static_cast<uint8_t>(messageSize);
  629. size_t i=0;
  630. for (; i < messageSize; ++i)
  631. midiEvent.data[i] = message->at(i);
  632. for (; i < EngineMidiEvent::kDataSize; ++i)
  633. midiEvent.data[i] = 0;
  634. fMidiInEvents.append(midiEvent);
  635. }
  636. // -------------------------------------------------------------------
  637. bool connectRackMidiInPort(const int portId) override
  638. {
  639. CARLA_SAFE_ASSERT_RETURN(fUsedMidiIns.count() > 0, false);
  640. CARLA_SAFE_ASSERT_RETURN(portId >= 0, false);
  641. CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(portId) < fUsedMidiIns.count(), false);
  642. carla_debug("CarlaEngineRtAudio::connectRackMidiInPort(%i)", portId);
  643. const char* const portName(fUsedMidiIns.getAt(static_cast<size_t>(portId)).name);
  644. char newPortName[STR_MAX+1];
  645. std::snprintf(newPortName, STR_MAX, "%s:in-%i", getName(), portId+1);
  646. bool found = false;
  647. uint rtMidiPortIndex;
  648. RtMidiIn* const rtMidiIn(new RtMidiIn(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), newPortName, 512));
  649. rtMidiIn->ignoreTypes();
  650. rtMidiIn->setCallback(carla_rtmidi_callback, this);
  651. for (uint i=0, count=rtMidiIn->getPortCount(); i < count; ++i)
  652. {
  653. if (rtMidiIn->getPortName(i) == portName)
  654. {
  655. found = true;
  656. rtMidiPortIndex = i;
  657. break;
  658. }
  659. }
  660. if (! found)
  661. {
  662. delete rtMidiIn;
  663. return false;
  664. }
  665. rtMidiIn->openPort(rtMidiPortIndex, newPortName+(std::strlen(getName())+1));
  666. MidiPort midiPort;
  667. midiPort.portId = portId;
  668. midiPort.rtmidi = rtMidiIn;
  669. fMidiIns.append(midiPort);
  670. return true;
  671. }
  672. bool connectRackMidiOutPort(const int portId) override
  673. {
  674. CARLA_SAFE_ASSERT_RETURN(fUsedMidiOuts.count() > 0, false);
  675. CARLA_SAFE_ASSERT_RETURN(portId >= 0, false);
  676. CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(portId) < fUsedMidiOuts.count(), false);
  677. carla_debug("CarlaEngineRtAudio::connectRackMidiOutPort(%i)", portId);
  678. const char* const portName(fUsedMidiOuts.getAt(static_cast<size_t>(portId)).name);
  679. char newPortName[STR_MAX+1];
  680. std::snprintf(newPortName, STR_MAX, "%s:out-%i", getName(), portId+1);
  681. bool found = false;
  682. uint rtMidiPortIndex;
  683. RtMidiOut* const rtMidiOut(new RtMidiOut(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), newPortName));
  684. for (uint i=0, count=rtMidiOut->getPortCount(); i < count; ++i)
  685. {
  686. if (rtMidiOut->getPortName(i) == portName)
  687. {
  688. found = true;
  689. rtMidiPortIndex = i;
  690. break;
  691. }
  692. }
  693. if (! found)
  694. {
  695. delete rtMidiOut;
  696. return false;
  697. }
  698. rtMidiOut->openPort(rtMidiPortIndex, newPortName+(std::strlen(getName())+1));
  699. MidiPort midiPort;
  700. midiPort.portId = portId;
  701. midiPort.rtmidi = rtMidiOut;
  702. fMidiOuts.append(midiPort);
  703. return true;
  704. }
  705. bool disconnectRackMidiInPort(const int portId) override
  706. {
  707. CARLA_SAFE_ASSERT_RETURN(fUsedMidiIns.count() > 0, false);
  708. CARLA_SAFE_ASSERT_RETURN(portId >= 0, false);
  709. CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(portId) < fUsedMidiIns.count(), false);
  710. carla_debug("CarlaEngineRtAudio::connectRackMidiInPort(%i)", portId);
  711. for (LinkedList<MidiPort>::Itenerator it=fMidiOuts.begin(); it.valid(); it.next())
  712. {
  713. MidiPort& midiPort(it.getValue());
  714. if (midiPort.portId == portId)
  715. {
  716. RtMidiOut* const midiOutPort((RtMidiOut*)midiPort.rtmidi);
  717. delete midiOutPort;
  718. fMidiOuts.remove(it);
  719. return true;
  720. }
  721. }
  722. return false;
  723. }
  724. bool disconnectRackMidiOutPort(const int portId) override
  725. {
  726. CARLA_SAFE_ASSERT_RETURN(fUsedMidiOuts.count() > 0, false);
  727. CARLA_SAFE_ASSERT_RETURN(portId >= 0, false);
  728. CARLA_SAFE_ASSERT_RETURN(static_cast<size_t>(portId) < fUsedMidiOuts.count(), false);
  729. carla_debug("CarlaEngineRtAudio::disconnectRackMidiOutPort(%i)", portId);
  730. for (LinkedList<MidiPort>::Itenerator it=fMidiIns.begin(); it.valid(); it.next())
  731. {
  732. MidiPort& midiPort(it.getValue());
  733. if (midiPort.portId == portId)
  734. {
  735. RtMidiIn* const midiInPort((RtMidiIn*)midiPort.rtmidi);
  736. midiInPort->cancelCallback();
  737. delete midiInPort;
  738. fMidiIns.remove(it);
  739. return true;
  740. }
  741. }
  742. return false;
  743. }
  744. // -------------------------------------------------------------------
  745. private:
  746. RtAudio fAudio;
  747. // audio copy to split and de-interleave rtaudio buffers
  748. float** fAudioInBuf;
  749. uint fAudioInCount;
  750. float** fAudioOutBuf;
  751. uint fAudioOutCount;
  752. // useful info
  753. uint64_t fLastEventTime;
  754. // current device name
  755. CarlaString fDeviceName;
  756. // dummy rtmidi to scan available ports
  757. RtMidiIn fDummyMidiIn;
  758. RtMidiOut fDummyMidiOut;
  759. LinkedList<PortNameToId> fUsedMidiIns;
  760. LinkedList<PortNameToId> fUsedMidiOuts;
  761. struct MidiPort {
  762. RtMidi* rtmidi;
  763. int portId;
  764. };
  765. LinkedList<MidiPort> fMidiIns;
  766. LinkedList<MidiPort> fMidiOuts;
  767. struct RtMidiEvent {
  768. uint64_t time; // needs to compare to internal time
  769. uint8_t size;
  770. uint8_t data[EngineMidiEvent::kDataSize];
  771. };
  772. struct RtMidiEvents {
  773. CarlaMutex mutex;
  774. RtLinkedList<RtMidiEvent>::Pool dataPool;
  775. RtLinkedList<RtMidiEvent> data;
  776. RtLinkedList<RtMidiEvent> dataPending;
  777. RtMidiEvents()
  778. : dataPool(512, 512),
  779. data(dataPool),
  780. dataPending(dataPool) {}
  781. ~RtMidiEvents()
  782. {
  783. clear();
  784. }
  785. void append(const RtMidiEvent& event)
  786. {
  787. mutex.lock();
  788. dataPending.append(event);
  789. mutex.unlock();
  790. }
  791. void clear()
  792. {
  793. mutex.lock();
  794. data.clear();
  795. dataPending.clear();
  796. mutex.unlock();
  797. }
  798. void splice()
  799. {
  800. dataPending.spliceAppend(data);
  801. }
  802. };
  803. RtMidiEvents fMidiInEvents;
  804. //RtMidiEvents fMidiOutEvents;
  805. #define handlePtr ((CarlaEngineRtAudio*)userData)
  806. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, uint nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  807. {
  808. handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  809. return 0;
  810. }
  811. static void carla_rtmidi_callback(double timeStamp, std::vector<uchar>* message, void* userData)
  812. {
  813. handlePtr->handleMidiCallback(timeStamp, message);
  814. }
  815. #undef handlePtr
  816. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  817. };
  818. // -----------------------------------------
  819. CarlaEngine* CarlaEngine::newRtAudio(const AudioApi api)
  820. {
  821. initRtApis();
  822. RtAudio::Api rtApi(RtAudio::UNSPECIFIED);
  823. switch (api)
  824. {
  825. case AUDIO_API_NULL:
  826. rtApi = RtAudio::RTAUDIO_DUMMY;
  827. break;
  828. case AUDIO_API_JACK:
  829. rtApi = RtAudio::UNIX_JACK;
  830. break;
  831. case AUDIO_API_ALSA:
  832. rtApi = RtAudio::LINUX_ALSA;
  833. break;
  834. case AUDIO_API_OSS:
  835. rtApi = RtAudio::LINUX_OSS;
  836. break;
  837. case AUDIO_API_PULSE:
  838. rtApi = RtAudio::LINUX_PULSE;
  839. break;
  840. case AUDIO_API_CORE:
  841. rtApi = RtAudio::MACOSX_CORE;
  842. break;
  843. case AUDIO_API_ASIO:
  844. rtApi = RtAudio::WINDOWS_ASIO;
  845. break;
  846. case AUDIO_API_DS:
  847. rtApi = RtAudio::WINDOWS_DS;
  848. break;
  849. }
  850. return new CarlaEngineRtAudio(rtApi);
  851. }
  852. uint CarlaEngine::getRtAudioApiCount()
  853. {
  854. initRtApis();
  855. return static_cast<uint>(gRtAudioApis.size());
  856. }
  857. const char* CarlaEngine::getRtAudioApiName(const uint index)
  858. {
  859. initRtApis();
  860. if (index >= gRtAudioApis.size())
  861. return nullptr;
  862. return CarlaBackend::getRtAudioApiName(gRtAudioApis[index]);
  863. }
  864. const char* const* CarlaEngine::getRtAudioApiDeviceNames(const uint index)
  865. {
  866. initRtApis();
  867. if (index >= gRtAudioApis.size())
  868. return nullptr;
  869. const RtAudio::Api& api(gRtAudioApis[index]);
  870. RtAudio rtAudio(api);
  871. const uint devCount(rtAudio.getDeviceCount());
  872. if (devCount == 0)
  873. return nullptr;
  874. LinkedList<const char*> devNames;
  875. for (uint i=0; i < devCount; ++i)
  876. {
  877. RtAudio::DeviceInfo devInfo(rtAudio.getDeviceInfo(i));
  878. if (devInfo.probed && devInfo.outputChannels > 0 /*&& (devInfo.nativeFormats & RTAUDIO_FLOAT32) != 0*/)
  879. devNames.append(carla_strdup(devInfo.name.c_str()));
  880. }
  881. const size_t realDevCount(devNames.count());
  882. if (gRetNames != nullptr)
  883. {
  884. for (int i=0; gRetNames[i] != nullptr; ++i)
  885. delete[] gRetNames[i];
  886. delete[] gRetNames;
  887. }
  888. gRetNames = new const char*[realDevCount+1];
  889. for (size_t i=0; i < realDevCount; ++i)
  890. gRetNames[i] = devNames.getAt(i);
  891. gRetNames[realDevCount] = nullptr;
  892. devNames.clear();
  893. return gRetNames;
  894. }
  895. const EngineDriverDeviceInfo* CarlaEngine::getRtAudioDeviceInfo(const uint index, const char* const deviceName)
  896. {
  897. initRtApis();
  898. if (index >= gRtAudioApis.size())
  899. return nullptr;
  900. const RtAudio::Api& api(gRtAudioApis[index]);
  901. RtAudio rtAudio(api);
  902. const uint devCount(rtAudio.getDeviceCount());
  903. if (devCount == 0)
  904. return nullptr;
  905. uint i;
  906. RtAudio::DeviceInfo rtAudioDevInfo;
  907. for (i=0; i < devCount; ++i)
  908. {
  909. rtAudioDevInfo = rtAudio.getDeviceInfo(i);
  910. if (rtAudioDevInfo.name == deviceName)
  911. break;
  912. }
  913. if (i == devCount)
  914. return nullptr;
  915. static EngineDriverDeviceInfo devInfo = { 0x0, nullptr, nullptr };
  916. static uint32_t dummyBufferSizes[11] = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 0 };
  917. static double dummySampleRates[14] = { 22050.0, 32000.0, 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0, 0.0 };
  918. // reset
  919. devInfo.hints = 0x0;
  920. devInfo.bufferSizes = dummyBufferSizes;
  921. // cleanup
  922. if (devInfo.sampleRates != nullptr && devInfo.sampleRates != dummySampleRates)
  923. {
  924. delete[] devInfo.sampleRates;
  925. devInfo.sampleRates = nullptr;
  926. }
  927. if (size_t sampleRatesCount = rtAudioDevInfo.sampleRates.size())
  928. {
  929. double* const sampleRates(new double[sampleRatesCount+1]);
  930. for (size_t j=0; j < sampleRatesCount; ++j)
  931. sampleRates[j] = rtAudioDevInfo.sampleRates[j];
  932. sampleRates[sampleRatesCount] = 0.0;
  933. devInfo.sampleRates = sampleRates;
  934. }
  935. else
  936. {
  937. devInfo.sampleRates = dummySampleRates;
  938. }
  939. return &devInfo;
  940. }
  941. // -----------------------------------------
  942. CARLA_BACKEND_END_NAMESPACE