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.

305 lines
7.4KB

  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. blockSizes.push_back((1 << i) / 2 * 3);
  146. }
  147. blockSizes.push_back(1 << 12);
  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. return RtAudio::getApiDisplayName(rtAudio->getCurrentApi());
  181. }
  182. std::vector<int> getDeviceIds() override {
  183. int count = rtAudio->getDeviceCount();
  184. std::vector<int> deviceIds;
  185. for (int i = 0; i < count; i++)
  186. deviceIds.push_back(i);
  187. return deviceIds;
  188. }
  189. std::string getDeviceName(int deviceId) override {
  190. if (deviceId >= 0) {
  191. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  192. return deviceInfo.name;
  193. }
  194. return "";
  195. }
  196. int getDeviceNumInputs(int deviceId) override {
  197. if (deviceId >= 0) {
  198. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  199. return deviceInfo.inputChannels;
  200. }
  201. return 0;
  202. }
  203. int getDeviceNumOutputs(int deviceId) override {
  204. if (deviceId >= 0) {
  205. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  206. return deviceInfo.outputChannels;
  207. }
  208. return 0;
  209. }
  210. audio::Device* subscribe(int deviceId, audio::Port* port) override {
  211. RtAudioDevice* device;
  212. auto it = devices.find(deviceId);
  213. if (it == devices.end()) {
  214. try {
  215. device = new RtAudioDevice(rtAudio->getCurrentApi(), deviceId);
  216. devices[deviceId] = device;
  217. }
  218. catch (Exception& e) {
  219. WARN("Could not subscribe to audio device: %s", e.what());
  220. return NULL;
  221. }
  222. }
  223. else {
  224. device = it->second;
  225. }
  226. device->subscribe(port);
  227. return device;
  228. }
  229. void unsubscribe(int deviceId, audio::Port* port) override {
  230. auto it = devices.find(deviceId);
  231. if (it == devices.end())
  232. return;
  233. RtAudioDevice* device = it->second;
  234. device->unsubscribe(port);
  235. if (device->subscribed.empty()) {
  236. devices.erase(it);
  237. delete device;
  238. }
  239. }
  240. };
  241. void rtaudioInit() {
  242. std::vector<RtAudio::Api> apis;
  243. RtAudio::getCompiledApi(apis);
  244. // I don't like the order returned by getCompiledApi(), so reorder it here.
  245. std::vector<RtAudio::Api> orderedApis = {
  246. RtAudio::LINUX_ALSA,
  247. RtAudio::UNIX_JACK,
  248. RtAudio::LINUX_PULSE,
  249. RtAudio::LINUX_OSS,
  250. RtAudio::WINDOWS_WASAPI,
  251. RtAudio::WINDOWS_ASIO,
  252. RtAudio::WINDOWS_DS,
  253. RtAudio::MACOSX_CORE,
  254. };
  255. for (RtAudio::Api api : orderedApis) {
  256. auto it = std::find(apis.begin(), apis.end(), api);
  257. if (it != apis.end()) {
  258. RtAudioDriver* driver = new RtAudioDriver(api);
  259. audio::addDriver((int) api, driver);
  260. }
  261. }
  262. }
  263. } // namespace rack