Статьи

API-интерфейс Web Audio: добавьте звук, подходящий для полосы пропускания, на вашу веб-страницу

Эта статья была рецензирована Марком Брауном и Джошем Ведекиндом . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!

Человек перед камином слушает звуки граммофона

API-интерфейс Web Audio позволяет разработчикам использовать мощные методы обработки звука в браузере с использованием JavaScript без использования плагинов. Помимо определения и обработки файловых аудиоисточников в режиме реального времени, он может синтезировать звуки на основе различных сигналов; это может быть полезно для веб-приложений, которые часто используются в сетях с низкой пропускной способностью.

В этом руководстве я собираюсь познакомить вас с API Web Audio, представив некоторые из его более полезных методов. Я продемонстрирую, как его можно использовать для загрузки и воспроизведения mp3-файла, а также для добавления звуков уведомлений в пользовательский интерфейс ( демонстрация ).

Если вам нравится эта статья и вы хотите углубиться в эту тему, я создаю серию из 5 частей для SitePoint Premium под названием « Вы еще ничего не слышали!»

Что я могу сделать с помощью Web Audio API?

Варианты использования API в производстве разнообразны, но некоторые из наиболее распространенных включают в себя:

  • Обработка звука в реальном времени, например, добавление реверберации к голосу пользователя
  • Генерация звуковых эффектов для игр
  • Добавление звуков уведомлений в пользовательские интерфейсы

В этой статье мы в конечном итоге напишем некоторый код для реализации третьего варианта использования.

Хорошо ли это поддерживается браузерами?

Веб-аудио поддерживается Chrome, Edge, Firefox, Opera и Safari. Тем не менее, на момент написания Safari считает эту функцию браузера экспериментальной и требует префикса webkit

Использование API

Точкой входа API Web Audio является глобальный конструктор AudioContext . При реализации он предоставляет методы для определения различных узлов, которые соответствуют интерфейсу AudioNode . Их можно разделить на три группы:

  • Исходные узлы — например, источник MP3, синтезированный источник
  • Узлы эффекта — например, панорамирование
  • Узлы назначения — AudioContextdestinationAudioContext это представляет собой устройство вывода пользователя по умолчанию, такое как динамики или наушники

Эти узлы могут быть объединены в различные комбинации с использованием метода соединения . Вот общая идея построения аудиографа с помощью API Web Audio.

Построение аудио графа с помощью AudioContext
Источник: MDN

Вот пример преобразования файла MP3 в AudioBufferSourceNode и воспроизведения его через узел destinationAudioBufferSourceNode

Генерация аудио

Помимо поддержки записанного звука через OscillatorNodeOscillatorNode . Это позволяет генерировать частоты на основе определенной формы волны. Но что это на самом деле означает?

На высоком уровне частота определяет высоту звука, измеряемую в Гц. Чем выше частота, тем выше будет высота звука. Помимо пользовательских волн, type'sine'

Встроенные осциллограммы, поддерживаемые OscillatorNode
Источник: Омегатрон / Википедия

  • 'square'
  • 'triangle'
  • 'sawtooth'
  • OscillatorNode

Вот пример того, как OscillatorNode можно использовать для синтеза звука в режиме реального времени:

Как OscillatorNode приносит пользу сети?

Возможность синтезировать звуки с помощью кода приведет к гораздо меньшей полезной нагрузке, чем при использовании файлов. Это важно для поддержания четности вашего приложения на всех видах пропускной способности, от 2G до 4G. Невозможно гарантировать скорость мобильной передачи данных, особенно на развивающихся рынках.

48 процентов тех, кто использует мобильный интернет в сетях 2G или 3G, не могут почувствовать разницу между услугами 2G и 3G.

Ericsson, меняющийся ландшафт мобильного широкополосного доступа

Чтобы продемонстрировать это, я записал приведенный выше пример OscillatorNode Полученный файл имеет размер 10 КБ, и, в соответствии с функцией регулирования сети Chrome Dev Tools, загрузка по обычному соединению 2G займет 2,15 секунды. В этом случае программный подход является явным победителем.

Использование OscillatorNode для звуков уведомлений

Давайте использовать AudioContext В начале статьи я упоминал, что мы добавим звуки уведомлений в пользовательский интерфейс. Если мы откроем этот CodePen , то увидим пользовательский интерфейс приложения обмена сообщениями. После нажатия кнопки « Отправить» появится уведомление о том, что сообщение было отправлено. Этот шаблон содержит две части, которые представляют для нас интерес; экземпляр contextplaySoundplaySound

Перед началом нажмите кнопку Fork . Это создаст копию шаблона, на котором вы можете сохранить свои изменения.

Стоит отметить, что я протестировал это как в Chrome, так и в Firefox, поэтому вы должны использовать один из этих браузеров.

В oscillatorNodecontext.createOscillator()const oscillatorNode = context.createOscillator();

 type

Далее давайте настроим наш узел. Установите для его свойства 'sine'frequency.value150

 oscillatorNode.type = 'sine';
oscillatorNode.frequency.value = 150;

Чтобы воспроизвести нашу синусоидальную волну через наши динамики или наушники, вызовите oscillatorNode.connectcontext.destination Наконец, давайте вызовем oscillatorNode.startoscillatorNode.stopcontext.currentTime + 0.5 это остановит звук через 500 миллисекунд в соответствии с меткой времени аппаратного планирования нашего AudioContext's Наш метод playSound

 function playSound() {
  const oscillatorNode = context.createOscillator();

  oscillatorNode.type = 'sine';
  oscillatorNode.frequency.value = 150;

  oscillatorNode.connect(context.destination);
  oscillatorNode.start();
  oscillatorNode.stop(context.currentTime + 0.5);
}

