如何解决将正弦波流式传输到 XAudio2
我正在尝试编写一个通过 xaudio2 播放的非常简单的正弦波发生器。
目前正在播放声音,如果我调用 Win32XAudioInit() 然后调用 Win32PlayTone() 会播放一个提示音,并且在随后调用 Win32PlayTone() 时提示音会改变,但是几乎每次提示音都会有明显的咔嗒声变化。
我知道有几个原因可能会导致这种情况:
- 我没有跟踪相位偏移,这意味着新的波浪会错位。
- 我只是更新缓冲区指向的内存,而不考虑正在播放的内容。
关于#2,我不确定 XAudio 是否希望我创建一个新的 xaudio2_BUFFER 并在每次更改音调时重新提交,或者我是否应该以某种方式跟踪“播放头”的位置(因为缺少一个更好的术语)并且只更新已经播放的字节。
我知道 #2 是否有问题,如果我修复了它,我将无法听到我仍然受到问题 #1 的困扰。 我已经通读了 XAudio2 - Play generated sine,when changing frequency clicking sound,如果我知道 xaudio2 设置正确,我想我可以找出正弦波问题。
任何想法都会有所帮助,谢谢!
struct win32_audio_buffer
{
real32 Memory[44100 * 1]; // samples per buffer (44100) * channels 1
int BytesPerBuffer;
xaudio2_BUFFER XBuffer;
Ixaudio2 *XEngine;
Ixaudio2SourceVoice *SourceVoice;
WAVEFORMATEX WaveFormat;
};
// NOTE xaudio2
internal HRESULT
Win32XAudioInit(win32_audio_buffer *AudioBuffer)
{
// Initialize a COM:
HRESULT HRes;
HRes = CoInitializeEx(NULL,COINIT_MULTITHREADED);
if(Failed(HRes)) { return(HRes); }
// Init XAUdio Engine
AudioBuffer->XEngine = {};
if (Failed(HRes = xaudio2Create(&AudioBuffer->XEngine,xaudio2_DEFAULT_PROCESSOR)))
{ return HRes; }
// MASTER VOICE
Ixaudio2MasteringVoice* XAudioMasterVoice = nullptr;
if (Failed(HRes = AudioBuffer->XEngine->CreateMasteringVoice(&XAudioMasterVoice)))
{ return HRes; }
AudioBuffer->WaveFormat = {};
//int32 SamplesPerBuffer = 4410;
int SampleHz = 44100;
WORD Channels = 1;
WORD BitsPerChannel = 32; // 4 byte samples
int32 BufferSize = Channels * BitsPerChannel * SampleHz;
AudioBuffer->BytesPerBuffer = SampleHz * Channels;
AudioBuffer->WaveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; // or Could use WAVE_FORMAT_PCM WAVE_FORMAT_IEEE_FLOAT
AudioBuffer->WaveFormat.nChannels = Channels;
AudioBuffer->WaveFormat.nSamplesPerSec = SampleHz;
AudioBuffer->WaveFormat.wBitsPerSample = BitsPerChannel; // 32
AudioBuffer->WaveFormat.nBlockAlign = (Channels * BitsPerChannel) / 8;
AudioBuffer->WaveFormat.nAvgBytesPerSec = SampleHz * Channels * BitsPerChannel / 8;
AudioBuffer->WaveFormat.cbSize = 0; // set to zero for PCM or IEEE float
AudioBuffer->XBuffer.Flags = 0;
AudioBuffer->XBuffer.AudioBytes = SampleHz * Channels * BitsPerChannel / 8;
AudioBuffer->XBuffer.PlayBegin = 0;
AudioBuffer->XBuffer.PlayLength = 0;
AudioBuffer->XBuffer.LoopBegin = 0;
AudioBuffer->XBuffer.LoopLength = 0;
AudioBuffer->XBuffer.LoopCount = xaudio2_LOOP_INFINITE;
AudioBuffer->XBuffer.pContext = NULL;
AudioBuffer->XBuffer.pAudioData = (BYTE *)&AudioBuffer->Memory;
if(Failed(HRes = AudioBuffer->XEngine->CreateSourceVoice(&AudioBuffer->SourceVoice,(WAVEFORMATEX*)&AudioBuffer->WaveFormat)))
{ return HRes; }
if(Failed(HRes = AudioBuffer->SourceVoice->Start(0)))
{ return HRes; }
if(Failed(HRes = AudioBuffer->SourceVoice->SubmitSourceBuffer(&AudioBuffer->XBuffer)))
{ return HRes; }
return(S_OK);
}
internal HRESULT
Win32PlayTone(win32_audio_buffer *Buffer,int32 Hz)
{
real32 PI2 = (real32)6.28318; //530718;
for(int i = 0;
i < Buffer->BytesPerBuffer;
i++)
{
real32 CurrentSample = sinf(i * PI2 / 44100 * Hz);
Buffer->Memory[i] = CurrentSample;
}
return(S_OK);
}
解决方法
XAudio2 是完全异步的,因此在数据包完成之前,您不应更改播放数据包所指向的内存,否则您将获得如您描述的点击。
此外,当当前数据包完成时,如果您希望声音连续,您希望另一个已经排队。
请参阅这些资源以了解如何对 XAudio2 进行编程:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。