Collection of tools useful for audio production
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.

366 lines
9.4KB

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