PCM の基本


サンプリングレートと音

さて、ここからしばらくはコンピュータと音の関係について深入りしたいと思います
すでにご存知の通り、コンピュータに格納されているデータは全てが「情報」であり
音楽やグラフィックスなど、アートもひとつの「情報」として格納されています
コンピュータにおける情報とは、数学的に一意に認識できる意味のある数列です
音楽もまた、DIB のように数字の列として表現することができるのです

グラフィックスの RGB は直感的に理解しやすく
特別な数学知識などは必要なく理解し、操作することができました
しかし、音声の場合は音の高さ、大きさなどを表現するために
数学的、物理学的、音楽学的知識を要するため、それなりの基礎知識が求められます

ここで扱う音とは、Windows で最も一般的なマルチメディアと思われる、波形オーディオです
コンピュータでは、物理的な空気振動によって発生する「音」を数値で表現します
現在、最も一般的なフォーマットは PCM(Pulse Code Modulation) です
PCM は波形データを圧縮しない形式のもので、CD や Windows で使われています
MP3 等も波形オーディオですが、圧縮されているため PCM とは異なります

音声と数値でータの入出力には、それぞれ専用のハードウェアが使われます
波形を数値に変換するには、ADC(Analog-to-Digital Converter) が使われ
PCM データを音として出力するには、DAC(Digital-toAnalog Converter) が使われます

音声とDIBの違いのひとつに、音声は「時間」が関係してくるということがあります
波形の振り幅を1秒間に何回保存するかということをサンプリングレートと呼び
例えば、1秒間に1000回の割合で、音声を数値化するならば 1000 サンプルであり
サンプル数はヘルツ Hz で表すので 1000Hz、または 1kHz と表します

波形オーディオがサポートするサンプリングレートは
一般的に 8kHz、11.025kHz、22.05kHz、44.1kHz などがあります
例えば、CD は 44.1kHz を用いています。
このような、奇妙な数値のサンプリングレートは、物理的理由で決められています
人間の耳に正確に音が再生されたように聴かせるには 44.1kHz あれば十分です

音をデジタルに録音するとは、波形データの「波」を連続した数値の「点」に変換することで
これを再び音にするには、連続した「点」を繋ぎ合わせて「波」に変換します


物理的な音の「波」
論理的な音の「点」

この図のように、波形は連続した数値として保存されます
数値を音に変換する時は DAC が数値を読み取り電子波形に変換します
当然、これは録音した音声とは論理的に異なり、完全な複製ではありません

波形を表す点の数、すなわちサンプリングレートが少なければ少ないほど
元の音声の情報が減少し、人間にとって「劣化」したような音に感じられるでしょう
綺麗は波形の線を描くには、それだけ多くの点を連続的に保存しなければならないのです
これが、良質な音声を保存するメディアファイルの容量が大きい原因です

では、コンピュータは実際に、どのような数列で音を表現するのでしょうか
音の長さは、数列の数によって決定されます

例えば、11.025kHz であれば、1秒間の音声は 11025 個の数列となります
実際のバイト数は、1つの音を表すのにどの程度の情報量を使うかでことなります
Windows の場合、8 ビット、または 16 ビットのいずれかを選択することができます
もし、8 ビットであれば、1バイトは 1/11025 秒の音声の情報をあらわすことになるでしょう

次に音の高さ、すなわち音程ですが
実世界は、これを周波数、つまり物理的振動の波の数で決定されます
波の間隔が狭ければ音は高く、波の間隔が広ければ低く感じられます
救急車が近づいた時などに発生する、ドップラー効果は、音の波を実感する良い例です

数字における音の波は、数字が高くなったり低くなったりを繰り返すことで表現します
8 ビットの場合は、符号無しで 128 という値の連続が「無音」として扱われ
16 ビットであれば、符合有りで 0 の連続が「無音」として扱われます
この基本となる値よりも高くなったり低くなったりすることで、周波が表現されます

