方法 : XAudio2 でオーディオ データ ファイルを読み込む

Note

このコンテンツはデスクトップ アプリにのみ適用され (UWP アプリで機能するためにはリビジョンが必要になり) ます。 CreateFile2CreateEventExWaitForSingleObjectExSetFilePointerEx および GetOverlappedResultEx のドキュメントを参照してください。 現在アーカイブされている Windows SDK サンプル ギャラリーの BasicSound Windows 8 サンプル アプリSoundFileReader.h.cpp を参照してください。

XAudio2 でオーディオ データを再生するために必要な構造体を設定するには:

  • オーディオ ファイルを読み込み込むかストリーミングを行います。
  • または、独自の波形を生成し、その波形をバッファー内のサンプルとして表すことができます (「単純な XAudio2 プロジェクト (完全版)」を参照してください)。

このトピックでは、オーディオ ファイルを読み込む方法について説明します。 次の手順では、オーディオ ファイルの fmtdata のチャンクを読み込み、それらを使用して WAVEFORMATEXTENSIBLE 構造体と XAUDIO2_BUFFER 構造体を設定します。

オーディオ ファイルの解析準備

XAudio2 でサポートされているオーディオ ファイルは、リソース交換ファイル形式 (RIFF) で書式設定されます。 RIFF の説明については、トピック「リソース交換ファイル形式 (RIFF)」を参照してください。 RIFF ファイル内のオーディオ データは、RIFF チャンクを検索した後、RIFF チャンクに含まれる個々のチャンクを見つけるためにチャンクをループすることで読み込まれます。 次の関数は、チャンクを検索し、チャンクに含まれるデータを読み込むコードの例です。

  • RIFF ファイルでチャンクを検索するには:

    #ifdef _XBOX //Big-Endian
    #define fourccRIFF 'RIFF'
    #define fourccDATA 'data'
    #define fourccFMT 'fmt '
    #define fourccWAVE 'WAVE'
    #define fourccXWMA 'XWMA'
    #define fourccDPDS 'dpds'
    #endif
    
    #ifndef _XBOX //Little-Endian
    #define fourccRIFF 'FFIR'
    #define fourccDATA 'atad'
    #define fourccFMT ' tmf'
    #define fourccWAVE 'EVAW'
    #define fourccXWMA 'AMWX'
    #define fourccDPDS 'sdpd'
    #endif
    HRESULT FindChunk(HANDLE hFile, DWORD fourcc, DWORD & dwChunkSize, DWORD & dwChunkDataPosition)
    {
        HRESULT hr = S_OK;
        if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ) )
            return HRESULT_FROM_WIN32( GetLastError() );
    
        DWORD dwChunkType;
        DWORD dwChunkDataSize;
        DWORD dwRIFFDataSize = 0;
        DWORD dwFileType;
        DWORD bytesRead = 0;
        DWORD dwOffset = 0;
    
        while (hr == S_OK)
        {
            DWORD dwRead;
            if( 0 == ReadFile( hFile, &dwChunkType, sizeof(DWORD), &dwRead, NULL ) )
                hr = HRESULT_FROM_WIN32( GetLastError() );
    
            if( 0 == ReadFile( hFile, &dwChunkDataSize, sizeof(DWORD), &dwRead, NULL ) )
                hr = HRESULT_FROM_WIN32( GetLastError() );
    
            switch (dwChunkType)
            {
            case fourccRIFF:
                dwRIFFDataSize = dwChunkDataSize;
                dwChunkDataSize = 4;
                if( 0 == ReadFile( hFile, &dwFileType, sizeof(DWORD), &dwRead, NULL ) )
                    hr = HRESULT_FROM_WIN32( GetLastError() );
                break;
    
            default:
                if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, dwChunkDataSize, NULL, FILE_CURRENT ) )
                return HRESULT_FROM_WIN32( GetLastError() );            
            }
    
            dwOffset += sizeof(DWORD) * 2;
    
            if (dwChunkType == fourcc)
            {
                dwChunkSize = dwChunkDataSize;
                dwChunkDataPosition = dwOffset;
                return S_OK;
            }
    
            dwOffset += dwChunkDataSize;
    
            if (bytesRead >= dwRIFFDataSize) return S_FALSE;
    
        }
    
        return S_OK;
    }
    
  • チャンク内のデータを見つけた後に読み取る。

    目的のチャンクが見つかったら、チャンクのデータ セクションの先頭にファイル ポインターを調整することで、そのデータを読み取ることができます。 チャンクが見つかったらチャンクからデータを読み取る関数は、次のようになります。

    HRESULT ReadChunkData(HANDLE hFile, void * buffer, DWORD buffersize, DWORD bufferoffset)
    {
        HRESULT hr = S_OK;
        if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, bufferoffset, NULL, FILE_BEGIN ) )
            return HRESULT_FROM_WIN32( GetLastError() );
        DWORD dwRead;
        if( 0 == ReadFile( hFile, buffer, buffersize, &dwRead, NULL ) )
            hr = HRESULT_FROM_WIN32( GetLastError() );
        return hr;
    }
    

