DirectSoundを利用してマイクから録音する
(その2)

マイクからの録音を開始する

ダイアログの[録音]ボタンを押されたときに、外部入力(マイク)からの録音を開始します。

[録音]ボタンは、録音開始時と一時停止からの録音復帰時に押されますので、入出力デバイス等の二重オープンを防止する為に、入力デバイスの有無でデバイスのオープン済みかどうかを判定します。
(よって、何れかのデバイスでオープンに失敗したときは、オープンに成功した他のデバイスもクローズするようにしておきます。)

録音開始までの手順は以下のようになります。

最後に録音の一時停止中を判定する為に録画中フラグをセットしておきます。

サンプルコードを以下に示します。


/****************************************************************************/
/*!
 *  @brief  外部音声の録音を開始する.
 *
 *  @param  [in]    hDlg    ダイアログのウインドウ・ハンドル.
 *
 *  @retval TRUE = OK. / FALSE = NG.
 */
static BOOL     RecSound( HWND hDlg )
{
    if( !CapDev ){
        //! オーディオ・データ・フォーマットを設定する.
        WAVEFORMATEX wf;
        wf.wFormatTag      = WAVE_FORMAT_PCM;
        wf.nChannels       = 2;
        wf.wBitsPerSample  = 16;
        wf.nBlockAlign     = 4;
        wf.nSamplesPerSec  = SMPFRQ;
        wf.nAvgBytesPerSec = SMPFRQ * wf.nBlockAlign;
        wf.cbSize          = 0;

        //! ダイアログから再生するWAVファイル名を取得する.
        GetWindowText( GetDlgItem( hDlg, IDC_FILENAME ), FileName, sizeof(FileName) - 1 );

        //! 保存するWAVファイルを新規作成でオープンする.
        int result = SaveOpenWaveFile( FileName, &wf, FALSE );
        if( result == -2 ){
            //! 同一のファイル名がある場合、上書きするかどうかを問い合わせる.
            if( MessageBox( hDlg, _T("既にファイルが存在しています。上書きしますか?"), _T("WAVファイルの保存"), MB_YESNO ) == IDYES ){

                //! 上書きモードでファイルをオープンする.
                result = SaveOpenWaveFile( FileName, &wf, TRUE );
            }else{
                return FALSE;
            }
        }
        if( result != 0 ){
            MessageBox( hDlg, _T("ファイルをオープンできません"), _T("WAVファイルの保存"), MB_OK );
            return FALSE;
        }

        //! サウンド入力デバイスをオープンする.
        UINT num = ComboBox_GetCurSel( GetDlgItem( hDlg, IDC_INPUT_DEVICE ) );
        if( !OpenSoundCapDevice( hDlg, num, &wf ) ){
            return FALSE;
        }
        //! サウンド出力デバイスをオープンする.
        num = ComboBox_GetCurSel( GetDlgItem( hDlg, IDC_OUTPUT_DEVICE ) );
        if( !OpenSoundOutDevice( hDlg, num, &wf ) ){
            return FALSE;
        }

        //! 読み込みバッファを確保する.
        if( !DataBuff ){
            DataBuff = new BYTE[CapBufSize];
            memset( DataBuff, 0, CapBufSize );
        }
        //! ボリューム設定をダイアログの設定にあわせる.
        VolumeControl( GetDlgItem( hDlg, IDC_VOLUME ) );

        //! バランス設定をダイアログの設定にあわせる.
        VolumeControl( GetDlgItem( hDlg, IDC_BALANCE ) );

        //! 再生カーソルの位置を初期化する.
        OutPos = 0;
        OutBuf->SetCurrentPosition( 0 );

        //! サウンド出力を開始する.
        OutBuf->Play( 0, 0, DSBPLAY_LOOPING );

        //! キャプチャを開始する.
        GetPos = (CapBufSize >> 1);
        PutPos = 0;
        CapBuf->Start( DSCBSTART_LOOPING );
    }
    //! 録画中フラグをセットする.
    RecFlag = TRUE;

    EnableWindow( GetDlgItem( hDlg, IDC_REC           ), FALSE );
    EnableWindow( GetDlgItem( hDlg, IDC_PAUSE         ), TRUE  );
    EnableWindow( GetDlgItem( hDlg, IDC_STOP          ), TRUE  );
    EnableWindow( GetDlgItem( hDlg, IDC_FILENAME      ), FALSE );
    EnableWindow( GetDlgItem( hDlg, IDC_FILE_SELECT   ), FALSE );
    EnableWindow( GetDlgItem( hDlg, IDC_OUTPUT_DEVICE ), FALSE );
    EnableWindow( GetDlgItem( hDlg, IDC_INPUT_DEVICE  ), FALSE );
    return TRUE;
}
	


