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.

548 lines
14KB

  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)),
  66. fMidiOut(getMatchedAudioMidiAPi(api))
  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. if (fAudio.getDeviceCount() == 0)
  91. {
  92. setLastError("No audio devices available for this driver");
  93. return false;
  94. }
  95. fBufferSize = fOptions.preferredBufferSize;
  96. // Audio
  97. {
  98. RtAudio::StreamParameters iParams, oParams;
  99. iParams.deviceId = fAudio.getDefaultInputDevice();
  100. oParams.deviceId = fAudio.getDefaultOutputDevice();
  101. iParams.nChannels = 2;
  102. oParams.nChannels = 2;
  103. RtAudio::StreamOptions rtOptions;
  104. rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
  105. rtOptions.numberOfBuffers = 2;
  106. rtOptions.streamName = clientName;
  107. rtOptions.priority = 85;
  108. if (fAudio.getCurrentApi() != RtAudio::LINUX_PULSE)
  109. {
  110. rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
  111. fAudioIsInterleaved = false;
  112. if (fAudio.getCurrentApi() == RtAudio::LINUX_ALSA)
  113. rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
  114. }
  115. else
  116. fAudioIsInterleaved = true;
  117. try {
  118. fAudio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fOptions.preferredSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
  119. }
  120. catch (RtError& e)
  121. {
  122. setLastError(e.what());
  123. return false;
  124. }
  125. try {
  126. fAudio.startStream();
  127. }
  128. catch (RtError& e)
  129. {
  130. setLastError(e.what());
  131. return false;
  132. }
  133. fAudioInBuf1 = new float[fBufferSize];
  134. fAudioInBuf2 = new float[fBufferSize];
  135. fAudioOutBuf1 = new float[fBufferSize];
  136. fAudioOutBuf2 = new float[fBufferSize];
  137. fSampleRate = fAudio.getStreamSampleRate();
  138. }
  139. // MIDI
  140. {
  141. fMidiIn.setCallback(carla_rtmidi_callback, this);
  142. fMidiIn.openVirtualPort("events-in");
  143. fMidiOut.openVirtualPort("events-out");
  144. }
  145. fAudioIsReady = true;
  146. return CarlaEngine::init(clientName);
  147. }
  148. bool close()
  149. {
  150. carla_debug("CarlaEngineRtAudio::close()");
  151. CARLA_ASSERT(fAudioIsReady);
  152. CARLA_ASSERT(fAudioInBuf1 != nullptr);
  153. CARLA_ASSERT(fAudioInBuf2 != nullptr);
  154. CARLA_ASSERT(fAudioOutBuf1 != nullptr);
  155. CARLA_ASSERT(fAudioOutBuf2 != nullptr);
  156. CarlaEngine::close();
  157. fAudioIsReady = false;
  158. if (fAudio.isStreamRunning())
  159. fAudio.stopStream();
  160. if (fAudio.isStreamOpen())
  161. fAudio.closeStream();
  162. fMidiIn.cancelCallback();
  163. fMidiIn.closePort();
  164. fMidiOut.closePort();
  165. if (fAudioInBuf1 != nullptr)
  166. {
  167. delete[] fAudioInBuf1;
  168. fAudioInBuf1 = nullptr;
  169. }
  170. if (fAudioInBuf2 != nullptr)
  171. {
  172. delete[] fAudioInBuf2;
  173. fAudioInBuf2 = nullptr;
  174. }
  175. if (fAudioOutBuf1 != nullptr)
  176. {
  177. delete[] fAudioOutBuf1;
  178. fAudioOutBuf1 = nullptr;
  179. }
  180. if (fAudioOutBuf2 != nullptr)
  181. {
  182. delete[] fAudioOutBuf2;
  183. fAudioOutBuf2 = nullptr;
  184. }
  185. fMidiInEvents.clear();
  186. fMidiOutEvents.clear();
  187. return true;
  188. }
  189. bool isRunning() const
  190. {
  191. return fAudio.isStreamRunning();
  192. }
  193. bool isOffline() const
  194. {
  195. return false;
  196. }
  197. EngineType type() const
  198. {
  199. return kEngineTypeRtAudio;
  200. }
  201. // -------------------------------------
  202. protected:
  203. void handleAudioProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  204. {
  205. // get buffers from RtAudio
  206. float* insPtr = (float*)inputBuffer;
  207. float* outsPtr = (float*)outputBuffer;
  208. // assert buffers
  209. CARLA_ASSERT(insPtr != nullptr);
  210. CARLA_ASSERT(outsPtr != nullptr);
  211. if (currentPluginCount() == 0 || ! fAudioIsReady)
  212. {
  213. carla_zeroFloat(outsPtr, sizeof(float)*nframes*2);
  214. return;
  215. }
  216. // initialize audio input
  217. if (fAudioIsInterleaved)
  218. {
  219. for (unsigned int i=0; i < nframes*2; i++)
  220. {
  221. if (i % 2 == 0)
  222. fAudioInBuf1[i/2] = insPtr[i];
  223. else
  224. fAudioInBuf2[i/2] = insPtr[i];
  225. }
  226. }
  227. else
  228. {
  229. std::memcpy(fAudioInBuf1, insPtr, sizeof(float)*nframes);
  230. std::memcpy(fAudioInBuf2, insPtr+nframes, sizeof(float)*nframes);
  231. //for (unsigned int i=0; i < nframes; i++)
  232. // fAudioInBuf1[i] = insPtr[i];
  233. //for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
  234. // fAudioInBuf2[i] = insPtr[j];
  235. }
  236. // initialize audio output
  237. carla_zeroFloat(fAudioOutBuf1, fBufferSize);
  238. carla_zeroFloat(fAudioOutBuf2, fBufferSize);
  239. // initialize events input
  240. //memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS);
  241. {
  242. // TODO
  243. }
  244. // create audio buffers
  245. float* inBuf[2] = { fAudioInBuf1, fAudioInBuf2 };
  246. float* outBuf[2] = { fAudioOutBuf1, fAudioOutBuf2 };
  247. processRack(inBuf, outBuf, nframes);
  248. // output audio
  249. if (fAudioIsInterleaved)
  250. {
  251. for (unsigned int i=0; i < nframes*2; i++)
  252. {
  253. if (i % 2 == 0)
  254. outsPtr[i] = fAudioOutBuf1[i/2];
  255. else
  256. outsPtr[i] = fAudioOutBuf2[i/2];
  257. }
  258. }
  259. else
  260. {
  261. std::memcpy(outsPtr, fAudioOutBuf1, sizeof(float)*nframes);
  262. std::memcpy(outsPtr+nframes, fAudioOutBuf2, sizeof(float)*nframes);
  263. //for (unsigned int i=0; i < nframes; i++)
  264. // outsPtr[i] = fAudioOutBuf1[i];
  265. //for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
  266. // outsPtr[j] = fAudioOutBuf2[i];
  267. }
  268. // output events
  269. {
  270. // TODO
  271. //fMidiOut.sendMessage();
  272. }
  273. (void)streamTime;
  274. (void)status;
  275. }
  276. void handleMidiCallback(const double timeStamp, std::vector<unsigned char>* const message)
  277. {
  278. const size_t messageSize = message->size();
  279. if (messageSize == 0 || messageSize > 3)
  280. return;
  281. RtMidiEvent midiEvent;
  282. midiEvent.time = timeStamp;
  283. if (messageSize == 1)
  284. {
  285. midiEvent.data[0] = message->at(0);
  286. midiEvent.data[1] = 0;
  287. midiEvent.data[2] = 0;
  288. }
  289. else if (messageSize == 2)
  290. {
  291. midiEvent.data[0] = message->at(0);
  292. midiEvent.data[1] = message->at(1);
  293. midiEvent.data[2] = 0;
  294. }
  295. else
  296. {
  297. midiEvent.data[0] = message->at(0);
  298. midiEvent.data[1] = message->at(1);
  299. midiEvent.data[2] = message->at(2);
  300. }
  301. fMidiInEvents.append(midiEvent);
  302. }
  303. // -------------------------------------
  304. private:
  305. RtAudio fAudio;
  306. bool fAudioIsInterleaved;
  307. bool fAudioIsReady;
  308. float* fAudioInBuf1;
  309. float* fAudioInBuf2;
  310. float* fAudioOutBuf1;
  311. float* fAudioOutBuf2;
  312. RtMidiIn fMidiIn;
  313. RtMidiOut fMidiOut;
  314. struct RtMidiEvent {
  315. double time;
  316. unsigned char data[3];
  317. };
  318. struct RtMidiEvents {
  319. CarlaMutex mutex;
  320. RtList<RtMidiEvent>::Pool dataPool;
  321. RtList<RtMidiEvent> data;
  322. RtList<RtMidiEvent> dataPending;
  323. RtMidiEvents()
  324. : dataPool(512, 512),
  325. data(&dataPool),
  326. dataPending(&dataPool) {}
  327. ~RtMidiEvents()
  328. {
  329. clear();
  330. }
  331. void append(const RtMidiEvent& event)
  332. {
  333. mutex.lock();
  334. dataPending.append(event);
  335. mutex.unlock();
  336. }
  337. void clear()
  338. {
  339. mutex.lock();
  340. data.clear();
  341. dataPending.clear();
  342. mutex.unlock();
  343. }
  344. void trySplice()
  345. {
  346. if (mutex.tryLock())
  347. {
  348. dataPending.splice(data, true);
  349. mutex.unlock();
  350. }
  351. }
  352. };
  353. RtMidiEvents fMidiInEvents;
  354. RtMidiEvents fMidiOutEvents;
  355. #define handlePtr ((CarlaEngineRtAudio*)userData)
  356. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  357. {
  358. handlePtr->handleAudioProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  359. return 0;
  360. }
  361. static void carla_rtmidi_callback(double timeStamp, std::vector<unsigned char>* message, void* userData)
  362. {
  363. handlePtr->handleMidiCallback(timeStamp, message);
  364. }
  365. #undef handlePtr
  366. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  367. };
  368. // -----------------------------------------
  369. static std::vector<RtAudio::Api> sRtAudioApis;
  370. static void initRtApis()
  371. {
  372. static bool initiated = false;
  373. if (! initiated)
  374. {
  375. initiated = true;
  376. RtAudio::getCompiledApi(sRtAudioApis);
  377. }
  378. }
  379. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  380. {
  381. RtAudio::Api rtApi = RtAudio::UNSPECIFIED;
  382. switch (api)
  383. {
  384. case RTAUDIO_DUMMY:
  385. rtApi = RtAudio::RTAUDIO_DUMMY;
  386. break;
  387. case RTAUDIO_LINUX_ALSA:
  388. rtApi = RtAudio::LINUX_ALSA;
  389. break;
  390. case RTAUDIO_LINUX_PULSE:
  391. rtApi = RtAudio::LINUX_PULSE;
  392. break;
  393. case RTAUDIO_LINUX_OSS:
  394. rtApi = RtAudio::LINUX_OSS;
  395. break;
  396. case RTAUDIO_UNIX_JACK:
  397. rtApi = RtAudio::UNIX_JACK;
  398. break;
  399. case RTAUDIO_MACOSX_CORE:
  400. rtApi = RtAudio::MACOSX_CORE;
  401. break;
  402. case RTAUDIO_WINDOWS_ASIO:
  403. rtApi = RtAudio::WINDOWS_ASIO;
  404. break;
  405. case RTAUDIO_WINDOWS_DS:
  406. rtApi = RtAudio::WINDOWS_DS;
  407. break;
  408. }
  409. return new CarlaEngineRtAudio(rtApi);
  410. }
  411. size_t CarlaEngine::getRtAudioApiCount()
  412. {
  413. initRtApis();
  414. return sRtAudioApis.size();
  415. }
  416. const char* CarlaEngine::getRtAudioApiName(const unsigned int index)
  417. {
  418. initRtApis();
  419. if (index < sRtAudioApis.size())
  420. {
  421. const RtAudio::Api& api(sRtAudioApis[index]);
  422. switch (api)
  423. {
  424. case RtAudio::UNSPECIFIED:
  425. return "Unspecified";
  426. case RtAudio::LINUX_ALSA:
  427. return "ALSA";
  428. case RtAudio::LINUX_PULSE:
  429. return "PulseAudio";
  430. case RtAudio::LINUX_OSS:
  431. return "OSS";
  432. case RtAudio::UNIX_JACK:
  433. return "JACK (RtAudio)";
  434. case RtAudio::MACOSX_CORE:
  435. return "CoreAudio";
  436. case RtAudio::WINDOWS_ASIO:
  437. return "ASIO";
  438. case RtAudio::WINDOWS_DS:
  439. return "DirectSound";
  440. case RtAudio::RTAUDIO_DUMMY:
  441. return "Dummy";
  442. }
  443. }
  444. return nullptr;
  445. }
  446. // -----------------------------------------
  447. CARLA_BACKEND_END_NAMESPACE
  448. #endif // CARLA_ENGINE_RTAUDIO