Compartilhar via


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).

  1. Declare estruturas WAVEFORMATEXTENSIBLE e XAUDIO2_BUFFER.

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. 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() );
    
  3. 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;
    
  4. Localize o trecho 'fmt' e copie seu conteúdo em uma estrutura WAVEFORMATEXTENSIBLE.

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. 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);
    
  6. 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