abcjs 6.0.0-beta.9 → 6.0.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/.github/workflows/tests.yml +29 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/CONTRIBUTING.md +1 -0
- package/LICENSE.md +1 -1
- package/README.md +88 -7
- package/RELEASE.md +939 -1
- package/abcjs-audio.css +14 -5
- package/dist/.gitignore +1 -2
- package/dist/abcjs-basic-min.js +3 -0
- package/dist/abcjs-basic-min.js.LICENSE +23 -0
- package/dist/abcjs-basic.js +28231 -0
- package/dist/abcjs-basic.js.map +1 -0
- package/dist/abcjs-plugin-min.js +3 -0
- package/dist/abcjs-plugin-min.js.LICENSE +23 -0
- package/dist/report-basic.html +37 -0
- package/dist/report-before-glyph-compress.html +37 -0
- package/dist/report-brown-ts-target-es5.html +37 -0
- package/dist/report-dev-orig-no-babel.html +37 -0
- package/dist/report-synth.html +37 -0
- package/docker-build.sh +1 -0
- package/glyphs.json +1 -0
- package/index.js +27 -2
- package/{static-wrappers/license.js → license.js} +1 -1
- package/package.json +26 -29
- package/{src/plugin/abc_plugin.js → plugin.js} +31 -19
- package/src/api/abc_animation.js +1 -17
- package/src/api/abc_tablatures.js +144 -0
- package/src/api/abc_timing_callbacks.js +216 -117
- package/src/api/abc_tunebook.js +18 -67
- package/src/api/abc_tunebook_svg.js +38 -46
- package/src/data/abc_tune.js +232 -972
- package/src/data/deline-tune.js +199 -0
- package/src/edit/abc_editarea.js +112 -0
- package/src/edit/abc_editor.js +95 -221
- package/src/midi/abc_midi_create.js +48 -50
- package/src/parse/abc_common.js +0 -14
- package/src/parse/abc_parse.js +167 -1321
- package/src/parse/abc_parse_book.js +62 -0
- package/src/parse/abc_parse_directive.js +164 -41
- package/src/parse/abc_parse_header.js +116 -145
- package/src/parse/abc_parse_key_voice.js +26 -20
- package/src/parse/abc_parse_music.js +1337 -0
- package/src/parse/abc_tokenizer.js +21 -15
- package/src/parse/abc_transpose.js +3 -15
- package/src/parse/tune-builder.js +896 -0
- package/src/parse/wrap_lines.js +205 -453
- package/src/synth/abc_midi_flattener.js +1292 -0
- package/src/{midi → synth}/abc_midi_renderer.js +44 -17
- package/src/synth/abc_midi_sequencer.js +648 -0
- package/src/synth/active-audio-context.js +3 -14
- package/src/synth/cents-to-factor.js +10 -0
- package/src/synth/create-note-map.js +21 -32
- package/src/synth/create-synth-control.js +20 -103
- package/src/synth/create-synth.js +185 -77
- package/src/synth/download-buffer.js +7 -21
- package/src/synth/get-midi-file.js +13 -20
- package/src/synth/images/{loading.svg → loading.svg.js} +4 -0
- package/src/synth/images/loop.svg.js +65 -0
- package/src/synth/images/pause.svg.js +10 -0
- package/src/synth/images/play.svg.js +9 -0
- package/src/synth/images/{reset.svg → reset.svg.js} +5 -1
- package/src/synth/instrument-index-to-name.js +1 -16
- package/src/synth/load-note.js +37 -76
- package/src/synth/pitch-to-note-name.js +0 -15
- package/src/synth/pitches-to-perc.js +64 -0
- package/src/synth/place-note.js +78 -68
- package/src/synth/play-event.js +17 -18
- package/src/synth/register-audio-context.js +11 -23
- package/src/synth/sounds-cache.js +0 -15
- package/src/synth/supports-audio.js +9 -23
- package/src/synth/synth-controller.js +80 -49
- package/src/synth/synth-sequence.js +20 -34
- package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
- package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
- package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
- package/src/tablatures/instruments/string-patterns.js +277 -0
- package/src/tablatures/instruments/string-tablature.js +56 -0
- package/src/tablatures/instruments/tab-note.js +282 -0
- package/src/tablatures/instruments/tab-notes.js +41 -0
- package/src/tablatures/instruments/violin/tab-violin.js +47 -0
- package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
- package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
- package/src/tablatures/tab-absolute-elements.js +310 -0
- package/src/tablatures/tab-common.js +29 -0
- package/src/tablatures/tab-renderer.js +243 -0
- package/src/tablatures/transposer.js +110 -0
- package/src/test/abc_midi_lint.js +5 -22
- package/src/test/abc_midi_sequencer_lint.js +11 -14
- package/src/test/abc_parser_lint.js +136 -32
- package/src/test/abc_vertical_lint.js +94 -32
- package/src/test/rendering-lint.js +38 -5
- package/src/write/abc_absolute_element.js +112 -120
- package/src/write/abc_abstract_engraver.js +102 -253
- package/src/write/abc_beam_element.js +30 -290
- package/src/write/abc_brace_element.js +12 -121
- package/src/write/abc_create_clef.js +21 -32
- package/src/write/abc_create_key_signature.js +8 -26
- package/src/write/abc_create_note_head.js +107 -0
- package/src/write/abc_create_time_signature.js +2 -21
- package/src/write/abc_crescendo_element.js +3 -50
- package/src/write/abc_decoration.js +7 -30
- package/src/write/abc_dynamic_decoration.js +3 -37
- package/src/write/abc_ending_element.js +1 -57
- package/src/write/abc_engraver_controller.js +111 -234
- package/src/write/abc_glyphs.js +8 -18
- package/src/write/abc_relative_element.js +57 -97
- package/src/write/abc_renderer.js +10 -832
- package/src/write/abc_spacing.js +0 -15
- package/src/write/abc_staff_group_element.js +14 -349
- package/src/write/abc_tempo_element.js +9 -117
- package/src/write/abc_tie_element.js +5 -68
- package/src/write/abc_triplet_element.js +6 -124
- package/src/write/abc_voice_element.js +7 -222
- package/src/write/add-chord.js +103 -0
- package/src/write/add-text-if.js +33 -0
- package/src/write/bottom-text.js +79 -0
- package/src/write/calcHeight.js +17 -0
- package/src/write/classes.js +100 -0
- package/src/write/draw/absolute.js +68 -0
- package/src/write/draw/beam.js +56 -0
- package/src/write/draw/brace.js +106 -0
- package/src/write/draw/crescendo.js +38 -0
- package/src/write/draw/debug-box.js +8 -0
- package/src/write/draw/draw.js +56 -0
- package/src/write/draw/dynamics.js +20 -0
- package/src/write/draw/ending.js +46 -0
- package/src/write/draw/group-elements.js +66 -0
- package/src/write/draw/horizontal-line.js +25 -0
- package/src/write/draw/non-music.js +50 -0
- package/src/write/draw/print-line.js +24 -0
- package/src/write/draw/print-path.js +7 -0
- package/src/write/draw/print-stem.js +30 -0
- package/src/write/draw/print-symbol.js +59 -0
- package/src/write/draw/print-vertical-line.js +18 -0
- package/src/write/draw/relative.js +77 -0
- package/src/write/draw/round-number.js +5 -0
- package/src/write/draw/selectables.js +59 -0
- package/src/write/draw/separator.js +16 -0
- package/src/write/draw/set-paper-size.js +45 -0
- package/src/write/{sprintf.js → draw/sprintf.js} +0 -0
- package/src/write/draw/staff-group.js +226 -0
- package/src/write/draw/staff-line.js +9 -0
- package/src/write/draw/staff.js +33 -0
- package/src/write/draw/tab-line.js +40 -0
- package/src/write/draw/tempo.js +45 -0
- package/src/write/draw/text.js +71 -0
- package/src/write/draw/tie.js +97 -0
- package/src/write/draw/triplet.js +46 -0
- package/src/write/draw/voice.js +102 -0
- package/src/write/format-jazz-chord.js +15 -0
- package/src/write/free-text.js +41 -0
- package/src/write/get-font-and-attr.js +37 -0
- package/src/write/get-text-size.js +56 -0
- package/src/write/highlight.js +11 -0
- package/src/write/layout/VoiceElements.js +121 -0
- package/src/write/layout/beam.js +213 -0
- package/src/write/layout/get-left-edge-of-staff.js +56 -0
- package/src/write/layout/getBarYAt.js +6 -0
- package/src/write/layout/layout.js +94 -0
- package/src/write/layout/setUpperAndLowerElements.js +232 -0
- package/src/write/layout/staffGroup.js +146 -0
- package/src/write/layout/triplet.js +75 -0
- package/src/write/layout/voice.js +137 -0
- package/src/write/selection.js +188 -70
- package/src/write/separator.js +10 -0
- package/src/write/set-class.js +21 -0
- package/src/write/subtitle.js +12 -0
- package/src/write/svg.js +95 -43
- package/src/write/top-text.js +54 -0
- package/src/write/unhighlight.js +11 -0
- package/temp.txt +17 -0
- package/test.js +27 -64
- package/types/index.d.ts +1095 -0
- package/version.js +1 -1
- package/.babelrc +0 -5
- package/.eslintrc +0 -3
- package/.gitmodules +0 -3
- package/Dockerfile +0 -8
- package/abcjs-midi.css +0 -166
- package/build-utils/loadPresets.js +0 -14
- package/build-utils/presets/webpack.analyze.js +0 -6
- package/build-utils/presets/webpack.optimize.js +0 -30
- package/build-utils/webpack.development.js +0 -14
- package/build-utils/webpack.production.js +0 -35
- package/deploy-docs.sh +0 -25
- package/docker-compose.yml +0 -13
- package/docs/README.md +0 -33
- package/fix-versions.sh +0 -23
- package/midi.js +0 -62
- package/src/api/abc_tunebook_midi.js +0 -116
- package/src/midi/abc_midi_controls.js +0 -701
- package/src/midi/abc_midi_flattener.js +0 -1119
- package/src/midi/abc_midi_js_preparer.js +0 -243
- package/src/midi/abc_midi_sequencer.js +0 -401
- package/src/midi/abc_midi_ui_generator.js +0 -86
- package/src/plugin/abc_plugin_midi.js +0 -220
- package/src/synth/images/loop.svg +0 -61
- package/src/synth/images/pause.svg +0 -6
- package/src/synth/images/play.svg +0 -5
- package/src/transform/abc2abc_write.js +0 -395
- package/static-wrappers/basic.js +0 -2
- package/static-wrappers/midi.js +0 -2
- package/static-wrappers/plugin-midi.js +0 -6
- package/static-wrappers/plugin.js +0 -6
- package/webpack.config.js +0 -29
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
var RelativeElement = require('../abc_relative_element');
|
|
2
|
+
var spacing = require('../abc_spacing');
|
|
3
|
+
var getBarYAt = require('./getBarYAt');
|
|
4
|
+
|
|
5
|
+
var layoutBeam = function(beam) {
|
|
6
|
+
if (beam.elems.length === 0 || beam.allrests) return;
|
|
7
|
+
|
|
8
|
+
var dy = calcDy(beam.stemsUp, beam.isgrace); // This is the width of the beam line.
|
|
9
|
+
|
|
10
|
+
// create the main beam
|
|
11
|
+
var firstElement = beam.elems[0];
|
|
12
|
+
var lastElement = beam.elems[beam.elems.length - 1];
|
|
13
|
+
var minStemHeight = 0; // The following is to leave space for "!///!" marks.
|
|
14
|
+
var referencePitch = beam.stemsUp ? firstElement.abcelem.maxpitch : firstElement.abcelem.minpitch;
|
|
15
|
+
minStemHeight = minStem(firstElement, beam.stemsUp, referencePitch, minStemHeight);
|
|
16
|
+
minStemHeight = minStem(lastElement, beam.stemsUp, referencePitch, minStemHeight);
|
|
17
|
+
minStemHeight = Math.max(beam.stemHeight, minStemHeight + 3); // TODO-PER: The 3 is the width of a 16th beam. The actual height of the beam should be used instead.
|
|
18
|
+
var yPos = calcYPos(beam.average, beam.elems.length, minStemHeight, beam.stemsUp, firstElement.abcelem.averagepitch, lastElement.abcelem.averagepitch, beam.isflat, beam.min, beam.max, beam.isgrace);
|
|
19
|
+
var xPos = calcXPos(beam.stemsUp, firstElement, lastElement);
|
|
20
|
+
beam.addBeam({ startX: xPos[0], endX: xPos[1], startY: yPos[0], endY: yPos[1], dy: dy });
|
|
21
|
+
|
|
22
|
+
// create the rest of the beams (in the case of 1/16th notes, etc.
|
|
23
|
+
var beams = createAdditionalBeams(beam.elems, beam.stemsUp, beam.beams[0], beam.isgrace, dy);
|
|
24
|
+
for (var i = 0; i < beams.length; i++)
|
|
25
|
+
beam.addBeam(beams[i]);
|
|
26
|
+
|
|
27
|
+
// Now that the main beam is defined, we know how tall the stems should be, so create them and attach them to the original notes.
|
|
28
|
+
createStems(beam.elems, beam.stemsUp, beam.beams[0], dy, beam.mainNote);
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
var getDurlog = function(duration) {
|
|
32
|
+
// TODO-PER: This is a hack to prevent a Chrome lockup. Duration should have been defined already,
|
|
33
|
+
// but there's definitely a case where it isn't. [Probably something to do with triplets.]
|
|
34
|
+
if (duration === undefined) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
// console.log("getDurlog: " + duration);
|
|
38
|
+
return Math.floor(Math.log(duration)/Math.log(2));
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
//
|
|
42
|
+
// private functions
|
|
43
|
+
//
|
|
44
|
+
function minStem(element, stemsUp, referencePitch, minStemHeight) {
|
|
45
|
+
if (!element.children)
|
|
46
|
+
return minStemHeight;
|
|
47
|
+
for (var i = 0; i < element.children.length; i++) {
|
|
48
|
+
var elem = element.children[i];
|
|
49
|
+
if (stemsUp && elem.top !== undefined && elem.c === "flags.ugrace")
|
|
50
|
+
minStemHeight = Math.max(minStemHeight, elem.top - referencePitch);
|
|
51
|
+
else if (!stemsUp && elem.bottom !== undefined && elem.c === "flags.ugrace")
|
|
52
|
+
minStemHeight = Math.max(minStemHeight, referencePitch - elem.bottom + 7); // The extra 7 is because we are measuring the slash from the top.
|
|
53
|
+
}
|
|
54
|
+
return minStemHeight;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function calcSlant(leftAveragePitch, rightAveragePitch, numStems, isFlat) {
|
|
58
|
+
if (isFlat)
|
|
59
|
+
return 0;
|
|
60
|
+
var slant = leftAveragePitch - rightAveragePitch;
|
|
61
|
+
var maxSlant = numStems / 2;
|
|
62
|
+
|
|
63
|
+
if (slant > maxSlant) slant = maxSlant;
|
|
64
|
+
if (slant < -maxSlant) slant = -maxSlant;
|
|
65
|
+
return slant;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function calcDy(asc, isGrace) {
|
|
69
|
+
var dy = (asc) ? spacing.STEP : -spacing.STEP;
|
|
70
|
+
if (isGrace) dy = dy * 0.4;
|
|
71
|
+
return dy;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function calcXPos(asc, firstElement, lastElement) {
|
|
75
|
+
var starthead = firstElement.heads[asc ? 0 : firstElement.heads.length - 1];
|
|
76
|
+
var endhead = lastElement.heads[asc ? 0 : lastElement.heads.length - 1];
|
|
77
|
+
var startX = starthead.x;
|
|
78
|
+
if (asc) startX += starthead.w - 0.6;
|
|
79
|
+
var endX = endhead.x;
|
|
80
|
+
endX += (asc) ? endhead.w : 0.6;
|
|
81
|
+
return [ startX, endX ];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function calcYPos(average, numElements, stemHeight, asc, firstAveragePitch, lastAveragePitch, isFlat, minPitch, maxPitch, isGrace) {
|
|
85
|
+
var barpos = stemHeight - 2; // (isGrace)? 5:7;
|
|
86
|
+
var barminpos = stemHeight - 2;
|
|
87
|
+
var pos = Math.round(asc ? Math.max(average + barpos, maxPitch + barminpos) : Math.min(average - barpos, minPitch - barminpos));
|
|
88
|
+
|
|
89
|
+
var slant = calcSlant(firstAveragePitch, lastAveragePitch, numElements, isFlat);
|
|
90
|
+
var startY = pos + Math.floor(slant / 2);
|
|
91
|
+
var endY = pos + Math.floor(-slant / 2);
|
|
92
|
+
|
|
93
|
+
// If the notes are too high or too low, make the beam go down to the middle
|
|
94
|
+
if (!isGrace) {
|
|
95
|
+
if (asc && pos < 6) {
|
|
96
|
+
startY = 6;
|
|
97
|
+
endY = 6;
|
|
98
|
+
} else if (!asc && pos > 6) {
|
|
99
|
+
startY = 6;
|
|
100
|
+
endY = 6;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return [ startY, endY];
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function createStems(elems, asc, beam, dy, mainNote) {
|
|
108
|
+
for (var i = 0; i < elems.length; i++) {
|
|
109
|
+
var elem = elems[i];
|
|
110
|
+
if (elem.abcelem.rest)
|
|
111
|
+
continue;
|
|
112
|
+
// TODO-PER: This is odd. If it is a regular beam then elems is an array of AbsoluteElements, if it is a grace beam then it is an array of objects , so we directly attach the element to the parent. We tell it if is a grace note because they are passed in as a generic object instead of an AbsoluteElement.
|
|
113
|
+
var isGrace = elem.addExtra ? false : true;
|
|
114
|
+
var parent = isGrace ? mainNote : elem;
|
|
115
|
+
var furthestHead = elem.heads[(asc) ? 0 : elem.heads.length - 1];
|
|
116
|
+
var ovalDelta = 1 / 5;//(isGrace)?1/3:1/5;
|
|
117
|
+
var pitch = furthestHead.pitch + ((asc) ? ovalDelta : -ovalDelta);
|
|
118
|
+
var dx = asc ? furthestHead.w : 0; // down-pointing stems start on the left side of the note, up-pointing stems start on the right side, so we offset by the note width.
|
|
119
|
+
if (!isGrace)
|
|
120
|
+
dx += furthestHead.dx;
|
|
121
|
+
var x = furthestHead.x + dx; // this is now the actual x location in pixels.
|
|
122
|
+
var bary = getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, x);
|
|
123
|
+
var lineWidth = (asc) ? -0.6 : 0.6;
|
|
124
|
+
if (!asc)
|
|
125
|
+
bary -= (dy / 2) / spacing.STEP; // TODO-PER: This is just a fudge factor so the down-pointing stems don't overlap.
|
|
126
|
+
if (isGrace)
|
|
127
|
+
dx += elem.heads[0].dx;
|
|
128
|
+
// TODO-PER-HACK: One type of note head has a different placement of the stem. This should be more generically calculated:
|
|
129
|
+
if (furthestHead.c === 'noteheads.slash.quarter') {
|
|
130
|
+
if (asc)
|
|
131
|
+
pitch += 1;
|
|
132
|
+
else
|
|
133
|
+
pitch -= 1;
|
|
134
|
+
}
|
|
135
|
+
var stem = new RelativeElement(null, dx, 0, pitch, {
|
|
136
|
+
"type": "stem",
|
|
137
|
+
"pitch2": bary,
|
|
138
|
+
linewidth: lineWidth
|
|
139
|
+
});
|
|
140
|
+
stem.setX(parent.x); // This is after the x coordinates were set, so we have to set it directly.
|
|
141
|
+
parent.addRight(stem);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function createAdditionalBeams(elems, asc, beam, isGrace, dy) {
|
|
147
|
+
var beams = [];
|
|
148
|
+
var auxBeams = []; // auxbeam will be {x, y, durlog, single} auxbeam[0] should match with durlog=-4 (16th) (j=-4-durlog)
|
|
149
|
+
for (var i = 0; i < elems.length; i++) {
|
|
150
|
+
var elem = elems[i];
|
|
151
|
+
if (elem.abcelem.rest)
|
|
152
|
+
continue;
|
|
153
|
+
var furthestHead = elem.heads[(asc) ? 0 : elem.heads.length - 1];
|
|
154
|
+
var x = furthestHead.x + ((asc) ? furthestHead.w : 0);
|
|
155
|
+
var bary = getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, x);
|
|
156
|
+
|
|
157
|
+
var sy = (asc) ? -1.5 : 1.5;
|
|
158
|
+
if (isGrace) sy = sy * 2 / 3; // This makes the second beam on grace notes closer to the first one.
|
|
159
|
+
var duration = elem.abcelem.duration; // get the duration via abcelem because of triplets
|
|
160
|
+
if (duration === 0) duration = 0.25; // if this is stemless, then we use quarter note as the duration.
|
|
161
|
+
for (var durlog = getDurlog(duration); durlog < -3; durlog++) {
|
|
162
|
+
var index = -4 - durlog;
|
|
163
|
+
if (auxBeams[index]) {
|
|
164
|
+
auxBeams[index].single = false;
|
|
165
|
+
} else {
|
|
166
|
+
auxBeams[index] = {
|
|
167
|
+
x: x + ((asc) ? -0.6 : 0), y: bary + sy * (index + 1),
|
|
168
|
+
durlog: durlog, single: true
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
if (i > 0 && elem.abcelem.beambr && elem.abcelem.beambr <= (index+1)) {
|
|
172
|
+
if (!auxBeams[index].split)
|
|
173
|
+
auxBeams[index].split = [auxBeams[index].x];
|
|
174
|
+
var xPos = calcXPos(asc, elems[i-1], elem);
|
|
175
|
+
if (auxBeams[index].split[auxBeams[index].split.length-1] >= xPos[0]) {
|
|
176
|
+
// the reduction in beams leaves a note unattached so create a small flag for it.
|
|
177
|
+
xPos[0] += elem.w;
|
|
178
|
+
}
|
|
179
|
+
auxBeams[index].split.push(xPos[0]);
|
|
180
|
+
auxBeams[index].split.push(xPos[1]);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
for (var j = auxBeams.length - 1; j >= 0; j--) {
|
|
185
|
+
if (i === elems.length - 1 || getDurlog(elems[i + 1].abcelem.duration) > (-j - 4)) {
|
|
186
|
+
|
|
187
|
+
var auxBeamEndX = x;
|
|
188
|
+
var auxBeamEndY = bary + sy * (j + 1);
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
if (auxBeams[j].single) {
|
|
192
|
+
auxBeamEndX = (i === 0) ? x + 5 : x - 5;
|
|
193
|
+
auxBeamEndY = getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, auxBeamEndX) + sy * (j + 1);
|
|
194
|
+
}
|
|
195
|
+
var b = { startX: auxBeams[j].x, endX: auxBeamEndX, startY: auxBeams[j].y, endY: auxBeamEndY, dy: dy }
|
|
196
|
+
if (auxBeams[j].split !== undefined) {
|
|
197
|
+
var split = auxBeams[j].split;
|
|
198
|
+
if (b.endX <= split[split.length-1]) {
|
|
199
|
+
// the reduction in beams leaves the last note by itself, so create a little flag for it
|
|
200
|
+
split[split.length-1] -= elem.w;
|
|
201
|
+
}
|
|
202
|
+
split.push(b.endX);
|
|
203
|
+
b.split = auxBeams[j].split;
|
|
204
|
+
}
|
|
205
|
+
beams.push(b);
|
|
206
|
+
auxBeams = auxBeams.slice(0, j);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return beams;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
module.exports = layoutBeam;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
function getLeftEdgeOfStaff(renderer, getTextSize, voices, brace, bracket) {
|
|
2
|
+
var x = renderer.padding.left;
|
|
3
|
+
|
|
4
|
+
// find out how much space will be taken up by voice headers
|
|
5
|
+
var voiceheaderw = 0;
|
|
6
|
+
var i;
|
|
7
|
+
var size;
|
|
8
|
+
for (i=0;i<voices.length;i++) {
|
|
9
|
+
if(voices[i].header) {
|
|
10
|
+
size = getTextSize.calc(voices[i].header, 'voicefont', '');
|
|
11
|
+
voiceheaderw = Math.max(voiceheaderw,size.width);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
voiceheaderw = addBraceSize(voiceheaderw, brace, getTextSize);
|
|
15
|
+
voiceheaderw = addBraceSize(voiceheaderw, bracket, getTextSize);
|
|
16
|
+
|
|
17
|
+
if (voiceheaderw) {
|
|
18
|
+
// Give enough spacing to the right - we use the width of an A for the amount of spacing.
|
|
19
|
+
var sizeW = getTextSize.calc("A", 'voicefont', '');
|
|
20
|
+
voiceheaderw += sizeW.width;
|
|
21
|
+
}
|
|
22
|
+
x += voiceheaderw;
|
|
23
|
+
|
|
24
|
+
var ofs = 0;
|
|
25
|
+
ofs = setBraceLocation(brace, x, ofs);
|
|
26
|
+
ofs = setBraceLocation(bracket, x, ofs);
|
|
27
|
+
return x + ofs;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function addBraceSize(voiceheaderw, brace, getTextSize) {
|
|
31
|
+
if (brace) {
|
|
32
|
+
for (var i = 0; i < brace.length; i++) {
|
|
33
|
+
if (brace[i].header) {
|
|
34
|
+
var size = getTextSize.calc(brace[i].header, 'voicefont', '');
|
|
35
|
+
voiceheaderw = Math.max(voiceheaderw,size.width);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return voiceheaderw;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function setBraceLocation(brace, x, ofs) {
|
|
43
|
+
if (brace) {
|
|
44
|
+
for (var i = 0; i < brace.length; i++) {
|
|
45
|
+
setLocation(x, brace[i]);
|
|
46
|
+
ofs = Math.max(ofs, brace[i].getWidth());
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return ofs;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function setLocation(x, element) {
|
|
53
|
+
element.x = x;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = getLeftEdgeOfStaff;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
var layoutVoice = require('./voice');
|
|
2
|
+
var setUpperAndLowerElements = require('./setUpperAndLowerElements');
|
|
3
|
+
var layoutStaffGroup = require('./staffGroup');
|
|
4
|
+
var getLeftEdgeOfStaff = require('./get-left-edge-of-staff');
|
|
5
|
+
|
|
6
|
+
var layout = function (renderer, abctune, width, space) {
|
|
7
|
+
var i;
|
|
8
|
+
var abcLine;
|
|
9
|
+
// Adjust the x-coordinates to their absolute positions
|
|
10
|
+
var maxWidth = width;
|
|
11
|
+
for(i=0; i<abctune.lines.length; i++) {
|
|
12
|
+
abcLine = abctune.lines[i];
|
|
13
|
+
if (abcLine.staff) {
|
|
14
|
+
setXSpacing(renderer, width, space, abcLine.staffGroup, abctune.formatting, i === abctune.lines.length - 1, false);
|
|
15
|
+
if (abcLine.staffGroup.w > maxWidth) maxWidth = abcLine.staffGroup.w;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Layout the beams and add the stems to the beamed notes.
|
|
20
|
+
for(i=0; i<abctune.lines.length; i++) {
|
|
21
|
+
abcLine = abctune.lines[i];
|
|
22
|
+
if (abcLine.staffGroup && abcLine.staffGroup.voices) {
|
|
23
|
+
for (var j = 0; j < abcLine.staffGroup.voices.length; j++)
|
|
24
|
+
layoutVoice(abcLine.staffGroup.voices[j]);
|
|
25
|
+
setUpperAndLowerElements(renderer, abcLine.staffGroup);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Set the staff spacing
|
|
30
|
+
// TODO-PER: we should have been able to do this by the time we called setUpperAndLowerElements, but for some reason the "bottom" element seems to be set as a side effect of setting the X spacing.
|
|
31
|
+
for(i=0; i<abctune.lines.length; i++) {
|
|
32
|
+
abcLine = abctune.lines[i];
|
|
33
|
+
if (abcLine.staffGroup) {
|
|
34
|
+
abcLine.staffGroup.setHeight();
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return maxWidth;
|
|
38
|
+
}
|
|
39
|
+
// Do the x-axis positioning for a single line (a group of related staffs)
|
|
40
|
+
var setXSpacing = function (renderer, width, space, staffGroup, formatting, isLastLine, debug) {
|
|
41
|
+
var leftEdge = getLeftEdgeOfStaff(renderer, staffGroup.getTextSize, staffGroup.voices, staffGroup.brace, staffGroup.bracket);
|
|
42
|
+
var newspace = space;
|
|
43
|
+
for (var it = 0; it < 8; it++) { // TODO-PER: shouldn't need multiple passes, but each pass gets it closer to the right spacing. (Only affects long lines: normal lines break out of this loop quickly.)
|
|
44
|
+
var ret = layoutStaffGroup(newspace, renderer, debug, staffGroup, leftEdge);
|
|
45
|
+
newspace = calcHorizontalSpacing(isLastLine, formatting.stretchlast, width+renderer.padding.left, staffGroup.w, newspace, ret.spacingUnits, ret.minSpace, renderer.padding.left+renderer.padding.right);
|
|
46
|
+
if (debug)
|
|
47
|
+
console.log("setXSpace", it, staffGroup.w, newspace, staffGroup.minspace);
|
|
48
|
+
if (newspace === null) break;
|
|
49
|
+
}
|
|
50
|
+
centerWholeRests(staffGroup.voices);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
function calcHorizontalSpacing(isLastLine, stretchLast, targetWidth, lineWidth, spacing, spacingUnits, minSpace, padding) {
|
|
54
|
+
if (isLastLine) {
|
|
55
|
+
if (stretchLast === undefined) {
|
|
56
|
+
if (lineWidth / targetWidth < 0.66) return null; // keep this for backward compatibility. The break isn't quite the same for some reason.
|
|
57
|
+
} else {
|
|
58
|
+
// "Stretch the last music line of a tune when it lacks less than the float fraction of the page width."
|
|
59
|
+
var lack = 1 - (lineWidth+padding) / targetWidth;
|
|
60
|
+
var stretch = lack < stretchLast;
|
|
61
|
+
if (!stretch) return null; // don't stretch last line too much
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (Math.abs(targetWidth-lineWidth) < 2) return null; // if we are already near the target width, we're done.
|
|
65
|
+
var relSpace = spacingUnits * spacing;
|
|
66
|
+
var constSpace = lineWidth - relSpace;
|
|
67
|
+
if (spacingUnits > 0) {
|
|
68
|
+
spacing = (targetWidth - constSpace) / spacingUnits;
|
|
69
|
+
if (spacing * minSpace > 50) {
|
|
70
|
+
spacing = 50 / minSpace;
|
|
71
|
+
}
|
|
72
|
+
return spacing;
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function centerWholeRests(voices) {
|
|
78
|
+
// whole rests are a special case: if they are by themselves in a measure, then they should be centered.
|
|
79
|
+
// (If they are not by themselves, that is probably a user error, but we'll just center it between the two items to either side of it.)
|
|
80
|
+
for (var i = 0; i < voices.length; i++) {
|
|
81
|
+
var voice = voices[i];
|
|
82
|
+
// Look through all of the elements except for the first and last. If the whole note appears there then there isn't anything to center it between anyway.
|
|
83
|
+
for (var j = 1; j < voice.children.length-1; j++) {
|
|
84
|
+
var absElem = voice.children[j];
|
|
85
|
+
if (absElem.abcelem.rest && (absElem.abcelem.rest.type === 'whole' || absElem.abcelem.rest.type === 'multimeasure')) {
|
|
86
|
+
var before = voice.children[j-1];
|
|
87
|
+
var after = voice.children[j+1];
|
|
88
|
+
absElem.center(before, after);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = layout;
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
var spacing = require('../abc_spacing');
|
|
2
|
+
|
|
3
|
+
var setUpperAndLowerElements = function(renderer, staffGroup) {
|
|
4
|
+
// Each staff already has the top and bottom set, now we see if there are elements that are always on top and bottom, and resolve their pitch.
|
|
5
|
+
// Also, get the overall height of all the staves in this group.
|
|
6
|
+
var lastStaffBottom;
|
|
7
|
+
for (var i = 0; i < staffGroup.staffs.length; i++) {
|
|
8
|
+
var staff = staffGroup.staffs[i];
|
|
9
|
+
// the vertical order of elements that are above is: tempo, part, volume/dynamic, ending/chord, lyric
|
|
10
|
+
// the vertical order of elements that are below is: lyric, chord, volume/dynamic
|
|
11
|
+
var positionY = {
|
|
12
|
+
tempoHeightAbove: 0,
|
|
13
|
+
partHeightAbove: 0,
|
|
14
|
+
volumeHeightAbove: 0,
|
|
15
|
+
dynamicHeightAbove: 0,
|
|
16
|
+
endingHeightAbove: 0,
|
|
17
|
+
chordHeightAbove: 0,
|
|
18
|
+
lyricHeightAbove: 0,
|
|
19
|
+
|
|
20
|
+
lyricHeightBelow: 0,
|
|
21
|
+
chordHeightBelow: 0,
|
|
22
|
+
volumeHeightBelow: 0,
|
|
23
|
+
dynamicHeightBelow: 0
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
if (renderer.showDebug && renderer.showDebug.indexOf("box") >= 0) {
|
|
27
|
+
staff.originalTop = staff.top; // This is just being stored for debugging purposes.
|
|
28
|
+
staff.originalBottom = staff.bottom; // This is just being stored for debugging purposes.
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
incTop(staff, positionY, 'lyricHeightAbove');
|
|
32
|
+
incTop(staff, positionY, 'chordHeightAbove', staff.specialY.chordLines.above);
|
|
33
|
+
if (staff.specialY.endingHeightAbove) {
|
|
34
|
+
if (staff.specialY.chordHeightAbove)
|
|
35
|
+
staff.top += 2;
|
|
36
|
+
else
|
|
37
|
+
staff.top += staff.specialY.endingHeightAbove + margin;
|
|
38
|
+
positionY.endingHeightAbove = staff.top;
|
|
39
|
+
}
|
|
40
|
+
if (staff.specialY.dynamicHeightAbove && staff.specialY.volumeHeightAbove) {
|
|
41
|
+
staff.top += Math.max(staff.specialY.dynamicHeightAbove, staff.specialY.volumeHeightAbove) + margin;
|
|
42
|
+
positionY.dynamicHeightAbove = staff.top;
|
|
43
|
+
positionY.volumeHeightAbove = staff.top;
|
|
44
|
+
} else {
|
|
45
|
+
incTop(staff, positionY, 'dynamicHeightAbove');
|
|
46
|
+
incTop(staff, positionY, 'volumeHeightAbove');
|
|
47
|
+
}
|
|
48
|
+
incTop(staff, positionY, 'partHeightAbove');
|
|
49
|
+
incTop(staff, positionY, 'tempoHeightAbove');
|
|
50
|
+
|
|
51
|
+
if (staff.specialY.lyricHeightBelow) {
|
|
52
|
+
staff.specialY.lyricHeightBelow += renderer.spacing.vocal/spacing.STEP;
|
|
53
|
+
positionY.lyricHeightBelow = staff.bottom;
|
|
54
|
+
staff.bottom -= (staff.specialY.lyricHeightBelow + margin);
|
|
55
|
+
}
|
|
56
|
+
if (staff.specialY.chordHeightBelow) {
|
|
57
|
+
positionY.chordHeightBelow = staff.bottom;
|
|
58
|
+
var hgt = staff.specialY.chordHeightBelow;
|
|
59
|
+
if (staff.specialY.chordLines.below)
|
|
60
|
+
hgt *= staff.specialY.chordLines.below;
|
|
61
|
+
staff.bottom -= (hgt + margin);
|
|
62
|
+
}
|
|
63
|
+
if (staff.specialY.volumeHeightBelow && staff.specialY.dynamicHeightBelow) {
|
|
64
|
+
positionY.volumeHeightBelow = staff.bottom;
|
|
65
|
+
positionY.dynamicHeightBelow = staff.bottom;
|
|
66
|
+
staff.bottom -= (Math.max(staff.specialY.volumeHeightBelow, staff.specialY.dynamicHeightBelow) + margin);
|
|
67
|
+
} else if (staff.specialY.volumeHeightBelow) {
|
|
68
|
+
positionY.volumeHeightBelow = staff.bottom; staff.bottom -= (staff.specialY.volumeHeightBelow + margin);
|
|
69
|
+
} else if (staff.specialY.dynamicHeightBelow) {
|
|
70
|
+
positionY.dynamicHeightBelow = staff.bottom; staff.bottom -= (staff.specialY.dynamicHeightBelow + margin);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (renderer.showDebug && renderer.showDebug.indexOf("box") >= 0)
|
|
74
|
+
staff.positionY = positionY; // This is just being stored for debugging purposes.
|
|
75
|
+
|
|
76
|
+
for (var j = 0; j < staff.voices.length; j++) {
|
|
77
|
+
var voice = staffGroup.voices[staff.voices[j]];
|
|
78
|
+
setUpperAndLowerVoiceElements(positionY, voice, renderer.spacing);
|
|
79
|
+
}
|
|
80
|
+
// We might need a little space in between staves if the staves haven't been pushed far enough apart by notes or extra vertical stuff.
|
|
81
|
+
// Only try to put in extra space if this isn't the top staff.
|
|
82
|
+
if (lastStaffBottom !== undefined) {
|
|
83
|
+
var thisStaffTop = staff.top - 10;
|
|
84
|
+
var forcedSpacingBetween = lastStaffBottom + thisStaffTop;
|
|
85
|
+
var minSpacingInPitches = renderer.spacing.systemStaffSeparation/spacing.STEP;
|
|
86
|
+
var addedSpace = minSpacingInPitches - forcedSpacingBetween;
|
|
87
|
+
if (addedSpace > 0)
|
|
88
|
+
staff.top += addedSpace;
|
|
89
|
+
}
|
|
90
|
+
lastStaffBottom = 2 - staff.bottom; // the staff starts at position 2 and the bottom variable is negative. Therefore to find out how large the bottom is, we reverse the sign of the bottom, and add the 2 in.
|
|
91
|
+
|
|
92
|
+
// Now we need a little margin on the top, so we'll just throw that in.
|
|
93
|
+
//staff.top += 4;
|
|
94
|
+
//console.log("Staff Y: ",i,heightInPitches,staff.top,staff.bottom);
|
|
95
|
+
}
|
|
96
|
+
//console.log("Staff Height: ",heightInPitches,this.height);
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
var margin = 1;
|
|
100
|
+
function incTop(staff, positionY, item, count) {
|
|
101
|
+
if (staff.specialY[item]) {
|
|
102
|
+
var height = staff.specialY[item];
|
|
103
|
+
if (count)
|
|
104
|
+
height *= count;
|
|
105
|
+
staff.top += height + margin;
|
|
106
|
+
positionY[item] = staff.top;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function setUpperAndLowerVoiceElements(positionY, voice, spacing) {
|
|
111
|
+
var i;
|
|
112
|
+
var abselem;
|
|
113
|
+
for (i = 0; i < voice.children.length; i++) {
|
|
114
|
+
abselem = voice.children[i];
|
|
115
|
+
setUpperAndLowerAbsoluteElements(positionY, abselem, spacing);
|
|
116
|
+
}
|
|
117
|
+
for (i = 0; i < voice.otherchildren.length; i++) {
|
|
118
|
+
abselem = voice.otherchildren[i];
|
|
119
|
+
switch (abselem.type) {
|
|
120
|
+
case 'CrescendoElem':
|
|
121
|
+
setUpperAndLowerCrescendoElements(positionY, abselem);
|
|
122
|
+
break;
|
|
123
|
+
case 'DynamicDecoration':
|
|
124
|
+
setUpperAndLowerDynamicElements(positionY, abselem);
|
|
125
|
+
break;
|
|
126
|
+
case 'EndingElem':
|
|
127
|
+
setUpperAndLowerEndingElements(positionY, abselem);
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// For each of the relative elements that can't be placed in advance (because their vertical placement depends on everything
|
|
134
|
+
// else on the line), this iterates through them and sets their pitch. By the time this is called, specialYResolved contains a
|
|
135
|
+
// hash with the vertical placement (in pitch units) for each type.
|
|
136
|
+
// TODO-PER: I think this needs to be separated by "above" and "below". How do we know that for dynamics at the point where they are being defined, though? We need a pass through all the relative elements to set "above" and "below".
|
|
137
|
+
function setUpperAndLowerAbsoluteElements(specialYResolved, element, spacing) {
|
|
138
|
+
// specialYResolved contains the actual pitch for each of the classes of elements.
|
|
139
|
+
for (var i = 0; i < element.children.length; i++) {
|
|
140
|
+
var child = element.children[i];
|
|
141
|
+
for (var key in element.specialY) { // for each class of element that needs to be placed vertically
|
|
142
|
+
if (element.specialY.hasOwnProperty(key)) {
|
|
143
|
+
if (child[key]) { // If this relative element has defined a height for this class of element
|
|
144
|
+
child.pitch = specialYResolved[key];
|
|
145
|
+
if (child.top === undefined) { // TODO-PER: HACK! Not sure this is the right place to do this.
|
|
146
|
+
if (child.type === 'TempoElement') {
|
|
147
|
+
setUpperAndLowerTempoElement(specialYResolved, child);
|
|
148
|
+
} else {
|
|
149
|
+
setUpperAndLowerRelativeElements(specialYResolved, child, spacing);
|
|
150
|
+
}
|
|
151
|
+
element.pushTop(child.top);
|
|
152
|
+
element.pushBottom(child.bottom);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function setUpperAndLowerCrescendoElements(positionY, element) {
|
|
161
|
+
if (element.dynamicHeightAbove)
|
|
162
|
+
element.pitch = positionY.dynamicHeightAbove;
|
|
163
|
+
else
|
|
164
|
+
element.pitch = positionY.dynamicHeightBelow;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function setUpperAndLowerDynamicElements(positionY, element) {
|
|
168
|
+
if (element.volumeHeightAbove)
|
|
169
|
+
element.pitch = positionY.volumeHeightAbove;
|
|
170
|
+
else
|
|
171
|
+
element.pitch = positionY.volumeHeightBelow;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function setUpperAndLowerEndingElements(positionY, element) {
|
|
175
|
+
element.pitch = positionY.endingHeightAbove - 2;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function setUpperAndLowerTempoElement(positionY, element) {
|
|
179
|
+
element.pitch = positionY.tempoHeightAbove;
|
|
180
|
+
element.top = positionY.tempoHeightAbove;
|
|
181
|
+
element.bottom = positionY.tempoHeightAbove;
|
|
182
|
+
if (element.note) {
|
|
183
|
+
var tempoPitch = element.pitch - element.totalHeightInPitches + 1; // The pitch we receive is the top of the allotted area: change that to practically the bottom.
|
|
184
|
+
element.note.top = tempoPitch;
|
|
185
|
+
element.note.bottom = tempoPitch;
|
|
186
|
+
for (var i = 0; i < element.note.children.length; i++) {
|
|
187
|
+
var child = element.note.children[i];
|
|
188
|
+
child.top += tempoPitch;
|
|
189
|
+
child.bottom += tempoPitch;
|
|
190
|
+
child.pitch += tempoPitch;
|
|
191
|
+
if (child.pitch2 !== undefined)
|
|
192
|
+
child.pitch2 += tempoPitch;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function setUpperAndLowerRelativeElements(positionY, element, renderSpacing) {
|
|
198
|
+
switch(element.type) {
|
|
199
|
+
case "part":
|
|
200
|
+
element.top = positionY.partHeightAbove + element.height;
|
|
201
|
+
element.bottom = positionY.partHeightAbove;
|
|
202
|
+
break;
|
|
203
|
+
case "text":
|
|
204
|
+
case "chord":
|
|
205
|
+
if (element.chordHeightAbove) {
|
|
206
|
+
element.top = positionY.chordHeightAbove;
|
|
207
|
+
element.bottom = positionY.chordHeightAbove;
|
|
208
|
+
} else {
|
|
209
|
+
element.top = positionY.chordHeightBelow;
|
|
210
|
+
element.bottom = positionY.chordHeightBelow;
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
case "lyric":
|
|
214
|
+
if (element.lyricHeightAbove) {
|
|
215
|
+
element.top = positionY.lyricHeightAbove;
|
|
216
|
+
element.bottom = positionY.lyricHeightAbove;
|
|
217
|
+
} else {
|
|
218
|
+
element.top = positionY.lyricHeightBelow + renderSpacing.vocal/spacing.STEP;
|
|
219
|
+
element.bottom = positionY.lyricHeightBelow + renderSpacing.vocal/spacing.STEP;
|
|
220
|
+
element.pitch -= renderSpacing.vocal/spacing.STEP;
|
|
221
|
+
}
|
|
222
|
+
break;
|
|
223
|
+
case "debug":
|
|
224
|
+
element.top = positionY.chordHeightAbove;
|
|
225
|
+
element.bottom = positionY.chordHeightAbove;
|
|
226
|
+
break;
|
|
227
|
+
}
|
|
228
|
+
if (element.pitch === undefined || element.top === undefined)
|
|
229
|
+
console.error("RelativeElement position not set.", element.type, element.pitch, element.top, positionY);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
module.exports = setUpperAndLowerElements;
|