Anleitung: Laden von Audiodatendateien in XAudio2
Hinweis
Dieser Inhalt gilt nur für Desktop-Apps und (und würde eine Überarbeitung erfordern, um in einer UWP-App zu funktionieren). Bitte lesen Sie die Dokumentation für CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx und GetOverlappedResultEx. Sehen Sie sich SoundFileReader.h
und .cpp
in der Windows 8-Beispiel-App für BasicSound aus dem jetzt archivierten Windows SDK-Beispielkatalog an.
So füllen Sie die Strukturen auf, die zum Wiedergeben von Audiodaten in XAudio2 erforderlich sind:
- Sie können eine Audiodatei laden oder streamen,
- oder selbst eine Waveform erzeugen und sie als Samples in einem Puffer anzeigen (siehe Ein komplettes einfaches XAudio2-Projekt).
In diesem Thema geht es um die Methode zum Laden einer Audiodatei. Mit den folgenden Schritten werden die Blöcke fmt
und data
einer Audiodatei geladen und verwendet, um eine WAVEFORMATEXTENSIBLE-Struktur und eine XAUDIO2_BUFFER-Struktur aufzufüllen.
Vorbereiten der Analyse der Audiodatei
Von XAudio2 unterstützte Audiodateien sind mit dem Resource Interchange File Format (RIFF) formatiert. RIFF wird im Thema Resource Interchange File Format (RIFF) beschrieben. Audiodaten in einer RIFF-Datei werden geladen, indem der RIFF-Block gesucht und dann einen Schleifendurchlauf durch den Block durchgeführt wird, um einzelne Blöcke zu finden, die im RIFF-Block enthalten sind. Die folgenden Funktionen sind Beispiele für Code zum Suchen von Blöcken und Laden von Daten, 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; }
So lesen Sie Daten in einem Abschnitt, nachdem sie lokalisiert wurden
Nachdem ein gewünschter Block gefunden wurde, können seine Daten gelesen werden, indem der Dateizeiger an den Anfang des Datenabschnitts des Blocks gesetzt wird. Eine Funktion zum Lesen der Daten aus einem Block, nachdem dieser gefunden wurde, 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, wird eine WAVEFORMATEX-Struktur und eine XAUDIO2_BUFFER-Struktur benötigt. Die WAVEFORMATEX-Struktur kann eine größere Struktur wie WAVEFORMATEXTENSIBLE sein, die eine WAVEFORMATEX-Struktur als erstes Member enthält. Weitere Informationen finden Sie auf der Referenzseite für WAVEFORMATEX.
In diesem Beispiel wird 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 nur einen "RIFF"-, "fmt"- und "data"-Block. Andere Formate können zusätzliche Blocktypen enthalten, wie unter Resource Interchange File Format (RIFF) beschrieben.
Deklarieren Sie WAVEFORMATEXTENSIBLE- und XAUDIO2_BUFFER-Strukturen.
WAVEFORMATEXTENSIBLE wfx = {0}; XAUDIO2_BUFFER buffer = {0};
Ö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() );
Suchen Sie in der Audiodatei nach dem Abschnitt "RIFF", 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;
Suchen Sie den "fmt"-Block, und kopieren Sie den Inhalt in eine WAVEFORMATEXTENSIBLE-Struktur.
FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition ); ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
Suchen Sie den "data"-Block, und lesen Sie den Inhalt in einem 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);
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