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.

rtaudio.cpp 8.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. int inputStride = device->getNumInputs();
  170. int outputStride = device->getNumOutputs();
  171. device->processBuffer((const float*) inputBuffer, inputStride, (float*) outputBuffer, outputStride, nFrames);
  172. return 0;
  173. }
  174. };
  175. struct RtAudioDriver : audio::Driver {
  176. // Just for querying device IDs names
  177. RtAudio* rtAudio;
  178. // deviceId -> Device
  179. std::map<int, RtAudioDevice*> devices;
  180. RtAudioDriver(RtAudio::Api api) {
  181. rtAudio = new RtAudio(api);
  182. rtAudio->showWarnings(false);
  183. }
  184. ~RtAudioDriver() {
  185. assert(devices.empty());
  186. delete rtAudio;
  187. }
  188. std::string getName() override {
  189. static const std::map<RtAudio::Api, std::string> apiNames = {
  190. {RtAudio::LINUX_ALSA, "ALSA"},
  191. {RtAudio::UNIX_JACK, "JACK (unsupported)"},
  192. {RtAudio::LINUX_PULSE, "PulseAudio"},
  193. {RtAudio::LINUX_OSS, "OSS"},
  194. {RtAudio::WINDOWS_WASAPI, "WASAPI"},
  195. {RtAudio::WINDOWS_ASIO, "ASIO"},
  196. {RtAudio::WINDOWS_DS, "DirectSound"},
  197. {RtAudio::MACOSX_CORE, "CoreAudio"},
  198. {RtAudio::RTAUDIO_DUMMY, "Dummy"},
  199. {RtAudio::UNSPECIFIED, "Unspecified"},
  200. };
  201. return apiNames.at(rtAudio->getCurrentApi());
  202. }
  203. std::vector<int> getDeviceIds() override {
  204. int count = rtAudio->getDeviceCount();
  205. std::vector<int> deviceIds;
  206. for (int i = 0; i < count; i++)
  207. deviceIds.push_back(i);
  208. return deviceIds;
  209. }
  210. std::string getDeviceName(int deviceId) override {
  211. if (deviceId >= 0) {
  212. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  213. return deviceInfo.name;
  214. }
  215. return "";
  216. }
  217. int getDeviceNumInputs(int deviceId) override {
  218. if (deviceId >= 0) {
  219. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  220. return deviceInfo.inputChannels;
  221. }
  222. return 0;
  223. }
  224. int getDeviceNumOutputs(int deviceId) override {
  225. if (deviceId >= 0) {
  226. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  227. return deviceInfo.outputChannels;
  228. }
  229. return 0;
  230. }
  231. audio::Device* subscribe(int deviceId, audio::Port* port) override {
  232. RtAudioDevice* device;
  233. auto it = devices.find(deviceId);
  234. if (it == devices.end()) {
  235. // Can throw Exception
  236. device = new RtAudioDevice(rtAudio->getCurrentApi(), deviceId);
  237. devices[deviceId] = device;
  238. }
  239. else {
  240. device = it->second;
  241. }
  242. device->subscribe(port);
  243. return device;
  244. }
  245. void unsubscribe(int deviceId, audio::Port* port) override {
  246. auto it = devices.find(deviceId);
  247. if (it == devices.end())
  248. return;
  249. RtAudioDevice* device = it->second;
  250. device->unsubscribe(port);
  251. if (device->subscribed.empty()) {
  252. devices.erase(it);
  253. delete device;
  254. }
  255. }
  256. };
  257. void rtaudioInit() {
  258. std::vector<RtAudio::Api> apis;
  259. RtAudio::getCompiledApi(apis);
  260. // I don't like the order returned by getCompiledApi(), so reorder it here.
  261. std::vector<RtAudio::Api> orderedApis = {
  262. RtAudio::LINUX_ALSA,
  263. RtAudio::UNIX_JACK,
  264. RtAudio::LINUX_PULSE,
  265. RtAudio::LINUX_OSS,
  266. RtAudio::WINDOWS_WASAPI,
  267. RtAudio::WINDOWS_ASIO,
  268. RtAudio::WINDOWS_DS,
  269. RtAudio::MACOSX_CORE,
  270. };
  271. for (RtAudio::Api api : orderedApis) {
  272. auto it = std::find(apis.begin(), apis.end(), api);
  273. if (it != apis.end()) {
  274. RtAudioDriver* driver = new RtAudioDriver(api);
  275. audio::addDriver((int) api, driver);
  276. }
  277. }
  278. }
  279. } // namespace rack