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.

466 lines
12KB

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