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.

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