Last active
May 11, 2024 13:16
-
-
Save kevinmoran/2e673695058c7bc32fb5172848900db5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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