LINUX.ORG.RU

Совет по синтезу звука в realtime


1

2

Хочу вернуться к вопросу, который я задавал на lisper.ru (или lisp.ru, как его там? Сайт archimag'а)

В общем такая ситуация: я синтезирую звук в риалтайме через OSS (если чё, наверно можно взять Jack, но никаких альс или пульсаудио!) Звук идет от некоего объекта-генератора. Я хочу, чтобы при изменении мной параметра генератора, сразу изменился и звук.

Генерация и запись происходит примерно так:

(loop while t do
    (write-buffer (gen-buffer generator) *oss-output*))

Вызов write-buffer блокирующий, т.е. пока буфер не запишется, выполнение дальше не пойдет. Соответственно, изменить буфер в это время нельзя, а только со следующей итерации, и будет слышна задержка.

Другой вариант: писать каждый семпл в отдельности. Но тогда слишком много системных вызовов, и тоже плохо.

Вот предложите модель, пожалуйста, чтобы и не ресурсозатратно, и в real-time. Язык не важен, в принципе, так как это что-то языконезависимое, в принципе.

Получасовое копание других (в основном cpp) прожектов ничего не дало, увы. А ещё беда в том, что они (SuperCollider, например, почему-то падают). Мне кажется, что в случае с SuperCollider это какой-то бустобаг.

Т.е., ещё раз, есть генератор, генерирующий семплы, и бэкенд, куда, собственно, идет запись и который отвечает за звук. Надо их «сдружить» таким образом, чтобы задержка между изменением параметров генератора и изменением звука была минимальна. И по возможности, без затрат

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

Другой вариант: писать каждый семпл в отдельности. Но тогда слишком много системных вызовов, и тоже плохо.

500 - 100 write'ов в сек. (т.е. с лагом от 10мс до 2х) это относительно немного. Я бы даже сказал, мало. Иного выбора у тебя всё равно нет.

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

Вообще да, нагрузка на ЦП 2% system (top показывает).

А ловсанчег крикнул что-то про asynchronous I/O, но я нифига не понял. Все эти kqueue для sockets/vnodes/pipes и прочего, как показывает man, а не для character devices (/dev/dsp). Или я что-то не так понял? Он не говорит

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

Ога. Но мне модель взаимодействия важна.

Например, если у меня будет обычный цикл:

сгенерировать, записать, повторить, то он будет генерировать без остановки и грузить процессор, так? Могу я с O_NONBLOCK как-то отслеживать процесс записи не прерываясь?

типа предиката (write-finishedp stream).

Тогда я мог бы сделать что-то вроде очереди, которая будет поддерживать буфер наполненным, но не генерировать слишком много

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

сгенерировать, записать, повторить, то он будет генерировать без остановки и грузить процессор, так?

нужно грузить не процессор, а устройство вывода (оно, кстати, тоже имеет свой буфер, это к вопросу о задержках, т.к. он может быть относительно большим). Если твоя генерация вдруг лаганёт в этом цикле, то услышишь неприятный треск. Т.е. так работать нормально не будет.

Нужно либо делать два потока один из которых будет только писать в блокирующем режиме текущий фрейм, а второй готовить следуюший (или несколько следующих).

либо заморачиваться с неблокирующим режимом и делать всё в одном потоке.

Могу я с O_NONBLOCK как-то отслеживать процесс записи не прерываясь?

Не прерываясь от чего? Через стандартный интерфейс можно только узнать можно ли ещё записать данные (через pool() или select() например).

Тогда я мог бы сделать что-то вроде очереди, которая будет поддерживать буфер наполненным, но не генерировать слишком много

да, как-так и нужно в любом случае. Вопрос только в форме реализации.

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

Не прерываясь от чего?

От выполнения дальше. Типа неблокирующего вызова тоже, который скажет, все ли данные записаны или ещё нет. Сложно сформулировать, но суть в том, что должен быть какой-то контроль, когда генерировать, а когда ждать.

Нужно либо делать два потока один из которых будет только писать в блокирующем режиме текущий фрейм, а второй готовить следуюший (или несколько следующих).

От задержки это не избавит. Пока блокирующий вызов не завершится, изменение параметра генератора нельзя будет услышать, не?

Ещё вопрос: в манах написано, что select принимает file descriptors, но часто упоминаются сокеты. Значит ли это, что все эти select/poll итд работают именно с сокетами, а не с обычными файлами или character устройствами?

Мда, надо бы сначала с C поэкспериментировать, а потом думать, как сделать в CL

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

От задержки это не избавит. Пока блокирующий вызов не завершится, изменение параметра генератора нельзя будет услышать, не?

чё тупишь. Блокирующий вызов будет писать фреймами, от 2мс до 10-25 каждый. Соответственно, величина лага на твоей стороне будет примерно в два фрейма (один пишется + минимум один генерируется) + ещё лаг в буфере самого девайса.

совсем избавиться от лага невозможно, можно только довести его до приемлемой величины. 10-50мс вполе допустимые значения для человека. Меньше всё равно будет сделать трудно на обычной ОС из-за особенностей работы планировщика.

Ещё вопрос: в манах написано, что select принимает file descriptors, но часто упоминаются сокеты. Значит ли это, что все эти select/poll итд работают именно с сокетами, а не с обычными файлами или character устройствами?

fd это APIшный интерфейс. Файло, сокет и т.п. есть объект, который спрятан за интерфейсом. Соответственно, «все эти...» работают именно с fd, но не всё ядерные объекты умеют работать в неблокирующем режиме. Нужно проверять, я на счёт OSS не знаю.

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

чё тупишь. Блокирующий вызов будет писать фреймами, от 2мс до 10-25 каждый. Соответственно, величина лага на твоей стороне будет примерно в два фрейма (один пишется + минимум один генерируется) + ещё лаг в буфере самого девайса.

ОК, похоже что мне надо сделать, так это верно подобрать размер буфера, чтобы задержка была приемлема, и можно фигачить блокирующие вызовы

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