- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我尝试在独占模式下使用 Windows Audio Session API (WASAPI) 播放简单的正弦波形,但无论我做什么,都会遇到声音故障。我一直在使用 MSDN Exclusive-Mode Streams example作为引用点,这里是稍微调整后的代码目前的样子。
设置代码:
-- <variable declarations, incl. "HRESULT hr; BYTE *pData;" > --
// also, hr is checked for errors every step of the way
hr = CoCreateInstance(
CLSID_MMDeviceEnumerator, NULL,
CLSCTX_ALL, IID_IMMDeviceEnumerator,
(void**)&pEnumerator);
hr = pEnumerator->GetDefaultAudioEndpoint(
eRender, eConsole, &pDevice);
hr = pDevice->Activate(
IID_IAudioClient, CLSCTX_ALL,
NULL, (void**)&pAudioClient);
REFERENCE_TIME DefaultDevicePeriod = 0, MinimumDevicePeriod = 0;
hr = pAudioClient->GetDevicePeriod(&DefaultDevicePeriod, &MinimumDevicePeriod);
WAVEFORMATEX wave_format = {};
wave_format.wFormatTag = WAVE_FORMAT_PCM;
wave_format.nChannels = 2;
wave_format.nSamplesPerSec = 44100;
wave_format.nAvgBytesPerSec = 44100 * 2 * 16 / 8;
wave_format.nBlockAlign = 2 * 16 / 8;
wave_format.wBitsPerSample = 16;
hr = pAudioClient->IsFormatSupported(
AUDCLNT_SHAREMODE_EXCLUSIVE,
&wave_format,
NULL // can't suggest a "closest match" in exclusive mode
);
hr = pAudioClient->Initialize(
AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
MinimumDevicePeriod,
MinimumDevicePeriod,
&wave_format,
NULL);
// Get the actual size of the allocated buffer.
hr = pAudioClient->GetBufferSize(&bufferFrameCount);
INT32 FrameSize_bytes = bufferFrameCount * wave_format.nChannels * wave_format.wBitsPerSample / 8;
hr = pAudioClient->GetService(
IID_IAudioRenderClient,
(void**)&pRenderClient);
hEvent = CreateEvent(nullptr, false, false, nullptr);
if (hEvent == INVALID_HANDLE_VALUE) { printf("CreateEvent failed\n"); return -1; }
hr = pAudioClient->SetEventHandle(hEvent);
缓冲区设置:
const size_t num_samples = FrameSize_bytes / sizeof(unsigned short);
unsigned short *samples = new unsigned short[num_samples];
float min = (float)(std::numeric_limits<unsigned short>::min)();
float max = (float)(std::numeric_limits<unsigned short>::max)();
float halfmax = max / 2.0;
float dt = 1.0 / (float)wave_format.nSamplesPerSec;
float freq = (float)wave_format.nSamplesPerSec / (float)bufferFrameCount;
for (int i = 0; i < num_samples/2; ++i) {
float t = (float)i * dt;
samples[2*i] = sin_minmax_Hz(min, max, freq, t);
samples[2*i + 1] = sin_minmax_Hz(min, max, freq, t);
}
hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
memcpy(pData, samples, FrameSize_bytes);
hr = pRenderClient->ReleaseBuffer(bufferFrameCount, flags);
DWORD taskIndex = 0;
hTask = AvSetMmThreadCharacteristics(TEXT("Pro Audio"), &taskIndex);
if (hTask == NULL) {
hr = E_FAIL;
IF_ERROR_EXIT(hr);
}
函数sin_minmax_Hz
定义如下:
#define TWO_PI (3.14159265359*2)
static inline float sin01(float alpha) {
return 0.5*sin(alpha) + 0.5;
}
static inline float sin_minmax_Hz(float min, float max, float freq_Hz, float t) {
return (max - min) / 2.0 * sin01(t * freq_Hz * TWO_PI);
}
回放:
hr = pAudioClient->Start(); // Start playing.
IF_ERROR_EXIT(hr);
// just play indefinitely
while (true) {
WaitForSingleObject(hEvent, INFINITE);
hr = pRenderClient->GetBuffer(bufferFrameCount, &pData);
memcpy(pData, samples, FrameSize_bytes);
hr = pRenderClient->ReleaseBuffer(bufferFrameCount, 0);
}
问题在于,在最小延迟时,正弦波通常会平稳播放大约 2 秒,然后开始出现大量混叠,听起来几乎像锯齿波。我在这里遗漏了什么吗?
(整个工作示例可以在 here 中找到。)
最佳答案
刚刚尝试了您的完整示例,IAudioClient::Initialize 失败并显示 AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED。这个错误是在 windows 7 中引入的,你运行的是 vista 吗?校正对齐的周期大小后,我得到了完美的正弦波。如果您的系统没有生成此错误,请尝试在 128 字节(不是位)边界上手动对齐缓冲区。否则这里是对齐代码:
hr = pAudioClient->Initialize(
AUDCLNT_SHAREMODE_EXCLUSIVE,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
MinimumDevicePeriod,
MinimumDevicePeriod,
&wave_format,
NULL);
if(hr == AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED) {
UINT32 nFramesInBuffer;
REFERENCE_TIME hnsPeriod;
hr = pAudioClient->GetBufferSize(&nFramesInBuffer);
IF_ERROR_EXIT(hr);
hnsPeriod = (REFERENCE_TIME)(REFTIMES_PER_SEC * nFramesInBuffer / wave_format.nSamplesPerSec + 0.5);
hr = pAudioClient->Release();
IF_ERROR_EXIT(hr);
hr = pDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
IF_ERROR_EXIT(hr);
hr = pAudioClient->Initialize(AUDCLNT_SHAREMODE_EXCLUSIVE, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, hnsPeriod, hnsPeriod, &wave_format, NULL);
IF_ERROR_EXIT(hr);
}
关于c++ - WASAPI:以最小延迟播放正弦波声音而没有故障(独占事件驱动模式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37754642/
当我在其中一个扬声器上打开独占模式音频流时,会发出奇怪的嗡嗡声。这种嗡嗡声不会在我的其他设备上的相同条件下发生,也不会在一般的独占推送模式或共享模式下发生。 问题似乎是 WASAPI 将周期设置为比我
我的一个类中有一个 double 值,并且有一个上限。 问题是当我尝试将此变量设置为大于其限制的值时。当发生这种情况时,我想将其设置为限制内最接近的值。 当我尝试时,尴尬的情况发生了 .getLimi
我有锁定每个函数(某个库的)的代码,我想对其进行优化。给定函数A和B ,我不介意A与任何其他同时运行 A ,或任何 B与任何其他同时运行 B ,但没有A可以在任何 B 时运行正在运行,反之亦然。线程计
当 XML 必须根据 http://www.w3.org/TR/xml-exc-c14n/ 规范化时,下面的 XML 片段应该相等吗?(注意,. 字符代表一个 ' ' 空格) . ..data .
我想限制对整个应用程序的访问 /*但对于某些 Servlet 则不然。它们应该是公开的。 有没有一种方法可以轻松做到这一点(我想象有一些排除或可能覆盖?)或者我是否必须将文件排列在子文件夹中并允许访问
在一个 spring-mvc 项目中,我对索引/主页的内容进行了测试: @RunWith(SpringRunner.class) @SpringBootTest @AutoConfigureMockM
完全依赖 ARKit 自动平面检测是我不想做的事情,因为它需要时间来检测表面,然后现实生活中的表面应该有足够的纹理,因此我需要考虑一些事情提供一个选项,如果我愿意,我应该能够通过点击按钮随意添加 an
我是一名优秀的程序员,十分优秀!