XAudio2 構造体に RIFF チャンクの内容を設定する

XAudio2 がソース音声でオーディオを再生するには、WAVEFORMATEX 構造体と XAUDIO2_BUFFER 構造体が必要です。 WAVEFORMATEX 構造体は、最初のメンバーとして WAVEFORMATEX 構造体を含 WAVEFORMATEXTENSIBLE などの大きな構造体である場合があります。 詳細については、WAVEFORMATEX 参照資料を参照してください。

この例では、WAVEFORMATEXTENSIBLE を使用して、2 つ以上のチャネルを持つ PCM オーディオ ファイルの読み込みを許可します。

次の手順では、上記の関数を使用して、WAVEFORMATEXTENSIBLE 構造体と XAUDIO2_BUFFER 構造体を設定する方法を示しています。 この場合、読み込まれるオーディオ ファイルには PCM データが含まれ、「RIFF」、「fmt」、および「data」チャンクのみが含まれます。 他の形式には、「Resource Interchange File Format(RIFF)」で説明されているように追加のチャンクの種類が含まれる場合があります。

  1. WAVEFORMATEXTENSIBLE 構造体および XAUDIO2_BUFFER 構造体を宣言します。

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. CreateFile でオーディオ ファイルを開きます。

    #ifdef _XBOX
    char * strFileName = "game:\\media\\MusicMono.wav";
    #else
    TCHAR * strFileName = _TEXT("media\\MusicMono.wav");
    #endif
    // Open the file
    HANDLE hFile = CreateFile(
        strFileName,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL );
    
    if( INVALID_HANDLE_VALUE == hFile )
        return HRESULT_FROM_WIN32( GetLastError() );
    
    if( INVALID_SET_FILE_POINTER == SetFilePointer( hFile, 0, NULL, FILE_BEGIN ) )
        return HRESULT_FROM_WIN32( GetLastError() );
    
  3. オーディオ ファイル内で「RIFF」チャンクを見つけて、ファイルの種類を確認します。

    DWORD dwChunkSize;
    DWORD dwChunkPosition;
    //check the file type, should be fourccWAVE or 'XWMA'
    FindChunk(hFile,fourccRIFF,dwChunkSize, dwChunkPosition );
    DWORD filetype;
    ReadChunkData(hFile,&filetype,sizeof(DWORD),dwChunkPosition);
    if (filetype != fourccWAVE)
        return S_FALSE;
    
  4. 「fmt」チャンクを見つけて、その内容を WAVEFORMATEXTENSIBLE 構造体にコピーします。

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. 「data」チャンクを見つけて、その内容をバッファーに読み取ります。

    //fill out the audio data buffer with the contents of the fourccDATA chunk
    FindChunk(hFile,fourccDATA,dwChunkSize, dwChunkPosition );
    BYTE * pDataBuffer = new BYTE[dwChunkSize];
    ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition);
    
  6. XAUDIO2_BUFFER 構造体を設定します。

    buffer.AudioBytes = dwChunkSize;  //size of the audio buffer in bytes
    buffer.pAudioData = pDataBuffer;  //buffer containing audio data
    buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer