W3docs

JavaScript Web Audio API

Web Audio API в JavaScript: аудиограф из AudioContext и AudioNode, загрузка и воспроизведение звуков, громкость и генерация тонов.

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

Введение в Web Audio API

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

Мыслим аудиографами

Любой звук в Web Audio API проходит по цепочке узлов — от источника до получателя (destination):

source  →  (effects)  →  destination
 (file,    (gain,        (your
 oscillator)  filter)     speakers)

Три понятия, с которых стоит начать:

  • AudioContext — контейнер, которому принадлежит весь граф и аудиочасы. Вы создаёте один контекст на страницу и переиспользуете его.
  • AudioNode — модульная единица обработки. Узлы-источники производят звук (буфер или осциллятор), узлы-эффекты преобразуют его (gain, filter, panner), а узел destination отправляет его на динамики.
  • AudioBuffer — декодированные аудиоданные в памяти. Идеально подходят для коротких звуков (эффектов, сэмплов), которые нужно запускать многократно и с точным таймингом.

Граф строится вызовами node.connect(otherNode). Звук всегда заканчивается в audioContext.destination.

Начало работы с Web Audio API

Чтобы работать со звуком, сначала создайте AudioContext — контейнер для вашего аудиографа.

Создание AudioContext

const audioContext = new (window.AudioContext || window.webkitAudioContext)();

Этот код инициализирует новый AudioContext. Запасной вариант webkit нужен для старых версий Safari; современные браузеры напрямую поддерживают AudioContext без префикса.

Подвох политики автовоспроизведения. Браузеры создают контекст в состоянии "suspended" и отказываются воспроизводить звук, пока пользователь не взаимодействует со страницей (клик или нажатие клавиши). Всегда возобновляйте контекст внутри обработчика события, прежде чем играть звук:

button.addEventListener("click", async () => {
  if (audioContext.state === "suspended") {
    await audioContext.resume();
  }
  // ...now it is safe to play
});

Если звука нет, а в консоли нет ошибок, чаще всего причина в невозобновлённом контексте.

Загрузка и воспроизведение аудио

Чтобы воспроизвести звуковой файл, загрузите его в AudioBuffer, а затем подключите к контексту узел-источник.

Загрузка аудиофайлов

Здесь используются Fetch API и async/await: файл скачивается и декодируется:

async function loadAudioFile(url, audioContext) {
  const response = await fetch(url);
  const arrayBuffer = await response.arrayBuffer();
  const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
  return audioBuffer;
}

Функция загружает файл, читает его как «сырой» ArrayBuffer и передаёт в decodeAudioData, который распаковывает такие форматы, как MP3, WAV или OGG, в готовый к воспроизведению AudioBuffer. Декодирование выполняется вне основного потока и возвращает промис, поэтому его нужно дождаться через await.

Воспроизведение загруженного аудио

function playAudio(audioBuffer, audioContext) {
  const sourceNode = audioContext.createBufferSource();
  sourceNode.buffer = audioBuffer;
  sourceNode.connect(audioContext.destination);
  sourceNode.start();
}

Код создаёт BufferSourceNode, указывает ему декодированный буфер, подключает его к динамикам (audioContext.destination) и запускает воспроизведение.

Узел-источник одноразовый. AudioBufferSourceNode можно запустить только один раз — после остановки для повторного воспроизведения того же буфера нужно создать новый узел. Сам AudioBuffer пригоден для повторного использования, поэтому храните буфер и каждый раз пересоздавайте дешёвый узел-источник:

// ❌ Throws after the first play: "cannot call start more than once"
// sourceNode.start();
// sourceNode.start();

// ✅ One fresh source node per playback
function playOnce(buffer, ctx) {
  const src = ctx.createBufferSource();
  src.buffer = buffer;
  src.connect(ctx.destination);
  src.start();
}

Обработка звука

Web Audio API раскрывается в полную силу, когда между источником и получателем вставляются узлы-эффекты. Самый распространённый из них — узел gain для управления громкостью.

Создание узла Gain

function createGainNode(audioContext, volume) {
  const gainNode = audioContext.createGain();
  gainNode.gain.value = volume; // 1 = full volume, 0 = silent, 0.5 = half
  return gainNode;
}

GainNode умножает сигнал на значение gain. Свойство gain — это AudioParam, поэтому вместо резкой установки значения можно запланировать плавное изменение во времени (для затуханий и нарастаний):

// Fade from silent to full volume over 2 seconds, avoiding clicks/pops
gainNode.gain.setValueAtTime(0, audioContext.currentTime);
gainNode.gain.linearRampToValueAtTime(1, audioContext.currentTime + 2);

