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.

422 lines
10KB

  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 "carla_engine_internal.hpp"
  19. #include "carla_backend_utils.hpp"
  20. #include "carla_midi.h"
  21. #include "RtAudio.h"
  22. #include "RtMidi.h"
  23. CARLA_BACKEND_START_NAMESPACE
  24. #if 0
  25. } // Fix editor indentation
  26. #endif
  27. // -------------------------------------------------------------------------------------------------------------------
  28. // RtAudio Engine
  29. class CarlaEngineRtAudio : public CarlaEngine
  30. {
  31. public:
  32. CarlaEngineRtAudio(RtAudio::Api api)
  33. : CarlaEngine(),
  34. audio(api)
  35. {
  36. qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio(%i)", api);
  37. evIn = nullptr;
  38. evOut = nullptr;
  39. m_audioInterleaved = false;
  40. m_inBuf1 = nullptr;
  41. m_inBuf2 = nullptr;
  42. m_outBuf1 = nullptr;
  43. m_outBuf2 = nullptr;
  44. // just to make sure
  45. fOptions.forceStereo = true;
  46. fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
  47. }
  48. ~CarlaEngineRtAudio()
  49. {
  50. qDebug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
  51. }
  52. // -------------------------------------
  53. bool init(const char* const clientName)
  54. {
  55. qDebug("CarlaEngineRtAudio::init(\"%s\")", clientName);
  56. if (audio.getDeviceCount() < 1)
  57. {
  58. setLastError("No audio devices available for this driver");
  59. return false;
  60. }
  61. fBufferSize = fOptions.preferredBufferSize;
  62. fSampleRate = fOptions.preferredSampleRate;
  63. RtAudio::StreamParameters iParams, oParams;
  64. iParams.deviceId = audio.getDefaultInputDevice();
  65. oParams.deviceId = audio.getDefaultOutputDevice();
  66. iParams.nChannels = 2;
  67. oParams.nChannels = 2;
  68. RtAudio::StreamOptions rtOptions;
  69. rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
  70. rtOptions.numberOfBuffers = 2;
  71. rtOptions.streamName = clientName;
  72. rtOptions.priority = 85;
  73. if (audio.getCurrentApi() != RtAudio::LINUX_PULSE)
  74. {
  75. rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
  76. m_audioInterleaved = false;
  77. if (audio.getCurrentApi() == RtAudio::LINUX_ALSA)
  78. rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
  79. }
  80. else
  81. m_audioInterleaved = true;
  82. try {
  83. audio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, fSampleRate, &fBufferSize, carla_rtaudio_process_callback, this, &rtOptions);
  84. }
  85. catch (RtError& e)
  86. {
  87. setLastError(e.what());
  88. return false;
  89. }
  90. try {
  91. audio.startStream();
  92. }
  93. catch (RtError& e)
  94. {
  95. setLastError(e.what());
  96. return false;
  97. }
  98. fSampleRate = audio.getStreamSampleRate();
  99. m_inBuf1 = new float[fBufferSize];
  100. m_inBuf2 = new float[fBufferSize];
  101. m_outBuf1 = new float[fBufferSize];
  102. m_outBuf2 = new float[fBufferSize];
  103. //midiIn = new MidiInAlsa(clientName, 512);
  104. //midiIn->openVirtualPort("control-in");
  105. //midiIn->openVirtualPort("midi-in");
  106. //midiOut = new MidiOutAlsa(clientName);
  107. //midiOut->openVirtualPort("control-out");
  108. //midiOut->openVirtualPort("midi-out");
  109. fName = clientName;
  110. fName.toBasic();
  111. CarlaEngine::init(fName);
  112. return true;
  113. }
  114. bool close()
  115. {
  116. qDebug("CarlaEngineRtAudio::close()");
  117. CarlaEngine::close();
  118. if (audio.isStreamRunning())
  119. audio.stopStream();
  120. if (audio.isStreamOpen())
  121. audio.closeStream();
  122. #if 0
  123. if (midiIn)
  124. {
  125. midiIn->cancelCallback();
  126. midiIn->closePort();
  127. delete midiIn;
  128. midiIn = nullptr;
  129. }
  130. if (midiOut)
  131. {
  132. midiOut->closePort();
  133. delete midiOut;
  134. midiOut = nullptr;
  135. }
  136. #endif
  137. if (m_inBuf1)
  138. {
  139. delete[] m_inBuf1;
  140. m_inBuf1 = nullptr;
  141. }
  142. if (m_inBuf2)
  143. {
  144. delete[] m_inBuf2;
  145. m_inBuf2 = nullptr;
  146. }
  147. if (m_outBuf1)
  148. {
  149. delete[] m_outBuf1;
  150. m_outBuf1 = nullptr;
  151. }
  152. if (m_outBuf2)
  153. {
  154. delete[] m_outBuf2;
  155. m_outBuf2 = nullptr;
  156. }
  157. return true;
  158. }
  159. bool isRunning() const
  160. {
  161. return audio.isStreamRunning();
  162. }
  163. bool isOffline() const
  164. {
  165. return false;
  166. }
  167. EngineType type() const
  168. {
  169. return kEngineTypeRtAudio;
  170. }
  171. // -------------------------------------
  172. protected:
  173. void handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  174. {
  175. if (maxPluginNumber() == 0)
  176. return;
  177. // get buffers from RtAudio
  178. float* insPtr = (float*)inputBuffer;
  179. float* outsPtr = (float*)outputBuffer;
  180. // assert buffers
  181. CARLA_ASSERT(insPtr);
  182. CARLA_ASSERT(outsPtr);
  183. // initialize audio input
  184. if (m_audioInterleaved)
  185. {
  186. for (unsigned int i=0; i < nframes*2; i++)
  187. {
  188. if (i % 2)
  189. m_inBuf2[i/2] = insPtr[i];
  190. else
  191. m_inBuf1[i/2] = insPtr[i];
  192. }
  193. }
  194. else
  195. {
  196. for (unsigned int i=0; i < nframes; i++)
  197. m_inBuf1[i] = insPtr[i];
  198. for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
  199. m_inBuf2[i] = insPtr[j];
  200. }
  201. // create audio buffers
  202. float* inBuf[2] = { m_inBuf1, m_inBuf2 };
  203. float* outBuf[2] = { m_outBuf1, m_outBuf2 };
  204. // initialize events input
  205. //memset(rackEventsIn, 0, sizeof(EngineEvent)*MAX_EVENTS);
  206. {
  207. // TODO
  208. }
  209. processRack(inBuf, outBuf, nframes);
  210. // output audio
  211. if (m_audioInterleaved)
  212. {
  213. for (unsigned int i=0; i < nframes*2; i++)
  214. {
  215. if (i % 2)
  216. outsPtr[i] = m_outBuf2[i/2];
  217. else
  218. outsPtr[i] = m_outBuf1[i/2];
  219. }
  220. }
  221. else
  222. {
  223. for (unsigned int i=0; i < nframes; i++)
  224. outsPtr[i] = m_outBuf1[i];
  225. for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
  226. outsPtr[j] = m_outBuf2[i];
  227. }
  228. // output control
  229. {
  230. // TODO
  231. }
  232. // output midi
  233. {
  234. // TODO
  235. }
  236. Q_UNUSED(streamTime);
  237. Q_UNUSED(status);
  238. }
  239. // -------------------------------------
  240. private:
  241. RtAudio audio;
  242. ScopedPointer<MidiInApi> evIn;
  243. ScopedPointer<MidiOutApi> evOut;
  244. bool m_audioInterleaved;
  245. float* m_inBuf1;
  246. float* m_inBuf2;
  247. float* m_outBuf1;
  248. float* m_outBuf2;
  249. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  250. {
  251. CarlaEngineRtAudio* const _this_ = (CarlaEngineRtAudio*)userData;
  252. _this_->handleProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  253. return 0;
  254. }
  255. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineRtAudio)
  256. };
  257. // -----------------------------------------
  258. static std::vector<RtAudio::Api> rtApis;
  259. static void initRtApis()
  260. {
  261. static bool initiated = false;
  262. if (! initiated)
  263. {
  264. initiated = true;
  265. RtAudio::getCompiledApi(rtApis);
  266. }
  267. }
  268. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  269. {
  270. RtAudio::Api rtApi = RtAudio::UNSPECIFIED;
  271. switch (api)
  272. {
  273. case RTAUDIO_DUMMY:
  274. rtApi = RtAudio::RTAUDIO_DUMMY;
  275. break;
  276. case RTAUDIO_LINUX_ALSA:
  277. rtApi = RtAudio::LINUX_ALSA;
  278. break;
  279. case RTAUDIO_LINUX_PULSE:
  280. rtApi = RtAudio::LINUX_PULSE;
  281. break;
  282. case RTAUDIO_LINUX_OSS:
  283. rtApi = RtAudio::LINUX_OSS;
  284. break;
  285. case RTAUDIO_UNIX_JACK:
  286. rtApi = RtAudio::UNIX_JACK;
  287. break;
  288. case RTAUDIO_MACOSX_CORE:
  289. rtApi = RtAudio::MACOSX_CORE;
  290. break;
  291. case RTAUDIO_WINDOWS_ASIO:
  292. rtApi = RtAudio::WINDOWS_ASIO;
  293. break;
  294. case RTAUDIO_WINDOWS_DS:
  295. rtApi = RtAudio::WINDOWS_DS;
  296. break;
  297. }
  298. return new CarlaEngineRtAudio(rtApi);
  299. }
  300. unsigned int CarlaEngine::getRtAudioApiCount()
  301. {
  302. initRtApis();
  303. return rtApis.size();
  304. }
  305. const char* CarlaEngine::getRtAudioApiName(unsigned int index)
  306. {
  307. initRtApis();
  308. if (index < rtApis.size())
  309. {
  310. const RtAudio::Api& api(rtApis[index]);
  311. switch (api)
  312. {
  313. case RtAudio::UNSPECIFIED:
  314. return "Unspecified";
  315. case RtAudio::LINUX_ALSA:
  316. return "ALSA";
  317. case RtAudio::LINUX_PULSE:
  318. return "PulseAudio";
  319. case RtAudio::LINUX_OSS:
  320. return "OSS";
  321. case RtAudio::UNIX_JACK:
  322. return "JACK (RtAudio)";
  323. case RtAudio::MACOSX_CORE:
  324. return "CoreAudio";
  325. case RtAudio::WINDOWS_ASIO:
  326. return "ASIO";
  327. case RtAudio::WINDOWS_DS:
  328. return "DirectSound";
  329. case RtAudio::RTAUDIO_DUMMY:
  330. return "Dummy";
  331. }
  332. }
  333. return nullptr;
  334. }
  335. // -----------------------------------------
  336. CARLA_BACKEND_END_NAMESPACE
  337. #ifdef QTCREATOR_TEST
  338. int main()
  339. {
  340. return 0;
  341. }
  342. #endif
  343. #endif // CARLA_ENGINE_RTAUDIO