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.

665 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. std::memcpy(fAudioInBuf1, insPtr, sizeof(float)*nframes);
  250. std::memcpy(fAudioInBuf2, insPtr+nframes, sizeof(float)*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.getLast(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. std::memcpy(outsPtr, fAudioOutBuf1, sizeof(float)*nframes);
  349. std::memcpy(outsPtr+nframes, fAudioOutBuf2, sizeof(float)*nframes);
  350. }
  351. // output events
  352. {
  353. // TODO
  354. //fMidiOut.sendMessage();
  355. }
  356. // TESTING
  357. fTimeInfo.playing = true;
  358. fTimeInfo.frame += nframes;
  359. proccessPendingEvents();
  360. return;
  361. // unused
  362. (void)streamTime;
  363. (void)status;
  364. }
  365. void handleMidiCallback(double timeStamp, std::vector<unsigned char>* const message)
  366. {
  367. const size_t messageSize = message->size();
  368. static uint32_t lastTime = 0;
  369. if (messageSize == 0 || messageSize > 3)
  370. return;
  371. timeStamp /= 2;
  372. if (timeStamp > 0.95)
  373. timeStamp = 0.95;
  374. RtMidiEvent midiEvent;
  375. midiEvent.time = fTimeInfo.frame + (timeStamp*(double)fBufferSize);
  376. carla_stdout("Put midi, frame:%09i/%09i, stamp:%g", fTimeInfo.frame, midiEvent.time, timeStamp);
  377. if (midiEvent.time < lastTime)
  378. midiEvent.time = lastTime;
  379. else
  380. lastTime = midiEvent.time;
  381. if (messageSize == 1)
  382. {
  383. midiEvent.data[0] = message->at(0);
  384. midiEvent.data[1] = 0;
  385. midiEvent.data[2] = 0;
  386. midiEvent.size = 1;
  387. }
  388. else if (messageSize == 2)
  389. {
  390. midiEvent.data[0] = message->at(0);
  391. midiEvent.data[1] = message->at(1);
  392. midiEvent.data[2] = 0;
  393. midiEvent.size = 2;
  394. }
  395. else
  396. {
  397. midiEvent.data[0] = message->at(0);
  398. midiEvent.data[1] = message->at(1);
  399. midiEvent.data[2] = message->at(2);
  400. midiEvent.size = 3;
  401. }
  402. fMidiInEvents.append(midiEvent);
  403. }
  404. // -------------------------------------
  405. private:
  406. RtAudio fAudio;
  407. bool fAudioIsInterleaved;
  408. bool fAudioIsReady;
  409. float* fAudioInBuf1;
  410. float* fAudioInBuf2;
  411. float* fAudioOutBuf1;
  412. float* fAudioOutBuf2;
  413. RtMidiIn fMidiIn;
  414. RtMidiOut fMidiOut;
  415. struct RtMidiEvent {
  416. uint32_t time;
  417. unsigned char data[3];
  418. unsigned char size;
  419. };
  420. struct RtMidiEvents {
  421. CarlaMutex mutex;
  422. RtList<RtMidiEvent>::Pool dataPool;
  423. RtList<RtMidiEvent> data;
  424. RtList<RtMidiEvent> dataPending;
  425. RtMidiEvents()
  426. : dataPool(512, 512),
  427. data(&dataPool),
  428. dataPending(&dataPool) {}
  429. ~RtMidiEvents()
  430. {
  431. clear();
  432. }
  433. void append(const RtMidiEvent& event)
  434. {
  435. mutex.lock();
  436. dataPending.append(event);
  437. mutex.unlock();
  438. }
  439. void clear()
  440. {
  441. mutex.lock();
  442. data.clear();
  443. dataPending.clear();
  444. mutex.unlock();
  445. }
  446. void splice()
  447. {
  448. dataPending.splice(data, true);
  449. }
  450. };
  451. RtMidiEvents fMidiInEvents;
  452. RtMidiEvents fMidiOutEvents;
  453. #define handlePtr ((CarlaEngineRtAudio*)userData)
  454. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  455. {
  456. handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  457. return 0;
  458. }
  459. static void carla_rtmidi_callback(double timeStamp, std::vector<unsigned char>* message, void* userData)
  460. {
  461. handlePtr->handleMidiCallback(timeStamp, message);
  462. }
  463. #undef handlePtr
  464. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  465. };
  466. // -----------------------------------------
  467. static std::vector<RtAudio::Api> sRtAudioApis;
  468. static void initRtApis()
  469. {
  470. static bool initiated = false;
  471. if (! initiated)
  472. {
  473. initiated = true;
  474. RtAudio::getCompiledApi(sRtAudioApis);
  475. }
  476. }
  477. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  478. {
  479. RtAudio::Api rtApi = RtAudio::UNSPECIFIED;
  480. switch (api)
  481. {
  482. case RTAUDIO_DUMMY:
  483. rtApi = RtAudio::RTAUDIO_DUMMY;
  484. break;
  485. case RTAUDIO_LINUX_ALSA:
  486. rtApi = RtAudio::LINUX_ALSA;
  487. break;
  488. case RTAUDIO_LINUX_PULSE:
  489. rtApi = RtAudio::LINUX_PULSE;
  490. break;
  491. case RTAUDIO_LINUX_OSS:
  492. rtApi = RtAudio::LINUX_OSS;
  493. break;
  494. case RTAUDIO_UNIX_JACK:
  495. rtApi = RtAudio::UNIX_JACK;
  496. break;
  497. case RTAUDIO_MACOSX_CORE:
  498. rtApi = RtAudio::MACOSX_CORE;
  499. break;
  500. case RTAUDIO_WINDOWS_ASIO:
  501. rtApi = RtAudio::WINDOWS_ASIO;
  502. break;
  503. case RTAUDIO_WINDOWS_DS:
  504. rtApi = RtAudio::WINDOWS_DS;
  505. break;
  506. }
  507. return new CarlaEngineRtAudio(rtApi);
  508. }
  509. size_t CarlaEngine::getRtAudioApiCount()
  510. {
  511. initRtApis();
  512. return sRtAudioApis.size();
  513. }
  514. const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
  515. {
  516. initRtApis();
  517. if (index < sRtAudioApis.size())
  518. {
  519. const RtAudio::Api& api(sRtAudioApis[index]);
  520. switch (api)
  521. {
  522. case RtAudio::UNSPECIFIED:
  523. return "Unspecified";
  524. case RtAudio::LINUX_ALSA:
  525. return "ALSA";
  526. case RtAudio::LINUX_PULSE:
  527. return "PulseAudio";
  528. case RtAudio::LINUX_OSS:
  529. return "OSS";
  530. case RtAudio::UNIX_JACK:
  531. return "JACK (RtAudio)";
  532. case RtAudio::MACOSX_CORE:
  533. return "CoreAudio";
  534. case RtAudio::WINDOWS_ASIO:
  535. return "ASIO";
  536. case RtAudio::WINDOWS_DS:
  537. return "DirectSound";
  538. case RtAudio::RTAUDIO_DUMMY:
  539. return "Dummy";
  540. }
  541. }
  542. return nullptr;
  543. }
  544. // -----------------------------------------
  545. CARLA_BACKEND_END_NAMESPACE
  546. #endif // CARLA_ENGINE_RTAUDIO