Учебник по VexFlow.js
В этой статье я хочу рассказать про JavaScript библиотеку VexFlow и показать несколько примеров того что она умеет. Библиотека VexFlow предназначена для создания скриптов, при помощи которых будет происходить запись музыкального текста, с целью дальнейшей отрисовки этого текста в браузере. Она может быть полезной тем, кто собирается разрабатывать такие сервисы как: jellynote.com, musicnotes.com, музыкальный редактор (аналог Сибелиуса) или даже систему распознавания отсканированных музыкальных нот (что-то типа SharpEye)
Чтобы полноценно использовать данную библиотеку требуется некоторый опыт программирования на JavaScript и знание музыкальной теории, на уровне того как записывается музыка для различных музыкальных инструментов: что такое нотоносец, скрипичный и басовый ключи, как записываются ноты, длительности и т.д. Кстати, следует сказать, что VexFlow поддерживает работу как с Canvas, так и с SVG, благодаря чему у нас появляются безграничные оформительские возможности.
Подключаем библиотеку:
С помощью NPM
$ npm install vexflow
Через CDN
- Debug version: https://unpkg.com/vexflow/releases/vexflow-debug.js
- Minified version: https://unpkg.com/vexflow/releases/vexflow-min.js
Либо по старинке – скачиваем архив (https://github.com/0xfe/vexflow/archive/master.zip) в папку с проектом, ну а дальше сами знаете.
Нотный стан:
Запись музыкального произведения начинается со строки состоящей из пяти параллельных линий, которая называется нотным станом или нотоносцем. В самом начале этой строки нужно указать ключ и обозначить размер. Этим мы сейчас и займемся.
В HTML-файле нам потребуется всего лишь один элемент:
Имя идентификатора указываем на свой вкус.
Начинаем скриптовать.
Работа с библиотекой начинается с выбора базовых параметров. Нам нужно указать элемент, внутри которого будет происходить запись нотного текста, выбрать формат рендеринга (я предпочитаю SVG) и установить необходимые размеры для нашего «полотна»
По сути, мы создали цифровую версию нотной тетради, внутри которой можно нарисовать любой музыкальный символ. Самое время заняться творчеством.
Для начала нарисуем нотный стан, разместим на нём скрипичный ключ и укажем музыкальный размер в четыре четверти:
Вот как это выглядит: [запустить]
А теперь немного разъяснений:
При создании «нотной тетради» я решил использовать формат SVG:
var renderer = new VF.Renderer(elem, VF.Renderer.Backends.SVG);
Разумеется, у вас есть выбор, и вместо VF.Renderer.Backends.SVG
вы можете указать VF.Renderer.Backends.CANVAS
После создания «нотной тетради» весь дальнейший процесс будет сводиться к созданию VexFlow-элементов, размещению их в контексте нашей тетради и отрисовки с помощью метода .draw().
Каждый VexFlow-элемент (VF) представляет собой тот или иной музыкальный символ. Например, VF.Stave
– нотная строка, VF.StaveNote
– какая-то нота, VF.Beam
– горизонтальное ребро для группировки нот и т.д. Разумеется, что у каждого VF-элемента есть соответствующие параметры.
Создавая нотную строку, я указал начало координат относительно нашего полотна:
var fiveLineStave = new VF.Stave(10, 25, 400);
Таким образом я зарезервировал немного места сверху, для того чтобы в дальнейшем оставить там какую-нибудь заметку, например, forte. Если вы ничего такого не предполагаете, то укажите координаты: 0, 0.
Ещё может возникнуть вопрос, почему мы делаем не так – fiveLineStave.draw()
, а так – fiveLineStave.setContext(context).draw();
Отвечаю – учитесь думать головой! Шутка! Дело в том, что у fiveLineStave
нет метода draw()
. Зато у нашего контекста (нашей «нотной тетради») есть такой метод! Этот и множество других замечательных методов ;) Кстати, контекст вообще очень гибко настраивается. Вы можете управлять такими вещами как цвет, шрифт, масштабирование: context.setStrokeStyle('red');
context.setLineWidth(50);
и т.д.
Кстати, а попробуйте переделать наш пример таким образом, чтобы вместо скрипичного ключа стоял басовый, а музыкальный размер был в шесть восьмых. Получилось? Не сомневаюсь! ;-)
Ноты, длительности, простая мелодия:
Для начала рассмотрим общие принципы создания партитур в данной библиотеке, ну а сразу после примера пробежим по нюансам.
Размещая в определенной последовательности ноты, мы создаем мелодию, так называемый голос. Делается это с помощью конструктора new VF.Voice()
Если мелодию нужно обогатить, мы создаем ещё один голос, и так далее. В момент, когда у нас появляется второй голос, наша партитура представляет собой полифоническую музыку, т.е. многоголосье. Голоса можно группировать в группы – VoiceGroup
.
После того как ввод закончен, мы вызываем метод, который выполнит отрисовку, так называемый рендеринг. Но, перед этим, к введенной партитуре рекомендуется применить методы класса Formatter()
, для того чтобы все ноты выровнялись равномерно, и получилась красивая партитурная композиция – типографский партитурный ритм. Автор библиотеки выявил правила красивого партитурного оформления и упаковал их в соответствующий класс, за что ему отдельные респект и уважуха.
Давайте посмотрим, как это выглядит: [запустить]
Итак, с помощью конструктора StaveNote
мы можем создавать ноту, трезвучие или аккорд. Объединив ноты в массив и применив соответствующий метод (см. в пример) мы получаем голос.
Пара слов о параметрах:
Поле clef
не является обязательным параметром. Т.е. clef: "treble"
указывать необязательно, если вам, конечно, не потребовалось в каком-нибудь месте партитуры сменить ключ. Более того, скрипичный ключ в данной библиотеке устанавливается в качестве дефолтного значения. Как-то так:
Flow.keyProperties = (key, clef, params) => { if (clef === undefined) { clef = 'treble'; }
Рассмотрим оставшиеся параметры:
keys: ["c/4"]
– так в нашей библиотеке обозначается «до» первой октавы. Если вам это кажется удивительным, то уверяю вас – ничего удивительного в этом нет. Это вполне обычная запись так называемой «научной нотацией», предложенной в 1939 году Американским акустическим обществом. В этой нотации номер октавы записывается сразу после обозначения ступени, при этом октавная система индексируется (нумеруются) с субконтроктавы, которой присваивается номер 0. Соответственно, контроктаве присваивается номер 1, большой октаве номер 2 и т.д.
В поле duration
обозначается длительность ноты. "q"
– обозначает четвертную ноту (сокращение от слова «quarter-note») Также можно использовать цифры.
Двигаем дальше.
Добавим второй голос в нашу мелодию: [запустить]
Второй голос представляет собой целую ноту – duration: "w"
, сокращение от whole note.
И конечно, из-за того, что у нас образовался массив голосов (var voices = […]), их отрисовка происходит в цикле.
Модификаторы:
Модификаторами в изучаемой нами библиотеке называются такие элементы музыкальной нотации, которые относятся к знакам альтерации, артикуляции, мелизмам. Т.е. диезы, бемоли, знаки стаккато, вибрато и т.д. Модификаторы наследуются от базового класса VF.Modifier
, например, VF.Accidental
– знаки альтерации, VF.Vibrato
– для вибрато и других мелизмов, VF.Annotation
– для аннотаций и т. д.
Посмотрим, как работать с модификаторами на примере двух септаккордов:
Собственно, вот что у нас получилось: [запустить]
Полагаю, что данный пример настолько нагляден, что в дополнительных комментариях не нуждается.
И ещё один фрагмент, для разнообразия:
В результате мы имеем вот что: [запустить]
Попробуйте самостоятельно заменить дубль-диез дубль-бемолем, и сделать двойное увеличение продолжительности для ноты с точкой (для любой) В общем, попробуйте оба метода: addDot(<параметр>)
и addDotToAll()
. Я в вас верю ;)
Вместо заключения:
Вот и подошла к концу первая часть туториала по VexFlow.js. Это была ознакомительная часть, что называется, небольшая демонстрация возможностей. Впереди ожидается ещё две части, в которых я планирую показать, как научиться создавать профессиональные музыкальные нотации для различных инструментов: от фортепиано, где требуется объединение двух нотоносцев со скрипичным и басовым ключом, до гитарных табулатур. Также следует ожидать исчерпывающие сведения обо всех параметрах и методах доступных в данной библиотеке. Что-то типа путеводителя по API.
Спасибо за внимание.