После сохранения изменений и нажатия кнопки « Отправить» мы услышим звук уведомления.

Представляем GainNode

Само собой разумеется, это довольно броско. Почему бы не использовать узел эффектов, чтобы сделать этот звук более приятным? GainNode — один из примеров узла эффектов. Усиление является средством изменения амплитуды входного сигнала, и в нашем случае оно позволяет нам контролировать громкость аудиоисточника.

Под объявлением oscillatorNodegainNodecontext.createGain()

 const gainNode = context.createGain();

В конфигурации oscillatorNodegainNodegain.value Это будет воспроизводить звук на 30% от его первоначальной громкости:

 gainNode.gain.value = 0.3;

Наконец, чтобы добавить GainNodegainNodeoscillatorNode.connectgainNode.connectcontext.destination

 function playSound() {
  const oscillatorNode = context.createOscillator();
  const gainNode = context.createGain();

  oscillatorNode.type = 'sine';
  oscillatorNode.frequency.value = 150;

  gainNode.gain.value = 0.3;

  oscillatorNode.connect(gainNode);
  gainNode.connect(context.destination);

  oscillatorNode.start();
  oscillatorNode.stop(context.currentTime + 0.5);
}

После сохранения изменений и нажатия кнопки « Отправить» мы услышим, что наш звук звучит тише.

Смешивание вещей с AudioParam

Возможно, вы заметили, что для того, чтобы установить частоту нашего OscillatorNodeGainNodevalue Причина этого контракта заключается в том, что gainfrequencyAudioParam . Это интерфейс, который можно использовать для установки не только определенных значений, но и запланированных, постепенно меняющихся значений. AudioParam

  • setValueAtTime
  • linearRampToValueAtTime
  • exponentialRampToValueAtTime В отличие от линейного изменения, которое является постоянным, экспоненциальное изменение будет увеличиваться или уменьшаться с большими приращениями по мере приближения планировщика к конечному времени. Это может быть предпочтительнее, так как звучит более естественно для человеческого слуха

Теперь мы будем экспоненциально увеличивать частоту и усиление. Чтобы использовать метод exponentialRampToValueAtTime Замените oscillatorNode.frequency.valueoscillatorNode.frequency.setValueAtTime Передайте ту же частоту 150context.currentTime

 oscillatorNode.frequency.setValueAtTime(150, context.currentTime);

Ниже вызова setValueAtTimeoscillatorNode.frequency.exponentialRampToValueAtTime500 Запланируйте это 0.5

 oscillatorNode.frequency.exponentialRampToValueAtTime(500, context.currentTime + 0.5);

После сохранения и нажатия кнопки « Отправить» вы услышите, что частота увеличивается по мере воспроизведения.

Чтобы обернуть вещи, замените настройку gainNode.gain.valuegainNode.gain.setValueAtTimeOscillatorNode

 gainNode.gain.setValueAtTime(0.3, context.currentTime);

Чтобы ослабить звук, экспоненциально увеличивайте усиление до 0.010.5

 function playSound() {
  const oscillatorNode = context.createOscillator();
  const gainNode = context.createGain();

  oscillatorNode.type = 'sine';
  oscillatorNode.frequency.setValueAtTime(150, context.currentTime);
  oscillatorNode.frequency.exponentialRampToValueAtTime(500, context.currentTime + 0.5);

  gainNode.gain.setValueAtTime(0.3, context.currentTime);
  gainNode.gain.exponentialRampToValueAtTime(0.01, context.currentTime + 0.5);

  oscillatorNode.connect(gainNode);
  gainNode.connect(context.destination);

  oscillatorNode.start();
  oscillatorNode.stop(context.currentTime + 0.5);
}

После нажатия кнопки « Сохранить и отправить» вы услышите, что со временем звук нашего уведомления становится тише. Теперь мы звучим более человечно.

Вот законченное демо.

Воспроизведение исходных узлов

Прежде чем закончить эту статью, важно отметить путаницу для тех, кто знакомится с API. Чтобы снова воспроизвести наш звук после его завершения, казалось бы, имеет смысл написать следующее:

 oscillatorNode.start();
oscillatorNode.stop(context.currentTime + 0.5);
oscillatorNode.start(context.currentTime + 0.5);
oscillatorNode.stop(context.currentTime + 1);

После этого мы увидим, что InvalidStateErrorcannot call start more than once

AudioNode В нашем случае нам пришлось бы снова вызывать функцию playSound

Вывод

Надеюсь, вам понравилось это введение в синтез звука с помощью Web Audio API. Мы продемонстрировали один из его многочисленных вариантов использования, хотя рост количества уведомлений на веб-сайтах и ​​в веб-приложениях — интересный вопрос UX, на который можно будет ответить только со временем.

Если вы хотите узнать больше об API Web Audio, я делаю серию из 5 частей для SitePoint Premium под названием « Вы еще ничего не слышали!» , Первый эпизод доступен для просмотра сейчас.

Используете ли вы API Web Audio на своих веб-страницах и в приложениях? Я хотел бы услышать о вашем опыте и случаях использования в комментариях ниже.