本文概述
你是否有演奏乐器的朋友, 并且想玩得开心?音乐由多种符号组成, 其中最基本的是谱号, 谱号和音符。从理论上讲, 绘制这些符号很简单, 但是要理解它们并产生旋律则非常复杂。如果你是网络开发人员, 并且需要处理一些需要在浏览器上呈现音乐符号的音乐项目, 那么今天就是你的幸运日, 因为你无需编写自己的脚本即可实现这一目标。要使用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="path-to-scripts/vexflow.min.js"></script>
该库是在MIT许可下发布的开源代码。
入门
就像VexFlow的官方教程所说的一样, 我们希望你具有一些JavaScript编程经验以及对音乐符号术语的基本了解, 否则, 你将在尝试实现它时会哭泣。
音乐表的生成基本上将基于Staves。 VexFlow API允许你使用一些可自定义的选项添加简单的五线谱:
注意
在大多数示例中, 我们将使用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 workspace
var WorkspaceInformation = {
// The <canvas> element in which you're going to work
canvas: document.getElementById("some-canvas-id"), // Vex creates a canvas with specific dimensions
canvasWidth: 500, canvasHeight: 500
};
// Create a renderer with Canvas
var renderer = new VF.Renderer(
WorkspaceInformation.canvas, VF.Renderer.Backends.CANVAS
);
// Use the renderer to give the dimensions to the canvas
renderer.resize(WorkspaceInformation.canvasWidth, WorkspaceInformation.canvasHeight);
// Expose the context of the renderer
var context = renderer.getContext();
// And give some style to our canvas
context.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 workspace
var WorkspaceInformation = {
// The div in which you're going to work
div: document.getElementById("some-div-id"), // Vex creates a svg with specific dimensions
canvasWidth: 500, canvasHeight: 500
};
// Create a renderer with SVG
var renderer = new VF.Renderer(
WorkspaceInformation.div, VF.Renderer.Backends.SVG
);
// Use the renderer to give the dimensions to the SVG
renderer.resize(WorkspaceInformation.canvasWidth, WorkspaceInformation.canvasHeight);
// Expose the context of the renderer
var context = renderer.getContext();
// And give some style to our SVG
context.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 signature
var 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 workspace
var WorkspaceInformation = {
// The div in which you're going to work
div: document.getElementById("some-div-id"), // Vex creates a svg with specific dimensions
canvasWidth: 500, canvasHeight: 500
};
// Create a renderer with SVG
var renderer = new VF.Renderer(
WorkspaceInformation.div, VF.Renderer.Backends.SVG
);
// Use the renderer to give the dimensions to the SVG
renderer.resize(WorkspaceInformation.canvasWidth, WorkspaceInformation.canvasHeight);
// Expose the context of the renderer
var context = renderer.getContext();
// And give some style to our SVG
context.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 notes
var 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 voice
voice.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 SVG
var 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 note
new VF.TabNote({
positions: [
{str: 3, fret: 7}
], duration: "q"
}), // A chord with the note on the 3rd string bent
new 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 vibrato
new 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。
编码愉快!
评论前必须登录!
注册