Web Audio API – новые возможности генерации, обработки и объемного распределения звука в браузере.

dj1Web Audio API – одна из новинок, которая значительно расширяет возможности web приложений при работе со звуком. Это мощнейший инструмент, без которого Вам сложно будет обойтись в будущем при разработке современных игр и интерактивных веб приложений. API достаточно высокоуровневый, продуман до мелочей, самодостаточен, легок в освоении и особенно элегантно интегрируется в приложения, использующие WebGl и WebRTC.

Если вы лучше воспринимаете видео, можете посмотреть мое выступление по мотивам этой статьи на Web Standards Days в на Yandex Events (Декабрь 2013)

Но, все же, в статье все описано более развернуто ;)

Web audio api yandex web standards days 2013

Немного истории…

web audio api vs tag audio

Давным давно на заре развития веб Internet explorer предпринял робкую попытку разрушить тишину, царящую в браузере, придумал тэг <bgsound>, который позволял автоматически проигрывать midi файлы при открытии сайта. В ответ на это разработчики Netscape добавили аналогичную функцию с помощью тега <embed> . Ни одно из этих решений так и не было стандартизовано, как, в принципе, и не было впоследствии наследовано остальными браузерами.

Прошло несколько лет и в браузерах начали активно использоваться сторонние плагины. Проигрывать аудио стало возможным с помощью Flash, Silverlight, QuickTime и т.п. Все они хорошо выполняли свою роль, но все же плагин имеет кучу недостатков. Поэтому возможность иметь инструмент для работы со звуком, поддерживаемый веб стандартами, уже давно будоражила умы разработчиков. С массовым приходом мобильных браузеров, не поддерживающих Flash, проблема стала еще острее.

Пионером в борьбе с тишиной без плагинов стал элемент <audio>, появившийся уже в первой спецификации html5. Он позволяет проигрывать аудио файлы и стримы, контролировать воспроизведение, буферизацию и уровень звука. Кроме того, он прост в использовании и понимании. Сейчас он поддерживается всеми мобильными и десктопными браузерами (включая IE9), работает достаточно хорошо, но говорить сегодня мы будем не об <audio> элементе.

Мы поговорим о Web Audio API, который призван выполнять гораздо более интересные, разносторонние и сложные задачи.

web audio API – это НЕ элемент <audio> и НЕ его надстройка.

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

web audio api vs tag audio

Задачи, которые призван решать элемент <audio>:

  • Простой аудио плеер
  • Однопоточное фоновое аудио.
  • Аудио подсказки, капчи и т.п.

Задачи, которые призван решать Web Audio API:

  • Объемный звук для игр и интерактивных веб приложений
  • Приложения для обработки звука
  • Аудио синтез
  • Визуализация аудио и многое, многое, многое другое…

Преимущества Web Audio API

  • Абсолютно синхронное воспроизведение аудио (возможность проигрывать сотни семплов одновременно с разницей в миллисекунды, точно планируя начало и конец воспроизведения каждого из них)
  • Возможность обработки звука с помощью десятков встроенных высокоуровневых блоков (фильтров, усилителей, линий задержки, модулей свертки, и т.д.)
  • Богатые возможности для синтеза колебаний звуковой частоты с различной формой огибающей. (Можно написать простейший синтезатор за 10 мин)
  • Работа с многоканальным аудио (Исходя из спецификации, API обязан поддерживать до 32 каналов аудио!!! Для справки: стерео – это 2 канала, Dolby Digital – это 5 каналов, самый навороченный Dolby TrueHD – 8 каналов, т.е на сегодняшний день у немногих пользователей дома есть звуковые карты с более чем 8-ю каналами :)
  • Непосредственный доступ к временным и спектральным характеристикам сигнала (позволяет делать визуализации и анализ аудио потока)
  • Высокоуровневое 3D распределение аудио по каналам, в зависимости от положения, направления и скорости источника звука и слушателя (что особенно круто при разработке объемных WebGL игр и приложений)
  • Тесная интеграция с WebRTC (как источник звука можно использовать системный микрофон, подключить гитару или микшер. Вы также можете получить аудио из любого внешнего стрима, как, впрочем, и отправить его туда же)

