Compartir a través de


Cómo: cargar archivos de datos de audio en XAudio2

Nota

Este contenido solo se aplica a las aplicaciones de escritorio y requerirá revisión para funcionar en una aplicación de la Tienda Windows. Consulte la documentación de CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx y GetOverlappedResultEx. Consulte SoundFileReader.h/.cpp en el ejemplo BasicSound Windows 8 de la Galería de ejemplos de Windows SDK.

 

En este tema se describen los pasos para rellenar las estructuras necesarias para reproducir datos de audio en XAudio2. Los pasos siguientes cargan los fragmentos "fmt" y "data" de un archivo de audio y los usa para rellenar una estructura WAVEFORMATEXTENSIBLE y una estructura XAUDIO2_BUFFER .

Preparación para analizar el archivo de audio

Los archivos de audio compatibles con XAudio2 usan el formato de archivo de intercambio de recursos (RIFF). RIFF se describe en la introducción al formato de archivo de intercambio de recursos (RIFF ). Los datos de audio de un archivo RIFF se cargan mediante la búsqueda del fragmento RIFF y, a continuación, recorren el fragmento para buscar fragmentos individuales incluidos en el fragmento RIFF. Las siguientes funciones son ejemplos de código para buscar fragmentos y cargar datos contenidos en los fragmentos.

  • Para buscar un fragmento en un archivo 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 leer datos en un fragmento después de que se haya localizado.

    Una vez que se encuentra un fragmento deseado, sus datos se pueden leer ajustando el puntero de archivo al principio de la sección de datos del fragmento. Una función para leer los datos de un fragmento una vez que se encuentra podría tener este aspecto.

    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;
    }
    

Rellenar estructuras XAudio2 con el contenido de fragmentos RIFF

Para que XAudio2 reproduzca audio con una voz de origen, necesita una estructura WAVEFORMATEX y una estructura XAUDIO2_BUFFER . La estructura WAVEFORMATEX puede ser una estructura más grande, como WAVEFORMATEXTENSIBLE , que contiene una estructura WAVEFORMATEX como primer miembro. Consulte la página de referencia WAVEFORMATEX para obtener más información.

En este ejemplo se usa WAVEFORMATEXTENSIBLE para permitir la carga de archivos de audio PCM con más de dos canales.

Los pasos siguientes muestran el uso de las funciones descritas anteriormente para rellenar una estructura WAVEFORMATEXTENSIBLE y una estructura de XAUDIO2_BUFFER . En este caso, el archivo de audio que se carga contiene datos PCM y solo contendrá un fragmento "RIFF", "fmt" y "data". Otros formatos pueden contener tipos de fragmentos adicionales, como se describe en Formato de archivo de intercambio de recursos (RIFF).

  1. Declare las estructuras WAVEFORMATEXTENSIBLE y XAUDIO2_BUFFER .

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. Abra el archivo de audio con 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. Busque el fragmento "RIFF" en el archivo de audio y compruebe el tipo de archivo.

    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. Busque el fragmento "fmt" y copie su contenido en una estructura WAVEFORMATEXTENSIBLE .

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. Busque el fragmento "data" y lea su contenido en un búfer.

    //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. Rellene una estructura de 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
    

Introducción

Cómo: reproducir un sonido con XAudio2

Referencia de programación de XAudio2