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.

329 lines
9.2KB

  1. /*
  2. * Carla Backend
  3. * Copyright (C) 2012 Filipe Coelho <falktx@gmail.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.h"
  19. #include "carla_plugin.h"
  20. CARLA_BACKEND_START_NAMESPACE
  21. // -------------------------------------------------------------------------------------------------------------------
  22. // static RtAudio<->Engine calls
  23. static int carla_rtaudio_process_callback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status, void* userData)
  24. {
  25. CarlaEngineRtAudio* const engine = (CarlaEngineRtAudio*)userData;
  26. engine->handleProcessCallback(outputBuffer, inputBuffer, nframes, streamTime, status);
  27. return 0;
  28. }
  29. // -------------------------------------------------------------------------------------------------------------------
  30. // Carla Engine (RtAudio)
  31. CarlaEngineRtAudio::CarlaEngineRtAudio(RtAudio::Api api)
  32. : CarlaEngine(),
  33. adac(api)
  34. {
  35. qDebug("CarlaEngineRtAudio::CarlaEngineRtAudio()");
  36. type = CarlaEngineTypeRtAudio;
  37. procThread = nullptr;
  38. }
  39. CarlaEngineRtAudio::~CarlaEngineRtAudio()
  40. {
  41. qDebug("CarlaEngineRtAudio::~CarlaEngineRtAudio()");
  42. }
  43. bool CarlaEngineRtAudio::init(const char* const clientName)
  44. {
  45. qDebug("CarlaEngineRtAudio::init(\"%s\")", clientName);
  46. procThread = nullptr;
  47. if (adac.getDeviceCount() < 1)
  48. {
  49. setLastError("No audio devices available");
  50. return false;
  51. }
  52. sampleRate = 48000;
  53. unsigned int rtBufferFrames = 512;
  54. RtAudio::StreamParameters iParams, oParams;
  55. //iParams.deviceId = 3;
  56. //oParams.deviceId = 2;
  57. iParams.nChannels = 2;
  58. oParams.nChannels = 2;
  59. RtAudio::StreamOptions options;
  60. options.flags = /*RTAUDIO_NONINTERLEAVED |*/ RTAUDIO_MINIMIZE_LATENCY /*| RTAUDIO_HOG_DEVICE*/ | RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_ALSA_USE_DEFAULT;
  61. options.streamName = clientName;
  62. options.priority = 85;
  63. try {
  64. adac.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, sampleRate, &rtBufferFrames, carla_rtaudio_process_callback, this, &options);
  65. }
  66. catch (RtError& e)
  67. {
  68. setLastError(e.what());
  69. return false;
  70. }
  71. bufferSize = rtBufferFrames;
  72. // set client name, fixed for OSC usage
  73. // FIXME - put this in shared?
  74. char* fixedName = strdup(clientName);
  75. for (size_t i=0; i < strlen(fixedName); i++)
  76. {
  77. if (! (std::isalpha(fixedName[i]) || std::isdigit(fixedName[i])))
  78. fixedName[i] = '_';
  79. }
  80. name = strdup(fixedName);
  81. free((void*)fixedName);
  82. qDebug("RtAudio bufferSize = %i", bufferSize);
  83. try {
  84. adac.startStream();
  85. }
  86. catch (RtError& e)
  87. {
  88. setLastError(e.what());
  89. return false;
  90. }
  91. CarlaEngine::init(name);
  92. return true;
  93. }
  94. bool CarlaEngineRtAudio::close()
  95. {
  96. qDebug("CarlaEngineRtAudio::close()");
  97. CarlaEngine::close();
  98. if (name)
  99. {
  100. free((void*)name);
  101. name = nullptr;
  102. }
  103. if (adac.isStreamRunning())
  104. adac.stopStream();
  105. if (adac.isStreamOpen())
  106. adac.closeStream();
  107. return true;
  108. }
  109. bool CarlaEngineRtAudio::isOnAudioThread()
  110. {
  111. return (QThread::currentThread() == procThread);
  112. }
  113. bool CarlaEngineRtAudio::isOffline()
  114. {
  115. return false;
  116. }
  117. bool CarlaEngineRtAudio::isRunning()
  118. {
  119. return adac.isStreamRunning();
  120. }
  121. CarlaEngineClient* CarlaEngineRtAudio::addClient(CarlaPlugin* const plugin)
  122. {
  123. CarlaEngineClientNativeHandle handle;
  124. // unsigned int rtBufferFrames = getBufferSize();
  125. // RtAudio::StreamParameters iParams, oParams;
  126. // iParams.nChannels = plugin->audioInCount();
  127. // oParams.nChannels = plugin->audioOutCount();
  128. // RtAudio::StreamOptions options;
  129. // options.flags = /*RTAUDIO_NONINTERLEAVED |*/ RTAUDIO_MINIMIZE_LATENCY /*| RTAUDIO_HOG_DEVICE*/ | RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_ALSA_USE_DEFAULT;
  130. // options.streamName = plugin->name();
  131. // options.priority = 85;
  132. // try {
  133. // adac.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, getSampleRate(), &rtBufferFrames, carla_rtaudio_process_callback, this, &options);
  134. // }
  135. // catch (RtError& e)
  136. // {
  137. // setLastError(e.what());
  138. // return false;
  139. // }
  140. return new CarlaEngineClient(CarlaEngineTypeRtAudio, handle);
  141. Q_UNUSED(plugin);
  142. }
  143. // -------------------------------------------------------------------------------------------------------------------
  144. void CarlaEngineRtAudio::handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  145. {
  146. if (procThread == nullptr)
  147. procThread = QThread::currentThread();
  148. if (maxPluginNumber == 0)
  149. return;
  150. // get buffers from RtAudio
  151. float* insPtr = (float*)inputBuffer;
  152. float* outsPtr = (float*)outputBuffer;
  153. // assert buffers
  154. Q_ASSERT(insPtr);
  155. Q_ASSERT(outsPtr);
  156. // create temporary audio buffers
  157. float ains_tmp_buf1[nframes];
  158. float ains_tmp_buf2[nframes];
  159. float aouts_tmp_buf1[nframes];
  160. float aouts_tmp_buf2[nframes];
  161. float* ains_tmp[2] = { ains_tmp_buf1, ains_tmp_buf2 };
  162. float* aouts_tmp[2] = { aouts_tmp_buf1, aouts_tmp_buf2 };
  163. // initialize audio input
  164. for (unsigned int i=0; i < nframes*2; i++)
  165. {
  166. if (i % 2)
  167. ains_tmp_buf2[i/2] = insPtr[i];
  168. else
  169. ains_tmp_buf1[i/2] = insPtr[i];
  170. }
  171. // initialize control input
  172. memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS);
  173. {
  174. // TODO
  175. }
  176. // initialize midi input
  177. memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  178. {
  179. // TODO
  180. }
  181. // initialize outputs (zero)
  182. memset(aouts_tmp_buf1, 0, sizeof(float)*nframes);
  183. memset(aouts_tmp_buf2, 0, sizeof(float)*nframes);
  184. memset(rackControlEventsOut, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS);
  185. memset(rackMidiEventsOut, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  186. bool processed = false;
  187. // process plugins
  188. for (unsigned short i=0; i < maxPluginNumber; i++)
  189. {
  190. CarlaPlugin* const plugin = getPluginUnchecked(i);
  191. if (plugin && plugin->enabled())
  192. {
  193. if (processed)
  194. {
  195. // initialize inputs (from previous outputs)
  196. memcpy(ains_tmp_buf1, aouts_tmp_buf1, sizeof(float)*nframes);
  197. memcpy(ains_tmp_buf2, aouts_tmp_buf2, sizeof(float)*nframes);
  198. memcpy(rackMidiEventsIn, rackMidiEventsOut, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  199. // initialize outputs (zero)
  200. memset(aouts_tmp_buf1, 0, sizeof(float)*nframes);
  201. memset(aouts_tmp_buf2, 0, sizeof(float)*nframes);
  202. memset(rackMidiEventsOut, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  203. }
  204. // process
  205. plugin->engineProcessLock();
  206. plugin->initBuffers();
  207. if (carlaOptions.processHighPrecision)
  208. {
  209. float* ains_buffer2[2];
  210. float* aouts_buffer2[2];
  211. for (uint32_t j=0; j < nframes; j += 8)
  212. {
  213. ains_buffer2[0] = ains_tmp_buf1 + j;
  214. ains_buffer2[1] = ains_tmp_buf2 + j;
  215. aouts_buffer2[0] = aouts_tmp_buf1 + j;
  216. aouts_buffer2[1] = aouts_tmp_buf2 + j;
  217. plugin->process(ains_buffer2, aouts_buffer2, 8, j);
  218. }
  219. }
  220. else
  221. plugin->process(ains_tmp, aouts_tmp, nframes);
  222. plugin->engineProcessUnlock();
  223. // if plugin has no audio inputs, add previous buffers
  224. if (plugin->audioInCount() == 0)
  225. {
  226. for (uint32_t j=0; j < nframes; j++)
  227. {
  228. aouts_tmp_buf1[j] += ains_tmp_buf1[j];
  229. aouts_tmp_buf2[j] += ains_tmp_buf2[j];
  230. }
  231. }
  232. processed = true;
  233. }
  234. }
  235. // if no plugins in the rack, copy inputs over outputs
  236. if (! processed)
  237. {
  238. memcpy(aouts_tmp_buf1, ains_tmp_buf1, sizeof(float)*nframes);
  239. memcpy(aouts_tmp_buf2, ains_tmp_buf2, sizeof(float)*nframes);
  240. memcpy(rackMidiEventsOut, rackMidiEventsIn, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  241. }
  242. // output audio
  243. for (unsigned int i=0; i < nframes*2; i++)
  244. {
  245. if (i % 2)
  246. outsPtr[i] = aouts_tmp_buf2[i/2];
  247. else
  248. outsPtr[i] = aouts_tmp_buf1[i/2];
  249. }
  250. // output control
  251. {
  252. // TODO
  253. }
  254. // output midi
  255. {
  256. // TODO
  257. }
  258. Q_UNUSED(streamTime);
  259. Q_UNUSED(status);
  260. }
  261. CARLA_BACKEND_END_NAMESPACE
  262. #endif // CARLA_ENGINE_RTAUDIO