本文概述
- 要求
- 入门
- 使用EasyScore
- 沙盒
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)的执行将生成以下梯级:
文章图片
你将要(并且需要)在一个工作空间(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>
执行上一个脚本, 应在画布上生成以下内容:
文章图片
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);
执行上一个脚本, 应在画布上生成以下内容:
文章图片
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);
前一个脚本的执行应生成以下梯级:
文章图片
使用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相同的结果:
文章图片
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, 他们会提供一个总是使用库的最新版本的小提琴, 请在此处查看。最后, 我们鼓励阅读VexFlow Wiki。
编码愉快!
推荐阅读
- 如何检查reCAPTCHA框是否已过期
- 如何在JavaScript中从字符串名称执行函数(按名称执行函数)
- Java读取txt文件,并且对其文件内容进行统计排序
- Opencv图像读取,显示,保存,类型转换
- Java逐行读取数据
- java读取txt文件
- Numpy之线性代数
- 穷举搜索的例子(Google方程式(Java题解))
- Canny 边缘检测