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.

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