alsa snd_pcm_writei

标签 alsa

我注意到 pcm.c 和 speaker-test.c 中的正弦发生器循环生成一个新的正弦缓冲区。所以它不断地重新创建相同的缓冲区。我想播放缓冲区而不是每次都重新创建它以节省一些 cpu 时间。但是,当我尝试通过先构建缓冲区然后将相同的缓冲区发送到 snd_pcm_writei 来运行代码时,我在每个缓冲区的末尾都听到了一点咔哒声。然而,当它每次都被重建然后发送到 snd_pcm_writei 时,缓冲区末尾没有一点点击。为什么每次播放前都需要重建正弦缓冲区,才不会出现卡嗒声?

任何帮助将不胜感激?

来自 pcm.c:

while (1) {
    generate_sine(areas, 0, period_size, &phase);
    ptr = samples;
    cptr = period_size;

最佳答案

您假设每次都生成相同的正弦波,但由于使用了 phase 变量并且正弦波并不总是完全适合缓冲区,因此生成了不同的正弦波在每次迭代中,移动一点。

不是每次都生成正弦波会导致正弦波“中断”。

我将尝试使用锯齿波而不是正弦波进行可视化。假设缓冲区大小为 16,波值范围为 A 到 H。

// Old way
  phase = 0        phase = 2        phase = 4
ABCDEFGHGFEDCBAB|CDEFGHGFEDCBABCD|EFGHGFEDCBABCDEF....

// New way
  phase = 0        phase = 0        phase = 0
ABCDEFGHGFEDCBAB|ABCDEFGHGFEDCBAB|ABCDEFGHGFEDCBAB....

请注意,缓冲区边缘周围只有一小部分声音“格式错误”(例如 AB|AB 而不是 AB|CD)。这就是为什么它在大多数时候听起来是正确的,中间有一些令人不安的短促“咔嗒声”。

在极少数情况下,如果缓冲区长度是波长的倍数,或者当 phase 与之前迭代中的值相同时,您可能确实会跳过生成缓冲区,但您可以每次都这样做。

编辑:查看 generate_sine查看 phase 是如何改变的函数:

static void generate_sine(const snd_pcm_channel_area_t *areas, 
                          snd_pcm_uframes_t offset,
                          int count, double *_phase)
{
    static double max_phase = 2. * M_PI;
    double phase = *_phase;
    double step = max_phase*freq/(double)rate;

    [...]

             phase += step;
             if (phase >= max_phase)
                    phase -= max_phase;
     }
     *_phase = phase;
}

EDIT2:这张图片可能是更好/更清晰的可视化:

enter image description here

关于alsa snd_pcm_writei,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5920613/

相关文章:

linux - ALSA 错误 : "unable to open timer" in USB Sound Card

linux - 插孔音频以生成虚拟声卡并在其中输入

c - 编程 Linux 应用程序以同时播放多个声音

alsa - 如何优雅地从 ALSA 中的 -EPIPE 错误中恢复?

linux - Ubuntu VM 上 Docker 容器中的假输入设备

c - 如何用 ALSA 播放短音

c++ - boost 共享内存 : vector of char *

linux - linux分层系统中的声音系统是否为OSI模型?

audio - GNU radio : Use sound output as input source

c - 如何正确设置 ALSA 设备