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.

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