使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

本文概述

  • 要求
  • 入门
  • 使用EasyScore
  • 沙盒
你是否有演奏乐器的朋友, 并且想玩得开心?音乐由多种符号组成, 其中最基本的是谱号, 谱号和音符。从理论上讲, 绘制这些符号很简单, 但是要理解它们并产生旋律则非常复杂。如果你是网络开发人员, 并且需要处理一些需要在浏览器上呈现音乐符号的音乐项目, 那么今天就是你的幸运日, 因为你无需编写自己的脚本即可实现这一目标。要使用Javascript绘制乐谱, 建议你使用很棒的VexFlow库。
VexFlow是一个基于Web的开源音乐符号渲染API。它完全用JavaScript编写, 并且可以在浏览器中直接运行。 VexFlow支持HTML5 Canvas和SVG, 并且可以在所有现代浏览器上运行。 VexFlow支持标准音乐, 吉他谱和打击乐符号。虽然支持大多数西方音乐符号是一个目标, 但VexFlow还支持一些替代元素, 例如微音符符号。
在本教程中, 我们将介绍你可以使用Javascript中的VexFlow库执行的所有基本任务。
要求 如前所述, 我们将使用VexFlow 2来实现使用Javascript创建超赞音乐表的目标。你可以使用NPM在Node命令提示符下执行以下命令来获取该库:
npm install vexflow

或者, 你显然可以在VexFlow的Github中的官方存储库中获得.js文件分发(调试或压缩后的发行版, 这些版本会在unpkg中自动发布和更新), 并通过脚本标签将其包含在文档中:
< script src="http://www.srcmini.com/path-to-scripts/vexflow.min.js"> < /script>

该库是在MIT许可下发布的开源代码。
入门 就像VexFlow的官方教程所说的一样, 我们希望你具有一些JavaScript编程经验以及对音乐符号术语的基本了解, 否则, 你将在尝试实现它时会哭泣。
音乐表的生成基本上将基于Staves。 VexFlow API允许你使用一些可自定义的选项添加简单的五线谱:
注意 【使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)】在大多数示例中, 我们将使用SVG。使用SVG可以比< canvas> 更好地满足可伸缩性优先的大多数方案。高保真复杂图形(例如建筑图和工程图, 乐谱, 生物图等)就是此类示例。但是, 由于VexFlow允许, 你可以按照自己想要的方式自由工作。
1.用谱号和拍号创建谱表
谱号是一种音乐符号, 指示音符的音高。它放置在五线谱开始处的其中一行上, 它指示该行上音符的名称和音高。仅使用了一个在空间而非行中引用音符的谱号。
要添加谱号和拍号, 首先需要在要放置的谱号上创建谱号。如前所述, 你可以使用canvas或SVG使用VexFlow:
A.帆布 首先, 你需要使用HTML创建画布元素, Vex Flow将在其中工作:
< canvas id="some-canvas-id"> < /canvas>

然后创建Vex Flow渲染器的新实例。渲染器期望将先前创建的canvas元素作为第一个参数, 并将Canvas类型作为第二个参数存储在VF.Renderer.Backends.CANVAS中作为常量。然后使用渲染的调整大小方法提供Canvas元素的尺寸。要创建梯级, 你将需要使用的Canvas的上下文, 使用getContext方法从渲染器对象(而不是直接从画布)检索上下文并将其存储到变量中。
最后一步, 创建VX Stave类的新实例。此方法需要3个参数, 第一个参数是一个整数, 指定了画布在x轴上的位置, 第二个参数也是一个整数, 指定了画布在y轴上的位置, 第三个参数参数, 也是一个整数, 它指定梯级的宽度。从创建的对象中, 你将能够调用addClef方法(将作为谱号类型的字符串作为第一个参数)和addTimeSignature(将作为时间标记的标识符作为第一个参数, 例如4/4, 4/2等)。 )。然后使用setContext方法, 该方法将先前存储在变量中的渲染器对象的上下文作为参数, 并从中执行draw方法绘制梯级。
VF = Vex.Flow; // We created an object to store the information about the workspacevar WorkspaceInformation = {// The < canvas> element in which you're going to workcanvas: document.getElementById("some-canvas-id"), // Vex creates a canvas with specific dimensionscanvasWidth: 500, canvasHeight: 500}; // Create a renderer with Canvasvar renderer = new VF.Renderer(WorkspaceInformation.canvas, VF.Renderer.Backends.CANVAS); // Use the renderer to give the dimensions to the canvasrenderer.resize(WorkspaceInformation.canvasWidth, WorkspaceInformation.canvasHeight); // Expose the context of the renderervar context = renderer.getContext(); // And give some style to our canvascontext.setFont("Arial", 10, "").setBackgroundFillStyle("#eed"); /** * Creating a new stave */// Create a stave of width 400 at position x10, y40 on the canvas.var stave = new VF.Stave(10, 40, 400); // Add a clef and time signature.stave.addClef("treble").addTimeSignature("4/4"); // Set the context of the stave our previous exposed context and execute the method draw !stave.setContext(context).draw();

