Partager via


Guide pratique : Charger des fichiers de données audio dans XAudio2

Remarque

Ce contenu s’applique uniquement aux applications de bureau (et nécessiterait une révision pour fonctionner dans une application UWP). Veuillez consulter la documentation pour CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx, et GetOverlappedResultEx. Veuillez consulter SoundFileReader.h et .cpp dans l’exemple d’application BasicSound pour Windows 8 de la Windows SDK Samples Gallery désormais archivée.

Pour remplir les structures nécessaires à la lecture des données audio dans XAudio2 :

  • Vous pouvez charger ou diffuser un fichier audio,
  • ou vous pouvez générer une forme d’onde de votre choix et représenter cette forme d’onde sous forme d’échantillons dans un buffer (veuillez consulter la section un projet XAudio2 simple en intégralité).

Cette rubrique se concentre sur la méthode de chargement d’un fichier audio. Les étapes suivantes consistent à charger les segments fmt et data d’un fichier audio et à les utiliser 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 sont formatés avec le Resource Interchange File Format (RIFF). Le format RIFF est décrit dans la rubrique Resource Interchange File Format (RIFF). Les données audio d’un fichier RIFF sont chargées en trouvant le segment RIFF, puis en parcourant le segment en boucle pour trouver les segments individuels contenus dans le segment RIFF. Les fonctions suivantes sont des exemples de code permettant de trouver les segments et de charger les données qu’ils contiennent.

  • Recherche d’un segment 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 les données d’un segment après qu’il a été localisé.

    Une fois que le segment 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 segment. Une fonction permettant de lire les données d’un segment une fois qu’il a été trouvé pourrait 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 des structures XAudio2 avec le contenu des segments RIFF

Pour que XAudio2 puisse lire 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 large telle que WAVEFORMATEXTENSIBLE qui contient une structure WAVEFORMATEX comme premier membre. Consultez la page de référence WAVEFORMATEX pour plus d’informations.

Dans cet exemple, un WAVEFORMATEXTENSIBLE est utilisé pour permettre le chargement de fichiers audio PCM comportant plus de deux chaînes.

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 contiendra qu’un segment ’RIFF’, ’fmt’, et ’data’. D’autres formats peuvent contenir des segments supplémentaires, comme décrit dans Resource Interchange File Format (RIFF).

  1. Déclarez les structures WAVEFORMATEXTENSIBLE et XAUDIO2_BUFFER.

    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. Localisez le segment ’RIFF’ dans le fichier audio et vérifiez 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. Localisez le segment ’fmt’ et copiez son contenu dans une structure WAVEFORMATEXTENSIBLE.

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. Localisez le segment ’data’ et lisez son contenu dans un 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