Share via


Procedura: Caricare file di dati audio in XAudio2

Nota

Questo contenuto si applica solo alle app desktop e richiederà la revisione per funzionare in un'app di Windows Store. Fare riferimento alla documentazione per CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx e GetOverlappedResultEx. Vedere SoundFileReader.h/.cpp nell'esempio basicSound Windows 8 dalla raccolta di esempi di Windows SDK.

 

Questo argomento descrive i passaggi per popolare le strutture necessarie per riprodurre dati audio in XAudio2. I passaggi seguenti caricano i blocchi "fmt" e "data" di un file audio e li usa per popolare una struttura WAVEFORMATEXTENSIBLE e una struttura XAUDIO2_BUFFER .

Preparazione dell'analisi del file audio

I file audio supportati da XAudio2 usano il formato RIFF (Resource Interchange File Format). RIFF è descritto nella panoramica del formato di file di interscambio delle risorse .RIFF (Resource Interchange File Format). I dati audio in un file RIFF vengono caricati trovando il blocco RIFF e quindi eseguendo un ciclo attraverso il blocco per trovare singoli blocchi contenuti nel blocco RIFF. Le funzioni seguenti sono esempi di codice per trovare blocchi e caricare i dati contenuti nei blocchi.

  • Per trovare un blocco in un file 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;
    
    }
    
  • Per leggere i dati in un blocco dopo che è stato individuato.

    Una volta trovato un blocco desiderato, i dati possono essere letti modificando il puntatore del file all'inizio della sezione dei dati del blocco. Una funzione per leggere i dati da un blocco dopo che è stato trovato potrebbe avere un aspetto simile al seguente.

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

Popolamento delle strutture XAudio2 con il contenuto dei blocchi RIFF

Per consentire a XAudio2 di riprodurre l'audio con una voce di origine, è necessaria una struttura WAVEFORMATEX e una struttura XAUDIO2_BUFFER . La struttura WAVEFORMATEX può essere una struttura più grande, ad esempio WAVEFORMATEXTENSIBLE che contiene una struttura WAVEFORMATEX come primo membro. Per altre informazioni, vedere la pagina di riferimento WAVEFORMATEX .

In questo esempio viene usato waveFORMATEXTENSIBLE per consentire il caricamento di file audio PCM con più di due canali.

La procedura seguente illustra l'uso delle funzioni descritte in precedenza per popolare una struttura WAVEFORMATEXTENSIBLE e una struttura XAUDIO2_BUFFER . In questo caso, il file audio caricato contiene dati PCM e conterrà solo un blocco "RIFF", "fmt " e "data". Altri formati possono contenere tipi di blocchi aggiuntivi, come descritto in Formato file interscambio risorse (RIFF).

  1. Dichiarare strutture WAVEFORMATEXTENSIBLE e XAUDIO2_BUFFER .

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. Aprire il file 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. Individuare il blocco "RIFF" nel file audio e controllare il tipo di file.

    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. Individuare il blocco "fmt" e copiarne il contenuto in una struttura WAVEFORMATEXTENSIBLE .

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. Individuare il blocco "data" e leggerne il contenuto in un 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. Popolare una struttura 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
    

Per iniziare

Procedura: Riprodurre un suono con XAudio2

Guida di riferimento alla programmazione di XAudio2