/****************************************************************************/
/*!
 *  @brief  サウンド入力デバイスをオープンする.
 *
 *  @param  [in]    hDlg    ダイアログのウインドウ・ハンドル.
 *  @param  [in]    num     オープンするデバイス番号.
 *  @param  [in]    wf      再生するWAVファイルのオーディオ情報構造体のポインタ.
 *
 *  @retval TRUE = OK. / FALSE = NG.
 */
static BOOL     OpenSoundCapDevice( HWND hDlg, UINT num, WAVEFORMATEX* wf )
{
    //! DirectSoundのキャプチャ・オブジェクトを作成する.
    if( DirectSoundCaptureCreate8( &DevGuid[1][num], &CapDev, NULL ) != S_OK ){
        return FALSE;
    }
    //! キャプチャバッファ・オブジェクトを作成する.
    DSCBUFFERDESC desc;
    memset( &desc, 0, sizeof(desc) );
    desc.dwSize        = sizeof(desc);
    desc.dwFlags       = 0;
    desc.dwBufferBytes = BUFSIZE;
    desc.lpwfxFormat   = wf;
    if( CapDev->CreateCaptureBuffer( &desc, &CapBuf, NULL ) != DS_OK ){
        return FALSE;
    }
    // 確保されたキャプチャ・バッファのサイズを取得する.
    DSCBCAPS caps;
    memset( &caps, 0, sizeof(caps) );
    caps.dwSize = sizeof(caps);
    if( CapBuf->GetCaps( &caps ) == DS_OK ){
        CapBufSize = caps.dwBufferBytes;
    }
    // キャプチャ・イベントのオブジェクトを作成する.
    for( int i = 0; i < 2; i++ ){
        CapEvent[i] = CreateEvent( NULL, FALSE, FALSE, NULL );
    }
    LPDIRECTSOUNDNOTIFY8 Notify;
    if( CapBuf->QueryInterface( IID_IDirectSoundNotify, (LPVOID*)&Notify ) != DS_OK ){
        return FALSE;
    }
    //! キャプチャ・イベントを設定する.
    DSBPOSITIONNOTIFY pos[2];
    pos[0].dwOffset     = (CapBufSize / 2) - 1;
    pos[0].hEventNotify = CapEvent[0];
    pos[1].dwOffset     = CapBufSize - 1;
    pos[1].hEventNotify = CapEvent[1];
    Notify->SetNotificationPositions( 2, pos );
    Notify->Release();

    CapState = TRUE;

    //! イベントタスクを起動する.
    DWORD tid;
    CreateThread( NULL, 0, CaptureEventTask, NULL, 0, &tid );
    return TRUE;
}
	

IDirectSoundCapture8インターフェイスのオブジェクトを作成する

DirectSoundCaptureCreate8()を呼び出して、IDirectSoundCapture8インターフェイスのオブジェクト(キャプチャ・オブジェクト)を作成します。


    HRESULT WINAPI DirectSoundCaptureCreate8(
                           LPCGUID lpcGUID,
                           LPDIRECTSOUNDCAPTURE8* lplpDSC,
                           LPUNKNOWN pUnkOuter )
	

引数説明
lpcGUID

オーディオ入力デバイスのGUIDのポインタ
デフォルトのドライバを指定するときはNULLにします。

lplpDSC

IDirectSoundCapture8インターフェイスのオブジェクトのポインタを受け取る変数のポインタ。

pUnkOuter

NULLを指定します。

DirectSoundCaptureCreate8()からの戻り値がS_OKであれば、オブジェクトの作成は成功です。

IDirectSoundCapture8インターフェイスの各メソッドは以下のとおりです。

クラス識別子CLSID_DirectSoundCapture8
インターフェイス識別子IID_IDirectSoundCapture8
継承クラス

IUnknown

メソッド名説明
CreateCaptureBuffer

キャプチャデータを格納するバッファを作成します。

GetCaps

デバイスの性能を取得します。

Initialize

オブジェクトを初期化します。

キャプチャバッファを作成する

IDirectSoundCapture8のメソッドCreateCaptureBuffer()を呼び出して、キャプチャしたオーディオデータを格納するバッファのオブジェクトを作成します。


    HRESULT IDirectSoundCapture8::CreateCaptureBuffer(
                                       LPCDSCBUFFERDESC pcDSCBufferDesc,
                                       LPDIRECTSOUNDCAPTUREBUFFER * ppDSCBuffer,
                                       LPUNKNOWN pUnkOuter )
	

引数説明
pcDSCBufferDesc

作成するバッファの設定を記述した構造体のポインタ。

ppDSCBuffer

作成したバッファ・オブジェクト(IDirectSoundCaptureBufferインターフェイス)のポインタを受け取る変数のポインタ。

pUnkOuter

