DirectSoundを利用してWAVファイルを再生する
(その2)

WAVファイルの再生を開始する

ダイアログの[再生]ボタンを押されたときに、WAVファイルの再生を開始します。

WAVファイルがオープンされていない場合、WAVファイルをオープンします。

次にオープンしたWAVファイルの情報を元に以下の手順でサウンド出力デバイスに対応したストリームバッファを作成します。

作成したストリームバッファの再生開始位置を初期化します。

最後にDirectSoundの再生を開始します。

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


/****************************************************************************/
/*!
 *  @brief  WAVファイルを再生する.
 *
 *  @param  [in]    hDlg    ダイアログのウインドウ・ハンドル.
 *
 *  @retval TRUE = OK. / FALSE = NG.
 */
static BOOL     PlaySoundOutput( HWND hDlg )
{
    //! WAVファイルをオープンしていない場合、オープンする.
    if( !IsOpenWaveFile() ){

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

        //! -2.再生するWAVファイル名をオープンする.
        if( !ReadOpenWaveFile( FileName ) ){
            MessageBox( hDlg, _T("ファイルをオープンできません"),
                              _T("WAVファイルの再生"), MB_OK );
            return FALSE;
        }
        WaveEnd  = FALSE;
        EndDelay = 0;
    }
    if( !OutDev ){
        //! オープンしたWAVファイルのオーディオ・フィーマットを取得する.
        WAVEFORMATEX wf;
        GetAudioFormat( &wf );

        //! サウンド出力デバイスをオープンする.
        UINT num = ComboBox_GetCurSel( GetDlgItem( hDlg, IDC_OUTPUT_DEVICE ) );
        if( OpenSoundOutDevice( hDlg, num, &wf ) ){
            //! WAVファイルの読み込み用バッファを確保する.
            if( !DataBuff ){
                DataSize = wf.nAvgBytesPerSec >> 2;     // 1sec / 4 = 250ms.
                DataBuff = new BYTE[DataSize];
            }
            //! ボリューム設定をダイアログの設定にあわせる.
            VolumeControl( GetDlgItem( hDlg, IDC_VOLUME ) );

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

            //! 再生カーソルの位置を初期化する.
            OutPos = 0;
            OutBuf->SetCurrentPosition( 0 );
        }
    }
    //! サウンド出力を開始する.
    OutBuf->Play( 0, 0, DSBPLAY_LOOPING );

    EnableWindow( GetDlgItem( hDlg, IDC_PLAY          ), 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 );
    return TRUE;
}
	


/****************************************************************************/
/*!
 *  @brief  サウンド出力デバイスをオープンする.
 *
 *  @param  [in]    hDlg    ダイアログのウインドウ・ハンドル.
 *  @param  [in]    num     オープンするデバイス番号.
 *  @param  [in]    wf      再生するWAVファイルのオーディオ情報構造体のポインタ.
 *
 *  @retval TRUE = OK. / FALSE = NG.
 */
