在 xaudio2 中集成 3D 音频

Integrating 3D audio in xaudio2

我正在关注 xaudio2 的 msdn 教程。 2D 音频工作正常,但当我尝试集成 3D 音频时,它就是不工作。

#include <xaudio2.h>
#include <x3daudio.h>
#include <assert.h>
#include <iostream>
#pragma comment(lib,"xaudio2.lib") 

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

int main()
{
    IXAudio2* pXAudio2;
    IXAudio2MasteringVoice* pMasterVoice;
    IXAudio2SourceVoice* pSource;
    X3DAUDIO_HANDLE X3DInstance;
    WAVEFORMATEXTENSIBLE wfx = { 0 };
    XAUDIO2_BUFFER buffer = { 0 };

    HRESULT hr;

    assert(SUCCEEDED(hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED)));

    assert(SUCCEEDED(hr = XAudio2Create(&pXAudio2, XAUDIO2_DEBUG_ENGINE, XAUDIO2_DEFAULT_PROCESSOR)));

    assert(SUCCEEDED(hr = pXAudio2->CreateMasteringVoice(&pMasterVoice)));

    //XAUDIO2_DEBUG_CONFIGURATION debug;
    //pXAudio2->SetDebugConfiguration(&debug);

    DWORD dwChannelMask;
    pMasterVoice->GetChannelMask(&dwChannelMask);

    assert(SUCCEEDED(hr = X3DAudioInitialize(dwChannelMask, X3DAUDIO_SPEED_OF_SOUND, X3DInstance)));

    X3DAUDIO_LISTENER Listener = {};
    X3DAUDIO_EMITTER Emitter = {};
    Emitter.ChannelCount = 1;
    Emitter.CurveDistanceScaler = FLT_MIN;

    XAUDIO2_VOICE_DETAILS details;
    pMasterVoice->GetVoiceDetails(&details);

    X3DAUDIO_DSP_SETTINGS DSPSettings = { 0 };
    FLOAT32* matrix = new FLOAT32[details.InputChannels];
    DSPSettings.SrcChannelCount = 1;
    DSPSettings.DstChannelCount = details.InputChannels;
    DSPSettings.pMatrixCoefficients = matrix;


    Emitter.OrientFront = { -1, 0, 0 };
    Emitter.OrientTop = { 0, 1, 0 };
    Emitter.Position = { 5, 2, 3 };
    Emitter.Velocity = { 0, 0, 0 };
    Listener.OrientFront = { 1, 0, 0 };
    Listener.OrientTop = { 0, 1, 0 };
    Listener.Position = { 0, 0, 0 };
    Listener.Velocity = { 0, 0, 0 };

    HANDLE hFile = CreateFile(
        (LPCSTR)"woodBreak.wav",
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        0,
        NULL);


    SetFilePointer(hFile, 0, NULL, FILE_BEGIN);

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

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

    //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);

    buffer.AudioBytes = dwChunkSize;
    buffer.pAudioData = pDataBuffer;
    buffer.Flags = XAUDIO2_END_OF_STREAM;
    buffer.LoopCount = XAUDIO2_LOOP_INFINITE;

    
    assert(SUCCEEDED(hr = pXAudio2->CreateSourceVoice(&pSource, (WAVEFORMATEX*)&wfx)));
    assert(SUCCEEDED(hr = pSource->SubmitSourceBuffer(&buffer)));

    X3DAudioCalculate(X3DInstance, &Listener, &Emitter,
        X3DAUDIO_CALCULATE_MATRIX | X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_REVERB,
        &DSPSettings);

    assert(SUCCEEDED(hr = pSource->SetFrequencyRatio(DSPSettings.DopplerFactor)));
    assert(SUCCEEDED(hr = pSource->SetOutputMatrix(pMasterVoice, 1, details.InputChannels, DSPSettings.pMatrixCoefficients)));

    pSource->Start();

    int i;
    std::cin >> i;

    return 0;
}

问题出在我尝试应用 3d 音频时,但是当我 运行 代码时,断言触发代码 88960001 https://docs.microsoft.com/en-us/windows/win32/xaudio2/xaudio2-error-codes

如果有人有任何想法,请告诉我。 我先谢谢你了。

首先,您可能希望为 XAudio2 启用调试以帮助您跟踪问题。参见 Microsoft Docs

您得到的 HRESULT (88960001) 是 XAUDIO2_E_INVALID_CALL

你的代码有两个问题(除了评论中提到的 assert 的滥用):

  1. 您的 HRESULT 失败很可能是因为您的代码仅适用于单通道/单声道 wav 文件。

  2. 即使您解决了这个问题,您仍然会听到静音,因为您将 Emitter.CurveDistanceScaler 设置为一个愚蠢的值。将其设置为 1 开始。

For the latest XAudio2 samples for Win32 desktop, see GitHub. There are additional samples for Universal Windows Platform (UWP) here.

You may also want to look at the DirectX Tool Kit for Audio in the DirectX Tool Kit DX11 / DX12.