waveout.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #include <mmsystem.h>
  2. auto CALLBACK waveOutCallback(HWAVEOUT handle, UINT message, DWORD_PTR userData, DWORD_PTR, DWORD_PTR) -> void;
  3. struct AudioWaveOut : AudioDriver {
  4. AudioWaveOut& self = *this;
  5. AudioWaveOut(Audio& super) : AudioDriver(super) {}
  6. ~AudioWaveOut() { terminate(); }
  7. auto create() -> bool override {
  8. super.setChannels(2);
  9. super.setFrequency(44100);
  10. super.setLatency(512);
  11. return initialize();
  12. }
  13. auto driver() -> string override { return "waveOut"; }
  14. auto ready() -> bool override { return true; }
  15. auto hasDevices() -> vector<string> override {
  16. vector<string> devices{"Default"};
  17. for(uint index : range(waveOutGetNumDevs())) {
  18. WAVEOUTCAPS caps{};
  19. if(waveOutGetDevCaps(index, &caps, sizeof(WAVEOUTCAPS)) == MMSYSERR_NOERROR) {
  20. devices.append((const char*)utf8_t(caps.szPname));
  21. }
  22. }
  23. return devices;
  24. }
  25. auto hasBlocking() -> bool override { return true; }
  26. auto hasDynamic() -> bool override { return true; }
  27. auto hasFrequencies() -> vector<uint> override { return {44100}; }
  28. auto hasLatencies() -> vector<uint> override { return {512, 384, 320, 256, 192, 160, 128, 96, 80, 64, 48, 40, 32}; }
  29. auto setBlocking(bool blocking) -> bool override { return true; }
  30. auto setDynamic(bool dynamic) -> bool override { return initialize(); }
  31. auto setLatency(uint latency) -> bool override { return initialize(); }
  32. auto clear() -> void override {
  33. for(auto& header : headers) {
  34. memory::fill(header.lpData, frameCount * 4);
  35. }
  36. }
  37. auto level() -> double override {
  38. return (double)((blockQueue * frameCount) + frameIndex) / (blockCount * frameCount);
  39. }
  40. auto output(const double samples[]) -> void override {
  41. uint16_t lsample = sclamp<16>(samples[0] * 32767.0);
  42. uint16_t rsample = sclamp<16>(samples[1] * 32767.0);
  43. auto block = (uint32_t*)headers[blockIndex].lpData;
  44. block[frameIndex] = lsample << 0 | rsample << 16;
  45. if(++frameIndex >= frameCount) {
  46. frameIndex = 0;
  47. if(self.dynamic) {
  48. while(waveOutWrite(handle, &headers[blockIndex], sizeof(WAVEHDR)) == WAVERR_STILLPLAYING);
  49. InterlockedIncrement(&blockQueue);
  50. } else while(true) {
  51. auto result = waveOutWrite(handle, &headers[blockIndex], sizeof(WAVEHDR));
  52. if(!self.blocking || result != WAVERR_STILLPLAYING) break;
  53. InterlockedIncrement(&blockQueue);
  54. }
  55. if(++blockIndex >= blockCount) {
  56. blockIndex = 0;
  57. }
  58. }
  59. }
  60. private:
  61. auto initialize() -> bool {
  62. terminate();
  63. auto deviceIndex = hasDevices().find(self.device);
  64. if(!deviceIndex) deviceIndex = 0;
  65. WAVEFORMATEX format{};
  66. format.wFormatTag = WAVE_FORMAT_PCM;
  67. format.nChannels = 2;
  68. format.nSamplesPerSec = 44100;
  69. format.nBlockAlign = 4;
  70. format.wBitsPerSample = 16;
  71. format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
  72. format.cbSize = 0; //not sizeof(WAVEFORMAT); size of extra information after WAVEFORMATEX
  73. //-1 = default; 0+ = specific device; subtract -1 as hasDevices() includes "Default" entry
  74. waveOutOpen(&handle, (int)*deviceIndex - 1, &format, (DWORD_PTR)waveOutCallback, (DWORD_PTR)this, CALLBACK_FUNCTION);
  75. frameCount = self.latency;
  76. blockCount = 32;
  77. frameIndex = 0;
  78. blockIndex = 0;
  79. blockQueue = 0;
  80. headers.resize(blockCount);
  81. for(auto& header : headers) {
  82. memory::fill(&header, sizeof(WAVEHDR));
  83. header.lpData = (LPSTR)LocalAlloc(LMEM_FIXED, frameCount * 4);
  84. header.dwBufferLength = frameCount * 4;
  85. waveOutPrepareHeader(handle, &header, sizeof(WAVEHDR));
  86. }
  87. waveOutSetVolume(handle, 0xffff'ffff); //100% volume (65535 left, 65535 right)
  88. waveOutRestart(handle);
  89. return true;
  90. }
  91. auto terminate() -> void {
  92. if(!handle) return;
  93. waveOutPause(handle);
  94. waveOutReset(handle);
  95. for(auto& header : headers) {
  96. waveOutUnprepareHeader(handle, &header, sizeof(WAVEHDR));
  97. LocalFree(header.lpData);
  98. }
  99. waveOutClose(handle);
  100. handle = nullptr;
  101. headers.reset();
  102. }
  103. HWAVEOUT handle = nullptr;
  104. vector<WAVEHDR> headers;
  105. uint frameCount = 0;
  106. uint blockCount = 0;
  107. uint frameIndex = 0;
  108. uint blockIndex = 0;
  109. public:
  110. LONG blockQueue = 0;
  111. };
  112. auto CALLBACK waveOutCallback(HWAVEOUT handle, UINT message, DWORD_PTR userData, DWORD_PTR, DWORD_PTR) -> void {
  113. auto instance = (AudioWaveOut*)userData;
  114. if(instance->blockQueue > 0) InterlockedDecrement(&instance->blockQueue);
  115. }