Проблемы на текущий момент (10.2013)

  1. API все еще находится в стадии черновика и немного меняется. В большинстве своем это изменения в названиях методов и наборе параметров. Например, еще полгода назад для того, чтобы начать воспроизведение, нужно было использовать source.noteOn(0), сейчас это source.start(0). Проблема небольшая и Вы можете использовать обертку AudioContext-MonkeyPatch, которую при желании можно поддержать своими пулл реквестами.
  2. Поддержка браузерами. На сегодняшний день Chrome, Safari, Opera, FF25+, Chrome android, Safari iOS, поддерживают Web Audio API в полном объеме. IE и некоторые мобильные браузеры думают о поддержке в “ближайшем” будущем. Подробнее можно посмотреть тут caniuse.
  3. Пока не существует хорошего универсального аудио формата, который можно не задумываясь использовать в web приложениях. Форматов много (mp3, mp4, wma, ogg, aac, WebM,…) и браузеров тоже много. При этом каждый браузер пытается продвигать свой набор форматов. Подробнее можно посмотреть тут. В итоге, ни один из перечисленных форматов не поддерживается всеми браузерами (09.2013). Для решения проблемы Вам иногда могут понадобится одни и те же аудио семплы, представленные в разных форматах для разных браузеров.

Начинаем погружение. Audio context

Одним из основополагающих понятий при работе с Web Audio API является аудио контекст.

JS

var context = new AudioContext();

Пока спецификация находится в черновике, в webkit браузерах нужно использовать webkitAudioContext. Т.е что-то наподобие:

JS

var context;
window.addEventListener('load', function(){
  try {
    window.AudioContext = window.AudioContext||window.webkitAudioContext;
    context = new AudioContext();
  }
  catch(e) {
    alert('Opps.. Your browser do not support audio API');
  }
}, false);

У одного документа может быть только один контекст. Этого вполне достаточно для всего спектра задач решаемого Web Audio API. Наличие одного аудио контекста позволяет строить сколь угодно сложные аудио графы с неограниченым количеством источников и получателей звукового сигнала. Практически все методы и конструкторы для создания аудио модулей являются методами аудио контекста.

Возможные источники звукового сигнала:

  1. AudioBufferSourceNode – аудио буфер (рассмотрим ниже)
  2. MediaElementAudioSourceNode<audio> или <video> элемент
  3. MediaStreamAudioSourceNode – внешний аудио поток (стрим) (микрофон или любой другой аудио стрим, в том числе внешний)

Возможные получатели звукового сигнала:

  1. context.destination – системный звуковой выход по умолчанию (в типичном случае – колонки).
  2. MediaStreamAudioDestinationNode – аудио поток (стрим). Этот поток может быть использован таким же образом, как поток, полученный через getUserMedia(), и, к примеру, может быть отправлен на удаленный RTCPeerConnection с помощью метода addStream().

Строим графы (схемы обработки аудио)

В любой задуманной Вами схеме может быть один или несколько источников и получателей звукового сигнала, а также модули для работы со звуком (далее мы рассмотрим каждый из них подробнее). Схема может быть с прямыми и обратными связями, каждый модуль может иметь сколь угодно много входов/выходов. Всю заботу о правильном функционировании берет на себя API. Ваша задача состоит в том, чтобы соединить все правильно. Давайте представим себе некую абстрактную схему, просто чтобы разобраться, как она строится при помощи кода.

connect nodes web audio api

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

JS

source1.connect(node1);
source2.connect(node3);
node1.connect(node4);
node1.connect(node2);
node2.connect(destination);
node3.connect(node1);
node4.connect(destination);
node4.connect(node3);

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

Давайте рассмотрим простейший, но довольно типовой пример работы с web Audio API, где источником звукового сигнала является буфер, созданный из аудио файла, предзагруженного с помощью XMLHttpRequest (AJAX), а получателем является системный звуковой выход.

JS

// создаем аудио контекст
var context = new window.AudioContext(); //
// переменные для буфера, источника и получателя
var buffer, source, destination; 

// функция для подгрузки файла в буфер
var loadSoundFile = function(url) {
  // делаем XMLHttpRequest (AJAX) на сервер
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = 'arraybuffer'; // важно
  xhr.onload = function(e) {
    // декодируем бинарный ответ
    context.decodeAudioData(this.response,
    function(decodedArrayBuffer) {
      // получаем декодированный буфер
      buffer = decodedArrayBuffer;
    }, function(e) {
      console.log('Error decoding file', e);
    });
  };
  xhr.send();
}

// функция начала воспроизведения
var play = function(){
  // создаем источник
  source = context.createBufferSource();
  // подключаем буфер к источнику
  source.buffer = buffer;
  // дефолтный получатель звука
  destination = context.destination;
  // подключаем источник к получателю
  source.connect(destination);
  // воспроизводим
  source.start(0);
}

// функция остановки воспроизведения
var stop = function(){
  source.stop(0);
}

loadSoundFile('example.mp3');

Давайте опробуем этот код в действии. Этот и все остальные примеры работают в webkit, чтобы объяснить основные принципы API. Целью статьи не было сделать их рабочими во всех браузерах :)

Web audio simple

Модули

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

построение схем web audio api Давайте рассмотрим основные модули, начиная с самых простых.

