vexflow
Version:
A JavaScript library for rendering music notation and guitar tablature
1,008 lines (668 loc) • 34.9 kB
HTML
<html>
<head>
<title>pedalmarking.js</title>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<link rel="stylesheet" media="all" href="public/stylesheets/normalize.css" />
<link rel="stylesheet" media="all" href="docco.css" />
</head>
<body>
<div class="container">
<div class="page">
<div class="header">
<h1>pedalmarking.js</h1>
<div class="toc">
<h3>Table of Contents</h3>
<ol>
<li>
<a class="source" href="accidental.html">
accidental.js
</a>
</li>
<li>
<a class="source" href="annotation.html">
annotation.js
</a>
</li>
<li>
<a class="source" href="articulation.html">
articulation.js
</a>
</li>
<li>
<a class="source" href="barnote.html">
barnote.js
</a>
</li>
<li>
<a class="source" href="beam.html">
beam.js
</a>
</li>
<li>
<a class="source" href="bend.html">
bend.js
</a>
</li>
<li>
<a class="source" href="boundingbox.html">
boundingbox.js
</a>
</li>
<li>
<a class="source" href="boundingboxcomputation.html">
boundingboxcomputation.js
</a>
</li>
<li>
<a class="source" href="canvascontext.html">
canvascontext.js
</a>
</li>
<li>
<a class="source" href="clef.html">
clef.js
</a>
</li>
<li>
<a class="source" href="clefnote.html">
clefnote.js
</a>
</li>
<li>
<a class="source" href="crescendo.html">
crescendo.js
</a>
</li>
<li>
<a class="source" href="curve.html">
curve.js
</a>
</li>
<li>
<a class="source" href="dot.html">
dot.js
</a>
</li>
<li>
<a class="source" href="easyscore.html">
easyscore.js
</a>
</li>
<li>
<a class="source" href="element.html">
element.js
</a>
</li>
<li>
<a class="source" href="factory.html">
factory.js
</a>
</li>
<li>
<a class="source" href="formatter.html">
formatter.js
</a>
</li>
<li>
<a class="source" href="fraction.html">
fraction.js
</a>
</li>
<li>
<a class="source" href="frethandfinger.html">
frethandfinger.js
</a>
</li>
<li>
<a class="source" href="ghostnote.html">
ghostnote.js
</a>
</li>
<li>
<a class="source" href="glyph.html">
glyph.js
</a>
</li>
<li>
<a class="source" href="glyphnote.html">
glyphnote.js
</a>
</li>
<li>
<a class="source" href="gracenote.html">
gracenote.js
</a>
</li>
<li>
<a class="source" href="gracenotegroup.html">
gracenotegroup.js
</a>
</li>
<li>
<a class="source" href="gracetabnote.html">
gracetabnote.js
</a>
</li>
<li>
<a class="source" href="index.html">
index.js
</a>
</li>
<li>
<a class="source" href="keymanager.html">
keymanager.js
</a>
</li>
<li>
<a class="source" href="keysignature.html">
keysignature.js
</a>
</li>
<li>
<a class="source" href="keysignote.html">
keysignote.js
</a>
</li>
<li>
<a class="source" href="modifier.html">
modifier.js
</a>
</li>
<li>
<a class="source" href="modifiercontext.html">
modifiercontext.js
</a>
</li>
<li>
<a class="source" href="multimeasurerest.html">
multimeasurerest.js
</a>
</li>
<li>
<a class="source" href="music.html">
music.js
</a>
</li>
<li>
<a class="source" href="note.html">
note.js
</a>
</li>
<li>
<a class="source" href="notehead.html">
notehead.js
</a>
</li>
<li>
<a class="source" href="notesubgroup.html">
notesubgroup.js
</a>
</li>
<li>
<a class="source" href="ornament.html">
ornament.js
</a>
</li>
<li>
<a class="source" href="parser.html">
parser.js
</a>
</li>
<li>
<a class="source" href="pedalmarking.html">
pedalmarking.js
</a>
</li>
<li>
<a class="source" href="raphaelcontext.html">
raphaelcontext.js
</a>
</li>
<li>
<a class="source" href="registry.html">
registry.js
</a>
</li>
<li>
<a class="source" href="renderer.html">
renderer.js
</a>
</li>
<li>
<a class="source" href="repeatnote.html">
repeatnote.js
</a>
</li>
<li>
<a class="source" href="smufl.html">
smufl.js
</a>
</li>
<li>
<a class="source" href="stave.html">
stave.js
</a>
</li>
<li>
<a class="source" href="stavebarline.html">
stavebarline.js
</a>
</li>
<li>
<a class="source" href="staveconnector.html">
staveconnector.js
</a>
</li>
<li>
<a class="source" href="stavehairpin.html">
stavehairpin.js
</a>
</li>
<li>
<a class="source" href="staveline.html">
staveline.js
</a>
</li>
<li>
<a class="source" href="stavemodifier.html">
stavemodifier.js
</a>
</li>
<li>
<a class="source" href="stavenote.html">
stavenote.js
</a>
</li>
<li>
<a class="source" href="staverepetition.html">
staverepetition.js
</a>
</li>
<li>
<a class="source" href="stavesection.html">
stavesection.js
</a>
</li>
<li>
<a class="source" href="stavetempo.html">
stavetempo.js
</a>
</li>
<li>
<a class="source" href="stavetext.html">
stavetext.js
</a>
</li>
<li>
<a class="source" href="stavetie.html">
stavetie.js
</a>
</li>
<li>
<a class="source" href="stavevolta.html">
stavevolta.js
</a>
</li>
<li>
<a class="source" href="stem.html">
stem.js
</a>
</li>
<li>
<a class="source" href="stemmablenote.html">
stemmablenote.js
</a>
</li>
<li>
<a class="source" href="stringnumber.html">
stringnumber.js
</a>
</li>
<li>
<a class="source" href="strokes.html">
strokes.js
</a>
</li>
<li>
<a class="source" href="svgcontext.html">
svgcontext.js
</a>
</li>
<li>
<a class="source" href="system.html">
system.js
</a>
</li>
<li>
<a class="source" href="tables.html">
tables.js
</a>
</li>
<li>
<a class="source" href="tabnote.html">
tabnote.js
</a>
</li>
<li>
<a class="source" href="tabslide.html">
tabslide.js
</a>
</li>
<li>
<a class="source" href="tabstave.html">
tabstave.js
</a>
</li>
<li>
<a class="source" href="tabtie.html">
tabtie.js
</a>
</li>
<li>
<a class="source" href="textbracket.html">
textbracket.js
</a>
</li>
<li>
<a class="source" href="textdynamics.html">
textdynamics.js
</a>
</li>
<li>
<a class="source" href="textnote.html">
textnote.js
</a>
</li>
<li>
<a class="source" href="tickable.html">
tickable.js
</a>
</li>
<li>
<a class="source" href="tickcontext.html">
tickcontext.js
</a>
</li>
<li>
<a class="source" href="timesignature.html">
timesignature.js
</a>
</li>
<li>
<a class="source" href="timesignote.html">
timesignote.js
</a>
</li>
<li>
<a class="source" href="tremolo.html">
tremolo.js
</a>
</li>
<li>
<a class="source" href="tuning.html">
tuning.js
</a>
</li>
<li>
<a class="source" href="tuplet.html">
tuplet.js
</a>
</li>
<li>
<a class="source" href="vex.html">
vex.js
</a>
</li>
<li>
<a class="source" href="vibrato.html">
vibrato.js
</a>
</li>
<li>
<a class="source" href="vibratobracket.html">
vibratobracket.js
</a>
</li>
<li>
<a class="source" href="voice.html">
voice.js
</a>
</li>
<li>
<a class="source" href="voicegroup.html">
voicegroup.js
</a>
</li>
</ol>
</div>
</div>
<p><a href="http://vexflow.com">VexFlow</a> - Copyright (c) Mohit Muthanna 2010.</p>
<h2 id="description">Description</h2>
<p>This file implements different types of pedal markings. These notation
elements indicate to the performer when to depress and release the a pedal.</p>
<p>In order to create “Sostenuto”, and “una corda” markings, you must set
custom text for the release/depress pedal markings.</p>
<div class='highlight'><pre>
<span class="hljs-keyword">import</span> { Vex } <span class="hljs-keyword">from</span> <span class="hljs-string">'./vex'</span>;
<span class="hljs-keyword">import</span> { Element } <span class="hljs-keyword">from</span> <span class="hljs-string">'./element'</span>;
<span class="hljs-keyword">import</span> { Glyph } <span class="hljs-keyword">from</span> <span class="hljs-string">'./glyph'</span>;</pre></div>
<p>To enable logging for this class. Set <code>Vex.Flow.PedalMarking.DEBUG</code> to <code>true</code>.</p>
<div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">L</span>(<span class="hljs-params">...args</span>) </span>{ <span class="hljs-keyword">if</span> (PedalMarking.DEBUG) Vex.L(<span class="hljs-string">'Vex.Flow.PedalMarking'</span>, args); }</pre></div>
<p>Draws a pedal glyph with the provided <code>name</code> on a rendering <code>context</code>
at the coordinates <code>x</code> and `y. Takes into account the glyph data
coordinate shifts.</p>
<div class='highlight'><pre><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">drawPedalGlyph</span>(<span class="hljs-params">name, context, x, y, point</span>) </span>{
<span class="hljs-keyword">const</span> glyph_data = PedalMarking.GLYPHS[name];
<span class="hljs-keyword">const</span> glyph = <span class="hljs-keyword">new</span> Glyph(glyph_data.code, point, { <span class="hljs-attr">category</span>: <span class="hljs-string">'pedalMarking'</span> });
glyph.render(context, x + glyph_data.x_shift, y + glyph_data.y_shift);
}
<span class="hljs-keyword">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PedalMarking</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Element</span> </span>{</pre></div>
<p>Glyph data</p>
<div class='highlight'><pre> <span class="hljs-keyword">static</span> get GLYPHS() {
<span class="hljs-keyword">return</span> {
<span class="hljs-string">'pedal_depress'</span>: {
<span class="hljs-attr">code</span>: <span class="hljs-string">'keyboardPedalPed'</span>,
<span class="hljs-attr">x_shift</span>: <span class="hljs-number">-10</span>,
<span class="hljs-attr">y_shift</span>: <span class="hljs-number">0</span>,
},
<span class="hljs-string">'pedal_release'</span>: {
<span class="hljs-attr">code</span>: <span class="hljs-string">'keyboardPedalUp'</span>,
<span class="hljs-attr">x_shift</span>: <span class="hljs-number">-2</span>,
<span class="hljs-attr">y_shift</span>: <span class="hljs-number">3</span>,
},
};
}
<span class="hljs-keyword">static</span> get Styles() {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">TEXT</span>: <span class="hljs-number">1</span>,
<span class="hljs-attr">BRACKET</span>: <span class="hljs-number">2</span>,
<span class="hljs-attr">MIXED</span>: <span class="hljs-number">3</span>,
};
}
<span class="hljs-keyword">static</span> get StylesString() {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">text</span>: PedalMarking.Styles.TEXT,
<span class="hljs-attr">bracket</span>: PedalMarking.Styles.BRACKET,
<span class="hljs-attr">mixed</span>: PedalMarking.Styles.MIXED,
};
}</pre></div>
<p>Create a sustain pedal marking. Returns the defaults PedalMarking.
Which uses the traditional “Ped” and “*”” markings.</p>
<div class='highlight'><pre> <span class="hljs-keyword">static</span> createSustain(notes) {
<span class="hljs-keyword">const</span> pedal = <span class="hljs-keyword">new</span> PedalMarking(notes);
<span class="hljs-keyword">return</span> pedal;
}</pre></div>
<p>Create a sostenuto pedal marking</p>
<div class='highlight'><pre> <span class="hljs-keyword">static</span> createSostenuto(notes) {
<span class="hljs-keyword">const</span> pedal = <span class="hljs-keyword">new</span> PedalMarking(notes);
pedal.setStyle(PedalMarking.Styles.MIXED);
pedal.setCustomText(<span class="hljs-string">'Sost. Ped.'</span>);
<span class="hljs-keyword">return</span> pedal;
}</pre></div>
<p>Create an una corda pedal marking</p>
<div class='highlight'><pre> <span class="hljs-keyword">static</span> createUnaCorda(notes) {
<span class="hljs-keyword">const</span> pedal = <span class="hljs-keyword">new</span> PedalMarking(notes);
pedal.setStyle(PedalMarking.Styles.TEXT);
pedal.setCustomText(<span class="hljs-string">'una corda'</span>, <span class="hljs-string">'tre corda'</span>);
<span class="hljs-keyword">return</span> pedal;
}</pre></div>
<h2 id="prototype-methods">Prototype Methods</h2>
<div class='highlight'><pre> <span class="hljs-keyword">constructor</span>(notes) {
<span class="hljs-keyword">super</span>();
<span class="hljs-keyword">this</span>.setAttribute(<span class="hljs-string">'type'</span>, <span class="hljs-string">'PedalMarking'</span>);
<span class="hljs-keyword">this</span>.notes = notes;
<span class="hljs-keyword">this</span>.style = PedalMarking.TEXT;
<span class="hljs-keyword">this</span>.line = <span class="hljs-number">0</span>;</pre></div>
<p>Custom text for the release/depress markings</p>
<div class='highlight'><pre> <span class="hljs-keyword">this</span>.custom_depress_text = <span class="hljs-string">''</span>;
<span class="hljs-keyword">this</span>.custom_release_text = <span class="hljs-string">''</span>;
<span class="hljs-keyword">this</span>.font = {
<span class="hljs-attr">family</span>: <span class="hljs-string">'Times New Roman'</span>,
<span class="hljs-attr">size</span>: <span class="hljs-number">12</span>,
<span class="hljs-attr">weight</span>: <span class="hljs-string">'italic bold'</span>,
};
<span class="hljs-keyword">this</span>.render_options = {
<span class="hljs-attr">bracket_height</span>: <span class="hljs-number">10</span>,
<span class="hljs-attr">text_margin_right</span>: <span class="hljs-number">6</span>,
<span class="hljs-attr">bracket_line_width</span>: <span class="hljs-number">1</span>,
<span class="hljs-attr">color</span>: <span class="hljs-string">'black'</span>,
};
}</pre></div>
<p>Set custom text for the <code>depress</code>/<code>release</code> pedal markings. No text is
set if the parameter is falsy.</p>
<div class='highlight'><pre> setCustomText(depress, release) {
<span class="hljs-keyword">this</span>.custom_depress_text = depress || <span class="hljs-string">''</span>;
<span class="hljs-keyword">this</span>.custom_release_text = release || <span class="hljs-string">''</span>;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}</pre></div>
<p>Set the pedal marking style</p>
<div class='highlight'><pre> setStyle(style) {
<span class="hljs-keyword">if</span> (style < <span class="hljs-number">1</span> && style > <span class="hljs-number">3</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'InvalidParameter'</span>, <span class="hljs-string">'The style must be one found in PedalMarking.Styles'</span>);
}
<span class="hljs-keyword">this</span>.style = style;
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>;
}</pre></div>
<p>Set the staff line to render the markings on</p>
<div class='highlight'><pre> setLine(line) { <span class="hljs-keyword">this</span>.line = line; <span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>; }</pre></div>
<p>Draw the bracket based pedal markings</p>
<div class='highlight'><pre> drawBracketed() {
<span class="hljs-keyword">const</span> ctx = <span class="hljs-keyword">this</span>.context;
<span class="hljs-keyword">let</span> is_pedal_depressed = <span class="hljs-literal">false</span>;
<span class="hljs-keyword">let</span> prev_x;
<span class="hljs-keyword">let</span> prev_y;
<span class="hljs-keyword">const</span> pedal = <span class="hljs-keyword">this</span>;</pre></div>
<p>Iterate through each note</p>
<div class='highlight'><pre> <span class="hljs-keyword">this</span>.notes.forEach(<span class="hljs-function">(<span class="hljs-params">note, index, notes</span>) =></span> {</pre></div>
<p>Each note triggers the opposite pedal action</p>
<div class='highlight'><pre> is_pedal_depressed = !is_pedal_depressed;</pre></div>
<p>Get the initial coordinates for the note</p>
<div class='highlight'><pre> <span class="hljs-keyword">const</span> x = note.getAbsoluteX();
<span class="hljs-keyword">const</span> y = note.getStave().getYForBottomText(pedal.line + <span class="hljs-number">3</span>);</pre></div>
<p>Throw if current note is positioned before the previous note</p>
<div class='highlight'><pre> <span class="hljs-keyword">if</span> (x < prev_x) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(
<span class="hljs-string">'InvalidConfiguration'</span>, <span class="hljs-string">'The notes provided must be in order of ascending x positions'</span>
);
}</pre></div>
<p>Determine if the previous or next note are the same
as the current note. We need to keep track of this for
when adjustments are made for the release+depress action</p>
<div class='highlight'><pre> <span class="hljs-keyword">const</span> next_is_same = notes[index + <span class="hljs-number">1</span>] === note;
<span class="hljs-keyword">const</span> prev_is_same = notes[index - <span class="hljs-number">1</span>] === note;
<span class="hljs-keyword">let</span> x_shift = <span class="hljs-number">0</span>;
<span class="hljs-keyword">const</span> point = <span class="hljs-keyword">this</span>.musicFont.lookupMetric(<span class="hljs-string">`pedalMarking.<span class="hljs-subst">${is_pedal_depressed ? <span class="hljs-string">'down'</span> : <span class="hljs-string">'up'</span>}</span>.point`</span>);
<span class="hljs-keyword">if</span> (is_pedal_depressed) {</pre></div>
<p>Adjustment for release+depress</p>
<div class='highlight'><pre> x_shift = prev_is_same ? <span class="hljs-number">5</span> : <span class="hljs-number">0</span>;
<span class="hljs-keyword">if</span> (pedal.style === PedalMarking.Styles.MIXED && !prev_is_same) {</pre></div>
<p>For MIXED style, start with text instead of bracket</p>
<div class='highlight'><pre> <span class="hljs-keyword">if</span> (pedal.custom_depress_text) {</pre></div>
<p>If we have custom text, use instead of the default “Ped” glyph</p>
<div class='highlight'><pre> <span class="hljs-keyword">const</span> text_width = ctx.measureText(pedal.custom_depress_text).width;
ctx.fillText(pedal.custom_depress_text, x - (text_width / <span class="hljs-number">2</span>), y);
x_shift = (text_width / <span class="hljs-number">2</span>) + pedal.render_options.text_margin_right;
} <span class="hljs-keyword">else</span> {</pre></div>
<p>Render the Ped glyph in position</p>
<div class='highlight'><pre> drawPedalGlyph(<span class="hljs-string">'pedal_depress'</span>, ctx, x, y, point);
x_shift = <span class="hljs-number">20</span> + pedal.render_options.text_margin_right;
}
} <span class="hljs-keyword">else</span> {</pre></div>
<p>Draw start bracket</p>
<div class='highlight'><pre> ctx.beginPath();
ctx.moveTo(x, y - pedal.render_options.bracket_height);
ctx.lineTo(x + x_shift, y);
ctx.stroke();
ctx.closePath();
}
} <span class="hljs-keyword">else</span> {</pre></div>
<p>Adjustment for release+depress</p>
<div class='highlight'><pre> x_shift = next_is_same ? <span class="hljs-number">-5</span> : <span class="hljs-number">0</span>;</pre></div>
<p>Draw end bracket</p>
<div class='highlight'><pre> ctx.beginPath();
ctx.moveTo(prev_x, prev_y);
ctx.lineTo(x + x_shift, y);
ctx.lineTo(x, y - pedal.render_options.bracket_height);
ctx.stroke();
ctx.closePath();
}</pre></div>
<p>Store previous coordinates</p>
<div class='highlight'><pre> prev_x = x + x_shift;
prev_y = y;
});
}</pre></div>
<p>Draw the text based pedal markings. This defaults to the traditional
“Ped” and “*”” symbols if no custom text has been provided.</p>
<div class='highlight'><pre> drawText() {
<span class="hljs-keyword">const</span> ctx = <span class="hljs-keyword">this</span>.context;
<span class="hljs-keyword">let</span> is_pedal_depressed = <span class="hljs-literal">false</span>;
<span class="hljs-keyword">const</span> pedal = <span class="hljs-keyword">this</span>;</pre></div>
<p>Iterate through each note, placing glyphs or custom text accordingly</p>
<div class='highlight'><pre> <span class="hljs-keyword">this</span>.notes.forEach(<span class="hljs-function"><span class="hljs-params">note</span> =></span> {
is_pedal_depressed = !is_pedal_depressed;
<span class="hljs-keyword">const</span> stave = note.getStave();
<span class="hljs-keyword">const</span> x = note.getAbsoluteX();
<span class="hljs-keyword">const</span> y = stave.getYForBottomText(pedal.line + <span class="hljs-number">3</span>);
<span class="hljs-keyword">const</span> point = <span class="hljs-keyword">this</span>.musicFont.lookupMetric(<span class="hljs-string">`pedalMarking.<span class="hljs-subst">${is_pedal_depressed ? <span class="hljs-string">'down'</span> : <span class="hljs-string">'up'</span>}</span>.point`</span>);
<span class="hljs-keyword">let</span> text_width = <span class="hljs-number">0</span>;
<span class="hljs-keyword">if</span> (is_pedal_depressed) {
<span class="hljs-keyword">if</span> (pedal.custom_depress_text) {
text_width = ctx.measureText(pedal.custom_depress_text).width;
ctx.fillText(pedal.custom_depress_text, x - (text_width / <span class="hljs-number">2</span>), y);
} <span class="hljs-keyword">else</span> {
drawPedalGlyph(<span class="hljs-string">'pedal_depress'</span>, ctx, x, y, point);
}
} <span class="hljs-keyword">else</span> {
<span class="hljs-keyword">if</span> (pedal.custom_release_text) {
text_width = ctx.measureText(pedal.custom_release_text).width;
ctx.fillText(pedal.custom_release_text, x - (text_width / <span class="hljs-number">2</span>), y);
} <span class="hljs-keyword">else</span> {
drawPedalGlyph(<span class="hljs-string">'pedal_release'</span>, ctx, x, y, point);
}
}
});
}</pre></div>
<p>Render the pedal marking in position on the rendering context</p>
<div class='highlight'><pre> draw() {
<span class="hljs-keyword">const</span> ctx = <span class="hljs-keyword">this</span>.checkContext();
<span class="hljs-keyword">this</span>.setRendered();
ctx.save();
ctx.setStrokeStyle(<span class="hljs-keyword">this</span>.render_options.color);
ctx.setFillStyle(<span class="hljs-keyword">this</span>.render_options.color);
ctx.setFont(<span class="hljs-keyword">this</span>.font.family, <span class="hljs-keyword">this</span>.font.size, <span class="hljs-keyword">this</span>.font.weight);
L(<span class="hljs-string">'Rendering Pedal Marking'</span>);
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.style === PedalMarking.Styles.BRACKET || <span class="hljs-keyword">this</span>.style === PedalMarking.Styles.MIXED) {
ctx.setLineWidth(<span class="hljs-keyword">this</span>.render_options.bracket_line_width);
<span class="hljs-keyword">this</span>.drawBracketed();
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.style === PedalMarking.Styles.TEXT) {
<span class="hljs-keyword">this</span>.drawText();
}
ctx.restore();
}
}</pre></div>
<div class="fleur">h</div>
</div>
</div>
</body>
</html>