WASAPI:以最小的延迟播放正弦波声音而不会出现毛刺(事件驱动模式) [英] WASAPI: Play sine wave sound in minimum latency without glitches (exclusive-event driven mode)

查看:239
本文介绍了WASAPI:以最小的延迟播放正弦波声音而不会出现毛刺(事件驱动模式)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在独占模式下使用Windows音频会话API(WASAPI)播放简单的正弦波形,但是无论我做什么,都会遇到声音故障.我一直在使用 MSDN专有-Mode流示例作为参考点,这是当前略微修改的代码的样子.

I'm trying to play a simple sineous waveform using the Windows Audio Session API (WASAPI) in exclusive mode, but encountering sound glitches no matter what I do. I've been using the MSDN Exclusive-Mode Streams example as a reference point, and here's how the slightly adapted code currently looks like.

设置代码:

-- <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秒钟,然后开始出现大量混叠现象,听起来几乎像锯齿波.我在这里想念东西吗?

The problem is that at the minimum latency, the sine wave usually plays smoothly for about 2 seconds, and then starts glitching out with massive aliasing, sounding almost like a sawtooth wave. Am I missing something here?

(可以在此处找到整个工作示例.)

(The whole working example can be found here.)

推荐答案

只需尝试完整的示例,IAudioClient :: Initialize就会失败,并显示AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED.Windows 7中引入了此错误,您正在运行Vista吗?校正周期大小以进行对齐后,我得到了一个完美的正弦波.如果您的系统没有产生此错误,请尝试在128字节(非位)边界上手动对齐缓冲区.否则,这是对齐代码:

Just tried your full sample, IAudioClient::Initialize fails with AUDCLNT_E_BUFFER_SIZE_NOT_ALIGNED. This error was introduced in windows 7, are you running vista? After correcting the period size for alignment i get a perfect sinewave. If your system doesnt generate this error, try manually aligning the buffer on a 128-byte (not bit) boundary. Otherwise here's the alignment code:

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);
  }

这篇关于WASAPI:以最小的延迟播放正弦波声音而不会出现毛刺(事件驱动模式)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