В начале разработки моего веб-приложения метронома (https://metpro34.com) я быстро понял, что обычные подходы к воспроизведению аудио с помощью кода просто не работают.
Вариант использования метронома может показаться не таким захватывающим, но он требует предельной точности и последовательности, иначе он непригоден для использования.
Давайте посмотрим, что я пробовал, и что нужно, чтобы получить звук с низкой задержкой в Интернете.
Наивный подход
Первоначально использование setInterval
или setTimeout
кажется разумной идеей. Эти функции позволяют программисту указать количество миллисекунд ожидания перед запуском некоторой функции, которая в данном случае должна воспроизводить звук.
Если вы хотите посмотреть, как это получится, вставьте этот код в свою консоль; он создает функцию звукового сигнала и запускает ее 20 раз с интервалом 500 мс, что составляет 120 ударов в минуту (ударов в минуту), что является очень средним темпом для музыки.
Спасибо https://www.rgagnon.com/jsdetails/js-0024.html за чистый звуковой сигнал JS, супер круто!
Запустив это несколько раз, я получил среднюю задержку 501,4 мс между каждым звуковым сигналом.
Хотя большинство звуковых сигналов кажутся достаточно последовательными, время от времени звуковой сигнал будет очень запаздывающим. Ты знаешь почему?
Вопреки распространенному мнению, setInterval
и setTimeout
не указывают интерпретатору JS выполнять обратный вызов через точное число миллисекунд. Что они на самом деле делают, так это говорят ему запускать обратный вызов черезпо крайней мере некоторое количество миллисекунд, всякий раз, когда ресурсы доступны для выполнения.
Это означает, что производительность может сильно различаться от машины к машине и в зависимости от того, какие другие задачи выполняются. Это неприемлемо для варианта использования метронома.
После некоторого начального тестирования стало ясно, что он никогда не будет достаточно точным, чтобы музыкант мог использовать его в качестве метронома сам по себе. Попробуем исправить!
(Немного) лучший наивный подход
Мы быстро поняли, что старые добрые setInterval
или setTimeout
не смогут быть точными из-за задержек в ожидании ресурсов от браузера.
Следующая идея, которая может прийти в голову, — это корректировка этой задержки путем отслеживания системного времени и изменения задержки для корректировки пропусков.
Давайте попробуем этот код, учитывающий задержку каждого звукового сигнала, и посмотрим, каким будет среднее значение.
Запустив это несколько раз, я получил среднюю задержку 501,1 мс между каждым звуковым сигналом, улучшение на 0,3 мс на звуковой сигнал в целом.
Тем не менее, все еще слишком много звуковых сигналов, которые далеки от цели, и даже один несвоевременный звуковой сигнал считается непригодным для использования музыкантом любого калибра.
После этих усилий с setTimeout
все выглядит не очень хорошо. Нам нужно управление звуком более низкого уровня, чтобы получить первозданную точность и согласованность.
Нам нужно…
Веб-аудиоконтекст
«Интерфейс
AudioContext
представляет собой граф обработки звука, построенный из аудиомодулей, связанных вместе, каждый из которых представленAudioNode
. Аудиоконтекст управляет как созданием содержащихся в нем узлов, так и выполнением аудиообработки или декодирования».
Объект AudioContext
дает программисту очень гибкое и мощное представление о звуковом движке браузера.
Это позволяет программисту легко понимать и разрабатывать аудио приложения в виде структуры данных ориентированного графа.
Это означает, что новый узел легко присоединить к графу, подключив его к другому узлу, уже находящемуся в графе, или напрямую присоединив его к конечному выходному узлу: audioContext.destination
Это может быть очень полезно, когда вам нужно много потоков аудио, или вам нужно микшировать потоки или устанавливать громкость/эквалайзер для каждого узла.
Скопируйте и вставьте этот код в свою консоль, чтобы испытать чрезвычайно точный метроном AudioContext
!
Постоянный запуск этого кода дает мне среднюю задержку между сигналами ~499,75 мс, без заметных сбоев в ритме… Вот это хороший метроном!
Использование AudioContext
для вашего следующего веб-приложения может быть излишним, в зависимости от ваших потребностей.
Конечно, существует множество способов воспроизведения и настройки воспроизведения звука в вашем приложении с множеством доступных библиотек, а также встроенными функциями Javascript.
Однако, когда требуется звук с чрезвычайно низкой задержкой или вам нужен максимальный контроль над каждой частью звука вашего приложения, AudioContext
— отличный выбор!