Waveメッセージ


ウェーブイベントを処理する

waveOutOpen() 関数で、dwCallback 引数にコールバック先を指定し
フラグで適切な値を指定すれば、イベントごとにメッセージが送られてきます

これを処理すれば、デバイスが開かれた時、閉じられた時など
ウェーブの再生処理などに関連したメッセージを受けることができます

デバイスを開くと、MM_WOM_OPEN メッセージが、
デバイスを閉じれば MM_WOM_CLOSE メッセージが発生します
これらのメッセージには、WPARAM に出力デバイスのハンドルが格納されています
LPARAM は常に0、戻り値は定義されていません

これらのメッセージを処理することで、初期化処理と解放処理のタイミングを決定できます
デバイスに送信したバッファが返されたとき、MM_WOM_DONE が送信されます
WPARAM には再生した出力デバイスのハンドルが
LPARAM には、出力バッファを表す WAVEHDR 構造体へのポインタが格納されています
戻り値は定義されていません

例えば、MM_WOM_DONE が発生した時、再びデバイスにバッファを送出すれば
特定のバッファを無限ループさせる、といった処理ができるようになります
#include <windows.h>
#define TITLE 	TEXT("Kitty on your lap")
#define SRATE 	11025

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	DWORD dwCount , dwWave = 0;
	WAVEFORMATEX wfe;
	static HWAVEOUT hWave;
	static BYTE *bWave;
	static WAVEHDR whdr;

	switch (msg) {
	case WM_DESTROY:
		waveOutClose(hWave);
		PostQuitMessage(0);
		return 0;
	case WM_CREATE:
		bWave = malloc(SRATE);
		for (dwCount = 0 ; dwCount < SRATE ; dwCount++ , dwWave += 10) {
			if (dwWave == 256) dwWave = 0;
			*(bWave + dwCount) = dwWave;
		}			
		wfe.wFormatTag = WAVE_FORMAT_PCM;
		wfe.nChannels = 1;
		wfe.nSamplesPerSec = SRATE;
		wfe.nAvgBytesPerSec = SRATE;
		wfe.wBitsPerSample = 8;
		wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample / 8;

		waveOutOpen(&hWave , WAVE_MAPPER , &wfe ,
			(DWORD)hWnd , 0 , CALLBACK_WINDOW);

		whdr.lpData = bWave;
		whdr.dwBufferLength = SRATE;
		whdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
		whdr.dwLoops = 1;
		waveOutPrepareHeader(hWave , &whdr , sizeof(WAVEHDR));
		return 0;
	case MM_WOM_OPEN:
	case MM_WOM_DONE:
		waveOutWrite((HWAVEOUT)wp , &whdr , sizeof(WAVEHDR));
		return 0;
	case MM_WOM_CLOSE:
		waveOutUnprepareHeader((HWAVEOUT)wp , &whdr , sizeof(WAVEHDR));
		free(bWave);
		return 0;
	}
	return DefWindowProc(hWnd , msg , wp , lp);
}

int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
			PSTR lpCmdLine , int nCmdShow) {
	HWND hWnd;
	MSG msg;
	WNDCLASS winc;

	winc.style 		= CS_HREDRAW | CS_VREDRAW;
	winc.lpfnWndProc	= WndProc;
	winc.cbClsExtra		= winc.cbWndExtra = 0;
	winc.hInstance		= hInstance;
	winc.hIcon		= LoadIcon(NULL , IDI_APPLICATION);
	winc.hCursor		= LoadCursor(NULL , IDC_ARROW);
	winc.hbrBackground	= (HBRUSH)GetStockObject(WHITE_BRUSH);
	winc.lpszMenuName	= NULL;
	winc.lpszClassName	= TEXT("KITTY");

	if (!RegisterClass(&winc)) return 1;

	hWnd = CreateWindow(
		TEXT("KITTY") , TITLE ,
		WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
		CW_USEDEFAULT , CW_USEDEFAULT ,
		CW_USEDEFAULT , CW_USEDEFAULT ,
		NULL , NULL , hInstance , NULL
	);

	if (hWnd == NULL) return 1;

	while (GetMessage(&msg , NULL , 0 , 0 )) {
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}
このプログラムは、バッファが返されるたびにデバイスに再送出を行います
そのため、アプリケーション起動中は永遠にノコギリ波が鳴り続けます
MM_WOM_DONE が処理される度に、一瞬だけ音が途切れることを確認できます

音を途切らせずにループさせる方法としては
複数のバッファを送出する、いわゆるダブルバッファリングを行う方法が考えられます



前のページへ戻る次のページへ