Freigeben über


So wird's gemacht: Laden von Datendateien in XAudio2

Hinweis

Dieser Inhalt gilt nur für Desktop-Apps und erfordert eine Überarbeitung, um in einer Windows Store-App zu funktionieren. Weitere Informationen finden Sie in der Dokumentation zu CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx und GetOverlappedResultEx. Weitere Informationen finden Sie unter SoundFileReader.h/.cpp im Beispiel BasicSound Windows 8 aus dem Windows SDK-Beispielkatalog.

 

In diesem Thema werden die Schritte zum Auffüllen der Strukturen beschrieben, die zum Wiedergeben von Audiodaten in XAudio2 erforderlich sind. Die folgenden Schritte laden die Blöcke "fmt" und "data" einer Audiodatei und verwenden sie, um eine WAVEFORMATEXTENSIBLE-Struktur und eine XAUDIO2_BUFFER Struktur aufzufüllen.

Vorbereiten der Analyse der Audiodatei

Von XAudio2 unterstützte Audiodateien verwenden das Resource Interchange File Format (RIFF). RIFF wird in der Übersicht über das Resource Interchange File Format (RIFF) beschrieben. Audiodaten in einer RIFF-Datei werden geladen, indem sie den RIFF-Block finden und dann den Block durchschleifen, um einzelne Blöcke zu finden, die im RIFF-Block enthalten sind. Die folgenden Funktionen sind Beispiele für Code, um Blöcke zu finden und Daten zu laden, die in den Blöcken enthalten sind.

  • So suchen Sie einen Block in einer RIFF-Datei:

    #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;
    
    }
    
  • Um Daten in einem Block zu lesen, nachdem er gefunden wurde.

    Sobald ein gewünschter Block gefunden wurde, können seine Daten gelesen werden, indem der Dateizeiger an den Anfang des Datenabschnitts des Blöckes angepasst wird. Eine Funktion zum Lesen der Daten aus einem Block, nachdem sie gefunden wurden, könnte wie folgt aussehen.

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

Auffüllen von XAudio2-Strukturen mit dem Inhalt von RIFF-Blöcken

Damit XAudio2 Audio mit einer Quellstimme wiedergeben kann, benötigt es eine WAVEFORMATEX-Struktur und eine XAUDIO2_BUFFER-Struktur . Die WAVEFORMATEX-Struktur kann eine größere Struktur wie WAVEFORMATEXTENSIBLE sein, die eine WAVEFORMATEX-Struktur als erstes Element enthält. Weitere Informationen finden Sie auf der WAVEFORMATEX-Referenzseite .

In diesem Beispiel wird ein WAVEFORMATEXTENSIBLE verwendet, um das Laden von PCM-Audiodateien mit mehr als zwei Kanälen zu ermöglichen.

Die folgenden Schritte veranschaulichen die Verwendung der oben beschriebenen Funktionen zum Auffüllen einer WAVEFORMATEXTENSIBLE-Struktur und einer XAUDIO2_BUFFER-Struktur . In diesem Fall enthält die geladene Audiodatei PCM-Daten und enthält nur die Blöcke "RIFF", "fmt" und "data". Andere Formate können zusätzliche Blocktypen enthalten, wie unter Resource Interchange File Format (RIFF) beschrieben.

  1. Deklarieren Sie WAVEFORMATEXTENSIBLE - und XAUDIO2_BUFFER-Strukturen .

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. Öffnen Sie die Audiodatei mit 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. Suchen Sie den Bereich "RIFF" in der Audiodatei, und überprüfen Sie den Dateityp.

    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. Suchen Sie den Fmt-Block, und kopieren Sie den Inhalt in eine WAVEFORMATEXTENSIBLE-Struktur .

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. Suchen Sie den Datenblock, und lesen Sie den Inhalt in einen Puffer.

    //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. Füllen Sie eine XAUDIO2_BUFFER-Struktur auf.

    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
    

Erste Schritte

So wird's gemacht: Wiedergeben von Ton mit XAudio2

XAudio2-Programmierreferenz