Кодируем музыку в браузере

от автора

Регулярно появляются статьи о создании кода Javascript который издаёт звуки в браузере. В них объясняется чем частота ноты До отличается от частоты ноты Ля, примеры кода исправно издают «бип-бип».

Сделаем что-то подобное, но с результатом больше похожим на музыку. И относительно наглядной нотацией в духе ABC, примерно вот так:

image

Запустить код и прослушать можно здесь:
https://jsbin.com/nosojaz/edit?html,output

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

Для воспроизведения используется технология WebAudioFont.
Скрипты иснструментов берутся непосредственно из проекта на GitHub

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

function bass(pitch, duration) { 	return { 		preset : _tone_Rubber_32Bass000079_461_460_45127, 		pitch : pitch, 		duration : duration 	}; } 

т.е. просто возврат объекта содержащего пресет (инструмент, если в терминах WebAudioFont), высоту и длительность ноты.

Для наглядности высоту будем задавать в заранее заданных константах (var C = 0; var Cs= 1; var D = 2; и т.д.), а длительность — в долях от полной ноты.
Естественно, для ударных высота с длительностью не имеют смысла и поэтому задаются одинаковыми значениями.

Для вывода звука перебираем массив в цикле и ставим каждый пресет в очередь воспроизведения:

function beats(notes) { 	for (var n = 0; n < notes.length; n++) { 		var beat = notes[n]; 		for (var i = 0; i < beat.length; i++) { 			if (beat[i]) { 				player.queueWaveTable(audioContext 				, audioContext.destination 				, beat[i].preset 				, startTime + n * beatLen 				, beat[i].pitch 				, beat[i].duration); 			} 		} 	} } 

Отправляем массив в плеер бесконечно с определённым интервалом:

setInterval(function () { 	if (audioContext.currentTime > startTime - 1 / 4 * N) { 		nextPiece(); 		startTime = startTime + pieceLen; 	} }, 20); 

После каждой отправки увеличиваем переменную startTime, в которой хранится время начала текущего куска.

Предупреждение: в современных браузерах при переводе фокуса в другое окно функции setTimeout и setInterval принудительно замедляются и мелодия будет «заедать».

Ещё пример для JSFiddle

Всё примерно то же самое, но нот побольше и инструменты воспроизводятся каждый через собственный GainNode для корректировки уровня громкости:

image

Запустить и прослушать пример можно тут: https://jsfiddle.net/sss1024/c53Lwete/2/

В JSFiddle, в отличии от JSBin, можно ограничиться чистым JS-кодом без HTML, а скрипты инструментов и плеера WebAudioFont указать в левой части редактора в разделе External Resources.

Предупреждение для начинающих гитаристов: если в музыкальном магазине проверяете гитару перед покупкой и машинально начинаете наигрывать «Дым над водой» — сразу взимается штраф 150 руб.

ссылка на оригинал статьи https://habrahabr.ru/post/314472/


Комментарии

Добавить комментарий

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