https://habrahabr.ru/post/353036/- Работа со звуком
- JavaScript
Будем делать проигрыватель файлов .mid на Javascript и Web Audio API.
Конечный результат может выглядеть
вот так.
Для чего
Делать свой плеер имеет смысл для интерактивных музыкальных приложений т.к. будет возможен полный контроль за воспроизведением (смена инструментов, редактирование нот в рилтайме, точное позиционирование и т.п.).
Для обычной фоновой музыки больше подходит обычный mp3.
Составные части
Файл с нотами надо как-то прочитать, загрузить используемые инструменты, синтезировать звук и отправить его в аудиовыход.
Всё просто.
Чтение файлов
Простой поиск по GitHub даёт нам кучу проектов для чтения MIDI-событий из файлов.
Выберем
https://github.com/nfroidure/MIDIFile. Он выдаёт массив событий от смены программы, noteOn/noteOff и пр.
Для удобства придётся его немного модифицировать чтоб сразу получать ноты со временем и длительностью:
Загрузка музыкальных инструментов
Для звука используется библиотека
WebAudioFont, загрузка инструментов в ней делается буквально парой строчек, примерно так:
for (var i = 0; i < song.tracks.length; i++) {
var nn = findFirstIns(player, song.tracks[i].program);
var info = player.loader.instrumentInfo(nn);
player.loader.startLoad(audioContext, info.url, info.variable);
}
Синтез звука
Можно отправить в очередь воспроизведения все ноты сразу. Но их тысячи даже в небольших музыкальных фрагментах и такой размер «повесит» аудио подсистему. Выход — отправлять небольшими кусками через обычную функцию setInterval:
setInterval(function () {
if (audioContext.currentTime > nextStepTime - stepDuration) {
sendNotes(song, songStart, currentSongTime, currentSongTime + stepDuration, audioContext, input, player);
currentSongTime = currentSongTime + stepDuration;
nextStepTime = nextStepTime + stepDuration;
}
}, 22);
О параметрах функции отправки звуков в очередь воспроизведения можно прочитать на странице проекта
WebAudioFont.
Интерактив
В любой момент можно определить в каком месте файла сейчас находится воспроизведения. В демо-плеере это выглядит так:
function showPosition(song, currentSongTime) {
var o = document.getElementById('position');
o.value = 100 * currentSongTime / song.duration;
document.getElementById('tmr').innerHTML = '' + Math.round(100 * currentSongTime / song.duration) + '%';
}
Смена инструмента выглядит примерно так:
var nn=selectIns.value;
var info = player.loader.instrumentInfo(nn);
player.loader.startLoad(audioContext, info.url, info.variable);
player.loader.waitLoad(function () {
console.log('loaded');
song.tracks[i].info = info;
});
— буквально несколько строчек и всё подгружается само.
Исходный код
Пример плеера доступен
по ссылке
Весь код занимает чуть менее 300 строк.