Gain (Усилитель)

Модуль позволяет изменять уровень звукового сигнала.

Любой модуль Web Audio API можно создать, используя соответствующий конструктор объекта context. Для того, чтобы получить новый объект gain, нужно просто вызвать context.createGain(). Далее Вы можете конфигурировать полученный объект как до начала, так и во время воспроизведения. Конфигурация, a также ее возможности и способы зависят от типа модуля, но в большинстве случаев все сводится к простой установке значений для соответствующих полей объекта. Вот пример того, как создать модуль gain и изменить его уровень усиления.

JS

var gainNode = context.createGain();
gainNode.gain.value = 0.4; // значение 0..1 (можно изменять динамически)

Вставляем усилитель в вышеописанную схему между источником и получателем:

JS

source.connect(gainNode);
gainNode.connect(destination);

И начинаем воспроизведение:

JS

source.start(0);

Web audio gain node

Как Вы уже поняли, все действительно круто и продумано. Для более наглядного примера давайте сделаем простой crossfade эффект, которым можно управлять вручную с помощью слайдера. Нам понадобится 2 источника звука и 2 модуля gain.

Web audio crossfade effect

Мы не будем приводить код примера, дабы не засорять статью, однако Вы всегда можете открыть пример в новом окне, проинспектировать и посмотреть, как он работает.

Delay (Линия задержки)

Этот модуль позволяет задерживать звук на определенное время.

Создается и конфигурируется по такому же принципу, как вышеописанный gain.

JS

var delayNode = context.createDelay();
delayNode.delayTime.value = 2; // 2 секунды

source.connect(delayNode);
delayNode.connect(destination);
source.start(0);

Web audio delay node

Давайте для закрепления основных принципов создадим простую схему с бесконечным зацикливанием сигнала, используя gain для ослабления сигнала и delay для задержки. Так мы получим простейший “эхо” эффект.

source.connect(gainNode);
gainNode.connect(destination);
gainNode.connect(delayNode);
delayNode.connect(gainNode);

var now = context.currentTime;
source.start(now);
source.stop(now + 0.3);

Web audio delay and gain echo

Надо сказать, что это не самый лучший образец того, как нужно делать “эхо” эффект, и годится он только в качестве примера. Настоящее реалистичное эхо можно достигнуть с помощью модуля свертки звукового сигнала. Давайте рассмотрим его подробнее.

Convolution ( Свертка )

Говоря простым языком, свертка – это математическая операция, такая же как сложение, умножение или интегрирование. При сложении двух исходных чисел получается третье, при свертке – из двух исходных сигналов получается третий сигнал. В теории линейных систем свертка используется для описания отношений между тремя сигналами:

  • входным сигналом
  • импульсной характеристикой
  • выходным сигналом

Другими словами, выходной сигнал равен свертке входного сигнала с импульсной характеристикой системы.

convolution web audio api. Результат свертки с импульсной характеристикой простого одиночного эха

Что такое входной и выходной сигнал, вроде итак понятно. Осталось только разобраться со “страшным” словом импульсная характеристика (impulse response) :)

Давайте рассмотрим жизненный пример и все сразу станет ясно.

Вы пришли в лес. Громко крикнули что-нибудь своему другу. Что он услышит? Правильно! Ваш голос, только немного искаженный и с эффектом множественного эха. Дело в том, что совокупность аккустических колебаний, генерируемая Вашими связками и гортанью, прежде, чем попасть в ушную раковину Вашего друга, будет несколько изменена под воздействием окружающего пространства. Преломления и искажения возникнут, например, из-за влажности в лесу. Определенная часть энергии аккустического колебания будет поглощена мягким покрытием из мха. Также звук будет отражен от сотен деревьев и окружающих Вас предметов, находящихся на разном удалении. Можно еще долго перечислять все эти факторы, но давайте разберемся в том, какое отношение все это имеет к свертке :)

Вы уже наверно поняли, что в описанной ситуации входным сигналом (источником сигнала) будет то, что кричите Вы. Выходным же сигналом будет то, что слышит Ваш друг. А вот лес можно представить себе как линейную систему, способную изменять характеристики сигнала по неким правилам, зависящим от огромного набора факторов. Не вникая в теорию, всю эту савокупность правил можно представить в виде так называемой импульсной характеристики.

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

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

Web audio convolution

Модуль свертки создается, подключается и конфигурируется точно также, как и все остальные модули.

JS

convolverNode = context.createConvolver();
convolverNode.buffer = buffer; // impulse response

source.connect(convolverNode);
convolverNode.connect();

Практически во всех типовых случаях нужная Вам импульсная характеристика – это обычный аудио файл (чаще всего .wav). Как и входной сигнал, она должна быть предзагружена, декодирована и записана в буфер.

