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.

1450 lines
44KB

  1. /*
  2. * Carla RtAudio Engine
  3. * Copyright (C) 2012-2013 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. #ifdef WANT_RTAUDIO
  18. #include "CarlaEngineInternal.hpp"
  19. #include "CarlaBackendUtils.hpp"
  20. #include "CarlaMIDI.h"
  21. #include "RtList.hpp"
  22. #include "RtAudio.h"
  23. #include "RtMidi.h"
  24. CARLA_BACKEND_START_NAMESPACE
  25. #if 0
  26. } // Fix editor indentation
  27. #endif
  28. // -------------------------------------------------------------------------------------------------------------------
  29. static const char** gRetNames = nullptr;
  30. static std::vector<RtAudio::Api> gRtAudioApis;
  31. static void initRtApis()
  32. {
  33. static bool initiated = false;
  34. if (! initiated)
  35. {
  36. initiated = true;
  37. RtAudio::getCompiledApi(gRtAudioApis);
  38. }
  39. }
  40. RtMidi::Api getMatchedAudioMidiAPi(const RtAudio::Api rtApi)
  41. {
  42. switch (rtApi)
  43. {
  44. case RtAudio::UNSPECIFIED:
  45. return RtMidi::UNSPECIFIED;
  46. case RtAudio::LINUX_ALSA:
  47. case RtAudio::LINUX_OSS:
  48. case RtAudio::LINUX_PULSE:
  49. return RtMidi::LINUX_ALSA;
  50. case RtAudio::UNIX_JACK:
  51. #if defined(CARLA_OS_WIN)
  52. return RtMidi::WINDOWS_MM;
  53. #elif defined(CARLA_OS_MAC)
  54. return RtMidi::MACOSX_CORE;
  55. #elif defined(CARLA_OS_LINUX)
  56. return RtMidi::LINUX_ALSA;
  57. #else
  58. return RtMidi::UNIX_JACK;
  59. #endif
  60. case RtAudio::MACOSX_CORE:
  61. return RtMidi::MACOSX_CORE;
  62. case RtAudio::WINDOWS_ASIO:
  63. case RtAudio::WINDOWS_DS:
  64. return RtMidi::WINDOWS_MM;
  65. case RtAudio::RTAUDIO_DUMMY:
  66. return RtMidi::RTMIDI_DUMMY;
  67. }
  68. return RtMidi::UNSPECIFIED;
  69. }
  70. // -------------------------------------------------------------------------------------------------------------------
  71. // RtAudio Engine
  72. class CarlaEngineRtAudio : public CarlaEngine
  73. {
  74. public:
  75. CarlaEngineRtAudio(const RtAudio::Api api)
  76. : CarlaEngine(),
  77. fAudio(api),
  78. fAudioBufIn(nullptr),
  79. fAudioBufOut(nullptr),
  80. fAudioBufRackIn{nullptr},
  81. fAudioBufRackOut{nullptr},
  82. fAudioCountIn(0),
  83. fAudioCountOut(0),
  84. fAudioIsInterleaved(false),
  85. fAudioIsReady(false),
  86. fDummyMidiIn(getMatchedAudioMidiAPi(api), "Carla-Probe-In"),
  87. fDummyMidiOut(getMatchedAudioMidiAPi(api), "Carla-Probe-Out"),
  88. fLastConnectionId(0)
  89. {
  90. carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);
  91. // just to make sure
  92. fOptions.forceStereo = true;
  93. fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
  94. }
  95. ~CarlaEngineRtAudio() override
  96. {
  97. CARLA_ASSERT(fAudioBufIn == nullptr);
  98. CARLA_ASSERT(fAudioBufOut == nullptr);
  99. CARLA_ASSERT(fAudioCountIn == 0);
  100. CARLA_ASSERT(fAudioCountOut == 0);
  101. CARLA_ASSERT(! fAudioIsReady);
  102. carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
  103. fUsedMidiIns.clear();
  104. fUsedMidiOuts.clear();
  105. fUsedConnections.clear();
  106. if (gRetNames != nullptr)
  107. {
  108. delete[] gRetNames;
  109. gRetNames = nullptr;
  110. }
  111. }
  112. // -------------------------------------
  113. bool init(const char* const clientName) override
  114. {
  115. CARLA_ASSERT(fAudioBufIn == nullptr);
  116. CARLA_ASSERT(fAudioBufOut == nullptr);
  117. CARLA_ASSERT(fAudioCountIn == 0);
  118. CARLA_ASSERT(fAudioCountOut == 0);
  119. CARLA_ASSERT(! fAudioIsReady);
  120. CARLA_ASSERT(clientName != nullptr);
  121. carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName);
  122. RtAudio::StreamParameters iParams, oParams;
  123. bool deviceSet = false;
  124. const unsigned int devCount(fAudio.getDeviceCount());
  125. if (devCount == 0)
  126. {
  127. setLastError("No audio devices available for this driver");
  128. return false;
  129. }
  130. if (fOptions.rtaudioDevice.isNotEmpty())
  131. {
  132. for (unsigned int i=0; i < devCount; ++i)
  133. {
  134. RtAudio::DeviceInfo devInfo(fAudio.getDeviceInfo(i));
  135. if (devInfo.probed && devInfo.outputChannels > 0 && devInfo.name == (const char*)fOptions.rtaudioDevice)
  136. {
  137. deviceSet = true;
  138. fConnectName = devInfo.name.c_str();
  139. iParams.deviceId = i;
  140. oParams.deviceId = i;
  141. iParams.nChannels = devInfo.inputChannels;
  142. oParams.nChannels = devInfo.outputChannels;
  143. break;
  144. }
  145. }
  146. }
  147. if (! deviceSet)
  148. {
  149. iParams.deviceId = fAudio.getDefaultInputDevice();
  150. oParams.deviceId = fAudio.getDefaultOutputDevice();
  151. iParams.nChannels = 2;
  152. oParams.nChannels = 2;
  153. }
  154. RtAudio::StreamOptions rtOptions;
  155. rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
  156. rtOptions.streamName = clientName;
  157. rtOptions.priority = 85;
  158. if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE)
  159. {
  160. rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
  161. fAudioIsInterleaved = false;
  162. if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA && ! deviceSet)
  163. rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
  164. }
  165. else
  166. fAudioIsInterleaved = true;
  167. fBufferSize = fOptions.rtaudioBufferSize;
  168. try {
  169. fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fOptions.rtaudioSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
  170. }
  171. catch (RtError& e)
  172. {
  173. setLastError(e.what());
  174. return false;
  175. }
  176. try {
  177. fAudio.startStream();
  178. }
  179. catch (RtError& e)
  180. {
  181. setLastError(e.what());
  182. fAudio.closeStream();
  183. return false;
  184. }
  185. fAudioCountIn = iParams.nChannels;
  186. fAudioCountOut = oParams.nChannels;
  187. fSampleRate = fAudio.getStreamSampleRate();
  188. CARLA_ASSERT(fAudioCountOut > 0);
  189. if (fAudioCountIn > 0)
  190. {
  191. fAudioBufIn = new float*[fAudioCountIn];
  192. for (uint i=0; i < fAudioCountIn; ++i)
  193. fAudioBufIn[i] = new float[fBufferSize];
  194. }
  195. if (fAudioCountOut > 0)
  196. {
  197. fAudioBufOut = new float*[fAudioCountOut];
  198. for (uint i=0; i < fAudioCountOut; ++i)
  199. fAudioBufOut[i] = new float[fBufferSize];
  200. }
  201. fAudioBufRackIn[0] = new float[fBufferSize];
  202. fAudioBufRackIn[1] = new float[fBufferSize];
  203. fAudioBufRackOut[0] = new float[fBufferSize];
  204. fAudioBufRackOut[1] = new float[fBufferSize];
  205. fAudioIsReady = true;
  206. CarlaEngine::init(clientName);
  207. patchbayRefresh();
  208. return true;
  209. }
  210. bool close() override
  211. {
  212. carla_debug("CarlaEngineRtAudio::close()");
  213. CARLA_ASSERT(fAudioBufOut != nullptr);
  214. CARLA_ASSERT(fAudioCountOut > 0);
  215. CARLA_ASSERT(fAudioIsReady);
  216. fAudioIsReady = false;
  217. bool hasError = !CarlaEngine::close();
  218. if (fAudio.isStreamRunning())
  219. {
  220. try {
  221. fAudio.stopStream();
  222. }
  223. catch (RtError& e)
  224. {
  225. if (! hasError)
  226. {
  227. setLastError(e.what());
  228. hasError = true;
  229. }
  230. }
  231. }
  232. if (fAudio.isStreamOpen())
  233. {
  234. try {
  235. fAudio.closeStream();
  236. }
  237. catch (RtError& e)
  238. {
  239. if (! hasError)
  240. {
  241. setLastError(e.what());
  242. hasError = true;
  243. }
  244. }
  245. }
  246. if (fAudioBufIn != nullptr)
  247. {
  248. CARLA_ASSERT(fAudioCountIn > 0);
  249. for (uint i=0; i < fAudioCountIn; ++i)
  250. delete[] fAudioBufIn[i];
  251. delete[] fAudioBufIn;
  252. fAudioBufIn = nullptr;
  253. }
  254. if (fAudioBufOut != nullptr)
  255. {
  256. CARLA_ASSERT(fAudioCountOut > 0);
  257. for (uint i=0; i < fAudioCountOut; ++i)
  258. delete[] fAudioBufOut[i];
  259. delete[] fAudioBufOut;
  260. fAudioBufOut = nullptr;
  261. }
  262. delete[] fAudioBufRackIn[0];
  263. delete[] fAudioBufRackIn[1];
  264. delete[] fAudioBufRackOut[0];
  265. delete[] fAudioBufRackOut[1];
  266. fAudioCountIn = 0;
  267. fAudioCountOut = 0;
  268. fConnectedAudioIns[0].clear();
  269. fConnectedAudioIns[1].clear();
  270. fConnectedAudioOuts[0].clear();
  271. fConnectedAudioOuts[1].clear();
  272. fConnectName.clear();
  273. for (auto it = fMidiIns.begin(); it.valid(); it.next())
  274. {
  275. MidiPort& port(*it);
  276. RtMidiIn* const midiInPort((RtMidiIn*)port.rtmidi);
  277. midiInPort->cancelCallback();
  278. delete midiInPort;
  279. }
  280. for (auto it = fMidiOuts.begin(); it.valid(); it.next())
  281. {
  282. MidiPort& port(*it);
  283. RtMidiOut* const midiOutPort((RtMidiOut*)port.rtmidi);
  284. delete midiOutPort;
  285. }
  286. fMidiIns.clear();
  287. fMidiOuts.clear();
  288. fMidiInEvents.clear();
  289. fMidiOutEvents.clear();
  290. return true;
  291. }
  292. bool isRunning() const override
  293. {
  294. return fAudio.isStreamRunning();
  295. }
  296. bool isOffline() const override
  297. {
  298. return false;
  299. }
  300. EngineType type() const override
  301. {
  302. return kEngineTypeRtAudio;
  303. }
  304. // -------------------------------------------------------------------
  305. // Patchbay
  306. bool patchbayConnect(int portA, int portB) override
  307. {
  308. CARLA_ASSERT(fAudioIsReady);
  309. CARLA_ASSERT(portA > PATCHBAY_PORT_MAX);
  310. CARLA_ASSERT(portB > PATCHBAY_PORT_MAX);
  311. if (! fAudioIsReady)
  312. {
  313. setLastError("Engine not ready");
  314. return false;
  315. }
  316. if (portA < PATCHBAY_PORT_MAX)
  317. {
  318. setLastError("Invalid output port");
  319. return false;
  320. }
  321. if (portB < PATCHBAY_PORT_MAX)
  322. {
  323. setLastError("Invalid input port");
  324. return false;
  325. }
  326. // only allow connections between Carla and other ports
  327. if (portA < 0 && portB < 0)
  328. {
  329. setLastError("Invalid connection");
  330. return false;
  331. }
  332. if (portA >= 0 && portB >= 0)
  333. {
  334. setLastError("Invalid connection");
  335. return false;
  336. }
  337. const int carlaPort = (portA < 0) ? portA : portB;
  338. const int targetPort = (carlaPort == portA) ? portB : portA;
  339. bool makeConnection = false;
  340. switch (carlaPort)
  341. {
  342. case PATCHBAY_PORT_AUDIO_IN1:
  343. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000);
  344. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_IN*1000+999);
  345. fConnectAudioLock.lock();
  346. fConnectedAudioIns[0].append(targetPort - PATCHBAY_GROUP_AUDIO_IN*1000);
  347. fConnectAudioLock.unlock();
  348. makeConnection = true;
  349. break;
  350. case PATCHBAY_PORT_AUDIO_IN2:
  351. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000);
  352. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_IN*1000+999);
  353. fConnectAudioLock.lock();
  354. fConnectedAudioIns[1].append(targetPort - PATCHBAY_GROUP_AUDIO_IN*1000);
  355. fConnectAudioLock.unlock();
  356. makeConnection = true;
  357. break;
  358. case PATCHBAY_PORT_AUDIO_OUT1:
  359. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000);
  360. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_OUT*1000+999);
  361. fConnectAudioLock.lock();
  362. fConnectedAudioOuts[0].append(targetPort - PATCHBAY_GROUP_AUDIO_OUT*1000);
  363. fConnectAudioLock.unlock();
  364. makeConnection = true;
  365. break;
  366. case PATCHBAY_PORT_AUDIO_OUT2:
  367. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000);
  368. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_AUDIO_OUT*1000+999);
  369. fConnectAudioLock.lock();
  370. fConnectedAudioOuts[1].append(targetPort - PATCHBAY_GROUP_AUDIO_OUT*1000);
  371. fConnectAudioLock.unlock();
  372. makeConnection = true;
  373. break;
  374. case PATCHBAY_PORT_MIDI_IN:
  375. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_MIDI_IN*1000);
  376. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_MIDI_IN*1000 + 999);
  377. makeConnection = connectMidiInPort(targetPort - PATCHBAY_GROUP_MIDI_IN*1000);
  378. break;
  379. case PATCHBAY_PORT_MIDI_OUT:
  380. CARLA_ASSERT(targetPort >= PATCHBAY_GROUP_MIDI_OUT*1000);
  381. CARLA_ASSERT(targetPort <= PATCHBAY_GROUP_MIDI_OUT*1000 + 999);
  382. makeConnection = connectMidiOutPort(targetPort - PATCHBAY_GROUP_MIDI_OUT*1000);
  383. break;
  384. }
  385. if (! makeConnection)
  386. {
  387. setLastError("Invalid connection");
  388. return false;
  389. }
  390. ConnectionToId connectionToId;
  391. connectionToId.id = fLastConnectionId;
  392. connectionToId.portOut = portA;
  393. connectionToId.portIn = portB;
  394. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, portA, portB, nullptr);
  395. fUsedConnections.append(connectionToId);
  396. fLastConnectionId++;
  397. return true;
  398. }
  399. bool patchbayDisconnect(int connectionId) override
  400. {
  401. CARLA_ASSERT(fAudioIsReady);
  402. CARLA_ASSERT(fUsedConnections.count() > 0);
  403. if (! fAudioIsReady)
  404. {
  405. setLastError("Engine not ready");
  406. return false;
  407. }
  408. if (fUsedConnections.count() == 0)
  409. {
  410. setLastError("No connections available");
  411. return false;
  412. }
  413. for (auto it=fUsedConnections.begin(); it.valid(); it.next())
  414. {
  415. const ConnectionToId& connection(*it);
  416. if (connection.id == connectionId)
  417. {
  418. const int targetPort((connection.portOut >= 0) ? connection.portOut : connection.portIn);
  419. const int carlaPort((targetPort == connection.portOut) ? connection.portIn : connection.portOut);
  420. if (targetPort >= PATCHBAY_GROUP_MIDI_OUT*1000)
  421. {
  422. int portId = targetPort-PATCHBAY_GROUP_MIDI_IN*1000;
  423. for (auto it=fMidiOuts.begin(); it.valid(); it.next())
  424. {
  425. MidiPort& midiPort(*it);
  426. if (midiPort.portId == portId)
  427. {
  428. RtMidiOut* const midiOutPort((RtMidiOut*)midiPort.rtmidi);
  429. delete midiOutPort;
  430. fMidiOuts.remove(it);
  431. break;
  432. }
  433. }
  434. }
  435. else if (targetPort >= PATCHBAY_GROUP_MIDI_IN*1000)
  436. {
  437. int portId = targetPort-PATCHBAY_GROUP_MIDI_IN*1000;
  438. for (auto it=fMidiIns.begin(); it.valid(); it.next())
  439. {
  440. MidiPort& midiPort(*it);
  441. if (midiPort.portId == portId)
  442. {
  443. RtMidiIn* const midiInPort((RtMidiIn*)midiPort.rtmidi);
  444. midiInPort->cancelCallback();
  445. delete midiInPort;
  446. fMidiIns.remove(it);
  447. break;
  448. }
  449. }
  450. }
  451. else if (targetPort >= PATCHBAY_GROUP_AUDIO_OUT*1000)
  452. {
  453. CARLA_ASSERT(carlaPort == PATCHBAY_PORT_AUDIO_OUT1 || carlaPort == PATCHBAY_PORT_AUDIO_OUT2);
  454. fConnectAudioLock.lock();
  455. if (carlaPort == PATCHBAY_PORT_AUDIO_OUT1)
  456. fConnectedAudioOuts[0].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_OUT*1000);
  457. else
  458. fConnectedAudioOuts[1].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_OUT*1000);
  459. fConnectAudioLock.unlock();
  460. }
  461. else if (targetPort >= PATCHBAY_GROUP_AUDIO_IN*1000)
  462. {
  463. CARLA_ASSERT(carlaPort == PATCHBAY_PORT_AUDIO_IN1 || carlaPort == PATCHBAY_PORT_AUDIO_IN2);
  464. fConnectAudioLock.lock();
  465. if (carlaPort == PATCHBAY_PORT_AUDIO_IN1)
  466. fConnectedAudioIns[0].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_IN*1000);
  467. else
  468. fConnectedAudioIns[1].removeAll(targetPort-PATCHBAY_GROUP_AUDIO_IN*1000);
  469. fConnectAudioLock.unlock();
  470. }
  471. else
  472. {
  473. CARLA_ASSERT(false);
  474. }
  475. callback(CALLBACK_PATCHBAY_CONNECTION_REMOVED, 0, connection.id, 0, 0.0f, nullptr);
  476. fUsedConnections.remove(it);
  477. break;
  478. }
  479. }
  480. return true;
  481. }
  482. void patchbayRefresh() override
  483. {
  484. CARLA_ASSERT(fAudioIsReady);
  485. if (! fAudioIsReady)
  486. return;
  487. char strBuf[STR_MAX+1];
  488. fLastConnectionId = 0;
  489. fUsedMidiIns.clear();
  490. fUsedMidiOuts.clear();
  491. fUsedConnections.clear();
  492. // Main
  493. {
  494. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_CARLA, 0, 0.0f, getName());
  495. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_IN1, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, "audio-in1");
  496. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_IN2, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, "audio-in2");
  497. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_OUT1, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, "audio-out1");
  498. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_AUDIO_OUT2, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, "audio-out2");
  499. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_MIDI_IN, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_INPUT, "midi-in");
  500. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_CARLA, PATCHBAY_PORT_MIDI_OUT, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_OUTPUT, "midi-out");
  501. }
  502. // Audio In
  503. {
  504. if (fConnectName.isNotEmpty())
  505. std::snprintf(strBuf, STR_MAX, "Capture (%s)", (const char*)fConnectName);
  506. else
  507. std::strncpy(strBuf, "Capture", STR_MAX);
  508. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_AUDIO_IN, 0, 0.0f, strBuf);
  509. for (unsigned int i=0; i < fAudioCountIn; ++i)
  510. {
  511. std::snprintf(strBuf, STR_MAX, "capture_%i", i+1);
  512. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_AUDIO_IN, PATCHBAY_GROUP_AUDIO_IN*1000 + i, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_OUTPUT, strBuf);
  513. }
  514. }
  515. // Audio Out
  516. {
  517. if (fConnectName.isNotEmpty())
  518. std::snprintf(strBuf, STR_MAX, "Playback (%s)", (const char*)fConnectName);
  519. else
  520. std::strncpy(strBuf, "Playback", STR_MAX);
  521. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_AUDIO_OUT, 0, 0.0f, strBuf);
  522. for (unsigned int i=0; i < fAudioCountOut; ++i)
  523. {
  524. std::snprintf(strBuf, STR_MAX, "playback_%i", i+1);
  525. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_AUDIO_OUT, PATCHBAY_GROUP_AUDIO_OUT*1000 + i, PATCHBAY_PORT_IS_AUDIO|PATCHBAY_PORT_IS_INPUT, strBuf);
  526. }
  527. }
  528. // MIDI In
  529. {
  530. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_MIDI_IN, 0, 0.0f, "Readable MIDI ports");
  531. for (unsigned int i=0, count=fDummyMidiIn.getPortCount(); i < count; ++i)
  532. {
  533. PortNameToId portNameToId;
  534. portNameToId.portId = PATCHBAY_GROUP_MIDI_IN*1000 + i;
  535. std::strncpy(portNameToId.name, fDummyMidiIn.getPortName(i).c_str(), STR_MAX);
  536. fUsedMidiIns.append(portNameToId);
  537. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_MIDI_IN, portNameToId.portId, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_OUTPUT, portNameToId.name);
  538. }
  539. }
  540. // MIDI Out
  541. {
  542. callback(CALLBACK_PATCHBAY_CLIENT_ADDED, 0, PATCHBAY_GROUP_MIDI_OUT, 0, 0.0f, "Writable MIDI ports");
  543. for (unsigned int i=0, count=fDummyMidiOut.getPortCount(); i < count; ++i)
  544. {
  545. PortNameToId portNameToId;
  546. portNameToId.portId = PATCHBAY_GROUP_MIDI_OUT*1000 + i;
  547. std::strncpy(portNameToId.name, fDummyMidiOut.getPortName(i).c_str(), STR_MAX);
  548. fUsedMidiOuts.append(portNameToId);
  549. callback(CALLBACK_PATCHBAY_PORT_ADDED, 0, PATCHBAY_GROUP_MIDI_OUT, portNameToId.portId, PATCHBAY_PORT_IS_MIDI|PATCHBAY_PORT_IS_INPUT, portNameToId.name);
  550. }
  551. }
  552. // Connections
  553. fConnectAudioLock.lock();
  554. for (auto it = fConnectedAudioIns[0].begin(); it.valid(); it.next())
  555. {
  556. const uint& port(*it);
  557. CARLA_ASSERT(port < fAudioCountIn);
  558. ConnectionToId connectionToId;
  559. connectionToId.id = fLastConnectionId;
  560. connectionToId.portOut = PATCHBAY_GROUP_AUDIO_IN*1000 + port;
  561. connectionToId.portIn = PATCHBAY_PORT_AUDIO_IN1;
  562. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  563. fUsedConnections.append(connectionToId);
  564. fLastConnectionId++;
  565. }
  566. for (auto it = fConnectedAudioIns[1].begin(); it.valid(); it.next())
  567. {
  568. const uint& port(*it);
  569. CARLA_ASSERT(port < fAudioCountIn);
  570. ConnectionToId connectionToId;
  571. connectionToId.id = fLastConnectionId;
  572. connectionToId.portOut = PATCHBAY_GROUP_AUDIO_IN*1000 + port;
  573. connectionToId.portIn = PATCHBAY_PORT_AUDIO_IN2;
  574. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  575. fUsedConnections.append(connectionToId);
  576. fLastConnectionId++;
  577. }
  578. for (auto it = fConnectedAudioOuts[0].begin(); it.valid(); it.next())
  579. {
  580. const uint& port(*it);
  581. CARLA_ASSERT(port < fAudioCountOut);
  582. ConnectionToId connectionToId;
  583. connectionToId.id = fLastConnectionId;
  584. connectionToId.portOut = PATCHBAY_PORT_AUDIO_OUT1;
  585. connectionToId.portIn = PATCHBAY_GROUP_AUDIO_OUT*1000 + port;
  586. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  587. fUsedConnections.append(connectionToId);
  588. fLastConnectionId++;
  589. }
  590. for (auto it = fConnectedAudioOuts[1].begin(); it.valid(); it.next())
  591. {
  592. const uint& port(*it);
  593. CARLA_ASSERT(port < fAudioCountOut);
  594. ConnectionToId connectionToId;
  595. connectionToId.id = fLastConnectionId;
  596. connectionToId.portOut = PATCHBAY_PORT_AUDIO_OUT2;
  597. connectionToId.portIn = PATCHBAY_GROUP_AUDIO_OUT*1000 + port;
  598. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  599. fUsedConnections.append(connectionToId);
  600. fLastConnectionId++;
  601. }
  602. fConnectAudioLock.unlock();
  603. for (auto it=fMidiIns.begin(); it.valid(); it.next())
  604. {
  605. const MidiPort& midiPort(*it);
  606. ConnectionToId connectionToId;
  607. connectionToId.id = fLastConnectionId;
  608. connectionToId.portOut = midiPort.portId;
  609. connectionToId.portIn = PATCHBAY_PORT_MIDI_IN;
  610. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  611. fUsedConnections.append(connectionToId);
  612. fLastConnectionId++;
  613. }
  614. for (auto it=fMidiOuts.begin(); it.valid(); it.next())
  615. {
  616. const MidiPort& midiPort(*it);
  617. ConnectionToId connectionToId;
  618. connectionToId.id = fLastConnectionId;
  619. connectionToId.portOut = PATCHBAY_PORT_MIDI_OUT;
  620. connectionToId.portIn = midiPort.portId;
  621. callback(CALLBACK_PATCHBAY_CONNECTION_ADDED, 0, fLastConnectionId, connectionToId.portOut, connectionToId.portIn, nullptr);
  622. fUsedConnections.append(connectionToId);
  623. fLastConnectionId++;
  624. }
  625. }
  626. // -------------------------------------------------------------------
  627. protected:
  628. void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  629. {
  630. // get buffers from RtAudio
  631. float* insPtr = (float*)inputBuffer;
  632. float* outsPtr = (float*)outputBuffer;
  633. // assert buffers
  634. CARLA_ASSERT(nframes == fBufferSize);
  635. CARLA_ASSERT(outsPtr != nullptr);
  636. if (kData->curPluginCount == 0 || ! (fAudioIsReady && fConnectAudioLock.tryLock()))
  637. {
  638. carla_zeroFloat(outsPtr, nframes*fAudioCountOut);
  639. return proccessPendingEvents();
  640. }
  641. // initialize audio input
  642. if (fAudioIsInterleaved)
  643. {
  644. for (unsigned int i=0, j=0; i < nframes*fAudioCountIn; ++i)
  645. {
  646. fAudioBufIn[i/fAudioCountIn][j] = insPtr[i];
  647. if ((i+1) % fAudioCountIn == 0)
  648. j += 1;
  649. }
  650. }
  651. else
  652. {
  653. for (unsigned int i=0; i < fAudioCountIn; ++i)
  654. carla_copyFloat(fAudioBufIn[i], insPtr+(nframes*i), nframes);
  655. }
  656. // initialize audio output
  657. for (unsigned int i=0; i < fAudioCountOut; ++i)
  658. carla_zeroFloat(fAudioBufOut[i], nframes);
  659. carla_zeroFloat(fAudioBufRackOut[0], nframes);
  660. carla_zeroFloat(fAudioBufRackOut[1], nframes);
  661. // initialize input events
  662. carla_zeroMem(kData->rack.in, sizeof(EngineEvent)*RACK_EVENT_COUNT);
  663. if (fMidiInEvents.mutex.tryLock())
  664. {
  665. uint32_t engineEventIndex = 0;
  666. fMidiInEvents.splice();
  667. while (! fMidiInEvents.data.isEmpty())
  668. {
  669. const RtMidiEvent& midiEvent(fMidiInEvents.data.getFirst(true));
  670. EngineEvent& engineEvent(kData->rack.in[engineEventIndex++]);
  671. engineEvent.clear();
  672. const uint8_t midiStatus = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  673. const uint8_t midiChannel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
  674. engineEvent.channel = midiChannel;
  675. if (midiEvent.time < fTimeInfo.frame)
  676. engineEvent.time = 0;
  677. else if (midiEvent.time >= fTimeInfo.frame + nframes)
  678. {
  679. engineEvent.time = fTimeInfo.frame + nframes-1;
  680. carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent.time, fTimeInfo.frame);
  681. }
  682. else
  683. engineEvent.time = midiEvent.time - fTimeInfo.frame;
  684. carla_stdout("Got midi, time %f vs %i", midiEvent.time, engineEvent.time);
  685. if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus))
  686. {
  687. const uint8_t midiControl = midiEvent.data[1];
  688. engineEvent.type = kEngineEventTypeControl;
  689. if (MIDI_IS_CONTROL_BANK_SELECT(midiControl))
  690. {
  691. const uint8_t midiBank = midiEvent.data[2];
  692. engineEvent.ctrl.type = kEngineControlEventTypeMidiBank;
  693. engineEvent.ctrl.param = midiBank;
  694. engineEvent.ctrl.value = 0.0f;
  695. }
  696. else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF)
  697. {
  698. engineEvent.ctrl.type = kEngineControlEventTypeAllSoundOff;
  699. engineEvent.ctrl.param = 0;
  700. engineEvent.ctrl.value = 0.0f;
  701. }
  702. else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF)
  703. {
  704. engineEvent.ctrl.type = kEngineControlEventTypeAllNotesOff;
  705. engineEvent.ctrl.param = 0;
  706. engineEvent.ctrl.value = 0.0f;
  707. }
  708. else
  709. {
  710. const uint8_t midiValue = midiEvent.data[2];
  711. engineEvent.ctrl.type = kEngineControlEventTypeParameter;
  712. engineEvent.ctrl.param = midiControl;
  713. engineEvent.ctrl.value = float(midiValue)/127.0f;
  714. }
  715. }
  716. else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
  717. {
  718. const uint8_t midiProgram = midiEvent.data[1];
  719. engineEvent.type = kEngineEventTypeControl;
  720. engineEvent.ctrl.type = kEngineControlEventTypeMidiProgram;
  721. engineEvent.ctrl.param = midiProgram;
  722. engineEvent.ctrl.value = 0.0f;
  723. }
  724. else
  725. {
  726. engineEvent.type = kEngineEventTypeMidi;
  727. engineEvent.midi.data[0] = midiStatus;
  728. engineEvent.midi.data[1] = midiEvent.data[1];
  729. engineEvent.midi.data[2] = midiEvent.data[2];
  730. engineEvent.midi.data[3] = midiEvent.data[3];
  731. engineEvent.midi.size = midiEvent.size;
  732. }
  733. if (engineEventIndex >= RACK_EVENT_COUNT)
  734. break;
  735. }
  736. fMidiInEvents.mutex.unlock();
  737. }
  738. // connect input buffers
  739. if (fConnectedAudioIns[0].count() == 0)
  740. {
  741. carla_zeroFloat(fAudioBufRackIn[0], nframes);
  742. }
  743. else
  744. {
  745. bool first = true;
  746. for (auto it = fConnectedAudioIns[0].begin(); it.valid(); it.next())
  747. {
  748. const uint& port(*it);
  749. CARLA_ASSERT(port < fAudioCountIn);
  750. if (first)
  751. {
  752. carla_copyFloat(fAudioBufRackIn[0], fAudioBufIn[port], nframes);
  753. first = false;
  754. }
  755. else
  756. carla_addFloat(fAudioBufRackIn[0], fAudioBufIn[port], nframes);
  757. }
  758. if (first)
  759. carla_zeroFloat(fAudioBufRackIn[0], nframes);
  760. }
  761. if (fConnectedAudioIns[1].count() == 0)
  762. {
  763. carla_zeroFloat(fAudioBufRackIn[1], nframes);
  764. }
  765. else
  766. {
  767. bool first = true;
  768. for (auto it = fConnectedAudioIns[1].begin(); it.valid(); it.next())
  769. {
  770. const uint& port(*it);
  771. CARLA_ASSERT(port < fAudioCountIn);
  772. if (first)
  773. {
  774. carla_copyFloat(fAudioBufRackIn[1], fAudioBufIn[port], nframes);
  775. first = false;
  776. }
  777. else
  778. carla_addFloat(fAudioBufRackIn[1], fAudioBufIn[port], nframes);
  779. }
  780. if (first)
  781. carla_zeroFloat(fAudioBufRackIn[1], nframes);
  782. }
  783. // process
  784. processRack(fAudioBufRackIn, fAudioBufRackOut, nframes);
  785. // connect output buffers
  786. if (fConnectedAudioOuts[0].count() != 0)
  787. {
  788. for (auto it = fConnectedAudioOuts[0].begin(); it.valid(); it.next())
  789. {
  790. const uint& port(*it);
  791. CARLA_ASSERT(port < fAudioCountOut);
  792. carla_addFloat(fAudioBufOut[port], fAudioBufRackOut[0], nframes);
  793. }
  794. }
  795. fConnectAudioLock.unlock();
  796. // output audio
  797. if (fAudioIsInterleaved)
  798. {
  799. for (unsigned int i=0, j=0; i < nframes*fAudioCountOut; ++i)
  800. {
  801. outsPtr[i] = fAudioBufOut[i/fAudioCountOut][j];
  802. if ((i+1) % fAudioCountOut == 0)
  803. j += 1;
  804. }
  805. }
  806. else
  807. {
  808. for (unsigned int i=0; i < fAudioCountOut; ++i)
  809. carla_copyFloat(outsPtr+(nframes*i), fAudioBufOut[i], nframes);
  810. }
  811. // output events
  812. {
  813. // TODO
  814. //fMidiOut.sendMessage();
  815. }
  816. proccessPendingEvents();
  817. return;
  818. // unused
  819. (void)streamTime;
  820. (void)status;
  821. }
  822. void handleMidiCallback(double timeStamp, std::vector<unsigned char>* const message)
  823. {
  824. if (! fAudioIsReady)
  825. return;
  826. const size_t messageSize = message->size();
  827. static uint32_t lastTime = 0;
  828. if (messageSize == 0 || messageSize > 4)
  829. return;
  830. timeStamp /= 2;
  831. if (timeStamp > 0.95)
  832. timeStamp = 0.95;
  833. else if (timeStamp < 0.0)
  834. timeStamp = 0.0;
  835. RtMidiEvent midiEvent;
  836. midiEvent.time = fTimeInfo.frame + (timeStamp*(double)fBufferSize);
  837. carla_stdout("Put midi, frame:%09i/%09i, stamp:%f", fTimeInfo.frame, midiEvent.time, timeStamp);
  838. if (midiEvent.time < lastTime)
  839. midiEvent.time = lastTime;
  840. else
  841. lastTime = midiEvent.time;
  842. if (messageSize == 1)
  843. {
  844. midiEvent.data[0] = message->at(0);
  845. midiEvent.data[1] = 0;
  846. midiEvent.data[2] = 0;
  847. midiEvent.data[3] = 0;
  848. midiEvent.size = 1;
  849. }
  850. else if (messageSize == 2)
  851. {
  852. midiEvent.data[0] = message->at(0);
  853. midiEvent.data[1] = message->at(1);
  854. midiEvent.data[2] = 0;
  855. midiEvent.data[3] = 0;
  856. midiEvent.size = 2;
  857. }
  858. else if (messageSize == 3)
  859. {
  860. midiEvent.data[0] = message->at(0);
  861. midiEvent.data[1] = message->at(1);
  862. midiEvent.data[2] = message->at(2);
  863. midiEvent.data[3] = 0;
  864. midiEvent.size = 3;
  865. }
  866. else
  867. {
  868. midiEvent.data[0] = message->at(0);
  869. midiEvent.data[1] = message->at(1);
  870. midiEvent.data[2] = message->at(2);
  871. midiEvent.data[3] = message->at(3);
  872. midiEvent.size = 4;
  873. }
  874. fMidiInEvents.append(midiEvent);
  875. }
  876. bool connectMidiInPort(const int portId)
  877. {
  878. const char* portName = nullptr;
  879. for (auto it = fUsedMidiIns.begin(); it.valid(); it.next())
  880. {
  881. const PortNameToId& portNameId(*it);
  882. if (portNameId.portId == portId)
  883. {
  884. portName = portNameId.name;
  885. break;
  886. }
  887. }
  888. if (portName == nullptr)
  889. return false;
  890. int rtMidiPortIndex = -1;
  891. RtMidiIn* const rtMidiIn(new RtMidiIn(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), getName(), 512));
  892. rtMidiIn->ignoreTypes();
  893. rtMidiIn->setCallback(carla_rtmidi_callback, this);
  894. for (unsigned int i=0, count=rtMidiIn->getPortCount(); i < count; ++i)
  895. {
  896. if (rtMidiIn->getPortName(i) == portName)
  897. {
  898. rtMidiPortIndex = i;
  899. break;
  900. }
  901. }
  902. if (rtMidiPortIndex == -1)
  903. {
  904. delete rtMidiIn;
  905. return false;
  906. }
  907. rtMidiIn->openPort(rtMidiPortIndex, "in");
  908. MidiPort midiPort;
  909. midiPort.portId = portId;
  910. midiPort.rtmidi = rtMidiIn;
  911. fMidiIns.append(midiPort);
  912. return true;
  913. }
  914. bool connectMidiOutPort(const int portId)
  915. {
  916. const char* portName = nullptr;
  917. for (auto it = fUsedMidiOuts.begin(); it.valid(); it.next())
  918. {
  919. const PortNameToId& portNameId(*it);
  920. if (portNameId.portId == portId)
  921. {
  922. portName = portNameId.name;
  923. break;
  924. }
  925. }
  926. if (portName == nullptr)
  927. return false;
  928. int rtMidiPortIndex = -1;
  929. RtMidiOut* const rtMidiOut(new RtMidiOut(getMatchedAudioMidiAPi(fAudio.getCurrentApi()), getName()));
  930. for (unsigned int i=0, count=rtMidiOut->getPortCount(); i < count; ++i)
  931. {
  932. if (rtMidiOut->getPortName(i) == portName)
  933. {
  934. rtMidiPortIndex = i;
  935. break;
  936. }
  937. }
  938. if (rtMidiPortIndex == -1)
  939. {
  940. delete rtMidiOut;
  941. return false;
  942. }
  943. rtMidiOut->openPort(rtMidiPortIndex, "in");
  944. MidiPort midiPort;
  945. midiPort.portId = portId;
  946. midiPort.rtmidi = rtMidiOut;
  947. fMidiOuts.append(midiPort);
  948. return true;
  949. }
  950. // -------------------------------------
  951. private:
  952. RtAudio fAudio;
  953. float** fAudioBufIn;
  954. float** fAudioBufOut;
  955. float* fAudioBufRackIn[2];
  956. float* fAudioBufRackOut[2];
  957. uint fAudioCountIn;
  958. uint fAudioCountOut;
  959. bool fAudioIsInterleaved;
  960. bool fAudioIsReady;
  961. NonRtList<uint> fConnectedAudioIns[2];
  962. NonRtList<uint> fConnectedAudioOuts[2];
  963. CarlaMutex fConnectAudioLock;
  964. CarlaString fConnectName;
  965. RtMidiIn fDummyMidiIn;
  966. RtMidiOut fDummyMidiOut;
  967. enum PatchbayGroupIds {
  968. PATCHBAY_GROUP_CARLA = -1,
  969. PATCHBAY_GROUP_AUDIO_IN = 0,
  970. PATCHBAY_GROUP_AUDIO_OUT = 1,
  971. PATCHBAY_GROUP_MIDI_IN = 2,
  972. PATCHBAY_GROUP_MIDI_OUT = 3,
  973. PATCHBAY_GROUP_MAX = 4
  974. };
  975. enum PatchbayPortIds {
  976. PATCHBAY_PORT_AUDIO_IN1 = -1,
  977. PATCHBAY_PORT_AUDIO_IN2 = -2,
  978. PATCHBAY_PORT_AUDIO_OUT1 = -3,
  979. PATCHBAY_PORT_AUDIO_OUT2 = -4,
  980. PATCHBAY_PORT_MIDI_IN = -5,
  981. PATCHBAY_PORT_MIDI_OUT = -6,
  982. PATCHBAY_PORT_MAX = -7
  983. };
  984. struct ConnectionToId {
  985. int id;
  986. int portOut;
  987. int portIn;
  988. };
  989. struct PortNameToId {
  990. int portId;
  991. char name[STR_MAX+1];
  992. };
  993. int fLastConnectionId;
  994. NonRtList<PortNameToId> fUsedMidiIns;
  995. NonRtList<PortNameToId> fUsedMidiOuts;
  996. NonRtList<ConnectionToId> fUsedConnections;
  997. struct MidiPort {
  998. RtMidi* rtmidi;
  999. int portId;
  1000. };
  1001. NonRtList<MidiPort> fMidiIns;
  1002. NonRtList<MidiPort> fMidiOuts;
  1003. struct RtMidiEvent {
  1004. uint32_t time;
  1005. unsigned char data[4];
  1006. unsigned char size;
  1007. };
  1008. struct RtMidiEvents {
  1009. CarlaMutex mutex;
  1010. RtList<RtMidiEvent>::Pool dataPool;
  1011. RtList<RtMidiEvent> data;
  1012. RtList<RtMidiEvent> dataPending;
  1013. RtMidiEvents()
  1014. : dataPool(512, 512),
  1015. data(&dataPool),
  1016. dataPending(&dataPool) {}
  1017. ~RtMidiEvents()
  1018. {
  1019. clear();
  1020. }
  1021. void append(const RtMidiEvent& event)
  1022. {
  1023. mutex.lock();
  1024. dataPending.append(event);
  1025. mutex.unlock();
  1026. }
  1027. void clear()
  1028. {
  1029. mutex.lock();
  1030. data.clear();
  1031. dataPending.clear();
  1032. mutex.unlock();
  1033. }
  1034. void splice()
  1035. {
  1036. dataPending.spliceAppend(data, true);
  1037. }
  1038. };
  1039. RtMidiEvents fMidiInEvents;
  1040. RtMidiEvents fMidiOutEvents;
  1041. #define handlePtr ((CarlaEngineRtAudio*)userData)
  1042. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  1043. {
  1044. handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  1045. return 0;
  1046. }
  1047. static void carla_rtmidi_callback(double timeStamp, std::vector<unsigned char>* message, void* userData)
  1048. {
  1049. handlePtr->handleMidiCallback(timeStamp, message);
  1050. }
  1051. #undef handlePtr
  1052. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  1053. };
  1054. // -----------------------------------------
  1055. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  1056. {
  1057. RtAudio::Api rtApi(RtAudio::UNSPECIFIED);
  1058. switch (api)
  1059. {
  1060. case RTAUDIO_DUMMY:
  1061. rtApi = RtAudio::RTAUDIO_DUMMY;
  1062. break;
  1063. case RTAUDIO_LINUX_ALSA:
  1064. rtApi = RtAudio::LINUX_ALSA;
  1065. break;
  1066. case RTAUDIO_LINUX_PULSE:
  1067. rtApi = RtAudio::LINUX_PULSE;
  1068. break;
  1069. case RTAUDIO_LINUX_OSS:
  1070. rtApi = RtAudio::LINUX_OSS;
  1071. break;
  1072. case RTAUDIO_UNIX_JACK:
  1073. rtApi = RtAudio::UNIX_JACK;
  1074. break;
  1075. case RTAUDIO_MACOSX_CORE:
  1076. rtApi = RtAudio::MACOSX_CORE;
  1077. break;
  1078. case RTAUDIO_WINDOWS_ASIO:
  1079. rtApi = RtAudio::WINDOWS_ASIO;
  1080. break;
  1081. case RTAUDIO_WINDOWS_DS:
  1082. rtApi = RtAudio::WINDOWS_DS;
  1083. break;
  1084. }
  1085. return new CarlaEngineRtAudio(rtApi);
  1086. }
  1087. size_t CarlaEngine::getRtAudioApiCount()
  1088. {
  1089. initRtApis();
  1090. return gRtAudioApis.size();
  1091. }
  1092. const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
  1093. {
  1094. initRtApis();
  1095. if (index < gRtAudioApis.size())
  1096. {
  1097. const RtAudio::Api& api(gRtAudioApis[index]);
  1098. switch (api)
  1099. {
  1100. case RtAudio::UNSPECIFIED:
  1101. return "Unspecified";
  1102. case RtAudio::LINUX_ALSA:
  1103. return "ALSA";
  1104. case RtAudio::LINUX_PULSE:
  1105. return "PulseAudio";
  1106. case RtAudio::LINUX_OSS:
  1107. return "OSS";
  1108. case RtAudio::UNIX_JACK:
  1109. #if defined(CARLA_OS_WIN)
  1110. return "JACK with WinMM";
  1111. #elif defined(CARLA_OS_MAC)
  1112. return "JACK with CoreMidi";
  1113. #elif defined(CARLA_OS_LINUX)
  1114. return "JACK with ALSA-MIDI";
  1115. #else
  1116. return "JACK (RtAudio)";
  1117. #endif
  1118. case RtAudio::MACOSX_CORE:
  1119. return "CoreAudio";
  1120. case RtAudio::WINDOWS_ASIO:
  1121. return "ASIO";
  1122. case RtAudio::WINDOWS_DS:
  1123. return "DirectSound";
  1124. case RtAudio::RTAUDIO_DUMMY:
  1125. return "Dummy";
  1126. }
  1127. }
  1128. return nullptr;
  1129. }
  1130. const char** CarlaEngine::getRtAudioApiDeviceNames(const unsigned int index)
  1131. {
  1132. initRtApis();
  1133. if (index < gRtAudioApis.size())
  1134. {
  1135. const RtAudio::Api& api(gRtAudioApis[index]);
  1136. RtAudio rtAudio(api);
  1137. if (gRetNames != nullptr)
  1138. {
  1139. int i=0;
  1140. while (gRetNames[i] != nullptr)
  1141. delete[] gRetNames[i++];
  1142. delete[] gRetNames;
  1143. gRetNames = nullptr;
  1144. }
  1145. const unsigned int devCount(rtAudio.getDeviceCount());
  1146. if (devCount > 0)
  1147. {
  1148. NonRtList<const char*> devNames;
  1149. for (unsigned int i=0; i < devCount; ++i)
  1150. {
  1151. RtAudio::DeviceInfo devInfo(rtAudio.getDeviceInfo(i));
  1152. if (devInfo.probed && devInfo.outputChannels > 0 /*&& (devInfo.nativeFormats & RTAUDIO_FLOAT32) != 0*/)
  1153. devNames.append(carla_strdup(devInfo.name.c_str()));
  1154. }
  1155. const unsigned int realDevCount(devNames.count());
  1156. gRetNames = new const char*[realDevCount+1];
  1157. for (unsigned int i=0; i < realDevCount; ++i)
  1158. gRetNames[i] = devNames.getAt(i);
  1159. gRetNames[realDevCount] = nullptr;
  1160. devNames.clear();
  1161. return gRetNames;
  1162. }
  1163. }
  1164. return nullptr;
  1165. }
  1166. // -----------------------------------------
  1167. CARLA_BACKEND_END_NAMESPACE
  1168. #endif // CARLA_ENGINE_RTAUDIO