开发者

alsa snd_pcm_writei

I noticed that the sine generator in pcm.c and speaker-test.c generate a new sine buffer in a loop. So it constantly recreates the same b开发者_JS百科uffer. I wanted to play the buffer without recreating it every time to save some cpu time. However, When I tried to run the code by building the buffer first and then send the same buffer to the snd_pcm_writei I get a little clicky sound at the end of each buffer. However when it gets rebuilt every time and then sent to snd_pcm_writei there is no little click at the end of the buffer. Why is it required to rebuild the sine buffer every time before playing it so as not get the click noise?

Any help would be appreciated?

from pcm.c:

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


You're assuming there's the same sine wave generated every time, but since there's a phase variable used and the sine wave won't always fit exactly in the buffer, a different sine wave is generated in each iteration, shifted a bit.

Not generating the sine wave every time leads to an "break" in the sine wave.

I'll try some visualization with a sawtooth wave instead of a sine wave. Imagine the buffer size being 16 and the wave values ranging from A to H.

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

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

Note that there are only small pieces around the buffer edges where the sound is "malformed" (for example AB|AB instead of AB|CD). This is why it sounds correct most of the time with some disturbing short "clicks" in between.

For some rare cases, if the buffer length is a multiple of the wave length or when phase has the same value as in the iteration before, you might indeed skip generating the buffer, but you can't do it every time.

EDIT: Look at the generate_sine function to see how phase is changed:

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: This image might be a better/clearer visualization:

alsa snd_pcm_writei

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