Где найти импульсные характеристики для различных эффектов? Ищите в гугле что-то типа “download free impulse response” и найдете их в огромном количестве. Например, тут, тут или тут.

В конце статьи будет несколько ссылок для желающих разобраться со сверткой подробнее. Движемся дальше и переходим к не менее интересной теме – фильтрации в Web Audio API.

Filter ( Фильтрация )

Под фильтрацией в цифровой обработке сигналов чаще всего подразумевают частотную фильтрацию. Если Вы знаете, что такое спектр сигнала, преобразование Фурье и амплитудно-частотная характеристика фильтра, то просто посмотрите пример. Если же Вы вообще не в курсе, что это такое, и времени разбираться нет, попробую объяснить на пальцах.

web audio api equalizer and frequancy response

Все пользовались эквалайзером в любимом winamp, aimp, itunes и т.п., наверняка, пробовали разные предустановленные режимы (бас, диско, вокал) и обязательно дергали ползунки на разных частотах, пытаясь добиться нужного звучания. Эквалайзер представляет собой устройство, которое может как усилить, так и ослабить определенные частоты (низкие, высокие частоты и т.п.)

Так вот, не вдаваясь в детали

  • Эквалайзер – это и есть частотный фильтр
  • Кривая, образованная всеми ползунками – это АЧХ (амплитудно-частотная характеристика) фильтра, а по-английски frequency response function.

Говоря простым языком, с помощью Web Audio API Вы можете добавить такой “эквалайзер” (фильтр) в свой граф обработки сигнала в виде модуля.

С настройкой амплитудно-частотной характеристики все будет немного сложнее. Дело в том, что исторически все распространенные типы фильтров уже имеют физические аналоги, у которых есть определенные параметры, характеризующие эти фильтры.

Вот список фильтров доступных из коробки:

  1. lowpass – фильтр нижних частот (обрезает все, что выше выбранной частоты)
  2. highpass – высокочастотный фильтр (обрезает все, что ниже выбранной частоты)
  3. bandpass – полосовой фильтр (пропускает только определенную полосу частот)
  4. lowshelf – полка на низких частотах (означает, что усиливается или ослабляется все, что ниже выбранной частоты)
  5. highshelf – полка на высоких частотах (означает, что усиливается или ослабляется все, что выше выбранной частоты)
  6. peaking – узкополосный пиковый фильтр (усиливает определенную частоту, народное название – “фильтр-колокол”)
  7. notch – узкополосный режекторный фильтр (ослабляет определенную частоту, народное название – “фильтр-пробка”)
  8. allpass – фильтр, пропускающий все частоты сигнала с равным усилением, однако изменяющий фазу сигнала. Происходит это при изменении задержки пропускания по частотам. Обычно такой фильтр описывается одним параметром — частотой, на которой фазовый сдвиг достигает 90°.

Для того, чтобы настраивать эти фильтры, существует несколько параметров, которые, как мы уже сказали, есть у физических аналогов фильтров. Эти параметры можно найти во всех книжках по теории обработки сигналов.

  • Frequency – частота, на которой базируется фильтр. Измеряется в герцах (Hz)
  • Q – (добротность) – ширина полосы вокруг выбранной частоты, к которой будет применяться усиление или ослабление. Чем выше значение Q, тем уже полоса. Чем ниже – тем шире.
  • Gain – уровень усиления или ослабления данной частоты. Измеряется в децибелах (dB). Увеличение мощности сигнала в 2 раза равно 3dB. В 4 раза – 6dB. В 8 раз – 9dB и т.д.

Тут нужно сказать, что не все параметры актуальны для конкретного типа фильтра (подробнее можно посмотреть тут)

Если Вы напуганы обилием новых слов, не расстраивайтесь!

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

js

var filterNode = context.createBiquadFilter(); 
filterNode.type = 1; // High-pass filter (Тип фильтра)
filterNode.frequency.value = 1000; // Cutoff to 1kHZ (Базовая частота)
filterNode.frequency.Q = 1; // Quality factor (Добротность)
//filterNode.gain.value = 1000; // Усиление (не нужно этому типу фильтра)

Web audio biquad filter

Анализатор

Анализатор предназначен для того, чтобы получать информацию о частотных и временных параметрах сигнала в виде массива данных. Как только Вы получите этот массив, сможете анализировать и визуализировать все, что происходит со звуком. Типовые примеры использования:

  • Отобразить форму или спектр сигнала на canvas
  • Смоделировать красивую 3D визуализацию звука в webGL
  • Сделать обработку для обнаружения каких-нибудь зависимостей в форме или спектре сигнала
  • Анализировать громкость на входе с микрофона
  • .. да что угодно, вплоть до текста на странице, прыгающего в такт музыке :)

