Как работает синхронизация WebAudio? Является ли использование setInterval плохим решением?
Я пытаюсь сделать синтезатор / секвенсор с API WebAudio. Главным образом пытаясь создать что-то, что может воспроизводить песню, состоящую из нот и событий, таких как MIDI, для управления несколькими каналами синтезатора. Но мне все еще нужно заняться моментом времени.
Я читал учебники по API WebAudio, но я не совсем понимаю, как работает тайминг / планирование / часы. Сначала я сделал полифонический синтезатор, который воспроизводил ноты для нажатий клавиш, и это не требовало внимания к выбору времени. Затем я сделал воспроизведение осциллятора массивом заметок через определенные промежутки времени, используя setInterval
, Однако, как я заметил в прошлом при переключении вкладок в Google Chrome, скорость воспроизведения значительно замедлилась, я предполагаю, что она менее ресурсоемкая - но другие библиотеки синтезаторов не имели этой проблемы. Также я могу только предположить, что с помощью setInterval
не подходит для плавного (буферизуется ли правильное слово?) воспроизведения, особенно если рассматривать генераторы огибающих ADSR.
Судя по тому, что я читаю, API-интерфейс WebAudio постоянно расширяется. currentTime
переменная таймера. Но если заметки хранятся в массиве, и я хочу циклически повторять его с заданной скоростью, как бы можно было манипулировать таймером WebAudio для итерации массива с заданной скоростью? Мое решение setInterval (предупреждение о громкости) вообще не учитывает таймер WebAudio, а просто вызывает voice()
с setInterval
играть ноту, перезаписывая последний сыгранный голос.
Существуют ли лучшие или эффективные способы воспроизведения / зацикливания последовательности нот, кроме setInterval
?
Просто обновление, чтобы уточнить: когда я писал этот вопрос, я использовал setInterval
проигрывать последовательность нот с фиксированными интервалами (например, внеплановые - постоянно запускать / останавливать генераторы) и интересовался более надежными способами воспроизведения нот. Я обнаружил, что лучшим решением было бы использовать setValueAtTime
на osc.frequency
также как и GainNode
, Для простого прототипа синтезатора это работает хорошо, но более продвинутый синтезатор может использовать таймер на osc.start
а также osc.stop
, Проблема в зацикливании песни. Чтобы зациклить, мне нужно постоянно планировать больше нот, чтобы к концу песни все начиналось заново. я могу использовать setInterval
запланировать весь цикл песни, но он все еще должен держать время при воспроизведении песни, и setInterval
(и даже веб-работников onmessage
звонки) может быть замедлено, например, когда вкладка неактивна. Часы setInterval даже не надежны, поэтому я просто проверяю каждые 5 мс, если (currentTime >= songTime)
и график, если условие выполнено. Этот метод не может быть слишком эффективным. Что у меня так далеко.
1 ответ
Я написал эту статью несколько лет назад: https://www.html5rocks.com/en/tutorials/audio/scheduling/. Это касается различий между таймерами веб-аудио и setInterval; Короче говоря, вы не можете "манипулировать временем" в веб-аудио часах, они управляются аппаратными часами в вашей звуковой карте. Вы можете запланировать события, происходящие в его временном интервале, используя setInterval в качестве напоминания о очень медленном или медленном цикле для планирования новых событий.
Что касается проблемы с переключением вкладок, это ограничение частоты 1 Гц, которое большинство современных браузеров должны избегать затрат на электроэнергию от людей, использующих setInterval в качестве таймера рендеринга (например, setInterval с интервалом 16 мс, чтобы попытаться запланировать каждый кадр видео). Вы можете избежать этого двумя способами - взломать с помощью Web Workers, который я использую в своей демонстрации метронома ( https://github.com/cwilso/metronome), или вы можете подключиться, когда окно теряет фокус (запуск события onblur на объекте окна), чтобы начать планирование более чем 1 с событий одновременно. Единственная проблема заключается в том, что когда окно снова фокусируется (событие onfocus срабатывает на объект окна), у вас будет до запланированных в секундах событий, уже запланированных в Web Audio - вы не можете переключиться обратно в окно и сразу же нажать " стоп ", например
setInterval сам по себе не является отличным решением для музыкальной синхронизации повторяющихся ритмов, поскольку он будет дрожать (т. е. будет задерживаться), когда в основном потоке происходят существенные другие вещи (включая сборку мусора). Вы начнете слышать дрожание, особенно на менее мощных процессорах.