LINUX.ORG.RU

Воспроизвести звук заданной частоты


0

2

Возникла необходимость из программы воспроизводить звуки заданной частоты. Использую примерно такой код:

 
int fd = open("/dev/dsp",O_WRONLY,0);
ioctl(fd, SNDCTL_DSP_RESET, NULL);
ioctl(fd, SNDCTL_DSP_NONBLOCK, NULL);
int stereo = 0;
ioctl(fd, SNDCTL_DSP_STEREO, &stereo);
int rate = 22050;
ioctl(fd, SNDCTL_DSP_SPEED, &rate);
int nchans = 1;
ioctl(fd, SNDCTL_DSP_CHANNELS, &nchans);
int format = AFMT_U8;
ioctl(fd, SNDCTL_DSP_SETFMT, &format);

DWORD numSamples = rate;
unsigned char *samples = new unsigned char[numSamples];
for(DWORD i=0; i<numSamples; i++)
  samples[i] = BYTE(128+127*sin(2*M_PI*i*1000/double(rate)));

int res;
res = write(fd, samples, numSamples);
//Воспроизведение второй раз - если без паузы, то щелчков не будет
res = write(fd, samples, numSamples);
Так вот, в результате в начале и конце воспроизведения слышны сильные щелчки. Если выполнить процедуру записи 2 раза подряд, то шелчков между ними не будет. Но если сделать хотя бы небольшую паузу, будут щелчки.

Как можно исправить? Чего не хватает?



Последнее исправление: GhostII (всего исправлений: 1)
Ответ на: комментарий от anon_666

Спасибо! Как вариант, можно поизучать исходники speaker-test, он вроде как нормально работает, без щелчков. Попробую.

GhostII
() автор топика

>Как можно исправить? Чего не хватает?

(пальцем в небо)Может нужно как-то сообщать о том, что ты завершил передачу данных? Возможно потом продолжается вывод остатка какого-то внутреннего буфера, который ты не до конца заполнил - тогда мусор в нем и даст щелчки.

Pavval ★★★★★
()
Ответ на: комментарий от Pavval

Тогда почему и в начале щелчки? Хотя тоже такие мысли были - что есть какой-то внутренний буфер, мусор в котором и дает щелчки. Но не нашел ничего про него. Пробовал команду Reset в начале - никак не помогло.

GhostII
() автор топика
Ответ на: комментарий от kiverattes

Ну начинаю-то всяко нулем (128 соответствует 0). А еще я пробовал начинать постоянным периодом в 128 и им же заканчивать - при этом щелчки в начале и конце, а в переходах между постоянным 128 и синусоидой и обратно - щелчков нет.

GhostII
() автор топика

Вы не проверили значение, возвращаемое вызовом write. После

res = write(fd, samples, numSamples);

вставьте

printf("%i\n", res);

и запустите.

anonymous
()
Ответ на: комментарий от anonymous

Это в приведенном коде возвращаемое значение не проверяется - я для простоты убрал все проверки. А на самом деле в исходной программе это значение проверяется - и оно равно numSamples - то есть, сколько записалось (записалось все).

GhostII
() автор топика

Ну... не знаю, что за щелчки. Есть возможность выложить звуковой пример щелчков?

Тем не менее, есть подозрение. Попробуй разложить (в уме есессно) функцию в ряд фурье такую вот:

       { 0        , x < 0
f(x) = { sin(x)   , 0 <= x < 10*pi
       { 0        , x >= 10*pi

Внезапно, тут будет присутствовать куча высокочастотного мусора.

Иными словами, чтобы исправить, нужно сделать fade in и fade out

Waterlaz ★★★★★
()
Ответ на: комментарий от Waterlaz

Или хотя бы выложи рабочий код. А то доводить его еще, что-бы запускать и смотреть, мне лень.

Waterlaz ★★★★★
()

Я бы начал с sample rate = 48000 и format = AFMT_S16_*.

fopen ★★
()
Ответ на: комментарий от GhostII

Я думаю, дело всё же в нуле. Попробуй всё же заменить 128 на 64 (или чему там равна половина диапазона), а синус умножать не на 127, а тоже на 64.

den73 ★★★★★
()
Ответ на: комментарий от anon_666

>speaker-test -t sine

Оно у меня щелкает в один момент с выводом Time per period. // Arch

Dimanc ★★
()
Ответ на: комментарий от den73

Нет, не в этом дело. Под виндой соответствующий код работает без проблем. 128 - это ноль. Синус умножается на 127. :-) Вобщем, сделал все через alsa. Все работает идеально без щелчков. :-) anon_666, еще раз благодарю за наводку! ;-)

GhostII
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.