特定の周波数を発生させたい場合、1秒間に目的の周波数だけ波を発生させます
例えば、440Hz の音を発生させたければ、1秒間に 440 回だけ数値が上下します
この時の数値が上下する間隔をサイクルと呼びます

1サイクルのサンプル数を計算するには、サンプリングレートに周波数を除算します
例えば 11,025 kHz に 440 Hz の音を発生させる場合、11025÷440 を計算し
1サイクルに約 25 サンプル必要になるという事がわかります

残念ながら、波形の世界では「ミ」の音を出したいという要求はこたえられません
そもそも、「ドレミファソラシド」というのは、人間の耳に合う波形の間隔に名前をつけたもので
基音の周波数に 2 を乗算するとオクターブが上がるという性質を持っています
基音に対して完全 5 度上の音は 1.5 倍、長 3 度上は 5/4 倍というように計算します
やはり、音に対してより詳しくなりたければ、音楽学と物理学を勉強する必要がでてきますね

物理学的な音の性質の最後は音の強さ、すなわち音量です
音量は、波形データの振幅、つまり波の高さで決定されます
数値配列で表現された波の、最上部と最下部の絶対値が振幅となります

因みに、音の強さは一般的にデシベル (dB)で表されます
1dB はかすかに聞こえる程度の音量で、100 dB にもなると、苦痛に感じる音量になります
2つの音の差をダイナミックレンジと呼び、次のように計算できます

dB = 20 log (S1/S2)

S1 と S2 には、それぞれ比較する2つの音の振幅を指定します
これで計算すればわかりますが、振幅を8ビットにするか16ビットにするかという問題は
ダイナミックレンジ、つまり音量の表現力に直接影響します

さて、では実際にプログラムで作成した数列を音として出力する方法を説明します
「波」には様々な形があり、きれいな曲線を描く正弦波(sin波)や
三角形の山が連続する三角波などが考えられます
これらの波は、人工的に作った機械的な音質を作り出します
今回のサンプルでは、ループで単純に作ることができる、ノコギリ波を用います

波形オーディオの出力に関連した関数などは mmsystem.h で宣言され
winmm.lib ファイルでインポートすることができます
環境によっては winmm.lib ファイルを明示的にインポートする必要があります

波形オーディオを出力するには、出力デバイスを開く必要があります
これには、waveOutOpen() 関数を用います
MMRESULT waveOutOpen(
	LPHWAVEOUT phwo , UINT uDeviceID,            
	LPWAVEFORMATEX pwfx ,
	DWORD dwCallback , DWORD dwCallbackInstance ,
	DWORD fdwOpen
);
phwo は HWAVEOUT 型の、デバイス識別用ハンドルへのポインタを指定します
これは、ウェーブフォームオーディオ出力デバイスのハンドルで
このハンドルに、オープンした出力デバイスの識別子を格納します
以後、音声出力関数に対しては、このハンドルを用いて出力デバイスを指定します

uDeviceID には、対象の出力デバイスの識別子を指定します
この値は常に 「0 〜 インストールされている有効なデバイス数 - 1」の範囲になります
WAVE_MAPPER を指定すれば、ユーザーが選択している優先デバイスが適応されます
特別なことがない限り、通常は WAVE_MAPPAER を指定するべきです

pwfx には、WAVEFORMATEX 構造体へのポインタを指定します
この構造体には、ウェーブフォーマットやサンプリングレートなどを設定します

dwCallback は、再生中にウェーブの関連メッセージを受け取る対象を指定します
ここには、コールバック関数、ウィンドウハンドル、イベントハンドル
または、スレッドハンドルのいずれかを指定することができます

dwCallbackInstance には、コールバック関数に渡すデータを指定できます
ウィンドウハンドルによるコールバックを採用した場合、この値は使われません

fdwOpen は、デバイスを開くためのフラグを指定します
この引数には、以下の値のいずれか、または組み合わせを指定できます

