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.

440 lines
11KB

  1. /*
  2. * Carla RtAudio Engine
  3. * Copyright (C) 2012 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 CARLA_ENGINE_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. // -------------------------------------------------------------------------------------------------------------------
  25. // RtAudio Engine client
  26. class CarlaEngineRtAudioClient : public CarlaEngineClient
  27. {
  28. public:
  29. CarlaEngineRtAudioClient(const CarlaEngineType engineType, const ProcessMode processMode)
  30. : CarlaEngineClient(engineType, processMode)
  31. {
  32. }
  33. ~CarlaEngineRtAudioClient()
  34. {
  35. }
  36. const CarlaEnginePort* addPort(const CarlaEnginePortType portType, const char* const name, const bool isInput)
  37. {
  38. qDebug("CarlaEngineRtAudioClient::addPort(%s, \"%s\", %s)", CarlaEnginePortType2Str(portType), name, bool2str(isInput));
  39. switch (portType)
  40. {
  41. case CarlaEnginePortTypeNull:
  42. break;
  43. case CarlaEnginePortTypeAudio:
  44. return new CarlaEngineAudioPort(isInput, processMode);
  45. case CarlaEnginePortTypeControl:
  46. return new CarlaEngineControlPort(isInput, processMode);
  47. case CarlaEnginePortTypeMIDI:
  48. return new CarlaEngineMidiPort(isInput, processMode);
  49. }
  50. qCritical("CarlaEngineRtAudioClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput));
  51. return nullptr;
  52. }
  53. };
  54. // -------------------------------------------------------------------------------------------------------------------
  55. // RtAudio Engine
  56. class CarlaEngineRtAudio : public CarlaEngine
  57. {
  58. public:
  59. CarlaEngineRtAudio(RtAudio::Api api)
  60. : CarlaEngine(),
  61. audio(api)
  62. {
  63. qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio()");
  64. midiIn = nullptr;
  65. midiOut = nullptr;
  66. m_audioInterleaved = false;
  67. m_inBuf1 = nullptr;
  68. m_inBuf2 = nullptr;
  69. m_outBuf1 = nullptr;
  70. m_outBuf2 = nullptr;
  71. // just to make sure
  72. options.forceStereo = true;
  73. options.processMode = PROCESS_MODE_CONTINUOUS_RACK;
  74. }
  75. ~CarlaEngineRtAudio()
  76. {
  77. qDebug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
  78. }
  79. // -------------------------------------
  80. bool init(const char* const clientName)
  81. {
  82. qDebug("CarlaEngineRtAudio::init(\"%s\")", clientName);
  83. if (audio.getDeviceCount() < 1)
  84. {
  85. setLastError("No audio devices available for this driver");
  86. return false;
  87. }
  88. bufferSize = options.preferredBufferSize;
  89. sampleRate = options.preferredSampleRate;
  90. RtAudio::StreamParameters iParams, oParams;
  91. iParams.deviceId = audio.getDefaultInputDevice();
  92. oParams.deviceId = audio.getDefaultOutputDevice();
  93. iParams.nChannels = 2;
  94. oParams.nChannels = 2;
  95. RtAudio::StreamOptions rtOptions;
  96. rtOptions.flags = RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_HOG_DEVICE | RTAUDIO_SCHEDULE_REALTIME;
  97. rtOptions.numberOfBuffers = 2;
  98. rtOptions.streamName = clientName;
  99. rtOptions.priority = 85;
  100. if (audio.getCurrentApi() != RtAudio::LINUX_PULSE)
  101. {
  102. rtOptions.flags |= RTAUDIO_NONINTERLEAVED;
  103. m_audioInterleaved = false;
  104. if (audio.getCurrentApi() == RtAudio::LINUX_ALSA)
  105. rtOptions.flags |= RTAUDIO_ALSA_USE_DEFAULT;
  106. }
  107. else
  108. m_audioInterleaved = true;
  109. try {
  110. audio.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, sampleRate, &bufferSize, carla_rtaudio_process_callback, this, &rtOptions);
  111. }
  112. catch (RtError& e)
  113. {
  114. setLastError(e.what());
  115. return false;
  116. }
  117. try {
  118. audio.startStream();
  119. }
  120. catch (RtError& e)
  121. {
  122. setLastError(e.what());
  123. return false;
  124. }
  125. sampleRate = audio.getStreamSampleRate();
  126. m_inBuf1 = new float [bufferSize];
  127. m_inBuf2 = new float [bufferSize];
  128. m_outBuf1 = new float [bufferSize];
  129. m_outBuf2 = new float [bufferSize];
  130. //midiIn = new MidiInAlsa(clientName, 512);
  131. //midiIn->openVirtualPort("control-in");
  132. //midiIn->openVirtualPort("midi-in");
  133. //midiOut = new MidiOutAlsa(clientName);
  134. //midiOut->openVirtualPort("control-out");
  135. //midiOut->openVirtualPort("midi-out");
  136. name = clientName;
  137. name.toBasic();
  138. CarlaEngine::init(name);
  139. return true;
  140. }
  141. bool close()
  142. {
  143. qDebug("CarlaEngineRtAudio::close()");
  144. CarlaEngine::close();
  145. if (audio.isStreamRunning())
  146. audio.stopStream();
  147. if (audio.isStreamOpen())
  148. audio.closeStream();
  149. #if 0
  150. if (midiIn)
  151. {
  152. midiIn->cancelCallback();
  153. midiIn->closePort();
  154. delete midiIn;
  155. midiIn = nullptr;
  156. }
  157. if (midiOut)
  158. {
  159. midiOut->closePort();
  160. delete midiOut;
  161. midiOut = nullptr;
  162. }
  163. #endif
  164. if (m_inBuf1)
  165. {
  166. delete[] m_inBuf1;
  167. m_inBuf1 = nullptr;
  168. }
  169. if (m_inBuf2)
  170. {
  171. delete[] m_inBuf2;
  172. m_inBuf2 = nullptr;
  173. }
  174. if (m_outBuf1)
  175. {
  176. delete[] m_outBuf1;
  177. m_outBuf1 = nullptr;
  178. }
  179. if (m_outBuf2)
  180. {
  181. delete[] m_outBuf2;
  182. m_outBuf2 = nullptr;
  183. }
  184. return true;
  185. }
  186. bool isRunning() const
  187. {
  188. return audio.isStreamRunning();
  189. }
  190. bool isOffline() const
  191. {
  192. return false;
  193. }
  194. CarlaEngineType type() const
  195. {
  196. return CarlaEngineTypeRtAudio;
  197. }
  198. CarlaEngineClient* addClient(CarlaPlugin* const)
  199. {
  200. return new CarlaEngineRtAudioClient(CarlaEngineTypeRtAudio, options.processMode);
  201. }
  202. // -------------------------------------
  203. protected:
  204. void handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  205. {
  206. if (maxPluginNumber() == 0)
  207. return;
  208. // get buffers from RtAudio
  209. float* insPtr = (float*)inputBuffer;
  210. float* outsPtr = (float*)outputBuffer;
  211. // assert buffers
  212. CARLA_ASSERT(insPtr);
  213. CARLA_ASSERT(outsPtr);
  214. // initialize audio input
  215. if (m_audioInterleaved)
  216. {
  217. for (unsigned int i=0; i < nframes*2; i++)
  218. {
  219. if (i % 2)
  220. m_inBuf2[i/2] = insPtr[i];
  221. else
  222. m_inBuf1[i/2] = insPtr[i];
  223. }
  224. }
  225. else
  226. {
  227. for (unsigned int i=0; i < nframes; i++)
  228. m_inBuf1[i] = insPtr[i];
  229. for (unsigned int i=0, j=nframes; i < nframes; i++, j++)
  230. m_inBuf2[i] = insPtr[j];
  231. }
  232. // create audio buffers
  233. float* inBuf[2] = { m_inBuf1, m_inBuf2 };
  234. float* outBuf[2] = { m_outBuf1, m_outBuf2 };
  235. // initialize control input
  236. memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_CONTROL_EVENTS);
  237. {
  238. // TODO
  239. }
  240. // initialize midi input
  241. memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_MIDI_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. MidiInApi* midiIn;
  279. MidiOutApi* midiOut;
  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. };
  292. // -----------------------------------------
  293. CarlaEngine* CarlaEngine::newRtAudio(RtAudioApi api)
  294. {
  295. RtAudio::Api rtApi = RtAudio::UNSPECIFIED;
  296. switch (api)
  297. {
  298. case RTAUDIO_DUMMY:
  299. rtApi = RtAudio::RTAUDIO_DUMMY;
  300. break;
  301. case RTAUDIO_LINUX_ALSA:
  302. rtApi = RtAudio::LINUX_ALSA;
  303. break;
  304. case RTAUDIO_LINUX_PULSE:
  305. rtApi = RtAudio::LINUX_PULSE;
  306. break;
  307. case RTAUDIO_LINUX_OSS:
  308. rtApi = RtAudio::LINUX_OSS;
  309. break;
  310. case RTAUDIO_UNIX_JACK:
  311. rtApi = RtAudio::UNIX_JACK;
  312. break;
  313. case RTAUDIO_MACOSX_CORE:
  314. rtApi = RtAudio::MACOSX_CORE;
  315. break;
  316. case RTAUDIO_WINDOWS_ASIO:
  317. rtApi = RtAudio::WINDOWS_ASIO;
  318. break;
  319. case RTAUDIO_WINDOWS_DS:
  320. rtApi = RtAudio::WINDOWS_DS;
  321. break;
  322. }
  323. return new CarlaEngineRtAudio(rtApi);
  324. }
  325. unsigned int CarlaEngine::getRtAudioApiCount()
  326. {
  327. std::vector<RtAudio::Api> apis;
  328. RtAudio::getCompiledApi(apis);
  329. return apis.size();
  330. }
  331. const char* CarlaEngine::getRtAudioApiName(unsigned int index)
  332. {
  333. std::vector<RtAudio::Api> apis;
  334. RtAudio::getCompiledApi(apis);
  335. if (index < apis.size())
  336. {
  337. const RtAudio::Api& api(apis[index]);
  338. switch (api)
  339. {
  340. case RtAudio::UNSPECIFIED:
  341. return "Unspecified";
  342. case RtAudio::LINUX_ALSA:
  343. return "ALSA";
  344. case RtAudio::LINUX_PULSE:
  345. return "PulseAudio";
  346. case RtAudio::LINUX_OSS:
  347. return "OSS";
  348. case RtAudio::UNIX_JACK:
  349. return "JACK (RtAudio)";
  350. case RtAudio::MACOSX_CORE:
  351. return "CoreAudio";
  352. case RtAudio::WINDOWS_ASIO:
  353. return "ASIO";
  354. case RtAudio::WINDOWS_DS:
  355. return "DirectSound";
  356. case RtAudio::RTAUDIO_DUMMY:
  357. return "Dummy";
  358. }
  359. }
  360. return nullptr;
  361. }
  362. CARLA_BACKEND_END_NAMESPACE
  363. #endif // CARLA_ENGINE_RTAUDIO