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
7.8KB

  1. #include <map>
  2. #include <algorithm>
  3. #pragma GCC diagnostic push
  4. #ifndef __clang__
  5. #pragma GCC diagnostic ignored "-Wsuggest-override"
  6. #endif
  7. #include <rtaudio/RtAudio.h>
  8. #pragma GCC diagnostic pop
  9. #include <rtaudio.hpp>
  10. #include <audio.hpp>
  11. #include <string.hpp>
  12. #include <math.hpp>
  13. #include <system.hpp>
  14. namespace rack {
  15. struct RtAudioDevice : audio::Device {
  16. RtAudio *rtAudio;
  17. int deviceId;
  18. RtAudio::DeviceInfo deviceInfo;
  19. RtAudio::StreamParameters inputParameters;
  20. RtAudio::StreamParameters outputParameters;
  21. RtAudio::StreamOptions options;
  22. int blockSize = 0;
  23. int sampleRate = 44100;
  24. RtAudioDevice(RtAudio::Api api, int deviceId) {
  25. rtAudio = new RtAudio(api);
  26. if (!rtAudio) {
  27. throw Exception(string::f("Failed to create RtAudio driver %d", api));
  28. }
  29. rtAudio->showWarnings(false);
  30. try {
  31. deviceInfo = rtAudio->getDeviceInfo(deviceId);
  32. }
  33. catch (RtAudioError& e) {
  34. WARN("Failed to query RtAudio device: %s", e.what());
  35. throw Exception(string::f("Failed to query RtAudio device: %s", e.what()));
  36. }
  37. this->deviceId = deviceId;
  38. openStream();
  39. }
  40. ~RtAudioDevice() {
  41. closeStream();
  42. delete rtAudio;
  43. }
  44. void openStream() {
  45. // Open new device
  46. if (deviceInfo.outputChannels == 0 && deviceInfo.inputChannels == 0) {
  47. WARN("RtAudio device %d has 0 inputs and 0 outputs", deviceId);
  48. return;
  49. }
  50. inputParameters = RtAudio::StreamParameters();
  51. inputParameters.deviceId = deviceId;
  52. inputParameters.nChannels = deviceInfo.inputChannels;
  53. inputParameters.firstChannel = 0;
  54. outputParameters = RtAudio::StreamParameters();
  55. outputParameters.deviceId = deviceId;
  56. outputParameters.nChannels = deviceInfo.outputChannels;
  57. outputParameters.firstChannel = 0;
  58. options = RtAudio::StreamOptions();
  59. options.flags |= RTAUDIO_MINIMIZE_LATENCY;
  60. options.flags |= RTAUDIO_SCHEDULE_REALTIME;
  61. options.numberOfBuffers = 2;
  62. options.streamName = "VCV Rack";
  63. int closestSampleRate = deviceInfo.preferredSampleRate;
  64. if (sampleRate > 0) {
  65. // Find the closest sample rate to the requested one.
  66. for (int sr : deviceInfo.sampleRates) {
  67. if (std::abs(sr - sampleRate) < std::abs(closestSampleRate - sampleRate)) {
  68. closestSampleRate = sr;
  69. }
  70. }
  71. }
  72. if (blockSize <= 0) {
  73. blockSize = 256;
  74. }
  75. INFO("Opening audio RtAudio device %d with %d in %d out", deviceId, inputParameters.nChannels, outputParameters.nChannels);
  76. try {
  77. rtAudio->openStream(
  78. outputParameters.nChannels > 0 ? &outputParameters : NULL,
  79. inputParameters.nChannels > 0 ? &inputParameters : NULL,
  80. RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize,
  81. &rtAudioCallback, this, &options, NULL);
  82. }
  83. catch (RtAudioError& e) {
  84. WARN("Failed to open RtAudio stream: %s", e.what());
  85. return;
  86. }
  87. INFO("Starting RtAudio stream %d", deviceId);
  88. try {
  89. rtAudio->startStream();
  90. }
  91. catch (RtAudioError& e) {
  92. WARN("Failed to start RtAudio stream: %s", e.what());
  93. return;
  94. }
  95. // Update sample rate to actual value
  96. sampleRate = rtAudio->getStreamSampleRate();
  97. INFO("Opened RtAudio stream");
  98. onOpenStream();
  99. }
  100. void closeStream() {
  101. if (rtAudio->isStreamRunning()) {
  102. INFO("Stopping RtAudio stream %d", deviceId);
  103. try {
  104. rtAudio->stopStream();
  105. }
  106. catch (RtAudioError& e) {
  107. WARN("Failed to stop RtAudio stream %s", e.what());
  108. }
  109. }
  110. if (rtAudio->isStreamOpen()) {
  111. INFO("Closing RtAudio stream %d", deviceId);
  112. try {
  113. rtAudio->closeStream();
  114. }
  115. catch (RtAudioError& e) {
  116. WARN("Failed to close RtAudio stream %s", e.what());
  117. }
  118. }
  119. INFO("Closed RtAudio stream");
  120. onCloseStream();
  121. }
  122. std::string getName() override {
  123. return deviceInfo.name;
  124. }
  125. int getNumInputs() override {
  126. return inputParameters.nChannels;
  127. }
  128. int getNumOutputs() override {
  129. return outputParameters.nChannels;
  130. }
  131. std::vector<int> getSampleRates() override {
  132. std::vector<int> sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end());
  133. return sampleRates;
  134. }
  135. int getSampleRate() override {
  136. return sampleRate;
  137. }
  138. void setSampleRate(int sampleRate) override {
  139. closeStream();
  140. this->sampleRate = sampleRate;
  141. openStream();
  142. }
  143. std::vector<int> getBlockSizes() override {
  144. std::vector<int> blockSizes;
  145. for (int i = 4; i <= 12; i++) {
  146. blockSizes.push_back(1 << i);
  147. }
  148. return blockSizes;
  149. }
  150. int getBlockSize() override {
  151. return blockSize;
  152. }
  153. void setBlockSize(int blockSize) override {
  154. closeStream();
  155. this->blockSize = blockSize;
  156. openStream();
  157. }
  158. static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
  159. RtAudioDevice* device = (RtAudioDevice*) userData;
  160. assert(device);
  161. int inputStride = device->getNumInputs();
  162. int outputStride = device->getNumOutputs();
  163. device->processBuffer((const float*) inputBuffer, inputStride, (float*) outputBuffer, outputStride, nFrames);
  164. return 0;
  165. }
  166. };
  167. struct RtAudioDriver : audio::Driver {
  168. // Just for querying device IDs names
  169. RtAudio *rtAudio;
  170. // deviceId -> Device
  171. std::map<int, RtAudioDevice*> devices;
  172. RtAudioDriver(RtAudio::Api api) {
  173. rtAudio = new RtAudio(api);
  174. }
  175. ~RtAudioDriver() {
  176. assert(devices.empty());
  177. delete rtAudio;
  178. }
  179. std::string getName() override {
  180. static const std::map<RtAudio::Api, std::string> apiNames = {
  181. {RtAudio::LINUX_ALSA, "ALSA"},
  182. {RtAudio::UNIX_JACK, "JACK (unsupported)"},
  183. {RtAudio::LINUX_PULSE, "PulseAudio"},
  184. {RtAudio::LINUX_OSS, "OSS"},
  185. {RtAudio::WINDOWS_WASAPI, "WASAPI"},
  186. {RtAudio::WINDOWS_ASIO, "ASIO"},
  187. {RtAudio::WINDOWS_DS, "DirectSound"},
  188. {RtAudio::MACOSX_CORE, "CoreAudio"},
  189. {RtAudio::RTAUDIO_DUMMY, "Dummy"},
  190. {RtAudio::UNSPECIFIED, "Unspecified"},
  191. };
  192. return apiNames.at(rtAudio->getCurrentApi());
  193. }
  194. std::vector<int> getDeviceIds() override {
  195. int count = rtAudio->getDeviceCount();
  196. std::vector<int> deviceIds;
  197. for (int i = 0; i < count; i++)
  198. deviceIds.push_back(i);
  199. return deviceIds;
  200. }
  201. std::string getDeviceName(int deviceId) override {
  202. if (deviceId >= 0) {
  203. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  204. return deviceInfo.name;
  205. }
  206. return "";
  207. }
  208. int getDeviceNumInputs(int deviceId) override {
  209. if (deviceId >= 0) {
  210. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  211. return deviceInfo.inputChannels;
  212. }
  213. return 0;
  214. }
  215. int getDeviceNumOutputs(int deviceId) override {
  216. if (deviceId >= 0) {
  217. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  218. return deviceInfo.outputChannels;
  219. }
  220. return 0;
  221. }
  222. audio::Device* subscribe(int deviceId, audio::Port* port) override {
  223. RtAudioDevice* device;
  224. auto it = devices.find(deviceId);
  225. if (it == devices.end()) {
  226. try {
  227. device = new RtAudioDevice(rtAudio->getCurrentApi(), deviceId);
  228. devices[deviceId] = device;
  229. }
  230. catch (Exception& e) {
  231. WARN("Could not subscribe to audio device: %s", e.what());
  232. return NULL;
  233. }
  234. }
  235. else {
  236. device = it->second;
  237. }
  238. device->subscribe(port);
  239. return device;
  240. }
  241. void unsubscribe(int deviceId, audio::Port* port) override {
  242. auto it = devices.find(deviceId);
  243. if (it == devices.end())
  244. return;
  245. RtAudioDevice* device = it->second;
  246. device->unsubscribe(port);
  247. if (device->subscribed.empty()) {
  248. devices.erase(it);
  249. delete device;
  250. }
  251. }
  252. };
  253. void rtaudioInit() {
  254. std::vector<RtAudio::Api> apis;
  255. RtAudio::getCompiledApi(apis);
  256. // I don't like the order returned by getCompiledApi(), so reorder it here.
  257. std::vector<RtAudio::Api> orderedApis = {
  258. RtAudio::LINUX_ALSA,
  259. RtAudio::UNIX_JACK,
  260. RtAudio::LINUX_PULSE,
  261. RtAudio::LINUX_OSS,
  262. RtAudio::WINDOWS_WASAPI,
  263. RtAudio::WINDOWS_ASIO,
  264. RtAudio::WINDOWS_DS,
  265. RtAudio::MACOSX_CORE,
  266. };
  267. for (RtAudio::Api api : orderedApis) {
  268. auto it = std::find(apis.begin(), apis.end(), api);
  269. if (it != apis.end()) {
  270. RtAudioDriver* driver = new RtAudioDriver(api);
  271. audio::addDriver((int) api, driver);
  272. }
  273. }
  274. }
  275. } // namespace rack