定数解説
CALLBACK_EVENT dwCallback はイベントハンドルである
CALLBACK_FUNCTION dwCallback はコールバック関数のポインタである
CALLBACK_NULL コールバックは使用しない
CALLBACK_THREAD dwCallback はスレッドハンドルである
CALLBACK_WINDOW dwCallback はウィンドウハンドルである
WAVE_ALLOWSYNC このフラグが指定されていれば
同期したウェーブオーディオを開くことができる
指定されていなければ、失敗する
WAVE_FORMAT_DIRECT このフラグが指定されていれば
ACM ドライバは音声データを転送しない
WAVE_FORMAT_QUERY このフラグが指定されていれば
関数はデバイスに、指定フォーマットをサポートしているか求める
ただし、実際にデバイスはオープンされない
WAVE_MAPPED このフラグが指定されていれば
uDeviceID は、ウェーブマっパによってマップされる
ウェーブフォームオーディオデバイスを指定する

関数が成功すれば MMSYSERR_NOERROR が、そうでなければエラー値が返ります
エラーが発生した場合、次のいずれかの値がかえります

定数解説
MMSYSERR_ALLOCATED リソースは、すでに割り当てられている
MMSYSERR_BADDEVICEID デバイス識別子が無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない
WAVERR_BADFORMAT デバイスドライバは、指定されたフォーマットをサポートしていない
WAVERR_SYNC 同期デバイスが指定されたが
WAVE_ALLOWSYNC フラグが指定されていない

今は、コールバックメッセージを使わないので、コールバックについては後ほど説明します
WAVEFORMATEX 構造体は次のように定義されています
typedef struct { 
    WORD  wFormatTag; 
    WORD  nChannels; 
    DWORD nSamplesPerSec; 
    DWORD nAvgBytesPerSec; 
    WORD  nBlockAlign; 
    WORD  wBitsPerSample; 
    WORD  cbSize; 
} WAVEFORMATEX;
nFormatTag には、ウェーブフォームオーディオのフォーマットを指定します
ここに指定する定数は、MMREG.H ヘッダファイルに記述されています
フォーマットは圧縮アルゴリズムなどに備えて Microsoft に登録されていますが
PCM の場合は、常に WAVE_FORMAT_PCM を指定します

nChannels はチャンネルの数を指定することで、モノラルかステレオかを指定するメンバです
モノラルの場合は 1 を、ステレオの場合は 2 (右チャンネルと左チャンネル)を指定します
とりあえず、この場のサンプルプログラムはモノラルとして出力します

nSamplesPerSec にはサンプリングレートを指定します
nAvgBytesPerSec は、必須平均データ転送レートを バイト/秒 単位で指定します
PCM の場合、通常はサンプリングレート * nBlockAlign を指定します

nBlockAlign は、指定フォーマットの最小単位のデータサイズを指定します
これをブロックアラインメントと呼び
PCM の場合、このメンバには nChannels * wBitsPerSample / 8 を指定します

nBitsPerSample は、サンプルあたりのビット数を指定します
先ほど説明したように、PCM の場合は 8 ビット、または 16 ビットを指定できます
cbSize は、この構造体の末尾に追加される、拡張情報のサイズをバイト単位で指定します
このメンバは PCM フォーマットの場合は 0 を指定します

もし、waveOutOpen() 関数の dwCallback にコールバック関数を指定する場合
次の waveOutProc() と同じ型の関数でなければなりません
void CALLBACK waveOutProc(
	HWAVEOUT hwo , UINT uMsg,         
	DWORD dwInstance,  
	DWORD dwParam1, DWORD dwParam2     
);
hwo には、waveOutOpen() で作成された出力デバイスのハンドルが
uMsg には、送信メッセージが格納されます

dwInstance は、関数で指定したユーザー定義の追加情報
dwParam1 と dwParam2 にはメッセージの追加情報が指定されます

