问题描述
我正在尝试设置 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 的简单音频库。它支持您在这里尝试做的“一次性”声音,以及循环声音、语音管理、位置音频、环境效果、基于文件的流媒体等。