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.

685 lines
19KB

  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. RtMidi::Api getMatchedAudioMidiAPi(const RtAudio::Api rtApi)
  30. {
  31. switch (rtApi)
  32. {
  33. case RtAudio::UNSPECIFIED:
  34. return RtMidi::UNSPECIFIED;
  35. case RtAudio::LINUX_ALSA:
  36. case RtAudio::LINUX_OSS:
  37. case RtAudio::LINUX_PULSE:
  38. return RtMidi::LINUX_ALSA;
  39. case RtAudio::UNIX_JACK:
  40. #if defined(CARLA_OS_WIN)
  41. return RtMidi::WINDOWS_MM;
  42. #elif defined(CARLA_OS_MAC)
  43. return RtMidi::MACOSX_CORE;
  44. #elif defined(CARLA_OS_LINUX)
  45. return RtMidi::LINUX_ALSA;
  46. #else
  47. return RtMidi::UNIX_JACK;
  48. #endif
  49. case RtAudio::MACOSX_CORE:
  50. return RtMidi::MACOSX_CORE;
  51. case RtAudio::WINDOWS_ASIO:
  52. case RtAudio::WINDOWS_DS:
  53. return RtMidi::WINDOWS_MM;
  54. case RtAudio::RTAUDIO_DUMMY:
  55. return RtMidi::RTMIDI_DUMMY;
  56. }
  57. return RtMidi::UNSPECIFIED;
  58. }
  59. // -------------------------------------------------------------------------------------------------------------------
  60. // RtAudio Engine
  61. class CarlaEngineRtAudio : public CarlaEngine
  62. {
  63. public:
  64. CarlaEngineRtAudio(const RtAudio::Api api)
  65. : CarlaEngine(),
  66. fAudio(api),
  67. fAudioIsInterleaved(false),
  68. fAudioIsReady(false),
  69. fAudioInBuf1(nullptr),
  70. fAudioInBuf2(nullptr),
  71. fAudioOutBuf1(nullptr),
  72. fAudioOutBuf2(nullptr),
  73. fMidiIn(getMatchedAudioMidiAPi(api), "Carla"),
  74. fMidiOut(getMatchedAudioMidiAPi(api), "Carla")
  75. {
  76. carla_debug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);
  77. // just to make sure
  78. fOptions.forceStereo = true;
  79. fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
  80. }
  81. ~CarlaEngineRtAudio()
  82. {
  83. carla_debug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
  84. CARLA_ASSERT(fAudioInBuf1 == nullptr);
  85. CARLA_ASSERT(fAudioInBuf2 == nullptr);
  86. CARLA_ASSERT(fAudioOutBuf1 == nullptr);
  87. CARLA_ASSERT(fAudioOutBuf2 == nullptr);
  88. }
  89. // -------------------------------------
  90. bool init(const char* const clientName)
  91. {
  92. carla_debug("CarlaEngineRtAudio::init(\"%s\")", clientName);
  93. CARLA_ASSERT(! fAudioIsReady);
  94. CARLA_ASSERT(fAudioInBuf1 == nullptr);
  95. CARLA_ASSERT(fAudioInBuf2 == nullptr);
  96. CARLA_ASSERT(fAudioOutBuf1 == nullptr);
  97. CARLA_ASSERT(fAudioOutBuf2 == nullptr);
  98. CARLA_ASSERT(clientName != nullptr);
  99. if (fAudio.getDeviceCount() == 0)
  100. {
  101. setLastError("No audio devices available for this driver");
  102. return false;
  103. }
  104. fBufferSize = fOptions.preferredBufferSize;
  105. // Audio
  106. {
  107. RtAudio::StreamParameters iParams, oParams;
  108. iParams.deviceId = fAudio.getDefaultInputDevice();
  109. oParams.deviceId = fAudio.getDefaultOutputDevice();
  110. iParams.nChannels = 2;
  111. oParams.nChannels = 2;
  112. RtAudio::StreamOptions rtOptions;
  113. rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
  114. rtOptions.numberOfBuffers = 2;
  115. rtOptions.streamName = clientName;
  116. rtOptions.priority = 85;
  117. if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE)
  118. {
  119. rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
  120. fAudioIsInterleaved = false;
  121. if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA)
  122. rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
  123. }
  124. else
  125. fAudioIsInterleaved = true;
  126. try {
  127. fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fOptions.preferredSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
  128. }
  129. catch (RtError& e)
  130. {
  131. carla_stderr2("RtAudio::openStream() failed");
  132. if (e.getType() == RtError::SYSTEM_ERROR)
  133. setLastError("Stream cannot be opened with the specified parameters");
  134. else if (e.getType() == RtError::INVALID_USE)
  135. setLastError("Invalid device ID");
  136. else
  137. setLastError("Unknown error");
  138. return false;
  139. }
  140. try {
  141. fAudio.startStream();
  142. }
  143. catch (RtError& e)
  144. {
  145. carla_stderr2("RtAudio::startStream() failed");
  146. setLastError(e.what());
  147. fAudio.closeStream();
  148. return false;
  149. }
  150. fAudioInBuf1 = new float[fBufferSize];
  151. fAudioInBuf2 = new float[fBufferSize];
  152. fAudioOutBuf1 = new float[fBufferSize];
  153. fAudioOutBuf2 = new float[fBufferSize];
  154. fSampleRate = fAudio.getStreamSampleRate();
  155. }
  156. // MIDI
  157. {
  158. fMidiIn.setCallback(carla_rtmidi_callback, this);
  159. fMidiIn.openVirtualPort("events-in");
  160. fMidiOut.openVirtualPort("events-out");
  161. }
  162. fAudioIsReady = true;
  163. return CarlaEngine::init(clientName);
  164. }
  165. bool close()
  166. {
  167. carla_debug("CarlaEngineRtAudio::close()");
  168. CARLA_ASSERT(fAudioIsReady);
  169. CARLA_ASSERT(fAudioInBuf1 != nullptr);
  170. CARLA_ASSERT(fAudioInBuf2 != nullptr);
  171. CARLA_ASSERT(fAudioOutBuf1 != nullptr);
  172. CARLA_ASSERT(fAudioOutBuf2 != nullptr);
  173. CarlaEngine::close();
  174. fAudioIsReady = false;
  175. if (fAudio.isStreamRunning())
  176. {
  177. try {
  178. fAudio.stopStream();
  179. }
  180. catch (...) {}
  181. }
  182. if (fAudio.isStreamOpen())
  183. {
  184. try {
  185. fAudio.closeStream();
  186. }
  187. catch (...) {}
  188. }
  189. fMidiIn.cancelCallback();
  190. fMidiIn.closePort();
  191. fMidiOut.closePort();
  192. if (fAudioInBuf1 != nullptr)
  193. {
  194. delete[] fAudioInBuf1;
  195. fAudioInBuf1 = nullptr;
  196. }
  197. if (fAudioInBuf2 != nullptr)
  198. {
  199. delete[] fAudioInBuf2;
  200. fAudioInBuf2 = nullptr;
  201. }
  202. if (fAudioOutBuf1 != nullptr)
  203. {
  204. delete[] fAudioOutBuf1;
  205. fAudioOutBuf1 = nullptr;
  206. }
  207. if (fAudioOutBuf2 != nullptr)
  208. {
  209. delete[] fAudioOutBuf2;
  210. fAudioOutBuf2 = nullptr;
  211. }
  212. fMidiInEvents.clear();
  213. fMidiOutEvents.clear();
  214. return true;
  215. }
  216. bool isRunning() const
  217. {
  218. return fAudio.isStreamRunning();
  219. }
  220. bool isOffline() const
  221. {
  222. return false;
  223. }
  224. EngineType type() const
  225. {
  226. return kEngineTypeRtAudio;
  227. }
  228. // -------------------------------------
  229. protected:
  230. void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  231. {
  232. // get buffers from RtAudio
  233. float* insPtr = (float*)inputBuffer;
  234. float* outsPtr = (float*)outputBuffer;
  235. // assert buffers
  236. CARLA_ASSERT(insPtr != nullptr);
  237. CARLA_ASSERT(outsPtr != nullptr);
  238. if (! fAudioIsReady)
  239. {
  240. carla_zeroFloat(outsPtr, nframes*2);
  241. return proccessPendingEvents();
  242. }
  243. if (kData->curPluginCount == 0)
  244. {
  245. // pass-through
  246. if (fOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK)
  247. carla_copyFloat(outsPtr, insPtr, nframes*2);
  248. return proccessPendingEvents();
  249. }
  250. // initialize audio input
  251. if (fAudioIsInterleaved)
  252. {
  253. for (unsigned int i=0; i < nframes*2; i++)
  254. {
  255. if (i % 2 == 0)
  256. fAudioInBuf1[i/2] = insPtr[i];
  257. else
  258. fAudioInBuf2[i/2] = insPtr[i];
  259. }
  260. }
  261. else
  262. {
  263. carla_copyFloat(fAudioInBuf1, insPtr, nframes);
  264. carla_copyFloat(fAudioInBuf2, insPtr+nframes, nframes);
  265. }
  266. // initialize audio output
  267. carla_zeroFloat(fAudioOutBuf1, fBufferSize);
  268. carla_zeroFloat(fAudioOutBuf2, fBufferSize);
  269. // initialize input events
  270. carla_zeroMem(kData->rack.in, sizeof(EngineEvent)*RACK_EVENT_COUNT);
  271. if (fMidiInEvents.mutex.tryLock())
  272. {
  273. uint32_t engineEventIndex = 0;
  274. fMidiInEvents.splice();
  275. while (! fMidiInEvents.data.isEmpty())
  276. {
  277. const RtMidiEvent& midiEvent = fMidiInEvents.data.getFirst(true);
  278. EngineEvent* const engineEvent = &kData->rack.in[engineEventIndex++];
  279. engineEvent->clear();
  280. const uint8_t midiStatus = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  281. const uint8_t midiChannel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
  282. engineEvent->channel = midiChannel;
  283. if (midiEvent.time < fTimeInfo.frame)
  284. engineEvent->time = 0;
  285. else if (midiEvent.time >= fTimeInfo.frame + nframes)
  286. {
  287. engineEvent->time = fTimeInfo.frame + nframes-1;
  288. carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent->time, fTimeInfo.frame);
  289. }
  290. else
  291. engineEvent->time = midiEvent.time - fTimeInfo.frame;
  292. //carla_stdout("Got midi, time %f vs %i", midiEvent.time, engineEvent->time);
  293. if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus))
  294. {
  295. const uint8_t midiControl = midiEvent.data[1];
  296. engineEvent->type = kEngineEventTypeControl;
  297. if (MIDI_IS_CONTROL_BANK_SELECT(midiControl))
  298. {
  299. const uint8_t midiBank = midiEvent.data[2];
  300. engineEvent->ctrl.type = kEngineControlEventTypeMidiBank;
  301. engineEvent->ctrl.param = midiBank;
  302. engineEvent->ctrl.value = 0.0;
  303. }
  304. else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF)
  305. {
  306. engineEvent->ctrl.type = kEngineControlEventTypeAllSoundOff;
  307. engineEvent->ctrl.param = 0;
  308. engineEvent->ctrl.value = 0.0;
  309. }
  310. else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF)
  311. {
  312. engineEvent->ctrl.type = kEngineControlEventTypeAllNotesOff;
  313. engineEvent->ctrl.param = 0;
  314. engineEvent->ctrl.value = 0.0;
  315. }
  316. else
  317. {
  318. const uint8_t midiValue = midiEvent.data[2];
  319. engineEvent->ctrl.type = kEngineControlEventTypeParameter;
  320. engineEvent->ctrl.param = midiControl;
  321. engineEvent->ctrl.value = double(midiValue)/127.0;
  322. }
  323. }
  324. else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
  325. {
  326. const uint8_t midiProgram = midiEvent.data[1];
  327. engineEvent->type = kEngineEventTypeControl;
  328. engineEvent->ctrl.type = kEngineControlEventTypeMidiProgram;
  329. engineEvent->ctrl.param = midiProgram;
  330. engineEvent->ctrl.value = 0.0;
  331. }
  332. else
  333. {
  334. engineEvent->type = kEngineEventTypeMidi;
  335. engineEvent->midi.data[0] = midiStatus;
  336. engineEvent->midi.data[1] = midiEvent.data[1];
  337. engineEvent->midi.data[2] = midiEvent.data[2];
  338. engineEvent->midi.size = midiEvent.size;
  339. }
  340. if (engineEventIndex >= RACK_EVENT_COUNT)
  341. break;
  342. }
  343. fMidiInEvents.mutex.unlock();
  344. }
  345. // create audio buffers
  346. float* inBuf[2] = { fAudioInBuf1, fAudioInBuf2 };
  347. float* outBuf[2] = { fAudioOutBuf1, fAudioOutBuf2 };
  348. processRack(inBuf, outBuf, nframes);
  349. // output audio
  350. if (fAudioIsInterleaved)
  351. {
  352. for (unsigned int i=0; i < nframes*2; i++)
  353. {
  354. if (i % 2 == 0)
  355. outsPtr[i] = fAudioOutBuf1[i/2];
  356. else
  357. outsPtr[i] = fAudioOutBuf2[i/2];
  358. }
  359. }
  360. else
  361. {
  362. carla_copyFloat(outsPtr, fAudioOutBuf1, nframes);
  363. carla_copyFloat(outsPtr+nframes, fAudioOutBuf2, nframes);
  364. }
  365. // output events
  366. {
  367. // TODO
  368. //fMidiOut.sendMessage();
  369. }
  370. proccessPendingEvents();
  371. return;
  372. // unused
  373. (void)streamTime;
  374. (void)status;
  375. }
  376. void handleMidiCallback(double timeStamp, std::vector<unsigned char>* const message)
  377. {
  378. const size_t messageSize = message->size();
  379. static uint32_t lastTime = 0;
  380. if (messageSize == 0 || messageSize > 3)
  381. return;
  382. timeStamp /= 2;
  383. if (timeStamp > 0.95)
  384. timeStamp = 0.95;
  385. RtMidiEvent midiEvent;
  386. midiEvent.time = fTimeInfo.frame + (timeStamp*(double)fBufferSize);
  387. carla_stdout("Put midi, frame:%09i/%09i, stamp:%g", fTimeInfo.frame, midiEvent.time, timeStamp);
  388. if (midiEvent.time < lastTime)
  389. midiEvent.time = lastTime;
  390. else
  391. lastTime = midiEvent.time;
  392. if (messageSize == 1)
  393. {
  394. midiEvent.data[0] = message->at(0);
  395. midiEvent.data[1] = 0;
  396. midiEvent.data[2] = 0;
  397. midiEvent.size = 1;
  398. }
  399. else if (messageSize == 2)
  400. {
  401. midiEvent.data[0] = message->at(0);
  402. midiEvent.data[1] = message->at(1);
  403. midiEvent.data[2] = 0;
  404. midiEvent.size = 2;
  405. }
  406. else
  407. {
  408. midiEvent.data[0] = message->at(0);
  409. midiEvent.data[1] = message->at(1);
  410. midiEvent.data[2] = message->at(2);
  411. midiEvent.size = 3;
  412. }
  413. fMidiInEvents.append(midiEvent);
  414. }
  415. // -------------------------------------
  416. private:
  417. RtAudio fAudio;
  418. bool fAudioIsInterleaved;
  419. bool fAudioIsReady;
  420. float* fAudioInBuf1;
  421. float* fAudioInBuf2;
  422. float* fAudioOutBuf1;
  423. float* fAudioOutBuf2;
  424. RtMidiIn fMidiIn;
  425. RtMidiOut fMidiOut;
  426. struct RtMidiEvent {
  427. uint32_t time;
  428. unsigned char data[3];
  429. unsigned char size;
  430. };
  431. struct RtMidiEvents {
  432. CarlaMutex mutex;
  433. RtList<RtMidiEvent>::Pool dataPool;
  434. RtList<RtMidiEvent> data;
  435. RtList<RtMidiEvent> dataPending;
  436. RtMidiEvents()
  437. : dataPool(512, 512),
  438. data(&dataPool),
  439. dataPending(&dataPool) {}
  440. ~RtMidiEvents()
  441. {
  442. clear();
  443. }
  444. void append(const RtMidiEvent& event)
  445. {
  446. mutex.lock();
  447. dataPending.append(event);
  448. mutex.unlock();
  449. }
  450. void clear()
  451. {
  452. mutex.lock();
  453. data.clear();
  454. dataPending.clear();
  455. mutex.unlock();
  456. }
  457. void splice()
  458. {
  459. dataPending.spliceAppend(data, true);
  460. }
  461. };
  462. RtMidiEvents fMidiInEvents;
  463. RtMidiEvents fMidiOutEvents;
  464. #define handlePtr ((CarlaEngineRtAudio*)userData)
  465. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  466. {
  467. handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  468. return 0;
  469. }
  470. static void carla_rtmidi_callback(double timeStamp, std::vector<unsigned char>* message, void* userData)
  471. {
  472. handlePtr->handleMidiCallback(timeStamp, message);
  473. }
  474. #undef handlePtr
  475. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  476. };
  477. // -----------------------------------------
  478. static std::vector<RtAudio::Api> sRtAudioApis;
  479. static void initRtApis()
  480. {
  481. static bool initiated = false;
  482. if (! initiated)
  483. {
  484. initiated = true;
  485. RtAudio::getCompiledApi(sRtAudioApis);
  486. }
  487. }
  488. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  489. {
  490. RtAudio::Api rtApi = RtAudio::UNSPECIFIED;
  491. switch (api)
  492. {
  493. case RTAUDIO_DUMMY:
  494. rtApi = RtAudio::RTAUDIO_DUMMY;
  495. break;
  496. case RTAUDIO_LINUX_ALSA:
  497. rtApi = RtAudio::LINUX_ALSA;
  498. break;
  499. case RTAUDIO_LINUX_PULSE:
  500. rtApi = RtAudio::LINUX_PULSE;
  501. break;
  502. case RTAUDIO_LINUX_OSS:
  503. rtApi = RtAudio::LINUX_OSS;
  504. break;
  505. case RTAUDIO_UNIX_JACK:
  506. rtApi = RtAudio::UNIX_JACK;
  507. break;
  508. case RTAUDIO_MACOSX_CORE:
  509. rtApi = RtAudio::MACOSX_CORE;
  510. break;
  511. case RTAUDIO_WINDOWS_ASIO:
  512. rtApi = RtAudio::WINDOWS_ASIO;
  513. break;
  514. case RTAUDIO_WINDOWS_DS:
  515. rtApi = RtAudio::WINDOWS_DS;
  516. break;
  517. }
  518. return new CarlaEngineRtAudio(rtApi);
  519. }
  520. size_t CarlaEngine::getRtAudioApiCount()
  521. {
  522. initRtApis();
  523. return sRtAudioApis.size();
  524. }
  525. const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
  526. {
  527. initRtApis();
  528. if (index < sRtAudioApis.size())
  529. {
  530. const RtAudio::Api& api(sRtAudioApis[index]);
  531. switch (api)
  532. {
  533. case RtAudio::UNSPECIFIED:
  534. return "Unspecified";
  535. case RtAudio::LINUX_ALSA:
  536. return "ALSA";
  537. case RtAudio::LINUX_PULSE:
  538. return "PulseAudio";
  539. case RtAudio::LINUX_OSS:
  540. return "OSS";
  541. case RtAudio::UNIX_JACK:
  542. #if defined(CARLA_OS_WIN)
  543. return "JACK with WinMM";
  544. #elif defined(CARLA_OS_MAC)
  545. return "JACK with CoreMidi";
  546. #elif defined(CARLA_OS_LINUX)
  547. return "JACK with ALSA-MIDI";
  548. #else
  549. return "JACK (RtAudio)";
  550. #endif
  551. case RtAudio::MACOSX_CORE:
  552. return "CoreAudio";
  553. case RtAudio::WINDOWS_ASIO:
  554. return "ASIO";
  555. case RtAudio::WINDOWS_DS:
  556. return "DirectSound";
  557. case RtAudio::RTAUDIO_DUMMY:
  558. return "Dummy";
  559. }
  560. }
  561. return nullptr;
  562. }
  563. // -----------------------------------------
  564. CARLA_BACKEND_END_NAMESPACE
  565. #endif // CARLA_ENGINE_RTAUDIO