Share via


方法: ディスクからのサウンドのストリーム

注意

このコンテンツはデスクトップ アプリにのみ適用され、Windows ストア アプリで機能するにはリビジョンが必要です。 CreateFile2CreateEventExWaitForSingleObjectExSetFilePointerExGetOverlappedResultEx のドキュメントを参照してください。 Windows SDK サンプル ギャラリーの StreamEffect Windows 8 サンプルを参照してください。

 

XAudio2 でオーディオ データをストリーミングするには、別のスレッドを作成し、ストリーミング スレッドでオーディオ データのバッファー読み取りを実行し、コールバックを使用してそのスレッドを制御します。

ストリーミング スレッドでのバッファー読み取りの実行

ストリーミング スレッドでバッファー読み取りを実行するには、次の手順に従います。

  1. 読み取りバッファーの配列を作成します。

    #define STREAMING_BUFFER_SIZE 65536
    #define MAX_BUFFER_COUNT 3
    BYTE buffers[MAX_BUFFER_COUNT][STREAMING_BUFFER_SIZE];
    
  2. OVERLAPPED 構造体を初期化します。

    構造体は、非同期ディスクの読み取りが完了したときにチェックするために使用されます。

    OVERLAPPED Overlapped = {0};
    Overlapped.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
    
  3. ストリーミング オーディオを再生するソース音声Start 関数を呼び出します。

    hr = pSourceVoice->Start( 0, 0 );
    
  4. 現在の読み取り位置がオーディオ ファイルの末尾に渡されない間はループします。

    CurrentDiskReadBuffer = 0;
    CurrentPosition = 0;
    while ( CurrentPosition < cbWaveSize )
    {
        ...
    }
    

    ループで、次の操作を行います。

    1. ディスクから現在の読み取りバッファーにデータのチャンクを読み取ります。

      DWORD dwRead;
      if( SUCCEEDED(hr) && 0 == ReadFile( hFile, pData, dwDataSize, &dwRead, pOverlapped ) )
          hr = HRESULT_FROM_WIN32( GetLastError() );
          DWORD cbValid = min( STREAMING_BUFFER_SIZE, cbWaveSize - CurrentPosition );
          DWORD dwRead;
          if( 0 == ReadFile( hFile, buffers[CurrentDiskReadBuffer], STREAMING_BUFFER_SIZE, &dwRead, &Overlapped ) )
              hr = HRESULT_FROM_WIN32( GetLastError() );
          Overlapped.Offset += cbValid;
      
          //update the file position to where it will be once the read finishes
          CurrentPosition += cbValid;
      
    2. GetOverlappedResult 関数を使用して、読み取りが完了したことを通知するイベントを待機します。

      DWORD NumberBytesTransferred;
      ::GetOverlappedResult(hFile,&Overlapped,&NumberBytesTransferred, TRUE);
      
    3. ソース音声でキューに登録されているバッファーの数が読み取りバッファーの数より少なくなるのを待ちます。

      ソース音声の状態は、GetState 関数で確認されます。

      XAUDIO2_VOICE_STATE state;
      while( pSourceVoice->GetState( &state ), state.BuffersQueued >= MAX_BUFFER_COUNT - 1)
      {
          WaitForSingleObject( Context.hBufferEndEvent, INFINITE );
      }
      
    4. SubmitSourceBuffer 関数を使用して、現在の読み取りバッファーをソース音声に送信します。

      XAUDIO2_BUFFER buf = {0};
      buf.AudioBytes = cbValid;
      buf.pAudioData = buffers[CurrentDiskReadBuffer];
      if( CurrentPosition >= cbWaveSize )
      {
          buf.Flags = XAUDIO2_END_OF_STREAM;
      }
      pSourceVoice->SubmitSourceBuffer( &buf );
      
    5. 現在の読み取りバッファー インデックスを次のバッファーに設定します。

      CurrentDiskReadBuffer++;
      CurrentDiskReadBuffer %= MAX_BUFFER_COUNT;
      
  5. ループが完了したら、残りのキューに入っているバッファーの再生が完了するまで待ちます。

    残りのバッファーの再生が完了すると、サウンドが停止し、スレッドが終了するか、別のサウンドをストリーミングするために再利用できます。

    XAUDIO2_VOICE_STATE state;
    while( pSourceVoice->GetState( &state ), state.BuffersQueued > 0 )
    {
        WaitForSingleObjectEx( Context.hBufferEndEvent, INFINITE, TRUE );
    }
    

コールバック クラスの作成

コールバック クラスを作成するには、 IXAudio2VoiceCallback インターフェイスから継承するクラスを作成します。

クラスは 、OnBufferEnd メソッドでイベントを設定する必要があります。 これにより、ストリーミング スレッドは、XAudio2 がオーディオ バッファーからの読み取りを完了したことをイベントが通知するまでスリープ状態になります。 XAudio2 でコールバックを使用する方法の詳細については、「 方法: ソース音声コールバックを使用する」を参照してください。

struct StreamingVoiceContext : public IXAudio2VoiceCallback
{
    HANDLE hBufferEndEvent;
    StreamingVoiceContext(): hBufferEndEvent( CreateEvent( NULL, FALSE, FALSE, NULL ) ){}
    ~StreamingVoiceContext(){ CloseHandle( hBufferEndEvent ); }
    void OnBufferEnd( void* ){ SetEvent( hBufferEndEvent ); }
    ...
};

オーディオ データのストリーミング

XAudio2 のコールバック

XAudio2 プログラミング ガイド

方法: 基本的なオーディオ処理グラフの作成

方法: ソース ボイスのコールバックの使用