vexflow
Version:
A JavaScript library for rendering music notation and guitar tablature
999 lines (744 loc) • 51.1 kB
HTML
<!DOCTYPE html>
<html>
<head>
<title>music.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>music.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 class implements some standard music theory routines.</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">export</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Music</span> </span>{
<span class="hljs-keyword">static</span> get NUM_TONES() {
<span class="hljs-keyword">return</span> <span class="hljs-number">12</span>;
}
<span class="hljs-keyword">static</span> get roots() {
<span class="hljs-keyword">return</span> [<span class="hljs-string">'c'</span>, <span class="hljs-string">'d'</span>, <span class="hljs-string">'e'</span>, <span class="hljs-string">'f'</span>, <span class="hljs-string">'g'</span>, <span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>];
}
<span class="hljs-keyword">static</span> get root_values() {
<span class="hljs-keyword">return</span> [<span class="hljs-number">0</span>, <span class="hljs-number">2</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>, <span class="hljs-number">7</span>, <span class="hljs-number">9</span>, <span class="hljs-number">11</span>];
}
<span class="hljs-keyword">static</span> get root_indices() {
<span class="hljs-keyword">return</span> {
<span class="hljs-string">'c'</span>: <span class="hljs-number">0</span>,
<span class="hljs-string">'d'</span>: <span class="hljs-number">1</span>,
<span class="hljs-string">'e'</span>: <span class="hljs-number">2</span>,
<span class="hljs-string">'f'</span>: <span class="hljs-number">3</span>,
<span class="hljs-string">'g'</span>: <span class="hljs-number">4</span>,
<span class="hljs-string">'a'</span>: <span class="hljs-number">5</span>,
<span class="hljs-string">'b'</span>: <span class="hljs-number">6</span>,
};
}
<span class="hljs-keyword">static</span> get canonical_notes() {
<span class="hljs-keyword">return</span> [
<span class="hljs-string">'c'</span>, <span class="hljs-string">'c#'</span>, <span class="hljs-string">'d'</span>, <span class="hljs-string">'d#'</span>,
<span class="hljs-string">'e'</span>, <span class="hljs-string">'f'</span>, <span class="hljs-string">'f#'</span>, <span class="hljs-string">'g'</span>,
<span class="hljs-string">'g#'</span>, <span class="hljs-string">'a'</span>, <span class="hljs-string">'a#'</span>, <span class="hljs-string">'b'</span>,
];
}
<span class="hljs-keyword">static</span> get diatonic_intervals() {
<span class="hljs-keyword">return</span> [
<span class="hljs-string">'unison'</span>, <span class="hljs-string">'m2'</span>, <span class="hljs-string">'M2'</span>, <span class="hljs-string">'m3'</span>, <span class="hljs-string">'M3'</span>,
<span class="hljs-string">'p4'</span>, <span class="hljs-string">'dim5'</span>, <span class="hljs-string">'p5'</span>, <span class="hljs-string">'m6'</span>, <span class="hljs-string">'M6'</span>,
<span class="hljs-string">'b7'</span>, <span class="hljs-string">'M7'</span>, <span class="hljs-string">'octave'</span>,
];
}
<span class="hljs-keyword">static</span> get diatonic_accidentals() {
<span class="hljs-keyword">return</span> {
<span class="hljs-string">'unison'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'m2'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">-1</span> },
<span class="hljs-string">'M2'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'m3'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">-1</span> },
<span class="hljs-string">'M3'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'p4'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'dim5'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">-1</span> },
<span class="hljs-string">'p5'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'m6'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">-1</span> },
<span class="hljs-string">'M6'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'b7'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">-1</span> },
<span class="hljs-string">'M7'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'octave'</span>: { <span class="hljs-attr">note</span>: <span class="hljs-number">7</span>, <span class="hljs-attr">accidental</span>: <span class="hljs-number">0</span> },
};
}
<span class="hljs-keyword">static</span> get intervals() {
<span class="hljs-keyword">return</span> {
<span class="hljs-string">'u'</span>: <span class="hljs-number">0</span>, <span class="hljs-string">'unison'</span>: <span class="hljs-number">0</span>,
<span class="hljs-string">'m2'</span>: <span class="hljs-number">1</span>, <span class="hljs-string">'b2'</span>: <span class="hljs-number">1</span>, <span class="hljs-string">'min2'</span>: <span class="hljs-number">1</span>, <span class="hljs-string">'S'</span>: <span class="hljs-number">1</span>, <span class="hljs-string">'H'</span>: <span class="hljs-number">1</span>,
<span class="hljs-string">'2'</span>: <span class="hljs-number">2</span>, <span class="hljs-string">'M2'</span>: <span class="hljs-number">2</span>, <span class="hljs-string">'maj2'</span>: <span class="hljs-number">2</span>, <span class="hljs-string">'T'</span>: <span class="hljs-number">2</span>, <span class="hljs-string">'W'</span>: <span class="hljs-number">2</span>,
<span class="hljs-string">'m3'</span>: <span class="hljs-number">3</span>, <span class="hljs-string">'b3'</span>: <span class="hljs-number">3</span>, <span class="hljs-string">'min3'</span>: <span class="hljs-number">3</span>,
<span class="hljs-string">'M3'</span>: <span class="hljs-number">4</span>, <span class="hljs-string">'3'</span>: <span class="hljs-number">4</span>, <span class="hljs-string">'maj3'</span>: <span class="hljs-number">4</span>,
<span class="hljs-string">'4'</span>: <span class="hljs-number">5</span>, <span class="hljs-string">'p4'</span>: <span class="hljs-number">5</span>,
<span class="hljs-string">'#4'</span>: <span class="hljs-number">6</span>, <span class="hljs-string">'b5'</span>: <span class="hljs-number">6</span>, <span class="hljs-string">'aug4'</span>: <span class="hljs-number">6</span>, <span class="hljs-string">'dim5'</span>: <span class="hljs-number">6</span>,
<span class="hljs-string">'5'</span>: <span class="hljs-number">7</span>, <span class="hljs-string">'p5'</span>: <span class="hljs-number">7</span>,
<span class="hljs-string">'#5'</span>: <span class="hljs-number">8</span>, <span class="hljs-string">'b6'</span>: <span class="hljs-number">8</span>, <span class="hljs-string">'aug5'</span>: <span class="hljs-number">8</span>,
<span class="hljs-string">'6'</span>: <span class="hljs-number">9</span>, <span class="hljs-string">'M6'</span>: <span class="hljs-number">9</span>, <span class="hljs-string">'maj6'</span>: <span class="hljs-number">9</span>,
<span class="hljs-string">'b7'</span>: <span class="hljs-number">10</span>, <span class="hljs-string">'m7'</span>: <span class="hljs-number">10</span>, <span class="hljs-string">'min7'</span>: <span class="hljs-number">10</span>, <span class="hljs-string">'dom7'</span>: <span class="hljs-number">10</span>,
<span class="hljs-string">'M7'</span>: <span class="hljs-number">11</span>, <span class="hljs-string">'maj7'</span>: <span class="hljs-number">11</span>,
<span class="hljs-string">'8'</span>: <span class="hljs-number">12</span>, <span class="hljs-string">'octave'</span>: <span class="hljs-number">12</span>,
};
}
<span class="hljs-keyword">static</span> get scales() {
<span class="hljs-keyword">return</span> {
<span class="hljs-attr">major</span>: [<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>],
<span class="hljs-attr">dorian</span>: [<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>],
<span class="hljs-attr">mixolydian</span>: [<span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>],
<span class="hljs-attr">minor</span>: [<span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>],
};
}
<span class="hljs-keyword">static</span> get scaleTypes() {
<span class="hljs-keyword">return</span> {
<span class="hljs-string">'M'</span>: Music.scales.major,
<span class="hljs-string">'m'</span>: Music.scales.minor,
};
}
<span class="hljs-keyword">static</span> get accidentals() {
<span class="hljs-keyword">return</span> [<span class="hljs-string">'bb'</span>, <span class="hljs-string">'b'</span>, <span class="hljs-string">'n'</span>, <span class="hljs-string">'#'</span>, <span class="hljs-string">'##'</span>];
}
<span class="hljs-keyword">static</span> get noteValues() {
<span class="hljs-keyword">return</span> {
<span class="hljs-string">'c'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'cn'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'c#'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">1</span> },
<span class="hljs-string">'c##'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">2</span> },
<span class="hljs-string">'cb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">11</span> },
<span class="hljs-string">'cbb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">0</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">10</span> },
<span class="hljs-string">'d'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">2</span> },
<span class="hljs-string">'dn'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">2</span> },
<span class="hljs-string">'d#'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">3</span> },
<span class="hljs-string">'d##'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">4</span> },
<span class="hljs-string">'db'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">1</span> },
<span class="hljs-string">'dbb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">1</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'e'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">4</span> },
<span class="hljs-string">'en'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">4</span> },
<span class="hljs-string">'e#'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">5</span> },
<span class="hljs-string">'e##'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">6</span> },
<span class="hljs-string">'eb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">3</span> },
<span class="hljs-string">'ebb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">2</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">2</span> },
<span class="hljs-string">'f'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">5</span> },
<span class="hljs-string">'fn'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">5</span> },
<span class="hljs-string">'f#'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">6</span> },
<span class="hljs-string">'f##'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">7</span> },
<span class="hljs-string">'fb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">4</span> },
<span class="hljs-string">'fbb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">3</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">3</span> },
<span class="hljs-string">'g'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">7</span> },
<span class="hljs-string">'gn'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">7</span> },
<span class="hljs-string">'g#'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">8</span> },
<span class="hljs-string">'g##'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">9</span> },
<span class="hljs-string">'gb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">6</span> },
<span class="hljs-string">'gbb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">4</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">5</span> },
<span class="hljs-string">'a'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">9</span> },
<span class="hljs-string">'an'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">9</span> },
<span class="hljs-string">'a#'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">10</span> },
<span class="hljs-string">'a##'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">11</span> },
<span class="hljs-string">'ab'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">8</span> },
<span class="hljs-string">'abb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">5</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">7</span> },
<span class="hljs-string">'b'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">11</span> },
<span class="hljs-string">'bn'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">11</span> },
<span class="hljs-string">'b#'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">0</span> },
<span class="hljs-string">'b##'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">1</span> },
<span class="hljs-string">'bb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">10</span> },
<span class="hljs-string">'bbb'</span>: { <span class="hljs-attr">root_index</span>: <span class="hljs-number">6</span>, <span class="hljs-attr">int_val</span>: <span class="hljs-number">9</span> },
};
}
isValidNoteValue(note) {
<span class="hljs-keyword">if</span> (note == <span class="hljs-literal">null</span> || note < <span class="hljs-number">0</span> || note >= Music.NUM_TONES) {
<span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;
}
<span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;
}
isValidIntervalValue(interval) {
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.isValidNoteValue(interval);
}
getNoteParts(noteString) {
<span class="hljs-keyword">if</span> (!noteString || noteString.length < <span class="hljs-number">1</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">'Invalid note name: '</span> + noteString);
}
<span class="hljs-keyword">if</span> (noteString.length > <span class="hljs-number">3</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">'Invalid note name: '</span> + noteString);
}
<span class="hljs-keyword">const</span> note = noteString.toLowerCase();
<span class="hljs-keyword">const</span> regex = <span class="hljs-regexp">/^([cdefgab])(b|bb|n|#|##)?$/</span>;
<span class="hljs-keyword">const</span> match = regex.exec(note);
<span class="hljs-keyword">if</span> (match != <span class="hljs-literal">null</span>) {
<span class="hljs-keyword">const</span> root = match[<span class="hljs-number">1</span>];
<span class="hljs-keyword">const</span> accidental = match[<span class="hljs-number">2</span>];
<span class="hljs-keyword">return</span> {
root,
accidental,
};
} <span class="hljs-keyword">else</span> {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">'Invalid note name: '</span> + noteString);
}
}
getKeyParts(keyString) {
<span class="hljs-keyword">if</span> (!keyString || keyString.length < <span class="hljs-number">1</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">'Invalid key: '</span> + keyString);
}
<span class="hljs-keyword">const</span> key = keyString.toLowerCase();</pre></div>
<p>Support Major, Minor, Melodic Minor, and Harmonic Minor key types.</p>
<div class='highlight'><pre> <span class="hljs-keyword">const</span> regex = <span class="hljs-regexp">/^([cdefgab])(b|#)?(mel|harm|m|M)?$/</span>;
<span class="hljs-keyword">const</span> match = regex.exec(key);
<span class="hljs-keyword">if</span> (match != <span class="hljs-literal">null</span>) {
<span class="hljs-keyword">const</span> root = match[<span class="hljs-number">1</span>];
<span class="hljs-keyword">const</span> accidental = match[<span class="hljs-number">2</span>];
<span class="hljs-keyword">let</span> type = match[<span class="hljs-number">3</span>];</pre></div>
<p>Unspecified type implies major</p>
<div class='highlight'><pre> <span class="hljs-keyword">if</span> (!type) type = <span class="hljs-string">'M'</span>;
<span class="hljs-keyword">return</span> {
root,
accidental,
type,
};
} <span class="hljs-keyword">else</span> {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid key: <span class="hljs-subst">${keyString}</span>`</span>);
}
}
getNoteValue(noteString) {
<span class="hljs-keyword">const</span> value = Music.noteValues[noteString];
<span class="hljs-keyword">if</span> (value == <span class="hljs-literal">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid note name: <span class="hljs-subst">${noteString}</span>`</span>);
}
<span class="hljs-keyword">return</span> value.int_val;
}
getIntervalValue(intervalString) {
<span class="hljs-keyword">const</span> value = Music.intervals[intervalString];
<span class="hljs-keyword">if</span> (value == <span class="hljs-literal">null</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid interval name: <span class="hljs-subst">${intervalString}</span>`</span>);
}
<span class="hljs-keyword">return</span> value;
}
getCanonicalNoteName(noteValue) {
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.isValidNoteValue(noteValue)) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid note value: <span class="hljs-subst">${noteValue}</span>`</span>);
}
<span class="hljs-keyword">return</span> Music.canonical_notes[noteValue];
}
getCanonicalIntervalName(intervalValue) {
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.isValidIntervalValue(intervalValue)) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid interval value: <span class="hljs-subst">${intervalValue}</span>`</span>);
}
<span class="hljs-keyword">return</span> Music.diatonic_intervals[intervalValue];
}
<span class="hljs-comment">/* Given a note, interval, and interval direction, product the
* relative note.
*/</span>
getRelativeNoteValue(noteValue, intervalValue, direction) {
<span class="hljs-keyword">if</span> (direction == <span class="hljs-literal">null</span>) direction = <span class="hljs-number">1</span>;
<span class="hljs-keyword">if</span> (direction !== <span class="hljs-number">1</span> && direction !== <span class="hljs-number">-1</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid direction: <span class="hljs-subst">${direction}</span>`</span>);
}
<span class="hljs-keyword">let</span> sum = (noteValue + (direction * intervalValue)) % Music.NUM_TONES;
<span class="hljs-keyword">if</span> (sum < <span class="hljs-number">0</span>) sum += Music.NUM_TONES;
<span class="hljs-keyword">return</span> sum;
}
getRelativeNoteName(root, noteValue) {
<span class="hljs-keyword">const</span> parts = <span class="hljs-keyword">this</span>.getNoteParts(root);
<span class="hljs-keyword">const</span> rootValue = <span class="hljs-keyword">this</span>.getNoteValue(parts.root);
<span class="hljs-keyword">let</span> interval = noteValue - rootValue;
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.abs(interval) > Music.NUM_TONES - <span class="hljs-number">3</span>) {
<span class="hljs-keyword">let</span> multiplier = <span class="hljs-number">1</span>;
<span class="hljs-keyword">if</span> (interval > <span class="hljs-number">0</span>) multiplier = <span class="hljs-number">-1</span>;</pre></div>
<p>Possibly wrap around. (Add +1 for modulo operator)</p>
<div class='highlight'><pre> <span class="hljs-keyword">const</span> reverse_interval = (((noteValue + <span class="hljs-number">1</span>) + (rootValue + <span class="hljs-number">1</span>)) %
Music.NUM_TONES) * multiplier;
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.abs(reverse_interval) > <span class="hljs-number">2</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Notes not related: <span class="hljs-subst">${root}</span>, <span class="hljs-subst">${noteValue}</span>)`</span>);
} <span class="hljs-keyword">else</span> {
interval = reverse_interval;
}
}
<span class="hljs-keyword">if</span> (<span class="hljs-built_in">Math</span>.abs(interval) > <span class="hljs-number">2</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Notes not related: <span class="hljs-subst">${root}</span>, <span class="hljs-subst">${noteValue}</span>)`</span>);
}
<span class="hljs-keyword">let</span> relativeNoteName = parts.root;
<span class="hljs-keyword">if</span> (interval > <span class="hljs-number">0</span>) {
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">1</span>; i <= interval; ++i) {
relativeNoteName += <span class="hljs-string">'#'</span>;
}
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (interval < <span class="hljs-number">0</span>) {
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">-1</span>; i >= interval; --i) {
relativeNoteName += <span class="hljs-string">'b'</span>;
}
}
<span class="hljs-keyword">return</span> relativeNoteName;
}
<span class="hljs-comment">/* Return scale tones, given intervals. Each successive interval is
* relative to the previous one, e.g., Major Scale:
*
* TTSTTTS = [2,2,1,2,2,2,1]
*
* When used with key = 0, returns C scale (which is isomorphic to
* interval list).
*/</span>
getScaleTones(key, intervals) {
<span class="hljs-keyword">const</span> tones = [key];
<span class="hljs-keyword">let</span> nextNote = key;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i < intervals.length; i += <span class="hljs-number">1</span>) {
nextNote = <span class="hljs-keyword">this</span>.getRelativeNoteValue(nextNote, intervals[i]);
<span class="hljs-keyword">if</span> (nextNote !== key) tones.push(nextNote);
}
<span class="hljs-keyword">return</span> tones;
}
<span class="hljs-comment">/* Returns the interval of a note, given a diatonic scale.
*
* E.g., Given the scale C, and the note E, returns M3
*/</span>
getIntervalBetween(note1, note2, direction) {
<span class="hljs-keyword">if</span> (direction == <span class="hljs-literal">null</span>) direction = <span class="hljs-number">1</span>;
<span class="hljs-keyword">if</span> (direction !== <span class="hljs-number">1</span> && direction !== <span class="hljs-number">-1</span>) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid direction: <span class="hljs-subst">${direction}</span>`</span>);
}
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.isValidNoteValue(note1) || !<span class="hljs-keyword">this</span>.isValidNoteValue(note2)) {
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">`Invalid notes: <span class="hljs-subst">${note1}</span>, <span class="hljs-subst">${note2}</span>`</span>);
}
<span class="hljs-keyword">let</span> difference = direction === <span class="hljs-number">1</span>
? note2 - note1
: note1 - note2;
<span class="hljs-keyword">if</span> (difference < <span class="hljs-number">0</span>) difference += Music.NUM_TONES;
<span class="hljs-keyword">return</span> difference;
}</pre></div>
<p>Create a scale map that represents the pitch state for a
<code>keySignature</code>. For example, passing a <code>G</code> to <code>keySignature</code> would
return a scale map with every note naturalized except for <code>F</code> which
has an <code>F#</code> state.</p>
<div class='highlight'><pre> createScaleMap(keySignature) {
<span class="hljs-keyword">const</span> keySigParts = <span class="hljs-keyword">this</span>.getKeyParts(keySignature);
<span class="hljs-keyword">const</span> scaleName = Music.scaleTypes[keySigParts.type];
<span class="hljs-keyword">let</span> keySigString = keySigParts.root;
<span class="hljs-keyword">if</span> (keySigParts.accidental) keySigString += keySigParts.accidental;
<span class="hljs-keyword">if</span> (!scaleName) <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Vex.RERR(<span class="hljs-string">'BadArguments'</span>, <span class="hljs-string">'Unsupported key type: '</span> + keySignature);
<span class="hljs-keyword">const</span> scale = <span class="hljs-keyword">this</span>.g