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.

317 lines
9.0KB

  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. }
  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. // unsigned int rtBufferFrames = getBufferSize();
  119. // RtAudio::StreamParameters iParams, oParams;
  120. // iParams.nChannels = plugin->audioInCount();
  121. // oParams.nChannels = plugin->audioOutCount();
  122. // RtAudio::StreamOptions options;
  123. // options.flags = /*RTAUDIO_NONINTERLEAVED |*/ RTAUDIO_MINIMIZE_LATENCY /*| RTAUDIO_HOG_DEVICE*/ | RTAUDIO_SCHEDULE_REALTIME | RTAUDIO_ALSA_USE_DEFAULT;
  124. // options.streamName = plugin->name();
  125. // options.priority = 85;
  126. // try {
  127. // adac.openStream(&oParams, &iParams, RTAUDIO_FLOAT32, getSampleRate(), &rtBufferFrames, carla_rtaudio_process_callback, this, &options);
  128. // }
  129. // catch (RtError& e)
  130. // {
  131. // setLastError(e.what());
  132. // return false;
  133. // }
  134. return new CarlaEngineClient(CarlaEngineTypeRtAudio, handle);
  135. Q_UNUSED(plugin);
  136. }
  137. // -------------------------------------------------------------------------------------------------------------------
  138. void CarlaEngineRtAudio::handleProcessCallback(void* outputBuffer, void* inputBuffer, unsigned int nframes, double streamTime, RtAudioStreamStatus status)
  139. {
  140. if (maxPluginNumber() == 0)
  141. return;
  142. // get buffers from RtAudio
  143. float* insPtr = (float*)inputBuffer;
  144. float* outsPtr = (float*)outputBuffer;
  145. // assert buffers
  146. Q_ASSERT(insPtr);
  147. Q_ASSERT(outsPtr);
  148. // create temporary audio buffers
  149. float ains_tmp_buf1[nframes];
  150. float ains_tmp_buf2[nframes];
  151. float aouts_tmp_buf1[nframes];
  152. float aouts_tmp_buf2[nframes];
  153. float* ains_tmp[2] = { ains_tmp_buf1, ains_tmp_buf2 };
  154. float* aouts_tmp[2] = { aouts_tmp_buf1, aouts_tmp_buf2 };
  155. // initialize audio input
  156. for (unsigned int i=0; i < nframes*2; i++)
  157. {
  158. if (i % 2)
  159. ains_tmp_buf2[i/2] = insPtr[i];
  160. else
  161. ains_tmp_buf1[i/2] = insPtr[i];
  162. }
  163. // initialize control input
  164. memset(rackControlEventsIn, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS);
  165. {
  166. // TODO
  167. }
  168. // initialize midi input
  169. memset(rackMidiEventsIn, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  170. {
  171. // TODO
  172. }
  173. // initialize outputs (zero)
  174. memset(aouts_tmp_buf1, 0, sizeof(float)*nframes);
  175. memset(aouts_tmp_buf2, 0, sizeof(float)*nframes);
  176. memset(rackControlEventsOut, 0, sizeof(CarlaEngineControlEvent)*MAX_ENGINE_CONTROL_EVENTS);
  177. memset(rackMidiEventsOut, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  178. bool processed = false;
  179. // process plugins
  180. for (unsigned short i=0, max=maxPluginNumber(); i < max; i++)
  181. {
  182. CarlaPlugin* const plugin = getPluginUnchecked(i);
  183. if (plugin && plugin->enabled())
  184. {
  185. if (processed)
  186. {
  187. // initialize inputs (from previous outputs)
  188. memcpy(ains_tmp_buf1, aouts_tmp_buf1, sizeof(float)*nframes);
  189. memcpy(ains_tmp_buf2, aouts_tmp_buf2, sizeof(float)*nframes);
  190. memcpy(rackMidiEventsIn, rackMidiEventsOut, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  191. // initialize outputs (zero)
  192. memset(aouts_tmp_buf1, 0, sizeof(float)*nframes);
  193. memset(aouts_tmp_buf2, 0, sizeof(float)*nframes);
  194. memset(rackMidiEventsOut, 0, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  195. }
  196. // process
  197. plugin->engineProcessLock();
  198. plugin->initBuffers();
  199. if (carlaOptions.processHighPrecision)
  200. {
  201. float* ains_buffer2[2];
  202. float* aouts_buffer2[2];
  203. for (uint32_t j=0; j < nframes; j += 8)
  204. {
  205. ains_buffer2[0] = ains_tmp_buf1 + j;
  206. ains_buffer2[1] = ains_tmp_buf2 + j;
  207. aouts_buffer2[0] = aouts_tmp_buf1 + j;
  208. aouts_buffer2[1] = aouts_tmp_buf2 + j;
  209. plugin->process(ains_buffer2, aouts_buffer2, 8, j);
  210. }
  211. }
  212. else
  213. plugin->process(ains_tmp, aouts_tmp, nframes);
  214. plugin->engineProcessUnlock();
  215. // if plugin has no audio inputs, add previous buffers
  216. if (plugin->audioInCount() == 0)
  217. {
  218. for (uint32_t j=0; j < nframes; j++)
  219. {
  220. aouts_tmp_buf1[j] += ains_tmp_buf1[j];
  221. aouts_tmp_buf2[j] += ains_tmp_buf2[j];
  222. }
  223. }
  224. processed = true;
  225. }
  226. }
  227. // if no plugins in the rack, copy inputs over outputs
  228. if (! processed)
  229. {
  230. memcpy(aouts_tmp_buf1, ains_tmp_buf1, sizeof(float)*nframes);
  231. memcpy(aouts_tmp_buf2, ains_tmp_buf2, sizeof(float)*nframes);
  232. memcpy(rackMidiEventsOut, rackMidiEventsIn, sizeof(CarlaEngineMidiEvent)*MAX_ENGINE_MIDI_EVENTS);
  233. }
  234. // output audio
  235. for (unsigned int i=0; i < nframes*2; i++)
  236. {
  237. if (i % 2)
  238. outsPtr[i] = aouts_tmp_buf2[i/2];
  239. else
  240. outsPtr[i] = aouts_tmp_buf1[i/2];
  241. }
  242. // output control
  243. {
  244. // TODO
  245. }
  246. // output midi
  247. {
  248. // TODO
  249. }
  250. Q_UNUSED(streamTime);
  251. Q_UNUSED(status);
  252. }
  253. CARLA_BACKEND_END_NAMESPACE
  254. #endif // CARLA_ENGINE_RTAUDIO