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.

382 lines
9.4KB

  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. Port::Port() {
  9. setDriverId(RtAudio::UNSPECIFIED);
  10. }
  11. Port::~Port() {
  12. closeStream();
  13. }
  14. std::vector<int> Port::getDriverIds() {
  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 Port::getDriverName(int driverId) {
  26. switch (driverId) {
  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 Port::setDriverId(int driverId) {
  42. // Close device
  43. setDeviceId(-1, 0);
  44. // Close driver
  45. if (rtAudio) {
  46. delete rtAudio;
  47. rtAudio = NULL;
  48. }
  49. this->driverId = 0;
  50. // Open driver
  51. if (driverId >= 0) {
  52. rtAudio = new RtAudio((RtAudio::Api) driverId);
  53. this->driverId = (int) rtAudio->getCurrentApi();
  54. }
  55. else if (driverId == BRIDGE_DRIVER) {
  56. this->driverId = BRIDGE_DRIVER;
  57. }
  58. }
  59. int Port::getDeviceCount() {
  60. if (rtAudio) {
  61. return rtAudio->getDeviceCount();
  62. }
  63. else if (driverId == BRIDGE_DRIVER) {
  64. return BRIDGE_NUM_PORTS;
  65. }
  66. return 0;
  67. }
  68. bool Port::getDeviceInfo(int deviceId, RtAudio::DeviceInfo* deviceInfo) {
  69. if (!deviceInfo)
  70. return false;
  71. if (rtAudio) {
  72. if (deviceId == this->deviceId) {
  73. *deviceInfo = this->deviceInfo;
  74. return true;
  75. }
  76. else {
  77. try {
  78. *deviceInfo = rtAudio->getDeviceInfo(deviceId);
  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 Port::getDeviceChannels(int deviceId) {
  89. if (deviceId < 0)
  90. return 0;
  91. if (rtAudio) {
  92. RtAudio::DeviceInfo deviceInfo;
  93. if (getDeviceInfo(deviceId, &deviceInfo))
  94. return std::max((int) deviceInfo.inputChannels, (int) deviceInfo.outputChannels);
  95. }
  96. else if (driverId == BRIDGE_DRIVER) {
  97. return std::max(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
  98. }
  99. return 0;
  100. }
  101. std::string Port::getDeviceName(int deviceId) {
  102. if (deviceId < 0)
  103. return "";
  104. if (rtAudio) {
  105. RtAudio::DeviceInfo deviceInfo;
  106. if (getDeviceInfo(deviceId, &deviceInfo))
  107. return deviceInfo.name;
  108. }
  109. else if (driverId == BRIDGE_DRIVER) {
  110. return string::f("%d", deviceId + 1);
  111. }
  112. return "";
  113. }
  114. std::string Port::getDeviceDetail(int deviceId, int offset) {
  115. if (deviceId < 0)
  116. return "";
  117. if (rtAudio) {
  118. RtAudio::DeviceInfo deviceInfo;
  119. if (getDeviceInfo(deviceId, &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 (driverId == BRIDGE_DRIVER) {
  132. return string::f("Port %d", deviceId + 1);
  133. }
  134. return "";
  135. }
  136. void Port::setDeviceId(int deviceId, int offset) {
  137. closeStream();
  138. this->deviceId = deviceId;
  139. this->offset = offset;
  140. openStream();
  141. }
  142. std::vector<int> Port::getSampleRates() {
  143. if (rtAudio) {
  144. try {
  145. RtAudio::DeviceInfo deviceInfo = rtAudio->getDeviceInfo(deviceId);
  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 Port::setSampleRate(int sampleRate) {
  156. if (sampleRate == this->sampleRate)
  157. return;
  158. closeStream();
  159. this->sampleRate = sampleRate;
  160. openStream();
  161. }
  162. std::vector<int> Port::getBlockSizes() {
  163. if (rtAudio) {
  164. return {64, 128, 256, 512, 1024, 2048, 4096};
  165. }
  166. return {};
  167. }
  168. void Port::setBlockSize(int blockSize) {
  169. if (blockSize == this->blockSize)
  170. return;
  171. closeStream();
  172. this->blockSize = blockSize;
  173. openStream();
  174. }
  175. void Port::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. Port* port = (Port*) userData;
  182. assert(port);
  183. // Exploit the stream time to run code on startup of the audio thread
  184. if (streamTime == 0.0) {
  185. system::setThreadName("Audio");
  186. // system::setThreadRealTime();
  187. }
  188. port->processStream((const float*) inputBuffer, (float*) outputBuffer, nFrames);
  189. return 0;
  190. }
  191. void Port::openStream() {
  192. if (deviceId < 0)
  193. return;
  194. if (rtAudio) {
  195. // Open new device
  196. try {
  197. deviceInfo = rtAudio->getDeviceInfo(deviceId);
  198. }
  199. catch (RtAudioError& e) {
  200. WARN("Failed to query RtAudio device: %s", e.what());
  201. return;
  202. }
  203. if (rtAudio->isStreamOpen())
  204. return;
  205. setChannels(math::clamp((int) deviceInfo.outputChannels - offset, 0, maxChannels), math::clamp((int) deviceInfo.inputChannels - offset, 0, maxChannels));
  206. if (numOutputs == 0 && numInputs == 0) {
  207. WARN("RtAudio device %d has 0 inputs and 0 outputs", deviceId);
  208. return;
  209. }
  210. RtAudio::StreamParameters outParameters;
  211. outParameters.deviceId = deviceId;
  212. outParameters.nChannels = numOutputs;
  213. outParameters.firstChannel = offset;
  214. RtAudio::StreamParameters inParameters;
  215. inParameters.deviceId = deviceId;
  216. inParameters.nChannels = numInputs;
  217. inParameters.firstChannel = offset;
  218. RtAudio::StreamOptions options;
  219. options.flags |= RTAUDIO_JACK_DONT_CONNECT;
  220. options.streamName = "VCV Rack";
  221. int closestSampleRate = deviceInfo.preferredSampleRate;
  222. for (int sr : deviceInfo.sampleRates) {
  223. if (std::abs(sr - sampleRate) < std::abs(closestSampleRate - sampleRate)) {
  224. closestSampleRate = sr;
  225. }
  226. }
  227. try {
  228. INFO("Opening audio RtAudio device %d with %d in %d out", deviceId, numInputs, numOutputs);
  229. rtAudio->openStream(
  230. numOutputs == 0 ? NULL : &outParameters,
  231. numInputs == 0 ? NULL : &inParameters,
  232. RTAUDIO_FLOAT32, closestSampleRate, (unsigned int*) &blockSize,
  233. &rtCallback, this, &options, NULL);
  234. }
  235. catch (RtAudioError& e) {
  236. WARN("Failed to open RtAudio stream: %s", e.what());
  237. return;
  238. }
  239. try {
  240. INFO("Starting RtAudio stream %d", deviceId);
  241. rtAudio->startStream();
  242. }
  243. catch (RtAudioError& e) {
  244. WARN("Failed to start RtAudio stream: %s", e.what());
  245. return;
  246. }
  247. // Update sample rate because this may have changed
  248. this->sampleRate = rtAudio->getStreamSampleRate();
  249. onOpenStream();
  250. }
  251. else if (driverId == BRIDGE_DRIVER) {
  252. setChannels(BRIDGE_OUTPUTS, BRIDGE_INPUTS);
  253. bridgeAudioSubscribe(deviceId, this);
  254. }
  255. }
  256. void Port::closeStream() {
  257. setChannels(0, 0);
  258. if (rtAudio) {
  259. if (rtAudio->isStreamRunning()) {
  260. INFO("Stopping RtAudio stream %d", deviceId);
  261. try {
  262. rtAudio->stopStream();
  263. }
  264. catch (RtAudioError& e) {
  265. WARN("Failed to stop RtAudio stream %s", e.what());
  266. }
  267. }
  268. if (rtAudio->isStreamOpen()) {
  269. INFO("Closing RtAudio stream %d", deviceId);
  270. try {
  271. rtAudio->closeStream();
  272. }
  273. catch (RtAudioError& e) {
  274. WARN("Failed to close RtAudio stream %s", e.what());
  275. }
  276. }
  277. deviceInfo = RtAudio::DeviceInfo();
  278. }
  279. else if (driverId == BRIDGE_DRIVER) {
  280. bridgeAudioUnsubscribe(deviceId, this);
  281. }
  282. onCloseStream();
  283. }
  284. json_t* Port::toJson() {
  285. json_t* rootJ = json_object();
  286. json_object_set_new(rootJ, "driver", json_integer(driverId));
  287. std::string deviceName = getDeviceName(deviceId);
  288. if (!deviceName.empty())
  289. json_object_set_new(rootJ, "deviceName", json_string(deviceName.c_str()));
  290. json_object_set_new(rootJ, "offset", json_integer(offset));
  291. json_object_set_new(rootJ, "maxChannels", json_integer(maxChannels));
  292. json_object_set_new(rootJ, "sampleRate", json_integer(sampleRate));
  293. json_object_set_new(rootJ, "blockSize", json_integer(blockSize));
  294. return rootJ;
  295. }
  296. void Port::fromJson(json_t* rootJ) {
  297. closeStream();
  298. json_t* driverJ = json_object_get(rootJ, "driver");
  299. if (driverJ)
  300. setDriverId(json_number_value(driverJ));
  301. json_t* deviceNameJ = json_object_get(rootJ, "deviceName");
  302. if (deviceNameJ) {
  303. std::string deviceName = json_string_value(deviceNameJ);
  304. // Search for device ID with equal name
  305. for (int deviceId = 0; deviceId < getDeviceCount(); deviceId++) {
  306. if (getDeviceName(deviceId) == deviceName) {
  307. this->deviceId = deviceId;
  308. break;
  309. }
  310. }
  311. }
  312. json_t* offsetJ = json_object_get(rootJ, "offset");
  313. if (offsetJ)
  314. offset = json_integer_value(offsetJ);
  315. json_t* maxChannelsJ = json_object_get(rootJ, "maxChannels");
  316. if (maxChannelsJ)
  317. maxChannels = json_integer_value(maxChannelsJ);
  318. json_t* sampleRateJ = json_object_get(rootJ, "sampleRate");
  319. if (sampleRateJ)
  320. sampleRate = json_integer_value(sampleRateJ);
  321. json_t* blockSizeJ = json_object_get(rootJ, "blockSize");
  322. if (blockSizeJ)
  323. blockSize = json_integer_value(blockSizeJ);
  324. openStream();
  325. }
  326. } // namespace audio
  327. } // namespace rack