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.

CarlaEngineRtAudio.cpp 19KB

11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  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. return proccessPendingEvents();
  234. }
  235. if (kData->curPluginCount == 0)
  236. {
  237. // pass-through
  238. if (fOptions.processMode == PROCESS_MODE_CONTINUOUS_RACK)
  239. carla_copyFloat(outsPtr, insPtr, nframes*2);
  240. return proccessPendingEvents();
  241. }
  242. // initialize audio input
  243. if (fAudioIsInterleaved)
  244. {
  245. for (unsigned int i=0; i < nframes*2; i++)
  246. {
  247. if (i % 2 == 0)
  248. fAudioInBuf1[i/2] = insPtr[i];
  249. else
  250. fAudioInBuf2[i/2] = insPtr[i];
  251. }
  252. }
  253. else
  254. {
  255. carla_copyFloat(fAudioInBuf1, insPtr, nframes);
  256. carla_copyFloat(fAudioInBuf2, insPtr+nframes, nframes);
  257. }
  258. // initialize audio output
  259. carla_zeroFloat(fAudioOutBuf1, fBufferSize);
  260. carla_zeroFloat(fAudioOutBuf2, fBufferSize);
  261. // initialize input events
  262. carla_zeroMem(kData->rack.in, sizeof(EngineEvent)*RACK_EVENT_COUNT);
  263. if (fMidiInEvents.mutex.tryLock())
  264. {
  265. uint32_t engineEventIndex = 0;
  266. fMidiInEvents.splice();
  267. while (! fMidiInEvents.data.isEmpty())
  268. {
  269. const RtMidiEvent& midiEvent = fMidiInEvents.data.getFirst(true);
  270. EngineEvent* const engineEvent = &kData->rack.in[engineEventIndex++];
  271. engineEvent->clear();
  272. const uint8_t midiStatus = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  273. const uint8_t midiChannel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
  274. engineEvent->channel = midiChannel;
  275. if (midiEvent.time < fTimeInfo.frame)
  276. engineEvent->time = 0;
  277. else if (midiEvent.time >= fTimeInfo.frame + nframes)
  278. {
  279. engineEvent->time = fTimeInfo.frame + nframes-1;
  280. carla_stderr("MIDI Event in the future!, %i vs %i", engineEvent->time, fTimeInfo.frame);
  281. }
  282. else
  283. engineEvent->time = midiEvent.time - fTimeInfo.frame;
  284. //carla_stdout("Got midi, time %f vs %i", midiEvent.time, engineEvent->time);
  285. if (MIDI_IS_STATUS_CONTROL_CHANGE(midiStatus))
  286. {
  287. const uint8_t midiControl = midiEvent.data[1];
  288. engineEvent->type = kEngineEventTypeControl;
  289. if (MIDI_IS_CONTROL_BANK_SELECT(midiControl))
  290. {
  291. const uint8_t midiBank = midiEvent.data[2];
  292. engineEvent->ctrl.type = kEngineControlEventTypeMidiBank;
  293. engineEvent->ctrl.param = midiBank;
  294. engineEvent->ctrl.value = 0.0;
  295. }
  296. else if (midiControl == MIDI_CONTROL_ALL_SOUND_OFF)
  297. {
  298. engineEvent->ctrl.type = kEngineControlEventTypeAllSoundOff;
  299. engineEvent->ctrl.param = 0;
  300. engineEvent->ctrl.value = 0.0;
  301. }
  302. else if (midiControl == MIDI_CONTROL_ALL_NOTES_OFF)
  303. {
  304. engineEvent->ctrl.type = kEngineControlEventTypeAllNotesOff;
  305. engineEvent->ctrl.param = 0;
  306. engineEvent->ctrl.value = 0.0;
  307. }
  308. else
  309. {
  310. const uint8_t midiValue = midiEvent.data[2];
  311. engineEvent->ctrl.type = kEngineControlEventTypeParameter;
  312. engineEvent->ctrl.param = midiControl;
  313. engineEvent->ctrl.value = double(midiValue)/127.0;
  314. }
  315. }
  316. else if (MIDI_IS_STATUS_PROGRAM_CHANGE(midiStatus))
  317. {
  318. const uint8_t midiProgram = midiEvent.data[1];
  319. engineEvent->type = kEngineEventTypeControl;
  320. engineEvent->ctrl.type = kEngineControlEventTypeMidiProgram;
  321. engineEvent->ctrl.param = midiProgram;
  322. engineEvent->ctrl.value = 0.0;
  323. }
  324. else
  325. {
  326. engineEvent->type = kEngineEventTypeMidi;
  327. engineEvent->midi.data[0] = midiStatus;
  328. engineEvent->midi.data[1] = midiEvent.data[1];
  329. engineEvent->midi.data[2] = midiEvent.data[2];
  330. engineEvent->midi.size = midiEvent.size;
  331. }
  332. if (engineEventIndex >= RACK_EVENT_COUNT)
  333. break;
  334. }
  335. fMidiInEvents.mutex.unlock();
  336. }
  337. // create audio buffers
  338. float* inBuf[2] = { fAudioInBuf1, fAudioInBuf2 };
  339. float* outBuf[2] = { fAudioOutBuf1, fAudioOutBuf2 };
  340. processRack(inBuf, outBuf, nframes);
  341. // output audio
  342. if (fAudioIsInterleaved)
  343. {
  344. for (unsigned int i=0; i < nframes*2; i++)
  345. {
  346. if (i % 2 == 0)
  347. outsPtr[i] = fAudioOutBuf1[i/2];
  348. else
  349. outsPtr[i] = fAudioOutBuf2[i/2];
  350. }
  351. }
  352. else
  353. {
  354. carla_copyFloat(outsPtr, fAudioOutBuf1, nframes);
  355. carla_copyFloat(outsPtr+nframes, fAudioOutBuf2, nframes);
  356. }
  357. // output events
  358. {
  359. // TODO
  360. //fMidiOut.sendMessage();
  361. }
  362. proccessPendingEvents();
  363. return;
  364. // unused
  365. (void)streamTime;
  366. (void)status;
  367. }
  368. void handleMidiCallback(double timeStamp, std::vector<unsigned char>* const message)
  369. {
  370. const size_t messageSize = message->size();
  371. static uint32_t lastTime = 0;
  372. if (messageSize == 0 || messageSize > 3)
  373. return;
  374. timeStamp /= 2;
  375. if (timeStamp > 0.95)
  376. timeStamp = 0.95;
  377. RtMidiEvent midiEvent;
  378. midiEvent.time = fTimeInfo.frame + (timeStamp*(double)fBufferSize);
  379. carla_stdout("Put midi, frame:%09i/%09i, stamp:%g", fTimeInfo.frame, midiEvent.time, timeStamp);
  380. if (midiEvent.time < lastTime)
  381. midiEvent.time = lastTime;
  382. else
  383. lastTime = midiEvent.time;
  384. if (messageSize == 1)
  385. {
  386. midiEvent.data[0] = message->at(0);
  387. midiEvent.data[1] = 0;
  388. midiEvent.data[2] = 0;
  389. midiEvent.size = 1;
  390. }
  391. else if (messageSize == 2)
  392. {
  393. midiEvent.data[0] = message->at(0);
  394. midiEvent.data[1] = message->at(1);
  395. midiEvent.data[2] = 0;
  396. midiEvent.size = 2;
  397. }
  398. else
  399. {
  400. midiEvent.data[0] = message->at(0);
  401. midiEvent.data[1] = message->at(1);
  402. midiEvent.data[2] = message->at(2);
  403. midiEvent.size = 3;
  404. }
  405. fMidiInEvents.append(midiEvent);
  406. }
  407. // -------------------------------------
  408. private:
  409. RtAudio fAudio;
  410. bool fAudioIsInterleaved;
  411. bool fAudioIsReady;
  412. float* fAudioInBuf1;
  413. float* fAudioInBuf2;
  414. float* fAudioOutBuf1;
  415. float* fAudioOutBuf2;
  416. RtMidiIn fMidiIn;
  417. RtMidiOut fMidiOut;
  418. struct RtMidiEvent {
  419. uint32_t time;
  420. unsigned char data[3];
  421. unsigned char size;
  422. };
  423. struct RtMidiEvents {
  424. CarlaMutex mutex;
  425. RtList<RtMidiEvent>::Pool dataPool;
  426. RtList<RtMidiEvent> data;
  427. RtList<RtMidiEvent> dataPending;
  428. RtMidiEvents()
  429. : dataPool(512, 512),
  430. data(&dataPool),
  431. dataPending(&dataPool) {}
  432. ~RtMidiEvents()
  433. {
  434. clear();
  435. }
  436. void append(const RtMidiEvent& event)
  437. {
  438. mutex.lock();
  439. dataPending.append(event);
  440. mutex.unlock();
  441. }
  442. void clear()
  443. {
  444. mutex.lock();
  445. data.clear();
  446. dataPending.clear();
  447. mutex.unlock();
  448. }
  449. void splice()
  450. {
  451. dataPending.spliceAppend(data, true);
  452. }
  453. };
  454. RtMidiEvents fMidiInEvents;
  455. RtMidiEvents fMidiOutEvents;
  456. #define handlePtr ((CarlaEngineRtAudio*)userData)
  457. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  458. {
  459. handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  460. return 0;
  461. }
  462. static void carla_rtmidi_callback(double timeStamp, std::vector<unsigned char>* message, void* userData)
  463. {
  464. handlePtr->handleMidiCallback(timeStamp, message);
  465. }
  466. #undef handlePtr
  467. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  468. };
  469. // -----------------------------------------
  470. static std::vector<RtAudio::Api> sRtAudioApis;
  471. static void initRtApis()
  472. {
  473. static bool initiated = false;
  474. if (! initiated)
  475. {
  476. initiated = true;
  477. RtAudio::getCompiledApi(sRtAudioApis);
  478. }
  479. }
  480. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  481. {
  482. RtAudio::Api rtApi = RtAudio::UNSPECIFIED;
  483. switch (api)
  484. {
  485. case RTAUDIO_DUMMY:
  486. rtApi = RtAudio::RTAUDIO_DUMMY;
  487. break;
  488. case RTAUDIO_LINUX_ALSA:
  489. rtApi = RtAudio::LINUX_ALSA;
  490. break;
  491. case RTAUDIO_LINUX_PULSE:
  492. rtApi = RtAudio::LINUX_PULSE;
  493. break;
  494. case RTAUDIO_LINUX_OSS:
  495. rtApi = RtAudio::LINUX_OSS;
  496. break;
  497. case RTAUDIO_UNIX_JACK:
  498. rtApi = RtAudio::UNIX_JACK;
  499. break;
  500. case RTAUDIO_MACOSX_CORE:
  501. rtApi = RtAudio::MACOSX_CORE;
  502. break;
  503. case RTAUDIO_WINDOWS_ASIO:
  504. rtApi = RtAudio::WINDOWS_ASIO;
  505. break;
  506. case RTAUDIO_WINDOWS_DS:
  507. rtApi = RtAudio::WINDOWS_DS;
  508. break;
  509. }
  510. return new CarlaEngineRtAudio(rtApi);
  511. }
  512. size_t CarlaEngine::getRtAudioApiCount()
  513. {
  514. initRtApis();
  515. return sRtAudioApis.size();
  516. }
  517. const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
  518. {
  519. initRtApis();
  520. if (index < sRtAudioApis.size())
  521. {
  522. const RtAudio::Api& api(sRtAudioApis[index]);
  523. switch (api)
  524. {
  525. case RtAudio::UNSPECIFIED:
  526. return "Unspecified";
  527. case RtAudio::LINUX_ALSA:
  528. return "ALSA";
  529. case RtAudio::LINUX_PULSE:
  530. return "PulseAudio";
  531. case RtAudio::LINUX_OSS:
  532. return "OSS";
  533. case RtAudio::UNIX_JACK:
  534. return "JACK (RtAudio)";
  535. case RtAudio::MACOSX_CORE:
  536. return "CoreAudio";
  537. case RtAudio::WINDOWS_ASIO:
  538. return "ASIO";
  539. case RtAudio::WINDOWS_DS:
  540. return "DirectSound";
  541. case RtAudio::RTAUDIO_DUMMY:
  542. return "Dummy";
  543. }
  544. }
  545. return nullptr;
  546. }
  547. // -----------------------------------------
  548. CARLA_BACKEND_END_NAMESPACE
  549. #endif // CARLA_ENGINE_RTAUDIO