Web Audio API является мощным API браузера для создания, манипулирования и анализа звука. Я не музыкант, поэтому я оставлю создание и манипулирую экспертам. Вместо этого в этом посте мы рассмотрим анализ аудио. Чтобы сделать вещи очень интересными, мы увидим, как визуализировать аудио в компоненте React с Анкет
Когда мы закончим, у нас будет приложение React, которое может прослушать микрофон на вашем компьютере и показать форму волны для визуализации данных.
Начиная
Нам нужно Node.js Чтобы запустить приложение, поэтому убедитесь, что вы установили. Я Запустил приложение Для нас, поэтому следуйте этим инструкциям, чтобы запустить:
Клонировать или скачать репо с GitHub
Изменить в каталог и установить зависимости с помощью NPM
Начните приложение
Посетите Localhost: 3000 Чтобы увидеть запуск приложения
Мы готовы начать создавать приложение.
Вход микрофона
В интерфейсе есть кнопка, готовая схватить микрофон, но она еще не подключена к чему -либо. Мы собираемся создать функцию, которую кнопка выполняет при нажатии. Наша функция потребует разрешения на доступ к микрофону пользователя с помощью getusermedia API Анкет Затем, как только разрешение будет предоставлено, оно добавит звук в состояние заявки.
Во -первых, Open src/app.js и настроить объект состояния в Приложение конструктор компонента.
class App extends Component {
constructor(props) {
super(props);
this.state = {
audio: null
};
}
Нам нужен метод, который будет использовать getusermedia Чтобы запросить доступ к микрофону и установить аудио -поток в состоянии, если он успешен. Добавьте следующее в компонент:
async getMicrophone() {
const audio = await navigator.mediaDevices.getUserMedia({
audio: true,
video: false
});
this.setState({ audio });
}
Добавьте метод, чтобы остановить захват звука. Это проходит через каждый из MediaTrack S связан с Mediastream это getusermedia Возвращает и останавливает их, наконец, удаляя поток из штата.
stopMicrophone() {
this.state.audio.getTracks().forEach(track => track.stop());
this.setState({ audio: null });
}
Добавьте метод для включения и выключения микрофона.
toggleMicrophone() {
if (this.state.audio) {
this.stopMicrophone();
} else {
this.getMicrophone();
}
}
Мы собираемся использовать этот метод переключения с кнопкой в интерфейсе. Для этого нам нужно связать его контекст с компонентом. Добавьте следующее в конструктор:
constructor(props) {
super(props);
this.state = {
audio: null
};
this.toggleMicrophone = this.toggleMicrophone.bind(this);
}
Приложение уже отображает кнопку, но нам нужно подключить ее к этим функциям. Обновите рендер функционируйте так, чтобы кнопка переключалась между получением и остановкой входа микрофона.
render() {
return (
);
}
Вернитесь в браузер и нажмите кнопку «Получить вход микрофона». Браузер попросит ваше разрешение использовать микрофон, и когда вы предоставите его … ну, кнопка изменится. Не супер захватывающе, но теперь, когда у нас есть аудио -поток, мы на пути к анализу.
Аудио -анализ
Создайте новый компонент в SRC каталог для анализа; Назовите это Audioanalyser.js Анкет Мы собираемся передать аудио -поток этому компоненту через реквизит . Этот компонент будет отвечать за использование API веб -аудио для анализа аудио -потока и сохранить этот анализ в штате.
Мы начнем с пустого компонента:
import React, { Component } from 'react';
class AudioAnalyser extends Component {
}
export default AudioAnalyser;
Когда компонент устанавливаюсь, мы собираемся настроить объекты API Web Audio. Сначала мы создаем новый AudioContext (Safari по -прежнему поддерживает только префикс -версию Webkit, к сожалению). Тогда мы создадим AnalySernode Это сделает тяжелую работу для нас.
Из AnalySernode Нам нужно знать Частота -бинкунтинг что, согласно документации, обычно приравнивается к количеству значений данных, которые будут доступны для воспроизведения для визуализации. Мы создадим массив 8-битных целых чисел без знака, A Uint8array , длина Частота -конфинкаунт . Это DATARARRY будет использоваться для хранения данных о форме волны, которые AnalySernode будет создавать.
Мы пропустили потоку медиа из микрофона в компонент в качестве опоры, и нам нужно превратить его в источник для веб -аудио API. Для этого позвоните CreateMediAstreamSource на AudioContext объект, проходя в потоке. Как только у нас есть источник, мы сможем подключить анализатор.
componentDidMount() {
this.audioContext = new (window.AudioContext ||
window.webkitAudioContext)();
this.analyser = this.audioContext.createAnalyser();
this.dataArray = new Uint8Array(this.analyser.frequencyBinCount);
this.source = this.audioContext.createMediaStreamSource(this.props.audio);
this.source.connect(this.analyser);
}
Это еще не проводит для нас никакого анализа. Для этого нам нужно обратиться к AnalySernode S Getbytetimedomaindata Метод каждый раз, когда мы хотим обновить визуализацию. Поскольку мы будем анимировать эту визуализацию, мы призомем браузер requestAnimationFrame API, чтобы вытащить последние аудиоданные из AnalySernode Каждый раз, когда мы хотим обновить визуализацию.
Для этого мы создадим метод, который будет называться каждый раз requestAnimationFrame пробеги. Функция скопирует текущую форму волны как массив целых чисел, из AnalySernode в DATARARRY Анкет Затем он обновит Audiodata Свойство в состоянии компонента с DATARARRY Анкет Наконец, это позвонит requestAnimationFrame снова, чтобы запросить следующее обновление.
tick() {
this.analyser.getByteTimeDomainData(this.dataArray);
this.setState({ audioData: this.dataArray });
this.rafId = requestAnimationFrame(this.tick);
}
Мы запускаем петлю анимации с конца ComponentDidMount Метод после подключения источника к анализатору.
componentDidMount() {
// rest of the function
this.source.connect(this.analyser);
this.rafId = requestAnimationFrame(this.tick);
}
Мы инициализируем состояние компонента в конструкторе с пустым Uint8array а также связывайте область схватки поставить галочку функционируйте с компонентом.
constructor(props) {
super(props);
this.state = { audioData: new Uint8Array(0) };
this.tick = this.tick.bind(this);
}
Еще одна вещь, которую мы хотим сделать, это выпустить все ресурсы, если мы удалим компонент. Создать ComponentWillunMount Метод, который отменяет анимационную рамку и отключает аудиоздеции.
componentWillUnmount() {
cancelAnimationFrame(this.rafId);
this.analyser.disconnect();
this.source.disconnect();
}
Мы еще ничего не сделали из этого компонента. Мы можем взглянуть на данные, которые мы производим. Добавить рендер Метод компонента со следующим:
render() {
return ;
}
Open src/app.js и импортировать Audioanalyser составная часть:
import React, { Component } from 'react';
import AudioAnalyser from './AudioAnalyser';
В рендер Функция включает составная часть Только если состояние содержит аудио -поток.
render() {
return (
{this.state.audio ? : ''}
);
}
Загрузите страницу и нажмите кнопку, чтобы дать доступ к вашему микрофону, вы увидите массив значений, генерируемых в Анкет Посмотреть на кучу обновлений номеров не весело, поэтому давайте добавим новый компонент для визуализации этих данных.
Аудио визуализация
Создайте компонент с именем Audiovisualiser.js и заполните парикмромовую, в которой мы нуждаемся.
import React, { Component } from 'react';
class AudioVisualiser extends Component {
}
export default AudioVisualiser;
Давайте начнем этот класс с рендер метод Мы хотим нарисовать на Итак, мы отодвинем один на страницу.
render() {
return ;
}
Нам нужно получить ссылку на Элемент, чтобы мы могли нарисовать на нем позже. В конструкторе создать ссылку, используя React.createref () и добавить ref атрибут к элемент.
constructor(props) {
super(props);
this.canvas = React.createRef();
}
render() {
return ;
}
Давайте создадим функцию, которая нарисует форму волны на холсте. Это похоже на Этот учебник MDN Первоначально Соледад Пенадес , но адаптировано к работе в пределах отреагированного компонента.
Идея состоит в том, чтобы взять Audiodata Мы создали в предыдущем компоненте и нарисуем линию слева направо между каждой точкой данных в массиве.
Начните с новой функции под названием нарисовать Анкет Эта функция будет вызывать каждый раз, когда мы получаем новые данные из анализатора. Начнем с настройки переменных, которые хотим использовать:
-
Audiodataизреквизити его длина - холст из
рефери - высота и ширина холста
- Контекст 2D рисунка из холста
xкоторый будет использоваться для отслеживания через холстSliceWidthВ сумма, которую мы будем двигаться вправо каждый раз, когда рисоваем
draw() {
const { audioData } = this.props;
const canvas = this.canvas.current;
const height = canvas.height;
const width = canvas.width;
const context = canvas.getContext('2d');
let x = 0;
const sliceWidth = (width * 1.0) / audioData.length;
Теперь мы начинаем работать над созданием картинки, которую мы собираемся нарисовать на холсте. Впервые установив наш стиль рисования, в этом случае установите ширину линии 2 и стиль инсульта для черного цвета. Затем мы очищаем предыдущие рисунки с холста.
context.lineWidth = 2; context.strokeStyle = '#000000';
context.clearRect(0, 0, width, height);
Затем начните путь, который мы собираемся нарисовать и переместить положение рисунка на полпути вниз по левой стороне холста.
context.beginPath();
context.moveTo(0, height / 2);
Перевернуть данные в Audiodata . Каждая точка данных составляет от 0 до 255. Чтобы нормализовать это на наш холст, мы делим на 255, а затем умножаем на высоту холста. Затем мы нарисуем линию из предыдущего пункта до этого и приращение x по SliceWidth Анкет
for (const item of audioData) {
const y = (item / 255.0) * height;
context.lineTo(x, y);
x += sliceWidth;
}
Наконец, мы нарисуем линию до точки на полпути вниз по правой стороне холста и направляем холст, чтобы окрасить весь путь.
context.lineTo(x, height / 2);
context.stroke();
}
нарисовать Функция должна работать каждый раз Audiodata обновляется. Добавьте следующую функцию в компонент:
componentDidUpdate() {
this.draw();
}
Давайте свяжем все компоненты вместе и увидим визуализатор в действии.
Объединение компонентов
Open src/audioanalyser.js и импортировать Audiovisualiser составная часть.
import React, { Component } from 'react';
import AudioVisualiser from './AudioVisualiser';
Определите рендер Метод, который делает и проходит Audiodata от государства как имущества.
render() {
return ;
}
И мы закончили. Начните приложение с NPM запускается , если он больше не работает, и откройте браузер для Localhost: 3000 опять таки. Нажмите кнопку, сделайте немного шума и посмотрите, как визуализатор оживает.
Следующие шаги
В этом посте мы видели, как получить доступ к микрофону, настроить веб -API аудио для анализа аудио и визуализировать его на холсте, разделяя задание между двумя компонентами React.
Мы можем использовать это в качестве основы для создания более интересных и творческих визуализаций. В качестве альтернативы, если вы Создание видеочата в React Вы можете добавить эту визуализацию, чтобы показать, кто издает шум на вызове, или даже проверить, работает ли ваш собственный микрофон.
Вы можете проверить Весь код этого приложения на GitHub Анкет Я рекомендую прочитать через Статья MDN о визуализации с веб -аудио API Чтобы узнать, чего еще вы могли бы достичь с этим. Я хотел бы посмотреть, какие другие визуализации вы можете создать, если вы придумали что -то, дайте мне знать в комментариях или в Twitter в @Philnash Анкет
Оригинал: “https://dev.to/twilio/audio-visualisation-with-the-web-audio-api-and-react-k20”