Procédure : charger des fichiers de données audio dans XAudio2

Notes

Ce contenu s’applique uniquement aux applications de bureau et nécessite une révision pour fonctionner dans une application du Windows Store. Reportez-vous à la documentation pour CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx et GetOverlappedResultEx. Consultez SoundFileReader.h/.cpp dans l’exemple basicSound Windows 8 de la galerie d’exemples du SDK Windows.

 

Cette rubrique décrit les étapes à suivre pour remplir les structures requises pour lire les données audio dans XAudio2. Les étapes suivantes chargent les blocs « fmt » et « data » d’un fichier audio et les utilisent pour remplir une structure WAVEFORMATEXTENSIBLE et une structure XAUDIO2_BUFFER .

Préparation de l’analyse du fichier audio

Les fichiers audio pris en charge par XAudio2 utilisent le format RIFF (Resource Interchange File Format). RIFF est décrit dans la vue d’ensemble du format de fichier d’échange de ressources (RIFF). Les données audio d’un fichier RIFF sont chargées en recherchant le bloc RIFF, puis en effectuant une boucle dans le bloc pour rechercher des blocs individuels contenus dans le bloc RIFF. Les fonctions suivantes sont des exemples de code permettant de rechercher des blocs et de charger les données contenues dans les blocs.

  • Pour rechercher un bloc dans un fichier 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;
    
    }
    
  • Pour lire des données dans un bloc une fois qu’ils ont été localisés.

    Une fois qu’un bloc souhaité est trouvé, ses données peuvent être lues en ajustant le pointeur de fichier au début de la section de données du bloc. Une fonction permettant de lire les données d’un bloc une fois qu’il est trouvé peut ressembler à ceci.

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

Remplissage de structures XAudio2 avec le contenu des blocs RIFF

Pour que XAudio2 diffuse de l’audio avec une voix source, il a besoin d’une structure WAVEFORMATEX et d’une structure XAUDIO2_BUFFER . La structure WAVEFORMATEX peut être une structure plus grande telle que WAVEFORMATEXTENSIBLE qui contient une structure WAVEFORMATEX comme premier membre. Pour plus d’informations, consultez la page de référence WAVEFORMATEX .

Dans cet exemple, un OBJET WAVEFORMATEXTENSIBLE est utilisé pour permettre le chargement de fichiers audio PCM avec plus de deux canaux.

Les étapes suivantes illustrent l’utilisation des fonctions décrites ci-dessus pour remplir une structure WAVEFORMATEXTENSIBLE et une structure XAUDIO2_BUFFER . Dans ce cas, le fichier audio chargé contient des données PCM et ne contient qu’un bloc « RIFF », « fmt » et « data ». D’autres formats peuvent contenir des types de blocs supplémentaires, comme décrit dans Le format de fichier d’échange de ressources (RIFF).

  1. Déclarez WAVEFORMATEXTENSIBLE et XAUDIO2_BUFFER structures.

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. Ouvrez le fichier audio avec 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. Recherchez le bloc « RIFF » dans le fichier audio et case activée le type de fichier.

    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. Recherchez le bloc « fmt » et copiez son contenu dans une structure WAVEFORMATEXTENSIBLE .

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. Recherchez le bloc « data » et lisez son contenu dans une mémoire tampon.

    //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. Remplissez une structure 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
    

Prise en main

Procédure : lire un son avec XAudio2

Référence de programmation XAudio2