Condividi tramite


Procedura: Caricare file di dati audio in XAudio2

Nota

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

Per popolare le strutture necessarie per riprodurre dati audio in XAudio2:

  • È possibile caricare o trasmettere un file audio,
  • oppure è possibile generare una forma d'onda personalizzata e rappresentare tale forma d'onda come esempi in un buffer (vedere un semplice progetto XAudio2 completo).

Questo argomento è incentrato sul metodo di caricamento di un file audio. I passaggi seguenti caricano i blocchi e di un file audio e li usano per popolare una struttura WAVEFORMATEXTENSIBLE e una struttura XAUDIO2_BUFFER.data fmt

Preparazione per l'analisi del file audio

I file audio supportati da XAudio2 sono formattati con il formato RIFF (Resource Interchange File Format). RIFF è descritto nell'argomento Resource Interchange File Format (RIFF). I dati audio in un file RIFF vengono caricati trovando il blocco RIFF e quindi eseguendo un ciclo nel 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.

    Dopo aver trovato un blocco desiderato, i dati possono essere letti modificando il puntatore del file all'inizio della sezione dati del blocco. Una funzione per leggere i dati da un blocco una volta trovato potrebbe essere 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 di WAVEFORMATEX .

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

I passaggi seguenti illustrano 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).Other formats may contain additional chunk types as described in Resource Interchange File Format (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