音声を開いたデバイスに出力するには、まずデータブロックを準備します
適当な方法で準備された、波形データを表す数列を出力用に準備するのです
そのためには waveOutPrepareHeader() 関数を呼び出します
MMRESULT waveOutPrepareHeader(
	HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh
);
hwo にはウェーブフォームオーディオ出力デバイスのハンドルを指定します
pwh は、WAVEHDR 構造体へのポインタです
この構造体に、音声データのバッファの情報を与えておきます
cbwh には、WAVEHDR 構造体のサイズを指定します

関数が成功すれば MMSYSERR_NOERROR が、そうでなければエラー値が返ります
この関数が返すエラー値は、以下のいずれかの定数になります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない

WAVEHDR 構造体は次のように定義されています
この構造体で、入出力する音声データのバッファ情報を表すことができます
typedef struct { 
    LPSTR  lpData; 
    DWORD  dwBufferLength; 
    DWORD  dwBytesRecorded; 
    DWORD  dwUser; 
    DWORD  dwFlags; 
    DWORD  dwLoops; 
    struct wavehdr_tag * lpNext; 
    DWORD  reserved; 
} WAVEHDR;
lpData には、ウェーブフォームバッファへのポインタを指定します
dwBufferLength に、指定したバッファのサイズをバイト単位で指定します

dwBytesRecorded 入力バッファとして使用する場合に
指定したバッファ内のデータ要領を指定します
dwUser は、オプションのユーザーデータを指定することができます

dwFlags には、バッファに付いての追加情報をフラグで指定します
このメンバには、以下の定数の組み合わせを指定することができます

定数解説
WHDR_BEGINLOOP このバッファはループ内の先頭バッファである
WHDR_DONE このフラグはデバイスドライバが設定する
ドライバがバッファの使用を終了したことを表す
WHDR_ENDLOOP このバッファはループ内の最後のバッファである
WHDR_INQUEUE このフラグは Windows が設定する
バッファが再生キューに入ることを表す
WHDR_PREPARED このフラグは Windows が設定する
バッファが準備されたことを表す

dwLppps には、出力ループ回数を指定します
lpNext メンバと reserved メンバは使用しません
それぞれ 0 で初期化してください

バッファを準備した後も、この構造体の dwBufferLength、dwFlags、dwLoops は変更できます
ただし、再生中にメンバを変更してはいけません

バッファの準備ができたら、後は再生するだけです
再生するには waveOutWrite() 関数を使います
MMRESULT waveOutWrite(
	HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh
);
hwo にはウェーブフォームオーディオ出力デバイスのハンドルを指定します
pwh には、準備済みの WAVEHDR 構造体へのポインタを
cbwh には、WAVEHDR 構造体のサイズを指定します

関数が成功すれば MMSYSERR_NOERROR が、そうでなければエラー値が返ります
この関数が返すエラー値は、以下のいずれかの定数になります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない
WAVERR_UNPREPARED pwh が指すバッファが準備されていない

さて、これでバッファ内のデータを音声としてデバイスに出力できます
次に、再生が終了した時点で解放処理を行う必要があります

再生を終了するには waveOutReset() 関数を用います
この関数は、再生を終了し、現在の位置を 0 に戻します

MMRESULT waveOutReset(HWAVEOUT hwo);

hwo にはウェーブフォームオーディオ出力デバイスのハンドルを指定します
関数が成功すれば MMSYSERR_NOERROR が、それ以外の場合はエラー値がかえります
この関数が返すエラー値は、以下のいずれかの定数になります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない
MMSYSERR_NOTSUPPORTED 関数がサポートされていない

次に、バッファの解放を行う必要がありますが
waveOutPrepareHeader() で準備済みのバッファは解放してはいけません
解放するには waveOutUnprepareHeader() で準備を終了します
MMRESULT waveOutUnprepareHeader(
	HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh
);
hwo にはウェーブフォームオーディオ出力デバイスのハンドルを指定します
pwh には、準備済みの WAVEHDR 構造体へのポインタを
cbwh には、WAVEHDR 構造体のサイズを指定します

