我无法在 xaudio2 中播放两次声音

问题描述

我正在尝试设置 xaudio2 并且一直在关注文档。我可以很好地播放声音,直到我再次尝试播放,此时什么也没有发生。 我几乎一行一行地遵循文档,但无法弄清楚为什么会发生这种情况。 这是代码

        #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <xaudio2.h>
    #include <Windows.h>

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


    class VoiceCallback : public Ixaudio2VoiceCallback
    {
    public:
        void STDMETHODCALLTYPE OnStreamEnd() override
        {}
        void STDMETHODCALLTYPE OnVoiceProcessingPassEnd() override
        {}
        void STDMETHODCALLTYPE OnVoiceProcessingPassstart(UINT32 Samplesrequired) override
        {}
        void STDMETHODCALLTYPE OnBufferEnd(void* pBufferContext) override
        {
        
            std::cout << "buffer end" << std::endl;
        }
        void STDMETHODCALLTYPE OnBufferStart(void* pBufferContext) override
        {
            std::cout << "buffer start" << std::endl;
        }
        void STDMETHODCALLTYPE OnLoopEnd(void* pBufferContext) override
        {}
        void STDMETHODCALLTYPE OnVoiceError(void* pBufferContext,HRESULT Error) override
        {}
    };

    int main()
    {


        WAVEFORMATEXTENSIBLE wfx = { 0 };
        xaudio2_BUFFER buffer = { 0 };
        HANDLE hFile = CreateFileA(
            "meow.wav",GENERIC_READ,FILE_SHARE_READ,OPEN_EXISTING,NULL);

        if (INVALID_HANDLE_VALUE == hFile)
            return HRESULT_FROM_WIN32(GetLastError());

        if (INVALID_SET_FILE_POINTER == SetFilePointer(hFile,FILE_BEGIN))
            return 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);
        //fill out the audio data buffer with the contents of the fourccDATA chunk
        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



        HRESULT hr;
        VoiceCallback vcb;

        // initialize COM
        if (Failed(hr = CoInitializeEx(nullptr,COINITBASE_MULTITHREADED)))
        {
            return hr;
        }

        // audio engine initialized to nullptr
        Ixaudio2* audioEngine = nullptr;
        // initialize audio engine
        if ( Failed(hr = xaudio2Create(&audioEngine,0)))
        {
            return hr;
        }

        // create mastering voice
        Ixaudio2MasteringVoice* masteringVoice = nullptr;
        // initialize masterVoice
        if (Failed(hr = audioEngine->CreateMasteringVoice(&masteringVoice)))
        {
            return hr;
        }


        // create source voice
        Ixaudio2SourceVoice* sourceVoice = nullptr;
        // init source voice
        if (Failed(hr = audioEngine->CreateSourceVoice(&sourceVoice,(WAVEFORMATEX*)&wfx,0u,2.0f,&vcb)))
        {
            return hr;
        }
        // submit audio buffer to source voice
        if (Failed(hr = sourceVoice->SubmitSourceBuffer(&buffer)))
        {
            return hr;
        }


        bool over = false;
        while (!over)
        {
            if (GetAsyncKeyState('S'))
            {
                over = true;
            }
            if (GetAsyncKeyState('M'))
            {


                if (Failed(hr = sourceVoice->Start(0)))
                {
                    return hr;
                }
            

            }
            if (GetAsyncKeyState('A'))
            {
                sourceVoice->Stop();
            }
   
        }


        audioEngine->Release();
        audioEngine = nullptr;

        masteringVoice = nullptr;

        CoUninitialize();


    }

感谢任何帮助。

解决方法

单个XAudio2源语音只能播放或不播放。它不能播放“两次”。如果您想要重叠播放的相同声音,您需要有两个 XAudio2 源声音处于活动状态。您可以根据需要将相同的音频提交为多种不同格式的兼容语音。请记住,您的音频数据仍保留在应用程序的内存中,每个源语音只是直接从那里读取它(即,没有像 DirectSound 那样复制所有源数据)。

XAudio2 是一款“实时混音器”,用于处理游戏中的复杂声音。如果您只想播放 WAV 文件,那么旧的 Win32 import openvino.inference_engine.constants 函数就是这样做的。

如果要再次播放相同的声音,则必须再次提交音频包。如果重复执行,它会一直循环。

或者,您可以在播放时设置循环计数,以便一遍又一遍地重复使用相同的提交数据包。

您应该查看 DirectX Tool Kit for Audio 以获取基于 XAudio2 的简单音频库。它支持您在这里尝试做的“一次性”声音,以及循环声音、语音管理、位置音频、环境效果、基于文件的流媒体等。