asio.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. #include <nall/windows/registry.hpp>
  2. #include "asio.hpp"
  3. struct AudioASIO : AudioDriver {
  4. static AudioASIO* instance;
  5. AudioASIO& self = *this;
  6. AudioASIO(Audio& super) : AudioDriver(super) { instance = this; }
  7. ~AudioASIO() { terminate(); }
  8. auto create() -> bool override {
  9. super.setDevice(hasDevices().first());
  10. super.setChannels(2);
  11. super.setFrequency(48000);
  12. super.setLatency(2048);
  13. return initialize();
  14. }
  15. auto driver() -> string override { return "ASIO"; }
  16. auto ready() -> bool override { return _ready; }
  17. auto hasContext() -> bool override { return true; }
  18. auto hasBlocking() -> bool override { return true; }
  19. auto hasDevices() -> vector<string> override {
  20. self.devices.reset();
  21. for(auto candidate : registry::contents("HKLM\\SOFTWARE\\ASIO\\")) {
  22. if(auto classID = registry::read({"HKLM\\SOFTWARE\\ASIO\\", candidate, "CLSID"})) {
  23. self.devices.append({candidate.trimRight("\\", 1L), classID});
  24. }
  25. }
  26. vector<string> devices;
  27. for(auto& device : self.devices) devices.append(device.name);
  28. return devices;
  29. }
  30. auto hasChannels() -> vector<uint> override {
  31. return {1, 2};
  32. }
  33. auto hasFrequencies() -> vector<uint> override {
  34. return {self.frequency};
  35. }
  36. auto hasLatencies() -> vector<uint> override {
  37. vector<uint> latencies;
  38. uint latencyList[] = {64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 6144}; //factors of 6144
  39. for(auto& latency : latencyList) {
  40. if(self.activeDevice) {
  41. if(latency < self.activeDevice.minimumBufferSize) continue;
  42. if(latency > self.activeDevice.maximumBufferSize) continue;
  43. }
  44. latencies.append(latency);
  45. }
  46. //it is possible that no latencies in the hard-coded list above will match; so ensure driver-declared latencies are available
  47. if(!latencies.find(self.activeDevice.minimumBufferSize)) latencies.append(self.activeDevice.minimumBufferSize);
  48. if(!latencies.find(self.activeDevice.maximumBufferSize)) latencies.append(self.activeDevice.maximumBufferSize);
  49. if(!latencies.find(self.activeDevice.preferredBufferSize)) latencies.append(self.activeDevice.preferredBufferSize);
  50. latencies.sort();
  51. return latencies;
  52. }
  53. auto setContext(uintptr context) -> bool override { return initialize(); }
  54. auto setDevice(string device) -> bool override { return initialize(); }
  55. auto setBlocking(bool blocking) -> bool override { return initialize(); }
  56. auto setChannels(uint channels) -> bool override { return initialize(); }
  57. auto setLatency(uint latency) -> bool override { return initialize(); }
  58. auto clear() -> void override {
  59. if(!ready()) return;
  60. for(uint n : range(self.channels)) {
  61. memory::fill<uint8_t>(_channel[n].buffers[0], self.latency * _sampleSize);
  62. memory::fill<uint8_t>(_channel[n].buffers[1], self.latency * _sampleSize);
  63. }
  64. memory::fill<uint8_t>(_queue.samples, sizeof(_queue.samples));
  65. _queue.read = 0;
  66. _queue.write = 0;
  67. _queue.count = 0;
  68. }
  69. auto output(const double samples[]) -> void override {
  70. if(!ready()) return;
  71. //defer call to IASIO::start(), because the drivers themselves will sometimes crash internally.
  72. //if software initializes AudioASIO but does not play music at startup, this can prevent a crash loop.
  73. if(!_started) {
  74. _started = true;
  75. if(_asio->start() != ASE_OK) {
  76. _ready = false;
  77. return;
  78. }
  79. }
  80. if(self.blocking) {
  81. while(_queue.count >= self.latency);
  82. }
  83. for(uint n : range(self.channels)) {
  84. _queue.samples[_queue.write][n] = samples[n];
  85. }
  86. _queue.write++;
  87. _queue.count++;
  88. }
  89. private:
  90. auto initialize() -> bool {
  91. terminate();
  92. hasDevices(); //this call populates self.devices
  93. if(!self.devices) return false;
  94. self.activeDevice = {};
  95. for(auto& device : self.devices) {
  96. if(self.device == device.name) {
  97. self.activeDevice = device;
  98. break;
  99. }
  100. }
  101. if(!self.activeDevice) {
  102. self.activeDevice = self.devices.first();
  103. self.device = self.activeDevice.name;
  104. }
  105. CLSID classID;
  106. if(CLSIDFromString((LPOLESTR)utf16_t(self.activeDevice.classID), (LPCLSID)&classID) != S_OK) return false;
  107. if(CoCreateInstance(classID, 0, CLSCTX_INPROC_SERVER, classID, (void**)&_asio) != S_OK) return false;
  108. if(!_asio->init((void*)self.context)) return false;
  109. if(_asio->getSampleRate(&self.activeDevice.sampleRate) != ASE_OK) return false;
  110. if(_asio->getChannels(&self.activeDevice.inputChannels, &self.activeDevice.outputChannels) != ASE_OK) return false;
  111. if(_asio->getBufferSize(
  112. &self.activeDevice.minimumBufferSize,
  113. &self.activeDevice.maximumBufferSize,
  114. &self.activeDevice.preferredBufferSize,
  115. &self.activeDevice.granularity
  116. ) != ASE_OK) return false;
  117. self.frequency = self.activeDevice.sampleRate;
  118. self.latency = self.latency < self.activeDevice.minimumBufferSize ? self.activeDevice.minimumBufferSize : self.latency;
  119. self.latency = self.latency > self.activeDevice.maximumBufferSize ? self.activeDevice.maximumBufferSize : self.latency;
  120. for(uint n : range(self.channels)) {
  121. _channel[n].isInput = false;
  122. _channel[n].channelNum = n;
  123. _channel[n].buffers[0] = nullptr;
  124. _channel[n].buffers[1] = nullptr;
  125. }
  126. ASIOCallbacks callbacks;
  127. callbacks.bufferSwitch = &AudioASIO::_bufferSwitch;
  128. callbacks.sampleRateDidChange = &AudioASIO::_sampleRateDidChange;
  129. callbacks.asioMessage = &AudioASIO::_asioMessage;
  130. callbacks.bufferSwitchTimeInfo = &AudioASIO::_bufferSwitchTimeInfo;
  131. if(_asio->createBuffers(_channel, self.channels, self.latency, &callbacks) != ASE_OK) return false;
  132. if(_asio->getLatencies(&self.activeDevice.inputLatency, &self.activeDevice.outputLatency) != ASE_OK) return false;
  133. //assume for the sake of sanity that all buffers use the same sample format ...
  134. ASIOChannelInfo channelInformation = {};
  135. channelInformation.channel = 0;
  136. channelInformation.isInput = false;
  137. if(_asio->getChannelInfo(&channelInformation) != ASE_OK) return false;
  138. switch(_sampleFormat = channelInformation.type) {
  139. case ASIOSTInt16LSB: _sampleSize = 2; break;
  140. case ASIOSTInt24LSB: _sampleSize = 3; break;
  141. case ASIOSTInt32LSB: _sampleSize = 4; break;
  142. case ASIOSTFloat32LSB: _sampleSize = 4; break;
  143. case ASIOSTFloat64LSB: _sampleSize = 8; break;
  144. default: return false; //unsupported sample format
  145. }
  146. _ready = true;
  147. _started = false;
  148. clear();
  149. return true;
  150. }
  151. auto terminate() -> void {
  152. _ready = false;
  153. _started = false;
  154. self.activeDevice = {};
  155. if(_asio) {
  156. _asio->stop();
  157. _asio->disposeBuffers();
  158. _asio->Release();
  159. _asio = nullptr;
  160. }
  161. }
  162. private:
  163. static auto _bufferSwitch(long doubleBufferInput, ASIOBool directProcess) -> void {
  164. return instance->bufferSwitch(doubleBufferInput, directProcess);
  165. }
  166. static auto _sampleRateDidChange(ASIOSampleRate sampleRate) -> void {
  167. return instance->sampleRateDidChange(sampleRate);
  168. }
  169. static auto _asioMessage(long selector, long value, void* message, double* optional) -> long {
  170. return instance->asioMessage(selector, value, message, optional);
  171. }
  172. static auto _bufferSwitchTimeInfo(ASIOTime* parameters, long doubleBufferIndex, ASIOBool directProcess) -> ASIOTime* {
  173. return instance->bufferSwitchTimeInfo(parameters, doubleBufferIndex, directProcess);
  174. }
  175. auto bufferSwitch(long doubleBufferInput, ASIOBool directProcess) -> void {
  176. for(uint sampleIndex : range(self.latency)) {
  177. double samples[8] = {0};
  178. if(_queue.count) {
  179. for(uint n : range(self.channels)) {
  180. samples[n] = _queue.samples[_queue.read][n];
  181. }
  182. _queue.read++;
  183. _queue.count--;
  184. }
  185. for(uint n : range(self.channels)) {
  186. auto buffer = (uint8_t*)_channel[n].buffers[doubleBufferInput];
  187. buffer += sampleIndex * _sampleSize;
  188. switch(_sampleFormat) {
  189. case ASIOSTInt16LSB: {
  190. *(uint16_t*)buffer = (uint16_t)sclamp<16>(samples[n] * (32768.0 - 1.0));
  191. break;
  192. }
  193. case ASIOSTInt24LSB: {
  194. auto value = (uint32_t)sclamp<24>(samples[n] * (256.0 * 32768.0 - 1.0));
  195. buffer[0] = value >> 0;
  196. buffer[1] = value >> 8;
  197. buffer[2] = value >> 16;
  198. break;
  199. }
  200. case ASIOSTInt32LSB: {
  201. *(uint32_t*)buffer = (uint32_t)sclamp<32>(samples[n] * (65536.0 * 32768.0 - 1.0));
  202. break;
  203. }
  204. case ASIOSTFloat32LSB: {
  205. *(float*)buffer = max(-1.0, min(+1.0, samples[n]));
  206. break;
  207. }
  208. case ASIOSTFloat64LSB: {
  209. *(double*)buffer = max(-1.0, min(+1.0, samples[n]));
  210. break;
  211. }
  212. }
  213. }
  214. }
  215. }
  216. auto sampleRateDidChange(ASIOSampleRate sampleRate) -> void {
  217. }
  218. auto asioMessage(long selector, long value, void* message, double* optional) -> long {
  219. return ASE_OK;
  220. }
  221. auto bufferSwitchTimeInfo(ASIOTime* parameters, long doubleBufferIndex, ASIOBool directProcess) -> ASIOTime* {
  222. return nullptr;
  223. }
  224. bool _ready = false;
  225. bool _started = false;
  226. struct Queue {
  227. double samples[65536][8];
  228. uint16_t read;
  229. uint16_t write;
  230. std::atomic<uint16_t> count;
  231. };
  232. struct Device {
  233. explicit operator bool() const { return name; }
  234. string name;
  235. string classID;
  236. ASIOSampleRate sampleRate;
  237. long inputChannels;
  238. long outputChannels;
  239. long inputLatency;
  240. long outputLatency;
  241. long minimumBufferSize;
  242. long maximumBufferSize;
  243. long preferredBufferSize;
  244. long granularity;
  245. };
  246. Queue _queue;
  247. vector<Device> devices;
  248. Device activeDevice;
  249. IASIO* _asio = nullptr;
  250. ASIOBufferInfo _channel[8];
  251. long _sampleFormat;
  252. long _sampleSize;
  253. };
  254. AudioASIO* AudioASIO::instance = nullptr;