时钟同步
波形接收器要执行的关键任务是解决参考时钟和样本时钟晶体之间的时间偏移。 它使用等效于阶段锁定循环的软件执行此操作。
波形接收器会跟踪它接下来可以写入的缓冲区中的样本号。 因此,尽管它知道样本号为 20,但波形接收器仍需要检查主时钟以获取参考时间。 它有一个线程,大约每 20 毫秒唤醒一次,并要求主时钟提供当前时间。 例如,主时钟可能会报告当前时间(以毫秒为单位)为 420。
波形接收器还维护延迟时钟,该时钟会根据主时钟和采样时间显示当前时间之间的偏移量。 它使用此信息来计算预期的主时钟时间,并将它与实际主时钟读数进行比较,以查看两个时钟是否有偏差。
波形接收器使用相位锁定循环来调整采样时间。 当检查偏移时,波形接收器不会按整个量进行调整,因为读数包含一些抖动。 相反,它会将样本时钟向主时钟移近一小段距离。 这样,波形接收器会在大致保持同步时消除抖动误差。它还需要此时间,并将其转换为相对于主时钟的延迟时钟时间。 这一点很重要,因为应用程序可能需要知道合成器在任何时刻呈现的位置。
延迟时钟会告知应用程序可以安排播放新笔记的最早时间。 延迟时钟时间是主时钟时间加上表示合成器延迟的偏移量。 此延迟表示从应用程序提交要播放新笔记的时间到合成器实际播放该笔记的时间的最小延迟。 在任何时刻,应用程序都可以安排恰好在或晚于(但不早于)当前延迟时钟时间播放笔记。
例如,如果主时钟当前为 420,并且应用程序希望尽快播放某个笔记,则延迟时钟会告知它可以播放该笔记的最早时间。 如果软件合成器延迟为 100 毫秒,则下次可以播放笔记的时间为 520。
假设事件标记为在参考时间 520 时播放。 合成器通过以下方式来工作:将笔记向下呈现到样本中,并在采样时间执行其所有计算。 因此,它需要知道参考时间 520 在采样时间中会转换为什么。 在用户模式下,波形接收器会提供合成器使用的两个功能:
IDirectMusicSynthSink::SampleToRefTime and IDirectMusicSynthSink::RefTimeToSample**
为在此案例中执行转换,合成器会在波形接收器上调用 IDirectMusicSynthSink::RefTimeToSample。
然后,波形接收器将返回采样时间(例如 600)。 相关笔记在采样时间 600 呈现。 然后,当波形接收器调用合成器 IDirectMusicSynth::Render 方法以呈现流的下一部分(例如,从采样时间 600 到 800)时,笔记将在采样时间 600 呈现到缓冲区中。
请注意,采样时间保留为 64 位数字,以避免滚动更新。 (DWORD 值在 27 小时内滚动更新。)
总之,合成器在采样时间执行其所有内部数学运算,波形接收器从参考时间转换为采样时间,反之亦然。 波形接收器还会管理与主时钟的同步,并提供延迟信息。 在波形接收器中隐藏此功能可以更轻松地编写合成器。