微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用 XAudio2 C++ 播放音频

如何解决使用 XAudio2 C++ 播放音频

过去几天,我一直在用 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,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,NULL))
            hr = HRESULT_FROM_WIN32(GetLastError());
        switch (dwChunkType)
        {
        case fourccRIFF:
            dwRIFFDataSize = dwChunkDataSize;
            dwChunkDataSize = 4;
            if (0 == ReadFile(hFile,&dwFileType,NULL))
                hr = HRESULT_FROM_WIN32(GetLastError());
            break;
        default:
            if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile,dwChunkDataSize,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,FILE_BEGIN))
        return HRESULT_FROM_WIN32(GetLastError());
    DWORD dwRead;
    if (0 == ReadFile(hFile,buffer,buffersize,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,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,OPEN_EXISTING,NULL);

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

    if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile,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,dwChunkPosition);
    if (filetype != fourccwAVE)
        return S_FALSE;

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

    FindChunk(hFile,fourccDATA,dwChunkPosition);
    BYTE* pDataBuffer = new BYTE[dwChunkSize];
    ReadChunkData(hFile,pDataBuffer,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 文件。如果有人知道如何使用 xaudio2 播放 .mp3 文件,我将不胜感激。

解决方法

XAudio2 专为实时源速率转换、混合和应用 PCM 和 ADPCM 数据的音频效果而设计。 XAudio 2.9 还支持 Microsoft Media 格式的“xWMA”变体,以及在 Xbox 上的硬件辅助格式 XMA2。

要播放其他格式,您需要在 CPU 上将其解压缩并使用 PCM 格式数据将其流式传输为 XAudio2 语音。有关此示例,请参阅 XAudio2MFStream。它使用 Windows Media Foundation 从 WMA 文件执行这种流式传输。您可以使用一些 3rd 方库来播放 MP3、OGG 或任何做同样基本事情的东西。

您可能还会发现使用 DX11DX12 版本中包含的 DirectX Tool Kit for Audio 很有用。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。