Skip to content

Instantly share code, notes, and snippets.

@bit-hack
Created July 27, 2017 00:14
Show Gist options
  • Save bit-hack/5a51cf731c50d95723f86f2aa61ab022 to your computer and use it in GitHub Desktop.
Save bit-hack/5a51cf731c50d95723f86f2aa61ab022 to your computer and use it in GitHub Desktop.
polling winmm playback
#include <array>
#include <cassert>
#include <cmath>
#include <cstdint>
#include <Windows.h>
#define WAVE_RATE 44100
#define WAVE_SAMPLES 1024
#define WAVE_CHANNELS 2
#define WAVE_DEPTH 16
#define MMOK(EXP) ((EXP) == MMSYSERR_NOERROR)
struct WaveData {
std::array<WAVEHDR, 4> wavehdr;
};
float rate = ((2.f * 3.14f) / float(WAVE_RATE)) * 1000.f;
float wval = 0.f;
void fillBuffer(WAVEHDR* wavehdr, void* user)
{
int16_t* ptr = (int16_t*)wavehdr->lpData;
const int16_t* end = (int16_t*)((uint8_t*)ptr + wavehdr->dwBufferLength);
for (; ptr < end; ptr += 2) {
const int16_t v = int16_t(sinf(wval) * float(0x1fff));
ptr[0] = v;
ptr[1] = v;
wval += rate;
}
}
bool prepareWaveData(WaveData& data, HWAVEOUT& waveout)
{
const size_t numSamples = WAVE_SAMPLES * WAVE_CHANNELS;
const size_t numBytes = numSamples * WAVE_DEPTH / 8;
for (WAVEHDR& hdr : data.wavehdr) {
// allocate the wave header object
memset(&hdr, 0, sizeof(hdr));
hdr.lpData = (LPSTR) new int16_t[numBytes];
hdr.dwBufferLength = numBytes;
memset(hdr.lpData, 0, numBytes);
// prepare the header for the device
if (!MMOK(waveOutPrepareHeader(waveout, &hdr, sizeof(hdr)))) {
return false;
}
// write the buffer to the device
if (!MMOK(waveOutWrite(waveout, &hdr, sizeof(hdr)))) {
return false;
}
}
return true;
}
bool pollBuffers(WaveData& data, HWAVEOUT& waveout)
{
for (WAVEHDR& hdr : data.wavehdr) {
// if this buffer is used
if ((hdr.dwFlags & WHDR_DONE) == 0) {
continue;
}
if (!MMOK(waveOutUnprepareHeader(waveout, &hdr, sizeof(hdr)))) {
return false;
}
// fill with new data
fillBuffer(&hdr, 0);
if (!MMOK(waveOutPrepareHeader(waveout, &hdr, sizeof(hdr)))) {
return false;
}
if (!MMOK(waveOutWrite(waveout, &hdr, sizeof(WAVEHDR)))) {
return false;
}
}
return true;
}
int main()
{
// prepare output wave format
WAVEFORMATEX waveformat;
memset(&waveformat, 0, sizeof(waveformat));
waveformat.cbSize = 0;
waveformat.wFormatTag = WAVE_FORMAT_PCM;
waveformat.nChannels = WAVE_CHANNELS;
waveformat.nSamplesPerSec = WAVE_RATE;
waveformat.wBitsPerSample = WAVE_DEPTH;
waveformat.nBlockAlign = (WAVE_CHANNELS * waveformat.wBitsPerSample) / 8;
waveformat.nAvgBytesPerSec = WAVE_RATE * waveformat.nBlockAlign;
// create wave output
HWAVEOUT waveout;
memset(&waveout, 0, sizeof(waveout));
if (!MMOK(waveOutOpen(
&waveout,
WAVE_MAPPER,
&waveformat,
NULL,
NULL,
CALLBACK_NULL))) {
return 1;
}
// prepare waveout data
WaveData wavedata;
if (!prepareWaveData(wavedata, waveout)) {
return 1;
}
// buffer poll and refill loop
for (;;) {
if (!pollBuffers(wavedata, waveout)) {
break;
}
Sleep(10);
}
// teardown
waveOutClose(waveout);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment