НОВОСТИ [Перевод] Использование микрофона для создания произведений искусства, реагирующих на звук, на Javascript

Alvaros
Онлайн
Регистрация
14.05.16
Сообщения
21.452
Реакции
101
Репутация
204
Несколько приёмов для создания произведений процедурального (генеративного) искусства.

ib7piicq9ttydfwoc0t8-jy_-mc.gif


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



Куча туториалов могут объяснить это более подробно, но я что-то не видел советов, как перейти с Hello world на следующий уровень. Об этом я и хочу вам рассказать.

Не откладывая в долгий ящик предупрежу, что это не работает в Safari. И никогда не работало. Есть баги, благодаря которым может сработать… Но давайте реально, меня уже достал поиск обходных путей в этих не ахти каких браузерах. Как и вас, думаю.​


И ещё заметьте: с прошлого года нужно https соединение, чтобы использовать микрофон. Если вы используете что-то вроде от (а его использовать стоит, поверьте мне), микрофон настроится автоматически.

Итак, сначала очень скучное дело, настройка микрофона… Только не пугайтесь…


function Microphone (_fft) { var FFT_SIZE = _fft || 1024; this.spectrum = [];
this.volume = this.vol = 0;
this.peak_volume = 0; var self = this;
var audioContext = new AudioContext();
var SAMPLE_RATE = audioContext.sampleRate;

// это просто проверка браузера на то,
// поддерживает ли он AudioContext и getUserMedia
window.AudioContext = window.AudioContext || window.webkitAudioContext;
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia; //теперь просто ждите запуска микрофона
window.addEventListener('load', init, false); function init () {
try {
startMic(new AudioContext());
}
catch (e) {
console.error(e);
alert('Web Audio API is not supported in this browser');
}
} function startMic (context) { navigator.getUserMedia({ audio: true }, processSound, error); function processSound (stream) { //анализатор определяет частоту, колебательный сигнал и т. д.
var analyser = context.createAnalyser();
analyser.smoothingTimeConstant = 0.2;
analyser.fftSize = FFT_SIZE; var node = context.createScriptProcessor(FFT_SIZE*2, 1, 1); node.onaudioprocess = function () { // число битов возвращает массив, а это половина FFT_SIZE
self.spectrum = new Uint8Array(analyser.frequencyBinCount); // getByteFrequencyData выдаёт амплитуду для каждой ячейки
analyser.getByteFrequencyData(self.spectrum);
// getByteTimeDomainData определяет громкость за определённое время
// analyser.getByteTimeDomainData(self.spectrum);

self.vol = self.getRMS(self.spectrum);
// get peak – костыль, если громкость низкая
if (self.vol > self.peak_volume) self.peak_volume = self.vol;
self.volume = self.vol; }; var input = context.createMediaStreamSource(stream);
input.connect(analyser);
analyser.connect(node);
node.connect(context.destination); } function error () {
console.log(arguments);
}}//////// SOUND UTILITIES ..... потом вставим сюда ещё чего-нибудь....
return this;};
var Mic = new Microphone();



Это даст нам массив амплитуд на наших частотах (использую 512 по умолчанию), представленные как Mic.spectrum. Окей, давайте начнём играть…

Получение полной громкости.



kvmouamykd-vchywrdjxz25mh7w.gif

Пошумим!

Я нечасто это использую, но это удобно и можно использовать в куче других утилит. Чтобы получить полную громкость или уровни, мы используем функцию getRMS(). лучше указывает громкость входящего звука, он суммирует все громкости всех частот спектра. Итак, функция, которую мы добавим в Mic() выглядит так:


// A more accurate way to get overall volume
this.getRMS = function (spectrum) {var rms = 0;
for (var i = 0; i < vols.length; i++) {
rms += spectrum * spectrum;
}
rms /= spectrum.length;
rms = Math.sqrt(rms);
return rms;
}


И мы можем сделать простенькую анимацию, как ту, что выше, так:

var ctx = createCanvas("canvas1");
ctx.background(235);function draw(){var s = Mic.getRMS();
ctx.fillStyle = rgb(s*2);
ctx.HfillEllipse(w/2, h/2, s*5, s*5);
}


Получение спектра звука



looabltzfvxhuqk5vtn6_uwgovi.gif


Наш Mic() выдаёт Mic.spectrum, массив амплитуд или громкостей по всему спектру (или FFT_SIZE, у меня 512 по умолчанию). Мы можем использовать их как есть, вот так:


