abcjs 6.1.8 → 6.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE.md +66 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +4373 -4424
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/index.js +1 -1
- package/package.json +6 -6
- package/plugin.js +1 -1
- package/src/api/abc_timing_callbacks.js +7 -3
- package/src/api/abc_tunebook_svg.js +1 -2
- package/src/data/abc_tune.js +2 -2
- package/src/midi/abc_midi_create.js +8 -2
- package/src/parse/abc_common.js +0 -47
- package/src/parse/abc_parse.js +16 -16
- package/src/parse/abc_parse_book.js +3 -3
- package/src/parse/abc_parse_directive.js +26 -7
- package/src/parse/abc_parse_header.js +11 -9
- package/src/parse/abc_parse_key_voice.js +17 -17
- package/src/parse/abc_parse_music.js +89 -106
- package/src/parse/abc_tokenizer.js +60 -60
- package/src/parse/abc_transpose.js +14 -3
- package/src/parse/tune-builder.js +19 -14
- package/src/synth/abc_midi_flattener.js +25 -9
- package/src/synth/abc_midi_sequencer.js +1 -1
- package/src/synth/create-synth.js +41 -0
- package/src/synth/note-to-midi.js +50 -0
- package/src/tablatures/instruments/guitar/tab-guitar.js +0 -2
- package/src/tablatures/instruments/string-patterns.js +46 -28
- package/src/tablatures/instruments/tab-note.js +26 -103
- package/src/tablatures/instruments/violin/tab-violin.js +0 -2
- package/src/tablatures/tab-absolute-elements.js +9 -31
- package/src/tablatures/tab-renderer.js +2 -2
- package/src/test/abc_parser_lint.js +8 -5
- package/src/write/README.md +31 -0
- package/src/write/creation/abstract-engraver.js +1036 -0
- package/src/write/creation/add-chord.js +102 -0
- package/src/write/{add-text-if.js → creation/add-text-if.js} +6 -6
- package/src/write/{calcHeight.js → creation/calc-height.js} +2 -2
- package/src/write/creation/create-clef.js +72 -0
- package/src/write/creation/create-key-signature.js +31 -0
- package/src/write/creation/create-note-head.js +107 -0
- package/src/write/creation/create-time-signature.js +55 -0
- package/src/write/creation/decoration.js +357 -0
- package/src/write/{abc_absolute_element.js → creation/elements/absolute-element.js} +14 -15
- package/src/write/creation/elements/beam-element.js +113 -0
- package/src/write/{bottom-text.js → creation/elements/bottom-text.js} +14 -15
- package/src/write/{abc_brace_element.js → creation/elements/brace-element.js} +5 -5
- package/src/write/creation/elements/free-text.js +41 -0
- package/src/write/{abc_relative_element.js → creation/elements/relative-element.js} +8 -7
- package/src/write/{separator.js → creation/elements/separator.js} +2 -2
- package/src/write/{abc_staff_group_element.js → creation/elements/staff-group-element.js} +4 -4
- package/src/write/{subtitle.js → creation/elements/subtitle.js} +3 -3
- package/src/write/creation/elements/tempo-element.js +63 -0
- package/src/write/{abc_tie_element.js → creation/elements/tie-element.js} +15 -11
- package/src/write/{top-text.js → creation/elements/top-text.js} +12 -12
- package/src/write/creation/elements/triplet-element.js +28 -0
- package/src/write/{abc_voice_element.js → creation/elements/voice-element.js} +3 -3
- package/src/write/creation/glyphs.js +226 -0
- package/src/write/creation/translate-chord.js +37 -0
- package/src/write/draw/absolute.js +5 -5
- package/src/write/draw/beam.js +8 -8
- package/src/write/draw/brace.js +33 -33
- package/src/write/draw/crescendo.js +4 -4
- package/src/write/draw/debug-box.js +1 -1
- package/src/write/draw/draw.js +7 -7
- package/src/write/draw/dynamics.js +2 -2
- package/src/write/draw/ending.js +6 -6
- package/src/write/draw/glissando.js +17 -17
- package/src/write/draw/group-elements.js +51 -51
- package/src/write/draw/horizontal-line.js +9 -9
- package/src/write/draw/non-music.js +1 -1
- package/src/write/draw/print-line.js +15 -16
- package/src/write/draw/print-stem.js +5 -5
- package/src/write/draw/print-symbol.js +12 -12
- package/src/write/draw/print-vertical-line.js +8 -8
- package/src/write/draw/relative.js +17 -16
- package/src/write/draw/selectables.js +5 -5
- package/src/write/draw/separator.js +4 -4
- package/src/write/draw/set-paper-size.js +2 -2
- package/src/write/draw/sprintf.js +31 -31
- package/src/write/draw/staff-group.js +36 -30
- package/src/write/draw/staff-line.js +2 -2
- package/src/write/draw/staff.js +4 -4
- package/src/write/draw/tab-line.js +26 -26
- package/src/write/draw/tempo.js +30 -30
- package/src/write/draw/text.js +5 -5
- package/src/write/draw/tie.js +18 -18
- package/src/write/draw/triplet.js +6 -6
- package/src/write/draw/voice.js +16 -17
- package/src/write/{abc_engraver_controller.js → engraver-controller.js} +58 -51
- package/src/write/{classes.js → helpers/classes.js} +6 -6
- package/src/write/{get-font-and-attr.js → helpers/get-font-and-attr.js} +9 -7
- package/src/write/{get-text-size.js → helpers/get-text-size.js} +5 -5
- package/src/write/{set-class.js → helpers/set-class.js} +1 -1
- package/src/write/{abc_spacing.js → helpers/spacing.js} +1 -1
- package/src/write/{highlight.js → interactive/highlight.js} +1 -1
- package/src/write/{selection.js → interactive/selection.js} +27 -27
- package/src/write/{unhighlight.js → interactive/unhighlight.js} +1 -1
- package/src/write/layout/beam.js +13 -13
- package/src/write/layout/get-left-edge-of-staff.js +4 -4
- package/src/write/layout/layout.js +74 -74
- package/src/write/layout/{setUpperAndLowerElements.js → set-upper-and-lower-elements.js} +8 -8
- package/src/write/layout/{staffGroup.js → staff-group.js} +32 -32
- package/src/write/layout/triplet.js +4 -4
- package/src/write/layout/{VoiceElements.js → voice-elements.js} +23 -23
- package/src/write/layout/voice.js +6 -6
- package/src/write/{abc_renderer.js → renderer.js} +35 -32
- package/src/write/svg.js +35 -35
- package/test.js +1 -1
- package/types/index.d.ts +99 -22
- package/version.js +1 -1
- package/src/tablatures/instruments/guitar/guitar-fonts.js +0 -19
- package/src/tablatures/instruments/violin/violin-fonts.js +0 -19
- package/src/tablatures/transposer.js +0 -110
- package/src/write/abc_abstract_engraver.js +0 -1026
- package/src/write/abc_beam_element.js +0 -113
- package/src/write/abc_create_clef.js +0 -72
- package/src/write/abc_create_key_signature.js +0 -33
- package/src/write/abc_create_note_head.js +0 -107
- package/src/write/abc_create_time_signature.js +0 -55
- package/src/write/abc_decoration.js +0 -341
- package/src/write/abc_glyphs.js +0 -224
- package/src/write/abc_tempo_element.js +0 -63
- package/src/write/abc_triplet_element.js +0 -28
- package/src/write/add-chord.js +0 -103
- package/src/write/format-jazz-chord.js +0 -15
- package/src/write/free-text.js +0 -41
- /package/src/write/{abc_crescendo_element.js → creation/elements/crescendo-element.js} +0 -0
- /package/src/write/{abc_dynamic_decoration.js → creation/elements/dynamic-decoration.js} +0 -0
- /package/src/write/{abc_ending_element.js → creation/elements/ending-element.js} +0 -0
- /package/src/write/{abc_glissando_element.js → creation/elements/glissando-element.js} +0 -0
- /package/src/write/layout/{getBarYAt.js → get-bar-y-at.js} +0 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
// abc_decoration.js: Creates a data structure suitable for printing a line of abc
|
|
2
|
+
|
|
3
|
+
var DynamicDecoration = require('./elements/dynamic-decoration');
|
|
4
|
+
var CrescendoElem = require('./elements/crescendo-element');
|
|
5
|
+
var GlissandoElem = require('./elements/glissando-element');
|
|
6
|
+
var glyphs = require('./glyphs');
|
|
7
|
+
var RelativeElement = require('./elements/relative-element');
|
|
8
|
+
var TieElem = require('./elements/tie-element');
|
|
9
|
+
|
|
10
|
+
var Decoration = function Decoration() {
|
|
11
|
+
this.startDiminuendoX = undefined;
|
|
12
|
+
this.startCrescendoX = undefined;
|
|
13
|
+
this.minTop = 12; // TODO-PER: this is assuming a 5-line staff. Pass that info in.
|
|
14
|
+
this.minBottom = 0;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
var closeDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch) {
|
|
18
|
+
var yPos;
|
|
19
|
+
for (var i = 0; i < decoration.length; i++) {
|
|
20
|
+
if (decoration[i] === "staccato" || decoration[i] === "tenuto" || decoration[i] === "accent") {
|
|
21
|
+
var symbol = "scripts." + decoration[i];
|
|
22
|
+
if (decoration[i] === "accent") symbol = "scripts.sforzato";
|
|
23
|
+
if (yPos === undefined)
|
|
24
|
+
yPos = (dir === "down") ? pitch + 2 : minPitch - 2;
|
|
25
|
+
else
|
|
26
|
+
yPos = (dir === "down") ? yPos + 2 : yPos - 2;
|
|
27
|
+
if (decoration[i] === "accent") {
|
|
28
|
+
// Always place the accent three pitches away, no matter whether that is a line or space.
|
|
29
|
+
if (dir === "up") yPos--;
|
|
30
|
+
else yPos++;
|
|
31
|
+
} else {
|
|
32
|
+
// don't place on a stave line. The stave lines are 2,4,6,8,10
|
|
33
|
+
switch (yPos) {
|
|
34
|
+
case 2:
|
|
35
|
+
case 4:
|
|
36
|
+
case 6:
|
|
37
|
+
case 8:
|
|
38
|
+
case 10:
|
|
39
|
+
if (dir === "up") yPos--;
|
|
40
|
+
else yPos++;
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (pitch > 9) yPos++; // take up some room of those that are above
|
|
45
|
+
var deltaX = width / 2;
|
|
46
|
+
if (glyphs.getSymbolAlign(symbol) !== "center") {
|
|
47
|
+
deltaX -= (glyphs.getSymbolWidth(symbol) / 2);
|
|
48
|
+
}
|
|
49
|
+
abselem.addFixedX(new RelativeElement(symbol, deltaX, glyphs.getSymbolWidth(symbol), yPos));
|
|
50
|
+
}
|
|
51
|
+
if (decoration[i] === "slide" && abselem.heads[0]) {
|
|
52
|
+
var yPos2 = abselem.heads[0].pitch;
|
|
53
|
+
yPos2 -= 2; // TODO-PER: not sure what this fudge factor is.
|
|
54
|
+
var blank1 = new RelativeElement("", -roomtaken - 15, 0, yPos2 - 1);
|
|
55
|
+
var blank2 = new RelativeElement("", -roomtaken - 5, 0, yPos2 + 1);
|
|
56
|
+
abselem.addFixedX(blank1);
|
|
57
|
+
abselem.addFixedX(blank2);
|
|
58
|
+
voice.addOther(new TieElem({ anchor1: blank1, anchor2: blank2, fixedY: true }));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (yPos === undefined)
|
|
62
|
+
yPos = pitch;
|
|
63
|
+
|
|
64
|
+
return { above: yPos, below: abselem.bottom };
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
var volumeDecoration = function (voice, decoration, abselem, positioning) {
|
|
68
|
+
for (var i = 0; i < decoration.length; i++) {
|
|
69
|
+
switch (decoration[i]) {
|
|
70
|
+
case "p":
|
|
71
|
+
case "mp":
|
|
72
|
+
case "pp":
|
|
73
|
+
case "ppp":
|
|
74
|
+
case "pppp":
|
|
75
|
+
case "f":
|
|
76
|
+
case "ff":
|
|
77
|
+
case "fff":
|
|
78
|
+
case "ffff":
|
|
79
|
+
case "sfz":
|
|
80
|
+
case "mf":
|
|
81
|
+
var elem = new DynamicDecoration(abselem, decoration[i], positioning);
|
|
82
|
+
voice.addOther(elem);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
var compoundDecoration = function (decoration, pitch, width, abselem, dir) {
|
|
88
|
+
function highestPitch() {
|
|
89
|
+
if (abselem.heads.length === 0)
|
|
90
|
+
return 10; // TODO-PER: I don't know if this can happen, but we'll return the top of the staff if so.
|
|
91
|
+
var pitch = abselem.heads[0].pitch;
|
|
92
|
+
for (var i = 1; i < abselem.heads.length; i++)
|
|
93
|
+
pitch = Math.max(pitch, abselem.heads[i].pitch);
|
|
94
|
+
return pitch;
|
|
95
|
+
}
|
|
96
|
+
function lowestPitch() {
|
|
97
|
+
if (abselem.heads.length === 0)
|
|
98
|
+
return 2; // TODO-PER: I don't know if this can happen, but we'll return the bottom of the staff if so.
|
|
99
|
+
var pitch = abselem.heads[0].pitch;
|
|
100
|
+
for (var i = 1; i < abselem.heads.length; i++)
|
|
101
|
+
pitch = Math.min(pitch, abselem.heads[i].pitch);
|
|
102
|
+
return pitch;
|
|
103
|
+
}
|
|
104
|
+
function compoundDecoration(symbol, count) {
|
|
105
|
+
var placement = (dir === 'down') ? lowestPitch() + 1 : highestPitch() + 9;
|
|
106
|
+
if (dir !== 'down' && count === 1)
|
|
107
|
+
placement--;
|
|
108
|
+
var deltaX = width / 2;
|
|
109
|
+
deltaX += (dir === 'down') ? -5 : 3;
|
|
110
|
+
for (var i = 0; i < count; i++) {
|
|
111
|
+
placement -= 1;
|
|
112
|
+
abselem.addFixedX(new RelativeElement(symbol, deltaX, glyphs.getSymbolWidth(symbol), placement));
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
for (var i = 0; i < decoration.length; i++) {
|
|
117
|
+
switch (decoration[i]) {
|
|
118
|
+
case "/": compoundDecoration("flags.ugrace", 1); break;
|
|
119
|
+
case "//": compoundDecoration("flags.ugrace", 2); break;
|
|
120
|
+
case "///": compoundDecoration("flags.ugrace", 3); break;
|
|
121
|
+
case "////": compoundDecoration("flags.ugrace", 4); break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
var stackedDecoration = function (decoration, width, abselem, yPos, positioning, minTop, minBottom) {
|
|
127
|
+
function incrementPlacement(placement, height) {
|
|
128
|
+
if (placement === 'above')
|
|
129
|
+
yPos.above += height;
|
|
130
|
+
else
|
|
131
|
+
yPos.below -= height;
|
|
132
|
+
}
|
|
133
|
+
function getPlacement(placement) {
|
|
134
|
+
var y;
|
|
135
|
+
if (placement === 'above') {
|
|
136
|
+
y = yPos.above;
|
|
137
|
+
if (y < minTop)
|
|
138
|
+
y = minTop;
|
|
139
|
+
} else {
|
|
140
|
+
y = yPos.below;
|
|
141
|
+
if (y > minBottom)
|
|
142
|
+
y = minBottom;
|
|
143
|
+
}
|
|
144
|
+
return y;
|
|
145
|
+
}
|
|
146
|
+
function textDecoration(text, placement, anchor) {
|
|
147
|
+
var y = getPlacement(placement);
|
|
148
|
+
var textFudge = 2;
|
|
149
|
+
var textHeight = 5;
|
|
150
|
+
// TODO-PER: Get the height of the current font and use that for the thickness.
|
|
151
|
+
abselem.addFixedX(new RelativeElement(text, width / 2, 0, y + textFudge, { type: "decoration", klass: 'ornament', thickness: 3, anchor: anchor }));
|
|
152
|
+
|
|
153
|
+
incrementPlacement(placement, textHeight);
|
|
154
|
+
}
|
|
155
|
+
function symbolDecoration(symbol, placement) {
|
|
156
|
+
var deltaX = width / 2;
|
|
157
|
+
if (glyphs.getSymbolAlign(symbol) !== "center") {
|
|
158
|
+
deltaX -= (glyphs.getSymbolWidth(symbol) / 2);
|
|
159
|
+
}
|
|
160
|
+
var height = glyphs.symbolHeightInPitches(symbol) + 1; // adding a little padding so nothing touches.
|
|
161
|
+
var y = getPlacement(placement);
|
|
162
|
+
y = (placement === 'above') ? y + height / 2 : y - height / 2;// Center the element vertically.
|
|
163
|
+
abselem.addFixedX(new RelativeElement(symbol, deltaX, glyphs.getSymbolWidth(symbol), y, { klass: 'ornament', thickness: glyphs.symbolHeightInPitches(symbol) }));
|
|
164
|
+
|
|
165
|
+
incrementPlacement(placement, height);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
var symbolList = {
|
|
169
|
+
"+": "scripts.stopped",
|
|
170
|
+
"open": "scripts.open",
|
|
171
|
+
"snap": "scripts.snap",
|
|
172
|
+
"wedge": "scripts.wedge",
|
|
173
|
+
"thumb": "scripts.thumb",
|
|
174
|
+
"shortphrase": "scripts.shortphrase",
|
|
175
|
+
"mediumphrase": "scripts.mediumphrase",
|
|
176
|
+
"longphrase": "scripts.longphrase",
|
|
177
|
+
"trill": "scripts.trill",
|
|
178
|
+
"roll": "scripts.roll",
|
|
179
|
+
"irishroll": "scripts.roll",
|
|
180
|
+
"marcato": "scripts.umarcato",
|
|
181
|
+
"dmarcato": "scripts.dmarcato",
|
|
182
|
+
"umarcato": "scripts.umarcato",
|
|
183
|
+
"turn": "scripts.turn",
|
|
184
|
+
"uppermordent": "scripts.prall",
|
|
185
|
+
"pralltriller": "scripts.prall",
|
|
186
|
+
"mordent": "scripts.mordent",
|
|
187
|
+
"lowermordent": "scripts.mordent",
|
|
188
|
+
"downbow": "scripts.downbow",
|
|
189
|
+
"upbow": "scripts.upbow",
|
|
190
|
+
"fermata": "scripts.ufermata",
|
|
191
|
+
"invertedfermata": "scripts.dfermata",
|
|
192
|
+
"breath": ",",
|
|
193
|
+
"coda": "scripts.coda",
|
|
194
|
+
"segno": "scripts.segno"
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
var hasOne = false;
|
|
198
|
+
for (var i = 0; i < decoration.length; i++) {
|
|
199
|
+
switch (decoration[i]) {
|
|
200
|
+
case "0":
|
|
201
|
+
case "1":
|
|
202
|
+
case "2":
|
|
203
|
+
case "3":
|
|
204
|
+
case "4":
|
|
205
|
+
case "5":
|
|
206
|
+
case "D.C.":
|
|
207
|
+
case "D.S.":
|
|
208
|
+
textDecoration(decoration[i], positioning, 'middle');
|
|
209
|
+
hasOne = true;
|
|
210
|
+
break;
|
|
211
|
+
case "D.C.alcoda":
|
|
212
|
+
textDecoration("D.C. al coda", positioning, 'end');
|
|
213
|
+
hasOne = true;
|
|
214
|
+
break;
|
|
215
|
+
case "D.C.alfine":
|
|
216
|
+
textDecoration("D.C. al fine", positioning, 'end');
|
|
217
|
+
hasOne = true;
|
|
218
|
+
break;
|
|
219
|
+
case "D.S.alcoda":
|
|
220
|
+
textDecoration("D.S. al coda", positioning, 'end');
|
|
221
|
+
hasOne = true;
|
|
222
|
+
break;
|
|
223
|
+
case "D.S.alfine":
|
|
224
|
+
textDecoration("D.S. al fine", positioning, 'end');
|
|
225
|
+
hasOne = true;
|
|
226
|
+
break;
|
|
227
|
+
case "fine":
|
|
228
|
+
textDecoration("FINE", positioning, 'middle');
|
|
229
|
+
hasOne = true;
|
|
230
|
+
break;
|
|
231
|
+
case "+":
|
|
232
|
+
case "open":
|
|
233
|
+
case "snap":
|
|
234
|
+
case "wedge":
|
|
235
|
+
case "thumb":
|
|
236
|
+
case "shortphrase":
|
|
237
|
+
case "mediumphrase":
|
|
238
|
+
case "longphrase":
|
|
239
|
+
case "trill":
|
|
240
|
+
case "roll":
|
|
241
|
+
case "irishroll":
|
|
242
|
+
case "marcato":
|
|
243
|
+
case "dmarcato":
|
|
244
|
+
case "turn":
|
|
245
|
+
case "uppermordent":
|
|
246
|
+
case "pralltriller":
|
|
247
|
+
case "mordent":
|
|
248
|
+
case "lowermordent":
|
|
249
|
+
case "downbow":
|
|
250
|
+
case "upbow":
|
|
251
|
+
case "fermata":
|
|
252
|
+
case "breath":
|
|
253
|
+
case "umarcato":
|
|
254
|
+
case "coda":
|
|
255
|
+
case "segno":
|
|
256
|
+
symbolDecoration(symbolList[decoration[i]], positioning);
|
|
257
|
+
hasOne = true;
|
|
258
|
+
break;
|
|
259
|
+
case "invertedfermata":
|
|
260
|
+
symbolDecoration(symbolList[decoration[i]], 'below');
|
|
261
|
+
hasOne = true;
|
|
262
|
+
break;
|
|
263
|
+
case "mark":
|
|
264
|
+
abselem.klass = "mark";
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return hasOne;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
function leftDecoration(decoration, abselem, roomtaken) {
|
|
272
|
+
for (var i = 0; i < decoration.length; i++) {
|
|
273
|
+
switch (decoration[i]) {
|
|
274
|
+
case "arpeggio":
|
|
275
|
+
// The arpeggio symbol is the height of a note (that is, two Y units). This stacks as many as we need to go from the
|
|
276
|
+
// top note to the bottom note. The arpeggio should also be a little taller than the stacked notes, so there is an extra
|
|
277
|
+
// one drawn and it is offset by half of a note height (that is, one Y unit).
|
|
278
|
+
for (var j = abselem.abcelem.minpitch - 1; j <= abselem.abcelem.maxpitch; j += 2) {
|
|
279
|
+
abselem.addExtra(
|
|
280
|
+
new RelativeElement(
|
|
281
|
+
"scripts.arpeggio",
|
|
282
|
+
-glyphs.getSymbolWidth("scripts.arpeggio") * 2 - roomtaken,
|
|
283
|
+
0,
|
|
284
|
+
j + 2,
|
|
285
|
+
{ klass: 'ornament', thickness: glyphs.symbolHeightInPitches("scripts.arpeggio") }
|
|
286
|
+
)
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, positioning) {
|
|
295
|
+
var diminuendo;
|
|
296
|
+
var crescendo;
|
|
297
|
+
var glissando;
|
|
298
|
+
for (var i = 0; i < decoration.length; i++) {
|
|
299
|
+
switch (decoration[i]) {
|
|
300
|
+
case "diminuendo(":
|
|
301
|
+
this.startDiminuendoX = abselem;
|
|
302
|
+
diminuendo = undefined;
|
|
303
|
+
break;
|
|
304
|
+
case "diminuendo)":
|
|
305
|
+
diminuendo = { start: this.startDiminuendoX, stop: abselem };
|
|
306
|
+
this.startDiminuendoX = undefined;
|
|
307
|
+
break;
|
|
308
|
+
case "crescendo(":
|
|
309
|
+
this.startCrescendoX = abselem;
|
|
310
|
+
crescendo = undefined;
|
|
311
|
+
break;
|
|
312
|
+
case "crescendo)":
|
|
313
|
+
crescendo = { start: this.startCrescendoX, stop: abselem };
|
|
314
|
+
this.startCrescendoX = undefined;
|
|
315
|
+
break;
|
|
316
|
+
case "glissando(":
|
|
317
|
+
this.startGlissandoX = abselem;
|
|
318
|
+
glissando = undefined;
|
|
319
|
+
break;
|
|
320
|
+
case "glissando)":
|
|
321
|
+
glissando = { start: this.startGlissandoX, stop: abselem };
|
|
322
|
+
this.startGlissandoX = undefined;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
if (diminuendo) {
|
|
327
|
+
voice.addOther(new CrescendoElem(diminuendo.start, diminuendo.stop, ">", positioning));
|
|
328
|
+
}
|
|
329
|
+
if (crescendo) {
|
|
330
|
+
voice.addOther(new CrescendoElem(crescendo.start, crescendo.stop, "<", positioning));
|
|
331
|
+
}
|
|
332
|
+
if (glissando) {
|
|
333
|
+
voice.addOther(new GlissandoElem(glissando.start, glissando.stop));
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
|
|
337
|
+
Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals) {
|
|
338
|
+
if (!positioning)
|
|
339
|
+
positioning = { ornamentPosition: 'above', volumePosition: hasVocals ? 'above' : 'below', dynamicPosition: hasVocals ? 'above' : 'below' };
|
|
340
|
+
// These decorations don't affect the placement of other decorations
|
|
341
|
+
volumeDecoration(voice, decoration, abselem, positioning.volumePosition);
|
|
342
|
+
this.dynamicDecoration(voice, decoration, abselem, positioning.dynamicPosition);
|
|
343
|
+
compoundDecoration(decoration, pitch, width, abselem, dir);
|
|
344
|
+
|
|
345
|
+
// treat staccato, accent, and tenuto first (may need to shift other markers)
|
|
346
|
+
var yPos = closeDecoration(voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch);
|
|
347
|
+
// yPos is an object containing 'above' and 'below'. That is the placement of the next symbol on either side.
|
|
348
|
+
|
|
349
|
+
yPos.above = Math.max(yPos.above, this.minTop);
|
|
350
|
+
var hasOne = stackedDecoration(decoration, width, abselem, yPos, positioning.ornamentPosition, this.minTop, this.minBottom);
|
|
351
|
+
if (hasOne) {
|
|
352
|
+
// abselem.top = Math.max(yPos.above + 3, abselem.top); // TODO-PER: Not sure why we need this fudge factor.
|
|
353
|
+
}
|
|
354
|
+
leftDecoration(decoration, abselem, roomtaken);
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
module.exports = Decoration;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// abc_absolute_element.js: Definition of the AbsoluteElement class.
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
var
|
|
5
|
-
var unhighlight = require("./unhighlight");
|
|
3
|
+
var highlight = require("../../interactive/highlight");
|
|
4
|
+
var unhighlight = require("../../interactive/unhighlight");
|
|
6
5
|
|
|
7
6
|
// Everything that is placed in the SVG is first created as an absolute element. This is one unit of graphic information.
|
|
8
7
|
// That is, it embodies a concept: a clef, a time signature, a bar line,etc. or most complexly:
|
|
@@ -32,7 +31,7 @@ var unhighlight = require("./unhighlight");
|
|
|
32
31
|
// minspacing - spacing which must be taken on top of the width defined by the duration
|
|
33
32
|
// type is a meta-type for the element. It is not necessary for drawing, but it is useful to make semantic sense of the element. For instance, it can be used in the element's class name.
|
|
34
33
|
var AbsoluteElement = function AbsoluteElement(abcelem, duration, minspacing, type, tuneNumber, options) {
|
|
35
|
-
// console.log("Absolute:",abcelem, duration, minspacing, type, tuneNumber, options);
|
|
34
|
+
// console.log("Absolute:",abcelem, duration, minspacing, type, tuneNumber, options);
|
|
36
35
|
if (!options)
|
|
37
36
|
options = {};
|
|
38
37
|
this.tuneNumber = tuneNumber;
|
|
@@ -92,16 +91,16 @@ AbsoluteElement.prototype.addExtra = function (extra) {
|
|
|
92
91
|
// )
|
|
93
92
|
// console.log("extra", extra);
|
|
94
93
|
|
|
95
|
-
this.fixed.w = Math.max(this.fixed.w, extra.dx+extra.w);
|
|
94
|
+
this.fixed.w = Math.max(this.fixed.w, extra.dx + extra.w);
|
|
96
95
|
if (this.fixed.t === undefined) this.fixed.t = extra.top; else this.fixed.t = Math.max(this.fixed.t, extra.top);
|
|
97
96
|
if (this.fixed.b === undefined) this.fixed.b = extra.bottom; else this.fixed.b = Math.min(this.fixed.b, extra.bottom);
|
|
98
|
-
if (extra.dx<this.extraw) this.extraw = extra.dx;
|
|
97
|
+
if (extra.dx < this.extraw) this.extraw = extra.dx;
|
|
99
98
|
this.extra[this.extra.length] = extra;
|
|
100
99
|
this._addChild(extra);
|
|
101
100
|
};
|
|
102
101
|
|
|
103
102
|
AbsoluteElement.prototype.addHead = function (head) {
|
|
104
|
-
if (head.dx<this.extraw) this.extraw = head.dx;
|
|
103
|
+
if (head.dx < this.extraw) this.extraw = head.dx;
|
|
105
104
|
this.heads[this.heads.length] = head;
|
|
106
105
|
this.addRight(head);
|
|
107
106
|
};
|
|
@@ -128,7 +127,7 @@ AbsoluteElement.prototype.addRight = function (right) {
|
|
|
128
127
|
// )
|
|
129
128
|
// console.log("right", right);
|
|
130
129
|
// These are the elements that are the fixed part.
|
|
131
|
-
this.fixed.w = Math.max(this.fixed.w, right.dx+right.w);
|
|
130
|
+
this.fixed.w = Math.max(this.fixed.w, right.dx + right.w);
|
|
132
131
|
if (right.top !== undefined) {
|
|
133
132
|
if (this.fixed.t === undefined) this.fixed.t = right.top; else this.fixed.t = Math.max(this.fixed.t, right.top);
|
|
134
133
|
}
|
|
@@ -137,7 +136,7 @@ AbsoluteElement.prototype.addRight = function (right) {
|
|
|
137
136
|
}
|
|
138
137
|
// if (isNaN(this.fixed.t) || isNaN(this.fixed.b))
|
|
139
138
|
// debugger;
|
|
140
|
-
if (right.dx+right.w>this.w) this.w = right.dx+right.w;
|
|
139
|
+
if (right.dx + right.w > this.w) this.w = right.dx + right.w;
|
|
141
140
|
this.right[this.right.length] = right;
|
|
142
141
|
this._addChild(right);
|
|
143
142
|
};
|
|
@@ -161,15 +160,15 @@ AbsoluteElement.prototype.addCentered = function (elem) {
|
|
|
161
160
|
// elem.type !== 'lyric'
|
|
162
161
|
// )
|
|
163
162
|
// console.log("centered", elem);
|
|
164
|
-
var half = elem.w/2;
|
|
165
|
-
if (-half<this.extraw) this.extraw = -half;
|
|
163
|
+
var half = elem.w / 2;
|
|
164
|
+
if (-half < this.extraw) this.extraw = -half;
|
|
166
165
|
this.extra[this.extra.length] = elem;
|
|
167
|
-
if (elem.dx+half>this.w) this.w = elem.dx+half;
|
|
166
|
+
if (elem.dx + half > this.w) this.w = elem.dx + half;
|
|
168
167
|
this.right[this.right.length] = elem;
|
|
169
168
|
this._addChild(elem);
|
|
170
169
|
};
|
|
171
170
|
|
|
172
|
-
AbsoluteElement.prototype.setLimit = function(member, child) {
|
|
171
|
+
AbsoluteElement.prototype.setLimit = function (member, child) {
|
|
173
172
|
if (!child[member]) return;
|
|
174
173
|
if (!this.specialY[member])
|
|
175
174
|
this.specialY[member] = child[member];
|
|
@@ -178,7 +177,7 @@ AbsoluteElement.prototype.setLimit = function(member, child) {
|
|
|
178
177
|
};
|
|
179
178
|
|
|
180
179
|
AbsoluteElement.prototype._addChild = function (child) {
|
|
181
|
-
// console.log("Relative:",child);
|
|
180
|
+
// console.log("Relative:",child);
|
|
182
181
|
child.parent = this;
|
|
183
182
|
this.children[this.children.length] = child;
|
|
184
183
|
this.pushTop(child.top);
|
|
@@ -216,7 +215,7 @@ AbsoluteElement.prototype.pushBottom = function (bottom) {
|
|
|
216
215
|
|
|
217
216
|
AbsoluteElement.prototype.setX = function (x) {
|
|
218
217
|
this.x = x;
|
|
219
|
-
for (var i=0; i<this.children.length; i++)
|
|
218
|
+
for (var i = 0; i < this.children.length; i++)
|
|
220
219
|
this.children[i].setX(x);
|
|
221
220
|
};
|
|
222
221
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// abc_beam_element.js: Definition of the BeamElem class.
|
|
2
|
+
|
|
3
|
+
// Most elements on the page are related to a particular absolute element -- notes, rests, bars, etc. Beams, however, span multiple elements.
|
|
4
|
+
// This means that beams can't be laid out until the absolute elements are placed. There is the further complication that the stems for beamed
|
|
5
|
+
// notes can't be laid out until the beams are because we don't know how long they will be until we know the slope of the beam and the horizontal
|
|
6
|
+
// spacing of the absolute elements.
|
|
7
|
+
//
|
|
8
|
+
// So, when a beam is detected, a BeamElem is created, then all notes belonging to that beam are added to it. These notes are not given stems at that time.
|
|
9
|
+
// Then, after the horizontal layout is complete, all of the BeamElem are iterated to set the beam position, then all of the notes that are beamed are given
|
|
10
|
+
// stems. After that, we are ready for the drawing step.
|
|
11
|
+
|
|
12
|
+
// There are three phases: the setup phase, when new elements are being discovered, the layout phase, when everything is calculated, and the drawing phase,
|
|
13
|
+
// when the object is not changed, but is used to put the elements on the page.
|
|
14
|
+
|
|
15
|
+
//
|
|
16
|
+
// Setup phase
|
|
17
|
+
//
|
|
18
|
+
var BeamElem = function BeamElem(stemHeight, type, flat, firstElement) {
|
|
19
|
+
// type is "grace", "up", "down", or undefined. flat is used to force flat beams, as it commonly found in the grace notes of bagpipe music.
|
|
20
|
+
this.type = "BeamElem";
|
|
21
|
+
this.isflat = !!flat;
|
|
22
|
+
this.isgrace = !!(type && type === "grace");
|
|
23
|
+
this.forceup = !!(this.isgrace || (type && type === "up"));
|
|
24
|
+
this.forcedown = !!(type && type === "down");
|
|
25
|
+
this.elems = []; // all the AbsoluteElements that this beam touches. It may include embedded rests.
|
|
26
|
+
this.total = 0;
|
|
27
|
+
this.average = 6; // use middle line as start for average.
|
|
28
|
+
this.allrests = true;
|
|
29
|
+
this.stemHeight = stemHeight;
|
|
30
|
+
this.beams = []; // During the layout phase, this will become a list of the beams that need to be drawn.
|
|
31
|
+
if (firstElement && firstElement.duration) {
|
|
32
|
+
this.duration = firstElement.duration;
|
|
33
|
+
if (firstElement.startTriplet) {
|
|
34
|
+
this.duration *= firstElement.tripletMultiplier;
|
|
35
|
+
}
|
|
36
|
+
this.duration = Math.round(this.duration * 1000) / 1000;
|
|
37
|
+
} else
|
|
38
|
+
this.duration = 0;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
BeamElem.prototype.setHint = function () {
|
|
42
|
+
this.hint = true;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
BeamElem.prototype.runningDirection = function (abcelem) {
|
|
46
|
+
var pitch = abcelem.averagepitch;
|
|
47
|
+
if (pitch === undefined) return; // don't include elements like spacers in beams
|
|
48
|
+
this.total = Math.round(this.total + pitch);
|
|
49
|
+
if (!this.count)
|
|
50
|
+
this.count = 0;
|
|
51
|
+
this.count++
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
BeamElem.prototype.add = function (abselem) {
|
|
55
|
+
var pitch = abselem.abcelem.averagepitch;
|
|
56
|
+
if (pitch === undefined) return; // don't include elements like spacers in beams
|
|
57
|
+
if (!abselem.abcelem.rest)
|
|
58
|
+
this.allrests = false;
|
|
59
|
+
abselem.beam = this;
|
|
60
|
+
this.elems.push(abselem);
|
|
61
|
+
this.total = Math.round(this.total + pitch);
|
|
62
|
+
if (this.min === undefined || abselem.abcelem.minpitch < this.min) {
|
|
63
|
+
this.min = abselem.abcelem.minpitch;
|
|
64
|
+
}
|
|
65
|
+
if (this.max === undefined || abselem.abcelem.maxpitch > this.max) {
|
|
66
|
+
this.max = abselem.abcelem.maxpitch;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
BeamElem.prototype.addBeam = function (beam) {
|
|
71
|
+
this.beams.push(beam);
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
BeamElem.prototype.setStemDirection = function () {
|
|
75
|
+
// Have to figure this out before the notes are placed because placing the notes also places the decorations.
|
|
76
|
+
this.average = calcAverage(this.total, this.count);
|
|
77
|
+
if (this.forceup) {
|
|
78
|
+
this.stemsUp = true;
|
|
79
|
+
} else if (this.forcedown) {
|
|
80
|
+
this.stemsUp = false;
|
|
81
|
+
} else {
|
|
82
|
+
var middleLine = 6; // hardcoded 6 is B
|
|
83
|
+
this.stemsUp = this.average < middleLine; // true is up, false is down;
|
|
84
|
+
}
|
|
85
|
+
delete this.count;
|
|
86
|
+
this.total = 0;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
BeamElem.prototype.calcDir = function () {
|
|
90
|
+
this.average = calcAverage(this.total, this.elems.length);
|
|
91
|
+
if (this.forceup) {
|
|
92
|
+
this.stemsUp = true;
|
|
93
|
+
} else if (this.forcedown) {
|
|
94
|
+
this.stemsUp = false;
|
|
95
|
+
} else {
|
|
96
|
+
var middleLine = 6; // hardcoded 6 is B
|
|
97
|
+
this.stemsUp = this.average < middleLine; // true is up, false is down;
|
|
98
|
+
}
|
|
99
|
+
var dir = this.stemsUp ? 'up' : 'down';
|
|
100
|
+
for (var i = 0; i < this.elems.length; i++) {
|
|
101
|
+
for (var j = 0; j < this.elems[i].heads.length; j++) {
|
|
102
|
+
this.elems[i].heads[j].stemDir = dir;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
function calcAverage(total, numElements) {
|
|
108
|
+
if (!numElements)
|
|
109
|
+
return 0;
|
|
110
|
+
return total / numElements;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
module.exports = BeamElem;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const addTextIf = require("
|
|
1
|
+
const addTextIf = require("../add-text-if");
|
|
2
2
|
|
|
3
3
|
function BottomText(metaText, width, isPrint, paddingLeft, spacing, getTextSize) {
|
|
4
4
|
this.rows = [];
|
|
@@ -10,19 +10,18 @@ function BottomText(metaText, width, isPrint, paddingLeft, spacing, getTextSize)
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spacing, getTextSize) {
|
|
13
|
-
var indent = 50;
|
|
14
13
|
var klass = 'meta-bottom unaligned-words';
|
|
15
14
|
var defFont = 'wordsfont';
|
|
16
|
-
this.rows.push({startGroup: "unalignedWords", klass: 'abcjs-meta-bottom abcjs-unaligned-words', name: "words"});
|
|
15
|
+
this.rows.push({ startGroup: "unalignedWords", klass: 'abcjs-meta-bottom abcjs-unaligned-words', name: "words" });
|
|
17
16
|
var space = getTextSize.calc("i", defFont, klass);
|
|
18
17
|
|
|
19
|
-
this.rows.push({move: spacing.words});
|
|
18
|
+
this.rows.push({ move: spacing.words });
|
|
20
19
|
|
|
21
20
|
for (var j = 0; j < unalignedWords.length; j++) {
|
|
22
21
|
if (unalignedWords[j] === '')
|
|
23
|
-
this.rows.push({move: space.height});
|
|
22
|
+
this.rows.push({ move: space.height });
|
|
24
23
|
else if (typeof unalignedWords[j] === 'string') {
|
|
25
|
-
addTextIf(this.rows, { marginLeft: paddingLeft
|
|
24
|
+
addTextIf(this.rows, { marginLeft: paddingLeft, text: unalignedWords[j], font: defFont, klass: klass, inGroup: true, name: "words" }, getTextSize);
|
|
26
25
|
} else {
|
|
27
26
|
var largestY = 0;
|
|
28
27
|
var offsetX = 0;
|
|
@@ -30,7 +29,7 @@ BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spa
|
|
|
30
29
|
var thisWord = unalignedWords[j][k];
|
|
31
30
|
var font = (thisWord.font) ? thisWord.font : defFont;
|
|
32
31
|
this.rows.push({
|
|
33
|
-
left: paddingLeft +
|
|
32
|
+
left: paddingLeft + offsetX,
|
|
34
33
|
text: thisWord.text,
|
|
35
34
|
font: font,
|
|
36
35
|
anchor: 'start'
|
|
@@ -43,11 +42,11 @@ BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spa
|
|
|
43
42
|
offsetX += space.width;
|
|
44
43
|
}
|
|
45
44
|
}
|
|
46
|
-
this.rows.push({move: largestY});
|
|
45
|
+
this.rows.push({ move: largestY });
|
|
47
46
|
}
|
|
48
47
|
}
|
|
49
|
-
this.rows.push({move: space.height * 2});
|
|
50
|
-
this.rows.push({endGroup: "unalignedWords", absElemType: "unalignedWords", startChar: -1, endChar: -1, name: "unalignedWords"});
|
|
48
|
+
this.rows.push({ move: space.height * 2 });
|
|
49
|
+
this.rows.push({ endGroup: "unalignedWords", absElemType: "unalignedWords", startChar: -1, endChar: -1, name: "unalignedWords" });
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
BottomText.prototype.extraText = function (metaText, marginLeft, spacing, getTextSize) {
|
|
@@ -62,18 +61,18 @@ BottomText.prototype.extraText = function (metaText, marginLeft, spacing, getTex
|
|
|
62
61
|
if (metaText['abc-creator']) extraText += "Creator: " + metaText['abc-creator'] + "\n";
|
|
63
62
|
if (metaText['abc-edited-by']) extraText += "Edited By: " + metaText['abc-edited-by'] + "\n";
|
|
64
63
|
if (extraText.length > 0) {
|
|
65
|
-
|
|
64
|
+
addTextIf(this.rows, { marginLeft: marginLeft, text: extraText, font: 'historyfont', klass: 'meta-bottom extra-text', marginTop: spacing.info, absElemType: "extraText", name: "description" }, getTextSize);
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
BottomText.prototype.footer = function (footer, width, paddingLeft, getTextSize) {
|
|
70
69
|
var klass = 'header meta-bottom';
|
|
71
70
|
var font = "footerfont";
|
|
72
|
-
this.rows.push({startGroup: "footer", klass: klass});
|
|
71
|
+
this.rows.push({ startGroup: "footer", klass: klass });
|
|
73
72
|
// Note: whether there is a footer or not doesn't change any other positioning, so this doesn't change the Y-coordinate.
|
|
74
|
-
addTextIf(this.rows, { marginLeft: paddingLeft, text: footer.left, font: font, klass: klass, name: "footer"}, getTextSize);
|
|
75
|
-
addTextIf(this.rows, { marginLeft: paddingLeft + width / 2, text: footer.center, font: font, klass: klass, anchor: 'middle', name: "footer"}
|
|
76
|
-
addTextIf(this.rows, { marginLeft: paddingLeft + width, text: footer.right, font: font, klass: klass, anchor: 'end', name: "footer"}, getTextSize);
|
|
73
|
+
addTextIf(this.rows, { marginLeft: paddingLeft, text: footer.left, font: font, klass: klass, name: "footer" }, getTextSize);
|
|
74
|
+
addTextIf(this.rows, { marginLeft: paddingLeft + width / 2, text: footer.center, font: font, klass: klass, anchor: 'middle', name: "footer" }, getTextSize);
|
|
75
|
+
addTextIf(this.rows, { marginLeft: paddingLeft + width, text: footer.right, font: font, klass: klass, anchor: 'end', name: "footer" }, getTextSize);
|
|
77
76
|
}
|
|
78
77
|
|
|
79
78
|
module.exports = BottomText;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// abc_brace_element.js: Definition of the BraceElement class.
|
|
2
2
|
|
|
3
3
|
var BraceElem = function BraceElem(voice, type) {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
this.startVoice = voice;
|
|
5
|
+
this.type = type;
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
BraceElem.prototype.setBottomStaff = function(voice) {
|
|
8
|
+
BraceElem.prototype.setBottomStaff = function (voice) {
|
|
9
9
|
this.endVoice = voice;
|
|
10
10
|
// If only the start brace has a name then the name belongs to the brace instead of the staff.
|
|
11
11
|
if (this.startVoice.header && !this.endVoice.header) {
|
|
@@ -14,12 +14,12 @@ BraceElem.prototype.setBottomStaff = function(voice) {
|
|
|
14
14
|
}
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
BraceElem.prototype.continuing = function(voice) {
|
|
17
|
+
BraceElem.prototype.continuing = function (voice) {
|
|
18
18
|
// If the final staff isn't present, then use the last one we saw.
|
|
19
19
|
this.lastContinuedVoice = voice;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
|
-
BraceElem.prototype.getWidth = function() {
|
|
22
|
+
BraceElem.prototype.getWidth = function () {
|
|
23
23
|
return 10; // TODO-PER: right now the drawing function doesn't vary the width at all. If it does in the future then this will change.
|
|
24
24
|
};
|
|
25
25
|
|