【问题标题】:How do I write audio data at a certain sample rate?如何以一定的采样率写入音频数据?
【发布时间】:2016-11-04 04:55:49
【问题描述】:

我正在通过将数据传输到播放中来制作合成器(我知道这并不理想),并且声音落后于改变声音的按键。我相信这是因为 aplay 以恒定的 8000 Hz 运行,但 c 程序的运行速度不稳定。如何让 for 循环在 C 中以 8000 Hz 运行?

【问题讨论】:

  • 这个问题太宽泛了。没有简单的措施可以确保这一点。这取决于目标平台、可用库等。
  • 直接使用 ALSA、PulseAudio 等 API 可能比使用管道与 aplay 通信更成功。这些 API 将提供回调或阻塞函数,以允许您以所需的采样率(例如 8 kHz)可靠地生成数据,而不会引入延迟。使用管道,您将始终与内核缓冲区竞争……默认为 64 kB,或 2 秒的 16 位立体声!还有一些包装这些 API 的更简单的库,比如 PortAudio(也许是你最好的选择?)

标签: c frequency


【解决方案1】:

如果您将数据传送到aplay,您不会遇到任何采样率问题(例如8 kHz),因为当您write() 缓冲区已满时内核会阻塞您的程序。这将有效地将您的音频生成限制为 8 kHz,而您无需进行任何工作。

但是,这远非理想。仅当管道的内核缓冲区已满时,您的应用程序才会受到限制,Linux 上管道缓冲区的默认大小为 64 kB。对于 8 kHz 的立体声 16 位数据,这是整整两秒的音频数据,因此您会期望您的音频比用户输入滞后至少两秒。这对于合成器应用程序是不可接受的。

唯一真正的解决方案是直接使用 ALSA 库(或其他声音 API)。使用此 API,您可以将缓冲的音频数据发送到音频输出设备,而不会在内核缓冲区中累积过多的排队数据。

请参阅A Guide Through The Linux Sound API Jungle 了解一些提示。

【讨论】:

    【解决方案2】:

    要以 8000 Hz(或任何固定速率)生成音频样本,您不希望循环以该速率“运行”。这将涉及大量开销(99.99% 或更多)在生成下一个样本之前什么都不做,并且(特别是如果你睡觉而不是旋转)将是不可靠的,因为你的进程可能不会唤醒/得到调度及时获得一些样本。

    相反,您只想以符合消费者(aplay/音频设备)期望的总体速率生成样本。您可以计算应生成的当前样本总数,如下所示:

    current_time + buffer_depth - start_time
    

    然后,在生成该样本后,休眠一段时间与缓冲区深度成正比,但如果您的进程没有立即再次安排,您不会遇到麻烦。您可以使用的缓冲区深度取决于您需要什么样的延迟。如果您正在为实时/实时事件制作声音,您可能需要 1/50 秒(20 毫秒)或更短的缓冲深度。如果没有,您可以愉快地使用 5-10 秒之类的巨大缓冲区。

    【讨论】:

    • 由于有两个时钟(音频输出通常在自己的时钟上运行),这将导致音频故障。
    • 嗯,有点,但是由于 OP 想要使用 aplay,所以这个问题确实没有解决方案。对于直接播放,您应该使用音频设备作为时间源,而不是使用系统时钟,或者将基于系统时钟(或基于其他时钟)的音频传送到音频设备的过程(aplay或类似的)应该进行更正。但是这个 IMO 整个主题相对于 OP 的问题/理解来说是非常先进的,并且在该过程运行数小时之前不太重要。
    • 你说“不太重要”,但我经常会收到不同步的音频源的点击和爆裂声。所需要的只是aplay 实际上以 8001 Hz 而不是 8000 Hz(由系统时钟测量)运行。
    • 那么需要多长时间取决于您的缓冲深度和时钟误差。对于 1 秒的缓冲,该错误应该需要 8000 秒才能耗尽缓冲区。
    猜你喜欢
    • 1970-01-01
    • 2022-08-24
    • 1970-01-01
    • 2017-03-04
    • 2011-01-06
    • 2019-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多