NULLを指定します。

CreateCaptureBuffer()からの戻り値がDS_OKであれば、キャプチャバッファの作成は成功です。

IDirectSoundCaptureBufferインターフェイスの各メソッドは以下のとおりです。

インターフェイス識別子IID_IDirectSoundCaptureBuffer8
継承クラス

IDirectSoundCaptureBuffer

メソッド名説明
Start

オーディオデータのキャプチャを開始します。

Stop

オーディオデータのキャプチャを停止します。

Lock

キャプチャバッファをロックします。

Unlock

キャプチャバッファをアンロックします。

GetStatus

キャプチャバッファのステータスを取得します。

GetFormat

オーディオ・フォーマットを取得します。

GetCaps

バッファの能力を取得します。

GetCurrentPosition

バッファのキャプチャ・カーソルおよび読み込みカーソルの位置を取得します。

Initialize

オブジェクトを初期化します。

GetFXStatus

キャプチャ・エフェクトのステータスを取得します。

GetObjectInPath

バッファに関連付けられたエフェクト・オブジェクトのインターフェイスを取得します。

キャプチャ・バッファ設定構造体(DSCBUFFERDESC構造体)は以下のとおりです。

メンバ名説明
dwSize

DSCBUFFERDESC構造体のサイズ (バイト数)。

dwFlags

- DSCBCAPS_CTRLFX
  バッファはエフェクトをサポートします。
- DSCBCAPS_WAVEMAPPED
  未サポートのフォーマットに対しては、Win32ウェーブ マッパーを使用します。

dwBufferBytes

作成するバッファのサイズ(バイト数)。

dwReserved

0を指定します。

lpwfxFormat

オーディオ・フォーマット(WAVEFORMATEX構造体またはWAVEFORMATEXTENSIBLE構造体)のポインタを指定します。

dwFXCount

サポートするエフェクトの個数。

lpDSCFXDesc

サポートするエフェクトを表すDSCEFFECTDESC構造体配列のポインタ。



作成したキャプチャバッファのサイズを取得するには、IDirectSoundCaptureBufferのメソッドGetCaps()を使用します。


    HRESULT IDirectSoundCapture8::GetCaps( LPDSCCAPS pDSCCaps )
	

引数説明
pDSCCaps

バッファの能力が格納されるデータ(DSCCAPS構造体)のポインタ。
dwSizeメンバに構造体のバイト数をセットして呼び出します。

GetCaps()からの戻り値がDS_OKであれば成功です。

DSCCAPS構造体は以下のとおりです。

メンバ名説明
dwSize

DSCCAPS構造体のサイズ (バイト数)。

dwFlags

バッファの能力を示すフラグ。

dwBufferBytes

バッファのサイズ(バイト数)。

dwReserved

未使用。

キャプチャ完了イベントを設定する

IDirectSoundCapture8のメソッドQueryInterface()を呼び出して、イベント設定用のIDirectSoundNotify8インターフェースのオブジェクトを取得します。

IDirectSoundNotify8のメソッドSetNotificationPositions()を呼び出してキャプチャ完了イベントの通知位置を設定します。
キャプチャ中に、キャプチャ・カーソルが指定されたオフセットに到達するたびに、イベントが通知されます。


	HRESULT IDirectSoundNotify8::SetNotificationPositions(
                           DWORD dwPositionNotifies,
                           LPCDSBPOSITIONNOTIFY pcPositionNotifies )
	

引数説明
dwPositionNotifies

DSBPOSITIONNOTIFY構造体配列の個数。

pcPositionNotifies

DSBPOSITIONNOTIFY構造体配列のポインタ。

SetNotificationPositions()からの戻り値がDS_OKであればイベント設定は完了です。

※SetNotificationPositions()を呼び出すと、以前に設定していたイベント通知は上書きされて無効になります。

イベント設定構造体(DSBPOSITIONNOTIFY構造体)は以下のとおりです。

メンバ名説明
dwOffset

バッファの先頭から通知イベントが発生する場所までのオフセット。
または、DSBPN_OFFSETSTOP
DSBPN_OFFSETSTOPを指定すると、再生またはキャプチャが停止したときにイベントが通知されます。

hEventNotify

通知されるイベントのハンドル。

サンプルコードではキャプチャバッファの中間点と最後の2点にキャプチャ完了イベントを設定しています。

キャプチャを開始する

IDirectSoundCaptureBuffer8のメソッドStart()を呼び出してキャプチャを開始します。


    HRESULT IDirectSoundCaptureBuffer8::Start( DWORD dwFlags )
	

引数説明
dwFlags

キャプチャバッファをリングバッファとして動作させますのでDSCBSTART_LOOPINGを指定します。

Start()からの戻り値がDS_OKであればキャプチャが開始されます。



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