81 |
82 |
83 |
Have some fun!
84 |
85 |
86 | Try out the VexFlow API in this live editor.
87 |
88 |
89 |
90 |
91 |
129 |
130 |
131 |
132 |
151 |
176 |
177 |
178 |
179 |
180 |
181 | Confused? Go read the tutorial.
182 |
183 |
184 |
185 |
186 |
187 |
188 |
--------------------------------------------------------------------------------
/docs/viewer_demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
VexFlow Viewer
4 |
6 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
29 |
30 |
80 |
81 |
82 |
83 |
89 |
90 |
95 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/hack/Reunion.mxl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lasconic/vexflow-musicxml/a4bf68c7b43c8b4dcd8162f777a150ed6e3a15d7/hack/Reunion.mxl
--------------------------------------------------------------------------------
/hack/Reunion.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lasconic/vexflow-musicxml/a4bf68c7b43c8b4dcd8162f777a150ed6e3a15d7/hack/Reunion.zip
--------------------------------------------------------------------------------
/hack/build.sh:
--------------------------------------------------------------------------------
1 | cd ..
2 | rake
3 | cd hack
4 | cp ../build/vexflow/vexflow-* .
--------------------------------------------------------------------------------
/hack/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
VexFlow MusicXML Viewer
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
89 |
95 |
96 |
97 |
98 |
Please enable JavaScript to use the viewer.
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "eqnull": true, // allow == and ~= for nulls
3 | "sub": true, // don't enforce dot notation
4 | "trailing": true, // no more trailing spaces
5 | "globals": {
6 | "Vex": false,
7 | "Raphael": false
8 | } // allowed globals
9 | }
10 |
--------------------------------------------------------------------------------
/push.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Simple deployment script for vexflow.com.
3 | #
4 | # Pushes only JavaScript, tests, and supporting HTML (tutorial, playground)
5 |
6 | TARGET='/home/mohit/www/vexflow'
7 | SSH_TO="mohit@my.vexflow.com source ~/.bash_profile; cd $TARGET;"
8 | SCP_TO="mohit@my.vexflow.com:$TARGET"
9 |
10 | echo Building...
11 | rake clean; rake; rake docs
12 |
13 | ssh $SSH_TO "mkdir -p $TARGET; mkdir -p $TARGET/support"
14 | if [ "$?" != "0" ]
15 | then
16 | echo "Cannot create remote directory."
17 | exit 1
18 | fi
19 |
20 | echo Copying over compiled sources...
21 | scp build/vexflow/vexflow-min.js $SCP_TO/support
22 | scp build/vexflow/vexflow-debug.js $SCP_TO/support
23 |
24 | echo Copying over tests...
25 | rsync -przvl --delete --stats tests $SCP_TO
26 | scp tests/flow.html $SCP_TO/tests/index.html
27 |
28 | echo Copy over docs...
29 | rsync -przvl --delete --stats docs $SCP_TO
30 | scp -r docs/index.html $SCP_TO
31 | ssh $SSH_TO "rm docs/index.html"
32 |
33 | echo Done.
34 |
--------------------------------------------------------------------------------
/push_demo.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | # Deploy demo.
3 | #
4 | # Pushes JavaScript, tests, and docs (containing viewer and samples)
5 |
6 | /bin/echo -n "Target directory: "
7 | read TARGET
8 | /bin/echo -n "User@SSH server: "
9 | read SSH_TO
10 | SCP_TO="$SSH_TO:$TARGET"
11 |
12 | echo Building...
13 | scons -c
14 | ./build.sh
15 |
16 | ssh $SSH_TO "mkdir -p $TARGET; mkdir -p $TARGET/support"
17 | if [ "$?" != "0" ]
18 | then
19 | echo "Cannot create remote directory."
20 | exit 1
21 | fi
22 |
23 | echo Copying over compiled sources...
24 | scp build/vexflow/vexflow-min.js $SCP_TO/support
25 |
26 | echo Copying over tests...
27 | ssh $SSH_TO rm -rf tests/
28 | scp -r build/tests $SCP_TO
29 | scp build/tests/flow.html $SCP_TO/tests/index.html
30 |
31 | echo Copy over docs...
32 | scp -r docs $SCP_TO
33 |
34 | echo Done.
35 |
--------------------------------------------------------------------------------
/src/accidental.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
2 | //
3 | // ## Description
4 | //
5 | // This file implements accidentals as modifiers that can be attached to
6 | // notes. Support is included for both western and microtonal accidentals.
7 | //
8 | // See `tests/accidental_tests.js` for usage examples.
9 |
10 | Vex.Flow.Accidental = (function(){
11 | function Accidental(type) {
12 | if (arguments.length > 0) this.init(type);
13 | }
14 |
15 | // To enable logging for this class. Set `Vex.Flow.Accidental.DEBUG` to `true`.
16 | function L() { if (Accidental.DEBUG) Vex.L("Vex.Flow.Accidental", arguments); }
17 |
18 | var Modifier = Vex.Flow.Modifier;
19 |
20 | // ## Prototype Methods
21 | //
22 | // An `Accidental` inherits from `Modifier`, and is formatted within a
23 | // `ModifierContext`.
24 | Vex.Inherit(Accidental, Modifier, {
25 | // Create accidental. `type` can be a value from the
26 | // `Vex.Flow.accidentalCodes.accidentals` table in `tables.js`. For
27 | // example: `#`, `##`, `b`, `n`, etc.
28 | init: function(type) {
29 | Accidental.superclass.init.call(this);
30 | L("New accidental: ", type);
31 |
32 | this.note = null;
33 | // The `index` points to a specific note in a chord.
34 | this.index = null;
35 | this.type = type;
36 | this.position = Modifier.Position.LEFT;
37 |
38 | this.render_options = {
39 | // Font size for glyphs
40 | font_scale: 38,
41 |
42 | // Length of stroke across heads above or below the stave.
43 | stroke_px: 3
44 | };
45 |
46 | this.accidental = Vex.Flow.accidentalCodes(this.type);
47 | if (!this.accidental) throw new Vex.RERR("ArgumentError", "Unknown accidental type: " + type);
48 |
49 | // Cautionary accidentals have parentheses around them
50 | this.cautionary = false;
51 | this.paren_left = null;
52 | this.paren_right = null;
53 |
54 | // Initial width is set from table.
55 | this.setWidth(this.accidental.width);
56 | },
57 |
58 | // Return the modifier type. Used by the `ModifierContext` to calculate
59 | // layout.
60 | getCategory: function() { return "accidentals"; },
61 |
62 | // Attach this accidental to `note`, which must be a `StaveNote`.
63 | setNote: function(note){
64 | if (!note) throw new Vex.RERR("ArgumentError", "Bad note value: " + note);
65 | this.note = note;
66 |
67 | // Accidentals attached to grace notes are rendered smaller.
68 | if (this.note.getCategory() === 'gracenotes') {
69 | this.render_options.font_scale = 25;
70 | this.setWidth(this.accidental.gracenote_width);
71 | }
72 | },
73 |
74 | // If called, draws parenthesis around accidental.
75 | setAsCautionary: function() {
76 | this.cautionary = true;
77 | this.render_options.font_scale = 28;
78 | this.paren_left = Vex.Flow.accidentalCodes("{");
79 | this.paren_right = Vex.Flow.accidentalCodes("}");
80 | var width_adjust = (this.type == "##" || this.type == "bb") ? 6 : 4;
81 |
82 | // Make sure `width` accomodates for parentheses.
83 | this.setWidth(this.paren_left.width + this.accidental.width + this.paren_right.width - width_adjust);
84 | return this;
85 | },
86 |
87 | // Render accidental onto canvas.
88 | draw: function() {
89 | if (!this.context) throw new Vex.RERR("NoContext",
90 | "Can't draw accidental without a context.");
91 | if (!(this.note && (this.index != null))) throw new Vex.RERR("NoAttachedNote",
92 | "Can't draw accidental without a note and index.");
93 |
94 | // Figure out the start `x` and `y` coordinates for this note and index.
95 | var start = this.note.getModifierStartXY(this.position, this.index);
96 | var acc_x = (start.x + this.x_shift) - this.width;
97 | var acc_y = start.y + this.y_shift;
98 | L("Rendering: ", this.type, acc_x, acc_y);
99 |
100 | if (!this.cautionary) {
101 | // Render the accidental alone.
102 | Vex.Flow.renderGlyph(this.context, acc_x, acc_y,
103 | this.render_options.font_scale, this.accidental.code);
104 | } else {
105 | // Render the accidental in parentheses.
106 | acc_x += 3;
107 | Vex.Flow.renderGlyph(this.context, acc_x, acc_y,
108 | this.render_options.font_scale, this.paren_left.code);
109 | acc_x += 2;
110 | Vex.Flow.renderGlyph(this.context, acc_x, acc_y,
111 | this.render_options.font_scale, this.accidental.code);
112 | acc_x += this.accidental.width - 2;
113 | if (this.type == "##" || this.type == "bb") acc_x -= 2;
114 | Vex.Flow.renderGlyph(this.context, acc_x, acc_y,
115 | this.render_options.font_scale, this.paren_right.code);
116 | }
117 | }
118 | });
119 |
120 | return Accidental;
121 | }());
--------------------------------------------------------------------------------
/src/annotation.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
2 | //
3 | // ## Description
4 | //
5 | // This file implements text annotations as modifiers that can be attached to
6 | // notes.
7 | //
8 | // See `tests/annotation_tests.js` for usage examples.
9 |
10 | Vex.Flow.Annotation = (function() {
11 | function Annotation(text) {
12 | if (arguments.length > 0) this.init(text);
13 | }
14 |
15 | // To enable logging for this class. Set `Vex.Flow.Annotation.DEBUG` to `true`.
16 | function L() { if (Annotation.DEBUG) Vex.L("Vex.Flow.Annotation", arguments); }
17 |
18 | // Text annotations can be positioned and justified relative to the note.
19 | Annotation.Justify = {
20 | LEFT: 1,
21 | CENTER: 2,
22 | RIGHT: 3,
23 | CENTER_STEM: 4
24 | };
25 |
26 | Annotation.VerticalJustify = {
27 | TOP: 1,
28 | CENTER: 2,
29 | BOTTOM: 3,
30 | CENTER_STEM: 4
31 | };
32 |
33 | // ## Prototype Methods
34 | //
35 | // Annotations inherit from `Modifier` and is positioned correctly when
36 | // in a `ModifierContext`.
37 | var Modifier = Vex.Flow.Modifier;
38 | Vex.Inherit(Annotation, Modifier, {
39 | // Create a new `Annotation` with the string `text`.
40 | init: function(text) {
41 | Annotation.superclass.init.call(this);
42 |
43 | this.note = null;
44 | this.index = null;
45 | this.text_line = 0;
46 | this.text = text;
47 | this.justification = Annotation.Justify.CENTER;
48 | this.vert_justification = Annotation.VerticalJustify.TOP;
49 | this.font = {
50 | family: "Arial",
51 | size: 10,
52 | weight: ""
53 | };
54 |
55 | // The default width is calculated from the text.
56 | this.setWidth(Vex.Flow.textWidth(text));
57 | },
58 |
59 | // Return the modifier type. Used by the `ModifierContext` to calculate
60 | // layout.
61 | getCategory: function() { return "annotations"; },
62 |
63 | // Set the vertical position of the text relative to the stave.
64 | setTextLine: function(line) { this.text_line = line; return this; },
65 |
66 | // Set font family, size, and weight. E.g., `Arial`, `10pt`, `Bold`.
67 | setFont: function(family, size, weight) {
68 | this.font = { family: family, size: size, weight: weight };
69 | return this;
70 | },
71 |
72 | // Set vertical position of text (above or below stave). `just` must be
73 | // a value in `Annotation.VerticalJustify`.
74 | setVerticalJustification: function(just) {
75 | this.vert_justification = just;
76 | return this;
77 | },
78 |
79 | // Get and set horizontal justification. `justification` is a value in
80 | // `Annotation.Justify`.
81 | getJustification: function() { return this.justification; },
82 | setJustification: function(justification) {
83 | this.justification = justification; return this; },
84 |
85 | // Render text beside the note.
86 | draw: function() {
87 | if (!this.context) throw new Vex.RERR("NoContext",
88 | "Can't draw text annotation without a context.");
89 | if (!this.note) throw new Vex.RERR("NoNoteForAnnotation",
90 | "Can't draw text annotation without an attached note.");
91 |
92 | var start = this.note.getModifierStartXY(Modifier.Position.ABOVE,
93 | this.index);
94 |
95 | // We're changing context parameters. Save current state.
96 | this.context.save();
97 | this.context.setFont(this.font.family, this.font.size, this.font.weight);
98 | var text_width = this.context.measureText(this.text).width;
99 |
100 | // Estimate text height to be the same as the width of an 'm'.
101 | //
102 | // This is a hack to work around the inability to measure text height
103 | // in HTML5 Canvas (and SVG).
104 | var text_height = this.context.measureText("m").width;
105 | var x, y;
106 |
107 | if (this.justification == Annotation.Justify.LEFT) {
108 | x = start.x;
109 | } else if (this.justification == Annotation.Justify.RIGHT) {
110 | x = start.x - text_width;
111 | } else if (this.justification == Annotation.Justify.CENTER) {
112 | x = start.x - text_width / 2;
113 | } else /* CENTER_STEM */ {
114 | x = this.note.getStemX() - text_width / 2;
115 | }
116 |
117 | var stem_ext, spacing;
118 | var has_stem = this.note.hasStem();
119 | var stave = this.note.getStave();
120 |
121 | // The position of the text varies based on whether or not the note
122 | // has a stem.
123 | if (has_stem) {
124 | stem_ext = this.note.getStem().getExtents();
125 | spacing = stave.getSpacingBetweenLines();
126 | }
127 |
128 | if (this.vert_justification == Annotation.VerticalJustify.BOTTOM) {
129 | y = stave.getYForBottomText(this.text_line);
130 | if (has_stem) {
131 | var stem_base = (this.note.getStemDirection() === 1 ? stem_ext.baseY : stem_ext.topY);
132 | y = Math.max(y, stem_base + (spacing * (this.text_line + 2)));
133 | }
134 | } else if (this.vert_justification ==
135 | Annotation.VerticalJustify.CENTER) {
136 | var yt = this.note.getYForTopText(this.text_line) - 1;
137 | var yb = stave.getYForBottomText(this.text_line);
138 | y = yt + ( yb - yt ) / 2 + text_height / 2;
139 | } else if (this.vert_justification ==
140 | Annotation.VerticalJustify.TOP) {
141 | y = Math.min(stave.getYForTopText(this.text_line), this.note.getYs()[0] - 10);
142 | if (has_stem) {
143 | y = Math.min(y, (stem_ext.topY - 5) - (spacing * this.text_line));
144 | }
145 | } else /* CENTER_STEM */{
146 | var extents = this.note.getStemExtents();
147 | y = extents.topY + (extents.baseY - extents.topY) / 2 +
148 | text_height / 2;
149 | }
150 |
151 | L("Rendering annotation: ", this.text, x, y);
152 | this.context.fillText(this.text, x, y);
153 | this.context.restore();
154 | }
155 | });
156 |
157 | return Annotation;
158 | }());
--------------------------------------------------------------------------------
/src/barnote.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
2 | //
3 | // ## Description
4 | //
5 | // A `BarNote` is used to render bar lines (from `barline.js`). `BarNote`s can
6 | // be added to a voice and rendered in the middle of a stave. Since it has no
7 | // duration, it consumes no `tick`s, and is dealt with appropriately by the formatter.
8 | //
9 | // See `tests/barnote_tests.js` for usage examples.
10 |
11 | Vex.Flow.BarNote = (function() {
12 | function BarNote() { this.init(); }
13 |
14 | // To enable logging for this class. Set `Vex.Flow.BarNote.DEBUG` to `true`.
15 | function L() { if (BarNote.DEBUG) Vex.L("Vex.Flow.BarNote", arguments); }
16 |
17 | // ## Prototype Methods
18 | Vex.Inherit(BarNote, Vex.Flow.Note, {
19 | init: function() {
20 | BarNote.superclass.init.call(this, {duration: "b"});
21 |
22 | var TYPE = Vex.Flow.Barline.type;
23 | this.metrics = {
24 | widths: {}
25 | };
26 |
27 | // Defined this way to prevent lint errors.
28 | this.metrics.widths[TYPE.SINGLE] = 8;
29 | this.metrics.widths[TYPE.DOUBLE] = 12;
30 | this.metrics.widths[TYPE.END] = 15;
31 | this.metrics.widths[TYPE.REPEAT_BEGIN] = 14;
32 | this.metrics.widths[TYPE.REPEAT_END] = 14;
33 | this.metrics.widths[TYPE.REPEAT_BOTH] = 18;
34 | this.metrics.widths[TYPE.NONE] = 0;
35 |
36 | // Tell the formatter that bar notes have no duration.
37 | this.ignore_ticks = true;
38 | this.type = TYPE.SINGLE;
39 |
40 | // Set width to width of relevant `Barline`.
41 | this.setWidth(this.metrics.widths[this.type]);
42 | },
43 |
44 | // Get and set the type of Bar note. `type` must be one of `Vex.Flow.Barline.type`.
45 | getType: function() { return this.type; },
46 | setType: function(type) {
47 | this.type = type;
48 | this.setWidth(this.metrics.widths[this.type]);
49 | return this;
50 | },
51 |
52 | getBoundingBox: function() {
53 | return new Vex.Flow.BoundingBox(0, 0, 0, 0);
54 | },
55 |
56 | addToModifierContext: function() {
57 | /* overridden to ignore */
58 | return this;
59 | },
60 |
61 | preFormat: function() {
62 | /* overridden to ignore */
63 | this.setPreFormatted(true);
64 | return this;
65 | },
66 |
67 | // Render note to stave.
68 | draw: function() {
69 | if (!this.stave) throw new Vex.RERR("NoStave", "Can't draw without a stave.");
70 | L("Rendering bar line at: ", this.getAbsoluteX());
71 | var barline = new Vex.Flow.Barline(this.type, this.getAbsoluteX());
72 | barline.draw(this.stave);
73 | }
74 | });
75 |
76 | return BarNote;
77 | }());
78 |
--------------------------------------------------------------------------------
/src/boundingbox.js:
--------------------------------------------------------------------------------
1 | // Vex Music Notation
2 | // Mohit Muthanna
3 | //
4 | // Copyright Mohit Muthanna 2010
5 |
6 | // Bounding boxes for interactive notation
7 |
8 | /** @constructor */
9 | Vex.Flow.BoundingBox = (function() {
10 | function BoundingBox(x, y, w, h) { this.init(x, y, w, h); }
11 | BoundingBox.copy = function(that) {
12 | return new BoundingBox(that.x, that.y, that.w, that.h); };
13 |
14 | BoundingBox.prototype = {
15 | init: function(x, y, w, h) {
16 | this.x = x;
17 | this.y = y;
18 | this.w = w;
19 | this.h = h;
20 | },
21 |
22 | getX: function() { return this.x; },
23 | getY: function() { return this.y; },
24 | getW: function() { return this.w; },
25 | getH: function() { return this.h; },
26 |
27 | setX: function(x) { this.x = x; return this; },
28 | setY: function(y) { this.y = y; return this; },
29 | setW: function(w) { this.w = w; return this; },
30 | setH: function(h) { this.h = h; return this; },
31 |
32 | move: function(x, y) { this.x += x; this.y += y; },
33 | clone: function() { return BoundingBox.copy(this); },
34 |
35 | // Merge my box with given box. Creates a bigger bounding box unless
36 | // the given box is contained in this one.
37 | mergeWith: function(boundingBox, ctx) {
38 | var that = boundingBox;
39 |
40 | var new_x = this.x < that.x ? this.x : that.x;
41 | var new_y = this.y < that.y ? this.y : that.y;
42 | var new_w = (this.x + this.w) < (that.x + that.w) ? (that.x + that.w) - this.x : (this.x + this.w) - Vex.Min(this.x, that.x);
43 | var new_h = (this.y + this.h) < (that.y + that.h) ? (that.y + that.h) - this.y : (this.y + this.h) - Vex.Min(this.y, that.y);
44 |
45 | this.x = new_x;
46 | this.y = new_y;
47 | this.w = new_w;
48 | this.h = new_h;
49 |
50 | if (ctx) this.draw(ctx);
51 | return this;
52 | },
53 |
54 | draw: function(ctx, x, y) {
55 | if (!x) x = 0;
56 | if (!y) y = 0;
57 | ctx.rect(this.x + x, this.y + y, this.w, this.h);
58 | ctx.stroke();
59 | }
60 | };
61 |
62 | return BoundingBox;
63 | }());
--------------------------------------------------------------------------------
/src/canvascontext.js:
--------------------------------------------------------------------------------
1 | // Vex Flow
2 | // Mohit Muthanna
3 | //
4 | // A rendering context for the Raphael backend.
5 | //
6 | // Copyright Mohit Cheppudira 2010
7 |
8 | /** @constructor */
9 | Vex.Flow.CanvasContext = (function() {
10 | function CanvasContext(context) {
11 | if (arguments.length > 0) this.init(context);
12 | }
13 |
14 | CanvasContext.WIDTH = 600;
15 | CanvasContext.HEIGHT = 400;
16 |
17 | CanvasContext.prototype = {
18 | init: function(context) {
19 | // Use a name that is unlikely to clash with a canvas context
20 | // property
21 | this.vexFlowCanvasContext = context;
22 | if (!context.canvas) {
23 | this.canvas = {
24 | width: CanvasContext.WIDTH,
25 | height: CanvasContext.HEIGHT
26 | };
27 | } else {
28 | this.canvas = this.context.canvas;
29 | }
30 | },
31 |
32 | clear: function() {
33 | this.vexFlowCanvasContext.clearRect(0, 0, this.canvas.width, this.canvas.height);
34 | },
35 |
36 | setFont: function(family, size, weight) {
37 | this.vexFlowCanvasContext.font = (weight || "") + " " + size + "pt " + family;
38 | return this;
39 | },
40 |
41 | setRawFont: function(font) {
42 | this.vexFlowCanvasContext.font = font;
43 | return this;
44 | },
45 |
46 | setFillStyle: function(style) {
47 | this.vexFlowCanvasContext.fillStyle = style;
48 | return this;
49 | },
50 |
51 | setBackgroundFillStyle: function(style) {
52 | this.background_fillStyle = style;
53 | return this;
54 | },
55 |
56 | setStrokeStyle: function(style) {
57 | this.vexFlowCanvasContext.strokeStyle = style;
58 | return this;
59 | },
60 |
61 | setShadowColor: function(style) {
62 | this.vexFlowCanvasContext.shadowColor = style;
63 | return this;
64 | },
65 |
66 | setShadowBlur: function(blur) {
67 | this.vexFlowCanvasContext.shadowBlur = blur;
68 | return this;
69 | },
70 |
71 | setLineWidth: function(width) {
72 | this.vexFlowCanvasContext.lineWidth = width;
73 | return this;
74 | },
75 |
76 | setLineCap: function(cap_type) {
77 | this.vexFlowCanvasContext.lineCap = cap_type;
78 | return this;
79 | },
80 |
81 | setLineDash: function(dash) {
82 | this.vexFlowCanvasContext.lineDash = dash;
83 | },
84 |
85 | scale: function(x, y) {
86 | return this.vexFlowCanvasContext.scale(parseFloat(x), parseFloat(y));
87 | },
88 |
89 | resize: function(width, height) {
90 | return this.vexFlowCanvasContext.resize(
91 | parseInt(width, 10), parseInt(height, 10));
92 | },
93 |
94 | rect: function(x, y, width, height) {
95 | return this.vexFlowCanvasContext.rect(x, y, width, height);
96 | },
97 |
98 | fillRect: function(x, y, width, height) {
99 | return this.vexFlowCanvasContext.fillRect(x, y, width, height);
100 | },
101 |
102 | clearRect: function(x, y, width, height) {
103 | return this.vexFlowCanvasContext.clearRect(x, y, width, height);
104 | },
105 |
106 | beginPath: function() {
107 | return this.vexFlowCanvasContext.beginPath();
108 | },
109 |
110 | moveTo: function(x, y) {
111 | return this.vexFlowCanvasContext.moveTo(x, y);
112 | },
113 |
114 | lineTo: function(x, y) {
115 | return this.vexFlowCanvasContext.lineTo(x, y);
116 | },
117 |
118 | bezierCurveTo: function(x1, y1, x2, y2, x, y) {
119 | return this.vexFlowCanvasContext.bezierCurveTo(x1, y1, x2, y2, x, y);
120 | },
121 |
122 | quadraticCurveTo: function(x1, y1, x, y) {
123 | return this.vexFlowCanvasContext.quadraticCurveTo(x1, y1, x, y);
124 | },
125 |
126 | // This is an attempt (hack) to simulate the HTML5 canvas
127 | // arc method.
128 | arc: function(x, y, radius, startAngle, endAngle, antiClockwise) {
129 | return this.vexFlowCanvasContext.arc(x, y, radius, startAngle, endAngle, antiClockwise);
130 | },
131 |
132 | // Adapted from the source for Raphael's Element.glow
133 | glow: function() {
134 | return this.vexFlowCanvasContext.glow();
135 | },
136 |
137 | fill: function() {
138 | return this.vexFlowCanvasContext.fill();
139 | },
140 |
141 | stroke: function() {
142 | return this.vexFlowCanvasContext.stroke();
143 | },
144 |
145 | closePath: function() {
146 | return this.vexFlowCanvasContext.closePath();
147 | },
148 |
149 | measureText: function(text) {
150 | return this.vexFlowCanvasContext.measureText(text);
151 | },
152 |
153 | fillText: function(text, x, y) {
154 | return this.vexFlowCanvasContext.fillText(text, x, y);
155 | },
156 |
157 | save: function() {
158 | return this.vexFlowCanvasContext.save();
159 | },
160 |
161 | restore: function() {
162 | return this.vexFlowCanvasContext.restore();
163 | }
164 | };
165 |
166 | return CanvasContext;
167 | }());
168 |
--------------------------------------------------------------------------------
/src/clef.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna Cheppudira 2013.
2 | // Co-author: Benjamin W. Bohl
3 | //
4 | // ## Description
5 | //
6 | // This file implements various types of clefs that can be rendered on a stave.
7 | //
8 | // See `tests/clef_tests.js` for usage examples.
9 |
10 | Vex.Flow.Clef = (function() {
11 | function Clef(clef) {
12 | if (arguments.length > 0) this.init(clef);
13 | }
14 |
15 | // To enable logging for this class, set `Vex.Flow.Clef.DEBUG` to `true`.
16 | function L() { if (Vex.Flow.Clef.DEBUG) Vex.L("Vex.Flow.Clef", arguments); }
17 |
18 | // Every clef name is associated with a glyph code from the font file, a
19 | // point size, and a default stave line number.
20 | Clef.types = {
21 | "treble": {
22 | code: "v83",
23 | point: 40,
24 | line: 3
25 | },
26 | "bass": {
27 | code: "v79",
28 | point: 40,
29 | line: 1
30 | },
31 | "alto": {
32 | code: "vad",
33 | point: 40,
34 | line: 2
35 | },
36 | "tenor": {
37 | code: "vad",
38 | point: 40,
39 | line: 1
40 | },
41 | "percussion": {
42 | code: "v59",
43 | point: 40,
44 | line: 2
45 | },
46 | "soprano": {
47 | code: "vad",
48 | point: 40,
49 | line: 4
50 | },
51 | "mezzo-soprano": {
52 | code: "vad",
53 | point: 40,
54 | line: 3
55 | },
56 | "baritone-c": {
57 | code: "vad",
58 | point: 40,
59 | line: 0
60 | },
61 | "baritone-f": {
62 | code: "v79",
63 | point: 40,
64 | line: 2
65 | },
66 | "subbass": {
67 | code: "v79",
68 | point: 40,
69 | line: 0
70 | },
71 | "french": {
72 | code: "v83",
73 | point: 40,
74 | line: 4
75 | },
76 | "treble_small": {
77 | code: "v83",
78 | point: 32,
79 | line: 3
80 | },
81 | "bass_small": {
82 | code: "v79",
83 | point: 32,
84 | line: 1
85 | },
86 | "alto_small": {
87 | code: "vad",
88 | point: 32,
89 | line: 2
90 | },
91 | "tenor_small": {
92 | code: "vad",
93 | point: 32,
94 | line: 1
95 | },
96 | "soprano_small": {
97 | code: "vad",
98 | point: 32,
99 | line: 4
100 | },
101 | "mezzo-soprano_small": {
102 | code: "vad",
103 | point: 32,
104 | line: 3
105 | },
106 | "baritone-c_small": {
107 | code: "vad",
108 | point: 32,
109 | line: 0
110 | },
111 | "baritone-f_small": {
112 | code: "v79",
113 | point: 32,
114 | line: 2
115 | },
116 | "subbass_small": {
117 | code: "v79",
118 | point: 32,
119 | line: 0
120 | },
121 | "french_small": {
122 | code: "v83",
123 | point: 32,
124 | line: 4
125 | },
126 | "percussion_small": {
127 | code: "v59",
128 | point: 32,
129 | line: 2
130 | }
131 | };
132 |
133 | // ## Prototype Methods
134 | Vex.Inherit(Clef, Vex.Flow.StaveModifier, {
135 | // Create a new clef. The parameter `clef` must be a key from
136 | // `Clef.types`.
137 | init: function(clef) {
138 | var superclass = Vex.Flow.Clef.superclass;
139 | superclass.init.call(this);
140 |
141 | this.clef = Vex.Flow.Clef.types[clef];
142 | L("Creating clef:", clef);
143 | },
144 |
145 | // Add this clef to the start of the given `stave`.
146 | addModifier: function(stave) {
147 | var glyph = new Vex.Flow.Glyph(this.clef.code, this.clef.point);
148 | this.placeGlyphOnLine(glyph, stave, this.clef.line);
149 | stave.addGlyph(glyph);
150 | },
151 |
152 | // Add this clef to the end of the given `stave`.
153 | addEndModifier: function(stave) {
154 | var glyph = new Vex.Flow.Glyph(this.clef.code, this.clef.point);
155 | this.placeGlyphOnLine(glyph, stave, this.clef.line);
156 | stave.addEndGlyph(glyph);
157 | }
158 | });
159 |
160 | return Clef;
161 | }());
162 |
--------------------------------------------------------------------------------
/src/clefnote.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // Author Taehoon Moon 2014
5 |
6 | /** @constructor */
7 | Vex.Flow.ClefNote = (function() {
8 | function ClefNote(clef) { this.init(clef); }
9 |
10 | Vex.Inherit(ClefNote, Vex.Flow.Note, {
11 | init: function(clef) {
12 | ClefNote.superclass.init.call(this, {duration: "b"});
13 |
14 | this.setClef(clef);
15 |
16 | // Note properties
17 | this.ignore_ticks = true;
18 | },
19 |
20 | setClef: function(clef) {
21 | this.clef = Vex.Flow.Clef.types[clef];
22 | this.glyph = new Vex.Flow.Glyph(this.clef.code, this.clef.point);
23 | this.setWidth(this.glyph.getMetrics().width);
24 | return this;
25 | },
26 |
27 | getClef: function() {
28 | return this.clef;
29 | },
30 |
31 | setStave: function(stave) {
32 | var superclass = Vex.Flow.ClefNote.superclass;
33 | superclass.setStave.call(this, stave);
34 | },
35 |
36 | getBoundingBox: function() {
37 | return new Vex.Flow.BoundingBox(0, 0, 0, 0);
38 | },
39 |
40 | addToModifierContext: function() {
41 | /* overridden to ignore */
42 | return this;
43 | },
44 |
45 | preFormat: function() {
46 | this.setPreFormatted(true);
47 | return this;
48 | },
49 |
50 | draw: function() {
51 | if (!this.stave) throw new Vex.RERR("NoStave", "Can't draw without a stave.");
52 |
53 | if (!this.glyph.getContext()) {
54 | this.glyph.setContext(this.context);
55 | }
56 |
57 | this.glyph.setStave(this.stave);
58 | this.glyph.setYShift(
59 | this.stave.getYForLine(this.clef.line) - this.stave.getYForGlyphs());
60 | this.glyph.renderToStave(this.getAbsoluteX());
61 | }
62 | });
63 |
64 | return ClefNote;
65 | }());
66 |
--------------------------------------------------------------------------------
/src/crescendo.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
2 | //
3 | // ## Description
4 | //
5 | // This file implements the `Crescendo` object which draws crescendos and
6 | // decrescendo dynamics markings. A `Crescendo` is initialized with a
7 | // duration and formatted as part of a `Voice` like any other `Note`
8 | // type in VexFlow. This object would most likely be formatted in a Voice
9 | // with `TextNotes` - which are used to represent other dynamics markings.
10 | Vex.Flow.Crescendo = (function() {
11 | function Crescendo(note_struct) {
12 | if (arguments.length > 0) this.init(note_struct);
13 | }
14 |
15 | // To enable logging for this class. Set `Vex.Flow.Crescendo.DEBUG` to `true`.
16 | function L() { if (Crescendo.DEBUG) Vex.L("Vex.Flow.Crescendo", arguments); }
17 |
18 | // Private helper to draw the hairpin
19 | function renderHairpin(ctx, params) {
20 | var begin_x = params.begin_x;
21 | var end_x = params.end_x;
22 | var y = params.y;
23 | var half_height = params.height / 2;
24 |
25 | ctx.beginPath();
26 |
27 | if (params.reverse) {
28 | ctx.moveTo(begin_x, y - half_height);
29 | ctx.lineTo(end_x, y);
30 | ctx.lineTo(begin_x, y + half_height);
31 | } else {
32 | ctx.moveTo(end_x, y - half_height);
33 | ctx.lineTo(begin_x, y);
34 | ctx.lineTo(end_x, y + half_height);
35 | }
36 |
37 | ctx.stroke();
38 | ctx.closePath();
39 | }
40 |
41 | // ## Prototype Methods
42 | Vex.Inherit(Crescendo, Vex.Flow.Note, {
43 | // Initialize the crescendo's properties
44 | init: function(note_struct) {
45 | Crescendo.superclass.init.call(this, note_struct);
46 |
47 | // Whether the object is a decrescendo
48 | this.decrescendo = false;
49 |
50 | // The staff line to be placed on
51 | this.line = note_struct.line || 0;
52 |
53 | // The height at the open end of the cresc/decresc
54 | this.height = 15;
55 |
56 | Vex.Merge(this.render_options, {
57 | // Extensions to the length of the crescendo on either side
58 | extend_left: 0,
59 | extend_right: 0,
60 | // Vertical shift
61 | y_shift: 0
62 | });
63 | },
64 |
65 | // Set the line to center the element on
66 | setLine: function(line) { this.line = line; return this; },
67 |
68 | // Set the full height at the open end
69 | setHeight: function(height) { this.height = height; return this; },
70 |
71 | // Set whether the sign should be a descresendo by passing a bool
72 | // to `decresc`
73 | setDecrescendo: function(decresc) {
74 | this.decrescendo = decresc;
75 | return this;
76 | },
77 |
78 | // Preformat the note
79 | preFormat: function() { this.preFormatted = true; return this; },
80 |
81 | // Render the Crescendo object onto the canvas
82 | draw: function() {
83 | if (!this.context) throw new Vex.RERR("NoContext",
84 | "Can't draw Hairpin without a context.");
85 |
86 | var tick_context = this.getTickContext();
87 | var next_context = Vex.Flow.TickContext.getNextContext(tick_context);
88 |
89 | var begin_x = this.getAbsoluteX();
90 | var end_x;
91 | if (next_context) {
92 | end_x = next_context.getX();
93 | } else {
94 | end_x = this.stave.x + this.stave.width;
95 | }
96 |
97 | var y = this.stave.getYForLine(this.line + (-3)) + 1;
98 |
99 | L("Drawing ", this.decrescendo ? "decrescendo " : "crescendo ",
100 | this.height, "x", begin_x - end_x);
101 |
102 | renderHairpin(this.context, {
103 | begin_x: begin_x - this.render_options.extend_left,
104 | end_x: end_x + this.render_options.extend_right,
105 | y: y + this.render_options.y_shift,
106 | height: this.height,
107 | reverse: this.decrescendo
108 | });
109 | }
110 | });
111 |
112 | return Crescendo;
113 | })();
--------------------------------------------------------------------------------
/src/curve.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // This class implements curves (for slurs)
5 |
6 | Vex.Flow.Curve = (function() {
7 | // from: Start note
8 | // to: End note
9 | // options:
10 | // cps: List of control points
11 | // x_shift: pixels to shift
12 | // y_shift: pixels to shift
13 | function Curve(from, to, options) {
14 | if (arguments.length > 0) this.init(from, to, options);
15 | }
16 |
17 | Curve.Position = {
18 | NEAR_HEAD: 1,
19 | NEAR_TOP: 2
20 | };
21 |
22 | Curve.DEBUG = true;
23 |
24 | Curve.prototype = {
25 | init: function(from, to, options) {
26 | this.render_options = {
27 | spacing: 2,
28 | thickness: 2,
29 | x_shift: 0,
30 | y_shift: 10,
31 | position: Curve.Position.NEAR_HEAD,
32 | invert: false,
33 | cps: [{x: 0, y: 10}, {x: 0, y: 10}]
34 | };
35 |
36 | Vex.Merge(this.render_options, options);
37 | this.setNotes(from, to);
38 | },
39 |
40 | setContext: function(context) { this.context = context; return this; },
41 | setNotes: function(from, to) {
42 | if (!from && !to)
43 | throw new Vex.RuntimeError("BadArguments",
44 | "Curve needs to have either first_note or last_note set.");
45 |
46 | this.from = from;
47 | this.to = to;
48 | return this;
49 | },
50 |
51 | /**
52 | * @return {boolean} Returns true if this is a partial bar.
53 | */
54 | isPartial: function() {
55 | return (!this.from || !this.to);
56 | },
57 |
58 | renderCurve: function(params) {
59 | var ctx = this.context;
60 | var cps = this.render_options.cps;
61 |
62 | var x_shift = this.render_options.x_shift;
63 | var y_shift = this.render_options.y_shift * params.direction;
64 |
65 | var first_x = params.first_x + x_shift;
66 | var first_y = params.first_y + y_shift;
67 | var last_x = params.last_x - x_shift;
68 | var last_y = params.last_y + y_shift;
69 | var thickness = this.render_options.thickness;
70 |
71 | var cp_spacing = (last_x - first_x) / (cps.length + 2);
72 |
73 | ctx.beginPath();
74 | ctx.moveTo(first_x, first_y);
75 | ctx.bezierCurveTo(first_x + cp_spacing + cps[0].x,
76 | first_y + (cps[0].y * params.direction),
77 | last_x - cp_spacing + cps[1].x,
78 | last_y + (cps[1].y * params.direction),
79 | last_x, last_y);
80 | ctx.bezierCurveTo(last_x - cp_spacing + cps[1].x,
81 | last_y + ((cps[1].y + thickness) * params.direction),
82 | first_x + cp_spacing + cps[0].x,
83 | first_y + ((cps[0].y + thickness) * params.direction),
84 | first_x, first_y);
85 | ctx.stroke();
86 | ctx.closePath();
87 | ctx.fill();
88 | },
89 |
90 | draw: function() {
91 | if (!this.context)
92 | throw new Vex.RERR("NoContext", "No context to render tie.");
93 | var first_note = this.from;
94 | var last_note = this.to;
95 | var first_x, last_x, first_y, last_y, stem_direction;
96 |
97 | var metric = "baseY";
98 | var end_metric = "baseY";
99 | var position = this.render_options.position;
100 | var position_end = this.render_options.position_end;
101 |
102 | if (position === Curve.Position.NEAR_TOP) {
103 | metric = "topY";
104 | end_metric = "topY";
105 | }
106 |
107 | if (position_end == Curve.Position.NEAR_HEAD) {
108 | end_metric = "baseY";
109 | } else if (position_end == Curve.Position.NEAR_TOP) {
110 | end_metric = "topY";
111 | }
112 |
113 | if (first_note) {
114 | first_x = first_note.getTieRightX();
115 | stem_direction = first_note.getStemDirection();
116 | first_y = first_note.getStemExtents()[metric];
117 | } else {
118 | first_x = last_note.getStave().getTieStartX();
119 | first_y = last_note.getStemExtents()[metric];
120 | }
121 |
122 | if (last_note) {
123 | last_x = last_note.getTieLeftX();
124 | stem_direction = last_note.getStemDirection();
125 | last_y = last_note.getStemExtents()[end_metric];
126 | } else {
127 | last_x = first_note.getStave().getTieEndX();
128 | last_y = first_note.getStemExtents()[end_metric];
129 | }
130 |
131 | this.renderCurve({
132 | first_x: first_x,
133 | last_x: last_x,
134 | first_y: first_y,
135 | last_y: last_y,
136 | direction: stem_direction *
137 | (this.render_options.invert === true ? -1 : 1)
138 | });
139 | return true;
140 | }
141 | };
142 |
143 | return Curve;
144 | }());
145 |
--------------------------------------------------------------------------------
/src/dot.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // This class implements dot modifiers for notes.
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.Dot = (function() {
10 | function Dot() {
11 | this.init();
12 | }
13 |
14 | var Modifier = Vex.Flow.Modifier;
15 | Vex.Inherit(Dot, Modifier, {
16 | init: function() {
17 | Dot.superclass.init.call(this);
18 |
19 | this.note = null;
20 | this.index = null;
21 | this.position = Modifier.Position.RIGHT;
22 |
23 | this.radius = 2;
24 | this.setWidth(5);
25 | this.dot_shiftY = 0;
26 | },
27 |
28 | setNote: function(note){
29 | this.note = note;
30 |
31 | if (this.note.getCategory() === 'gracenotes') {
32 | this.radius *= 0.50;
33 | this.setWidth(3);
34 | }
35 | },
36 |
37 | getCategory: function() { return "dots"; },
38 |
39 | setDotShiftY: function(y) { this.dot_shiftY = y; return this; },
40 |
41 | draw: function() {
42 | if (!this.context) throw new Vex.RERR("NoContext",
43 | "Can't draw dot without a context.");
44 | if (!(this.note && (this.index != null))) throw new Vex.RERR("NoAttachedNote",
45 | "Can't draw dot without a note and index.");
46 |
47 | var line_space = this.note.stave.options.spacing_between_lines_px;
48 |
49 | var start = this.note.getModifierStartXY(this.position, this.index);
50 |
51 | // Set the starting y coordinate to the base of the stem for TabNotes
52 | if (this.note.getCategory() === 'tabnotes') {
53 | start.y = this.note.getStemExtents().baseY;
54 | }
55 |
56 | var dot_x = (start.x + this.x_shift) + this.width - this.radius;
57 | var dot_y = start.y + this.y_shift + (this.dot_shiftY * line_space);
58 | var ctx = this.context;
59 |
60 | ctx.beginPath();
61 | ctx.arc(dot_x, dot_y, this.radius, 0, Math.PI * 2, false);
62 | ctx.fill();
63 | }
64 | });
65 |
66 | return Dot;
67 | }());
68 |
--------------------------------------------------------------------------------
/src/flow.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Vex Flow - Mohit Muthanna
3 | */
4 |
5 | /**
6 | * New namespace.
7 | */
8 | Vex.Flow = {
9 | /**
10 | * The resolution used for all the rhythm timing in this
11 | * library.
12 | *
13 | * @const
14 | * @type {number}
15 | */
16 | RESOLUTION: 16384,
17 |
18 | /* Kerning (DEPRECATED) */
19 | IsKerned: true
20 | };
21 |
--------------------------------------------------------------------------------
/src/frethandfinger.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | // Author Larry Kuhns 2013
4 | // Class to draws string numbers into the notation.
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.FretHandFinger = (function() {
10 | function FretHandFinger(number) {
11 | if (arguments.length > 0) this.init(number);
12 | }
13 |
14 | var Modifier = Vex.Flow.Modifier;
15 | Vex.Inherit(FretHandFinger, Modifier, {
16 | init: function(number) {
17 | var superclass = Vex.Flow.FretHandFinger.superclass;
18 | superclass.init.call(this);
19 |
20 | this.note = null;
21 | this.index = null;
22 | this.finger = number;
23 | this.width = 7;
24 | this.position = Modifier.Position.LEFT; // Default position above stem or note head
25 | this.x_shift = 0;
26 | this.y_shift = 0;
27 | this.x_offset = 0; // Horizontal offset from default
28 | this.y_offset = 0; // Vertical offset from default
29 | this.font = {
30 | family: "sans-serif",
31 | size: 9,
32 | weight: "bold"
33 | };
34 | },
35 |
36 | getCategory: function() { return "frethandfinger"; },
37 | getNote: function() { return this.note; },
38 | setNote: function(note) { this.note = note; return this; },
39 | getIndex: function() { return this.index; },
40 | setIndex: function(index) { this.index = index; return this; },
41 | getPosition: function() { return this.position; },
42 | setPosition: function(position) {
43 | if (position >= Modifier.Position.LEFT &&
44 | position <= Modifier.Position.BELOW)
45 | this.position = position;
46 | return this;
47 | },
48 | setFretHandFinger: function(number) { this.finger = number; return this; },
49 | setOffsetX: function(x) { this.x_offset = x; return this; },
50 | setOffsetY: function(y) { this.y_offset = y; return this; },
51 |
52 | draw: function() {
53 | if (!this.context) throw new Vex.RERR("NoContext",
54 | "Can't draw string number without a context.");
55 | if (!(this.note && (this.index != null))) throw new Vex.RERR("NoAttachedNote",
56 | "Can't draw string number without a note and index.");
57 |
58 | var ctx = this.context;
59 | var start = this.note.getModifierStartXY(this.position, this.index);
60 | var dot_x = (start.x + this.x_shift + this.x_offset);
61 | var dot_y = start.y + this.y_shift + this.y_offset + 5;
62 |
63 | switch (this.position) {
64 | case Modifier.Position.ABOVE:
65 | dot_x -= 4;
66 | dot_y -= 12;
67 | break;
68 | case Modifier.Position.BELOW:
69 | dot_x -= 2;
70 | dot_y += 10;
71 | break;
72 | case Modifier.Position.LEFT:
73 | dot_x -= this.width;
74 | break;
75 | case Modifier.Position.RIGHT:
76 | dot_x += 1;
77 | break;
78 | }
79 |
80 | ctx.save();
81 | ctx.setFont(this.font.family, this.font.size, this.font.weight);
82 | ctx.fillText("" + this.finger, dot_x, dot_y);
83 |
84 | ctx.restore();
85 | }
86 | });
87 |
88 | return FretHandFinger;
89 | }());
--------------------------------------------------------------------------------
/src/ghostnote.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Mohit Muthanna
3 | //
4 | // Copyright Mohit Muthanna 2010
5 | //
6 | // Requires vex.js.
7 |
8 | /** @constructor */
9 | Vex.Flow.GhostNote = (function() {
10 | function GhostNote(duration) {
11 | if (arguments.length > 0) this.init(duration);
12 | }
13 |
14 | Vex.Inherit(GhostNote, Vex.Flow.StemmableNote, {
15 | init: function(parameter) {
16 | // Sanity check
17 | if (!parameter) {
18 | throw new Vex.RuntimeError("BadArguments",
19 | "Ghost note must have valid initialization data to identify " +
20 | "duration.");
21 | }
22 |
23 | var note_struct;
24 |
25 | // Preserve backwards-compatibility
26 | if (typeof(parameter) === "string") {
27 | note_struct = { duration: parameter };
28 | } else if (typeof(parameter) === "object") {
29 | note_struct = parameter;
30 | } else {
31 | throw new Vex.RuntimeError("BadArguments",
32 | "Ghost note must have valid initialization data to identify " +
33 | "duration.");
34 | }
35 |
36 | GhostNote.superclass.init.call(this, note_struct);
37 |
38 | // Note properties
39 | this.setWidth(0);
40 | },
41 |
42 | isRest: function() { return true; },
43 |
44 | setStave: function(stave) { GhostNote.superclass.setStave.call(this, stave); },
45 |
46 | addToModifierContext: function()
47 | { /* intentionally overridden */ return this; },
48 |
49 | preFormat: function() {
50 | this.setPreFormatted(true);
51 | return this;
52 | },
53 |
54 | draw: function() {
55 | if (!this.stave) throw new Vex.RERR("NoStave", "Can't draw without a stave.");
56 |
57 | // Draw the modifiers
58 | for (var i = 0; i < this.modifiers.length; ++i) {
59 | var modifier = this.modifiers[i];
60 | modifier.setContext(this.context);
61 | modifier.draw();
62 | }
63 | }
64 | });
65 |
66 | return GhostNote;
67 | }());
68 |
--------------------------------------------------------------------------------
/src/glyphs.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Vex Glyphs
5 |
7 |
41 |
42 |
43 |
44 |
45 |
46 |
105 |
106 |
107 |
108 |
109 | Gonville Glyphs
110 |
111 | Cross indicates render coordinates.
112 |
113 |
114 |
117 |
118 |
119 | For more information visit 0xfe.blogspot.com.
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/src/gracenote.js:
--------------------------------------------------------------------------------
1 | Vex.Flow.GraceNote = (function() {
2 | var GraceNote = function(note_struct) {
3 | if (arguments.length > 0) this.init(note_struct);
4 | };
5 |
6 | Vex.Inherit(GraceNote, Vex.Flow.StaveNote, {
7 | init: function(note_struct) {
8 | GraceNote.superclass.init.call(this, note_struct);
9 |
10 | this.render_options.glyph_font_scale = 22;
11 | this.render_options.stem_height = 20;
12 | this.render_options.stroke_px = 2;
13 | this.glyph.head_width = 6;
14 |
15 | this.slash = note_struct.slash;
16 | this.slur = true;
17 |
18 | this.buildNoteHeads();
19 |
20 | this.width = 3;
21 | },
22 |
23 | getStemExtension: function(){
24 | var glyph = this.getGlyph();
25 |
26 | if (this.stem_extension_override != null) {
27 | return this.stem_extension_override;
28 | }
29 |
30 | if (glyph) {
31 | return this.getStemDirection() === 1 ? glyph.gracenote_stem_up_extension :
32 | glyph.gracenote_stem_down_extension;
33 | }
34 |
35 | return 0;
36 | },
37 |
38 | getCategory: function() { return 'gracenotes'; },
39 |
40 | draw: function(){
41 | GraceNote.superclass.draw.call(this);
42 | var ctx = this.context;
43 | var stem_direction = this.getStemDirection();
44 |
45 | if (this.slash) {
46 | ctx.beginPath();
47 |
48 | var x = this.getAbsoluteX();
49 | var y = this.getYs()[0] - (this.stem.getHeight() / 2.8);
50 | if (stem_direction === 1) {
51 | x += 1;
52 | ctx.lineTo(x, y);
53 | ctx.lineTo(x + 13, y - 9);
54 | } else if (stem_direction === -1) {
55 | x -= 4;
56 | y += 1;
57 | ctx.lineTo(x, y);
58 | ctx.lineTo(x + 13, y + 9);
59 | }
60 |
61 | ctx.closePath();
62 | ctx.stroke();
63 | }
64 | }
65 | });
66 |
67 | return GraceNote;
68 | }());
69 |
--------------------------------------------------------------------------------
/src/gracenotegroup.js:
--------------------------------------------------------------------------------
1 | Vex.Flow.GraceNoteGroup = (function(){
2 | var GraceNoteGroup = function(grace_notes, config) {
3 | if (arguments.length > 0) this.init(grace_notes, config);
4 | };
5 |
6 | Vex.Inherit(GraceNoteGroup, Vex.Flow.Modifier, {
7 | init: function(grace_notes, show_slur) {
8 | var superclass = GraceNoteGroup.superclass;
9 | superclass.init.call(this);
10 |
11 | this.note = null;
12 | this.index = null;
13 | this.position = Vex.Flow.Modifier.Position.LEFT;
14 | this.grace_notes = grace_notes;
15 | this.width = 0;
16 |
17 | this.preFormatted = false;
18 |
19 | this.show_slur = show_slur;
20 | this.slur = null;
21 |
22 | this.formatter = new Vex.Flow.Formatter();
23 | this.voice = new Vex.Flow.Voice({
24 | num_beats: 4,
25 | beat_value: 4,
26 | resolution: Vex.Flow.RESOLUTION
27 | }).setStrict(false);
28 |
29 | this.voice.addTickables(this.grace_notes);
30 |
31 | return this;
32 | },
33 |
34 | preFormat: function(){
35 | if (this.preFormatted) return;
36 |
37 | this.formatter.joinVoices([this.voice]).format([this.voice], 0);
38 | this.setWidth(this.formatter.getMinTotalWidth());
39 |
40 | this.preFormatted = true;
41 | },
42 |
43 | beamNotes: function(){
44 | if (this.grace_notes.length > 1) {
45 | var beam = new Vex.Flow.Beam(this.grace_notes);
46 |
47 | beam.render_options.beam_width = 3;
48 | beam.render_options.partial_beam_length = 4;
49 |
50 | this.beam = beam;
51 | }
52 |
53 | return this;
54 | },
55 |
56 | setNote: function(note) {
57 | this.note = note;
58 | },
59 | getCategory: function() { return "gracenotegroups"; },
60 | setWidth: function(width){
61 | this.width = width;
62 | },
63 | getWidth: function(){
64 | return this.width;
65 | },
66 | setXShift: function(x_shift) {
67 | this.x_shift = x_shift;
68 | },
69 | draw: function() {
70 | if (!this.context) {
71 | throw new Vex.RuntimeError("NoContext",
72 | "Can't draw Grace note without a context.");
73 | }
74 |
75 | var note = this.getNote();
76 |
77 | if (!(note && (this.index !== null))) {
78 | throw new Vex.RuntimeError("NoAttachedNote",
79 | "Can't draw grace note without a parent note and parent note index.");
80 | }
81 |
82 | function alignGraceNotesWithNote(grace_notes, note) {
83 | // Shift over the tick contexts of each note
84 | // So that th aligned with the note
85 | var tickContext = note.getTickContext();
86 | var extraPx = tickContext.getExtraPx();
87 | var x = tickContext.getX() - extraPx.left - extraPx.extraLeft;
88 | grace_notes.forEach(function(graceNote) {
89 | var tick_context = graceNote.getTickContext();
90 | var x_offset = tick_context.getX();
91 | graceNote.setStave(note.stave);
92 | tick_context.setX(x + x_offset);
93 | });
94 | }
95 |
96 | alignGraceNotesWithNote(this.grace_notes, note);
97 |
98 | // Draw notes
99 | this.grace_notes.forEach(function(graceNote) {
100 | graceNote.setContext(this.context).draw();
101 | }, this);
102 |
103 | // Draw beam
104 | if (this.beam) {
105 | this.beam.setContext(this.context).draw();
106 | }
107 |
108 | if (this.show_slur) {
109 | // Create and draw slur
110 | this.slur = new Vex.Flow.StaveTie({
111 | last_note: this.grace_notes[0],
112 | first_note: note,
113 | first_indices: [0],
114 | last_indices: [0]
115 | });
116 |
117 | this.slur.render_options.cp2 = 12;
118 | this.slur.setContext(this.context).draw();
119 | }
120 | }
121 | });
122 |
123 | return GraceNoteGroup;
124 | }());
--------------------------------------------------------------------------------
/src/header.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow Engraver <%= BUILD_VERSION %>
3 | * A library for rendering musical notation and guitar tablature in HTML5.
4 | *
5 | * http://www.vexflow.com
6 | *
7 | * Copyright (c) 2010 Mohit Muthanna Cheppudira
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | *
27 | * This library makes use of Simon Tatham's awesome font - Gonville.
28 | *
29 | * Build ID: <%= BUILD_PREFIX %>@<%= BUILD_COMMIT %>
30 | * Build date: <%= BUILD_DATE %>
31 | */
32 |
--------------------------------------------------------------------------------
/src/keymanager.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // This class implements diatonic key management.
5 | //
6 | // requires: vex.js (Vex)
7 | // requires: flow.js (Vex.Flow)
8 | // requires: music.js (Vex.Flow.Music)
9 |
10 | /**
11 | * @constructor
12 | */
13 | Vex.Flow.KeyManager = (function() {
14 | function KeyManager(key) {
15 | this.init(key);
16 | }
17 |
18 | KeyManager.scales = {
19 | "M": Vex.Flow.Music.scales.major,
20 | "m": Vex.Flow.Music.scales.minor
21 | };
22 |
23 | KeyManager.prototype = {
24 | init: function(key) {
25 | this.music = new Vex.Flow.Music();
26 | this.setKey(key);
27 | },
28 |
29 | setKey: function(key) {
30 | this.key = key;
31 | this.reset();
32 | return this;
33 | },
34 |
35 | getKey: function() { return this.key; },
36 |
37 | reset: function() {
38 | this.keyParts = this.music.getKeyParts(this.key);
39 |
40 | this.keyString = this.keyParts.root;
41 | if (this.keyParts.accidental) this.keyString += this.keyParts.accidental;
42 |
43 | var is_supported_type = KeyManager.scales[this.keyParts.type];
44 | if (!is_supported_type)
45 | throw new Vex.RERR("BadArguments", "Unsupported key type: " + this.key);
46 |
47 | this.scale = this.music.getScaleTones(
48 | this.music.getNoteValue(this.keyString),
49 | Vex.Flow.KeyManager.scales[this.keyParts.type]);
50 |
51 | this.scaleMap = {};
52 | this.scaleMapByValue = {};
53 | this.originalScaleMapByValue = {};
54 |
55 | var noteLocation = Vex.Flow.Music.root_indices[this.keyParts.root];
56 |
57 | for (var i = 0; i < Vex.Flow.Music.roots.length; ++i) {
58 | var index = (noteLocation + i) % Vex.Flow.Music.roots.length;
59 | var rootName = Vex.Flow.Music.roots[index];
60 |
61 | var noteName = this.music.getRelativeNoteName(rootName, this.scale[i]);
62 | this.scaleMap[rootName] = noteName;
63 | this.scaleMapByValue[this.scale[i]] = noteName;
64 | this.originalScaleMapByValue[this.scale[i]] = noteName;
65 | }
66 |
67 | return this;
68 | },
69 |
70 | getAccidental: function(key) {
71 | var root = this.music.getKeyParts(key).root;
72 | var parts = this.music.getNoteParts(this.scaleMap[root]);
73 |
74 | return {
75 | note: this.scaleMap[root],
76 | accidental: parts.accidental
77 | };
78 | },
79 |
80 | selectNote: function(note) {
81 | note = note.toLowerCase();
82 | var parts = this.music.getNoteParts(note);
83 |
84 | // First look for matching note in our altered scale
85 | var scaleNote = this.scaleMap[parts.root];
86 | var modparts = this.music.getNoteParts(scaleNote);
87 |
88 | if (scaleNote == note) return {
89 | "note": scaleNote,
90 | "accidental": parts.accidental,
91 | "change": false
92 | };
93 |
94 | // Then search for a note of equivalent value in our altered scale
95 | var valueNote = this.scaleMapByValue[this.music.getNoteValue(note)];
96 | if (valueNote != null) {
97 | return {
98 | "note": valueNote,
99 | "accidental": this.music.getNoteParts(valueNote).accidental,
100 | "change": false
101 | };
102 | }
103 |
104 | // Then search for a note of equivalent value in the original scale
105 | var originalValueNote = this.originalScaleMapByValue[
106 | this.music.getNoteValue(note)];
107 | if (originalValueNote != null) {
108 | this.scaleMap[modparts.root] = originalValueNote;
109 | delete this.scaleMapByValue[this.music.getNoteValue(scaleNote)];
110 | this.scaleMapByValue[this.music.getNoteValue(note)] = originalValueNote;
111 | return {
112 | "note": originalValueNote,
113 | "accidental": this.music.getNoteParts(originalValueNote).accidental,
114 | "change": true
115 | };
116 | }
117 |
118 | // Then try to unmodify a currently modified note.
119 | if (modparts.root == note) {
120 | delete this.scaleMapByValue[
121 | this.music.getNoteValue(this.scaleMap[parts.root])];
122 | this.scaleMapByValue[this.music.getNoteValue(modparts.root)] =
123 | modparts.root;
124 | this.scaleMap[modparts.root] = modparts.root;
125 | return {
126 | "note": modparts.root,
127 | "accidental": null,
128 | "change": true
129 | };
130 | }
131 |
132 | // Last resort -- shitshoot
133 | delete this.scaleMapByValue[
134 | this.music.getNoteValue(this.scaleMap[parts.root])];
135 | this.scaleMapByValue[this.music.getNoteValue(note)] = note;
136 |
137 | delete this.scaleMap[modparts.root];
138 | this.scaleMap[modparts.root] = note;
139 |
140 | return {
141 | "note": note,
142 | "accidental": parts.accidental,
143 | "change": true
144 | };
145 | }
146 | };
147 |
148 | return KeyManager;
149 | }());
150 |
--------------------------------------------------------------------------------
/src/keysignature.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Implements key signatures
3 | //
4 | // Requires vex.js.
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.KeySignature = (function() {
10 | function KeySignature(keySpec) {
11 | if (arguments.length > 0) this.init(keySpec);
12 | }
13 |
14 | Vex.Inherit(KeySignature, Vex.Flow.StaveModifier, {
15 | init: function(key_spec) {
16 | KeySignature.superclass.init();
17 |
18 | this.glyphFontScale = 38; // TODO(0xFE): Should this match StaveNote?
19 | this.accList = Vex.Flow.keySignature(key_spec);
20 | },
21 |
22 | addAccToStave: function(stave, acc) {
23 | var glyph = new Vex.Flow.Glyph(acc.glyphCode, this.glyphFontScale);
24 | this.placeGlyphOnLine(glyph, stave, acc.line);
25 | stave.addGlyph(glyph);
26 | },
27 |
28 | addModifier: function(stave) {
29 | this.convertAccLines(stave.clef, this.accList[0].glyphCode);
30 | for (var i = 0; i < this.accList.length; ++i) {
31 | this.addAccToStave(stave, this.accList[i]);
32 | }
33 | },
34 |
35 | addToStave: function(stave, firstGlyph) {
36 | if (this.accList.length === 0)
37 | return this;
38 |
39 | if (!firstGlyph) {
40 | stave.addGlyph(this.makeSpacer(this.padding));
41 | }
42 |
43 | this.addModifier(stave);
44 | return this;
45 | },
46 |
47 | convertAccLines: function(clef, code) {
48 | var offset = 0.0; // if clef === "treble"
49 | var tenorSharps;
50 | var isTenorSharps = ((clef === "tenor") && (code === "v18")) ? true : false;
51 |
52 | switch (clef) {
53 | case "bass":
54 | offset = 1;
55 | break;
56 | case "alto":
57 | offset = 0.5;
58 | break;
59 | case "tenor":
60 | if (!isTenorSharps) {
61 | offset = -0.5;
62 | }
63 | break;
64 | }
65 |
66 | // Special-case for TenorSharps
67 | var i;
68 | if (isTenorSharps) {
69 | tenorSharps = [3, 1, 2.5, 0.5, 2, 0, 1.5];
70 | for (i = 0; i < this.accList.length; ++i) {
71 | this.accList[i].line = tenorSharps[i];
72 | }
73 | }
74 | else {
75 | if (clef != "treble") {
76 | for (i = 0; i < this.accList.length; ++i) {
77 | this.accList[i].line += offset;
78 | }
79 | }
80 | }
81 | }
82 | });
83 |
84 | return KeySignature;
85 | }());
--------------------------------------------------------------------------------
/src/modifier.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
2 | //
3 | // ## Description
4 | //
5 | // `Modifier` is an abstract interface for notational elements that modify
6 | // a `Note`. Examples of modifiers are `Accidental`, `Annotation`, `Stroke`, etc.
7 | //
8 | // For a `Modifier` instance to be positioned correctly, it must be part of
9 | // a `ModifierContext`. All modifiers in the same context are rendered relative to
10 | // one another.
11 | //
12 | // Typically, all modifiers to a note are part of the same `ModifierContext` instance. Also,
13 | // in multi-voice staves, all modifiers to notes on the same `tick` are part of the same
14 | // `ModifierContext`. This ensures that multiple voices don't trample all over each other.
15 |
16 | Vex.Flow.Modifier = (function() {
17 | function Modifier() { this.init(); }
18 | // To enable logging for this class. Set `Vex.Flow.Modifier.DEBUG` to `true`.
19 | function L() { if (Modifier.DEBUG) Vex.L("Vex.Flow.Modifier", arguments); }
20 |
21 | // Modifiers can be positioned almost anywhere, relative to a note.
22 | Modifier.Position = {
23 | LEFT: 1,
24 | RIGHT: 2,
25 | ABOVE: 3,
26 | BELOW: 4
27 | };
28 |
29 | // ## Prototype Methods
30 | Modifier.prototype = {
31 |
32 | // The constructor sets initial widhts and constants.
33 | init: function() {
34 | this.width = 0;
35 | this.context = null;
36 |
37 | // Modifiers are attached to a note and an index. An index is a
38 | // specific head in a chord.
39 | this.note = null;
40 | this.index = null;
41 |
42 | // The `text_line` is reserved space above or below a stave.
43 | this.text_line = 0;
44 | this.position = Modifier.Position.LEFT;
45 | this.modifier_context = null;
46 | this.x_shift = 0;
47 | this.y_shift = 0;
48 | L("Created new modifier");
49 | },
50 |
51 | // Every modifier has a category. The `ModifierContext` uses this to determine
52 | // the type and order of the modifiers.
53 | getCategory: function() { return "none"; },
54 |
55 | // Get and set modifier widths.
56 | getWidth: function() { return this.width; },
57 | setWidth: function(width) { this.width = width; return this; },
58 |
59 | // Get and set attached note (`StaveNote`, `TabNote`, etc.)
60 | getNote: function() { return this.note; },
61 | setNote: function(note) { this.note = note; return this; },
62 |
63 | // Get and set note index, which is a specific note in a chord.
64 | getIndex: function() { return this.index; },
65 | setIndex: function(index) { this.index = index; return this; },
66 |
67 | // Get and set rendering context.
68 | getContext: function() { return this.context; },
69 | setContext: function(context) { this.context = context; return this; },
70 |
71 | // Every modifier must be part of a `ModifierContext`.
72 | getModifierContext: function() { return this.modifier_context; },
73 | setModifierContext: function(c) { this.modifier_context = c; return this; },
74 |
75 | // Get and set articulation position.
76 | getPosition: function() { return this.position; },
77 | setPosition: function(position) { this.position = position; return this; },
78 |
79 | // Set the `text_line` for the modifier.
80 | setTextLine: function(line) { this.text_line = line; return this; },
81 |
82 | // Shift modifier down `y` pixels. Negative values shift up.
83 | setYShift: function(y) { this.y_shift = y; return this; },
84 |
85 | // Shift modifier `x` pixels in the direction of the modifier. Negative values
86 | // shift reverse.
87 | setXShift: function(x) {
88 | this.x_shift = 0;
89 | if (this.position == Modifier.Position.LEFT) {
90 | this.x_shift -= x;
91 | } else {
92 | this.x_shift += x;
93 | }
94 | },
95 |
96 | // Render the modifier onto the canvas.
97 | draw: function() {
98 | if (!this.context) throw new Vex.RERR("NoCanvasContext",
99 | "Can't draw without a canvas context.");
100 | throw new Vex.RERR("MethodNotImplemented",
101 | "Draw() not implemented for this modifier.");
102 | }
103 | };
104 |
105 | return Modifier;
106 | }());
107 |
--------------------------------------------------------------------------------
/src/renderer.js:
--------------------------------------------------------------------------------
1 | // Vex Flow
2 | // Mohit Muthanna
3 | //
4 | // Support for different rendering contexts: Canvas, Raphael
5 | //
6 | // Copyright Mohit Cheppudira 2010
7 |
8 | /* global document: false */
9 |
10 | Vex.Flow.Renderer = (function() {
11 | function Renderer(sel, backend) {
12 | if (arguments.length > 0) this.init(sel, backend);
13 | }
14 |
15 | Renderer.Backends = {
16 | CANVAS: 1,
17 | RAPHAEL: 2,
18 | SVG: 3,
19 | VML: 4
20 | };
21 |
22 | //End of line types
23 | Renderer.LineEndType = {
24 | NONE: 1, // No leg
25 | UP: 2, // Upward leg
26 | DOWN: 3 // Downward leg
27 | };
28 |
29 | // Set this to true if you're using VexFlow inside a runtime
30 | // that does not allow modifiying canvas objects. There is a small
31 | // performance degradation due to the extra indirection.
32 | Renderer.USE_CANVAS_PROXY = false;
33 |
34 | Renderer.buildContext = function(sel,
35 | backend, width, height, background) {
36 | var renderer = new Renderer(sel, backend);
37 | if (width && height) { renderer.resize(width, height); }
38 |
39 | if (!background) background = "#eed";
40 | var ctx = renderer.getContext();
41 | ctx.setBackgroundFillStyle(background);
42 | return ctx;
43 | };
44 |
45 | Renderer.getCanvasContext = function(sel, width, height, background) {
46 | return Renderer.buildContext(sel, Renderer.Backends.CANVAS,
47 | width, height, background);
48 | };
49 |
50 | Renderer.getRaphaelContext = function(sel, width, height, background) {
51 | return Renderer.buildContext(sel, Renderer.Backends.RAPHAEL,
52 | width, height, background);
53 | };
54 |
55 | Renderer.bolsterCanvasContext = function(ctx) {
56 | if (Renderer.USE_CANVAS_PROXY) {
57 | return new Vex.Flow.CanvasContext(ctx);
58 | }
59 |
60 | var methods = ["clear", "setFont", "setRawFont", "setFillStyle", "setBackgroundFillStyle",
61 | "setStrokeStyle", "setShadowColor", "setShadowBlur", "setLineWidth",
62 | "setLineCap", "setLineDash"];
63 | ctx.vexFlowCanvasContext = ctx;
64 |
65 | for (var i in methods) {
66 | var method = methods[i];
67 | ctx[method] = Vex.Flow.CanvasContext.prototype[method];
68 | }
69 |
70 | return ctx;
71 | };
72 |
73 | //Draw a dashed line (horizontal, vertical or diagonal
74 | //dashPattern = [3,3] draws a 3 pixel dash followed by a three pixel space.
75 | //setting the second number to 0 draws a solid line.
76 | Renderer.drawDashedLine = function(context, fromX, fromY, toX, toY, dashPattern) {
77 | context.beginPath();
78 |
79 | var dx = toX - fromX;
80 | var dy = toY - fromY;
81 | var angle = Math.atan2(dy, dx);
82 | var x = fromX;
83 | var y = fromY;
84 | context.moveTo(fromX, fromY);
85 | var idx = 0;
86 | var draw = true;
87 | while (!((dx < 0 ? x <= toX : x >= toX) && (dy < 0 ? y <= toY : y >= toY))) {
88 | var dashLength = dashPattern[idx++ % dashPattern.length];
89 | var nx = x + (Math.cos(angle) * dashLength);
90 | x = dx < 0 ? Math.max(toX, nx) : Math.min(toX, nx);
91 | var ny = y + (Math.sin(angle) * dashLength);
92 | y = dy < 0 ? Math.max(toY, ny) : Math.min(toY, ny);
93 | if (draw) {
94 | context.lineTo(x, y);
95 | } else {
96 | context.moveTo(x, y);
97 | }
98 | draw = !draw;
99 | }
100 |
101 | context.closePath();
102 | context.stroke();
103 | };
104 |
105 | Renderer.prototype = {
106 | init: function(sel, backend) {
107 | // Verify selector
108 | this.sel = sel;
109 | if (!this.sel) throw new Vex.RERR("BadArgument",
110 | "Invalid selector for renderer.");
111 |
112 | // Get element from selector
113 | this.element = document.getElementById(sel);
114 | if (!this.element) this.element = sel;
115 |
116 | // Verify backend and create context
117 | this.ctx = null;
118 | this.paper = null;
119 | this.backend = backend;
120 | if (this.backend == Renderer.Backends.CANVAS) {
121 | // Create context.
122 | if (!this.element.getContext) throw new Vex.RERR("BadElement",
123 | "Can't get canvas context from element: " + sel);
124 | this.ctx = Renderer.bolsterCanvasContext(
125 | this.element.getContext('2d'));
126 | } else if (this.backend == Renderer.Backends.RAPHAEL) {
127 | this.ctx = new Vex.Flow.RaphaelContext(this.element);
128 | } else {
129 | throw new Vex.RERR("InvalidBackend",
130 | "No support for backend: " + this.backend);
131 | }
132 | },
133 |
134 | resize: function(width, height) {
135 | if (this.backend == Renderer.Backends.CANVAS) {
136 | if (!this.element.getContext) throw new Vex.RERR("BadElement",
137 | "Can't get canvas context from element: " + this.sel);
138 | this.element.width = width;
139 | this.element.height = height;
140 | this.ctx = Renderer.bolsterCanvasContext(
141 | this.element.getContext('2d'));
142 | } else {
143 | this.ctx.resize(width, height);
144 | }
145 |
146 | return this;
147 | },
148 |
149 | getContext: function() { return this.ctx; }
150 | };
151 |
152 | return Renderer;
153 | }());
154 |
155 |
156 |
--------------------------------------------------------------------------------
/src/stavebarline.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Author Larry Kuhns 2011
3 | // Implements barlines (single, double, repeat, end)
4 | //
5 | // Requires vex.js.
6 |
7 | /**
8 | * @constructor
9 | */
10 | Vex.Flow.Barline = (function() {
11 | function Barline(type, x) {
12 | if (arguments.length > 0) this.init(type, x);
13 | }
14 |
15 | Barline.type = {
16 | SINGLE: 1,
17 | DOUBLE: 2,
18 | END: 3,
19 | REPEAT_BEGIN: 4,
20 | REPEAT_END: 5,
21 | REPEAT_BOTH: 6,
22 | NONE: 7
23 | };
24 |
25 | var THICKNESS = Vex.Flow.STAVE_LINE_THICKNESS;
26 |
27 | Vex.Inherit(Barline, Vex.Flow.StaveModifier, {
28 | init: function(type, x) {
29 | Barline.superclass.init.call(this);
30 | this.barline = type;
31 | this.x = x; // Left most x for the stave
32 | },
33 |
34 | getCategory: function() { return "barlines"; },
35 | setX: function(x) { this.x = x; return this; },
36 |
37 | // Draw barlines
38 | draw: function(stave, x_shift) {
39 | x_shift = typeof x_shift !== 'number' ? 0 : x_shift;
40 |
41 | switch (this.barline) {
42 | case Barline.type.SINGLE:
43 | this.drawVerticalBar(stave, this.x, false);
44 | break;
45 | case Barline.type.DOUBLE:
46 | this.drawVerticalBar(stave, this.x, true);
47 | break;
48 | case Barline.type.END:
49 | this.drawVerticalEndBar(stave, this.x);
50 | break;
51 | case Barline.type.REPEAT_BEGIN:
52 | // If the barline is shifted over (in front of clef/time/key)
53 | // Draw vertical bar at the beginning.
54 | if (x_shift > 0) {
55 | this.drawVerticalBar(stave, this.x);
56 | }
57 | this.drawRepeatBar(stave, this.x + x_shift, true);
58 | break;
59 | case Barline.type.REPEAT_END:
60 | this.drawRepeatBar(stave, this.x, false);
61 | break;
62 | case Barline.type.REPEAT_BOTH:
63 | this.drawRepeatBar(stave, this.x, false);
64 | this.drawRepeatBar(stave, this.x, true);
65 | break;
66 | default:
67 | // Default is NONE, so nothing to draw
68 | break;
69 | }
70 | },
71 |
72 | drawVerticalBar: function(stave, x, double_bar) {
73 | if (!stave.context) throw new Vex.RERR("NoCanvasContext",
74 | "Can't draw stave without canvas context.");
75 | var top_line = stave.getYForLine(0);
76 | var bottom_line = stave.getYForLine(stave.options.num_lines - 1) + (THICKNESS / 2);
77 | if (double_bar)
78 | stave.context.fillRect(x - 3, top_line, 1, bottom_line - top_line + 1);
79 | stave.context.fillRect(x, top_line, 1, bottom_line - top_line + 1);
80 | },
81 |
82 | drawVerticalEndBar: function(stave, x) {
83 | if (!stave.context) throw new Vex.RERR("NoCanvasContext",
84 | "Can't draw stave without canvas context.");
85 |
86 | var top_line = stave.getYForLine(0);
87 | var bottom_line = stave.getYForLine(stave.options.num_lines - 1) + (THICKNESS / 2);
88 | stave.context.fillRect(x - 5, top_line, 1, bottom_line - top_line + 1);
89 | stave.context.fillRect(x - 2, top_line, 3, bottom_line - top_line + 1);
90 | },
91 |
92 | drawRepeatBar: function(stave, x, begin) {
93 | if (!stave.context) throw new Vex.RERR("NoCanvasContext",
94 | "Can't draw stave without canvas context.");
95 |
96 | var top_line = stave.getYForLine(0);
97 | var bottom_line = stave.getYForLine(stave.options.num_lines - 1) + (THICKNESS / 2);
98 | var x_shift = 3;
99 |
100 | if (!begin) {
101 | x_shift = -5;
102 | }
103 |
104 | stave.context.fillRect(x + x_shift, top_line, 1, bottom_line - top_line + 1);
105 | stave.context.fillRect(x - 2, top_line, 3, bottom_line - top_line + 1);
106 |
107 | var dot_radius = 2;
108 |
109 | // Shift dots left or right
110 | if (begin) {
111 | x_shift += 4;
112 | } else {
113 | x_shift -= 4;
114 | }
115 |
116 | var dot_x = (x + x_shift) + (dot_radius / 2);
117 |
118 | // calculate the y offset based on number of stave lines
119 | var y_offset = (stave.options.num_lines -1) *
120 | stave.options.spacing_between_lines_px;
121 | y_offset = (y_offset / 2) -
122 | (stave.options.spacing_between_lines_px / 2);
123 | var dot_y = top_line + y_offset + (dot_radius / 2);
124 |
125 | // draw the top repeat dot
126 | stave.context.beginPath();
127 | stave.context.arc(dot_x, dot_y, dot_radius, 0, Math.PI * 2, false);
128 | stave.context.fill();
129 |
130 | //draw the bottom repeat dot
131 | dot_y += stave.options.spacing_between_lines_px;
132 | stave.context.beginPath();
133 | stave.context.arc(dot_x, dot_y, dot_radius, 0, Math.PI * 2, false);
134 | stave.context.fill();
135 | }
136 | });
137 |
138 | return Barline;
139 | }());
140 |
--------------------------------------------------------------------------------
/src/stavemodifier.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | //
3 | // A base class for stave modifiers (e.g. clefs, key signatures)
4 | //
5 |
6 |
7 | /**
8 | * @constructor
9 | */
10 | Vex.Flow.StaveModifier = (function() {
11 | function StaveModifier() {
12 | this.init();
13 | }
14 |
15 | StaveModifier.prototype = {
16 | init: function() {
17 | this.padding = 10;
18 | },
19 |
20 | getCategory: function() {return "";},
21 | makeSpacer: function(padding) {
22 | return {
23 | getContext: function() {return true;},
24 | setStave: function() {},
25 | renderToStave: function() {},
26 | getMetrics: function() {
27 | return {width: padding};
28 | }
29 | };
30 | },
31 |
32 | placeGlyphOnLine: function(glyph, stave, line) {
33 | glyph.setYShift(stave.getYForLine(line) - stave.getYForGlyphs());
34 | },
35 |
36 | setPadding: function(padding) {
37 | this.padding = padding;
38 | },
39 |
40 | addToStave: function(stave, firstGlyph) {
41 | if (!firstGlyph) {
42 | stave.addGlyph(this.makeSpacer(this.padding));
43 | }
44 |
45 | this.addModifier(stave);
46 | return this;
47 | },
48 |
49 | addToStaveEnd: function(stave, firstGlyph) {
50 | if (!firstGlyph) {
51 | stave.addEndGlyph(this.makeSpacer(this.padding));
52 | }
53 | else {
54 | stave.addEndGlyph(this.makeSpacer(2));
55 | }
56 |
57 | this.addEndModifier(stave);
58 | return this;
59 | },
60 |
61 | addModifier: function() {
62 | throw new Vex.RERR("MethodNotImplemented",
63 | "addModifier() not implemented for this stave modifier.");
64 | },
65 |
66 | addEndModifier: function() {
67 | throw new Vex.RERR("MethodNotImplemented",
68 | "addEndModifier() not implemented for this stave modifier.");
69 | }
70 | };
71 |
72 | return StaveModifier;
73 | }());
74 |
75 |
--------------------------------------------------------------------------------
/src/staverepetition.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Author Larry Kuhns 2011
3 | // Implements Repetitions (Coda, signo, D.C., etc.)
4 | //
5 | // Requires vex.js.
6 |
7 | Vex.Flow.Repetition = (function() {
8 | function Repetition(type, x, y_shift) {
9 | if (arguments.length > 0) this.init(type, x, y_shift);
10 | }
11 |
12 | Repetition.type = {
13 | NONE: 1, // no coda or segno
14 | CODA_LEFT: 2, // coda at beginning of stave
15 | CODA_RIGHT: 3, // coda at end of stave
16 | SEGNO_LEFT: 4, // segno at beginning of stave
17 | SEGNO_RIGHT: 5, // segno at end of stave
18 | DC: 6, // D.C. at end of stave
19 | DC_AL_CODA: 7, // D.C. al coda at end of stave
20 | DC_AL_FINE: 8, // D.C. al Fine end of stave
21 | DS: 9, // D.S. at end of stave
22 | DS_AL_CODA: 10, // D.S. al coda at end of stave
23 | DS_AL_FINE: 11, // D.S. al Fine at end of stave
24 | FINE: 12 // Fine at end of stave
25 | };
26 |
27 | Vex.Inherit(Repetition, Vex.Flow.StaveModifier, {
28 | init: function(type, x, y_shift) {
29 | Repetition.superclass.init.call(this);
30 |
31 | this.symbol_type = type;
32 | this.x = x;
33 | this.x_shift = 0;
34 | this.y_shift = y_shift;
35 | this.font = {
36 | family: "times",
37 | size: 12,
38 | weight: "bold italic"
39 | };
40 | },
41 |
42 | getCategory: function() { return "repetitions"; },
43 | setShiftX: function(x) { this.x_shift = x; return this; },
44 | setShiftY: function(y) { this.y_shift = y; return this; },
45 |
46 | draw: function(stave, x) {
47 | switch (this.symbol_type) {
48 | case Repetition.type.CODA_RIGHT:
49 | this.drawCodaFixed(stave, x + stave.width);
50 | break;
51 | case Repetition.type.CODA_LEFT:
52 | this.drawSymbolText(stave, x, "Coda", true);
53 | break;
54 | case Repetition.type.SEGNO_LEFT:
55 | this.drawSignoFixed(stave, x);
56 | break;
57 | case Repetition.type.SEGNO_RIGHT:
58 | this.drawSignoFixed(stave, x + stave.width);
59 | break;
60 | case Repetition.type.DC:
61 | this.drawSymbolText(stave, x, "D.C.", false);
62 | break;
63 | case Repetition.type.DC_AL_CODA:
64 | this.drawSymbolText(stave, x, "D.C. al", true);
65 | break;
66 | case Repetition.type.DC_AL_FINE:
67 | this.drawSymbolText(stave, x, "D.C. al Fine", false);
68 | break;
69 | case Repetition.type.DS:
70 | this.drawSymbolText(stave, x, "D.S.", false);
71 | break;
72 | case Repetition.type.DS_AL_CODA:
73 | this.drawSymbolText(stave, x, "D.S. al", true);
74 | break;
75 | case Repetition.type.DS_AL_FINE:
76 | this.drawSymbolText(stave, x, "D.S. al Fine", false);
77 | break;
78 | case Repetition.type.FINE:
79 | this.drawSymbolText(stave, x, "Fine", false);
80 | break;
81 | default:
82 | break;
83 | }
84 |
85 | return this;
86 | },
87 |
88 | drawCodaFixed: function(stave, x) {
89 | if (!stave.context) throw new Vex.RERR("NoCanvasContext",
90 | "Can't draw stave without canvas context.");
91 |
92 | var y = stave.getYForTopText(stave.options.num_lines) + this.y_shift;
93 | Vex.Flow.renderGlyph(stave.context, this.x + x + this.x_shift,
94 | y + 25, 40, "v4d", true);
95 | return this;
96 | },
97 |
98 | drawSignoFixed: function(stave, x) {
99 | if (!stave.context) throw new Vex.RERR("NoCanvasContext",
100 | "Can't draw stave without canvas context.");
101 | var y = stave.getYForTopText(stave.options.num_lines) + this.y_shift;
102 | Vex.Flow.renderGlyph(stave.context, this.x + x + this.x_shift,
103 | y + 25, 30, "v8c", true);
104 | return this;
105 | },
106 |
107 | drawSymbolText: function(stave, x, text, draw_coda) {
108 | if (!stave.context) throw new Vex.RERR("NoCanvasContext",
109 | "Can't draw stave without canvas context.");
110 |
111 | var ctx = stave.context;
112 | ctx.save();
113 | ctx.setFont(this.font.family, this.font.size, this.font.weight);
114 | // Default to right symbol
115 | var text_x = 0 + this.x_shift;
116 | var symbol_x = x + this.x_shift;
117 | if (this.symbol_type == Vex.Flow.Repetition.type.CODA_LEFT) {
118 | // Offset Coda text to right of stave beginning
119 | text_x = this.x + stave.options.vertical_bar_width;
120 | symbol_x = text_x + ctx.measureText(text).width + 12;
121 | } else {
122 | // Offset Signo text to left stave end
123 | symbol_x = this.x + x + stave.width - 5 + this.x_shift;
124 | text_x = symbol_x - + ctx.measureText(text).width - 12;
125 | }
126 | var y = stave.getYForTopText(stave.options.num_lines) + this.y_shift;
127 | if (draw_coda) {
128 | Vex.Flow.renderGlyph(ctx, symbol_x, y, 40, "v4d", true);
129 | }
130 |
131 | ctx.fillText(text, text_x, y + 5);
132 | ctx.restore();
133 |
134 | return this;
135 | }
136 | });
137 |
138 | return Repetition;
139 | }());
--------------------------------------------------------------------------------
/src/stavesection.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | // Author Larry Kuhns 2011
4 | // Implements stave section names.
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.StaveSection = (function() {
10 | function StaveSection(section, x, shift_y) {
11 | if (arguments.length > 0) this.init(section, x, shift_y);
12 | }
13 |
14 | var Modifier = Vex.Flow.Modifier;
15 | Vex.Inherit(StaveSection, Modifier, {
16 | init: function(section, x, shift_y) {
17 | StaveSection.superclass.init.call(this);
18 |
19 | this.setWidth(16);
20 | this.section = section;
21 | this.position = Modifier.Position.ABOVE;
22 | this.x = x;
23 | this.shift_x = 0;
24 | this.shift_y = shift_y;
25 | this.font = {
26 | family: "sans-serif",
27 | size: 12,
28 | weight: "bold"
29 | };
30 | },
31 |
32 | getCategory: function() { return "stavesection"; },
33 | setStaveSection: function(section) { this.section = section; return this; },
34 | setShiftX: function(x) { this.shift_x = x; return this; },
35 | setShiftY: function(y) { this.shift_y = y; return this; },
36 |
37 | draw: function(stave, shift_x) {
38 | if (!stave.context) throw new Vex.RERR("NoContext",
39 | "Can't draw stave section without a context.");
40 |
41 | var ctx = stave.context;
42 |
43 | ctx.save();
44 | ctx.lineWidth = 2;
45 | ctx.setFont(this.font.family, this.font.size, this.font.weight);
46 | var text_width = ctx.measureText("" + this.section).width;
47 | var width = text_width + 6; // add left & right padding
48 | if (width < 18) width = 18;
49 | var height = 20;
50 | // Seems to be a good default y
51 | var y = stave.getYForTopText(3) + this.shift_y;
52 | var x = this.x + shift_x;
53 | ctx.beginPath();
54 | ctx.lineWidth = 2;
55 | ctx.rect(x, y, width, height);
56 | ctx.stroke();
57 | x += (width - text_width) / 2;
58 | ctx.fillText("" + this.section, x, y + 16);
59 | ctx.restore();
60 | return this;
61 | }
62 | });
63 |
64 | return StaveSection;
65 | }());
--------------------------------------------------------------------------------
/src/stavetempo.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | // Author Radosaw Eichler 2012
4 | // Implements tempo marker.
5 |
6 | /**
7 | * @constructor
8 | * @param {Object} tempo Tempo parameters: { name, duration, dots, bpm }
9 | */
10 | Vex.Flow.StaveTempo = (function() {
11 | function StaveTempo(tempo, x, shift_y) {
12 | if (arguments.length > 0) this.init(tempo, x, shift_y);
13 | }
14 |
15 | Vex.Inherit(StaveTempo, Vex.Flow.StaveModifier, {
16 | init: function(tempo, x, shift_y) {
17 | StaveTempo.superclass.init.call(this);
18 |
19 | this.tempo = tempo;
20 | this.position = Vex.Flow.Modifier.Position.ABOVE;
21 | this.x = x;
22 | this.shift_x = 10;
23 | this.shift_y = shift_y;
24 | this.font = {
25 | family: "times",
26 | size: 14,
27 | weight: "bold"
28 | };
29 | this.render_options = {
30 | glyph_font_scale: 30 // font size for note
31 | };
32 | },
33 |
34 | getCategory: function() { return "stavetempo"; },
35 | setTempo: function(tempo) { this.tempo = tempo; return this; },
36 | setShiftX: function(x) { this.shift_x = x; return this; },
37 | setShiftY: function(y) { this.shift_y = y; return this; },
38 |
39 | draw: function(stave, shift_x) {
40 | if (!stave.context) throw new Vex.RERR("NoContext",
41 | "Can't draw stave tempo without a context.");
42 |
43 | var options = this.render_options;
44 | var scale = options.glyph_font_scale / 38;
45 | var name = this.tempo.name;
46 | var duration = this.tempo.duration;
47 | var dots = this.tempo.dots;
48 | var bpm = this.tempo.bpm;
49 | var font = this.font;
50 | var ctx = stave.context;
51 | var x = this.x + this.shift_x + shift_x;
52 | var y = stave.getYForTopText(1) + this.shift_y;
53 |
54 | ctx.save();
55 |
56 | if (name) {
57 | ctx.setFont(font.family, font.size, font.weight);
58 | ctx.fillText(name, x, y);
59 | x += ctx.measureText(name).width;
60 | }
61 |
62 | if (duration && bpm) {
63 | ctx.setFont(font.family, font.size, 'normal');
64 |
65 | if (name) {
66 | x += ctx.measureText(" ").width;
67 | ctx.fillText("(", x, y);
68 | x += ctx.measureText("(").width;
69 | }
70 |
71 | var code = Vex.Flow.durationToGlyph(duration);
72 |
73 | x += 3 * scale;
74 | Vex.Flow.renderGlyph(ctx, x, y, options.glyph_font_scale, code.code_head);
75 | x += code.head_width * scale;
76 |
77 | // Draw stem and flags
78 | if (code.stem) {
79 | var stem_height = 30;
80 |
81 | if (code.beam_count) stem_height += 3 * (code.beam_count - 1);
82 |
83 | stem_height *= scale;
84 |
85 | var y_top = y - stem_height;
86 | ctx.fillRect(x, y_top, scale, stem_height);
87 |
88 | if (code.flag) {
89 | Vex.Flow.renderGlyph(ctx, x + scale, y_top, options.glyph_font_scale,
90 | code.code_flag_upstem);
91 |
92 | if (!dots) x += 6 * scale;
93 | }
94 | }
95 |
96 | // Draw dot
97 | for (var i = 0; i < dots; i++) {
98 | x += 6 * scale;
99 | ctx.beginPath();
100 | ctx.arc(x, y + 2 * scale, 2 * scale, 0, Math.PI * 2, false);
101 | ctx.fill();
102 | }
103 |
104 | ctx.fillText(" = " + bpm + (name ? ")" : ""), x + 3 * scale, y);
105 | }
106 |
107 | ctx.restore();
108 | return this;
109 | }
110 | });
111 |
112 | return StaveTempo;
113 | }());
114 |
--------------------------------------------------------------------------------
/src/stavetext.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // Author Taehoon Moon 2014
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.StaveText = (function() {
10 | function StaveText(text, position, options) {
11 | if (arguments.length > 0) this.init(text, position, options);
12 | }
13 |
14 | var Modifier = Vex.Flow.Modifier;
15 | Vex.Inherit(StaveText, Modifier, {
16 | init: function(text, position, options) {
17 | StaveText.superclass.init.call(this);
18 |
19 | this.setWidth(16);
20 | this.text = text;
21 | this.position = position;
22 | this.options = {
23 | shift_x: 0,
24 | shift_y: 0,
25 | justification: Vex.Flow.TextNote.Justification.CENTER
26 | };
27 | Vex.Merge(this.options, options);
28 |
29 | this.font = {
30 | family: "times",
31 | size: 16,
32 | weight: "normal"
33 | };
34 | },
35 |
36 | getCategory: function() { return "stavetext"; },
37 | setStaveText: function(text) { this.text = text; return this; },
38 | setShiftX: function(x) { this.shift_x = x; return this; },
39 | setShiftY: function(y) { this.shift_y = y; return this; },
40 |
41 | setFont: function(font) {
42 | Vex.Merge(this.font, font);
43 | },
44 |
45 | setText: function(text) {
46 | this.text = text;
47 | },
48 |
49 | draw: function(stave) {
50 | if (!stave.context) throw new Vex.RERR("NoContext",
51 | "Can't draw stave text without a context.");
52 |
53 | var ctx = stave.context;
54 |
55 | ctx.save();
56 | ctx.lineWidth = 2;
57 | ctx.setFont(this.font.family, this.font.size, this.font.weight);
58 | var text_width = ctx.measureText("" + this.text).width;
59 |
60 | var x, y;
61 | var Modifier = Vex.Flow.Modifier;
62 | switch(this.position) {
63 | case Modifier.Position.LEFT:
64 | case Modifier.Position.RIGHT:
65 | y = (stave.getYForLine(0) + stave.getBottomLineY()) / 2 + this.options.shift_y;
66 | if(this.position == Modifier.Position.LEFT) {
67 | x = stave.getX() - text_width - 24 + this.options.shift_x;
68 | }
69 | else {
70 | x = stave.getX() + stave.getWidth() + 24 + this.options.shift_x;
71 | }
72 | break;
73 | case Modifier.Position.ABOVE:
74 | case Modifier.Position.BELOW:
75 | var Justification = Vex.Flow.TextNote.Justification;
76 | x = stave.getX() + this.options.shift_x;
77 | if(this.options.justification == Justification.CENTER) {
78 | x += stave.getWidth() / 2 - text_width / 2;
79 | }
80 | else if(this.options.justification == Justification.RIGHT) {
81 | x += stave.getWidth() - text_width;
82 | }
83 |
84 | if(this.position == Modifier.Position.ABOVE) {
85 | y = stave.getYForTopText(2) + this.options.shift_y;
86 | }
87 | else {
88 | y = stave.getYForBottomText(2) + this.options.shift_y;
89 | }
90 | break;
91 | default:
92 | throw new Vex.RERR("InvalidPosition",
93 | "Value Must be in Modifier.Position.");
94 | }
95 |
96 | ctx.fillText("" + this.text, x, y + 4);
97 | ctx.restore();
98 | return this;
99 | }
100 | });
101 |
102 | return StaveText;
103 | }());
104 |
--------------------------------------------------------------------------------
/src/stavevolta.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Author Larry Kuhns 2011
3 | // Implements voltas (repeat brackets)
4 | //
5 | // Requires vex.js.
6 |
7 | Vex.Flow.Volta = (function() {
8 | function Volta(type, number, x, y_shift) {
9 | if (arguments.length > 0) this.init(type, number, x, y_shift);
10 | }
11 |
12 | Volta.type = {
13 | NONE: 1,
14 | BEGIN: 2,
15 | MID: 3,
16 | END: 4,
17 | BEGIN_END: 5
18 | };
19 |
20 | Vex.Inherit(Volta, Vex.Flow.StaveModifier, {
21 | init: function(type, number, x, y_shift) {
22 | Volta.superclass.init.call(this);
23 |
24 | this.volta = type;
25 | this.x = x;
26 | this.y_shift = y_shift;
27 | this.number = number;
28 | this.font = {
29 | family: "sans-serif",
30 | size: 9,
31 | weight: "bold"
32 | };
33 | },
34 |
35 | getCategory: function() { return "voltas"; },
36 | setShiftY: function(y) { this.y_shift = y; return this; },
37 |
38 | draw: function(stave, x) {
39 | if (!stave.context) throw new Vex.RERR("NoCanvasContext",
40 | "Can't draw stave without canvas context.");
41 | var ctx = stave.context;
42 | var width = stave.width;
43 | var top_y = stave.getYForTopText(stave.options.num_lines) + this.y_shift;
44 | var vert_height = 1.5 * stave.options.spacing_between_lines_px;
45 | switch(this.volta) {
46 | case Vex.Flow.Volta.type.BEGIN:
47 | ctx.fillRect(this.x + x, top_y, 1, vert_height);
48 | break;
49 | case Vex.Flow.Volta.type.END:
50 | width -= 5;
51 | ctx.fillRect(this.x + x + width, top_y, 1, vert_height);
52 | break;
53 | case Vex.Flow.Volta.type.BEGIN_END:
54 | width -= 3;
55 | ctx.fillRect(this.x + x, top_y, 1, vert_height);
56 | ctx.fillRect(this.x + x + width, top_y, 1, vert_height);
57 | break;
58 | }
59 | // If the beginning of a volta, draw measure number
60 | if (this.volta == Volta.type.BEGIN ||
61 | this.volta == Volta.type.BEGIN_END) {
62 | ctx.save();
63 | ctx.setFont(this.font.family, this.font.size, this.font.weight);
64 | ctx.fillText(this.number, this.x + x + 5, top_y + 15);
65 | ctx.restore();
66 | }
67 | ctx.fillRect(this.x + x, top_y, width, 1);
68 | return this;
69 | }
70 | });
71 |
72 | return Volta;
73 | }());
--------------------------------------------------------------------------------
/src/stem.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
2 | //
3 | // ## Description
4 | //
5 | // This file implements the `Stem` object. Generally this object is handled
6 | // by its parent `StemmableNote`.
7 | //
8 | Vex.Flow.Stem = (function() {
9 | var Stem = function(options) {
10 | if (arguments.length > 0) this.init(options);
11 | };
12 |
13 | // To enable logging for this class. Set `Vex.Flow.Stem.DEBUG` to `true`.
14 | function L() { if (Stem.DEBUG) Vex.L("Vex.Flow.Stem", arguments); }
15 |
16 | // Stem directions
17 | Stem.UP = 1;
18 | Stem.DOWN = -1;
19 |
20 | // Theme
21 | Stem.WIDTH = Vex.Flow.STEM_WIDTH;
22 | Stem.HEIGHT = Vex.Flow.STEM_HEIGHT;
23 |
24 | // ## Prototype Methods
25 | Stem.prototype = {
26 | init: function(options) {
27 | // Default notehead x bounds
28 | this.x_begin = options.x_begin || 0;
29 | this.x_end = options.x_end || 0;
30 |
31 | // Y bounds for top/bottom most notehead
32 | this.y_top = options.y_top || 0;
33 | this.y_bottom = options.y_bottom || 0;
34 |
35 | // Stem base extension
36 | this.y_extend = options.y_extend || 0;
37 | // Stem top extension
38 | this.stem_extension = options.stem_extension || 0;
39 |
40 | // Direction of the stem
41 | this.stem_direction = options.stem_direction || 0;
42 |
43 | // Flag to override all draw calls
44 | this.hide = false;
45 | },
46 |
47 | // Set the x bounds for the default notehead
48 | setNoteHeadXBounds: function(x_begin, x_end) {
49 | this.x_begin = x_begin;
50 | this.x_end = x_end;
51 | return this;
52 | },
53 |
54 | // Set the direction of the stem in relation to the noteheads
55 | setDirection: function(direction){ this.stem_direction = direction; },
56 |
57 | // Set the extension for the stem, generally for flags or beams
58 | setExtension: function(ext) { this.stem_extension = ext; },
59 |
60 | // The the y bounds for the top and bottom noteheads
61 | setYBounds: function(y_top, y_bottom) {
62 | this.y_top = y_top;
63 | this.y_bottom = y_bottom;
64 | },
65 |
66 | // The category of the object
67 | getCategory: function() { return "stem"; },
68 |
69 | // Set the canvas context to render on
70 | setContext: function(context) { this.context = context; return this;},
71 |
72 | // Gets the entire height for the stem
73 | getHeight: function() {
74 | return ((this.y_bottom - this.y_top) * this.stem_direction) +
75 | ((Stem.HEIGHT + this.stem_extension) * this.stem_direction);
76 | },
77 |
78 | getBoundingBox: function() {
79 | throw new Vex.RERR("NotImplemented", "getBoundingBox() not implemented.");
80 | },
81 |
82 | // Get the y coordinates for the very base of the stem to the top of
83 | // the extension
84 | getExtents: function() {
85 | var ys = [this.y_top, this.y_bottom];
86 |
87 | var top_pixel = this.y_top;
88 | var base_pixel = this.y_bottom;
89 | var stem_height = Stem.HEIGHT + this.stem_extension;
90 |
91 | for (var i = 0; i < ys.length; ++i) {
92 | var stem_top = ys[i] + (stem_height * -this.stem_direction);
93 |
94 | if (this.stem_direction == Stem.DOWN) {
95 | top_pixel = (top_pixel > stem_top) ? top_pixel : stem_top;
96 | base_pixel = (base_pixel < ys[i]) ? base_pixel : ys[i];
97 | } else {
98 | top_pixel = (top_pixel < stem_top) ? top_pixel : stem_top;
99 | base_pixel = (base_pixel > ys[i]) ? base_pixel : ys[i];
100 | }
101 | }
102 |
103 | return { topY: top_pixel, baseY: base_pixel };
104 | },
105 |
106 | // Render the stem onto the canvas
107 | draw: function() {
108 | if (!this.context) throw new Vex.RERR("NoCanvasContext",
109 | "Can't draw without a canvas context.");
110 |
111 | if (this.hide) return;
112 |
113 | var ctx = this.context;
114 | var stem_x, stem_y;
115 | var stem_direction = this.stem_direction;
116 |
117 | if (stem_direction == Stem.DOWN) {
118 | // Down stems are rendered to the left of the head.
119 | stem_x = this.x_begin + (Stem.WIDTH / 2);
120 | stem_y = this.y_top + 2;
121 | } else {
122 | // Up stems are rendered to the right of the head.
123 | stem_x = this.x_end + (Stem.WIDTH / 2);
124 | stem_y = this.y_bottom - 2;
125 | }
126 |
127 | stem_y += this.y_extend * stem_direction;
128 |
129 | L("Rendering stem - ", "Top Y: ", this.y_top, "Bottom Y: ", this.y_bottom);
130 |
131 | // Draw the stem
132 | ctx.beginPath();
133 | ctx.setLineWidth(Stem.WIDTH);
134 | ctx.moveTo(stem_x, stem_y);
135 | ctx.lineTo(stem_x, stem_y - this.getHeight());
136 | ctx.stroke();
137 | ctx.setLineWidth(1);
138 | }
139 | };
140 |
141 | return Stem;
142 | }());
143 |
--------------------------------------------------------------------------------
/src/tabslide.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // This class implements varies types of ties between contiguous notes. The
5 | // ties include: regular ties, hammer ons, pull offs, and slides.
6 |
7 | /**
8 | * Create a new tie from the specified notes. The notes must
9 | * be part of the same line, and have the same duration (in ticks).
10 | *
11 | * @constructor
12 | * @param {!Object} context The canvas context.
13 | * @param {!Object} notes The notes to tie up.
14 | * @param {!Object} Options
15 | */
16 | Vex.Flow.TabSlide = (function() {
17 | function TabSlide(notes, direction) {
18 | if (arguments.length > 0) this.init(notes, direction);
19 | }
20 |
21 | TabSlide.SLIDE_UP = 1;
22 | TabSlide.SLIDE_DOWN = -1;
23 |
24 | TabSlide.createSlideUp = function(notes) {
25 | return new TabSlide(notes, TabSlide.SLIDE_UP);
26 | };
27 |
28 | TabSlide.createSlideDown = function(notes) {
29 | return new TabSlide(notes, TabSlide.SLIDE_DOWN);
30 | };
31 |
32 | Vex.Inherit(TabSlide, Vex.Flow.TabTie, {
33 | init: function(notes, direction) {
34 | /**
35 | * Notes is a struct that has:
36 | *
37 | * {
38 | * first_note: Note,
39 | * last_note: Note,
40 | * first_indices: [n1, n2, n3],
41 | * last_indices: [n1, n2, n3]
42 | * }
43 | *
44 | **/
45 | TabSlide.superclass.init.call(this, notes, "sl.");
46 | if (!direction) {
47 | var first_fret = notes.first_note.getPositions()[0].fret;
48 | var last_fret = notes.last_note.getPositions()[0].fret;
49 |
50 | direction = ((parseInt(first_fret, 10) > parseInt(last_fret, 10)) ?
51 | TabSlide.SLIDE_DOWN : TabSlide.SLIDE_UP);
52 | }
53 |
54 | this.slide_direction = direction;
55 | this.render_options.cp1 = 11;
56 | this.render_options.cp2 = 14;
57 | this.render_options.y_shift = 0.5;
58 |
59 | this.setFont({font: "Times", size: 10, style: "bold italic"});
60 | this.setNotes(notes);
61 | },
62 |
63 | renderTie: function(params) {
64 | if (params.first_ys.length === 0 || params.last_ys.length === 0)
65 | throw new Vex.RERR("BadArguments", "No Y-values to render");
66 |
67 | var ctx = this.context;
68 | var first_x_px = params.first_x_px;
69 | var first_ys = params.first_ys;
70 | var last_x_px = params.last_x_px;
71 |
72 | var direction = this.slide_direction;
73 | if (direction != TabSlide.SLIDE_UP &&
74 | direction != TabSlide.SLIDE_DOWN) {
75 | throw new Vex.RERR("BadSlide", "Invalid slide direction");
76 | }
77 |
78 | for (var i = 0; i < this.first_indices.length; ++i) {
79 | var slide_y = first_ys[this.first_indices[i]] +
80 | this.render_options.y_shift;
81 |
82 | if (isNaN(slide_y))
83 | throw new Vex.RERR("BadArguments", "Bad indices for slide rendering.");
84 |
85 | ctx.beginPath();
86 | ctx.moveTo(first_x_px, slide_y + (3 * direction));
87 | ctx.lineTo(last_x_px, slide_y - (3 * direction));
88 | ctx.closePath();
89 | ctx.stroke();
90 | }
91 | }
92 | });
93 |
94 | return TabSlide;
95 | }());
--------------------------------------------------------------------------------
/src/tabstave.js:
--------------------------------------------------------------------------------
1 | // Vex Flow
2 | // Mohit Muthanna
3 | //
4 | // Copyright Mohit Cheppudira 2010
5 |
6 | /** @constructor */
7 | Vex.Flow.TabStave = (function() {
8 | function TabStave(x, y, width, options) {
9 | if (arguments.length > 0) this.init(x, y, width, options);
10 | }
11 |
12 | Vex.Inherit(TabStave, Vex.Flow.Stave, {
13 | init: function(x, y, width, options) {
14 | var tab_options = {
15 | spacing_between_lines_px: 13,
16 | num_lines: 6,
17 | top_text_position: 1
18 | };
19 |
20 | Vex.Merge(tab_options, options);
21 | TabStave.superclass.init.call(this, x, y, width, tab_options);
22 | },
23 |
24 | getYForGlyphs: function() {
25 | return this.getYForLine(2.5);
26 | },
27 |
28 | addTabGlyph: function() {
29 | var glyphScale;
30 | var glyphOffset;
31 |
32 | switch(this.options.num_lines) {
33 | case 8:
34 | glyphScale = 55;
35 | glyphOffset = 14;
36 | break;
37 | case 7:
38 | glyphScale = 47;
39 | glyphOffset = 8;
40 | break;
41 | case 6:
42 | glyphScale = 40;
43 | glyphOffset = 1;
44 | break;
45 | case 5:
46 | glyphScale = 30;
47 | glyphOffset = -6;
48 | break;
49 | case 4:
50 | glyphScale = 23;
51 | glyphOffset = -12;
52 | break;
53 | }
54 |
55 | var tabGlyph = new Vex.Flow.Glyph("v2f", glyphScale);
56 | tabGlyph.y_shift = glyphOffset;
57 | this.addGlyph(tabGlyph);
58 | return this;
59 | }
60 | });
61 |
62 | return TabStave;
63 | }());
--------------------------------------------------------------------------------
/src/tabtie.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // This class implements varies types of ties between contiguous notes. The
5 | // ties include: regular ties, hammer ons, pull offs, and slides.
6 |
7 | /**
8 | * Create a new tie from the specified notes. The notes must
9 | * be part of the same line, and have the same duration (in ticks).
10 | *
11 | * @constructor
12 | * @param {!Object} context The canvas context.
13 | * @param {!Object} notes The notes to tie up.
14 | * @param {!Object} Options
15 | */
16 | Vex.Flow.TabTie = (function() {
17 | function TabTie(notes, text) {
18 | if (arguments.length > 0) this.init(notes, text);
19 | }
20 |
21 | TabTie.createHammeron = function(notes) {
22 | return new TabTie(notes, "H");
23 | };
24 |
25 | TabTie.createPulloff = function(notes) {
26 | return new TabTie(notes, "P");
27 | };
28 |
29 | Vex.Inherit(TabTie, Vex.Flow.StaveTie, {
30 | init: function(notes, text) {
31 | /**
32 | * Notes is a struct that has:
33 | *
34 | * {
35 | * first_note: Note,
36 | * last_note: Note,
37 | * first_indices: [n1, n2, n3],
38 | * last_indices: [n1, n2, n3]
39 | * }
40 | *
41 | **/
42 | TabTie.superclass.init.call(this, notes, text);
43 | this.render_options.cp1 = 9;
44 | this.render_options.cp2 = 11;
45 | this.render_options.y_shift = 3;
46 |
47 | this.setNotes(notes);
48 | },
49 |
50 | draw: function() {
51 | if (!this.context)
52 | throw new Vex.RERR("NoContext", "No context to render tie.");
53 | var first_note = this.first_note;
54 | var last_note = this.last_note;
55 | var first_x_px, last_x_px, first_ys, last_ys;
56 |
57 | if (first_note) {
58 | first_x_px = first_note.getTieRightX() + this.render_options.tie_spacing;
59 | first_ys = first_note.getYs();
60 | } else {
61 | first_x_px = last_note.getStave().getTieStartX();
62 | first_ys = last_note.getYs();
63 | this.first_indices = this.last_indices;
64 | }
65 |
66 | if (last_note) {
67 | last_x_px = last_note.getTieLeftX() + this.render_options.tie_spacing;
68 | last_ys = last_note.getYs();
69 | } else {
70 | last_x_px = first_note.getStave().getTieEndX();
71 | last_ys = first_note.getYs();
72 | this.last_indices = this.first_indices;
73 | }
74 |
75 | this.renderTie({
76 | first_x_px: first_x_px,
77 | last_x_px: last_x_px,
78 | first_ys: first_ys,
79 | last_ys: last_ys,
80 | direction: -1 // Tab tie's are always face up.
81 | });
82 |
83 | this.renderText(first_x_px, last_x_px);
84 | return true;
85 | }
86 | });
87 |
88 | return TabTie;
89 | }());
90 |
--------------------------------------------------------------------------------
/src/tickable.js:
--------------------------------------------------------------------------------
1 | // Vex Flow
2 | // Copyright Mohit Cheppudira
3 | //
4 | // The tickable interface. Tickables are things that sit on a score and
5 | // have a duration, i.e., they occupy space in the musical rendering dimension.
6 |
7 | /** @constructor */
8 | Vex.Flow.Tickable = (function() {
9 | function Tickable() {
10 | this.init();
11 | }
12 |
13 | Tickable.prototype = {
14 | init: function() {
15 | this.intrinsicTicks = 0;
16 | this.tickMultiplier = new Vex.Flow.Fraction(1, 1);
17 | this.ticks = new Vex.Flow.Fraction(0, 1);
18 | this.width = 0;
19 | this.x_shift = 0; // Shift from tick context
20 | this.voice = null;
21 | this.tickContext = null;
22 | this.modifierContext = null;
23 | this.modifiers = [];
24 | this.preFormatted = false;
25 | this.postFormatted = false;
26 | this.tuplet = null;
27 |
28 | // This flag tells the formatter to ignore this tickable during
29 | // formatting and justification. It is set by tickables such as BarNote.
30 | this.ignore_ticks = false;
31 | this.context = null;
32 | },
33 |
34 | setContext: function(context) { this.context = context; },
35 | getBoundingBox: function() { return null; },
36 | getTicks: function() { return this.ticks; },
37 | shouldIgnoreTicks: function() { return this.ignore_ticks; },
38 | getWidth: function() { return this.width; },
39 | setXShift: function(x) { this.x_shift = x; },
40 |
41 | // Every tickable must be associated with a voice. This allows formatters
42 | // and preFormatter to associate them with the right modifierContexts.
43 | getVoice: function() {
44 | if (!this.voice) throw new Vex.RERR("NoVoice", "Tickable has no voice.");
45 | return this.voice;
46 | },
47 | setVoice: function(voice) { this.voice = voice; },
48 |
49 | getTuplet: function() { return this.tuplet; },
50 | setTuplet: function(tuplet) {
51 | // Detach from previous tuplet
52 | var noteCount, beatsOccupied;
53 |
54 | if (this.tuplet) {
55 | noteCount = this.tuplet.getNoteCount();
56 | beatsOccupied = this.tuplet.getBeatsOccupied();
57 |
58 | // Revert old multiplier
59 | this.applyTickMultiplier(noteCount, beatsOccupied);
60 | }
61 |
62 | // Attach to new tuplet
63 | if (tuplet) {
64 | noteCount = tuplet.getNoteCount();
65 | beatsOccupied = tuplet.getBeatsOccupied();
66 |
67 | this.applyTickMultiplier(beatsOccupied, noteCount);
68 | }
69 |
70 | this.tuplet = tuplet;
71 |
72 | return this;
73 | },
74 |
75 | /** optional, if tickable has modifiers **/
76 | addToModifierContext: function(mc) {
77 | this.modifierContext = mc;
78 | // Add modifiers to modifier context (if any)
79 | this.preFormatted = false;
80 | },
81 |
82 | /** optional, if tickable has modifiers **/
83 | addModifier: function(mod) {
84 | this.modifiers.push(mod);
85 | this.preFormatted = false;
86 | return this;
87 | },
88 |
89 | setTickContext: function(tc) {
90 | this.tickContext = tc;
91 | this.preFormatted = false;
92 | },
93 |
94 | preFormat: function() {
95 | if (this.preFormatted) return;
96 |
97 | this.width = 0;
98 | if (this.modifierContext) {
99 | this.modifierContext.preFormat();
100 | this.width += this.modifierContext.getWidth();
101 | }
102 | },
103 |
104 | postFormat: function() {
105 | if (this.postFormatted) return;
106 | this.postFormatted = true;
107 | return this;
108 | },
109 |
110 | getIntrinsicTicks: function() {
111 | return this.intrinsicTicks;
112 | },
113 | setIntrinsicTicks: function(intrinsicTicks) {
114 | this.intrinsicTicks = intrinsicTicks;
115 | this.ticks = this.tickMultiplier.clone().multiply(this.intrinsicTicks);
116 | },
117 |
118 | getTickMultiplier: function() {
119 | return this.tickMultiplier;
120 | },
121 | applyTickMultiplier: function(numerator, denominator) {
122 | this.tickMultiplier.multiply(numerator, denominator);
123 | this.ticks = this.tickMultiplier.clone().multiply(this.intrinsicTicks);
124 | }
125 | };
126 |
127 | return Tickable;
128 | }());
129 |
--------------------------------------------------------------------------------
/src/tickcontext.js:
--------------------------------------------------------------------------------
1 | // Vex Flow
2 | // Copyright Mohit Cheppudira
3 | //
4 | // A formatter for abstract tickable objects, such as notes, chords,
5 | // tabs, etc.
6 |
7 | /** @constructor */
8 | Vex.Flow.TickContext = (function() {
9 | function TickContext() {
10 | this.init();
11 | }
12 |
13 | TickContext.prototype = {
14 | init: function() {
15 | this.currentTick = new Vex.Flow.Fraction(0, 1);
16 | this.maxTicks = new Vex.Flow.Fraction(0, 1);
17 | this.minTicks = null;
18 | this.width = 0;
19 | this.padding = 3; // padding on each side (width += padding * 2)
20 | this.pixelsUsed = 0;
21 | this.x = 0;
22 | this.tickables = []; // Notes, tabs, chords, lyrics.
23 | this.notePx = 0; // width of widest note in this context
24 | this.extraLeftPx = 0; // Extra left pixels for modifers & displace notes
25 | this.extraRightPx = 0; // Extra right pixels for modifers & displace notes
26 |
27 | this.tContexts = []; // Parent array of tick contexts
28 |
29 | // Ignore this tick context for formatting and justification
30 | this.ignore_ticks = true;
31 | this.preFormatted = false;
32 | this.postFormatted = false;
33 | this.context = null; // Rendering context
34 | },
35 |
36 | setContext: function(context) { this.context = context; return this; },
37 | getContext: function() { return this.context; },
38 | shouldIgnoreTicks: function() { return this.ignore_ticks; },
39 | getWidth: function() { return this.width + (this.padding * 2); },
40 | getX: function() { return this.x; },
41 | setX: function(x) { this.x = x; return this; },
42 | getPixelsUsed: function() { return this.pixelsUsed; },
43 | setPixelsUsed: function(pixelsUsed) { this.pixelsUsed = pixelsUsed; return this; },
44 | setPadding: function(padding) { this.padding = padding; return this; },
45 | getMaxTicks: function() { return this.maxTicks; },
46 | getMinTicks: function() { return this.minTicks; },
47 | getTickables: function() { return this.tickables; },
48 |
49 | // Get widths context, note and left/right modifiers for formatting
50 | getMetrics: function() {
51 | return { width: this.width, notePx: this.notePx,
52 | extraLeftPx: this.extraLeftPx, extraRightPx: this.extraRightPx };
53 | },
54 |
55 | getCurrentTick: function() { return this.currentTick; },
56 | setCurrentTick: function(tick) {
57 | this.currentTick = tick;
58 | this.preFormatted = false;
59 | },
60 |
61 | // Get left & right pixels used for modifiers
62 | getExtraPx: function() {
63 | var left_shift = 0;
64 | var right_shift = 0;
65 | var extraLeftPx = 0;
66 | var extraRightPx = 0;
67 | for (var i = 0; i < this.tickables.length; i++) {
68 | extraLeftPx = Math.max(this.tickables[i].extraLeftPx, extraLeftPx);
69 | extraRightPx = Math.max(this.tickables[i].extraRightPx, extraRightPx);
70 | var mContext = this.tickables[i].modifierContext;
71 | if (mContext && mContext != null) {
72 | left_shift = Math.max( left_shift, mContext.state.left_shift);
73 | right_shift = Math.max( right_shift, mContext.state.right_shift);
74 | }
75 | }
76 | return { left: left_shift, right: right_shift,
77 | extraLeft: extraLeftPx, extraRight: extraRightPx };
78 | },
79 |
80 | addTickable: function(tickable) {
81 | if (!tickable) {
82 | throw new Vex.RERR("BadArgument", "Invalid tickable added.");
83 | }
84 |
85 | if (!tickable.shouldIgnoreTicks()) {
86 | this.ignore_ticks = false;
87 |
88 | var ticks = tickable.getTicks();
89 |
90 | if (ticks.value() > this.maxTicks.value()) {
91 | this.maxTicks = ticks.clone();
92 | }
93 |
94 | if (this.minTicks == null) {
95 | this.minTicks = ticks.clone();
96 | } else if (ticks.value() < this.minTicks.value()) {
97 | this.minTicks = ticks.clone();
98 | }
99 | }
100 |
101 | tickable.setTickContext(this);
102 | this.tickables.push(tickable);
103 | this.preFormatted = false;
104 | return this;
105 | },
106 |
107 | preFormat: function() {
108 | if (this.preFormatted) return;
109 |
110 | for (var i = 0; i < this.tickables.length; ++i) {
111 | var tickable = this.tickables[i];
112 | tickable.preFormat();
113 | var metrics = tickable.getMetrics();
114 |
115 | // Maintain max extra pixels from all tickables in the context
116 | this.extraLeftPx = Math.max(this.extraLeftPx,
117 | metrics.extraLeftPx + metrics.modLeftPx);
118 | this.extraRightPx = Math.max(this.extraRightPx,
119 | metrics.extraRightPx + metrics.modRightPx);
120 |
121 | // Maintain the widest note for all tickables in the context
122 | this.notePx = Math.max(this.notePx, metrics.noteWidth);
123 |
124 | // Recalculate the tick context total width
125 | this.width = this.notePx +
126 | this.extraLeftPx +
127 | this.extraRightPx;
128 | }
129 |
130 | return this;
131 | },
132 |
133 | postFormat: function() {
134 | if (this.postFormatted) return this;
135 | this.postFormatted = true;
136 | return this;
137 | }
138 | };
139 |
140 | TickContext.getNextContext = function(tContext) {
141 | var contexts = tContext.tContexts;
142 | var index = contexts.indexOf(tContext);
143 |
144 | return contexts[index+1];
145 | };
146 |
147 | return TickContext;
148 | }());
149 |
--------------------------------------------------------------------------------
/src/timesignature.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Implements time signatures glyphs for staffs
3 | // See tables.js for the internal time signatures
4 | // representation
5 | //
6 |
7 | /**
8 | * @param {string} timeSpec time signature, i.e. "4/4"
9 | * @param {number} [customPadding] custom padding when using multi-stave/multi-instrument setting
10 | * to align key/time signature (in pixels), optional
11 | * @constructor
12 | */
13 | Vex.Flow.TimeSignature = (function() {
14 | function TimeSignature(timeSpec, customPadding) {
15 | if (arguments.length > 0) this.init(timeSpec, customPadding);
16 | }
17 |
18 | TimeSignature.glyphs = {
19 | "C": {
20 | code: "v41",
21 | point: 40,
22 | line: 2
23 | },
24 | "C|": {
25 | code: "vb6",
26 | point: 40,
27 | line: 2
28 | }
29 | };
30 |
31 | Vex.Inherit(TimeSignature, Vex.Flow.StaveModifier, {
32 | init: function(timeSpec, customPadding) {
33 | TimeSignature.superclass.init();
34 | var padding = customPadding || 15;
35 |
36 | this.setPadding(padding);
37 | this.point = 40;
38 | this.topLine = 2;
39 | this.bottomLine = 4;
40 | this.timeSig = this.parseTimeSpec(timeSpec);
41 | },
42 |
43 | parseTimeSpec: function(timeSpec) {
44 | if (timeSpec == "C" || timeSpec == "C|") {
45 | var glyphInfo = TimeSignature.glyphs[timeSpec];
46 | return {num: false, line: glyphInfo.line,
47 | glyph: new Vex.Flow.Glyph(glyphInfo.code, glyphInfo.point)};
48 | }
49 |
50 | var topNums = [];
51 | var i, c;
52 | for (i = 0; i < timeSpec.length; ++i) {
53 | c = timeSpec.charAt(i);
54 | if (c == "/") {
55 | break;
56 | }
57 | else if (/[0-9]/.test(c)) {
58 | topNums.push(c);
59 | }
60 | else {
61 | throw new Vex.RERR("BadTimeSignature",
62 | "Invalid time spec: " + timeSpec);
63 | }
64 | }
65 |
66 | if (i === 0) {
67 | throw new Vex.RERR("BadTimeSignature",
68 | "Invalid time spec: " + timeSpec);
69 | }
70 |
71 | // skip the "/"
72 | ++i;
73 |
74 | if (i == timeSpec.length) {
75 | throw new Vex.RERR("BadTimeSignature",
76 | "Invalid time spec: " + timeSpec);
77 | }
78 |
79 |
80 | var botNums = [];
81 | for (; i < timeSpec.length; ++i) {
82 | c = timeSpec.charAt(i);
83 | if (/[0-9]/.test(c)) {
84 | botNums.push(c);
85 | }
86 | else {
87 | throw new Vex.RERR("BadTimeSignature",
88 | "Invalid time spec: " + timeSpec);
89 | }
90 | }
91 |
92 |
93 | return {num: true, glyph: this.makeTimeSignatureGlyph(topNums, botNums)};
94 | },
95 |
96 | makeTimeSignatureGlyph: function(topNums, botNums) {
97 | var glyph = new Vex.Flow.Glyph("v0", this.point);
98 | glyph["topGlyphs"] = [];
99 | glyph["botGlyphs"] = [];
100 |
101 | var topWidth = 0;
102 | var i, num;
103 | for (i = 0; i < topNums.length; ++i) {
104 | num = topNums[i];
105 | var topGlyph = new Vex.Flow.Glyph("v" + num, this.point);
106 |
107 | glyph.topGlyphs.push(topGlyph);
108 | topWidth += topGlyph.getMetrics().width;
109 | }
110 |
111 | var botWidth = 0;
112 | for (i = 0; i < botNums.length; ++i) {
113 | num = botNums[i];
114 | var botGlyph = new Vex.Flow.Glyph("v" + num, this.point);
115 |
116 | glyph.botGlyphs.push(botGlyph);
117 | botWidth += botGlyph.getMetrics().width;
118 | }
119 |
120 | var width = (topWidth > botWidth ? topWidth : botWidth);
121 | var xMin = glyph.getMetrics().x_min;
122 |
123 | glyph.getMetrics = function() {
124 | return {
125 | x_min: xMin,
126 | x_max: xMin + width,
127 | width: width
128 | };
129 | };
130 |
131 | var topStartX = (width - topWidth) / 2.0;
132 | var botStartX = (width - botWidth) / 2.0;
133 |
134 | var that = this;
135 | glyph.renderToStave = function(x) {
136 | var start_x = x + topStartX;
137 | var i, g;
138 | for (i = 0; i < this.topGlyphs.length; ++i) {
139 | g = this.topGlyphs[i];
140 | Vex.Flow.Glyph.renderOutline(this.context, g.metrics.outline,
141 | g.scale, start_x + g.x_shift, this.stave.getYForLine(that.topLine) + 1);
142 | start_x += g.getMetrics().width;
143 | }
144 |
145 | start_x = x + botStartX;
146 | for (i = 0; i < this.botGlyphs.length; ++i) {
147 | g = this.botGlyphs[i];
148 | that.placeGlyphOnLine(g, this.stave, g.line);
149 | Vex.Flow.Glyph.renderOutline(this.context, g.metrics.outline,
150 | g.scale, start_x + g.x_shift, this.stave.getYForLine(that.bottomLine) + 1);
151 | start_x += g.getMetrics().width;
152 | }
153 | };
154 |
155 | return glyph;
156 | },
157 |
158 | getTimeSig: function() {
159 | return this.timeSig;
160 | },
161 |
162 | addModifier: function(stave) {
163 | if (!this.timeSig.num) {
164 | this.placeGlyphOnLine(this.timeSig.glyph, stave, this.timeSig.line);
165 | }
166 | stave.addGlyph(this.timeSig.glyph);
167 | },
168 |
169 | addEndModifier: function(stave) {
170 | if (!this.timeSig.num) {
171 | this.placeGlyphOnLine(this.timeSig.glyph, stave, this.timeSig.line);
172 | }
173 | stave.addEndGlyph(this.timeSig.glyph);
174 | }
175 | });
176 |
177 | return TimeSignature;
178 | }());
179 |
--------------------------------------------------------------------------------
/src/timesignote.js:
--------------------------------------------------------------------------------
1 | // Vex Flow Notation
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // Author Taehoon Moon 2014
5 |
6 | /** @constructor */
7 | Vex.Flow.TimeSigNote = (function() {
8 | function TimeSigNote(timeSpec, customPadding) {
9 | if (arguments.length > 0) this.init(timeSpec, customPadding);
10 | }
11 |
12 | Vex.Inherit(TimeSigNote, Vex.Flow.Note, {
13 | init: function(timeSpec, customPadding) {
14 | TimeSigNote.superclass.init.call(this, {duration: "b"});
15 |
16 | var timeSignature = new Vex.Flow.TimeSignature(timeSpec, customPadding);
17 | this.timeSig = timeSignature.getTimeSig();
18 | this.setWidth(this.timeSig.glyph.getMetrics().width);
19 |
20 | // Note properties
21 | this.ignore_ticks = true;
22 | },
23 |
24 | setStave: function(stave) {
25 | var superclass = Vex.Flow.TimeSigNote.superclass;
26 | superclass.setStave.call(this, stave);
27 | },
28 |
29 | getBoundingBox: function() {
30 | return new Vex.Flow.BoundingBox(0, 0, 0, 0);
31 | },
32 |
33 | addToModifierContext: function() {
34 | /* overridden to ignore */
35 | return this;
36 | },
37 |
38 | preFormat: function() {
39 | this.setPreFormatted(true);
40 | return this;
41 | },
42 |
43 | draw: function() {
44 | if (!this.stave) throw new Vex.RERR("NoStave", "Can't draw without a stave.");
45 |
46 | if (!this.timeSig.glyph.getContext()) {
47 | this.timeSig.glyph.setContext(this.context);
48 | }
49 |
50 | this.timeSig.glyph.setStave(this.stave);
51 | this.timeSig.glyph.setYShift(
52 | this.stave.getYForLine(this.timeSig.line) - this.stave.getYForGlyphs());
53 | this.timeSig.glyph.renderToStave(this.getAbsoluteX());
54 | }
55 | });
56 |
57 | return TimeSigNote;
58 | }());
59 |
--------------------------------------------------------------------------------
/src/tremolo.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Author: Mike Corrigan
3 | //
4 | // This class implements tremolo notation.
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.Tremolo = (function() {
10 | function Tremolo(num) {
11 | if (arguments.length > 0) this.init(num);
12 | }
13 |
14 | var Modifier = Vex.Flow.Modifier;
15 | Vex.Inherit(Tremolo, Modifier, {
16 | init: function(num) {
17 | Tremolo.superclass.init.call(this);
18 |
19 | this.num = num;
20 | this.note = null;
21 | this.index = null;
22 | this.position = Modifier.Position.CENTER;
23 | this.code = "v74";
24 | this.shift_right = -2;
25 | this.y_spacing = 4;
26 |
27 | this.render_options = {
28 | font_scale: 35,
29 | stroke_px: 3,
30 | stroke_spacing: 10
31 | };
32 |
33 | this.font = {
34 | family: "Arial",
35 | size: 16,
36 | weight: ""
37 | };
38 | },
39 |
40 | getCategory: function() { return "tremolo"; },
41 |
42 | draw: function() {
43 | if (!this.context) throw new Vex.RERR("NoContext",
44 | "Can't draw Tremolo without a context.");
45 | if (!(this.note && (this.index != null))) throw new Vex.RERR("NoAttachedNote",
46 | "Can't draw Tremolo without a note and index.");
47 |
48 | var start = this.note.getModifierStartXY(this.position, this.index);
49 | var x = start.x;
50 | var y = start.y;
51 |
52 | x += this.shift_right;
53 | for (var i = 0; i < this.num; ++i) {
54 | Vex.Flow.renderGlyph(this.context, x, y,
55 | this.render_options.font_scale, this.code);
56 | y += this.y_spacing;
57 | }
58 | }
59 | });
60 |
61 | return Tremolo;
62 | }());
63 |
--------------------------------------------------------------------------------
/src/tuning.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // This class implements varies types of tunings for tablature.
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.Tuning = (function() {
10 | function Tuning(tuningString) {
11 | this.init(tuningString);
12 | }
13 |
14 | Tuning.names = {
15 | "standard": "E/5,B/4,G/4,D/4,A/3,E/3",
16 | "dagdad": "D/5,A/4,G/4,D/4,A/3,D/3",
17 | "dropd": "E/5,B/4,G/4,D/4,A/3,D/3",
18 | "eb": "Eb/5,Bb/4,Gb/4,Db/4,Ab/3,Db/3"
19 | };
20 |
21 | Tuning.prototype = {
22 | init: function(tuningString) {
23 | // Default to standard tuning.
24 | this.setTuning(tuningString || "E/5,B/4,G/4,D/4,A/3,E/3,B/2,E/2");
25 | },
26 |
27 | noteToInteger: function(noteString) {
28 | return Vex.Flow.keyProperties(noteString).int_value;
29 | },
30 |
31 | setTuning: function(noteString) {
32 | if (Vex.Flow.Tuning.names[noteString])
33 | noteString = Vex.Flow.Tuning.names[noteString];
34 |
35 | this.tuningString = noteString;
36 | this.tuningValues = [];
37 | this.numStrings = 0;
38 |
39 | var keys = noteString.split(/\s*,\s*/);
40 | if (keys.length === 0)
41 | throw new Vex.RERR("BadArguments", "Invalid tuning string: " + noteString);
42 |
43 | this.numStrings = keys.length;
44 | for (var i = 0; i < this.numStrings; ++i) {
45 | this.tuningValues[i] = this.noteToInteger(keys[i]);
46 | }
47 | },
48 |
49 | getValueForString: function(stringNum) {
50 | var s = parseInt(stringNum, 10);
51 | if (s < 1 || s > this.numStrings)
52 | throw new Vex.RERR("BadArguments", "String number must be between 1 and " +
53 | this.numStrings + ": " + stringNum);
54 |
55 | return this.tuningValues[s - 1];
56 | },
57 |
58 | getValueForFret: function(fretNum, stringNum) {
59 | var stringValue = this.getValueForString(stringNum);
60 | var f = parseInt(fretNum, 10);
61 |
62 | if (f < 0) {
63 | throw new Vex.RERR("BadArguments", "Fret number must be 0 or higher: " +
64 | fretNum);
65 | }
66 |
67 | return stringValue + f;
68 | },
69 |
70 | getNoteForFret: function(fretNum, stringNum) {
71 | var noteValue = this.getValueForFret(fretNum, stringNum);
72 |
73 | var octave = Math.floor(noteValue / 12);
74 | var value = noteValue % 12;
75 |
76 | return Vex.Flow.integerToNote(value) + "/" + octave;
77 | }
78 | };
79 |
80 | return Tuning;
81 | }());
82 |
--------------------------------------------------------------------------------
/src/vex.js:
--------------------------------------------------------------------------------
1 | // [VexFlow](http://vexflow.com) - Copyright (c) Mohit Muthanna 2010.
2 | //
3 | // ## Description
4 | //
5 | // This file implements utility methods used by the rest of the VexFlow
6 | // codebase.
7 | //
8 | // ## JSHint Settings
9 | //
10 | /* global window: false */
11 | /* global document: false */
12 |
13 | function Vex() {}
14 |
15 | // Default log function sends all arguments to console.
16 | Vex.L = function(block, args) {
17 | if (!args) return;
18 | var line = Array.prototype.slice.call(args).join(" ");
19 | window.console.log(block + ": " + line);
20 | };
21 |
22 | // Default runtime exception.
23 | Vex.RuntimeError = function(code, message) {
24 | this.code = code;
25 | this.message = message;
26 | };
27 | Vex.RuntimeError.prototype.toString = function() {
28 | return "RuntimeError: " + this.message;
29 | };
30 |
31 | // Shortcut method for `RuntimeError`.
32 | Vex.RERR = Vex.RuntimeError;
33 |
34 | // Merge `destination` hash with `source` hash, overwriting like keys
35 | // in `source` if necessary.
36 | Vex.Merge = function(destination, source) {
37 | for (var property in source)
38 | destination[property] = source[property];
39 | return destination;
40 | };
41 |
42 | // DEPRECATED. Use `Math.min`.
43 | Vex.Min = function(a, b) {
44 | return (a > b) ? b : a;
45 | };
46 |
47 | // DEPRECATED. Use `Math.max`.
48 | Vex.Max = function(a, b) {
49 | return (a > b) ? a : b;
50 | };
51 |
52 | // Round number to nearest fractional value (`.5`, `.25`, etc.)
53 | Vex.RoundN = function(x, n) {
54 | return (x % n) >= (n/2) ?
55 | parseInt(x / n, 10) * n + n : parseInt(x / n, 10) * n;
56 | };
57 |
58 | // Locate the mid point between stave lines. Returns a fractional line if a space.
59 | Vex.MidLine = function(a, b) {
60 | var mid_line = b + (a - b) / 2;
61 | if (mid_line % 2 > 0) {
62 | mid_line = Vex.RoundN(mid_line * 10, 5) / 10;
63 | }
64 | return mid_line;
65 | };
66 |
67 | // Take `arr` and return a new list consisting of the sorted, unique,
68 | // contents of arr. Does not modify `arr`.
69 | Vex.SortAndUnique = function(arr, cmp, eq) {
70 | if (arr.length > 1) {
71 | var newArr = [];
72 | var last;
73 | arr.sort(cmp);
74 |
75 | for (var i = 0; i < arr.length; ++i) {
76 | if (i === 0 || !eq(arr[i], last)) {
77 | newArr.push(arr[i]);
78 | }
79 | last = arr[i];
80 | }
81 |
82 | return newArr;
83 | } else {
84 | return arr;
85 | }
86 | };
87 |
88 | // Check if array `a` contains `obj`.
89 | Vex.Contains = function(a, obj) {
90 | var i = a.length;
91 | while (i--) {
92 | if (a[i] === obj) {
93 | return true;
94 | }
95 | }
96 | return false;
97 | };
98 |
99 | // Get the 2D Canvas context from DOM element `canvas_sel`.
100 | Vex.getCanvasContext = function(canvas_sel) {
101 | if (!canvas_sel)
102 | throw new Vex.RERR("BadArgument", "Invalid canvas selector: " + canvas_sel);
103 |
104 | var canvas = document.getElementById(canvas_sel);
105 | if (!(canvas && canvas.getContext)) {
106 | throw new Vex.RERR("UnsupportedBrowserError",
107 | "This browser does not support HTML5 Canvas");
108 | }
109 |
110 | return canvas.getContext('2d');
111 | };
112 |
113 | // Draw a tiny dot marker on the specified canvas. A great debugging aid.
114 | //
115 | // `ctx`: Canvas context.
116 | // `x`, `y`: Dot coordinates.
117 | Vex.drawDot = function(ctx, x, y, color) {
118 | var c = color || "#f55";
119 | ctx.save();
120 | ctx.fillStyle = c;
121 |
122 | //draw a circle
123 | ctx.beginPath();
124 | ctx.arc(x, y, 3, 0, Math.PI*2, true);
125 | ctx.closePath();
126 | ctx.fill();
127 | ctx.restore();
128 | };
129 |
130 | // Benchmark. Run function `f` once and report time elapsed shifted by `s` milliseconds.
131 | Vex.BM = function(s, f) {
132 | var start_time = new Date().getTime();
133 | f();
134 | var elapsed = new Date().getTime() - start_time;
135 | Vex.L(s + elapsed + "ms");
136 | };
137 |
138 | // Basic classical inheritance helper. Usage:
139 | // ```
140 | // // Vex.Inherit(Child, Parent, {
141 | // // getName: function() {return this.name;},
142 | // // setName: function(name) {this.name = name}
143 | // // });
144 | // //
145 | // // Returns 'Child'.
146 | // ```
147 | Vex.Inherit = (function () {
148 | var F = function () {};
149 | // `C` is Child. `P` is parent. `O` is an object to
150 | // to extend `C` with.
151 | return function (C, P, O) {
152 | F.prototype = P.prototype;
153 | C.prototype = new F();
154 | C.superclass = P.prototype;
155 | C.prototype.constructor = C;
156 | Vex.Merge(C.prototype, O);
157 | return C;
158 | };
159 | }());
--------------------------------------------------------------------------------
/src/vibrato.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Music Engraving for HTML5
2 | // Copyright Mohit Muthanna 2010
3 | //
4 | // This class implements vibratos.
5 |
6 | /**
7 | * @constructor
8 | */
9 | Vex.Flow.Vibrato = (function() {
10 | function Vibrato() { this.init(); }
11 |
12 | var Modifier = Vex.Flow.Modifier;
13 | Vex.Inherit(Vibrato, Modifier, {
14 | init: function() {
15 | var superclass = Vex.Flow.Vibrato.superclass;
16 | superclass.init.call(this);
17 |
18 | this.harsh = false;
19 | this.position = Vex.Flow.Modifier.Position.RIGHT;
20 | this.render_options = {
21 | vibrato_width: 20,
22 | wave_height: 6,
23 | wave_width: 4,
24 | wave_girth: 2
25 | };
26 |
27 | this.setVibratoWidth(this.render_options.vibrato_width);
28 | },
29 |
30 | getCategory: function() { return "vibratos"; },
31 | setHarsh: function(harsh) { this.harsh = harsh; return this; },
32 | setVibratoWidth: function(width) {
33 | this.vibrato_width = width;
34 | this.setWidth(this.vibrato_width);
35 | return this;
36 | },
37 |
38 | draw: function() {
39 | if (!this.context) throw new Vex.RERR("NoContext",
40 | "Can't draw vibrato without a context.");
41 | if (!this.note) throw new Vex.RERR("NoNoteForVibrato",
42 | "Can't draw vibrato without an attached note.");
43 |
44 | var start = this.note.getModifierStartXY(Vex.Flow.Modifier.Position.RIGHT,
45 | this.index);
46 |
47 | var ctx = this.context;
48 | var that = this;
49 | var vibrato_width = this.vibrato_width;
50 |
51 | function renderVibrato(x, y) {
52 | var wave_width = that.render_options.wave_width;
53 | var wave_girth = that.render_options.wave_girth;
54 | var wave_height = that.render_options.wave_height;
55 | var num_waves = vibrato_width / wave_width;
56 |
57 | ctx.beginPath();
58 |
59 | var i;
60 | if (that.harsh) {
61 | ctx.moveTo(x, y + wave_girth + 1);
62 | for (i = 0; i < num_waves / 2; ++i) {
63 | ctx.lineTo(x + wave_width, y - (wave_height / 2));
64 | x += wave_width;
65 | ctx.lineTo(x + wave_width, y + (wave_height / 2));
66 | x += wave_width;
67 | }
68 | for (i = 0; i < num_waves / 2; ++i) {
69 | ctx.lineTo(x - wave_width, (y - (wave_height / 2)) + wave_girth + 1);
70 | x -= wave_width;
71 | ctx.lineTo(x - wave_width, (y + (wave_height / 2)) + wave_girth + 1);
72 | x -= wave_width;
73 | }
74 | ctx.fill();
75 | } else {
76 | ctx.moveTo(x, y + wave_girth);
77 | for (i = 0; i < num_waves / 2; ++i) {
78 | ctx.quadraticCurveTo(x + (wave_width / 2), y - (wave_height / 2),
79 | x + wave_width, y);
80 | x += wave_width;
81 | ctx.quadraticCurveTo(x + (wave_width / 2), y + (wave_height / 2),
82 | x + wave_width, y);
83 | x += wave_width;
84 | }
85 |
86 | for (i = 0; i < num_waves / 2; ++i) {
87 | ctx.quadraticCurveTo(
88 | x - (wave_width / 2),
89 | (y + (wave_height / 2)) + wave_girth,
90 | x - wave_width, y + wave_girth);
91 | x -= wave_width;
92 | ctx.quadraticCurveTo(
93 | x - (wave_width / 2),
94 | (y - (wave_height / 2)) + wave_girth,
95 | x - wave_width, y + wave_girth);
96 | x -= wave_width;
97 | }
98 | ctx.fill();
99 | }
100 | }
101 |
102 | var vx = start.x + this.x_shift;
103 | var vy = this.note.getYForTopText(this.text_line) + 2;
104 |
105 | renderVibrato(vx, vy);
106 | }
107 | });
108 |
109 | return Vibrato;
110 | }());
111 |
--------------------------------------------------------------------------------
/src/voicegroup.js:
--------------------------------------------------------------------------------
1 | // Vex Music Notation
2 | // Mohit Muthanna
3 | //
4 | // Copyright Mohit Muthanna 2010
5 |
6 | /** @constructor */
7 | Vex.Flow.VoiceGroup = (function() {
8 | function VoiceGroup() {
9 | this.init();
10 | }
11 |
12 | VoiceGroup.prototype = {
13 | init: function() {
14 | this.voices = [];
15 | this.modifierContexts = [];
16 | },
17 |
18 | // Every tickable must be associated with a voiceGroup. This allows formatters
19 | // and preformatters to associate them with the right modifierContexts.
20 | getVoices: function() { return this.voices; },
21 | getModifierContexts: function() { return this.modifierContexts; },
22 |
23 | addVoice: function(voice) {
24 | if (!voice) throw new Vex.RERR("BadArguments", "Voice cannot be null.");
25 | this.voices.push(voice);
26 | voice.setVoiceGroup(this);
27 | }
28 | };
29 |
30 | return VoiceGroup;
31 | }());
--------------------------------------------------------------------------------
/tests/boundingbox_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Bounding Box Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.BoundingBox = {}
7 |
8 | Vex.Flow.Test.BoundingBox.Start = function() {
9 | module("BoundingBox");
10 | test("Initialization Test", Vex.Flow.Test.BoundingBox.initialization);
11 | test("Merging Text", Vex.Flow.Test.BoundingBox.merging);
12 | }
13 |
14 | Vex.Flow.Test.BoundingBox.initialization = function() {
15 | var bb = new Vex.Flow.BoundingBox(4, 5, 6, 7);
16 | equal(bb.getX(), 4, "Bad X");
17 | equal(bb.getY(), 5, "Bad Y");
18 | equal(bb.getW(), 6, "Bad W");
19 | equal(bb.getH(), 7, "Bad H");
20 |
21 | bb.setX(5)
22 | equal(bb.getX(), 5, "Bad X");
23 | }
24 |
25 | Vex.Flow.Test.BoundingBox.merging = function() {
26 | var bb1 = new Vex.Flow.BoundingBox(10, 10, 10, 10);
27 | var bb2 = new Vex.Flow.BoundingBox(15, 20, 10, 10);
28 |
29 | equal(bb1.getX(), 10, "Bad X for bb1");
30 | equal(bb2.getX(), 15, "Bad X for bb2");
31 |
32 | bb1.mergeWith(bb2);
33 | equal(bb1.getX(), 10);
34 | equal(bb1.getY(), 10);
35 | equal(bb1.getW(), 15);
36 | equal(bb1.getH(), 20);
37 | }
38 |
--------------------------------------------------------------------------------
/tests/clef_tests.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Basic Tests
2 |
3 | Vex.Flow.Test.Clef = {}
4 |
5 | Vex.Flow.Test.Clef.Start = function() {
6 | module("Clef");
7 | Vex.Flow.Test.runTest("Clef Test", Vex.Flow.Test.Clef.draw);
8 | Vex.Flow.Test.runRaphaelTest("Clef Test (Raphael)",
9 | Vex.Flow.Test.Clef.draw);
10 | Vex.Flow.Test.runTest("Small Clef Test", Vex.Flow.Test.Clef.drawSmall);
11 | Vex.Flow.Test.runRaphaelTest("Small Clef Test (Raphael)",
12 | Vex.Flow.Test.Clef.drawSmall);
13 | Vex.Flow.Test.runTest("Clef Change Test", Vex.Flow.Test.Clef.drawClefChange);
14 | Vex.Flow.Test.runRaphaelTest("Clef Change Test (Raphael)", Vex.Flow.Test.Clef.drawClefChange);
15 | }
16 |
17 | Vex.Flow.Test.Clef.draw = function(options, contextBuilder) {
18 | var ctx = new contextBuilder(options.canvas_sel, 800, 120);
19 | var stave = new Vex.Flow.Stave(10, 10, 700);
20 |
21 | stave.addClef("treble");
22 | stave.addClef("alto");
23 | stave.addClef("tenor");
24 | stave.addClef("soprano");
25 | stave.addClef("bass");
26 | stave.addClef("mezzo-soprano");
27 | stave.addClef("baritone-c");
28 | stave.addClef("baritone-f");
29 | stave.addClef("subbass");
30 | stave.addClef("french");
31 |
32 | stave.addEndClef("treble");
33 | stave.addEndClef("alto");
34 | stave.addEndClef("tenor");
35 | stave.addEndClef("soprano");
36 | stave.addEndClef("bass");
37 | stave.addEndClef("mezzo-soprano");
38 | stave.addEndClef("baritone-c");
39 | stave.addEndClef("baritone-f");
40 | stave.addEndClef("subbass");
41 | stave.addEndClef("french");
42 |
43 | stave.setContext(ctx);
44 | stave.draw();
45 |
46 | ok(true, "all pass");
47 | }
48 |
49 | Vex.Flow.Test.Clef.drawSmall = function(options, contextBuilder) {
50 | var ctx = new contextBuilder(options.canvas_sel, 800, 120);
51 | var stave = new Vex.Flow.Stave(10, 10, 700);
52 |
53 | stave.addClef("treble_small");
54 | stave.addClef("alto_small");
55 | stave.addClef("tenor_small");
56 | stave.addClef("soprano_small");
57 | stave.addClef("bass_small");
58 | stave.addClef("mezzo-soprano_small");
59 | stave.addClef("baritone-c_small");
60 | stave.addClef("baritone-f_small");
61 | stave.addClef("subbass_small");
62 | stave.addClef("french_small");
63 |
64 | stave.addEndClef("treble_small");
65 | stave.addEndClef("alto_small");
66 | stave.addEndClef("tenor_small");
67 | stave.addEndClef("soprano_small");
68 | stave.addEndClef("bass_small");
69 | stave.addEndClef("mezzo-soprano_small");
70 | stave.addEndClef("baritone-c_small");
71 | stave.addEndClef("baritone-f_small");
72 | stave.addEndClef("subbass_small");
73 | stave.addEndClef("french_small");
74 |
75 | stave.setContext(ctx);
76 | stave.draw();
77 |
78 | ok(true, "all pass");
79 | }
80 |
81 | Vex.Flow.Test.Clef.drawClefChange = function(options, contextBuilder) {
82 | var ctx = new contextBuilder(options.canvas_sel, 800, 120);
83 | var stave = new Vex.Flow.Stave(10, 10, 700);
84 | stave.addClef("treble").setContext(ctx).draw();
85 |
86 | var notes = [
87 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "treble" }),
88 | new Vex.Flow.ClefNote("alto_small"),
89 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "alto" }),
90 | new Vex.Flow.ClefNote("tenor_small"),
91 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "tenor" }),
92 | new Vex.Flow.ClefNote("soprano_small"),
93 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "soprano" }),
94 | new Vex.Flow.ClefNote("bass_small"),
95 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "bass" }),
96 | new Vex.Flow.ClefNote("mezzo-soprano_small"),
97 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "mezzo-soprano" }),
98 | new Vex.Flow.ClefNote("baritone-c_small"),
99 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "baritone-c" }),
100 | new Vex.Flow.ClefNote("baritone-f_small"),
101 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "baritone-f" }),
102 | new Vex.Flow.ClefNote("subbass_small"),
103 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "subbass" }),
104 | new Vex.Flow.ClefNote("french_small"),
105 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q", clef: "french" })
106 | ];
107 |
108 | var voice = new Vex.Flow.Voice({
109 | num_beats: 10,
110 | beat_value: 4,
111 | resolution: Vex.Flow.RESOLUTION
112 | });
113 |
114 | voice.addTickables(notes);
115 |
116 | var formatter = new Vex.Flow.Formatter().
117 | joinVoices([voice]).format([voice], 500);
118 |
119 | voice.draw(ctx, stave);
120 | ok(true, "all pass");
121 | }
122 |
123 |
--------------------------------------------------------------------------------
/tests/dot_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Dot Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.Dot = {}
7 |
8 | Vex.Flow.Test.Dot.Start = function() {
9 | module("Dot");
10 | Vex.Flow.Test.runTest("Basic", Vex.Flow.Test.Dot.basic);
11 | Vex.Flow.Test.runRaphaelTest("Basic (Raphael)",
12 | Vex.Flow.Test.Dot.basic);
13 | Vex.Flow.Test.runTest("Multi Voice", Vex.Flow.Test.Dot.multiVoice);
14 | }
15 |
16 | Vex.Flow.Test.Dot.showNote = function(note, stave, ctx, x) {
17 | var mc = new Vex.Flow.ModifierContext();
18 | note.addToModifierContext(mc);
19 |
20 | var tickContext = new Vex.Flow.TickContext();
21 | tickContext.addTickable(note).preFormat().setX(x).setPixelsUsed(65);
22 |
23 | note.setContext(ctx).setStave(stave);
24 | note.draw();
25 |
26 | ctx.save();
27 | ctx.font = "10pt Arial"; ctx.strokeStyle = "#579"; ctx.fillStyle = "#345";
28 | ctx.fillText("w: " + note.getWidth(), note.getAbsoluteX() - 25, 200 / 1.5);
29 |
30 | ctx.beginPath();
31 | ctx.moveTo(note.getAbsoluteX() - (note.getWidth() / 2), 210/1.5);
32 | ctx.lineTo(note.getAbsoluteX() + (note.getWidth() / 2), 210/1.5);
33 | ctx.stroke();
34 | ctx.restore();
35 | return note;
36 | }
37 |
38 | Vex.Flow.Test.Dot.basic = function(options, contextBuilder) {
39 | var ctx = new contextBuilder(options.canvas_sel, 1000, 240);
40 | ctx.scale(1.5, 1.5); ctx.setFillStyle("#221"); ctx.setStrokeStyle("#221");
41 | var stave = new Vex.Flow.Stave(10, 10, 975);
42 | stave.setContext(ctx);
43 | stave.draw();
44 |
45 | function newNote(note_struct) { return new Vex.Flow.StaveNote(note_struct); }
46 | function newAcc(type) { return new Vex.Flow.Dot(type); }
47 |
48 | var notes = [
49 | newNote({ keys: ["c/4", "e/4", "a/4", "b/4"], duration: "w"}).
50 | addDotToAll(),
51 |
52 | newNote({ keys: ["c/5", "b/4", "a/4"],
53 | duration: "q", stem_direction: 1}).
54 | addDotToAll(),
55 |
56 | newNote({ keys: ["b/4", "a/4", "g/4"],
57 | duration: "q", stem_direction: -1}).
58 | addDotToAll(),
59 |
60 | newNote({ keys: ["c/5", "b/4", "f/4", "e/4"],
61 | duration: "q"}).
62 | addDotToAll(),
63 |
64 | newNote({ keys: ["g/5", "e/5", "d/5", "a/4", "g/4"],
65 | duration: "q", stem_direction: -1}).
66 | addDotToAll(),
67 |
68 | newNote({ keys: ["e/5", "d/5", "b/4", "g/4"],
69 | duration: "q", stem_direction: -1}).
70 | addDotToAll(),
71 |
72 | newNote({ keys: ["c/5", "b/4", "g/4", "e/4"],
73 | duration: "q", stem_direction: 1}).
74 | addDotToAll(),
75 |
76 | newNote({ keys: ["d/4", "e/4", "f/4", "a/4", "c/5", "e/5", "g/5"],
77 | duration: "h"}).
78 | addDotToAll().
79 | addDotToAll(),
80 |
81 | newNote({ keys: ["f/4", "g/4", "a/4", "b/4", "c/5", "e/5", "g/5"],
82 | duration: "16", stem_direction: -1}).
83 | addDotToAll().
84 | addDotToAll().
85 | addDotToAll()
86 | ];
87 |
88 | for (var i = 0; i < notes.length; ++i) {
89 | Vex.Flow.Test.Dot.showNote(notes[i], stave, ctx, 30 + (i * 65));
90 | var accidentals = notes[i].getDots();
91 | ok(accidentals.length > 0, "Note " + i + " has accidentals");
92 |
93 | for (var j = 0; j < accidentals.length; ++j) {
94 | ok(accidentals[j].width > 0, "Dot " + j + " has set width");
95 | }
96 | }
97 |
98 | ok(true, "Full Dot");
99 | }
100 |
101 | Vex.Flow.Test.Dot.showNotes = function(note1, note2, stave, ctx, x) {
102 | var mc = new Vex.Flow.ModifierContext();
103 | note1.addToModifierContext(mc);
104 | note2.addToModifierContext(mc);
105 |
106 | var tickContext = new Vex.Flow.TickContext();
107 | tickContext.addTickable(note1).addTickable(note2).
108 | preFormat().setX(x).setPixelsUsed(65);
109 |
110 | note1.setContext(ctx).setStave(stave).draw();
111 | note2.setContext(ctx).setStave(stave).draw();
112 |
113 | ctx.save();
114 | ctx.font = "10pt Arial"; ctx.strokeStyle = "#579"; ctx.fillStyle = "#345";
115 | ctx.fillText("w: " + note2.getWidth(), note2.getAbsoluteX() + 15, 20 / 1.5);
116 | ctx.fillText("w: " + note1.getWidth(), note1.getAbsoluteX() - 25, 220 / 1.5);
117 |
118 | ctx.beginPath();
119 | ctx.moveTo(note1.getAbsoluteX() - (note1.getWidth() / 2), 230/1.5);
120 | ctx.lineTo(note1.getAbsoluteX() + (note1.getWidth() / 2), 230/1.5);
121 | ctx.stroke();
122 | ctx.restore();
123 | }
124 |
125 | Vex.Flow.Test.Dot.multiVoice = function(options, contextBuilder) {
126 | var ctx = new contextBuilder(options.canvas_sel, 400, 150);
127 |
128 | ctx.scale(0.9, 0.9); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
129 | var stave = new Vex.Flow.Stave(10, 10, 420);
130 | stave.setContext(ctx);
131 | stave.draw();
132 |
133 | function newNote(note_struct) { return new Vex.Flow.StaveNote(note_struct); }
134 | function newAcc(type) { return new Vex.Flow.Dot(type); }
135 |
136 | var note1 = newNote(
137 | { keys: ["c/4", "e/4", "a/4"], duration: "h", stem_direction: -1}).
138 | addDotToAll().
139 | addDotToAll();
140 | var note2 = newNote(
141 | { keys: ["d/5", "a/5", "b/5"], duration: "h", stem_direction: 1}).
142 | addDotToAll();
143 |
144 | Vex.Flow.Test.Dot.showNotes(note1, note2, stave, ctx, 60);
145 |
146 | note1 = newNote(
147 | { keys: ["c/4", "e/4", "c/5"], duration: "h", stem_direction: -1}).
148 | addDot(0).
149 | addDot(0).
150 | addDot(1).
151 | addDot(1).
152 | addDot(2).
153 | addDot(2).
154 | addDot(2);
155 | note2 = newNote(
156 | { keys: ["d/5", "a/5", "b/5"], duration: "q", stem_direction: 1}).
157 | addDotToAll().
158 | addDotToAll();
159 |
160 | Vex.Flow.Test.Dot.showNotes(note1, note2, stave, ctx, 150);
161 |
162 | note1 = newNote(
163 | { keys: ["d/4", "c/5", "d/5"], duration: "h", stem_direction: -1}).
164 | addDotToAll().
165 | addDotToAll().
166 | addDot(0);
167 | note2 = newNote(
168 | { keys: ["d/5", "a/5", "b/5"], duration: "q", stem_direction: 1}).
169 | addDotToAll();
170 |
171 | Vex.Flow.Test.Dot.showNotes(note1, note2, stave, ctx, 250);
172 | ok(true, "Full Dot");
173 | }
174 |
--------------------------------------------------------------------------------
/tests/keymanager_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Music Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.KeyManager = {}
7 |
8 | Vex.Flow.Test.KeyManager.Start = function() {
9 | module("KeyManager");
10 | test("Valid Notes", Vex.Flow.Test.KeyManager.works);
11 | test("Select Notes", Vex.Flow.Test.KeyManager.selectNotes);
12 | }
13 |
14 | Vex.Flow.Test.KeyManager.works = function() {
15 | // expect(1);
16 |
17 | var manager = new Vex.Flow.KeyManager("g");
18 | equal(manager.getAccidental("f").accidental, "#");
19 |
20 | manager.setKey("a");
21 | equal(manager.getAccidental("c").accidental, "#");
22 | equal(manager.getAccidental("a").accidental, null);
23 | equal(manager.getAccidental("f").accidental, "#");
24 |
25 | manager.setKey("A");
26 | equal(manager.getAccidental("c").accidental, "#");
27 | equal(manager.getAccidental("a").accidental, null);
28 | equal(manager.getAccidental("f").accidental, "#");
29 | }
30 |
31 | Vex.Flow.Test.KeyManager.selectNotes = function(options) {
32 | var manager = new Vex.Flow.KeyManager("f");
33 | equal(manager.selectNote("bb").note, "bb");
34 | equal(manager.selectNote("bb").accidental, "b");
35 | equal(manager.selectNote("g").note, "g");
36 | equal(manager.selectNote("g").accidental, null);
37 | equal(manager.selectNote("b").note, "b");
38 | equal(manager.selectNote("b").accidental, null);
39 | equal(manager.selectNote("a#").note, "bb");
40 | equal(manager.selectNote("g#").note, "g#");
41 |
42 | // Changes have no effect?
43 | equal(manager.selectNote("g#").note, "g#");
44 | equal(manager.selectNote("bb").note, "bb");
45 | equal(manager.selectNote("bb").accidental, "b");
46 | equal(manager.selectNote("g").note, "g");
47 | equal(manager.selectNote("g").accidental, null);
48 | equal(manager.selectNote("b").note, "b");
49 | equal(manager.selectNote("b").accidental, null);
50 | equal(manager.selectNote("a#").note, "bb");
51 | equal(manager.selectNote("g#").note, "g#");
52 |
53 | // Changes should propagate
54 | manager.reset();
55 | equal(manager.selectNote("g#").change, true);
56 | equal(manager.selectNote("g#").change, false);
57 | equal(manager.selectNote("g").change, true);
58 | equal(manager.selectNote("g").change, false);
59 | equal(manager.selectNote("g#").change, true);
60 |
61 | manager.reset();
62 | var note = manager.selectNote("bb");
63 | equal(note.change, false);
64 | equal(note.accidental, "b");
65 | note = manager.selectNote("g");
66 | equal(note.change, false);
67 | equal(note.accidental, null);
68 | note = manager.selectNote("g#");
69 | equal(note.change, true);
70 | equal(note.accidental, "#");
71 | note = manager.selectNote("g");
72 | equal(note.change, true);
73 | equal(note.accidental, null);
74 | note = manager.selectNote("g");
75 | equal(note.change, false);
76 | equal(note.accidental, null);
77 | note = manager.selectNote("g#");
78 | equal(note.change, true);
79 | equal(note.accidental, "#");
80 | }
81 |
--------------------------------------------------------------------------------
/tests/keysignature_tests.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Basic Tests
2 |
3 | Vex.Flow.Test.KeySignature = {}
4 |
5 | Vex.Flow.Test.KeySignature.MAJOR_KEYS = [
6 | "C",
7 | "F",
8 | "Bb",
9 | "Eb",
10 | "Ab",
11 | "Db",
12 | "Gb",
13 | "Cb",
14 | "G",
15 | "D",
16 | "A",
17 | "E",
18 | "B",
19 | "F#",
20 | "C#"];
21 |
22 | Vex.Flow.Test.KeySignature.MINOR_KEYS = [
23 | "Am",
24 | "Dm",
25 | "Gm",
26 | "Cm",
27 | "Fm",
28 | "Bbm",
29 | "Ebm",
30 | "Abm",
31 | "Em",
32 | "Bm",
33 | "F#m",
34 | "C#m",
35 | "G#m",
36 | "D#m",
37 | "A#m"];
38 |
39 |
40 | Vex.Flow.Test.KeySignature.Start = function() {
41 | module("KeySignature");
42 | test("Key Parser Test", Vex.Flow.Test.KeySignature.parser);
43 | Vex.Flow.Test.runTest("Major Key Test", Vex.Flow.Test.KeySignature.majorKeys);
44 | Vex.Flow.Test.runRaphaelTest("Major Key Test (Raphael)",
45 | Vex.Flow.Test.KeySignature.majorKeys);
46 | Vex.Flow.Test.runTest("Minor Key Test", Vex.Flow.Test.KeySignature.minorKeys);
47 | Vex.Flow.Test.runRaphaelTest("Minor Key Test (Raphael)",
48 | Vex.Flow.Test.KeySignature.minorKeys);
49 | Vex.Flow.Test.runTest("Stave Helper", Vex.Flow.Test.KeySignature.staveHelper);
50 |
51 | }
52 |
53 | Vex.Flow.Test.KeySignature.catchError = function(spec) {
54 | try {
55 | Vex.Flow.keySignature(spec);
56 | } catch (e) {
57 | equal(e.code, "BadKeySignature", e.message);
58 | }
59 | }
60 |
61 | Vex.Flow.Test.KeySignature.parser = function() {
62 | expect(11);
63 | Vex.Flow.Test.KeySignature.catchError("asdf");
64 | Vex.Flow.Test.KeySignature.catchError("D!");
65 | Vex.Flow.Test.KeySignature.catchError("E#");
66 | Vex.Flow.Test.KeySignature.catchError("D#");
67 | Vex.Flow.Test.KeySignature.catchError("#");
68 | Vex.Flow.Test.KeySignature.catchError("b");
69 | Vex.Flow.Test.KeySignature.catchError("Kb");
70 | Vex.Flow.Test.KeySignature.catchError("Fb");
71 | Vex.Flow.Test.KeySignature.catchError("Ab");
72 | Vex.Flow.Test.KeySignature.catchError("Dbm");
73 | Vex.Flow.Test.KeySignature.catchError("B#m");
74 |
75 | Vex.Flow.keySignature("B");
76 | Vex.Flow.keySignature("C");
77 | Vex.Flow.keySignature("Fm");
78 | Vex.Flow.keySignature("Ab");
79 | Vex.Flow.keySignature("Abm");
80 | Vex.Flow.keySignature("F#");
81 | Vex.Flow.keySignature("G#m");
82 |
83 | ok(true, "all pass");
84 | }
85 |
86 | Vex.Flow.Test.KeySignature.majorKeys = function(options, contextBuilder) {
87 | var ctx = new contextBuilder(options.canvas_sel, 400, 240);
88 | var stave = new Vex.Flow.Stave(10, 10, 350);
89 | var stave2 = new Vex.Flow.Stave(10, 90, 350);
90 | var keys = Vex.Flow.Test.KeySignature.MAJOR_KEYS;
91 |
92 | var keySig = null;
93 | for (var i = 0; i < 8; ++i) {
94 | keySig = new Vex.Flow.KeySignature(keys[i]);
95 | keySig.addToStave(stave);
96 | }
97 |
98 | for (var n = 8; n < keys.length; ++n) {
99 | keySig = new Vex.Flow.KeySignature(keys[n]);
100 | keySig.addToStave(stave2);
101 | }
102 |
103 |
104 | stave.setContext(ctx);
105 | stave.draw();
106 | stave2.setContext(ctx);
107 | stave2.draw();
108 |
109 | ok(true, "all pass");
110 | }
111 |
112 | Vex.Flow.Test.KeySignature.minorKeys = function(options, contextBuilder) {
113 | var ctx = new contextBuilder(options.canvas_sel, 400, 240);
114 | var stave = new Vex.Flow.Stave(10, 10, 350);
115 | var stave2 = new Vex.Flow.Stave(10, 90, 350);
116 | var keys = Vex.Flow.Test.KeySignature.MINOR_KEYS;
117 |
118 | var keySig = null;
119 | for (var i = 0; i < 8; ++i) {
120 | keySig = new Vex.Flow.KeySignature(keys[i]);
121 | keySig.addToStave(stave);
122 | }
123 |
124 | for (var n = 8; n < keys.length; ++n) {
125 | keySig = new Vex.Flow.KeySignature(keys[n]);
126 | keySig.addToStave(stave2);
127 | }
128 |
129 |
130 | stave.setContext(ctx);
131 | stave.draw();
132 | stave2.setContext(ctx);
133 | stave2.draw();
134 |
135 | ok(true, "all pass");
136 | }
137 |
138 | Vex.Flow.Test.KeySignature.staveHelper = function(options, contextBuilder) {
139 | var ctx = new contextBuilder(options.canvas_sel, 400, 240);
140 | var stave = new Vex.Flow.Stave(10, 10, 350);
141 | var stave2 = new Vex.Flow.Stave(10, 90, 350);
142 | var keys = Vex.Flow.Test.KeySignature.MAJOR_KEYS;
143 |
144 | for (var i = 0; i < 8; ++i) {
145 | stave.addKeySignature(keys[i]);
146 | }
147 |
148 | for (var n = 8; n < keys.length; ++n) {
149 | stave2.addKeySignature(keys[n]);
150 | }
151 |
152 | stave.setContext(ctx);
153 | stave.draw();
154 | stave2.setContext(ctx);
155 | stave2.draw();
156 |
157 | ok(true, "all pass");
158 | }
159 |
--------------------------------------------------------------------------------
/tests/mocks.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - TickContext Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.TIME4_4 = {
7 | num_beats: 4,
8 | beat_value: 4,
9 | resolution: Vex.Flow.RESOLUTION
10 | };
11 |
12 | /* Mock Tickable */
13 |
14 | Vex.Flow.Test.MockTickable = function() { this.ignore_ticks = false; }
15 | Vex.Flow.Test.MockTickable.prototype.getX = function() {
16 | return this.tickContext.getX();}
17 | Vex.Flow.Test.MockTickable.prototype.getIntrinsicTicks = function() {return this.ticks;}
18 | Vex.Flow.Test.MockTickable.prototype.getTicks = function() {return this.ticks;}
19 | Vex.Flow.Test.MockTickable.prototype.setTicks = function(t) {
20 | this.ticks = new Vex.Flow.Fraction(t, 1); return this; };
21 | Vex.Flow.Test.MockTickable.prototype.getMetrics = function() {
22 | return { noteWidth: this.width,
23 | left_shift: 0,
24 | modLeftPx: 0, modRightPx: 0,
25 | extraLeftPx: 0, extraRightPx: 0 };
26 | }
27 | Vex.Flow.Test.MockTickable.prototype.getWidth = function() {return this.width;}
28 | Vex.Flow.Test.MockTickable.prototype.setWidth = function(w) {
29 | this.width = w; return this; }
30 | Vex.Flow.Test.MockTickable.prototype.setVoice = function(v) {
31 | this.voice = v; return this; }
32 | Vex.Flow.Test.MockTickable.prototype.setStave = function(stave) {
33 | this.stave = stave; return this; }
34 | Vex.Flow.Test.MockTickable.prototype.setTickContext = function(tc) {
35 | this.tickContext = tc; return this; }
36 | Vex.Flow.Test.MockTickable.prototype.setIgnoreTicks = function(ignore_ticks) {
37 | this.ignore_ticks = ignore_ticks; return this; }
38 | Vex.Flow.Test.MockTickable.prototype.shouldIgnoreTicks = function() {
39 | return this.ignore_ticks; }
40 | Vex.Flow.Test.MockTickable.prototype.preFormat = function() {}
41 |
42 | /* Mock Modifier */
43 |
44 | Vex.Flow.Test.MockModifier = Vex.Flow.Modifier;
45 |
--------------------------------------------------------------------------------
/tests/modifier_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Modifier Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.ModifierContext = {}
7 |
8 | Vex.Flow.Test.ModifierContext.Start = function() {
9 | module("ModifierContext");
10 | test("Modifier Width Test", Vex.Flow.Test.ModifierContext.width);
11 | test("Modifier Management", Vex.Flow.Test.ModifierContext.management);
12 | }
13 |
14 | Vex.Flow.Test.ModifierContext.width = function() {
15 | var mc = new Vex.Flow.ModifierContext();
16 | equal(mc.getWidth(), 0, "New modifier context has no width");
17 | }
18 |
19 | Vex.Flow.Test.ModifierContext.management = function() {
20 | var mc = new Vex.Flow.ModifierContext();
21 | var modifier1 = new Vex.Flow.Test.MockModifier;
22 | var modifier2 = new Vex.Flow.Test.MockModifier;
23 |
24 | mc.addModifier(modifier1);
25 | mc.addModifier(modifier2);
26 |
27 | var accidentals = mc.getModifiers("none");
28 |
29 | equal(accidentals.length, 2, "Added two modifiers");
30 | }
31 |
--------------------------------------------------------------------------------
/tests/notehead_tests.js:
--------------------------------------------------------------------------------
1 | Vex.Flow.Test.NoteHead = {};
2 |
3 | Vex.Flow.Test.NoteHead.Start = function(){
4 | module("NoteHead");
5 | Vex.Flow.Test.runTest("Basic", Vex.Flow.Test.NoteHead.basic);
6 | Vex.Flow.Test.runTest("Bounding Boxes", Vex.Flow.Test.NoteHead.basicBoundingBoxes);
7 | };
8 |
9 | Vex.Flow.Test.NoteHead.setupContext = function(options, x, y) {
10 |
11 | var ctx = new options.contextBuilder(options.canvas_sel, x || 450, y || 140);
12 | ctx.scale(0.9, 0.9); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
13 | ctx.font = " 10pt Arial";
14 | var stave = new Vex.Flow.Stave(10, 10, x || 450).addTrebleGlyph();
15 |
16 | return {context: ctx, stave: stave};
17 | };
18 |
19 | Vex.Flow.Test.NoteHead.basic = function(options, contextBuilder){
20 | options.contextBuilder = contextBuilder;
21 | var c = Vex.Flow.Test.NoteHead.setupContext(options, 450, 250);
22 |
23 | c.stave = new Vex.Flow.Stave(10, 0, 250).addTrebleGlyph();
24 |
25 | c.context.scale(2.0, 2.0);
26 | c.stave.setContext(c.context).draw();
27 |
28 | var formatter = new Vex.Flow.Formatter();
29 | var voice = new Vex.Flow.Voice(Vex.Flow.TIME4_4).setStrict(false);
30 |
31 | var note_head1 = new Vex.Flow.NoteHead({
32 | duration: "4",
33 | line: 3
34 | });
35 |
36 | var note_head2 = new Vex.Flow.NoteHead({
37 | duration: "1",
38 | line: 2.5
39 | });
40 |
41 | var note_head3 = new Vex.Flow.NoteHead({
42 | duration: "2",
43 | line: 0
44 | });
45 |
46 | voice.addTickables([note_head1, note_head2, note_head3]);
47 | formatter.joinVoices([voice]).formatToStave([voice], c.stave);
48 |
49 | voice.draw(c.context, c.stave);
50 |
51 | ok("Basic NoteHead test");
52 | };
53 |
54 | Vex.Flow.Test.NoteHead.basicBoundingBoxes = function(options, contextBuilder){
55 | options.contextBuilder = contextBuilder;
56 | var c = Vex.Flow.Test.NoteHead.setupContext(options, 350, 250);
57 |
58 | c.stave = new Vex.Flow.Stave(10, 0, 250).addTrebleGlyph();
59 |
60 | c.context.scale(2.0, 2.0);
61 | c.stave.setContext(c.context).draw();
62 |
63 | var formatter = new Vex.Flow.Formatter();
64 | var voice = new Vex.Flow.Voice(Vex.Flow.TIME4_4).setStrict(false);
65 |
66 | var note_head1 = new Vex.Flow.NoteHead({
67 | duration: "4",
68 | line: 3
69 | });
70 |
71 | var note_head2 = new Vex.Flow.NoteHead({
72 | duration: "2",
73 | line: 2.5
74 | });
75 |
76 | var note_head3 = new Vex.Flow.NoteHead({
77 | duration: "1",
78 | line: 0
79 | });
80 |
81 | voice.addTickables([note_head1, note_head2, note_head3]);
82 | formatter.joinVoices([voice]).formatToStave([voice], c.stave);
83 |
84 | voice.draw(c.context, c.stave);
85 |
86 | note_head1.getBoundingBox().draw(c.context);
87 | note_head2.getBoundingBox().draw(c.context);
88 | note_head3.getBoundingBox().draw(c.context);
89 |
90 | ok("NoteHead Bounding Boxes");
91 | };
92 |
93 |
--------------------------------------------------------------------------------
/tests/stavemodifier_tests.js:
--------------------------------------------------------------------------------
1 | // VexFlow - Basic Tests
2 |
3 | Vex.Flow.Test.StaveModifier = {}
4 |
5 | Vex.Flow.Test.StaveModifier.Start = function() {
6 | module("StaveModifier");
7 | Vex.Flow.Test.runTest("Stave Draw Test (Canvas)", Vex.Flow.Test.Stave.draw);
8 | Vex.Flow.Test.runTest("Vertical Bar Test (Canvas)",
9 | Vex.Flow.Test.Stave.drawVerticalBar);
10 | Vex.Flow.Test.runRaphaelTest("Stave Draw Test (Raphael)",
11 | Vex.Flow.Test.Stave.draw);
12 | Vex.Flow.Test.runRaphaelTest("Vertical Bar Test (Raphael)",
13 | Vex.Flow.Test.Stave.drawVerticalBar);
14 | }
15 |
16 | Vex.Flow.Test.Stave.draw = function(options, contextBuilder) {
17 | var ctx = new contextBuilder(options.canvas_sel, 400, 120);
18 | var stave = new Vex.Flow.Stave(10, 10, 300);
19 | stave.setContext(ctx);
20 | stave.draw();
21 |
22 | equal(stave.getYForNote(0), 100, "getYForNote(0)");
23 | equal(stave.getYForLine(5), 100, "getYForLine(5)");
24 | equal(stave.getYForLine(0), 50, "getYForLine(0) - Top Line");
25 | equal(stave.getYForLine(4), 90, "getYForLine(4) - Bottom Line");
26 |
27 | ok(true, "all pass");
28 | }
29 |
30 | Vex.Flow.Test.Stave.drawVerticalBar = function(options, contextBuilder) {
31 | var ctx = contextBuilder(options.canvas_sel, 400, 120);
32 | var stave = new Vex.Flow.Stave(10, 10, 300);
33 | stave.setContext(ctx);
34 | stave.draw();
35 | stave.drawVerticalBar(100);
36 | stave.drawVerticalBar(150);
37 | stave.drawVerticalBar(300);
38 |
39 | ok(true, "all pass");
40 | }
41 |
--------------------------------------------------------------------------------
/tests/stavetie_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - StaveTie Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.StaveTie = {}
7 |
8 | Vex.Flow.Test.StaveTie.Start = function() {
9 | module("StaveTie");
10 | Vex.Flow.Test.runTest("Simple StaveTie", Vex.Flow.Test.StaveTie.simple);
11 | Vex.Flow.Test.runTest("Chord StaveTie", Vex.Flow.Test.StaveTie.chord);
12 | Vex.Flow.Test.runTest("Stem Up StaveTie", Vex.Flow.Test.StaveTie.stemUp);
13 | Vex.Flow.Test.runTest("No End Note", Vex.Flow.Test.StaveTie.noEndNote);
14 | Vex.Flow.Test.runTest("No Start Note", Vex.Flow.Test.StaveTie.noStartNote);
15 | }
16 |
17 | Vex.Flow.Test.StaveTie.tieNotes = function(notes, indices, stave, ctx) {
18 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4);
19 | voice.addTickables(notes);
20 |
21 | var formatter = new Vex.Flow.Formatter().joinVoices([voice]).
22 | format([voice], 250);
23 | voice.draw(ctx, stave);
24 |
25 | var tie = new Vex.Flow.StaveTie({
26 | first_note: notes[0],
27 | last_note: notes[1],
28 | first_indices: indices,
29 | last_indices: indices,
30 | });
31 |
32 | tie.setContext(ctx);
33 | tie.draw();
34 | }
35 |
36 | Vex.Flow.Test.StaveTie.drawTie = function(notes, indices, options) {
37 | var ctx = new options.contextBuilder(options.canvas_sel, 350, 140);
38 |
39 | ctx.scale(0.9, 0.9); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
40 | var stave = new Vex.Flow.Stave(10, 10, 350).setContext(ctx).draw();
41 |
42 | Vex.Flow.Test.StaveTie.tieNotes(notes, indices, stave, ctx);
43 | }
44 |
45 | Vex.Flow.Test.StaveTie.simple = function(options, contextBuilder) {
46 | options.contextBuilder = contextBuilder;
47 | function newNote(note_struct) { return new Vex.Flow.StaveNote(note_struct); }
48 | function newAcc(type) { return new Vex.Flow.Accidental(type); }
49 |
50 | Vex.Flow.Test.StaveTie.drawTie([
51 | newNote({ keys: ["c/4", "e/4", "a/4"], stem_direction: -1, duration: "h"}).
52 | addAccidental(0, newAcc("b")).
53 | addAccidental(1, newAcc("#")),
54 | newNote({ keys: ["d/4", "e/4", "f/4"], stem_direction: -1, duration: "h"})
55 | ], [0, 1], options);
56 | ok(true, "Simple Test");
57 | }
58 |
59 | Vex.Flow.Test.StaveTie.chord = function(options, contextBuilder) {
60 | options.contextBuilder = contextBuilder;
61 | function newNote(note_struct) { return new Vex.Flow.StaveNote(note_struct); }
62 | function newAcc(type) { return new Vex.Flow.Accidental(type); }
63 |
64 | Vex.Flow.Test.StaveTie.drawTie([
65 | newNote({ keys: ["d/4", "e/4", "f/4"], stem_direction: -1, duration: "h"}),
66 | newNote({ keys: ["c/4", "f/4", "a/4"], stem_direction: -1, duration: "h"}).
67 | addAccidental(0, newAcc("n")).
68 | addAccidental(1, newAcc("#")),
69 | ], [0, 1, 2], options);
70 | ok(true, "Chord test");
71 | }
72 |
73 | Vex.Flow.Test.StaveTie.stemUp = function(options, contextBuilder) {
74 | options.contextBuilder = contextBuilder;
75 | function newNote(note_struct) { return new Vex.Flow.StaveNote(note_struct); }
76 | function newAcc(type) { return new Vex.Flow.Accidental(type); }
77 |
78 | Vex.Flow.Test.StaveTie.drawTie([
79 | newNote({ keys: ["d/4", "e/4", "f/4"], stem_direction: 1, duration: "h"}),
80 | newNote({ keys: ["c/4", "f/4", "a/4"], stem_direction: 1, duration: "h"}).
81 | addAccidental(0, newAcc("n")).
82 | addAccidental(1, newAcc("#")),
83 | ], [0, 1, 2], options);
84 | ok(true, "Stem up test");
85 | }
86 |
87 | Vex.Flow.Test.StaveTie.noEndNote = function(options, contextBuilder) {
88 | var ctx = contextBuilder(options.canvas_sel, 350, 140);
89 | ctx.scale(0.9, 0.9); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
90 | ctx.font = "10pt Arial";
91 | var stave = new Vex.Flow.Stave(10, 10, 350).setContext(ctx).draw();
92 |
93 | function newNote(note_struct) { return new Vex.Flow.StaveNote(note_struct); }
94 | function newAcc(type) { return new Vex.Flow.Accidental(type); }
95 |
96 | notes = [
97 | newNote({ keys: ["c/4", "e/4", "a/4"], stem_direction: -1, duration: "h"}).
98 | addAccidental(0, newAcc("b")).
99 | addAccidental(1, newAcc("#")),
100 | newNote({ keys: ["d/4", "e/4", "f/4"], stem_direction: -1, duration: "h"})
101 | ];
102 |
103 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4);
104 | voice.addTickables(notes);
105 |
106 | var formatter = new Vex.Flow.Formatter().joinVoices([voice]).
107 | format([voice], 250);
108 | voice.draw(ctx, stave);
109 |
110 | var tie = new Vex.Flow.StaveTie({
111 | first_note: notes[1],
112 | last_note: null,
113 | first_indices: [2],
114 | last_indices: [2]
115 | }, "slow.").setContext(ctx).draw();
116 |
117 | ok(true, "No end note");
118 | }
119 |
120 | Vex.Flow.Test.StaveTie.noStartNote = function(options, contextBuilder) {
121 | var ctx = contextBuilder(options.canvas_sel, 350, 140);
122 | ctx.scale(0.9, 0.9); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
123 | ctx.font = "10pt Arial";
124 | var stave = new Vex.Flow.Stave(10, 10, 350).addTrebleGlyph().
125 | setContext(ctx).draw();
126 |
127 | function newNote(note_struct) { return new Vex.Flow.StaveNote(note_struct); }
128 | function newAcc(type) { return new Vex.Flow.Accidental(type); }
129 |
130 | notes = [
131 | newNote({ keys: ["c/4", "e/4", "a/4"], stem_direction: -1, duration: "h"}).
132 | addAccidental(0, newAcc("b")).
133 | addAccidental(1, newAcc("#")),
134 | newNote({ keys: ["d/4", "e/4", "f/4"], stem_direction: -1, duration: "h"})
135 | ];
136 |
137 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4);
138 | voice.addTickables(notes);
139 |
140 | var formatter = new Vex.Flow.Formatter().joinVoices([voice]).
141 | format([voice], 250);
142 | voice.draw(ctx, stave);
143 |
144 | var tie = new Vex.Flow.StaveTie({
145 | first_note: null,
146 | last_note: notes[0],
147 | first_indices: [2],
148 | last_indices: [2],
149 | }, "H").setContext(ctx).draw();
150 |
151 | ok(true, "No end note");
152 | }
153 |
--------------------------------------------------------------------------------
/tests/support/qunit.css:
--------------------------------------------------------------------------------
1 | /**
2 | * QUnit v1.10.0pre - A JavaScript Unit Testing Framework
3 | *
4 | * http://qunitjs.com
5 | *
6 | * Copyright 2012 jQuery Foundation and other contributors
7 | * Dual licensed under the MIT or GPL Version 2 licenses.
8 | * http://jquery.org/license
9 | */
10 |
11 | /** Font Family and Sizes */
12 |
13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult {
14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif;
15 | }
16 |
17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; }
18 | #qunit-tests { font-size: smaller; }
19 |
20 |
21 | /** Resets */
22 |
23 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult {
24 | margin: 0;
25 | padding: 0;
26 | }
27 |
28 |
29 | /** Header */
30 |
31 | #qunit-header {
32 | padding: 0.5em 0 0.5em 1em;
33 |
34 | color: #8699a4;
35 | background-color: #0d3349;
36 |
37 | font-size: 1.5em;
38 | line-height: 1em;
39 | font-weight: normal;
40 |
41 | border-radius: 5px 5px 0 0;
42 | -moz-border-radius: 5px 5px 0 0;
43 | -webkit-border-top-right-radius: 5px;
44 | -webkit-border-top-left-radius: 5px;
45 | }
46 |
47 | #qunit-header a {
48 | text-decoration: none;
49 | color: #c2ccd1;
50 | }
51 |
52 | #qunit-header a:hover,
53 | #qunit-header a:focus {
54 | color: #fff;
55 | }
56 |
57 | #qunit-testrunner-toolbar label {
58 | display: inline-block;
59 | padding: 0 .5em 0 .1em;
60 | }
61 |
62 | #qunit-banner {
63 | height: 5px;
64 | }
65 |
66 | #qunit-testrunner-toolbar {
67 | padding: 0.5em 0 0.5em 2em;
68 | color: #5E740B;
69 | background-color: #eee;
70 | }
71 |
72 | #qunit-userAgent {
73 | padding: 0.5em 0 0.5em 2.5em;
74 | background-color: #2b81af;
75 | color: #fff;
76 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
77 | }
78 |
79 |
80 | /** Tests: Pass/Fail */
81 |
82 | #qunit-tests {
83 | list-style-position: inside;
84 | }
85 |
86 | #qunit-tests li {
87 | padding: 0.4em 0.5em 0.4em 2.5em;
88 | border-bottom: 1px solid #fff;
89 | list-style-position: inside;
90 | }
91 |
92 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
93 | display: none;
94 | }
95 |
96 | #qunit-tests li strong {
97 | cursor: pointer;
98 | }
99 |
100 | #qunit-tests li a {
101 | padding: 0.5em;
102 | color: #c2ccd1;
103 | text-decoration: none;
104 | }
105 | #qunit-tests li a:hover,
106 | #qunit-tests li a:focus {
107 | color: #000;
108 | }
109 |
110 | #qunit-tests ol {
111 | margin-top: 0.5em;
112 | padding: 0.5em;
113 |
114 | background-color: #fff;
115 |
116 | border-radius: 5px;
117 | -moz-border-radius: 5px;
118 | -webkit-border-radius: 5px;
119 | }
120 |
121 | #qunit-tests table {
122 | border-collapse: collapse;
123 | margin-top: .2em;
124 | }
125 |
126 | #qunit-tests th {
127 | text-align: right;
128 | vertical-align: top;
129 | padding: 0 .5em 0 0;
130 | }
131 |
132 | #qunit-tests td {
133 | vertical-align: top;
134 | }
135 |
136 | #qunit-tests pre {
137 | margin: 0;
138 | white-space: pre-wrap;
139 | word-wrap: break-word;
140 | }
141 |
142 | #qunit-tests del {
143 | background-color: #e0f2be;
144 | color: #374e0c;
145 | text-decoration: none;
146 | }
147 |
148 | #qunit-tests ins {
149 | background-color: #ffcaca;
150 | color: #500;
151 | text-decoration: none;
152 | }
153 |
154 | /*** Test Counts */
155 |
156 | #qunit-tests b.counts { color: black; }
157 | #qunit-tests b.passed { color: #5E740B; }
158 | #qunit-tests b.failed { color: #710909; }
159 |
160 | #qunit-tests li li {
161 | padding: 5px;
162 | background-color: #fff;
163 | border-bottom: none;
164 | list-style-position: inside;
165 | }
166 |
167 | /*** Passing Styles */
168 |
169 | #qunit-tests li li.pass {
170 | color: #3c510c;
171 | background-color: #fff;
172 | border-left: 10px solid #C6E746;
173 | }
174 |
175 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; }
176 | #qunit-tests .pass .test-name { color: #366097; }
177 |
178 | #qunit-tests .pass .test-actual,
179 | #qunit-tests .pass .test-expected { color: #999999; }
180 |
181 | #qunit-banner.qunit-pass { background-color: #C6E746; }
182 |
183 | /*** Failing Styles */
184 |
185 | #qunit-tests li li.fail {
186 | color: #710909;
187 | background-color: #fff;
188 | border-left: 10px solid #EE5757;
189 | white-space: pre;
190 | }
191 |
192 | #qunit-tests > li:last-child {
193 | border-radius: 0 0 5px 5px;
194 | -moz-border-radius: 0 0 5px 5px;
195 | -webkit-border-bottom-right-radius: 5px;
196 | -webkit-border-bottom-left-radius: 5px;
197 | }
198 |
199 | #qunit-tests .fail { color: #000000; background-color: #EE5757; }
200 | #qunit-tests .fail .test-name,
201 | #qunit-tests .fail .module-name { color: #000000; }
202 |
203 | #qunit-tests .fail .test-actual { color: #EE5757; }
204 | #qunit-tests .fail .test-expected { color: green; }
205 |
206 | #qunit-banner.qunit-fail { background-color: #EE5757; }
207 |
208 |
209 | /** Result */
210 |
211 | #qunit-testresult {
212 | padding: 0.5em 0.5em 0.5em 2.5em;
213 |
214 | color: #2b81af;
215 | background-color: #D2E0E6;
216 |
217 | border-bottom: 1px solid white;
218 | }
219 | #qunit-testresult .module-name {
220 | font-weight: bold;
221 | }
222 |
223 | /** Fixture */
224 |
225 | #qunit-fixture {
226 | position: absolute;
227 | top: -10000px;
228 | left: -10000px;
229 | width: 1000px;
230 | height: 1000px;
231 | }
232 |
--------------------------------------------------------------------------------
/tests/tabslide_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - TabSlide Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.TabSlide = {}
7 |
8 | Vex.Flow.Test.TabSlide.Start = function() {
9 | module("TabSlide");
10 | Vex.Flow.Test.runTest("Simple TabSlide", Vex.Flow.Test.TabSlide.simple);
11 | Vex.Flow.Test.runTest("Slide Up", Vex.Flow.Test.TabSlide.slideUp);
12 | Vex.Flow.Test.runTest("Slide Down", Vex.Flow.Test.TabSlide.slideDown);
13 | }
14 |
15 | Vex.Flow.Test.TabSlide.tieNotes = function(notes, indices, stave, ctx) {
16 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4);
17 | voice.addTickables(notes);
18 |
19 | var formatter = new Vex.Flow.Formatter().joinVoices([voice]).
20 | format([voice], 100);
21 | voice.draw(ctx, stave);
22 |
23 | var tie = new Vex.Flow.TabSlide({
24 | first_note: notes[0],
25 | last_note: notes[1],
26 | first_indices: indices,
27 | last_indices: indices,
28 | }, Vex.Flow.TabSlide.SLIDE_UP);
29 |
30 | tie.setContext(ctx);
31 | tie.draw();
32 | }
33 |
34 | Vex.Flow.Test.TabSlide.setupContext = function(options, x, y) {
35 | var ctx = options.contextBuilder(options.canvas_sel, 350, 140);
36 | ctx.scale(0.9, 0.9); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
37 | ctx.font = "10pt Arial";
38 | var stave = new Vex.Flow.TabStave(10, 10, x || 350).addTabGlyph().
39 | setContext(ctx).draw();
40 |
41 | return {context: ctx, stave: stave};
42 | }
43 |
44 |
45 | Vex.Flow.Test.TabSlide.simple = function(options, contextBuilder) {
46 | options.contextBuilder = contextBuilder;
47 | var c = Vex.Flow.Test.TabSlide.setupContext(options);
48 | function newNote(tab_struct) { return new Vex.Flow.TabNote(tab_struct); }
49 |
50 | Vex.Flow.Test.TabSlide.tieNotes([
51 | newNote({ positions: [{str:4, fret:4}], duration: "h"}),
52 | newNote({ positions: [{str:4, fret:6}], duration: "h"})
53 | ], [0], c.stave, c.context);
54 | ok(true, "Simple Test");
55 | }
56 |
57 | Vex.Flow.Test.TabSlide.multiTest = function(options, factory) {
58 | var c = Vex.Flow.Test.TabSlide.setupContext(options, 440, 100);
59 | function newNote(tab_struct) { return new Vex.Flow.TabNote(tab_struct); }
60 |
61 | var notes = [
62 | newNote({ positions: [{str:4, fret:4}], duration: "8"}),
63 | newNote({ positions: [{str:4, fret:4}], duration: "8"}),
64 | newNote({ positions: [{str:4, fret:4}, {str:5, fret:4}], duration: "8"}),
65 | newNote({ positions: [{str:4, fret:6}, {str:5, fret:6}], duration: "8"}),
66 | newNote({ positions: [{str:2, fret:14}], duration: "8"}),
67 | newNote({ positions: [{str:2, fret:16}], duration: "8"}),
68 | newNote({ positions: [{str:2, fret:14}, {str:3, fret:14}], duration: "8"}),
69 | newNote({ positions: [{str:2, fret:16}, {str:3, fret:16}], duration: "8"})
70 | ];
71 |
72 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4).addTickables(notes);
73 | var formatter = new Vex.Flow.Formatter().joinVoices([voice]).
74 | format([voice], 300);
75 | voice.draw(c.context, c.stave);
76 |
77 | factory({
78 | first_note: notes[0],
79 | last_note: notes[1],
80 | first_indices: [0],
81 | last_indices: [0],
82 | }).setContext(c.context).draw();
83 |
84 | ok(true, "Single note");
85 |
86 | factory({
87 | first_note: notes[2],
88 | last_note: notes[3],
89 | first_indices: [0, 1],
90 | last_indices: [0, 1],
91 | }).setContext(c.context).draw();
92 |
93 | ok(true, "Chord");
94 |
95 | factory({
96 | first_note: notes[4],
97 | last_note: notes[5],
98 | first_indices: [0],
99 | last_indices: [0],
100 | }).setContext(c.context).draw();
101 |
102 | ok(true, "Single note high-fret");
103 |
104 | factory({
105 | first_note: notes[6],
106 | last_note: notes[7],
107 | first_indices: [0, 1],
108 | last_indices: [0, 1],
109 | }).setContext(c.context).draw();
110 |
111 | ok(true, "Chord high-fret");
112 | }
113 |
114 | Vex.Flow.Test.TabSlide.slideUp = function(options, contextBuilder) {
115 | options.contextBuilder = contextBuilder;
116 | Vex.Flow.Test.TabSlide.multiTest(options, Vex.Flow.TabSlide.createSlideUp);
117 | }
118 |
119 | Vex.Flow.Test.TabSlide.slideDown = function(options, contextBuilder) {
120 | options.contextBuilder = contextBuilder;
121 | Vex.Flow.Test.TabSlide.multiTest(options, Vex.Flow.TabSlide.createSlideDown);
122 | }
123 |
--------------------------------------------------------------------------------
/tests/tabstave_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Basic Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.TabStave = {}
7 |
8 | Vex.Flow.Test.TabStave.Start = function() {
9 | module("TabStave");
10 | Vex.Flow.Test.runRaphaelTest("TabStave Draw Test (Raphael)",
11 | Vex.Flow.Test.TabStave.draw);
12 | Vex.Flow.Test.runRaphaelTest("Vertical Bar Test (Raphael)",
13 | Vex.Flow.Test.TabStave.drawVerticalBar);
14 | Vex.Flow.Test.runTest("TabStave Draw Test", Vex.Flow.Test.TabStave.draw);
15 | Vex.Flow.Test.runTest("Vertical Bar Test",
16 | Vex.Flow.Test.TabStave.drawVerticalBar);
17 | }
18 |
19 | Vex.Flow.Test.TabStave.draw = function(options, contextBuilder) {
20 | var ctx = new contextBuilder(options.canvas_sel,
21 | 400, 160);
22 |
23 | var stave = new Vex.Flow.TabStave(10, 10, 300);
24 | stave.setNumLines(6);
25 | stave.setContext(ctx);
26 | stave.draw();
27 |
28 | equal(stave.getYForNote(0), 127, "getYForNote(0)");
29 | equal(stave.getYForLine(5), 126, "getYForLine(5)");
30 | equal(stave.getYForLine(0), 61, "getYForLine(0) - Top Line");
31 | equal(stave.getYForLine(4), 113, "getYForLine(4) - Bottom Line");
32 |
33 | ok(true, "all pass");
34 | }
35 |
36 | Vex.Flow.Test.TabStave.drawVerticalBar = function(options, contextBuilder) {
37 | var ctx = new contextBuilder(options.canvas_sel,
38 | 400, 160);
39 |
40 | var stave = new Vex.Flow.TabStave(10, 10, 300);
41 | stave.setNumLines(6);
42 | stave.setContext(ctx);
43 | stave.drawVerticalBar(50, true);
44 | stave.drawVerticalBar(100, true);
45 | stave.drawVerticalBar(150, false);
46 | stave.setEndBarType(Vex.Flow.Barline.type.END);
47 | stave.draw();
48 |
49 | ok(true, "all pass");
50 | }
51 |
--------------------------------------------------------------------------------
/tests/tickcontext_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - TickContext Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.TickContext = {}
7 |
8 | Vex.Flow.Test.TickContext.Start = function() {
9 | module("TickContext");
10 | test("Current Tick Test", Vex.Flow.Test.TickContext.currentTick);
11 | test("Tracking Test", Vex.Flow.Test.TickContext.tracking);
12 | }
13 |
14 | Vex.Flow.Test.TickContext.currentTick = function() {
15 | var tc = new Vex.Flow.TickContext();
16 | equal(tc.getCurrentTick().value(), 0, "New tick context has no ticks");
17 | }
18 |
19 | Vex.Flow.Test.TickContext.tracking = function() {
20 | function createTickable() {
21 | return new Vex.Flow.Test.MockTickable(Vex.Flow.Test.TIME4_4);
22 | }
23 |
24 | var R = Vex.Flow.RESOLUTION;
25 | var BEAT = 1 * R / 4;
26 |
27 | var tickables = [
28 | createTickable().setTicks(BEAT).setWidth(10),
29 | createTickable().setTicks(BEAT * 2).setWidth(20),
30 | createTickable().setTicks(BEAT).setWidth(30)
31 | ];
32 |
33 | var tc = new Vex.Flow.TickContext();
34 | tc.setPadding(0);
35 |
36 | tc.addTickable(tickables[0]);
37 | equal(tc.getMaxTicks().value(), BEAT);
38 |
39 | tc.addTickable(tickables[1]);
40 | equal(tc.getMaxTicks().value(), BEAT * 2);
41 |
42 | tc.addTickable(tickables[2]);
43 | equal(tc.getMaxTicks().value(), BEAT * 2);
44 |
45 | equal(tc.getWidth(), 0);
46 | tc.preFormat();
47 | equal(tc.getWidth(), 30);
48 | }
49 |
--------------------------------------------------------------------------------
/tests/tuning_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Tuning Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.Tuning = {}
7 |
8 | Vex.Flow.Test.Tuning.Start = function() {
9 | module("Tuning");
10 | test("Standard Tuning", Vex.Flow.Test.Tuning.standard);
11 | test("Return note for fret", Vex.Flow.Test.Tuning.noteForFret);
12 | }
13 |
14 | Vex.Flow.Test.Tuning.checkStandard = function(tuning) {
15 | try {
16 | tuning.getValueForString(0);
17 | } catch (e) {
18 | equal(e.code, "BadArguments", "String 0");
19 | }
20 |
21 | try {
22 | tuning.getValueForString(9);
23 | } catch (e) {
24 | equal(e.code, "BadArguments", "String 7");
25 | }
26 |
27 | equal(tuning.getValueForString(6), 40, "Low E string");
28 | equal(tuning.getValueForString(5), 45, "A string");
29 | equal(tuning.getValueForString(4), 50, "D string");
30 | equal(tuning.getValueForString(3), 55, "G string");
31 | equal(tuning.getValueForString(2), 59, "B string");
32 | equal(tuning.getValueForString(1), 64, "High E string");
33 | }
34 |
35 | Vex.Flow.Test.Tuning.standard = function() {
36 | expect(16);
37 |
38 | var tuning = new Vex.Flow.Tuning();
39 | Vex.Flow.Test.Tuning.checkStandard(tuning);
40 |
41 | // Test named tuning
42 | tuning.setTuning("standard");
43 | Vex.Flow.Test.Tuning.checkStandard(tuning);
44 | }
45 |
46 | Vex.Flow.Test.Tuning.noteForFret = function() {
47 | expect(8);
48 | var tuning = new Vex.Flow.Tuning("E/5,B/4,G/4,D/4,A/3,E/3");
49 | try {
50 | tuning.getNoteForFret(-1, 1);
51 | } catch(e) {
52 | equal(e.code, "BadArguments", "Fret -1");
53 | }
54 |
55 | try {
56 | tuning.getNoteForFret(1, -1);
57 | } catch(e) {
58 | equal(e.code, "BadArguments", "String -1");
59 | }
60 |
61 | equal(tuning.getNoteForFret(0, 1), "E/5", "High E string");
62 | equal(tuning.getNoteForFret(5, 1), "A/5", "High E string, fret 5");
63 | equal(tuning.getNoteForFret(0, 2), "B/4", "B string");
64 | equal(tuning.getNoteForFret(0, 3), "G/4", "G string");
65 | equal(tuning.getNoteForFret(12, 2), "B/5", "B string, fret 12");
66 | equal(tuning.getNoteForFret(0, 6), "E/3", "Low E string");
67 | }
68 |
--------------------------------------------------------------------------------
/tests/vexflow_test_helpers.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow Test Support Library
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test = {}
7 |
8 | Vex.Flow.Test.Font = {size: 10}
9 |
10 | Vex.Flow.Test.genID = function() {
11 | return Vex.Flow.Test.genID.ID++;
12 | }
13 | Vex.Flow.Test.genID.ID = 0;
14 |
15 | Vex.Flow.setupCanvasArray = function () { return ""; }
16 | Vex.Flow.Test.createTestCanvas = function(canvas_sel_name, test_name) {
17 | var sel = Vex.Flow.Test.createTestCanvas.sel;
18 | var test_div = $('').addClass("testcanvas");
19 | test_div.append($('').addClass("name").text(test_name));
20 | test_div.append($('').addClass("vex-tabdiv").
21 | attr("id", canvas_sel_name).
22 | addClass("name").text(name));
23 | $(sel).append(test_div);
24 | }
25 | Vex.Flow.Test.createTestCanvas.sel = "#vexflow_testoutput";
26 |
27 | Vex.Flow.Test.createTestRaphael = function(canvas_sel_name, test_name) {
28 | var sel = Vex.Flow.Test.createTestCanvas.sel;
29 | var test_div = $('').addClass("testcanvas");
30 | test_div.append($('').addClass("name").text(test_name));
31 | test_div.append($('').addClass("vex-tabdiv").
32 | attr("id", canvas_sel_name));
33 | $(sel).append(test_div);
34 | }
35 |
36 | Vex.Flow.Test.resizeCanvas = function(sel, width, height) {
37 | $("#" + sel).width(width);
38 | $("#" + sel).attr("width", width);
39 | $("#" + sel).attr("height", height);
40 | }
41 |
42 | Vex.Flow.Test.runTest = function(name, func, params) {
43 | test(name, function() {
44 | test_canvas_sel = "canvas_" + Vex.Flow.Test.genID();
45 | test_canvas = Vex.Flow.Test.createTestCanvas(test_canvas_sel, name);
46 | func({ canvas_sel: test_canvas_sel, params: params },
47 | Vex.Flow.Renderer.getCanvasContext);
48 | });
49 | }
50 |
51 | Vex.Flow.Test.runRaphaelTest = function(name, func, params) {
52 | test(name, function() {
53 | test_canvas_sel = "canvas_" + Vex.Flow.Test.genID();
54 | test_canvas = Vex.Flow.Test.createTestRaphael(test_canvas_sel, name);
55 | func({ canvas_sel: test_canvas_sel, params: params },
56 | Vex.Flow.Renderer.getRaphaelContext);
57 | });
58 | }
59 |
--------------------------------------------------------------------------------
/tests/vibrato_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Vibrato Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.Vibrato = {}
7 |
8 | Vex.Flow.Test.Vibrato.Start = function() {
9 | module("Vibrato");
10 | Vex.Flow.Test.runTest("Simple Vibrato", Vex.Flow.Test.Vibrato.simple);
11 | Vex.Flow.Test.runTest("Harsh Vibrato", Vex.Flow.Test.Vibrato.harsh);
12 | Vex.Flow.Test.runTest("Vibrato with Bend", Vex.Flow.Test.Vibrato.withBend);
13 | Vex.Flow.Test.runRaphaelTest("Vibrato with Bend (Raphael)",
14 | Vex.Flow.Test.Vibrato.withBend);
15 | }
16 |
17 | Vex.Flow.Test.Vibrato.simple = function(options, contextBuilder) {
18 | var ctx = new contextBuilder(options.canvas_sel, 500, 140);
19 |
20 | ctx.scale(1.5, 1.5); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
21 | ctx.font = "10pt Arial";
22 | var stave = new Vex.Flow.TabStave(10, 10, 450).
23 | addTabGlyph().setContext(ctx).draw();
24 |
25 | function newNote(tab_struct) { return new Vex.Flow.TabNote(tab_struct); }
26 | function newVibrato() { return new Vex.Flow.Vibrato(); }
27 |
28 | var notes = [
29 | newNote({
30 | positions: [{str: 2, fret: 10}, {str: 4, fret: 9}], duration: "h" }).
31 | addModifier(newVibrato(), 0),
32 | newNote({
33 | positions: [{str: 2, fret: 10}], duration: "h" }).
34 | addModifier(newVibrato(), 0)
35 | ];
36 |
37 | Vex.Flow.Formatter.FormatAndDraw(ctx, stave, notes);
38 | ok(true, "Simple Vibrato");
39 | }
40 |
41 | Vex.Flow.Test.Vibrato.harsh = function(options, contextBuilder) {
42 | var ctx = new contextBuilder(options.canvas_sel, 500, 240);
43 |
44 | ctx.scale(1.5, 1.5); ctx.fillStyle = "#221"; ctx.strokeStyle = "#221";
45 | ctx.font = "10pt Arial";
46 | var stave = new Vex.Flow.TabStave(10, 10, 450).
47 | addTabGlyph().setContext(ctx).draw();
48 |
49 | function newNote(tab_struct) { return new Vex.Flow.TabNote(tab_struct); }
50 | function newVibrato() { return new Vex.Flow.Vibrato(); }
51 |
52 | var notes = [
53 | newNote({
54 | positions: [{str: 2, fret: 10}, {str: 4, fret: 9}], duration: "h" }).
55 | addModifier(newVibrato().setHarsh(true), 0),
56 | newNote({
57 | positions: [{str: 2, fret: 10}], duration: "h" }).
58 | addModifier(newVibrato().setHarsh(true), 0)
59 | ];
60 |
61 | Vex.Flow.Formatter.FormatAndDraw(ctx, stave, notes);
62 | ok(true, "Harsh Vibrato");
63 | }
64 |
65 | Vex.Flow.Test.Vibrato.withBend = function(options, contextBuilder) {
66 | var ctx = new contextBuilder(options.canvas_sel, 500, 240);
67 | ctx.scale(1.3, 1.3); ctx.setFillStyle("#221"); ctx.setStrokeStyle("#221");
68 | ctx.setFont("Arial", Vex.Flow.Test.Font.size, "");
69 | var stave = new Vex.Flow.TabStave(10, 10, 450).
70 | addTabGlyph().setContext(ctx).draw();
71 |
72 | function newNote(tab_struct) { return new Vex.Flow.TabNote(tab_struct); }
73 | function newBend(text, release) { return new Vex.Flow.Bend(text, release); }
74 | function newVibrato() { return new Vex.Flow.Vibrato(); }
75 |
76 | var notes = [
77 | newNote({
78 | positions: [{str: 2, fret: 9}, {str: 3, fret: 9}], duration: "q" }).
79 | addModifier(newBend("1/2", true), 0).
80 | addModifier(newBend("1/2", true), 1).
81 | addModifier(newVibrato(), 0),
82 | newNote({
83 | positions: [{str: 2, fret: 10}], duration: "q" }).
84 | addModifier(newBend("Full", false), 0).
85 | addModifier(newVibrato().setVibratoWidth(60), 0),
86 | newNote({
87 | positions: [{str: 2, fret: 10}], duration: "h" }).
88 | addModifier(newVibrato().setVibratoWidth(120).setHarsh(true), 0)
89 | ];
90 |
91 | Vex.Flow.Formatter.FormatAndDraw(ctx, stave, notes);
92 | ok(true, "Vibrato with Bend");
93 | }
94 |
--------------------------------------------------------------------------------
/tests/voice_tests.js:
--------------------------------------------------------------------------------
1 | /**
2 | * VexFlow - Voice Tests
3 | * Copyright Mohit Muthanna 2010
4 | */
5 |
6 | Vex.Flow.Test.Voice = {}
7 |
8 | Vex.Flow.Test.Voice.Start = function() {
9 | module("Voice");
10 | test("Strict Test", Vex.Flow.Test.Voice.strict);
11 | test("Ignore Test", Vex.Flow.Test.Voice.ignore);
12 | Vex.Flow.Test.runTest("Full Voice Mode Test", Vex.Flow.Test.Voice.full);
13 | }
14 |
15 | Vex.Flow.Test.Voice.strict = function(options) {
16 | expect(7);
17 | function createTickable() {
18 | return new Vex.Flow.Test.MockTickable(Vex.Flow.Test.TIME4_4);
19 | }
20 |
21 | var R = Vex.Flow.RESOLUTION;
22 | var BEAT = 1 * R / 4;
23 |
24 | var tickables = [
25 | createTickable().setTicks(BEAT),
26 | createTickable().setTicks(BEAT),
27 | createTickable().setTicks(BEAT)
28 | ];
29 |
30 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4);
31 | equal(voice.totalTicks.value(), BEAT * 4, "4/4 Voice has 4 beats");
32 | equal(voice.ticksUsed.value(), BEAT * 0, "No beats in voice");
33 | voice.addTickables(tickables);
34 | equal(voice.ticksUsed.value(), BEAT * 3, "Three beats in voice");
35 | voice.addTickable(createTickable().setTicks(BEAT));
36 | equal(voice.ticksUsed.value(), BEAT * 4, "Four beats in voice");
37 | equal(voice.isComplete(), true, "Voice is complete");
38 |
39 | try {
40 | voice.addTickable(createTickable().setTicks(BEAT));
41 | } catch (e) {
42 | equal(e.code, "BadArgument", "Too many ticks exception");
43 | }
44 |
45 | equal(voice.getSmallestTickCount().value(), BEAT, "Smallest tick count is BEAT");
46 | }
47 |
48 | Vex.Flow.Test.Voice.ignore = function() {
49 | function createTickable() {
50 | return new Vex.Flow.Test.MockTickable(Vex.Flow.Test.TIME4_4);
51 | }
52 |
53 | var R = Vex.Flow.RESOLUTION;
54 | var BEAT = 1 * R / 4;
55 |
56 | var tickables = [
57 | createTickable().setTicks(BEAT),
58 | createTickable().setTicks(BEAT),
59 | createTickable().setTicks(BEAT).setIgnoreTicks(true),
60 | createTickable().setTicks(BEAT),
61 | createTickable().setTicks(BEAT).setIgnoreTicks(true),
62 | createTickable().setTicks(BEAT)
63 | ];
64 |
65 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4);
66 | voice.addTickables(tickables);
67 | ok(true, "all pass");
68 | }
69 |
70 | Vex.Flow.Test.Voice.full = function(options, contextBuilder) {
71 | var ctx = contextBuilder(options.canvas_sel, 550, 200);
72 |
73 | var stave = new Vex.Flow.Stave(10, 50, 500);
74 | stave.addClef("treble").addTimeSignature("4/4").
75 | setEndBarType(Vex.Flow.Barline.type.END).setContext(ctx).draw();
76 |
77 | var notes = [
78 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "q" }),
79 | new Vex.Flow.StaveNote({ keys: ["d/4"], duration: "q" }),
80 | new Vex.Flow.StaveNote({ keys: ["b/4"], duration: "qr" })
81 | ];
82 |
83 | var voice = new Vex.Flow.Voice(Vex.Flow.Test.TIME4_4).
84 | setMode(Vex.Flow.Voice.Mode.FULL);
85 | voice.addTickables(notes);
86 |
87 | new Vex.Flow.Formatter().joinVoices([voice]).format([voice], 500);
88 | voice.draw(ctx, stave);
89 | voice.getBoundingBox().draw(ctx);
90 |
91 | try {
92 | voice.addTickable(
93 | new Vex.Flow.StaveNote({ keys: ["c/4"], duration: "h" })
94 | );
95 | } catch (e) {
96 | equal(e.code, "BadArgument", "Too many ticks exception");
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/tools/find_inconsistent_style.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/ruby
2 |
3 | # VexFlow - Copyright Mohit Muthanna Cheppudira 2012
4 | #
5 | # Look for >80 lines and hard tabs.
6 |
7 | SRCDIR = "../src"
8 | DIRS = [ "../src/*.js", "../vextab/*.js" ]
9 |
10 | unless File.exists?(SRCDIR)
11 | puts "This script needs to be run from the tools/ directory."
12 | exit 1
13 | end
14 |
15 | DIRS.each do |dir|
16 | files = Dir.glob(dir)
17 | files.each do |file|
18 | line = 0
19 | File.read(file).each_line do |l|
20 | line += 1
21 | puts "#{file}:#{line} -- #{l.length}" if l.length > 80
22 | end
23 | end
24 | end
25 |
--------------------------------------------------------------------------------
/tools/find_missing_includes.rb:
--------------------------------------------------------------------------------
1 | #!/usr/bin/ruby
2 |
3 | # VexFlow - Copyright Mohit Muthanna Cheppudira 2012
4 | #
5 | # This script verifies that the .js files in /src are included in all the
6 | # right places, e.g., SCons rules, HTML files, etc.
7 |
8 | require 'pp'
9 |
10 | SRCDIR = "../src"
11 | HTML_FILES = [
12 | "../tests/flow.html"
13 |
14 | # Might not need these anymore.
15 | # "../docs/tutorial.html",
16 | # "../docs/sandbox.html"
17 | ]
18 |
19 | unless File.exists?(SRCDIR)
20 | puts "This script needs to be run from the tools/ directory."
21 | exit 1
22 | end
23 |
24 | # Extract all .js files in src/ (non recursive)
25 | files = Dir.glob("#{SRCDIR}/*.js").map { |f| f.gsub(SRCDIR + "/", "")}
26 |
27 | # Work through HTML files and print out missing includes
28 | HTML_FILES.each do |html|
29 | test_includes = File.readlines(html).
30 | grep(/^.*script\ssrc.*\.\.\/src.*\.js.*/).
31 | map { |f| f.chomp.gsub(/^.*"(.+)".*$/, '\1').
32 | gsub(SRCDIR + "/", "") }
33 |
34 | puts "\nFiles in #{SRCDIR} but not in #{html}:"
35 | pp files - test_includes
36 | end
37 |
--------------------------------------------------------------------------------