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.

277 lines
6.7KB

  1. #include "util.hpp"
  2. #include "math.hpp"
  3. #include "audio.hpp"
  4. #define DRIVER_BRIDGE -1
  5. namespace rack {
  6. AudioIO::AudioIO() {
  7. setDriver(RtAudio::UNSPECIFIED);
  8. }
  9. AudioIO::~AudioIO() {
  10. closeStream();
  11. }
  12. std::vector<int> AudioIO::listDrivers() {
  13. std::vector<RtAudio::Api> apis;
  14. RtAudio::getCompiledApi(apis);
  15. std::vector<int> drivers;
  16. for (RtAudio::Api api : apis)
  17. drivers.push_back((int) api);
  18. // Add Bridge fake driver
  19. // drivers.push_back(DRIVER_BRIDGE);
  20. return drivers;
  21. }
  22. std::string AudioIO::getDriverName(int driver) {
  23. switch (driver) {
  24. case RtAudio::UNSPECIFIED: return "Unspecified";
  25. case RtAudio::LINUX_ALSA: return "ALSA";
  26. case RtAudio::LINUX_PULSE: return "PulseAudio";
  27. case RtAudio::LINUX_OSS: return "OSS";
  28. case RtAudio::UNIX_JACK: return "JACK";
  29. case RtAudio::MACOSX_CORE: return "Core Audio";
  30. case RtAudio::WINDOWS_WASAPI: return "WASAPI";
  31. case RtAudio::WINDOWS_ASIO: return "ASIO";
  32. case RtAudio::WINDOWS_DS: return "DirectSound";
  33. case RtAudio::RTAUDIO_DUMMY: return "Dummy";
  34. case DRIVER_BRIDGE: return "VCV Bridge";
  35. default: return "Unknown";
  36. }
  37. }
  38. void AudioIO::setDriver(int driver) {
  39. // Close driver
  40. closeStream();
  41. if (rtAudio) {
  42. delete rtAudio;
  43. rtAudio = NULL;
  44. }
  45. this->driver = 0;
  46. // Open driver
  47. if (driver >= 0) {
  48. rtAudio = new RtAudio((RtAudio::Api) driver);
  49. this->driver = (int) rtAudio->getCurrentApi();
  50. }
  51. else if (driver == DRIVER_BRIDGE) {
  52. // TODO Connect to Bridge
  53. this->driver = DRIVER_BRIDGE;
  54. }
  55. }
  56. int AudioIO::getDeviceCount() {
  57. if (rtAudio) {
  58. return rtAudio->getDeviceCount();
  59. }
  60. if (driver == DRIVER_BRIDGE) {
  61. return 16;
  62. }
  63. return 0;
  64. }
  65. std::string AudioIO::getDeviceName(int device) {
  66. if (rtAudio) {
  67. try {
  68. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device);
  69. return deviceInfo.name;
  70. }
  71. catch (RtAudioError &e) {
  72. warn("Failed to query RtAudio device: %s", e.what());
  73. }
  74. }
  75. if (driver == DRIVER_BRIDGE) {
  76. return stringf("%d", device + 1);
  77. }
  78. return "";
  79. }
  80. std::string AudioIO::getDeviceDetail(int device) {
  81. if (rtAudio) {
  82. try {
  83. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device);
  84. return stringf("%s (%d in, %d out)", deviceInfo.name.c_str(), deviceInfo.inputChannels, deviceInfo.outputChannels);
  85. }
  86. catch (RtAudioError &e) {
  87. warn("Failed to query RtAudio device: %s", e.what());
  88. }
  89. }
  90. if (driver == DRIVER_BRIDGE) {
  91. return stringf("Channel %d", device + 1);
  92. }
  93. return "";
  94. }
  95. static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) {
  96. AudioIO *audioIO = (AudioIO*) userData;
  97. assert(audioIO);
  98. audioIO->processStream((const float *) inputBuffer, (float *) outputBuffer, nFrames);
  99. return 0;
  100. }
  101. void AudioIO::openStream() {
  102. // Close device but remember the current device number
  103. int device = this->device;
  104. closeStream();
  105. if (device < 0)
  106. return;
  107. if (rtAudio) {
  108. // Open new device
  109. RtAudio::DeviceInfo deviceInfo;
  110. try {
  111. deviceInfo = rtAudio->getDeviceInfo(device);
  112. }
  113. catch (RtAudioError &e) {
  114. warn("Failed to query RtAudio device: %s", e.what());
  115. return;
  116. }
  117. numOutputs = mini(deviceInfo.outputChannels, maxOutputs);
  118. numInputs = mini(deviceInfo.inputChannels, maxInputs);
  119. if (numOutputs == 0 && numInputs == 0) {
  120. warn("RtAudio device %d has 0 inputs and 0 outputs");
  121. return;
  122. }
  123. RtAudio::StreamParameters outParameters;
  124. outParameters.deviceId = device;
  125. outParameters.nChannels = numOutputs;
  126. RtAudio::StreamParameters inParameters;
  127. inParameters.deviceId = device;
  128. inParameters.nChannels = numInputs;
  129. RtAudio::StreamOptions options;
  130. // options.flags |= RTAUDIO_SCHEDULE_REALTIME;
  131. int closestSampleRate = deviceInfo.preferredSampleRate;
  132. for (int sr : deviceInfo.sampleRates) {
  133. if (abs(sr - sampleRate) < abs(closestSampleRate - sampleRate)) {
  134. closestSampleRate = sr;
  135. }
  136. }
  137. try {
  138. debug("Opening audio RtAudio device %d", device);
  139. rtAudio->openStream(
  140. numOutputs == 0 ? NULL : &outParameters,
  141. numInputs == 0 ? NULL : &inParameters,
  142. RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize, &rtCallback, this, &options, NULL);
  143. }
  144. catch (RtAudioError &e) {
  145. warn("Failed to open RtAudio stream: %s", e.what());
  146. return;
  147. }
  148. try {
  149. debug("Starting RtAudio stream %d", device);
  150. rtAudio->startStream();
  151. }
  152. catch (RtAudioError &e) {
  153. warn("Failed to start RtAudio stream: %s", e.what());
  154. return;
  155. }
  156. // Update sample rate because this may have changed
  157. this->sampleRate = rtAudio->getStreamSampleRate();
  158. this->device = device;
  159. onOpenStream();
  160. }
  161. }
  162. void AudioIO::closeStream() {
  163. if (rtAudio) {
  164. if (rtAudio->isStreamRunning()) {
  165. debug("Stopping RtAudio stream %d", device);
  166. try {
  167. rtAudio->stopStream();
  168. }
  169. catch (RtAudioError &e) {
  170. warn("Failed to stop RtAudio stream %s", e.what());
  171. }
  172. }
  173. if (rtAudio->isStreamOpen()) {
  174. debug("Closing RtAudio stream %d", device);
  175. try {
  176. rtAudio->closeStream();
  177. }
  178. catch (RtAudioError &e) {
  179. warn("Failed to close RtAudio stream %s", e.what());
  180. }
  181. }
  182. }
  183. // Reset rtAudio settings
  184. device = -1;
  185. numOutputs = 0;
  186. numInputs = 0;
  187. onCloseStream();
  188. }
  189. std::vector<int> AudioIO::listSampleRates() {
  190. if (rtAudio) {
  191. try {
  192. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device);
  193. std::vector<int> sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end());
  194. return sampleRates;
  195. }
  196. catch (RtAudioError &e) {
  197. warn("Failed to query RtAudio device: %s", e.what());
  198. }
  199. }
  200. if (driver == DRIVER_BRIDGE) {
  201. return {44100, 48000, 88200, 96000, 176400, 192000};
  202. }
  203. return {};
  204. }
  205. json_t *AudioIO::toJson() {
  206. json_t *rootJ = json_object();
  207. json_object_set_new(rootJ, "driver", json_integer(driver));
  208. std::string deviceName = getDeviceName(device);
  209. json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
  210. json_object_set_new(rootJ, "sampleRate", json_integer(sampleRate));
  211. json_object_set_new(rootJ, "blockSize", json_integer(blockSize));
  212. return rootJ;
  213. }
  214. void AudioIO::fromJson(json_t *rootJ) {
  215. json_t *driverJ = json_object_get(rootJ, "driver");
  216. if (driverJ)
  217. setDriver(json_number_value(driverJ));
  218. json_t *deviceNameJ = json_object_get(rootJ, "deviceName");
  219. if (deviceNameJ) {
  220. std::string deviceName = json_string_value(deviceNameJ);
  221. // Search for device ID with equal name
  222. for (int device = 0; device < getDeviceCount(); device++) {
  223. if (getDeviceName(device) == deviceName) {
  224. this->device = device;
  225. break;
  226. }
  227. }
  228. }
  229. json_t *sampleRateJ = json_object_get(rootJ, "sampleRate");
  230. if (sampleRateJ)
  231. sampleRate = json_integer_value(sampleRateJ);
  232. json_t *blockSizeJ = json_object_get(rootJ, "blockSize");
  233. if (blockSizeJ)
  234. blockSize = json_integer_value(blockSizeJ);
  235. openStream();
  236. }
  237. } // namespace rack