1

我正在另一个论坛上与一些开发人员就准确生成 MIDI 事件(注意消息等)进行辩论。人耳对轻微的计时误差非常敏感,我认为他们的主要问题来自于他们使用分辨率相对较低的计时器,这些计时器以大约 15 毫秒的间隔量化他们的事件(这足以导致可察觉的不准确性)。

大约 10 年前,我编写了一个示例应用程序(Windows 95 上的 Visual Basic 5),它是一个组合的软件合成器和 MIDI 播放器。基本前提是一个跳跃缓冲播放系统,每个缓冲区是十六分音符的持续时间(例如:每分钟有 120 个四分音符,每个四分音符是 500 毫秒,因此每个十六分音符是 125 毫秒,所以每个缓冲区为 5513 个样本)。每个缓冲区都通过 waveOutWrite 方法播放,该方法的回调函数用于排队下一个缓冲区并发送 MIDI 消息。这使基于 WAV 的音频和 MIDI 音频保持同步。

在我看来,这种方法效果很好——MIDI 音符听起来甚至没有一点不同步(而如果你使用精确到 15 毫秒的普通计时器来播放 MIDI 音符,它们听起来会明显不同步)。

理论上,这种方法会产生精确到样本的 MIDI 时序,即 0.0227 毫秒(因为每毫秒有 44.1 个样本)。我怀疑这是这种方法的真正延迟,因为在缓冲区完成和通知 waveOutWrite 回调之间可能存在一些轻微延迟。有谁知道这个延迟实际上会有多大?

4

3 回答 3

5

默认情况下,Windows 调度程序以 10 毫秒或 16 毫秒的间隔运行,具体取决于处理器。如果您使用 timeBeginPeriod() API,您可以更改此间隔(以相当大的功耗成本)。

在 Windows XP 和 Windows 7 中,wave API 的运行延迟约为 30 毫秒,对于 Windows Vista,wave API 的延迟约为 50 毫秒。然后,您需要添加音频引擎延迟。

不幸的是,我没有一个方向的引擎延迟数字,但我们确实有一些关于引擎延迟的数字 - 我们运行了一个测试,播放通过 USB 音频设备循环回的音调并测量往返延迟(渲染到捕获)。在 Vista 上,往返延迟约为 80 毫秒,变化约为 10 毫秒。在 Win7 上,往返延迟约为 40 毫秒,变化约为 5 毫秒。然而,YMMV 因为每个硬件的音频硬件引入的延迟量是不同的。

我完全不知道 XP 音频引擎或 Win9x 音频堆栈的延迟是多少。

于 2009-08-23T16:50:07.737 回答
1

在最基本的层面上,Windows 是一个多线程操作系统。它以 100 毫秒的时间片调度线程。这意味着,如果没有 CPU 争用,缓冲区结束和 waveOutWrite 回调之间的延迟可能会非常短。或者,如果有其他繁忙的线程,您必须等待每个线程最多 100 毫秒。然而,在最好的情况下...... CPU 的时钟速度现在达到了 GHz。这为回调的调用速度设定了绝对下限,以 0.000,000,000,1 秒数量级。

除非你能计算出你在一秒钟内可以处理的最大 waveOutWrite 回调数,这可能意味着每个调用的延迟,我认为实际上,延迟将在大多数时间低于 preception 几个数量级,除非有太多忙碌的线程,在这种情况下,它会变得非常糟糕,非常糟糕。

于 2009-08-20T09:15:35.647 回答
1

添加到上面的好答案。

您的问题是关于 Windows 没有承诺不关心的延迟。因此,它可能会因操作系统版本、硬件和其他因素而有很大不同。WaveOut API 和 DirectSound(不确定 WASAPI,但我猜这个最新的 Vista+ 音频 API 也是如此)都设置为缓冲音频输出。只要您在当前仍在播放时按时排队下一个缓冲区,就不需要特定的回调准确性。

当您开始音频播放时,您有一些假设,例如在播放期间没有下溢并且所有输出都是连续的,并且音频时钟速率与您期望的完全一样,例如精确到 44,100 Hz。然后你做简单的数学来及时安排你的波形输出,将时间转换为样本,然后转换为字节。

可悲的是,有效的播放速率并不精确,例如想象真实的硬件采样率可能是 44,100 Hz -3%,从长远来看,时间到字节的数学可能会让你失望。已经尝试补偿这种影响,例如将音频硬件作为播放时钟并将视频同步到它(这是播放器的工作方式),以及速率匹配技术以将传入数据速率与硬件上的实际播放速率相匹配。这两者都使绝对时间测量和所讨论的延迟成为一种推测性的知识。

更重要的是,API 延迟 20 毫秒、30 毫秒、50 毫秒等等。很久以前,waveOut API 是其他 API 之上的一层。这意味着在数据实际到达硬件之前会进行一些处理,并且此处理要求您提前将手从排队的数据中移开,否则数据将无法到达硬件。假设您尝试在播放时间之前将数据放入 10 毫秒缓冲区中,API 将接受此数据,但它自己会将这些数据传递到下游,并且扬声器上会出现静音或舒适噪音。

现在这也与您收到的回调有关。您可以说您不关心缓冲区的延迟,而对您来说重要的是精确的回调时间。但是,由于 API 是分层的,因此您会在内层同步的准确性上收到回调,这样第二个内层会通知空闲缓冲区,并且第一个内层会更新其记录并检查它是否也可以释放您的缓冲区(嘿,那些缓冲区没有' t也必须匹配)。这使得回调准确性预期非常弱且不可靠。

假设我已经有一段时间没有接触waveOut API了,如果出现这种同步准确性的问题,我可能首先会想到两件事:

  • Windows 提供对音频硬件时钟的访问(我知道通过 DirectShow 可用的 IReferenceClock 接口,它可能来自另一个也可以访问的较低级别的东西)并且有可用的我会尝试与它同步

  • 来自 Microsoft 的最新音频 API,WASAPI,为低延迟音频提供了特殊支持,其中包含新的很酷的东西,例如更好的媒体线程调度、独占模式流和 PCM 的 <10 毫秒延迟 - 这是需要考虑更好同步的地方

于 2011-10-08T17:39:54.253 回答