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.

213 lines
5.0KB

  1. #include "util.hpp"
  2. #include "math.hpp"
  3. #include "audio.hpp"
  4. namespace rack {
  5. AudioIO::AudioIO() {
  6. setDriver(RtAudio::UNSPECIFIED);
  7. }
  8. AudioIO::~AudioIO() {
  9. closeStream();
  10. }
  11. std::vector<int> AudioIO::listDrivers() {
  12. std::vector<RtAudio::Api> apis;
  13. RtAudio::getCompiledApi(apis);
  14. std::vector<int> drivers;
  15. for (RtAudio::Api api : apis)
  16. drivers.push_back((int) api);
  17. return drivers;
  18. }
  19. std::string AudioIO::getDriverName(int driver) {
  20. switch (driver) {
  21. case RtAudio::UNSPECIFIED: return "Unspecified";
  22. case RtAudio::LINUX_ALSA: return "ALSA";
  23. case RtAudio::LINUX_PULSE: return "PulseAudio";
  24. case RtAudio::LINUX_OSS: return "OSS";
  25. case RtAudio::UNIX_JACK: return "JACK";
  26. case RtAudio::MACOSX_CORE: return "Core Audio";
  27. case RtAudio::WINDOWS_WASAPI: return "WASAPI";
  28. case RtAudio::WINDOWS_ASIO: return "ASIO";
  29. case RtAudio::WINDOWS_DS: return "DirectSound";
  30. case RtAudio::RTAUDIO_DUMMY: return "Dummy";
  31. default: return "Unknown";
  32. }
  33. }
  34. int AudioIO::getDriver() {
  35. if (!stream)
  36. return RtAudio::UNSPECIFIED;
  37. return stream->getCurrentApi();
  38. }
  39. void AudioIO::setDriver(int driver) {
  40. // closeStream();
  41. if (stream)
  42. delete stream;
  43. stream = new RtAudio((RtAudio::Api) driver);
  44. }
  45. int AudioIO::getDeviceCount() {
  46. if (!stream)
  47. return 0;
  48. return stream->getDeviceCount();
  49. }
  50. std::string AudioIO::getDeviceName(int device) {
  51. if (!stream || device < 0)
  52. return "";
  53. try {
  54. RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device);
  55. return deviceInfo.name;
  56. }
  57. catch (RtAudioError &e) {
  58. warn("Failed to query audio device: %s", e.what());
  59. return "";
  60. }
  61. }
  62. std::string AudioIO::getDeviceDetail(int device) {
  63. if (!stream || device < 0)
  64. return "";
  65. try {
  66. RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device);
  67. return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels);
  68. }
  69. catch (RtAudioError &e) {
  70. warn("Failed to query audio device: %s", e.what());
  71. return "";
  72. }
  73. }
  74. static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) {
  75. AudioIO *audioIO = (AudioIO*) userData;
  76. assert(audioIO);
  77. // audioInterface->stepStream((const float *) inputBuffer, (float *) outputBuffer, nFrames);
  78. return 0;
  79. }
  80. void AudioIO::openStream() {
  81. // Close device but remember the current device number
  82. int device = this->device;
  83. closeStream();
  84. if (!stream)
  85. return;
  86. // Open new device
  87. if (device >= 0) {
  88. RtAudio::DeviceInfo deviceInfo;
  89. try {
  90. deviceInfo = stream->getDeviceInfo(device);
  91. }
  92. catch (RtAudioError &e) {
  93. warn("Failed to query audio device: %s", e.what());
  94. return;
  95. }
  96. numOutputs = mini(deviceInfo.outputChannels, maxOutputs);
  97. numInputs = mini(deviceInfo.inputChannels, maxInputs);
  98. if (numOutputs == 0 && numInputs == 0) {
  99. warn("Audio device %d has 0 inputs and 0 outputs");
  100. return;
  101. }
  102. RtAudio::StreamParameters outParameters;
  103. outParameters.deviceId = device;
  104. outParameters.nChannels = numOutputs;
  105. RtAudio::StreamParameters inParameters;
  106. inParameters.deviceId = device;
  107. inParameters.nChannels = numInputs;
  108. RtAudio::StreamOptions options;
  109. // options.flags |= RTAUDIO_SCHEDULE_REALTIME;
  110. // Find closest sample rate
  111. unsigned int closestSampleRate = 0;
  112. for (unsigned int sr : deviceInfo.sampleRates) {
  113. if (fabsf(sr - sampleRate) < fabsf(closestSampleRate - sampleRate)) {
  114. closestSampleRate = sr;
  115. }
  116. }
  117. try {
  118. debug("Opening audio stream %d", device);
  119. stream->openStream(
  120. numOutputs == 0 ? NULL : &outParameters,
  121. numInputs == 0 ? NULL : &inParameters,
  122. RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize, &rtCallback, this, &options, NULL);
  123. }
  124. catch (RtAudioError &e) {
  125. warn("Failed to open audio stream: %s", e.what());
  126. return;
  127. }
  128. try {
  129. debug("Starting audio stream %d", device);
  130. stream->startStream();
  131. }
  132. catch (RtAudioError &e) {
  133. warn("Failed to start audio stream: %s", e.what());
  134. return;
  135. }
  136. // Update sample rate because this may have changed
  137. this->sampleRate = stream->getStreamSampleRate();
  138. this->device = device;
  139. }
  140. }
  141. void AudioIO::closeStream() {
  142. if (stream) {
  143. if (stream->isStreamRunning()) {
  144. debug("Aborting audio stream %d", device);
  145. try {
  146. stream->abortStream();
  147. }
  148. catch (RtAudioError &e) {
  149. warn("Failed to abort stream %s", e.what());
  150. }
  151. }
  152. if (stream->isStreamOpen()) {
  153. debug("Closing audio stream %d", device);
  154. try {
  155. stream->closeStream();
  156. }
  157. catch (RtAudioError &e) {
  158. warn("Failed to close stream %s", e.what());
  159. }
  160. }
  161. }
  162. // Reset stream settings
  163. device = -1;
  164. numOutputs = 0;
  165. numInputs = 0;
  166. }
  167. std::vector<int> AudioIO::listSampleRates() {
  168. if (!stream || device < 0)
  169. return {};
  170. try {
  171. RtAudio::DeviceInfo deviceInfo = stream->getDeviceInfo(device);
  172. std::vector<int> sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end());
  173. return sampleRates;
  174. }
  175. catch (RtAudioError &e) {
  176. warn("Failed to query audio device: %s", e.what());
  177. return {};
  178. }
  179. }
  180. } // namespace rack