Как сделать идеальный звук микрофона


Как сделать идеальный звук микрофона
Как сделать идеальный звук микрофона
Как сделать идеальный звук микрофона

Лучшие новости сайта

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

Если вы лучше воспринимаете видео, можете посмотреть мое выступление по мотивам этой статьи на Web Standards Days в на Yandex Events (Декабрь 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). Проблема небольшая и Вы можете использовать обертку , которую при желании можно поддержать своими пулл реквестами.
  2. Поддержка браузерами. На сегодняшний день Chrome, Safari, Opera, FF25+, Chrome android, Safari iOS, поддерживают Web Audio API в полном объеме. IE и некоторые мобильные браузеры думают о поддержке в “ближайшем” будущем. Подробнее можно посмотреть тут .
  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 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);

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

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

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

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

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

JS

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

Давайте для закрепления основных принципов создадим простую схему с бесконечным зацикливанием сигнала, используя 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);

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

Convolution ( Свертка )

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

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

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

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

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

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

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

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

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

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

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

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; // Усиление (не нужно этому типу фильтра)

Анализатор

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

  • Отобразить форму или спектр сигнала на 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);

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

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.

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

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

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


Источник: http://html5.by/blog/audio/


Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Как сделать идеальный звук микрофона

Похожие новости: