Поделиться через


Руководство: загрузка файлов звуковых данных в XAudio2

Примечание

Это содержимое применяется только к классическим приложениям и потребует редакции для работы в приложении Магазина Windows. Ознакомьтесь с документацией по CreateFile2, CreateEventEx, WaitForSingleObjectEx, SetFilePointerEx и GetOverlappedResultEx. См. раздел SoundFileReader.h/.cpp в примере basicSound Windows 8 из коллекции примеров windows SDK.

 

В этом разделе описываются действия по заполнению структур, необходимых для воспроизведения звуковых данных в XAudio2. Следующие шаги загружают блоки "fmt" и "data" звукового файла и используют их для заполнения структуры WAVEFORMATEXTENSIBLE и структуры XAUDIO2_BUFFER .

Подготовка к анализу звукового файла

Звуковые файлы, поддерживаемые XAudio2, используют формат RIFF. RIFF описано в обзоре формата файлов обмена ресурсами (RIFF). Звуковые данные в RIFF-файле загружаются путем поиска блока RIFF, а затем циклического перебора блока для поиска отдельных блоков, содержащихся в блоке RIFF. Ниже приведены примеры кода для поиска блоков и загрузки данных, содержащихся в блоках.

  • Чтобы найти фрагмент в 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;
    
    }
    
  • Чтение данных в блоке после их расположения.

    После обнаружения нужного фрагмента его данные можно считать, настроив указатель файла на начало раздела данных блока. Функция для чтения данных из блока после его обнаружения может выглядеть следующим образом.

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

Заполнение структур XAudio2 содержимым блоков RIFF

Чтобы XAudio2 воспроизводил звук с помощью исходного голоса, ему требуется структура WAVEFORMATEX и структура XAUDIO2_BUFFER . Структура WAVEFORMATEX может быть более крупной, например WAVEFORMATEXTENSIBLE , которая содержит структуру WAVEFORMATEX в качестве первого члена. Дополнительные сведения см. на справочной странице WAVEFORMATEX .

В этом примере используется WAVEFORMATEXTENSIBLE , чтобы разрешить загрузку аудиофайлов PCM с более чем двумя каналами.

Следующие шаги демонстрируют использование описанных выше функций для заполнения структуры WAVEFORMATEXTENSIBLE и структуры XAUDIO2_BUFFER . В этом случае загружаемый звуковой файл содержит данные PCM и будет содержать только фрагменты RIFF, fmt и data. Другие форматы могут содержать дополнительные типы блоков, как описано в разделе Формат файла обмена ресурсами (RIFF).

  1. Объявите структуры WAVEFORMATEXTENSIBLE и XAUDIO2_BUFFER.

    WAVEFORMATEXTENSIBLE wfx = {0};
    XAUDIO2_BUFFER buffer = {0};
    
  2. Откройте звуковой файл с помощью команды 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. Найдите фрагмент RIFF в звуковом файле и проверка тип файла.

    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. Найдите блок fmt и скопируйте его содержимое в структуру WAVEFORMATEXTENSIBLE .

    FindChunk(hFile,fourccFMT, dwChunkSize, dwChunkPosition );
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition );
    
  5. Найдите блок data и считайте его содержимое в буфер.

    //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. Заполните структуру 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
    

Начало работы

Руководство: воспроизведение звука при помощи XAudio2

Справочник по программированию в XAudio2