В мае 2018 года Google объявил о выпуске Magenta.js, JavaScript API для своих моделей машинного обучения музыки и искусства Magenta. Я узнал об этом через несколько месяцев и сразу захотел поиграть. Особый интерес для меня вызвали модели, использующие рекуррентные нейронные сети для создания музыки.

Начиная

Я решил сделать что-нибудь маленькое, приложение, которое берет музыку, над которой я работал некоторое время назад, и импровизирует мелодию на ее основе. Прекрасная возможность учиться публично! Вот как я это сделал.

Помимо Magenta, я также использовал Tonal, библиотеку теории музыки, для преобразования значений высоты звука в midi-значения и Tone.js, библиотеку WebAudio для создания музыки в браузере.

Все они доступны в npm, но чтобы приложение было относительно простым, я решил включить их в html-файл.

Обязательно вставьте файл JavaScript после остальных, чтобы у вас был доступ к переменным в библиотеках Magenta, Tone и Tonal.

Теперь обратимся к нашему файлу index.js. Magenta дает нам доступ к нескольким предварительно обученным моделям. Для этого приложения я использовал модель Improv RNN, которая, учитывая серию нот и последовательностей аккордов, выводит сгенерированную мелодию. Модели доступны через контрольно-пропускные пункты. Вы можете найти список контрольных точек, связанных с музыкой, здесь.

Magenta дает нам доступ к объекту с именем mm, к которому прикреплен конструктор MusicRNN. Мы можем создать экземпляр, дающий нам доступ к методам, связанным с нашей выбранной моделью, передав URL-адрес контрольной точки в конструктор.

Наша переменная implvRNN теперь имеет метод continueSequence, которому мы можем передать нашу мелодию, последовательности аккордов и пару других параметров.

Но сначала давайте отформатируем наш ввод. Я использую мелодию Изысканной леди, которую я взял с этого сайта нот.

Форматирование мелодии

Пурпурный цвет относится к вводу как к последовательности. Последовательность - это объект, содержащий следующие ключи:

ticksPerQuarter: Тик - это наименьшая единица времени, используемая в стандарте Midi. Подробнее см. Здесь. Я использовал значение, указанное в демонстрациях в репозитории Magenta на Github: 220.

totalTime: Длина последовательности в квантованных шагах, которую мы указываем в ключе примечаний.

timeSignatures: Он представлен массивом, содержащим объекты, представляющие каждый включенный размер. У каждого объекта есть числитель, знаменатель для соответствующих частей размера в нотной записи и ключ времени. Возможно, что временная клавиша относится к точке в последовательности, в которой начинается каждый временной размер, но я не нашел никакой документации, подтверждающей это. В демонстрации Github был только один размер и время было установлено равным 0, и я сделал то же самое.

tempos: это еще один массив объектов. У каждого объекта есть временная клавиша, которая, как я полагаю, относится ко времени начала каждого темпа, и клавиша qpm.

qpm: количество четвертей в минуту. Значение по умолчанию - 120.

Notes: Ноты в последовательности вводятся как массив объектов, представляющих высоту и продолжительность каждой ноты в последовательности. У каждого объекта есть ключи pitch, startTime и endTime. Pitch - это строковое значение, представляющее высоту ноты в MIDI числах. Здесь на помощь приходит Tonal. Я использовал его функцию midi, чтобы преобразовать высоту звука из научной записи высоты звука в числа MIDI. startTime и endTime - числа, представляющие начало и конец ноты в последовательности. Я построил значения startTime и endTime, предполагая, что четвертные ноты считаются одной единицей времени и что каждая нота начинается в то же время, что и заканчивается последняя. (Ноты, на которые я ссылался выше, находятся в сокращенном времени, но я использую размер 4/4 для последовательности.)

Прежде чем мы введем эту последовательность в модель, мы должны ее квантовать с помощью метода quantizeNoteSequence Magenta, передавая последовательность и количество шагов, которые каждая четвертная нота имеет в нашей последовательности. Из документации мне удалось выяснить, что этот метод округляет длительности нот, которые попадают между единицами измерения, используемыми в модели, в большую или меньшую сторону.

Привлечение ImprovRNN

Мы инициализируем implvRNN, вызывая его метод инициализации. Затем мы передаем нашу последовательность в ее метод continueSequence вместе с длиной желаемой последовательности, необязательным параметром (который я оставил нулевым), связанным с внутренней работой модели, и массивом последовательностей аккордов. Поскольку и initialize, и continueSequence возвращают обещания, я оборачиваю эту часть программы в функцию startProgram и использую async / await.

Воспроизведение сгенерированной мелодии

Здесь на помощь приходит Tone.js. Мы можем создать экземпляр синтезатора и использовать его метод triggerAttackRelease для воспроизведения каждой ноты в наших мелодиях. Здесь я написал две функции, которые преобразуют каждую ноту из ее номера MIDI и воспроизводят ее.

Перенос в браузер

Хорошо, давайте перенесем все это в браузер! Я добавил две кнопки для воспроизведения исходной и сгенерированной мелодии, вот так.

И я добавил к кнопкам прослушиватели событий для воспроизведения исходных и сгенерированных мелодий при нажатии.

Ресурсы

Вот и все! Вы используете Magenta.js. Ниже приведены некоторые ресурсы, которые я использовал, когда начинал изучать Magenta.js и готовил это руководство.

Автозаполнение нейронной мелодии: код приложения, которое также использует ImprovRNN. Приложение завершает мелодии, которые пользователь начинает играть на экранной клавиатуре. Если вы заинтересованы в создании музыки с помощью кода, я также рекомендую этот пост в блоге того же разработчика.

Melody Mixer: пошаговое руководство по приложению, которое использует модель Magenta MusicVAE для объединения и визуализации мелодий.

Magenta.js Demos: простые демонстрации моделей, доступных через Magenta.

Magenta.js Docs

Наконец, вы можете найти полный код этого приложения по адресу https://github.com/FunmiOjo/pep-magenta.

Конец

Спасибо за прочтение! Я сделал это руководство для таких же людей, как я, разработчиков, которые не являются экспертами в нейронных сетях, но заинтересованы в его изучении. Если у меня что-то не так или у вас есть вопросы по поводу того, что я здесь написал, прокомментируйте. Как бы то ни было, мне показалось, что взгляд Мадженты на Sophisticated Lady немного странный. Я оставлю вам видео, которое, на мой взгляд, является одним из лучших исполнений этой песни.