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.

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