Skip to content

Instantly share code, notes, and snippets.

@kbjorklu
Created August 23, 2013 09:27
Show Gist options
  • Save kbjorklu/6317308 to your computer and use it in GitHub Desktop.
Save kbjorklu/6317308 to your computer and use it in GitHub Desktop.
Sample code for the waveOutWrite function.
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")
int main()
{
HWAVEOUT hWaveOut = 0;
WAVEFORMATEX wfx = { WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8, 0 };
waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);
char buffer[8000 * 60] = {};
// See http://goo.gl/hQdTi
for (DWORD t = 0; t < sizeof(buffer); ++t)
buffer[t] = static_cast<char>((((t * (t >> 8 | t >> 9) & 46 & t >> 8)) ^ (t & t >> 13 | t >> 6)) & 0xFF);
WAVEHDR header = { buffer, sizeof(buffer), 0, 0, 0, 0, 0, 0 };
waveOutPrepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
waveOutWrite(hWaveOut, &header, sizeof(WAVEHDR));
waveOutUnprepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
waveOutClose(hWaveOut);
Sleep(60 * 1000);
}
@martinpiper
Copy link

martinpiper commented May 4, 2023

This is an example that uses several buffers, without needing a huge buffer, and loops around them whilst dynamically calculating the samples:

#include <stdio.h>
#include <windows.h>
#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")

int main()
{
	HWAVEOUT hWaveOut = 0;
	WAVEFORMATEX wfx = { WAVE_FORMAT_PCM, 1, 8000, 8000, 1, 8, 0 };
	waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL);

	// Make this size at least a good fraction of the sample rate.
	const DWORD chunkSize = 500;
	// It is good to have at least two buffers. One buffer causes crackles in the sound output.
	const DWORD numHeaders = 2;
	WAVEHDR headers[numHeaders];
	char bufferData[numHeaders][chunkSize];
	// Setup all buffers to be "done" so they are filled the first time around
	for (int i = 0 ; i < numHeaders ; i++)
	{
		headers[i].dwFlags = WHDR_DONE;
	}
	DWORD blockIndex = 0;
	// This demonstrates sending data as chunks into the output headers
	// Note no callback is needed because we test the dwFlags for WHDR_DONE
	DWORD t = 0;
	while (true)
	{
		WAVEHDR *header = headers+blockIndex;
		// Fill any buffers that are "done"
		if (header->dwFlags & WHDR_DONE)
		{
			printf("Setup for position = %d\n" , t);
			header->dwFlags = 0;
			header->lpData = bufferData[blockIndex];
			// Calculate a new chunk of data
			for (int i = 0 ; i < chunkSize ; i++)
			{
				// See http://goo.gl/hQdTi
				bufferData[blockIndex][i] = static_cast<char>((((t * (t >> 8 | t >> 9) & 46 & t >> 8)) ^ (t & t >> 13 | t >> 6)) & 0xFF);
				t++;
			}
			header->dwBufferLength = chunkSize;
			waveOutPrepareHeader(hWaveOut, header, sizeof(WAVEHDR));
			waveOutWrite(hWaveOut, header, sizeof(WAVEHDR));
			waveOutUnprepareHeader(hWaveOut, header, sizeof(WAVEHDR));
		}

		// Test the next buffer
		blockIndex++;
		if (blockIndex == numHeaders)
		{
			// If we have tested all buffers, then sleep for a very short while to avoid blocking the whole thread
			blockIndex = 0;
			Sleep(10);
		}
	}
	waveOutClose(hWaveOut);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment