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.

1476 lines
45KB

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