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.

393 lines
11KB

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