Platform SDK: DirectX

ストリーム バッファの使い方

ストリーム バッファは、一度にバッファに収まらない長いサウンドを再生する。バッファが再生されるにつれ、古いデータは定期的に新しいデータに置き換わる。

[C++]

ストリーム バッファを再生するには、dwFlags パラメータに DSBPLAY_LOOPING を指定して IDirectSoundBuffer::Play メソッドを呼び出す。

再生を停止するには、IDirectSoundBuffer::Stop メソッドを呼び出す。このメソッドはバッファを即時に停止するので、すべてのデータが再生されたことを確認する必要がある。これを行うには、再生位置をポーリングするか、通知位置を設定する。

バッファにストリーミングするには、次のステップが必要である。

  1. IDirectSoundBuffer::Lock を使って、バッファの一部をロックする。このメソッドは、データが記述される 1 つ、もしくは 2 つのアドレスを返す。
  2. この 1 つまたは 2 つのアドレスに対して、標準のメモリコピー ルーチンを使ってオーディオ データを書き込む。
  3. IDirectSoundBuffer::Unlock を使って、バッファをアンロックする。

IDirectSoundBuffer::Lock が 2 つのアドレスを返すことがあるのは、開始位置にかかわらず、バッファのサイズまでのバイト数をロックできるからである。必要に応じて、ロックされる部分はバッファの先頭にラップされる。ラップされる場合は、2 つの個別のメモリ コピーを実行しなければならない。

たとえば 40,000 バイトのバッファで、オフセット 20,000 で始まる 30,000 バイトをロックする場合、Lock を呼び出すと 4 つの値が返される。

ラップ アラウンドが必要ない場合は、最後の 2 つの値がそれぞれ NULL と 0 になる。

バッファ全体をロックすることもできるが、再生中に行うべきではない。毎回バッファの一部だけをリフレッシュすること。たとえば、再生位置が 2/4 に達したらすぐに、バッファの最初の 1/4 をロックして書き込むようにする。オーディオ出力が途切れる可能性を最小限に抑えるために、カレント プレイ ポジションの少なくとも 1 秒前方に書き込みを行うべきである。

次の C 関数は、dwOffset に渡されたバッファのオフセットから、データをサウンド バッファに書き込む。

BOOL AppWriteDataToBuffer( 
    LPDIRECTSOUNDBUFFER lpDsb,  // DirectSound バッファ。
    DWORD dwOffset,             // このサンプル固有の書き込みカーソル。
    LPBYTE lpbSoundData,        // このサンプル固有のデータ開始点。
    DWORD dwSoundBytes)         // コピーされるブロックのサイズ。
{ 
    LPVOID  lpvPtr1; 
    DWORD   dwBytes1; 
    LPVOID  lpvPtr2; 
    DWORD   dwBytes2; 
    HRESULT hr; 
 
    // 書き込みブロックのメモリ アドレスを取得する。ブロックがラップ アラウンドする
    // (先頭に戻る) 場合、書き込みブロックは 2 つの部分に分かれている。
    hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes, &lpvPtr1, 
        &dwBytes1, &lpvPtr2, &dwBytes2, 0); 
 
    // DSERR_BUFFERLOST が返された場合、復元とロックの再試行を行う。
    if (DSERR_BUFFERLOST == hr) 
    { 
        lpDsb->lpVtbl->Restore(lpDsb); 
        hr = lpDsb->lpVtbl->Lock(lpDsb, dwOffset, dwSoundBytes, 
            &lpvPtr1, &dwAudio1, &lpvPtr2, &dwAudio2, 0); 
    } 
    if SUCCEEDED(hr) 
    { 
        // ポインタに書き込む。
        CopyMemory(lpvPtr1, lpbSoundData, dwBytes1); 
        if (NULL != lpvPtr2) 
        { 
            CopyMemory(lpvPtr2, lpbSoundData+dwBytes1, dwBytes2); 
        } 
        // データを解放して DirectSound へ返す。
        hr = lpDsb->lpVtbl->Unlock(lpDsb, lpvPtr1, dwBytes1, lpvPtr2, 
            dwBytes2); 
        if SUCCEEDED(hr) 
        { 
            // 成功。
            return TRUE; 
        } 
    } 
    // ロック、アンロック、復元のいずれかが失敗。
    return FALSE; 
} 
 
[Visual Basic]

ストリーム バッファを再生するには、flags パラメータに DSBPLAY_LOOPING を指定して DirectSoundBuffer.Play メソッドを呼び出す。

再生を停止するには、DirectSoundBuffer.Stop メソッドを呼び出す。このメソッドはバッファを即時に停止するので、すべてのデータが再生されたことを確認する必要がある。これを行うには、再生位置をポーリングするか、通知位置を設定する。

DirectSoundBuffer.WriteBuffer メソッドを使ってバッファにデータをストリーミングする。このメソッドにより、バッファの任意の部分にデータを書き込める。バッファ全体に書き込むこともできるが、再生中に行うべきではない。毎回バッファの一部だけをリフレッシュすること。たとえば、カレント プレイ ポジションが 2/4 に達したらすぐに、バッファの最初の 1/4 に書き込むようにする。オーディオ出力が途切れる可能性を最小限に抑えるために、カレント プレイ ポジションの少なくとも 1 秒前方に書き込みを行うべきである。

次のサンプル コードは、バイト配列 myBuffer から、dsb で表された DirectSoundBuffer の先頭にデータ 1,000 バイトを書き込む。

dsb.WriteBuffer 0, 1000, myBuffer(0), DSBLOCK_DEFAULT

WriteBuffer は、ラップ アラウンドを透過的に処理する。たとえば、セカンダリ バッファが 10,000 バイトで作成されており、アプリケーションがバッファの中間を過ぎたオフセットに 5,000 バイト書き込む場合は、次のようになる。

dsb.WriteBuffer 8000, 5000, myBuffer(0), DSBLOCK_DEFAULT

この呼び出しは、バッファの最後に最初の 2,000 バイトを書き込み、バッファの先頭に次の 3,000 バイトを書き込む。

続くデータ記述に対するオフセットを追跡するのは、アプリケーションの責任である。この処理の最も簡単な方法は、通知位置を設定し、イベントがトリガされるたびに固定したバイト数を書き込むことである。

詳細情報については、次のトピックを参照すること。