← Архив: Common Lisp

Прервать write-sequence

Author: · 09.06.2013 13:57
· original author: shamaz.mazum
Привет. Объясняю идиотское название треда: я решил замутить штуку для синтеза звука в реальном времени, но не продумал одну вещь и жестко напоролся. Итак, штука состоит из менеджера, управляющего миксером и бекэндом, в который звук выводится. Миксер может собирать данные от подключенных к нему генераторов и подготавливать данные для записи в бэкенд. Данные генерируются и записываются буфером.
Сейчас менеджер работает в своём потоке, выполняя цикл, генерирующий данные и сразу записывающий их:
(defmethod run ((manager simple-manager))
  (let ((backend (manager-backend manager)))
    (backend-init backend)
    (flet ((run-loop ()
            (let* ((settings (audio-settings (manager-backend manager)))
                   (channels (audio-settings-channels settings))
                   (size (* *buffer-size* channels))
                   (buffer (make-array (list size) :element-type '(signed-byte 24)))
)

              (loop while (simple-manager-runningp manager) do
                    (write-buffer backend
                                  (prepare-buffer (manager-mixer manager)
                                                  buffer
)
)
)
)
)
)

      (setf (simple-manager-runningp manager) t
            (simple-manager-thread manager) (make-thread #'run-loop :name "Gen-write loop")
)
)
)

  manager
)

Есть ещё вариант, не создающих поток; и, наверное, будет вариант с очередью для хранения буферов про запас.
Сделано изменяемым всё, кроме параметров бекенда (бит на семпл, sample rate, number of channels).
Так вот я не продумал главное, если изменю параметр генератора (пока есть всего один, генерурующий синусоиду), как мне сделать так, чтобы изменения сразу вступили в силу? Ведь надо ждать, пока буфер запишется, а потом сгенерируется новый. В общем я ССЗБ. Есть идея, что может есть инструмент, которым можно прервать write-sequence (она вызвается из write-buffer), перенаполнить буфер и пойти дальше. Да и желательно, чтоб звук не дергался :)
В общем, ваши идеи, господа, как сделать механизм real-time генерации/записи наиболее Ъ.
· original author: shamaz.mazum
Штука на жидхабе, если чо.
· original author: Love5an
Тебе нужно асинхронное IO, смотри библиотеки для работы с ним
· original author: shamaz.mazum
Ох, самое сложное для меня. Из того, что я понял, читая man kqueue и гугля (нагуглил cl-async + знаю iolib), то это асинхронное IO доступно для сокетов, а не для обычных файлов. Или я не прав? В общем, если можешь, присоветуй что-то конкретное
· original author: den73
По-моему, это никак не делается. Машина у нас цифровая, дискретная и занята множеством дел одновременно, она может их успеть, лишь переключаясь между задачами. Иногда на "другие" задачи она отвлекается надолго. Поэтому иллюзия непрерывности звука возможна исключительно за счёт буферизации, потому что компьютеру нужно, например, отвечать на действия пользователя по дёрганию рычажков. Можно лишь уменьшать задержки, уменьшая размеры буферов и/или вынося буферизацию куда-нибудь вовне (например, в звуковое железо). Если, допустим, сделаешь буфер в 10 мс, то задержка будет мало заметна на слух.
· original author: den73
P.S. предел уменьшения буферов наступит в момент, когда звук начнёт "заикаться", появятся щелчки, разрывы и т.п. Для опознания этого явления крайне желательно, чтобы размер буфера не был пропорционален периоду колебаний, измеренному в семплах.
· original author: shamaz.mazum
Спасибо, посмотрю как в SuperCollider сделано. Я бы вообще не стал огород городить, если бы он у меня работал. Но похоже с бустом что-то