次の方法で共有


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

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

ディスクからオーディオをストリームするには

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

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 ); }
    ...
};

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

ストリーミング スレッドで以下の手順を実行します。

Windows:  Windows では、CoInitialize または CoInitializeEx をストリーミング スレッドで呼び出す必要があります。XAudio2 は COM オブジェクトとして実装され、COM のルールは、XAudio2 への呼び出しを実行するすべてのスレッドで CoInitialize または CoInitializeEx を呼び出す必要があります。

  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 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);
      

          PC で作成されたオーディオ ファイルは通常、Xbox 360 で作成されたものとはエンディアンが異なります。オーディオ ファイルを作成するツールに正しいエンディアンでデータを保存する機能がない場合は、XBox 360 に各データ チャンクを読み込んでから、オーディオ データをバイトスワップする必要があります。

    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 )
    {
        WaitForSingleObject( Context.hBufferEndEvent, INFINITE );
    }
    

関連トピック