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.

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