SVG 首先, 你需要使用Vex Flow将在其中运行的HTML创建div元素:
< div id="some-div-id"> < /div>

然后创建Vex Flow渲染器的新实例。渲染器希望将先前创建的div元素用作第一个参数, 而将SVG类型作为常量存储在VF.Renderer.Backends.SVG中作为第二个参数。然后, 使用渲染的调整大小方法提供SVG元素的尺寸。要创建梯级, 你将需要使用的SVG上下文, 使用getContext方法从渲染器对象检索上下文并将其存储到变量中。
最后一步, 创建VX Stave类的新实例。此方法需要3个参数, 第一个参数是一个整数, 指定在SVG的x轴上冷却壁的位置, 第二个参数也是一个整数, 它指定在y轴的冷却壁上的位置, 第三个参数参数, 也是一个整数, 它指定梯级的宽度。从创建的对象中, 你将能够调用addClef方法(将作为谱号类型的字符串作为第一个参数)和addTimeSignature(将作为时间标记的标识符作为第一个参数, 例如4/4, 4/2等)。 )。然后使用setContext方法, 该方法将先前存储在变量中的渲染器对象的上下文作为参数, 并从中执行draw方法绘制梯级。
VF = Vex.Flow; // We created an object to store the information about the workspacevar WorkspaceInformation = {// The div in which you're going to workdiv: document.getElementById("some-div-id"), // Vex creates a svg with specific dimensionscanvasWidth: 500, canvasHeight: 500}; // Create a renderer with SVGvar renderer = new VF.Renderer(WorkspaceInformation.div, VF.Renderer.Backends.SVG); // Use the renderer to give the dimensions to the SVGrenderer.resize(WorkspaceInformation.canvasWidth, WorkspaceInformation.canvasHeight); // Expose the context of the renderervar context = renderer.getContext(); // And give some style to our SVGcontext.setFont("Arial", 10, "").setBackgroundFillStyle("#eed"); /** * Creating a new stave */// Create a stave of width 400 at position x10, y40 on the SVG.var stave = new VF.Stave(10, 40, 400); // Add a clef and time signature.stave.addClef("treble").addTimeSignature("4/4"); // Set the context of the stave our previous exposed context and execute the method draw !stave.setContext(context).draw();

尽管乍一看似乎很复杂, 但事实并非如此, 你只需要耐心等待, 仔细阅读所有示例, 进行练习即可开始使用。前面任何示例(SVG或Canvas)的执行将生成以下梯级:
使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

文章图片
你将要(并且需要)在一个工作空间(SVG或Canvas)中绘制多个五线谱(具有不同的信息), 并且如果正确处理位置值, 就可以轻松实现。分析以下示例以查看如何在单个工作空间中渲染许多谱图:
< div id="boo"> < /div> < script> VF = Vex.Flow; // Create an SVG renderer and attach it to the DIV element named "boo".var div = document.getElementById("boo")var renderer = new VF.Renderer(div, VF.Renderer.Backends.SVG); var canvasDimensions = {width: 820, height: 300}; // Configure the rendering context.renderer.resize(canvasDimensions.width, canvasDimensions.height); var context = renderer.getContext(); context.setFont("Arial", 10, "").setBackgroundFillStyle("#eed"); /*** Left side staves */// Create a stave of width 400 at position x10, y40 on the canvas.var stave = new VF.Stave(10, 40, 400); // Add a clef and time signature.stave.addClef("treble").addTimeSignature("4/4"); // Connect it to the rendering context and draw!stave.setContext(context).draw(); // Create a stave with soprano clef width 400 at position x10, y120 on the canvas.var stave2 = new VF.Stave(10, 120, 400); stave2.addClef("soprano").addTimeSignature("4/4"); stave2.setContext(context).draw(); /*** Right side staves */// Create a stave with baritone-f clef width 400 at position x420, y40 on the canvas.var stave3 = new VF.Stave(420, 40, 400); stave3.addClef("baritone-f").addTimeSignature("4/2"); stave3.setContext(context).draw(); // Create a stave with mezzo-soprano clef width 400 at position x420, y120 on the canvas without time signaturevar stave4 = new VF.Stave(420, 120, 400); stave4.addClef("mezzo-soprano"); stave4.setContext(context).draw(); < /script>

执行上一个脚本, 应在画布上生成以下内容:
使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