js

var analyser = context.createAnalyser();

// Размерность преобразования Фурье
// Если не понимаете, что это такое - ставьте 512, 1024 или 2048 ;)
analyser.fftSize = 2048;

// Создаем массивы для хранения данных
fFrequencyData = new Float32Array(analyser.frequencyBinCount);
bFrequencyData = new Uint8Array(analyser.frequencyBinCount); 
bTimeData = new Uint8Array(analyser.frequencyBinCount);

// Получаем данные
analyser.getFloatFrequencyData(fFrequencyData); 
analyser.getByteFrequencyData(bFrequencyData); 
analyser.getByteTimeDomainData(bTimeData);

// дальше у Вас есть массивы fFrequencyData, bFrequencyData, bTimeData, с которыми можно делать все, что вздумается

Генератор

Генератор позволяет синтезировать сигналы различной формы и частоты. Все управляется 3-мя параметрами:

  1. type – форма сигнала (1 – синусоида, 2 – прямоугольный, 3 – пила, 4 – треугольный)
  2. frequency – частота генерации
  3. detune – расстройка (измеряется в центах). Каждая октава состоит из 1200 центов, и каждый полутон состоит из 100 центов. Указав расстройку 1200, Вы можете перейти на одну октаву вверх, а указав расстройку -1200 на одну октаву вниз.

web audio api oscillator signal types

А теперь соединяем генератор с вышеописанным анализатором и смотрим, что получилось.

js

oscillator = context.createOscillator(); 
analyser = context.createAnalyser();
oscillator.connect(analyser); 
analyser.connect(destination);
oscillator.start(0);

Все становится понятнее, если самостоятельно поиграться с демкой.

Web audio oscilator analyser

3D звук

Ну вот мы и добрались до самой крутой штуки в Web Audio API – распределения звука по каналам в трехмерном пространстве. Начнем с примера:

web audio api 3d

Что мы видим? Это типовая сцена 3D шутера. В ней есть герой, которого мы видим сзади. Он издает несколько звуков (бежит и стреляет), есть много нечисти, которая мечется и издает различные звуки, находясь на разном расстоянии от героя, есть фоновая музыка, есть ветер, который шумит вокруг и т.п.

Для того, чтобы сделать эту звуковую сцену 3D-реалистичной и объемной, нужно очень точно распределить звуки по каналам, в зависимости от положения, координат и скорости каждого из персонажей. В добавок ко всему, каналов может быть 2 (стерео), 5 (Dolby Digital), 8 (Dolby TrueHD), в принципе, сколько угодно, в зависимости от звуковой карты и установок системы. Да еще звуки от движущихся объектов должны иметь доплеровское смещение по частоте. Ну, и самое печальное то, что Ваше положение как слушателя, тоже меняется, если Вы смотрите на героя сбоку.

Возникает вопрос, как все просчитать? И вот она, самая главная фича – Web Audio API все сделает за Вас, т.е. вообще не надо ничего просчитывать. Нужно просто описать несколькими строчками кода координаты, направление и скорость движения каждого из источников звука и слушателя. И все! Всю остальную грязную работу берет на себя API, который распределит звук по каналам, учитывая при этом их количество, добавит доплера там, где надо и создаст сногсшибательный 3D звук.

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

Каждый паннер описывается:

  • координатами
  • направлением звука
  • скоростью движения.

js

// создадим, например, паннер для представления бегающей и гавкающей собаки
var panner = context.createPanner();
// подключаем источник гавканья к паннеру
barkingSource.connect(panner);
// подключаем собачий паннер к выходу
sound.panner.connect(destnation);

//  c какой-то периодичностью мы будем указывать 
panner.setPosition(q.x, q.y, q.z); // где сейчас находится собака
panner.setOrientation(vec.x, vec.y, vec.z); // в какую сторону она лает
panner.setVelocity(dx/dt, dy/dt, dz/dt); // c какой скоростью она бежит

В добавок к этому Вы, как слушатель ( context.listener ), тоже описываетесь:

  • координатами
  • направлением звука
  • скоростью движения.

js

context.listener.setPosition(q.x, q.y, q.z);
context.listener.setOrientation(vec.x, vec.y, vec.z);
context.listener.setVelocity(dx/dt, dy/dt, dz/dt);

По-моему, это очень круто!

Что еще?

Вот еще несколько интересных модулей с которыми можно что-нибудь придумать:

  • ChannelSplitterNode – разделение каналов
  • ChannelMergerNode – объединение каналов
  • DynamicsCompressorNode – динамический компрессор
  • WaveShaperNode – нелинейные искажения
  • ScriptProcessorNode – можно делать все что хотим (есть буффер чисел на входе, обрабатываем его и формируем буффер чисел на выходе модуля)

