我正在编写同时播放数字音频(合成音乐)和MIDI音乐的C ++代码(使用RtMidi库。)数字化音乐将播放计算机的音频设备,但MIDI音乐可以播放超出外部合成器。我想播放使用数字化乐器和MIDI乐器的歌曲,我不确定同步这两个音频流的最佳方式:
目前我正在使用nanosleep() - 它只适用于Linux,而不是Windows - 等待笔记之间的正确时间。这允许数字音频和MIDI数据保持同步,但是nanosleep()不是非常一致,因此产生的节奏非常不均匀。
有人能想出一种方法来保持数字音频和MIDI数据的音符之间的准确时间吗?
答案 0 :(得分:2)
如果您愿意使用Boost,则会有CPU-precision timers。如果没有,在Windows上有函数QueryPerformanceCounter
和QueryPerformanceFrequency
,它们可以用于基于CPU的计时,这当然可以满足您的所有需求。 Web上有很多Timer类实现,其中一些在windows和* ix系统上都有效。
答案 1 :(得分:1)
第一个问题是您需要知道音频设备传递了多少音频。如果您的延迟足够低,您可能会从您推送的数据量中猜出,但是它与播放之间的延迟是一个移动目标,因此您应该尝试从音频中获取该信息硬件。这些信息是可用的,因此使用它是因为从延迟测量中的错误中获得的“抖动”会以音乐上明显的方式影响同步。
如果你必须使用睡眠进行计时,有两个问题会让它睡得更久:1。优先级(如果另一个进程/线程具有更高的优先级,如果计时器已经用完则会运行)和2.系统延迟(如果系统需要5毫秒来交换进程/线程,它可能会将其添加到您请求的延迟时间)。这些延迟在音乐上是相关的。大多数midi API都有一个“sequencer”api,可以让你提前排队数据,以避免使用系统定时器。
即使您没有将portaudio用于音频I / O,也可能会发现此文档很有用。
答案 2 :(得分:0)
答案不在于小缓冲区,而在于大缓冲区。
让我们举一首3分钟的歌曲。
首先渲染数字部分,然后用MIDI音符“标记”它。 然后开始播放并在时间触发MIDI音符,也许使用std :: vector来保持有序列表。 可以使用总时间偏移来更改同步:
HORRIBLE不完整但有希望在该主题上使用示范伪代码:
start_digital_playing_thread();
int midi_time_sync = 10; // ms
if (time >= (midi_note[50]->time + midi_time_sync)) // play note