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

  1. #include <rtaudio.hpp>
  2. #include <audio.hpp>
  3. #include <string.hpp>
  4. #include <math.hpp>
  5. #include <system.hpp>
  6. #include <map>
  7. #include <algorithm>
  8. #pragma GCC diagnostic push
  9. #ifndef __clang__
  10. #pragma GCC diagnostic ignored "-Wsuggest-override"
  11. #endif
  12. #include <RtAudio.h>
  13. #pragma GCC diagnostic pop
  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_JACK_DONT_CONNECT;
  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. WARN("Failed to open RtAudio stream: %s", e.what());
  83. return;
  84. }
  85. INFO("Starting RtAudio stream %d", deviceId);
  86. try {
  87. rtAudio->startStream();
  88. }
  89. catch (RtAudioError& e) {
  90. WARN("Failed to start RtAudio stream: %s", e.what());
  91. return;
  92. }
  93. // Update sample rate to actual value
  94. sampleRate = rtAudio->getStreamSampleRate();
  95. INFO("Opened RtAudio stream");
  96. onOpenStream();
  97. }
  98. void closeStream() {
  99. if (rtAudio->isStreamRunning()) {
  100. INFO("Stopping RtAudio stream %d", deviceId);
  101. try {
  102. rtAudio->stopStream();
  103. }
  104. catch (RtAudioError& e) {
  105. WARN("Failed to stop RtAudio stream %s", e.what());
  106. }
  107. }
  108. if (rtAudio->isStreamOpen()) {
  109. INFO("Closing RtAudio stream %d", deviceId);
  110. try {
  111. rtAudio->closeStream();
  112. }
  113. catch (RtAudioError& e) {
  114. WARN("Failed to close RtAudio stream %s", e.what());
  115. }
  116. }
  117. INFO("Closed RtAudio stream");
  118. onCloseStream();
  119. }
  120. std::string getName() override {
  121. return deviceInfo.name;
  122. }
  123. int getNumInputs() override {
  124. return inputParameters.nChannels;
  125. }
  126. int getNumOutputs() override {
  127. return outputParameters.nChannels;
  128. }
  129. std::vector<int> getSampleRates() override {
  130. std::vector<int> sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end());
  131. return sampleRates;
  132. }
  133. int getSampleRate() override {
  134. return sampleRate;
  135. }
  136. void setSampleRate(int sampleRate) override {
  137. closeStream();
  138. this->sampleRate = sampleRate;
  139. openStream();
  140. }
  141. std::vector<int> getBlockSizes() override {
  142. std::vector<int> blockSizes;
  143. for (int i = 5; i <= 12; i++) {
  144. blockSizes.push_back(1 << i);
  145. }
  146. return blockSizes;
  147. }
  148. int getBlockSize() override {
  149. return blockSize;
  150. }
  151. void setBlockSize(int blockSize) override {
  152. closeStream();
  153. this->blockSize = blockSize;
  154. openStream();
  155. }
  156. static int rtAudioCallback(void* outputBuffer, void* inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void* userData) {
  157. RtAudioDevice* device = (RtAudioDevice*) userData;
  158. assert(device);
  159. int inputStride = device->getNumInputs();
  160. int outputStride = device->getNumOutputs();
  161. device->processBuffer((const float*) inputBuffer, inputStride, (float*) outputBuffer, outputStride, nFrames);
  162. return 0;
  163. }
  164. };
  165. struct RtAudioDriver : audio::Driver {
  166. // Just for querying device IDs names
  167. RtAudio *rtAudio;
  168. // deviceId -> Device
  169. std::map<int, RtAudioDevice*> devices;
  170. RtAudioDriver(RtAudio::Api api) {
  171. rtAudio = new RtAudio(api);
  172. }
  173. ~RtAudioDriver() {
  174. assert(devices.empty());
  175. delete rtAudio;
  176. }
  177. std::string getName() override {
  178. static const std::map<RtAudio::Api, std::string> apiNames = {
  179. {RtAudio::LINUX_ALSA, "ALSA"},
  180. {RtAudio::UNIX_JACK, "JACK (unsupported)"},
  181. {RtAudio::LINUX_PULSE, "PulseAudio"},
  182. {RtAudio::LINUX_OSS, "OSS"},
  183. {RtAudio::WINDOWS_WASAPI, "WASAPI"},
  184. {RtAudio::WINDOWS_ASIO, "ASIO"},
  185. {RtAudio::WINDOWS_DS, "DirectSound"},
  186. {RtAudio::MACOSX_CORE, "CoreAudio"},
  187. {RtAudio::RTAUDIO_DUMMY, "Dummy"},
  188. {RtAudio::UNSPECIFIED, "Unspecified"},
  189. };
  190. return apiNames.at(rtAudio->getCurrentApi());
  191. }
  192. std::vector<int> getDeviceIds() override {
  193. int count = rtAudio->getDeviceCount();
  194. std::vector<int> deviceIds;
  195. for (int i = 0; i < count; i++)
  196. deviceIds.push_back(i);
  197. return deviceIds;
  198. }
  199. std::string getDeviceName(int deviceId) override {
  200. if (deviceId >= 0) {
  201. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  202. return deviceInfo.name;
  203. }
  204. return "";
  205. }
  206. int getDeviceNumInputs(int deviceId) override {
  207. if (deviceId >= 0) {
  208. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  209. return deviceInfo.inputChannels;
  210. }
  211. return 0;
  212. }
  213. int getDeviceNumOutputs(int deviceId) override {
  214. if (deviceId >= 0) {
  215. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  216. return deviceInfo.outputChannels;
  217. }
  218. return 0;
  219. }
  220. audio::Device* subscribe(int deviceId, audio::Port* port) override {
  221. RtAudioDevice* device;
  222. auto it = devices.find(deviceId);
  223. if (it == devices.end()) {
  224. try {
  225. device = new RtAudioDevice(rtAudio->getCurrentApi(), deviceId);
  226. devices[deviceId] = device;
  227. }
  228. catch (Exception& e) {
  229. WARN("Could not subscribe to audio device: %s", e.what());
  230. return NULL;
  231. }
  232. }
  233. else {
  234. device = it->second;
  235. }
  236. device->subscribe(port);
  237. return device;
  238. }
  239. void unsubscribe(int deviceId, audio::Port* port) override {
  240. auto it = devices.find(deviceId);
  241. if (it == devices.end())
  242. return;
  243. RtAudioDevice* device = it->second;
  244. device->unsubscribe(port);
  245. if (device->subscribed.empty()) {
  246. devices.erase(it);
  247. delete device;
  248. }
  249. }
  250. };
  251. void rtaudioInit() {
  252. std::vector<RtAudio::Api> apis;
  253. RtAudio::getCompiledApi(apis);
  254. // I don't like the order returned by getCompiledApi(), so reorder it here.
  255. std::vector<RtAudio::Api> orderedApis = {
  256. RtAudio::LINUX_ALSA,
  257. RtAudio::UNIX_JACK,
  258. RtAudio::LINUX_PULSE,
  259. RtAudio::LINUX_OSS,
  260. RtAudio::WINDOWS_WASAPI,
  261. RtAudio::WINDOWS_ASIO,
  262. RtAudio::WINDOWS_DS,
  263. RtAudio::MACOSX_CORE,
  264. };
  265. for (RtAudio::Api api : orderedApis) {
  266. auto it = std::find(apis.begin(), apis.end(), api);
  267. if (it != apis.end()) {
  268. RtAudioDriver* driver = new RtAudioDriver(api);
  269. audio::addDriver((int) api, driver);
  270. }
  271. }
  272. }
  273. } // namespace rack