Skip to content

Instantly share code, notes, and snippets.

@d7samurai
Last active March 2, 2024 23:44
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save d7samurai/6d24d0ba93f8c8fe6b4f02b92d4c8ce0 to your computer and use it in GitHub Desktop.
Save d7samurai/6d24d0ba93f8c8fe6b4f02b92d4c8ce0 to your computer and use it in GitHub Desktop.
Minimal WASAPI

Minimal WASAPI

Minimal WASAPI reference implementation. Runnable console application contained in a single function and laid out in a linear, step-by-step fashion. No modern C++ / OOP / obscuring cruft. Produces a steady sine wave sound.

(This is a re-post of the same gist I posted a few years earlier, simply due to me wanting the Minimal D3D11 series to be listed contiguously and it's not possible to hide or rearrange gists).

#pragma comment(lib, "ole32")
///////////////////////////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <math.h> // for sine
///////////////////////////////////////////////////////////////////////////////////////////////////
int main()
{
CoInitializeEx(nullptr, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
///////////////////////////////////////////////////////////////////////////////////////////////
IMMDeviceEnumerator* deviceEnumerator;
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), reinterpret_cast<void**>(&deviceEnumerator));
///////////////////////////////////////////////////////////////////////////////////////////////
IMMDevice* audioDevice;
deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &audioDevice);
///////////////////////////////////////////////////////////////////////////////////////////////
IAudioClient3* audioClient;
audioDevice->Activate(__uuidof(IAudioClient3), CLSCTX_INPROC_SERVER, nullptr, reinterpret_cast<void**>(&audioClient));
///////////////////////////////////////////////////////////////////////////////////////////////
REFERENCE_TIME defaultPeriod;
REFERENCE_TIME minimumPeriod;
audioClient->GetDevicePeriod(&defaultPeriod, &minimumPeriod);
WAVEFORMATEX* mixFormat;
audioClient->GetMixFormat(&mixFormat);
audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, minimumPeriod, 0, mixFormat, nullptr);
IAudioRenderClient* audioRenderClient;
audioClient->GetService(__uuidof(IAudioRenderClient), reinterpret_cast<void**>(&audioRenderClient));
UINT32 bufferSize;
audioClient->GetBufferSize(&bufferSize);
HANDLE bufferReady = CreateEventA(nullptr, FALSE, FALSE, nullptr);
audioClient->SetEventHandle(bufferReady);
///////////////////////////////////////////////////////////////////////////////////////////////
double time = 0.0;
audioClient->Start();
while (WaitForSingleObject(bufferReady, INFINITE) == WAIT_OBJECT_0)
{
UINT32 bufferPadding;
audioClient->GetCurrentPadding(&bufferPadding);
UINT32 frameCount = bufferSize - bufferPadding;
float* buffer;
audioRenderClient->GetBuffer(frameCount, reinterpret_cast<BYTE**>(&buffer));
for (UINT32 frameIndex = 0; frameIndex < frameCount; frameIndex++)
{
float amplitude = static_cast<float>(sin(time));
*buffer++ = amplitude; // left
*buffer++ = amplitude; // right
time += 0.05;
}
audioRenderClient->ReleaseBuffer(frameCount, 0);
}
audioClient->Stop();
///////////////////////////////////////////////////////////////////////////////////////////////
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment