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.

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