А здесь можно найти спецификацию, что-бы ощутить всю глубину web audio API.

А теперь ссылки и демки!

Эта статья опубликована во время конференции Minsk Web Standard Days 2013. Сама презентация есть тут и работает в webkit браузерах.

Жду вопросов, эмоций, критики, советов и т.п. в комментариях.

Метки: , , , ,
65 комментариев на “Web Audio API – новые возможности генерации, обработки и объемного распределения звука в браузере.
  1. Я что-то не уверен, что EMBED не появился в ответ на OBJECT. А теги AUDIO и VIDEO придумали в Microsoft, в составе технологии HTML+TIME, сто лет назад ещё.

  2. Юрий Кравець пишет:

    А есть ли обратный процесс к Свертке ? или возможно ли в Свертке от входного сигнала отнимать импульсную характеристику вместо того, чтобы додавать ее ?

  3. spahi4 пишет:

    Скажите, как сделать простейший визуалайзер (спектрограмму) ?

    • admin пишет:

      Создайте analyser

      analyser = context.createAnalyser();
      analyser.smoothingTimeConstant = 0.3;
      analyser.fftSize = 1024; 
      

      …. и подключите его (в статье описано как)

      Потом с нужным Вам интервалом можно брать данные с анализатора

      var bFrequencyData = new Uint8Array(analyser.frequencyBinCount)
      analyser.getByteFrequencyData(bFrequencyData);
      

      теперь в массиве bFrequencyData будут лежать данные спеkтра сигнала в текущий момент с этими данными Вы можете делать все что угодно (отображать на canvas и т.п) ;)

      Пишите, если совсем непонятно :) сделаю демку

  4. Юрий пишет:

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

    • admin пишет:

      Здравствуйте! Ну во первых API не наш. )) А ответ на Ваш вопрос, думаю: “нет, невозможно”
      Возможные источники звука для работы с web audio API описаны в статье (на основе спецификации). Других нет, да и надо ли? Это веб браузер..

  5. Сергей пишет:

    `// создаем аудио контекст
    if (typeof AudioContext == “function”) {var audioContext = new AudioContext();
    }else if(typeof webkitAudioContext == “function”) {var audioContext = new webkitAudioContext();}
    var source = audioContext.createBufferSource();
    source.connect(audioContext.destination);

    var xhr = new XMLHttpRequest();
    xhr.open(“GET”, “sound/open.wav”, true);
    xhr.responseType = “arraybuffer”;
    xhr.onload = function() {
    var buffer_open = audioContext.createBuffer(xhr.response, false);
    source.buffer = buffer_open;
    };
    xhr.send();

    // функция начала воспроизведения
    var play_open = function(){
    // воспроизводим
    source.start(0);
    }

    ….//Тут события на клик и воспроизводится звук
    `

    Но вот при втором клике! я получаю ошибку

    Uncaught InvalidStateError: Failed to execute ‘start’ on ‘AudioBufferSourceNode': cannot call start more than once.

    1)Вопросы как отследить что звук проигрался?
    2)Получается каждый раз нодо заново создавать буффер?

  6. Антон пишет:

    В примере, где говорится о загрузке в буфер через AJAX удобно использовать мелкие файлы.

    Но как поступать в случае, когда аудио файл это микс на 120 минут? Есть ли какая то возможность постепенно подгружать в буфер музыку одновременно начинать играть ту часть, которая подгрузилась?

    • admin пишет:

      привет, Антон! Можно

      Самое адекватное – это использовать тэг <audio> как источник звука для web audio api

      У <audio> есть постепенная буферизация

      т.е. когда хоть что-то подгружено – уже можно играть

      Пример есть тут :)

  7. rustam пишет:

    простите за лень ума. у вас есть время написать демку, которая из файла аудиокниги (голос сочетается с тишиной) , будет выделять интервалы речи (секунды начала и конца каждой фразы)?

    • admin пишет:

      Здравствуйте! Времени нет :(
      Мне кажется, это не такая уж тривиальная задача, как кажется на первый взгляд :)

      • rustam пишет:

        а получить массив из файла , где будут значения децибел звукового сигнала через каждую 0.1 секунды сложно?

        чтобы в консоле можно было этот массив посмотреть, например.

        • admin пишет:

          Если я правильно понял, есть файл (mp3, wav,..)
          Нужно получить значения децибел звукового сигнала через каждую 0.1 секунды и сложить эти значения в массив.

          Я бы делал так:

          var analyser = context.createAnalyser();
          analyser.fftSize = 2048;
          bTimeData = new Uint8Array(analyser.frequencyBinCount);
          

          Когда трек играет, через каждую 0.1с:

          analyser.getByteTimeDomainData(bTimeData);
          // bTimeData - массив с амплитудами временных отсчетов сигнала в текущий момент времени
          

          Эти значения можно использовать для получения уровня сигнала и складывать в массив. Готовое решение писать не буду :)

          • rustam пишет:

            большое спасибо за ответ.
            проделал этот пример с analyzer http://www.developphp.com/view.php?tid=1348 теперь и учитывая ваш ответ всё стало прозрачно

            остался только один вопрос – везде этот analyzer работает при проигрывании аудио. А нельзя ли обойтись без проигрывания? чтобы просто из тега аудио получить массив всех значений (как будто они проигрываются) для каждого момента.

  8. Vital пишет:

    Есть ли возможность получить мгновенное значение уровня сигнала на ноде?

    • привет,
      получаете массив спектральных отсчетов с помощью analyser и вычисляете среднее значение:

      var array =  new Uint8Array(analyser.frequencyBinCount);
      analyser.getByteFrequencyData(array);
      var average = getAverageVolume(array);
      

      а функция вычисления среднего значения уровня сигнала getAverageVolume может выглядеть примерно так:

      function getAverageVolume(array) {
          var values = 0;
          var average;
      
          var length = array.length;
      
          // get all the frequency amplitudes
          for (var i = 0; i < length; i++) {
              values += array[i];
          }
      
          average = values / length;
          return average;
      }
      

      пример есть тут: http://www.smartjava.org/examples/webaudio/example2.html

      • Vital пишет:

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

  9. Vital пишет:

    в фаерфоксе что ли не работают фильтры? что не выбираю, всегда только ФНЧ включается

  10. Роман пишет:

    Здравствуйте! Возможно ли в Аудио Апи загружать в буфер сразу кусочки из разных песен, а именно у меня есть песня меня интересует такой-то кусок с 10 секунды по 30, я его загружаю ,потом загружаю следующий фрагмент из другой песни, и в итоге получить некий звуковой трек который можно будет сохранить к себе в mp3 формате?

  11. Алексей пишет:

    доброго времени суток! уже недели 2 ищу что-нибудь про визуализацию и случайно наткнулся на эту статью. собственно вопрос такой, на сайте нужно сделать визуализацию в реальном времени, эквалайзер. желательно на яве ну или на хтмл (флеш не хотелось бы но возможно), есть какая нибудь информация, может что подскажете, как будет возможность?)

  12. Владимир пишет:

    Добрый день, столкнулся со следующей проблемой: createMediaElementSource в хроме отрабатывает хорошо, но в firefox не отрабатывает, вероятно по описанной в ответе здесь причине: http://stackoverflow.com/questions/19708561/firefox-25-and-audiocontext-createjavascriptnote-not-a-function
    (origin вещания отличается от origin документа)

    Вы сталкивались с такой проблемой ?
    Если да, то как ее обошли ?

    • Владимир пишет:

      Забавно, что пример, указанный здесь не работает в FireFox :)
      https://developer.mozilla.org/en-US/docs/Web/API/AudioContext.createMediaElementSource

    • Владимир пишет:

      Не хотелось бы перекомпилировать исходники IceCast2 для добавления в header
      access-control-allow-origin:*

    • Попробовал в FF31. Как обойти защиту с Access-Control-Allow-Origin пока не понятно (

      Как и описано на stackOverflow работает только с треками с того-же origin ((


      По поводу https://developer.mozilla.org/en-US/docs/Web/API/AudioContext.createMediaElementSource

      … дааа MediaElementSource в целом очень глючит в FF.

      А есть ли стойкие основания использовать именно MediaElementSource?

      Если нет, то можно попробовать работать с буфером.

      Вот сделал пример (работает в FF) http://jsfiddle.net/nedudi/rnry7gom/

      Правда, как и оговаривалось, стрим берется из внешнего источника с (soundcloud.com) c Access-Control-Allow-Origin:*

      • Владимир пишет:

        Спасибо за ответ.
        Решил проблему при помощи прокси-перенаправления на 80 порт
        Использую Apache, активировал модули:

        proxy
        proxy_http
        proxy_connect

        После чего написал в default конфигурацию следующую строку:

        ProxyPass /stream http://localhost:[мой порт]/ices

        Теперь Web Audio Api работает, но выявился забавный момент: по какой-то причине в FireFox звук идет моно, в отличие от Chrome. Может быть что-нибудь подскажите ?

  13. Елена пишет:

    Дмитрий, столкнулись с проблемой звучания миди-файлов непосредственно в браузере.Очень нужно , чтобы звучали файлы МИДИ не с предварительной загрузкой,как это обычно бывает, а на самом сайте. Нигде ничего подобного не нашли, ни на каких форумах. Помогите.) Спасибо.)

    • Добрый Вечер!
      В светлом будущем можно будет проигрывать .mid файлы при помощи web midi api, но пока это далекая перспектива.

      А на сегодняшний день, есть такая библиотека midi.js.
      Она находится тут https://github.com/mudcube/MIDI.js

      Я сделал набольшой пример. Вот что получилось с midi.js
      http://html5.by/blogdemo/midijs/test-for-12notes.html

      Когда откроете страницу в chrome или firefox, должен заиграть avicii-wake_me_up.mid .
      Не знаю будет ли работать в старых браузерах и в internet explorer. Скорее всего – нет.

      P.S. Для старых браузеров возможно есть какие-то flash-решения, но я не уверен.

  14. Александр пишет:

    Здравствуйте.
    Есть примеры работы с микрофоном. Нужно записывать голос с микрофона в файл.
    Заранее спасибо.

  15. Александр пишет:

    Здравствуйте

    Можно ли сохранить звуковой поток не в WAV а в FLAC. Вместо encodeWAV что то типа encodeFLAC. Заранее спасибо.

  16. Mitya пишет:

    Очень интересная статья! Однако хотелось бы чтобы на выходе все таки был пример с плейером и эквалайзером…

  17. Сергей пишет:

    Всем привет! Если можете помогите, у меня такая задача: речь идем о общение через веб камеру, надо зделать искажение голоса а звука. подскажите как это сделать, огромное спасибо.

    • Привет.
      Зависти от того, какой тип искажения требуется.

      Если это стилистические искажения, а-ля искажения испорченного старого телефона – будет достаточно свертки. Смотрите выше в разделе Convolution ( Свертка ).

      Если же нужно исказить голос до неузноваемости, то нужен vocooder. Это уже непростая задача.

      Вот демо webaudiodemos.appspot.com/Vocoder
      Вот код github.com/cwilso/Vocoder

      Можно найти и другие примеры вокодеров сделанных на базе web audio api в Гугле по запросу “Web audio vocoder”

  18. Anonymz пишет:

    API достаточно высокоуровневый, продуман до мелочей, самодостаточен,
    легок в освоении

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

    На сегодняшний день Chrome, Safari, Opera, FF25+, Chrome android,
    Safari iOS, поддерживают Web Audio API в полном объеме.

    Chrome не поддерживает событие onended. То есть его можно добавить, но работать оно не будет.
    https://code.google.com/p/chromium/issues/detail?id=280541

  19. Дмитрий пишет:

    Здравствуйте! Отличная статья! А можно ли с помощью Web Audio Api вытащить определенный фрагмент из песни, а затем сохранить в новый файл?

  20. хороший человек пишет:

    у меня немного тупой вопрос.
    а можно ли получить сразу массив getByteTimeDomainData,
    не подключая анализатор и вообще не проигрывая этот трек.
    у меня конечно есть дурацкая идея прогнать просто весь трек на большой скорости через ScriptProcessorNode, который сейчас по другому как-то называется, а потом уже анализировать тот массив, который мы получили, но у меня есть чувство что js не потянет такой длинный массив

  21. Евгений пишет:

    А у меня такой вопрос. Я получаю звук из и можно мне как-то узнать мета-данные песни, которая играет в .

    Или может есть способ извлечь их напрямую из ..

    Спасибо)

  22. bnku пишет:

    А существует какой-нибудь способ получать данные для визуализации из потока, типа http://pub4.di.fm:80/di_oldschoolelectronica ?

  23. Евгений пишет:

    Кто подскажет , как создать playlist и как туда drag and drom вставить файлы чтобы потом скормить это api, где почитать можно?

  24. Андрей пишет:

    Писал дипломный проект на тему обработки аудио средствами веб-браузера и вот что у меня получилось, строго не судите ) http://online-audio-redaktor.esy.es/

  25. supfoo пишет:

    “тип фильтра определяется строковым значением”

    Подскажите, а как быть с совместимостью со старой спецификацией?
    для старой – type:5, для последней – type:’peaking’.
    Как это кодом сделать?

  26. Apollo пишет:

    Огромное спасибо вам Дмитрий, за труды!
    Такой вопрос: а как организовать простейшую трансляцию аудио потока? То есть, чтобы люди зашедшие на сайт, слышали в реальном времени меня с микрофона? И более того, могли также вещать и мы могли разговаривать?
    Спасибо.

  27. Влад пишет:

    Спасибо, содержательная статья. Осталось непонятным: можно ли сохранять полученные аудиоданные?

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

*

* Copy This Password *

* Type Or Paste Password Here *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Узнавай о новых статьях первым!

Спасибо за лайк в FACEBOOK
Подписывайтесь на новости вконтакте
Последние статьи от html5.by