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.

318 lines
8.9KB

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