Соединение узлов для аудиоэффектов

function applyEffects(audioBuffer, volume, audioContext) {
  const sourceNode = audioContext.createBufferSource();
  sourceNode.buffer = audioBuffer;

  const gainNode = createGainNode(audioContext, volume);

  // source → gain → destination
  sourceNode.connect(gainNode);
  gainNode.connect(audioContext.destination);

  sourceNode.start();
}

Так строится граф из трёх узлов: источник подаёт сигнал на узел gain, а узел gain — на получателя. Другие узлы-эффекты добавляются так же — например, BiquadFilterNode для формирования тембра:

const filter = audioContext.createBiquadFilter();
filter.type = "lowpass";      // let low frequencies through, cut highs
filter.frequency.value = 800; // cutoff in Hz

sourceNode.connect(filter);
filter.connect(gainNode);
gainNode.connect(audioContext.destination);

Порядок имеет значение: сигнал идёт в том направлении, в котором вы вызываете connect.

Рабочий пример: генератор тона

Для самодостаточной демонстрации, которой не нужен аудиофайл, вот генератор тона на основе осциллятора. Он также учитывает политику автовоспроизведения, возобновляя контекст при первом клике.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Simple Tone Generator</title>
  </head>
  <body>
    <h1>Simple Tone Generator</h1>
    <button onclick="playTone()">Play Tone</button>
    <button onclick="stopTone()">Stop Tone</button>

    <script>
      let audioContext;
      let oscillator;

      async function playTone() {
        if (!audioContext) {
          audioContext = new (window.AudioContext ||
            window.webkitAudioContext)();
        }
        // Satisfy the autoplay policy: resume on user gesture
        if (audioContext.state === "suspended") {
          await audioContext.resume();
        }
        if (!oscillator) {
          oscillator = audioContext.createOscillator();
          oscillator.type = "sine"; // Sine wave — other values are 'square', 'sawtooth', 'triangle'
          oscillator.frequency.setValueAtTime(440, audioContext.currentTime); // A4 note, 440 Hz
          oscillator.connect(audioContext.destination);
          oscillator.start();
        }
      }

      function stopTone() {
        if (oscillator) {
          oscillator.stop();
          oscillator.disconnect();
          oscillator = null; // Reset the oscillator to allow a new one to be created next time
        }
      }
    </script>
  </body>
</html>

Как это работает:

  • Узел осциллятора — генерирует чистую синусоиду частотой 440 Гц (нота ля первой октавы, A4, по которой настраивают инструменты). Другие значения type — "square", "sawtooth" и "triangle", и у каждого свой тембр.
  • Управляющие функции — playTone возобновляет контекст и запускает осциллятор; stopTone останавливает его, отключает и сбрасывает переменную, чтобы в следующий раз можно было создать новый осциллятор.
  • Зачем сбрасывать oscillator = null? Как и узел-источник буфера, осциллятор одноразовый: после остановки его нельзя перезапустить, поэтому для следующего тона создаётся новый.

Когда использовать Web Audio API

СценарийЧто выбрать
Воспроизвести одну фоновую композицию или подкастОбычный элемент <audio> — проще и меньше кода
Звуковые эффекты в игре с точным таймингомWeb Audio API + AudioBuffer
Управление громкостью, плавные переходы, фильтры, панорамированиеУзлы gain/filter/panner из Web Audio API
Синтезаторы и сгенерированные тонаOscillatorNode из Web Audio API
Визуализаторы формы волны и частот в реальном времениAnalyserNode из Web Audio API

Если нужны только запуск и остановка воспроизведения, достаточно элемента <audio>. Выбирайте Web Audio API, как только вам понадобится обработка, точный тайминг или синтез.

Заключение

Web Audio API превращает браузер в программируемый микшерный пульт: вы соединяете граф узлов от источника через эффекты к динамикам и управляете каждым этапом в реальном времени. Запомните главное:

  • Создавайте один AudioContext и возобновляйте его по действию пользователя перед воспроизведением.
  • Переиспользуйте AudioBuffer, но для каждого воспроизведения создавайте новый узел-источник или осциллятор.
  • Стройте эффекты, соединяя узлы через connect() и всегда завершая цепочку в audioContext.destination.

Дальше можно изучить другие возможности браузера, например Web MIDI API для подключения музыкальных инструментов или Web Animations API для синхронизации визуальных эффектов со звуком.

Практика

Практика
Какие утверждения верны относительно возможностей Web Audio API?
Какие утверждения верны относительно возможностей Web Audio API?
Was this page helpful?