Воспроизведение звука с помощью XAudio2 c++

Последние пару дней я делал аудиоплеер на С++. Я следил за учебником по msdn, как воспроизводить аудио с помощью XAudio2. Мне удалось сделать правильный код, но учебник по msds действительно запутанный и плохой. Поэтому я хотел опубликовать свой код здесь, чтобы было намного проще для всех, кто столкнулся с той же проблемой, что и я.

#include <xaudio2.h>
#include <iostream>
using namespace std;

#ifdef _XBOX 
#define fourccRIFF 'RIFF'
#define fourccDATA 'data'
#define fourccFMT 'fmt '
#define fourccWAVE 'WAVE'
#define fourccXWMA 'XWMA'
#define fourccDPDS 'dpds'
#endif

#ifndef _XBOX
#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;
}

int main()
{
    HRESULT hr;
    hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
    if (FAILED(hr))
        cout << hr;

    IXAudio2* pXAudio2 = nullptr;
    if (FAILED(hr = XAudio2Create(&pXAudio2, 0, XAUDIO2_DEFAULT_PROCESSOR)))
        cout << hr;

    IXAudio2MasteringVoice* pMasterVoice = nullptr;
    if (FAILED(hr = pXAudio2->CreateMasteringVoice(&pMasterVoice)))
        cout << hr;

    WAVEFORMATEXTENSIBLE wfx = { 0 };
    XAUDIO2_BUFFER buffer = { 0 };

#ifdef _XBOX
    char* strFileName = "s.wav";
#else
    const TCHAR* strFileName = TEXT("s.wav");
#endif
    HANDLE hFile = CreateFile(
        strFileName,
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);

    if (INVALID_HANDLE_VALUE == hFile)
        cout << HRESULT_FROM_WIN32(GetLastError());

    if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile, 0, NULL, FILE_BEGIN))
        cout << HRESULT_FROM_WIN32(GetLastError());

    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;

    FindChunk(hFile, fourccFMT, dwChunkSize, dwChunkPosition);
    ReadChunkData(hFile, &wfx, dwChunkSize, dwChunkPosition);

    FindChunk(hFile, fourccDATA, dwChunkSize, dwChunkPosition);
    BYTE* pDataBuffer = new BYTE[dwChunkSize];
    ReadChunkData(hFile, pDataBuffer, dwChunkSize, dwChunkPosition);

    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

    IXAudio2SourceVoice* pSourceVoice;
    if (FAILED(hr = pXAudio2->CreateSourceVoice(&pSourceVoice, (WAVEFORMATEX*)&wfx))) cout << hr;

    if (FAILED(hr = pSourceVoice->SubmitSourceBuffer(&buffer)))
        cout << hr;

    if (FAILED(hr = pSourceVoice->Start(0)))
        cout << hr;

    cout << "playing" << endl;
    cin.get();
}

Это код для воспроизведения звука с помощью XAudio2. PS: Похоже, он может воспроизводить только файлы .wav. Если кто-нибудь знает, как воспроизводить файлы .mp3 с помощью XAudio2, я был бы признателен за любой ответ.


person dimke123    schedule 06.05.2021    source источник
comment
Каков ваш актуальный вопрос? Это Как воспроизвести .mp3 файлы с помощью XAudio2? Если да, то это было бы лучшим названием для вашего вопроса. Воспроизвести MP3 из файла с именем @ social.msdn   -  person Ted Lyngmo    schedule 06.05.2021
comment
MSDN сообщает, что XAudio2 поддерживает типы голоса PCM и ADPCM. но MP3 не содержит звука PCM. Вам понадобится кодек MP3 для декодирования файлов MP3 в PCM.   -  person MSalters    schedule 06.05.2021


Ответы (1)


XAudio2 предназначен для преобразования исходной скорости в реальном времени, микширования и применения звуковых эффектов для данных PCM и ADPCM. XAudio 2.9 также поддерживает вариант «xWMA» форматов Microsoft Media, а на Xbox — аппаратный формат XMA2.

Чтобы воспроизвести другие форматы, вам необходимо распаковать его на ЦП и передать в поток голоса XAudio2 с использованием данных формата PCM. Пример этого см. в разделе XAudio2MFStream. который выполняет такую ​​потоковую передачу из файлов WMA с помощью Windows Media Foundation. Вы можете использовать какую-нибудь стороннюю библиотеку для воспроизведения MP3, OGG или чего-то еще, делая то же самое.

Вы также можете найти использование DirectX Tool Kit для аудио, включенного в оба DX11. и DX12.

person Chuck Walbourn    schedule 06.05.2021