#alsa
#alsa
Вопрос:
Я заметил, что генератор синусов в pcm.c и speaker-test.c генерируют новый буфер синусов в цикле. Таким образом, он постоянно воссоздает один и тот же буфер. Я хотел воспроизвести буфер, не создавая его заново каждый раз, чтобы сэкономить время процессора. Однако, когда я попытался запустить код, сначала создав буфер, а затем отправив тот же буфер в snd_pcm_writei, я получаю небольшой щелкающий звук в конце каждого буфера. Однако, когда он перестраивается каждый раз, а затем отправляется в snd_pcm_writei, в конце буфера нет маленького щелчка. Почему требуется перестраивать буфер sine каждый раз перед его воспроизведением, чтобы не возникал шум щелчка?
Буду признателен за любую помощь?
из pcm.c:
while (1) {
generate_sine(areas, 0, period_size, amp;phase);
ptr = samples;
cptr = period_size;
Ответ №1:
Вы предполагаете, что каждый раз генерируется одна и та же синусоидальная волна, но поскольку используется 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;
}
ПРАВКА 2: Это изображение может быть лучшей / более четкой визуализацией:
Комментарии:
1. Вероятно, вы могли бы использовать codegolf.stackexchange.com/questions/951 /… для более наглядного примера 🙂
2. @ninjalj: Спасибо, но теперь я решил добавить изображение вместо этого. Еще лучше был бы интерактивный апплет, где вы можете изменять длину буфера и прослушивать звук, но я думаю, что это перебор 🙂
3. Спасибо вам обоим за вашу помощь. Я только начал понимать, что значение фазы в конце длины буфера было критическим фактором. Тогда, основываясь на вашем подтверждении, я должен быть в состоянии создать единый буфер, который может непрерывно воспроизводиться, гарантируя, что фаза всегда равна 0 в начале и конце буфера.