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.

376 lines
9.0KB

  1. #include "audio.hpp"
  2. #include "string.hpp"
  3. #include "math.hpp"
  4. #include "bridge.hpp"
  5. namespace rack {
  6. namespace audio {
  7. IO::IO() {
  8. setDriver(RtAudio::UNSPECIFIED);
  9. }
  10. IO::~IO() {
  11. closeStream();
  12. }
  13. std::vector<int> IO::getDrivers() {
  14. std::vector<RtAudio::Api> apis;
  15. RtAudio::getCompiledApi(apis);
  16. std::vector<int> drivers;
  17. for (RtAudio::Api api : apis) {
  18. drivers.push_back((int) api);
  19. }
  20. // Add fake Bridge driver
  21. drivers.push_back(BRIDGE_DRIVER);
  22. return drivers;
  23. }
  24. std::string IO::getDriverName(int driver) {
  25. switch (driver) {
  26. case RtAudio::UNSPECIFIED: return "Unspecified";
  27. case RtAudio::LINUX_ALSA: return "ALSA";
  28. case RtAudio::LINUX_PULSE: return "PulseAudio";
  29. case RtAudio::LINUX_OSS: return "OSS";
  30. case RtAudio::UNIX_JACK: return "JACK";
  31. case RtAudio::MACOSX_CORE: return "Core Audio";
  32. case RtAudio::WINDOWS_WASAPI: return "WASAPI";
  33. case RtAudio::WINDOWS_ASIO: return "ASIO";
  34. case RtAudio::WINDOWS_DS: return "DirectSound";
  35. case RtAudio::RTAUDIO_DUMMY: return "Dummy Audio";
  36. case BRIDGE_DRIVER: return "Bridge";
  37. default: return "Unknown";
  38. }
  39. }
  40. void IO::setDriver(int driver) {
  41. // Close device
  42. setDevice(-1, 0);
  43. // Close driver
  44. if (rtAudio) {
  45. delete rtAudio;
  46. rtAudio = NULL;
  47. }
  48. this->driver = 0;
  49. // Open driver
  50. if (driver >= 0) {
  51. rtAudio = new RtAudio((RtAudio::Api) driver);
  52. this->driver = (int) rtAudio->getCurrentApi();
  53. }
  54. else if (driver == BRIDGE_DRIVER) {
  55. this->driver = BRIDGE_DRIVER;
  56. }
  57. }
  58. int IO::getDeviceCount() {
  59. if (rtAudio) {
  60. return rtAudio->getDeviceCount();
  61. }
  62. else if (driver == BRIDGE_DRIVER) {
  63. return BRIDGE_NUM_PORTS;
  64. }
  65. return 0;
  66. }
  67. bool IO::getDeviceInfo(int device, RtAudio::DeviceInfo *deviceInfo) {
  68. if (!deviceInfo)
  69. return false;
  70. if (rtAudio) {
  71. if (device == this->device) {
  72. *deviceInfo = this->deviceInfo;
  73. return true;
  74. }
  75. else {
  76. try {
  77. *deviceInfo = rtAudio->getDeviceInfo(device);
  78. return true;
  79. }
  80. catch (RtAudioError &e) {
  81. WARN("Failed to query RtAudio device: %s", e.what());
  82. }
  83. }
  84. }
  85. return false;
  86. }
  87. int IO::getDeviceChannels(int device) {
  88. if (device < 0)
  89. return 0;
  90. if (rtAudio) {
  91. RtAudio::DeviceInfo deviceInfo;
  92. if (getDeviceInfo(device, &deviceInfo))
  93. return std::max((int) deviceInfo.inputChannels, (int) deviceInfo.outputChannels);
  94. }
  95. else if (driver == BRIDGE_DRIVER) {
  96. return std::max(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
  97. }
  98. return 0;
  99. }
  100. std::string IO::getDeviceName(int device) {
  101. if (device < 0)
  102. return "";
  103. if (rtAudio) {
  104. RtAudio::DeviceInfo deviceInfo;
  105. if (getDeviceInfo(device, &deviceInfo))
  106. return deviceInfo.name;
  107. }
  108. else if (driver == BRIDGE_DRIVER) {
  109. return string::f("%d", device + 1);
  110. }
  111. return "";
  112. }
  113. std::string IO::getDeviceDetail(int device, int offset) {
  114. if (device < 0)
  115. return "";
  116. if (rtAudio) {
  117. RtAudio::DeviceInfo deviceInfo;
  118. if (getDeviceInfo(device, &deviceInfo)) {
  119. std::string deviceDetail = string::f("%s (", deviceInfo.name.c_str());
  120. if (offset < (int) deviceInfo.inputChannels)
  121. deviceDetail += string::f("%d-%d in", offset + 1, std::min(offset + maxChannels, (int) deviceInfo.inputChannels));
  122. if (offset < (int) deviceInfo.inputChannels && offset < (int) deviceInfo.outputChannels)
  123. deviceDetail += ", ";
  124. if (offset < (int) deviceInfo.outputChannels)
  125. deviceDetail += string::f("%d-%d out", offset + 1, std::min(offset + maxChannels, (int) deviceInfo.outputChannels));
  126. deviceDetail += ")";
  127. return deviceDetail;
  128. }
  129. }
  130. else if (driver == BRIDGE_DRIVER) {
  131. return string::f("Port %d", device + 1);
  132. }
  133. return "";
  134. }
  135. void IO::setDevice(int device, int offset) {
  136. closeStream();
  137. this->device = device;
  138. this->offset = offset;
  139. openStream();
  140. }
  141. std::vector<int> IO::getSampleRates() {
  142. if (rtAudio) {
  143. try {
  144. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(device);
  145. std::vector<int> sampleRates(deviceInfo.sampleRates.begin(), deviceInfo.sampleRates.end());
  146. return sampleRates;
  147. }
  148. catch (RtAudioError &e) {
  149. WARN("Failed to query RtAudio device: %s", e.what());
  150. }
  151. }
  152. return {};
  153. }
  154. void IO::setSampleRate(int sampleRate) {
  155. if (sampleRate == this->sampleRate)
  156. return;
  157. closeStream();
  158. this->sampleRate = sampleRate;
  159. openStream();
  160. }
  161. std::vector<int> IO::getBlockSizes() {
  162. if (rtAudio) {
  163. return {64, 128, 256, 512, 1024, 2048, 4096};
  164. }
  165. return {};
  166. }
  167. void IO::setBlockSize(int blockSize) {
  168. if (blockSize == this->blockSize)
  169. return;
  170. closeStream();
  171. this->blockSize = blockSize;
  172. openStream();
  173. }
  174. void IO::setChannels(int numOutputs, int numInputs) {
  175. this->numOutputs = numOutputs;
  176. this->numInputs = numInputs;
  177. onChannelsChange();
  178. }
  179. static int rtCallback(void *outputBuffer, void *inputBuffer, unsigned int nFrames, double streamTime, RtAudioStreamStatus status, void *userData) {
  180. IO *audioIO = (IO*) userData;
  181. assert(audioIO);
  182. audioIO->processStream((const float *) inputBuffer, (float *) outputBuffer, nFrames);
  183. return 0;
  184. }
  185. void IO::openStream() {
  186. if (device < 0)
  187. return;
  188. if (rtAudio) {
  189. // Open new device
  190. try {
  191. deviceInfo = rtAudio->getDeviceInfo(device);
  192. }
  193. catch (RtAudioError &e) {
  194. WARN("Failed to query RtAudio device: %s", e.what());
  195. return;
  196. }
  197. if (rtAudio->isStreamOpen())
  198. return;
  199. setChannels(math::clamp((int) deviceInfo.outputChannels - offset, 0, maxChannels), math::clamp((int) deviceInfo.inputChannels - offset, 0, maxChannels));
  200. if (numOutputs == 0 && numInputs == 0) {
  201. WARN("RtAudio device %d has 0 inputs and 0 outputs", device);
  202. return;
  203. }
  204. RtAudio::StreamParameters outParameters;
  205. outParameters.deviceId = device;
  206. outParameters.nChannels = numOutputs;
  207. outParameters.firstChannel = offset;
  208. RtAudio::StreamParameters inParameters;
  209. inParameters.deviceId = device;
  210. inParameters.nChannels = numInputs;
  211. inParameters.firstChannel = offset;
  212. RtAudio::StreamOptions options;
  213. options.flags |= RTAUDIO_JACK_DONT_CONNECT;
  214. options.streamName = "VCV Rack";
  215. int closestSampleRate = deviceInfo.preferredSampleRate;
  216. for (int sr : deviceInfo.sampleRates) {
  217. if (std::abs(sr - sampleRate) < std::abs(closestSampleRate - sampleRate)) {
  218. closestSampleRate = sr;
  219. }
  220. }
  221. try {
  222. INFO("Opening audio RtAudio device %d with %d in %d out", device, numInputs, numOutputs);
  223. rtAudio->openStream(
  224. numOutputs == 0 ? NULL : &outParameters,
  225. numInputs == 0 ? NULL : &inParameters,
  226. RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize,
  227. &rtCallback, this, &options, NULL);
  228. }
  229. catch (RtAudioError &e) {
  230. WARN("Failed to open RtAudio stream: %s", e.what());
  231. return;
  232. }
  233. try {
  234. INFO("Starting RtAudio stream %d", device);
  235. rtAudio->startStream();
  236. }
  237. catch (RtAudioError &e) {
  238. WARN("Failed to start RtAudio stream: %s", e.what());
  239. return;
  240. }
  241. // Update sample rate because this may have changed
  242. this->sampleRate = rtAudio->getStreamSampleRate();
  243. onOpenStream();
  244. }
  245. else if (driver == BRIDGE_DRIVER) {
  246. setChannels(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
  247. bridgeAudioSubscribe(device, this);
  248. }
  249. }
  250. void IO::closeStream() {
  251. setChannels(0, 0);
  252. if (rtAudio) {
  253. if (rtAudio->isStreamRunning()) {
  254. INFO("Stopping RtAudio stream %d", device);
  255. try {
  256. rtAudio->stopStream();
  257. }
  258. catch (RtAudioError &e) {
  259. WARN("Failed to stop RtAudio stream %s", e.what());
  260. }
  261. }
  262. if (rtAudio->isStreamOpen()) {
  263. INFO("Closing RtAudio stream %d", device);
  264. try {
  265. rtAudio->closeStream();
  266. }
  267. catch (RtAudioError &e) {
  268. WARN("Failed to close RtAudio stream %s", e.what());
  269. }
  270. }
  271. deviceInfo = RtAudio::DeviceInfo();
  272. }
  273. else if (driver == BRIDGE_DRIVER) {
  274. bridgeAudioUnsubscribe(device, this);
  275. }
  276. onCloseStream();
  277. }
  278. json_t *IO::toJson() {
  279. json_t *rootJ = json_object();
  280. json_object_set_new(rootJ, "driver", json_integer(driver));
  281. std::string deviceName = getDeviceName(device);
  282. if (!deviceName.empty())
  283. json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
  284. json_object_set_new(rootJ, "offset", json_integer(offset));
  285. json_object_set_new(rootJ, "maxChannels", json_integer(maxChannels));
  286. json_object_set_new(rootJ, "sampleRate", json_integer(sampleRate));
  287. json_object_set_new(rootJ, "blockSize", json_integer(blockSize));
  288. return rootJ;
  289. }
  290. void IO::fromJson(json_t *rootJ) {
  291. closeStream();
  292. json_t *driverJ = json_object_get(rootJ, "driver");
  293. if (driverJ)
  294. setDriver(json_number_value(driverJ));
  295. json_t *deviceNameJ = json_object_get(rootJ, "deviceName");
  296. if (deviceNameJ) {
  297. std::string deviceName = json_string_value(deviceNameJ);
  298. // Search for device ID with equal name
  299. for (int device = 0; device < getDeviceCount(); device++) {
  300. if (getDeviceName(device) == deviceName) {
  301. this->device = device;
  302. break;
  303. }
  304. }
  305. }
  306. json_t *offsetJ = json_object_get(rootJ, "offset");
  307. if (offsetJ)
  308. offset = json_integer_value(offsetJ);
  309. json_t *maxChannelsJ = json_object_get(rootJ, "maxChannels");
  310. if (maxChannelsJ)
  311. maxChannels = json_integer_value(maxChannelsJ);
  312. json_t *sampleRateJ = json_object_get(rootJ, "sampleRate");
  313. if (sampleRateJ)
  314. sampleRate = json_integer_value(sampleRateJ);
  315. json_t *blockSizeJ = json_object_get(rootJ, "blockSize");
  316. if (blockSizeJ)
  317. blockSize = json_integer_value(blockSizeJ);
  318. openStream();
  319. }
  320. } // namespace audio
  321. } // namespace rack