var ctx = createCanvas("canvas1");// сделайте сетку 200 по ширине
// Как создавать сетки я показал тут [ ]
var grid = new Grid(200, 1);function draw(){ctx.background(235);for (var i = 0; i < grid.length; i++) {
var s = Mic.spectrum;
ctx.fillStyle = hsl(map(i, 0, grid.length, 0, 360), 80, 50);
ctx.fillRect(grid.x, h - s, grid.spacing_x-1, s);
}}


Однако, я считаю, что было бы удобнее и эффективнее построить функцию отображения звука.

Отображение звука.



-iqm7y6v4smy29n9ioeq_omecca.gif


Если бы у нас было, к примеру, только 20 объектов, но наш спектр выдавал 512 частот (что является значением по умолчанию для объекта Mic()), было бы разумно распределить амплитуды, чтобы получить более чёткое отображение того, что происходит с нашим звуком. Поэтому давайте переотобразим наш спектр.

Чтоб начинающим было легче, я буду достаточно часто использовать простую map() функцию, которая хранится в моем главном файле , и выглядит вот так:

function map(value, min1, max1, min2, max2) {
var returnvalue = ((value-min1) / (max1 - min1) * (max2-min2)) + min2;
return returnvalue;
};


Основываясь на этом, мы можем сделать mapSound() функцию, чтобы равномерно распределять значения. Это, скорее всего, самый ценный инструмент анализа звука. Я использую его почти каждый день. Супер удобно и просто.


this.mapSound = function(_me, _total, _min, _max){if (self.spectrum.length > 0) {
// обозначьте значения по умолчанию, если другие не даны
var min = _min || 0;
var max = _max || 100;
//actual new freq
var new_freq = Math.floor(_me * self.spectrum.length /_total);
// обозначьте громкость до хороших значений
return map(self.spectrum[new_freq], 0, self.peak_volume, min, max);
} else {
return 0;
}

}


Мы затем можем легко создать спектр вот так:

b4dshcztzpkqbkc6iygzmhpwnfc.gif

Тест, тест, 1, 2, 3.

Визуализация спектра сделана из сетки, звук обозначается по длине сетки. Я также обозначил выданные значения (_min и _max) как 5 и высоту/4, чтобы лучше выглядело:


var ctx = createCanvas("canvas1");// make a grid 200 wide
var grid = new Grid(200, 1);function draw(){ctx.clearRect(0,0,w,h);for (var i = 0; i < grid.length; i++) {
// Mic.mapSound(_me, _total, _min, _max)
var s = Mic.mapSound(i, grid.length, 5, h/4);
ctx.fillStyle = rgb(0);
ctx.fillRect(grid.x, grid.y - s/2, grid.spacing_x-0.5, s);
}}


На самом деле, mapSound() сможет позаботиться о всех нуждах, связанных с анализом звука. Чаще всего, именно простота лучше всего работает для визуализация звука. Фишка творческого кодинга – просто выстраивать простые биты друг на друге, чтобы получились сложно выглядящие творения. Так, например, мы можем использовать некоторые приёмы Math.cos и Math.sin, чтобы сделать красивый круглый спектр:

bpruufjygqzr8t33_9lgglm3veu.gif

Мам, смотри, круглый спектр

Вот код-пример: просто создать кучи частиц и распределить длину каждой линии частицы к соответствующей громкости:


var ctx = createCanvas("canvas1");var num_items = 200;
var radius = 100;
ctx.lineWidth = 2;
var particles = [];// работаем над углами
for (var i = 0; i < num_items; i++) {
var angle = radians(distributeAngles(i, num_items));
particles = {
x: w/2 + Math.cos(angle) * radius,
y: h/2 + Math.sin(angle) * radius,
angle: angle
}
}
function draw(){ ctx.background(0); for (var i = 0; i < num_items; i++) { var p = particles;
var s = Mic.mapSound(i, num_items, 5, 100);
// map to greyscale
//ctx.strokeStyle = rgb(map(i, 0, num_items, 0, 255));

x2 = w/2 + Math.cos(p.angle) * (s + radius);
y2 = h/2 + Math.sin(p.angle) * (s + radius);
ctx.line(p.x, p.y, x2, y2); }}



И этот код может быть адаптирован в нечто типа этого — это одно из моих первых визуально-звуковых творений на Javascript.

tmq0p-kq-3nbo2nw4szihktrciy.gif


Вот и всё. Конец. Как-нибудь мы можем добавить кучу полезных утилит, чтобы добавить басы, средние и высокие частоты, тон и ещё много чего, сделав визуализацию звука ещё проще…

Как всегда, полный код можно найти у меня на .

Счастливого кодинга!
 
Сверху Снизу