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.

324 lines
8.0KB

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