alsa snd_pcm_writei - PullRequest
       18

alsa snd_pcm_writei

3 голосов
/ 07 мая 2011

Я заметил, что генератор синуса в pcm.c и speaker-test.c генерирует новый буфер синуса в цикле. Так что он постоянно воссоздает один и тот же буфер. Я хотел воспроизвести буфер без воссоздания его каждый раз, чтобы сэкономить время процессора. Однако, когда я попытался запустить код, сначала создав буфер, а затем отправив тот же буфер в snd_pcm_writei, в конце каждого буфера я получил немного щелкающий звук. Однако, когда его каждый раз перестраивают, а затем отправляют в snd_pcm_writei, щелчок в конце буфера становится маленьким. Почему каждый раз перед воспроизведением требуется перестраивать буфер синуса, чтобы не было шума щелчка?

Любая помощь будет оценена?

из pcm.c:

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

1 Ответ

4 голосов
/ 07 мая 2011

Вы предполагаете, что каждый раз генерируется одна и та же синусоида, но поскольку используется переменная 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|ABAB|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;
}

РЕДАКТИРОВАТЬ2: Это изображение может быть лучше / четче визуализация:

enter image description here

...