文章图片
2.在木板上书写笔记
StaveNote是代表和弦的一组音符头。它可以包含一个或多个带有或不带有茎和旗的音符。音符序列由音色表示, 并且可以在音色组中对多个音色进行分组。
VF = Vex.Flow; // We created an object to store the information about the workspacevar WorkspaceInformation = {// The div in which you're going to workdiv: document.getElementById("some-div-id"), // Vex creates a svg with specific dimensionscanvasWidth: 500, canvasHeight: 500}; // Create a renderer with SVGvar renderer = new VF.Renderer(WorkspaceInformation.div, VF.Renderer.Backends.SVG); // Use the renderer to give the dimensions to the SVGrenderer.resize(WorkspaceInformation.canvasWidth, WorkspaceInformation.canvasHeight); // Expose the context of the renderervar context = renderer.getContext(); // And give some style to our SVGcontext.setFont("Arial", 10, "").setBackgroundFillStyle("#eed"); /** * Creating a new stave */// Create a stave of width 400 at position x10, y40 on the SVG.var stave = new VF.Stave(10, 40, 400); // Add a clef and time signature.stave.addClef("treble").addTimeSignature("4/4"); // Set the context of the stave our previous exposed context and execute the method draw !stave.setContext(context).draw(); /*** Draw notes */var notes = [// A quarter-note C.new VF.StaveNote({clef: "treble", keys: ["c/4"], duration: "q" }), // A quarter-note D.new VF.StaveNote({clef: "treble", keys: ["d/4"], duration: "q" }), // A quarter-note rest. Note that the key (b/4) specifies the vertical// position of the rest.new VF.StaveNote({clef: "treble", keys: ["b/4"], duration: "qr" }), // A C-Major chord.new VF.StaveNote({clef: "treble", keys: ["c/4", "e/4", "g/4"], duration: "q" })]; // Create a voice in 4/4 and add above notesvar voice = new VF.Voice({num_beats: 4, beat_value: 4}); voice.addTickables(notes); // Format and justify the notes to 400 pixels.var formatter = new VF.Formatter().joinVoices([voice]).format([voice], 400); // Render voicevoice.draw(context, stave);

执行上一个脚本, 应在画布上生成以下内容:
使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

文章图片
3.创建吉他制琴谱
对于吉他和其他带颤音的乐器, 可以用谱号代替普通音符。在这种情况下, 通常会写一个TAB符号而不是谱号。五线谱的行数不一定是五行:乐器的每一串都使用一行
VF = Vex.Flow; // Create an SVG renderer and attach it to the DIV element named "boo".var div = document.getElementById("boo"); // Create a renderer that uses SVGvar renderer = new VF.Renderer(div, VF.Renderer.Backends.SVG); // Configure the rendering context.renderer.resize(500, 500); var context = renderer.getContext(); // Create a tab stave of width 400 at position 10, 40 on the canvas.var stave = new VF.TabStave(10, 40, 400); stave.addClef("tab").setContext(context).draw(); var notes = [// A single notenew VF.TabNote({positions: [{str: 3, fret: 7}], duration: "q"}), // A chord with the note on the 3rd string bentnew VF.TabNote({positions: [{str: 2, fret: 10}, {str: 3, fret: 9}, {str: 4, fret: 8}, ], duration: "q"}).addModifier(new VF.Bend("Full"), 1), // A single note with a harsh vibratonew VF.TabNote({positions: [{str: 2, fret: 5}], duration: "h"}).addModifier(new VF.Vibrato().setHarsh(true).setVibratoWidth(50), 0)]; VF.Formatter.FormatAndDraw(context, stave, notes);

前一个脚本的执行应生成以下梯级:
使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

文章图片
使用EasyScore 如果你已经达到本文的这一点, 那么你可能已经对自己说:” 该死的代码太多了” , 这就是VexFlow提供了一个实用程序来简化音乐符号的书写方式EasyScore的原因。 EasyScore是一种很小的语言, 可用于生成一系列乐谱所需的所有VexFlow元素。该语言支持笔记, 意外, 横梁, 圆点, 连音符和其他常见的符号元素。
例如, 可以使用EasyScore将入门教程的步骤3替换为以下代码:
// Create an SVG renderer and attach it to the DIV element named "boo".var vf = new Vex.Flow.Factory({renderer: {selector: 'some-div-id'}}); var score = vf.EasyScore(); var system = vf.System(); system.addStave({voices: [score.voice(score.notes('C4/q, d4, b4/r, (C4 E4 G4)/q'))]}).addClef('treble').addTimeSignature('4/4'); vf.draw();

显然, 它的代码更少, 并且在某种程度上易于阅读, 你认为吗?执行前面的代码将产生与步骤3相同的结果:
使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

文章图片
EasyScore甚至允许添加另一个梯级, 该梯级可以渲染另外两种声音:
// Create an SVG renderer and attach it to the DIV element named "boo".var vf = new Vex.Flow.Factory({renderer: {selector: 'boo', height: 800, width: 800}}); var score = vf.EasyScore(); var system = vf.System(); system.addStave({voices: [score.voice(score.notes('C#5/q, B4, A4, G#4', {stem: 'up'})), score.voice(score.notes('C#4/h, C#4', {stem: 'down'}))]}).addClef('treble').addTimeSignature('4/4'); system.addConnector(); system.addStave({voices: [score.voice(score.notes('C#3/q, B2, A2/8, B2, C#3, D3', {clef: 'bass', stem: 'up'})), score.voice(score.notes('C#2/h, C#2', {clef: 'bass', stem: 'down'}))]}).addClef('bass').addTimeSignature('4/4'); vf.draw();

会产生:
使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

文章图片
沙盒 如果你愿意在浏览器中尝试VexFlow, 他们会提供一个总是使用库的最新版本的小提琴, 请在此处查看。最后, 我们鼓励阅读VexFlow Wiki。
编码愉快!

    推荐阅读