DirectSoundを利用してマイクから録音する
(その3)
DirectSoundでは、SetNotificationPositions()にて事前に登録したキャプチャ完了位置までキャプチャが実行されるとアプリケーションに対してイベントが通知されます。
このイベントの通知を受けたアプリケーション側は、直前にキャプチャデータを取り出した最終位置から現在のキャプチャ完了位置までを計算して、キャプチャバッファからサウンドデータを取り出します。
※一応サンプルプログラムでは、キャプチャバッファから取り出すデータサイズをGetCurrentPosition()を使って問い合わせて、その結果を元に決めていますが、 サンプルプログラムで行っているバッファ制御方法なら、キャプチャバッファの1/2を常に読み込むという方法でよいのかな?とも思っています。
サンプルコードを以下に示します。
/****************************************************************************/
/*!
* @brief データ入力イベントを監視するタスク.
*
* @param [in] user 使用しない.
*
* @retval TRUE = OK. / FALSE = NG.
*/
static DWORD WINAPI CaptureEventTask( void* user )
{
while( CapState ){
switch( WaitForMultipleObjects( 2, CapEvent, 0, INFINITE ) ){
case WAIT_OBJECT_0 + 0:
case WAIT_OBJECT_0 + 1:
if( CapState ){
//! 読み込み可能なバッファ位置を取得する.
DWORD n = 0;
DWORD read_pos = 0;
DWORD dummy = 0;
CapBuf->GetCurrentPosition( &dummy, &read_pos );
//! WAVファイルに書き出す先頭のデータ位置を保存しておく.
DWORD wav_pos = PutPos;
/*!
* 読み込みカーソルとバッファの次のデータの読み込み開始位置から
* 読み込み可能な領域のバイト数を計算する.
* (バッファ制御の関係上、読み込むサイズは最大でバッファの1/2を超えないようにする.)
*/
if( PutPos > read_pos ){
n = (CapBufSize + read_pos) - PutPos;
}else
if( PutPos < read_pos ){
n = read_pos - PutPos;
}
DWORD len = (n >= (CapBufSize >> 1)) ? (CapBufSize >> 1) : n;
//! データを読み込む領域をロックする.
void* buf1 = NULL;
void* buf2 = NULL;
DWORD len1 = 0;
DWORD len2 = 0;
CapBuf->Lock( PutPos, len, &buf1, &len1, &buf2, &len2, 0 );
//! 読み込みバッファにキャプチャしたデータをコピーする.
if( buf1 && len1 ){
PutPos = PutCaptureData( (BYTE*)buf1, len1, PutPos );
}
//! キャプチャ・バッファの先頭に戻った場合、残りのデータをコピーする.
if( buf2 && len2 ){
PutPos = PutCaptureData( (BYTE*)buf2, len2, PutPos );
}
//! 読み出しの完了したバッファをアンロックする.
CapBuf->Unlock( buf1, len1, buf2, len2 );
if( wav_pos > PutPos ){
//! バッファの最後にあるデータをWAVファイルに書き込む.
WritedWaveFile( &DataBuff[wav_pos], CapBufSize - wav_pos );
//! バッファの先頭にある残りのデータをWAVファイルに書き込む.
if( PutPos > 0 ){
WritedWaveFile( DataBuff, PutPos );
}
}else{
//! キャプチャしたデータをWAVファイルに書き込む.
WritedWaveFile( &DataBuff[wav_pos], PutPos - wav_pos );
}
}
break;
}
}
return 0;
}
イベント通知を受けた時点でのキャプチャバッファのキャプチャ完了位置を知る為に、IDirectSoundCaptureBuffer8のメソッドGetCurrentPosition()を呼び出して、現在のキャプチャ完了カーソルの位置を取得します。
HRESULT IDirectSoundCaptureBuffer8::GetCurrentPosition(
LPDWORD pdwCapturePosition,
LPDWORD pdwReadPosition )
引数 | 説明 |
---|---|
pdwCapturePosition | キャプチャ・カーソル(バイト単位)を受け取る変数のポインタ。 |
pdwReadPosition | 読み込みカーソル(バイト単位)を受け取る変数のポインタ。 |
GetCurrentPosition()からの戻り値がDS_OKであれば、キャプチャバッファのカーソル位置が取得できます。
DirectSoundではキャプチャバッファの読み込みは排他制御で行う為に、IDirectSoundCaptureBuffer8のメソッドLock()を呼び出して、読み込みを行うキャプチャバッファのポインタを取得します。
取得したキャプチャバッファからにオーディオデータを読み込んだら、Unlock()メソッドを呼び出して、キャプチャバッファの排他制御を解除します。
HRESULT IDirectSoundCaptureBuffer8::Lock(
DWORD dwOffset,
DWORD dwBytes,
LPVOID *ppvAudioPtr1,
LPDWORD pdwAudioBytes1,
LPVOID *ppvAudioPtr2,
LPDWORD pdwAudioBytes2,
DWORD dwFlags )
引数 | 説明 |
---|---|
dwOffset | バッファの先頭からロック開始位置までのオフセット(バイト)。 |
dwBytes | ロックするバッファ部分のバイト数。 |
ppvAudioPtr1 | バッファのロックされた部分へのポインタを受け取る変数のポインタ。 |
pdwAudioBytes1 | ppvAudioPtr1 のブロックのバイト数を受け取る変数のポインタ。 |
ppvAudioPtr2 | 引数 dwBytes で指定したバイト数の途中でバッファの最後になってしまった場合、2番目にロックされた部分へのポインタを受け取る変数のポインタ。 |
pdwAudioBytes2 | ppvAudioPtr2 のブロックのバイト数を受け取る変数のポインタ。 |
dwFlags | 引数dwOffsetからロックするので0を指定します。 |
Lock()からの戻り値がDS_OKであれば、読み込み可能なキャプチャバッファのポインタが取得できます。
キャプチャバッファの排他制御を解除するUnlock()メソッドは以下のとおりです。
HRESULT IDirectSoundCaptureBuffer8::Unlock(
LPVOID pvAudioPtr1,
DWORD dwAudioBytes1,
LPVOID pvAudioPtr2,
DWORD dwAudioBytes2 )
引数 | 説明 |
---|---|
pvAudioPtr1 | Lock()の ppvAudioPtr1 で取得したポインタ。 |
dwAudioBytes1 | pvAudioPtr1 のアドレスに書き込んだバイト数。 |
pvAudioPtr2 | Lock()の ppvAudioPtr2 で取得したポインタ。 |
dwAudioBytes2 | pvAudioPtr2 のアドレスに書き込んだバイト数。 |
Unlock()からの戻り値がDS_OKであれば、キャプチャバッファの排他制御を解除できました。