Skip to content

Instantly share code, notes, and snippets.

@kevinmoran
Last active May 11, 2024 13:16
Show Gist options
  • Save kevinmoran/2e673695058c7bc32fb5172848900db5 to your computer and use it in GitHub Desktop.
Save kevinmoran/2e673695058c7bc32fb5172848900db5 to your computer and use it in GitHub Desktop.
#include <windows.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <assert.h>
#define _USE_MATH_DEFINES
#include <math.h> // for sin()
#include <stdint.h>
int main()
{
HRESULT hr = CoInitializeEx(nullptr, COINIT_SPEED_OVER_MEMORY);
assert(hr == S_OK);
IMMDeviceEnumerator* deviceEnumerator;
hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (LPVOID*)(&deviceEnumerator));
assert(hr == S_OK);
IMMDevice* audioDevice;
hr = deviceEnumerator->GetDefaultAudioEndpoint(eRender, eConsole, &audioDevice);
assert(hr == S_OK);
deviceEnumerator->Release();
IAudioClient2* audioClient;
hr = audioDevice->Activate(__uuidof(IAudioClient2), CLSCTX_ALL, nullptr, (LPVOID*)(&audioClient));
assert(hr == S_OK);
audioDevice->Release();
// WAVEFORMATEX* defaultMixFormat = NULL;
// hr = audioClient->GetMixFormat(&defaultMixFormat);
// assert(hr == S_OK);
WAVEFORMATEX mixFormat = {};
mixFormat.wFormatTag = WAVE_FORMAT_PCM;
mixFormat.nChannels = 2;
mixFormat.nSamplesPerSec = 44100;//defaultMixFormat->nSamplesPerSec;
mixFormat.wBitsPerSample = 16;
mixFormat.nBlockAlign = (mixFormat.nChannels * mixFormat.wBitsPerSample) / 8;
mixFormat.nAvgBytesPerSec = mixFormat.nSamplesPerSec * mixFormat.nBlockAlign;
const int64_t REFTIMES_PER_SEC = 10000000; // hundred nanoseconds
REFERENCE_TIME requestedSoundBufferDuration = REFTIMES_PER_SEC * 2;
DWORD initStreamFlags = ( AUDCLNT_STREAMFLAGS_RATEADJUST
| AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM
| AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY );
hr = audioClient->Initialize(AUDCLNT_SHAREMODE_SHARED,
initStreamFlags,
requestedSoundBufferDuration,
0, &mixFormat, nullptr);
assert(hr == S_OK);
IAudioRenderClient* audioRenderClient;
hr = audioClient->GetService(__uuidof(IAudioRenderClient), (LPVOID*)(&audioRenderClient));
assert(hr == S_OK);
UINT32 bufferSize;
hr = audioClient->GetBufferSize(&bufferSize);
assert(hr == S_OK);
hr = audioClient->Start();
assert(hr == S_OK);
double playbackTime = 0.0;
const float TONE_HZ = 440;
const int16_t TONE_VOLUME = 3000;
while (true)
{
UINT32 bufferPadding;
hr = audioClient->GetCurrentPadding(&bufferPadding);
assert(hr == S_OK);
UINT32 frameCount = bufferSize - bufferPadding;
int16_t* buffer;
hr = audioRenderClient->GetBuffer(frameCount, (BYTE**)(&buffer));
assert(hr == S_OK);
for(UINT32 frameIndex = 0; frameIndex < frameCount; frameIndex++)
{
float amplitude = (float)sin(playbackTime*2*M_PI*TONE_HZ);
int16_t y = (int16_t)(TONE_VOLUME * amplitude);
*buffer++ = y; // left
*buffer++ = y; // right
playbackTime += 1.f / mixFormat.nSamplesPerSec;
}
hr = audioRenderClient->ReleaseBuffer(frameCount, 0);
assert(hr == S_OK);
// Get playback cursor position
IAudioClock* audioClock;
audioClient->GetService(__uuidof(IAudioClock), (LPVOID*)(&audioClock));
UINT64 audioPlaybackFreq;
UINT64 audioPlaybackPos;
audioClock->GetFrequency(&audioPlaybackFreq);
audioClock->GetPosition(&audioPlaybackPos, 0);
audioClock->Release();
UINT64 audioPlaybackPosInSeconds = audioPlaybackPos/audioPlaybackFreq;
UINT64 audioPlaybackPosInSamples = audioPlaybackPosInSeconds*mixFormat.nSamplesPerSec;
}
audioClient->Stop();
audioClient->Release();
audioRenderClient->Release();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment