个性化阅读
专注于IT技术分析

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

本文概述

你是否有演奏乐器的朋友, 并且想玩得开心?音乐由多种符号组成, 其中最基本的是谱号, 谱号和音符。从理论上讲, 绘制这些符号很简单, 但是要理解它们并产生旋律则非常复杂。如果你是网络开发人员, 并且需要处理一些需要在浏览器上呈现音乐符号的音乐项目, 那么今天就是你的幸运日, 因为你无需编写自己的脚本即可实现这一目标。要使用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)的执行将生成以下梯级:

五线谱VexFlow示例

你将要(并且需要)在一个工作空间(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>

执行上一个脚本, 应在画布上生成以下内容:

多级VexFlow JavaScript

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);

执行上一个脚本, 应在画布上生成以下内容:

关于Stave Vexflow的说明

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);

前一个脚本的执行应生成以下梯级:

Guitar Tab Vex Flow 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相同的结果:

关于Stave Vexflow的说明

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();

会产生:

多种声音EasyScore VexFlow

沙盒

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

编码愉快!

赞(1)
未经允许不得转载:srcmini » 使用VexFlow 2在JavaScript中渲染音乐符号(乐谱)

评论 抢沙发

评论前必须登录!