static BOOL     OpenSoundOutDevice( HWND hDlg, UINT num, WAVEFORMATEX* wf )
{
    //! DirectSoundの再生オブジェクトを作成する.
    if( DirectSoundCreate8( &DevGuid[num], &OutDev, NULL ) != S_OK ){
        return FALSE;
    }
    //! 再生オブジェクトに対するアプリケーションの協調レベルを設定する.
    if( OutDev->SetCooperativeLevel( hDlg, DSSCL_PRIORITY ) != DS_OK ){
        return FALSE;
    }
    //! ストリームバッファ・オブジェクトを作成する.
    DSBUFFERDESC desc;
    memset( &desc, 0, sizeof(desc) );
    desc.dwSize  = sizeof(desc);
    desc.dwFlags = DSBCAPS_GLOBALFOCUS
                 | DSBCAPS_CTRLPOSITIONNOTIFY
                 | DSBCAPS_CTRLVOLUME
                 | DSBCAPS_CTRLPAN;
    desc.dwBufferBytes = wf->nAvgBytesPerSec >> 2;
    desc.lpwfxFormat   = wf;
    if( OutDev->CreateSoundBuffer( &desc, &OutBuf, NULL ) != DS_OK ){
        return FALSE;
    }
    //! 確保されたストリームバッファのサイズを取得する.
    DSBCAPS caps;
    memset( &caps, 0, sizeof(caps) );
    caps.dwSize = sizeof(caps);
    if( OutBuf->GetCaps( &caps ) == DS_OK ){
        OutBufSize = caps.dwBufferBytes;
    }
    //! 再生イベントのオブジェクトを作成する.
    for( int i = 0; i < 2; i++ ){
        OutEvent[i] = CreateEvent( NULL, FALSE, FALSE, NULL );
    }
    LPDIRECTSOUNDNOTIFY8 Notify;
    if( OutBuf->QueryInterface( IID_IDirectSoundNotify, (LPVOID*)&Notify )
                                                              != DS_OK ){
        return FALSE;
    }
    //! 再生イベントを設定する.
    DSBPOSITIONNOTIFY pos[2];
    pos[0].dwOffset     = (OutBufSize / 2) - 1;
    pos[0].hEventNotify = OutEvent[0];
    pos[1].dwOffset     = OutBufSize - 1;
    pos[1].hEventNotify = OutEvent[1];
    Notify->SetNotificationPositions( 2, pos );
    Notify->Release();

    OutState = TRUE;

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

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

DirectSoundCreate8()を呼び出して、IDirectSound8インターフェイスのオブジェクトを作成します。


    HRESULT WINAPI DirectSoundCreate8(
                           LPCGUID lpcGuidDevice,
                           LPDIRECTSOUND8* ppDS8,
                           LPUNKNOWN pUnkOuter )
	

引数説明
lpcGuidDevice

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

ppDS8

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

pUnkOuter

NULLを指定します。

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

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

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

IDirectSound

メソッド名説明
SetCooperativeLevel

デバイスに対するアプリケーションの協調レベルを設定します。

CreateSoundBuffer

オーディオデータを格納するバッファを作成します。

DuplicateSoundBuffer

新しいセカンダリ・バッファを作成します。

GetCaps

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

GetSpeakerConfig

スピーカの構成を取得します。

SetSpeakerConfig

スピーカ構成を設定します。

Initialize

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

Compact

オンボード・メモリで利用できる空きメモリ領域を最大にします。

VerifyCertification

ドライバが DirectX で認証されているかどうかを確認します。

アプリケーションの協調レベルを設定する

DirectSoundでは1つの出力デバイスを複数のアプリケーションから同時に利用できる為、IDirectSound8のメソッドSetCooperativeLevel()を呼び出して、使用するサウンド出力デバイスのアプリケーション間の協調レベルを設定します。


    HRESULT IDirectSound8::SetCooperativeLevel(
                                  HWND hwnd,
                                  DWORD dwLevel )
	

引数説明
hwnd

アプリケーションのウインドウ・ハンドル。

dwLevel

アプリケーションの協調レベル。
通常はDSSCL_PRIORITY(優先レベル)を指定します。

SetCooperativeLevel()からの戻り値がDS_OKであれば、協調レベルの設定は成功です。

ストリームバッファを作成する

IDirectSound8のメソッドCreateSoundBuffer()を呼び出して、オーディオデータを格納するストリームバッファのオブジェクトを作成します。


    HRESULT IDirectSound8::CreateSoundBuffer(
                                    LPCDSBUFFERDESC pcDSBufferDesc,
                                    LPDIRECTSOUNDBUFFER* ppDSBuffer,
                                    LPUNKNOWN pUnkOuter )
	

引数説明
pcDSBufferDesc

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

ppDSBuffer

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

pUnkOuter

NULLを指定します。

CreateSoundBuffer()からの戻り値がDS_OKであれば、オーディオデータ・バッファの作成は成功です。

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

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

IDirectSoundBuffer

メソッド名説明
Play

オーディオの再生を開始します。

Stop

オーディオの再生を停止します。

Lock

バッファをロックします。

Unlock

バッファをアンロックします。

GetFormat

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

SetFormat

プライマリ・バッファのオーディオ・フォーマットを設定します。

GetFrequency

サンプルレートを取得します。

SetFrequency

サンプルレートを設定します。

GetCaps

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

GetStatus

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

GetCurrentPosition

バッファの再生カーソルおよび読み込みカーソルの位置を取得します。

SetCurrentPosition

バッファの再生カーソルの位置を設定します。

GetVolume

ボリュームレベルを取得します。

SetVolume

ボリュームレベルを設定します。

GetPan

左右のボリュームバランスを取得します。

SetPan

左右のボリュームバランスを設定します。

Restore

失われたバッファへのメモリ割り当てを復元します。

AcquireResources

DSBCAPS_LOCDEFER フラグで作成されたバッファにリソースを割り当てます。

Initialize

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

GetObjectInPath

エフェクト・オブジェクトのインターフェイスを取得します。

SetFX

バッファのエフェクトを有効にします。

オーディオデータ・バッファ設定構造体(DSBUFFERDESC構造体)は以下のとおりです。

メンバ名説明
dwSize

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

dwFlags

サンプルコードで設定しているフラグは以下のとおりです。
 - DSBCAPS_GLOBALFOCUS
   グローバルなサウンド・バッファを作成します。
 - DSBCAPS_CTRLPOSITIONNOTIFY
   通知イベントを使用します。
 - DSBCAPS_CTRLVOLUME
   ボリュームレベルの設定を行います。
 - DSBCAPS_CTRLPAN
   左右のボリュームバランスの設定を行います。

dwBufferBytes

作成するバッファのサイズ(バイト数)。
プライマリ・バッファの場合、0を指定します。

dwReserved

0を指定します。

lpwfxFormat

オーディオ・フォーマット(WAVEFORMATEX構造体またはWAVEFORMATEXTENSIBLE構造体)のポインタを指定します。
プライマリ・バッファの場合、NULL を指定します。

guid3DAlgorithm

DirectSound3Dの2スピーカ仮想化アルゴリズムの指定。
サンプルコードでは使用しないのでDS3DALG_DEFAULTを指定します。

作成したストリームバッファのサイズを取得するには、IDirectSoundBuffer8のメソッドGetCaps()を使用します。


    HRESULT IDirectSoundBuffer8::GetCaps( LPDSBCAPS pDSBufferCaps )
	

引数説明
pDSBufferCaps

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

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

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

メンバ名説明
dwSize

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

dwFlags

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

dwBufferBytes

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

dwUnlockTransferRate

Unlock()を呼び出したときにデータをバッファ・メモリに転送する速度 (KB/秒)。

dwPlayCpuOverhead

サウンド・バッファをミキシングするために必要な時間。CPUサイクルのパーセンテージで表します。

再生イベントを設定する

IDirectSound8のメソッド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点に再生イベントを設定しています。

ストリームバッファの再生開始位置を初期化する

IDirectSoundBuffer8のメソッドSetCurrentPosition()を呼び出して再生開始位置を設定します。

サンプルコードでは再生開始位置の初期化なので、引数に0を設定します。


    HRESULT IDirectSoundBuffer8::SetCurrentPosition( DWORD dwNewPosition )
	

引数説明
dwNewPosition

バッファの先頭からの再生カーソルのオフセット(バイト単位)。

SetCurrentPosition()からの戻り値がDS_OKであれば再生開始位置の設定は完了です。

再生を開始する

IDirectSoundBuffer8のメソッドPlay()を呼び出して再生を開始します。


    HRESULT IDirectSoundBuffer8::Play(
                           DWORD dwReserved1,
                           DWORD dwPriority,
                           DWORD dwFlags )
	

引数説明
dwReserved1

0を指定。

dwPriority

サウンドの優先度。通常は0を指定します。

dwFlags

ストリームバッファをリングバッファとして動作させますのでDSBPLAY_LOOPINGを指定します。

Play()からの戻り値がDS_OKであれば再生が開始されます。



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