Como: carregar arquivos de dados de áudio no XAudio2
Observação
Este conteúdo se aplica somente a aplicativos de desktop (e exigirá revisão para funcionar em um aplicativo UWP). Consulte a documentação para CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx e GetOverlappedResultEx. Confira SoundFileReader.h
e .cpp
no aplicativo de exemplo BasicSound do Windows 8 da Galeria de Exemplos do SDK do Windows agora arquivado.
Para preencher as estruturas necessárias para reproduzir dados de áudio no XAudio2:
- Você pode carregar ou transmitir um arquivo de áudio
- ou você pode gerar uma forma de onda própria e representar essa forma de onda como exemplos em um buffer (consulte Um projeto do XAudio2 simples na íntegra).
Este tópico é voltado ao método de carregamento de um arquivo de áudio. As etapas a seguir carregam os trechos fmt
e data
de um arquivo de áudio e os utilizam para preencher uma estrutura WAVEFORMATEXTENSIBLE e uma estrutura XAUDIO2_BUFFER.
Preparando-se para analisar o arquivo de áudio
Os arquivos de áudio compatíveis com o XAudio2 são formatados com o RIFF (Resource Interchange File Format). RIFF é descrito no tópico Resource Interchange File Format (RIFF). Os dados de áudio em um arquivo RIFF são carregados localizando o trecho do RIFF e, em seguida, percorrendo o trecho para encontrar trechos individuais contidos no trecho do RIFF. As funções a seguir são exemplos de código para localizar trechos e carregar dados contidos nos trechos.
Para encontrar um trecho em um arquivo 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; }
Para ler dados em um trecho depois de terem sido localizados.
Depois que um trecho desejado for encontrado, seus dados poderão ser lidos ajustando o ponteiro do arquivo para o início da seção de dados do trecho. Uma função para ler os dados de um trecho, uma vez encontrado, pode ter esta aparência.
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; }
Preenchendo estruturas do XAudio2 com o conteúdo de trechos do RIFF
Para que o XAudio2 reproduza áudio com uma voz de origem, ele precisa de uma estrutura WAVEFORMATEX e uma estrutura XAUDIO2_BUFFER. A estrutura WAVEFORMATEX pode ser uma estrutura maior, como WAVEFORMATEXTENSIBLE que contém uma estrutura WAVEFORMATEX como seu primeiro membro. Consulte a página de referência WAVEFORMATEX para obter mais informações.
Neste exemplo, um WAVEFORMATEXTENSIBLE está sendo usado para permitir o carregamento de arquivos de áudio PCM com mais de dois canais.
As etapas a seguir ilustram o uso das funções descritas acima para preencher uma estrutura WAVEFORMATEXTENSIBLE e uma estrutura XAUDIO2_BUFFER. Neste caso, o arquivo de áudio que está sendo carregado contém dados PCM e conterá apenas um trecho do 'RIFF', 'fmt' e 'data'. Outros formatos podem conter tipos de trechos adicionais, conforme descrito em Resource Interchange File Format (RIFF).
Declare estruturas WAVEFORMATEXTENSIBLE e XAUDIO2_BUFFER.
WAVEFORMATEXTENSIBLE wfx = {0}; XAUDIO2_BUFFER buffer = {0};
Abra o arquivo de áudio com 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() );
Localize o trecho 'RIFF' no arquivo de áudio e verifique o tipo de arquivo.
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;
Localize o trecho 'fmt' e copie seu conteúdo em uma estrutura WAVEFORMATEXTENSIBLE.
FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition ); ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
Localize o trecho de 'dados' e leia seu conteúdo em um buffer.
//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);
Preencha uma estrutura 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