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

キャプチャ・カーソル(バイト単位)を受け取る変数のポインタ。
NULLを指定すると、キャプチャ・カーソルを取得しません。

pdwReadPosition

読み込みカーソル(バイト単位)を受け取る変数のポインタ。
NULLを指定すると、読み込みカーソルを取得しません。

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であれば、キャプチャバッファの排他制御を解除できました。



Windowsは米国Microsoft Corporationの登録商標です。
DirectXは米国Microsoft Corporationの登録商標です。
DirectSoundは米国Microsoft Corporationの登録商標です。