関数が成功すれば MMSYSERR_NOERROR が、そうでなければエラー値が返ります
この関数が返すエラー値は、以下のいずれかの定数になります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない

この関数で準備を終了すれば、バッファを解放することができます
最後に waveOutClose() 関数で、不用になったデバイスを解放します

MMRESULT waveOutClose(HWAVEOUT hwo);

hwo には、ウェーブフォームオーディを出力デバイスのハンドルを指定します
関数が成功すれば MMSYSERR_NOERROR が、そうでなければエラー値が返ります
この関数が返すエラー値は、以下のいずれかの定数になります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない

今説明したこれらの関数を使えば、簡単に波形データを出力することができます
プログラムで作成した数値データを、直接出力するという芸当は、低レベル API の特権です
#include <windows.h>
#define TITLE 	TEXT("Kitty on your lap")
#define SRATE 	11025

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

	switch (msg) {
	case WM_DESTROY:
		waveOutReset(hWave);
		waveOutUnprepareHeader(hWave , &whdr , sizeof(WAVEHDR));
		free(bWave);
		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 , 0 , 0 , CALLBACK_NULL);

		whdr.lpData = bWave;
		whdr.dwBufferLength = SRATE;
		whdr.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
		whdr.dwLoops = 5;
		waveOutPrepareHeader(hWave , &whdr , sizeof(WAVEHDR));
		waveOutWrite(hWave , &whdr , sizeof(WAVEHDR));
		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;
}
このプログラムを実行すると、420 Hz 前後の波形音声が 5 秒間出力されます
11025 バイトのバッファを用意し、これに振幅 8 ビットの波形データを格納しています
このバッファが1秒間の音声を表す波形データで、これを 5 回リピートしているのです

バッファは、次の一文で初期化していることがわかります
for (dwCount = 0 ; dwCount < SRATE ; dwCount++ , dwWave += 10) {
	if (dwWave == 256) dwWave = 0;
	*(bWave + dwCount) = dwWave;
}
このループは、数値を 0 〜 250 まで 10 ずつ加算し、その後 0 に再び戻します
これで、1つの山が 25 サンプルのノコギリ波を生成しています
440 Hz が標準的な「ラ」の音なので、この音はラよりもやや低い音になります


waveOutOpen()

MMRESULT waveOutOpen(
	LPHWAVEOUT phwo , UINT uDeviceID,            
	LPWAVEFORMATEX pwfx ,
	DWORD dwCallback , DWORD dwCallbackInstance ,
	DWORD fdwOpen
);
ウェーブフォームオーディオ出力デバイスを開きます

phwo - デバイス識別用ハンドルへのポインタを指定します
uDeviceID - 対象の出力デバイスの識別子を指定します
pwfx - WAVEFORMATEX 構造体へのポインタを指定します
dwCallback - 再生中にウェーブの関連メッセージを受け取る対象を指定します
dwCallbackInstance - コールバック関数に渡すデータを指定できます
fdwOpen - デバイスを開くためのフラグを指定します

戻り値 - 成功すれば MMSYSERR_NOERROR、そうでなければエラー値

fdwOpen には以下のいずれかの値、または組み合わせを指定します
WAVE_ に組みあわせることができるのは 1 つの CALLBACK_ だけです

定数解説
CALLBACK_EVENT dwCallback はイベントハンドルである
CALLBACK_FUNCTION dwCallback はコールバック関数のポインタである
CALLBACK_NULL コールバックは使用しない
CALLBACK_THREAD dwCallback はスレッドハンドルである
CALLBACK_WINDOW dwCallback はウィンドウハンドルである
WAVE_FORMAT_DIRECT このフラグが指定されていれば
ACM ドライバは音声データを転送しない
WAVE_FORMAT_QUERY このフラグが指定されていれば
関数はデバイスに、指定フォーマットをサポートしているか求める
ただし、実際にデバイスはオープンされない
WAVE_MAPPED このフラグが指定されていれば
uDeviceID は、ウェーブマっパによってマップされる
ウェーブフォームオーディオデバイスを指定する

