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.

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