Будем делать проигрыватель файлов .mid на Javascript и Web Audio API.
Конечный результат может выглядеть вот так.
Делать свой плеер имеет смысл для интерактивных музыкальных приложений т.к. будет возможен полный контроль за воспроизведением (смена инструментов, редактирование нот в рилтайме, точное позиционирование и т.п.).
Для обычной фоновой музыки больше подходит обычный mp3.
Файл с нотами надо как-то прочитать, загрузить используемые инструменты, синтезировать звук и отправить его в аудиовыход.
Всё просто.
Простой поиск по GitHub даёт нам кучу проектов для чтения MIDI-событий из файлов.
Выберем https://github.com/nfroidure/MIDIFile. Он выдаёт массив событий от смены программы, noteOn/noteOff и пр.
Для удобства придётся его немного модифицировать чтоб сразу получать ноты со временем и длительностью:
Для звука используется библиотека WebAudioFont, загрузка инструментов в ней делается буквально парой строчек, примерно так:
Можно отправить в очередь воспроизведения все ноты сразу. Но их тысячи даже в небольших музыкальных фрагментах и такой размер «повесит» аудио подсистему. Выход — отправлять небольшими кусками через обычную функцию setInterval:
О параметрах функции отправки звуков в очередь воспроизведения можно прочитать на странице проекта WebAudioFont.
В любой момент можно определить в каком месте файла сейчас находится воспроизведения. В демо-плеере это выглядит так:
Смена инструмента выглядит примерно так:
— буквально несколько строчек и всё подгружается само.
Пример плеера доступен по ссылке
Весь код занимает чуть менее 300 строк.
Конечный результат может выглядеть вот так.
Для чего
Делать свой плеер имеет смысл для интерактивных музыкальных приложений т.к. будет возможен полный контроль за воспроизведением (смена инструментов, редактирование нот в рилтайме, точное позиционирование и т.п.).
Для обычной фоновой музыки больше подходит обычный 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 строк.
inoyakaigor
Я думал тут будет свой велосипед с бoльшим количеством кровавых подробностей: чтение и разбор MIDI-файла руками, синтез звука через Web Audio API и т.п. и т.д.
musicriffstudio Автор
в 21 веке живём. 300 строк и полноценный звук на выходе.
Статьи про разбор бинарного формата и выдачу бип-бип в спикер, возможно, кому-то и интересны. Но как-то малорезультативны.
domix32
Это как раз самый смак.