この関数が返すエラー値は、以下の定数のいずれかになります

定数解説
MMSYSERR_ALLOCATED リソースは、すでに割り当てられている
MMSYSERR_BADDEVICEID デバイス識別子が無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない
WAVERR_BADFORMAT デバイスドライバは、指定されたフォーマットをサポートしていない
WAVERR_SYNC 同期デバイスが指定されたが
WAVE_ALLOWSYNC フラグが指定されていない

waveOutProc()

void CALLBACK waveOutProc(
	HWAVEOUT hwo , UINT uMsg,         
	DWORD dwInstance,  
	DWORD dwParam1, DWORD dwParam2     
);
waveOutOpen() 関数が呼び出すアプリケーション定義のコールバック関数です

hwo - waveOutOpen() で作成された出力デバイスのハンドルを指定します
uMsg - 送信メッセージを指定します
dwInstance - 関数で指定したユーザー定義の追加情報を指定します
dwParam1 - メッセージの追加情報を指定します
dwParam2 - メッセージの追加情報を指定します

waveOutPrepareHeader()

MMRESULT waveOutPrepareHeader(
	HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh
);
再生に使う出力バッファブロックを準備します

hwo - ウェーブフォームオーディオ出力デバイスのハンドルを指定します
pwh - WAVEHDR 構造体へのポインタを指定します
cbwh - WAVEHDR 構造体のサイズを指定します

戻り値 - 成功すれば MMSYSERR_NOERROR、そうでなければエラー値

この関数が返すエラー値は、以下の定数のいずれかになります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない

waveOutWrite()

MMRESULT waveOutWrite(
	HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh
);
データバッファブロックを指定出力デバイスに送信します

hwo - ウェーブフォームオーディオ出力デバイスのハンドルを指定します
pwh - WAVEHDR 構造体へのポインタを指定します
cbwh - WAVEHDR 構造体のサイズを指定します

戻り値 - 成功すれば MMSYSERR_NOERROR、そうでなければエラー値

この関数が返すエラー値は、以下の定数のいずれかになります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない
WAVERR_UNPREPARED pwh が指すバッファが準備されていない

waveOutReset()

MMRESULT waveOutReset(HWAVEOUT hwo);

再生を停止し、現在位置をリセットします

hwo - ウェーブフォームオーディオ出力デバイスのハンドルを指定します

戻り値 - 成功すれば MMSYSERR_NOERROR、それ以外の場合はエラー値

この関数が返すエラー値は、以下の定数のいずれかになります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない
MMSYSERR_NOTSUPPORTED 関数がサポートされていない

waveOutUnprepareHeader()

MMRESULT waveOutUnprepareHeader(
	HWAVEOUT hwo , LPWAVEHDR pwh , UINT cbwh
);
準備済みのバッファブロックを解放できるように、準備の終結処理を行います

hwo - ウェーブフォームオーディオ出力デバイスのハンドルを指定します
pwh - WAVEHDR 構造体へのポインタを指定します
cbwh - WAVEHDR 構造体のサイズを指定します

戻り値 - 成功すれば MMSYSERR_NOERROR、そうでなければエラー値

この関数が返すエラー値は、以下の定数のいずれかになります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない

waveOutClose()

MMRESULT waveOutClose(HWAVEOUT hwo);

ウェーブフォームオーディオ出力デバイスを閉じます

hwo - ウェーブフォームオーディを出力デバイスのハンドルを指定します

戻り値 - 成功すれば MMSYSERR_NOERROR、そうでなければエラー値

この関数が返すエラー値は、以下の定数のいずれかになります

定数解説
MMSYSERR_HANDLEBUSY 別のスレッドがハンドルを使用中である
MMSYSERR_INVALHANDLE デバイスハンドルが無効である
MMSYSERR_NODRIVER デバイスドライバがない
MMSYSERR_NOMEM メモリを割り当てられない、またはロックできない



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