7.如何加载音频数据文件
本主题描述的步骤来填充所需的结构在XAudio2播放音频数据。以下步骤加载“fmt”和“data”块的一个音频文件,并使用它们来填充WAVEFORMATEXTENSIBLE结构和一个XAUDIO2_BUFFER结构。
- 准备解析音频文件。
- 填充XAudio2结构即兴重复的内容块。
准备解析音频文件。
支持的音频文件XAudio2使用资源文件交换格式(RIFF)。Resource Interchange File Format (RIFF)主题描述了RIFF。音频数据在RIFF文件中是通过遍历加载可用的RIFF块。以下代码展示了查找块并从块中加载数据。
-
从RIFF文件查找一个块(chunk)
请注意
windows是小端,Xbox 360是大端。音频文件上创建Windows使用Xbox 360需要的部分或全部数据交换字节序在运行时,或音频文件需要被处理在运行时执行字节交换。有关更多信息,请参见音频数据和字节顺序。
-
#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结构可能是一个更大的结构如WAVEFORMATEXTENSIBLE包含WAVEFORMATEX结构作为它的第一个成员。有关更多信息,请参见WAVEFORMATEX主题页面。
在这个例子一个WAVEFORMATEXTENSIBLE被用于允许加载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; //buffer containing audio data buffer.pAudioData = pDataBuffer; //size of the audio buffer in bytes buffer.Flags = XAUDIO2_END_OF_STREAM; // tell the source voice not to expect any data after this buffer