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.

381 lines
9.2KB

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