如何:在 XAudio2 中加载音频数据文件
注意
此内容仅适用于桌面应用,需要修订才能在 Windows 应用商店应用中正常运行。 请参阅 CreateFile2、 CreateEventEx、 WaitForSingleObjectEx、 SetFilePointerEx 和 GetOverlappedResultEx 的文档。 请参阅 Windows SDK 示例库中 BasicSound Windows 8 示例中的 SoundFileReader.h/.cpp。
本主题介绍填充在 XAudio2 中播放音频数据所需的结构的步骤。 以下步骤加载音频文件的“fmt”和“data”区块,并使用它们填充 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; }
使用 RIFF 区块的内容填充 XAudio2 结构
为了使 XAudio2 能够使用源语音播放音频,它需要 一个 WAVEFORMATEX 结构和 一个XAUDIO2_BUFFER 结构。 WAVEFORMATEX 结构可以是更大的结构,例如将一个 WAVEFORMATEX 结构作为其第一个成员的 WAVEFORMATEXTENSIBLE。 有关详细信息,请参阅 WAVEFORMATEX 参考页。
在此示例中,使用 WAVEFORMATEXTENSIBLE 来允许加载具有两个以上通道的 PCM 音频文件。
以下步骤演示如何使用上述函数填充 WAVEFORMATEXTENSIBLE 结构和 XAUDIO2_BUFFER 结构。 在这种情况下,要加载的音频文件包含 PCM 数据,并且仅包含“RIFF”、“fmt”和“data”区块。 其他格式可能包含其他区块类型,如 资源交换文件格式 (RIFF) 中所述。
声明 WAVEFORMATEXTENSIBLE 和 XAUDIO2_BUFFER 结构。
WAVEFORMATEXTENSIBLE wfx = {0}; XAUDIO2_BUFFER buffer = {0};
使用 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() );
在音频文件中找到“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;
找到“fmt”区块,并将其内容复制到 WAVEFORMATEXTENSIBLE 结构中。
FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition ); ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
找到“数据”区块,并将其内容读入缓冲区。
//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);
填充 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
相关主题
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