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 が処理される度に、一瞬だけ音が途切れることを確認できます
音を途切らせずにループさせる方法としては
複数のバッファを送出する、いわゆるダブルバッファリングを行う方法が考えられます