在 xaudio2 中集成 3D 音频

Posted

技术标签:

【中文标题】在 xaudio2 中集成 3D 音频【英文标题】:Integrating 3D audio in xaudio2 【发布时间】:2021-09-15 05:01:14 【问题描述】:

我正在关注 msdn 上的 xaudio2 教程。 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

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

【问题讨论】:

您似乎正在使用 XAudio 2.8 (Windows 8.x) 或 XAudio 2.9 (Windows 10 & XAudio2Redist)。您应该提及您使用哪个操作系统来帮助诊断问题。 我使用的是 Windows 10 2.9 版本 顺便说一句,不要使用断言来检查失败。考虑类似ThrowIfFailed。 【参考方案1】:

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

您得到的 HRESULT (88960001) 是 XAUDIO2_E_INVALID_CALL

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

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

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

有关 Win32 桌面的最新 XAudio2 示例,请参阅GitHub。还有其他适用于通用 Windows 平台 (UWP) here 的示例。

您可能还想查看 DirectX Tool Kit 中的 DirectX Tool Kit for Audio DX11 / DX12。

【讨论】:

您好,我已经编辑了代码,以便可以将其复制粘贴到主文件中,并且在项目属性下应该使用多字节字符而不是 unicode。如果您评论 SetOutputMatrix 并将 wav 文件添加到项目中,它应该播放正常的 2d 音频。如果可以,请花时间尝试。 “woodbreak.wav”是什么音频格式?在您的代码中,您假设它是单声道(1 声道)声音。

以上是关于在 xaudio2 中集成 3D 音频的主要内容,如果未能解决你的问题,请参考以下文章

Windows基础-使用XAudio2播放音频(本质是WASAPI)

XAudio2播放PCM

XAudio2学习之IXAudio2VoiceCallback回调

XAudio2学习之调节音量

XAudio2 是不是有最大声音数?

Mingw,XAudio2和GetProcAddress失败