Используете AudioWorkletProcessor для планирования аудио с малой задержкой?

У меня есть приложение для интерактивного воспроизведения музыки, использующее следующую настройку:

  1. Пользователь вносит изменения в пользовательский интерфейс для управления графом аудиоузлов.
  2. Простой WebWorker отвечает за сохранение времени. Он отправляет сообщение "галочка" в основной поток через регулярные интервалы.
  3. Слушатель в основном потоке получает сообщение и выполняет следующий шаг в песне (воспроизведение сэмпла с помощью AudioBufferSourceNode.start, настройка параметров громкости и т. Д.).

Наличие таймера в WebWorker более надежно, чем просто использование setInterval, но все же может существовать задержка до того, как сообщение будет обработано основным потоком, что приведет к сбоям звука.

Похоже, что идеальным решением было бы выполнить шаг 3 в WebWorker, но AudioContext не поддерживается в worker-ах. Таким образом, AudioWorklet остается единственным API веб-аудио с низкой задержкой. Но это единственный узел на графике, а я ищу способ управлять всем этим. Помимо переписывания всей системы для работы в AudioWorkletProcessor (много работы), есть ли способ использовать процессор для точного планирования, но сохранить существующую структуру графа?

1 ответ

В AudioContext есть свои часы, используйте их.

  • если вы заранее знаете, что нужно сделать, вы можете использовать первый параметр вашего AudioBufferSourceNode.start(delay) метод:
node1.start( ctx.currentTime + 1 ); // in one second
node2.start( ctx.currentTime + 2 ); // in two seconds
node3.start( ctx.currentTime + 3 ); // in three seconds
  • если вы хотите отреагировать на конец предыдущего источника буфера, используйте его onended прослушиватель событий:
node.onended = (evt) => startANewNode();
  • если вы хотите иметь параллельный таймер, используйте цикл setTimeout, который исправляет возможные отклонения:
const duration = 1000;
let expected = ctx.currentTime + duration;
function loop() {
  const drift = expected - ctx.currentTime;
  startANewNode();
  setTimeout( loop, duration - drift );
}
setTimeout( loop, duration );

И, конечно же, вы можете даже объединить все эти точки вместе, чтобы создать свой собственный таймер, полностью основанный на часах AudioContext.

Другие вопросы по тегам