我注意到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;
答案 0 :(得分:4)
你假设每次都产生相同的正弦波,但是因为使用了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:此图像可能是更好/更清晰的可视化: