abcjs 6.0.0-beta.7 → 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 +92 -3
- package/RELEASE.md +957 -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 +234 -116
- 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 +9 -19
- 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/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/docs/README.md +0 -33
- package/fix-versions.sh +0 -23
- package/mei.js +0 -43
- 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,71 @@
|
|
|
1
|
+
var roundNumber = require("./round-number");
|
|
2
|
+
|
|
3
|
+
function renderText(renderer, params, alreadyInGroup) {
|
|
4
|
+
var y = params.y;
|
|
5
|
+
if (params.lane) {
|
|
6
|
+
var laneMargin = params.dim.font.size*0.25;
|
|
7
|
+
y += (params.dim.font.size + laneMargin) * params.lane;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
var hash;
|
|
11
|
+
if (params.dim) {
|
|
12
|
+
hash = params.dim;
|
|
13
|
+
hash.attr.class = params.klass;
|
|
14
|
+
} else
|
|
15
|
+
hash = renderer.controller.getFontAndAttr.calc(params.type, params.klass);
|
|
16
|
+
if (params.anchor)
|
|
17
|
+
hash.attr["text-anchor"] = params.anchor;
|
|
18
|
+
hash.attr.x = params.x;
|
|
19
|
+
hash.attr.y = y;
|
|
20
|
+
if (!params.centerVertically)
|
|
21
|
+
hash.attr.y += hash.font.size;
|
|
22
|
+
if (params.type === 'debugfont') {
|
|
23
|
+
console.log("Debug msg: " + params.text);
|
|
24
|
+
hash.attr.stroke = "#ff0000";
|
|
25
|
+
}
|
|
26
|
+
if (params.cursor) {
|
|
27
|
+
hash.attr.cursor = params.cursor;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
var text = params.text.replace(/\n\n/g, "\n \n");
|
|
31
|
+
text = text.replace(/^\n/, "\xA0\n");
|
|
32
|
+
|
|
33
|
+
if (hash.font.box) {
|
|
34
|
+
if (!alreadyInGroup)
|
|
35
|
+
renderer.paper.openGroup({klass: hash.attr['class'], fill: renderer.foregroundColor, "data-name": params.name});
|
|
36
|
+
if (hash.attr["text-anchor"] === "end") {
|
|
37
|
+
hash.attr.x -= hash.font.padding;
|
|
38
|
+
} else if (hash.attr["text-anchor"] === "start") {
|
|
39
|
+
hash.attr.x += hash.font.padding;
|
|
40
|
+
}
|
|
41
|
+
hash.attr.y += hash.font.padding;
|
|
42
|
+
delete hash.attr['class'];
|
|
43
|
+
}
|
|
44
|
+
if (params.noClass)
|
|
45
|
+
delete hash.attr['class'];
|
|
46
|
+
hash.attr.x = roundNumber(hash.attr.x);
|
|
47
|
+
hash.attr.y = roundNumber(hash.attr.y);
|
|
48
|
+
if (params.name)
|
|
49
|
+
hash.attr["data-name"] = params.name;
|
|
50
|
+
var elem = renderer.paper.text(text, hash.attr);
|
|
51
|
+
if (hash.font.box) {
|
|
52
|
+
var size = elem.getBBox();
|
|
53
|
+
|
|
54
|
+
var delta = 0;
|
|
55
|
+
if (hash.attr["text-anchor"] === "middle") {
|
|
56
|
+
delta = size.width / 2 + hash.font.padding;
|
|
57
|
+
} else if (hash.attr["text-anchor"] === "end") {
|
|
58
|
+
delta = size.width + hash.font.padding * 2;
|
|
59
|
+
}
|
|
60
|
+
var deltaY = 0;
|
|
61
|
+
if (params.centerVertically) {
|
|
62
|
+
deltaY = size.height - hash.font.padding;
|
|
63
|
+
}
|
|
64
|
+
renderer.paper.rect({ "data-name": "box", x: Math.round(params.x - delta), y: Math.round(y - deltaY), width: Math.round(size.width + hash.font.padding*2), height: Math.round(size.height + hash.font.padding*2)});
|
|
65
|
+
if (!alreadyInGroup)
|
|
66
|
+
elem = renderer.paper.closeGroup();
|
|
67
|
+
}
|
|
68
|
+
return elem;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
module.exports = renderText;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
var sprintf = require('./sprintf');
|
|
2
|
+
var roundNumber = require("./round-number");
|
|
3
|
+
|
|
4
|
+
function drawTie(renderer, params, linestartx, lineendx, selectables) {
|
|
5
|
+
layout(params, linestartx, lineendx);
|
|
6
|
+
|
|
7
|
+
var klass = '';
|
|
8
|
+
if (params.anchor1) {
|
|
9
|
+
klass += 'abcjs-start-m' + params.anchor1.parent.counters.measure + '-n' + params.anchor1.parent.counters.note;
|
|
10
|
+
} else
|
|
11
|
+
klass += 'abcjs-start-edge';
|
|
12
|
+
if (params.anchor2) {
|
|
13
|
+
klass += ' abcjs-end-m' + params.anchor2.parent.counters.measure + '-n' + params.anchor2.parent.counters.note;
|
|
14
|
+
} else
|
|
15
|
+
klass += ' abcjs-end-edge';
|
|
16
|
+
if (params.hint)
|
|
17
|
+
klass = "abcjs-hint";
|
|
18
|
+
var fudgeY = params.fixedY ? 1.5 : 0; // TODO-PER: This just compensates for drawArc, which contains too much knowledge of ties and slurs.
|
|
19
|
+
var el = drawArc(renderer, params.startX, params.endX, params.startY+fudgeY, params.endY+fudgeY, params.above, klass, params.isTie, params.dotted);
|
|
20
|
+
selectables.wrapSvgEl({ el_type: "slur", startChar: -1, endChar: -1 }, el);
|
|
21
|
+
return [el];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// TODO-PER: I think params part should have been done earlier in the layout pass.
|
|
25
|
+
var layout = function (params, lineStartX, lineEndX) {
|
|
26
|
+
// We now have all of the input variables set, so we can figure out the start and ending x,y coordinates, and finalize the direction of the arc.
|
|
27
|
+
|
|
28
|
+
// Ties and slurs are handled a little differently, so do calculations for them separately.
|
|
29
|
+
if (!params.anchor1 || !params.anchor2)
|
|
30
|
+
params.isTie = true; // if the slur goes off the end of the line, then draw it like a tie
|
|
31
|
+
else if (params.anchor1.pitch === params.anchor2.pitch && params.internalNotes.length === 0)
|
|
32
|
+
params.isTie = true;
|
|
33
|
+
else
|
|
34
|
+
params.isTie = false;
|
|
35
|
+
|
|
36
|
+
if (params.isTie) {
|
|
37
|
+
params.calcTieDirection();
|
|
38
|
+
params.calcX(lineStartX, lineEndX);
|
|
39
|
+
params.calcTieY();
|
|
40
|
+
|
|
41
|
+
} else {
|
|
42
|
+
params.calcSlurDirection();
|
|
43
|
+
params.calcX(lineStartX, lineEndX);
|
|
44
|
+
params.calcSlurY();
|
|
45
|
+
}
|
|
46
|
+
params.avoidCollisionAbove();
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
var drawArc = function(renderer, x1, x2, pitch1, pitch2, above, klass, isTie, dotted) {
|
|
50
|
+
// If it is a tie vs. a slur, draw it shallower.
|
|
51
|
+
var spacing = isTie ? 1.2 : 1.5;
|
|
52
|
+
|
|
53
|
+
x1 = roundNumber(x1 + 6);
|
|
54
|
+
x2 = roundNumber(x2 + 4);
|
|
55
|
+
pitch1 = pitch1 + ((above)?spacing:-spacing);
|
|
56
|
+
pitch2 = pitch2 + ((above)?spacing:-spacing);
|
|
57
|
+
var y1 = roundNumber(renderer.calcY(pitch1));
|
|
58
|
+
var y2 = roundNumber(renderer.calcY(pitch2));
|
|
59
|
+
|
|
60
|
+
//unit direction vector
|
|
61
|
+
var dx = x2-x1;
|
|
62
|
+
var dy = y2-y1;
|
|
63
|
+
var norm= Math.sqrt(dx*dx+dy*dy);
|
|
64
|
+
var ux = dx/norm;
|
|
65
|
+
var uy = dy/norm;
|
|
66
|
+
|
|
67
|
+
var flatten = norm/3.5;
|
|
68
|
+
var maxFlatten = isTie ? 10 : 25; // If it is a tie vs. a slur, draw it shallower.
|
|
69
|
+
var curve = ((above)?-1:1)*Math.min(maxFlatten, Math.max(4, flatten));
|
|
70
|
+
|
|
71
|
+
var controlx1 = roundNumber(x1+flatten*ux-curve*uy);
|
|
72
|
+
var controly1 = roundNumber(y1+flatten*uy+curve*ux);
|
|
73
|
+
var controlx2 = roundNumber(x2-flatten*ux-curve*uy);
|
|
74
|
+
var controly2 = roundNumber(y2-flatten*uy+curve*ux);
|
|
75
|
+
var thickness = 2;
|
|
76
|
+
if (klass)
|
|
77
|
+
klass += ' slur';
|
|
78
|
+
else
|
|
79
|
+
klass = 'slur';
|
|
80
|
+
klass += isTie ? ' tie' : ' legato';
|
|
81
|
+
var ret;
|
|
82
|
+
if (dotted) {
|
|
83
|
+
klass += ' dotted';
|
|
84
|
+
var pathString2 = sprintf("M %f %f C %f %f %f %f %f %f", x1, y1,
|
|
85
|
+
controlx1, controly1, controlx2, controly2, x2, y2);
|
|
86
|
+
ret = renderer.paper.path({path:pathString2, stroke:renderer.foregroundColor, fill:"none", 'stroke-dasharray': "5 5", 'class': renderer.controller.classes.generate(klass), "data-name": isTie ? "tie" : "slur"});
|
|
87
|
+
} else {
|
|
88
|
+
var pathString = sprintf("M %f %f C %f %f %f %f %f %f C %f %f %f %f %f %f z", x1, y1,
|
|
89
|
+
controlx1, controly1, controlx2, controly2, x2, y2,
|
|
90
|
+
roundNumber(controlx2 - thickness * uy), roundNumber(controly2 + thickness * ux), roundNumber(controlx1 - thickness * uy), roundNumber(controly1 + thickness * ux), x1, y1);
|
|
91
|
+
ret = renderer.paper.path({path:pathString, stroke:"none", fill:renderer.foregroundColor, 'class': renderer.controller.classes.generate(klass), "data-name": isTie ? "tie" : "slur"});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return ret;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
module.exports = drawTie;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
var sprintf = require('./sprintf');
|
|
2
|
+
var renderText = require('./text');
|
|
3
|
+
var printPath = require('./print-path');
|
|
4
|
+
var roundNumber = require("./round-number");
|
|
5
|
+
|
|
6
|
+
function drawTriplet(renderer, params, selectables) {
|
|
7
|
+
renderer.paper.openGroup({ klass: renderer.controller.classes.generate('triplet '+params.durationClass), "data-name": "triplet"});
|
|
8
|
+
if (!params.hasBeam) {
|
|
9
|
+
drawBracket(renderer, params.anchor1.x, params.startNote, params.anchor2.x + params.anchor2.w, params.endNote);
|
|
10
|
+
}
|
|
11
|
+
// HACK: adjust the position of "3". It is too high in all cases so we fudge it by subtracting 1 here.
|
|
12
|
+
renderText(renderer, {x: params.xTextPos, y: renderer.calcY(params.yTextPos - 1), text: "" + params.number, type: 'tripletfont', anchor: "middle", centerVertically: true, noClass: true, name: ""+params.number}, true);
|
|
13
|
+
var g = renderer.paper.closeGroup();
|
|
14
|
+
selectables.wrapSvgEl({ el_type: "triplet", startChar: -1, endChar: -1 }, g);
|
|
15
|
+
return g;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function drawLine(l, t, r, b) {
|
|
19
|
+
return sprintf("M %f %f L %f %f", roundNumber(l), roundNumber(t), roundNumber(r), roundNumber(b));
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function drawBracket(renderer, x1, y1, x2, y2) {
|
|
23
|
+
y1 = renderer.calcY(y1);
|
|
24
|
+
y2 = renderer.calcY(y2);
|
|
25
|
+
var bracketHeight = 5;
|
|
26
|
+
|
|
27
|
+
// Draw vertical lines at the beginning and end
|
|
28
|
+
var pathString = "";
|
|
29
|
+
pathString += drawLine(x1, y1, x1, y1 + bracketHeight);
|
|
30
|
+
pathString += drawLine(x2, y2, x2, y2 + bracketHeight);
|
|
31
|
+
|
|
32
|
+
// figure out midpoints to draw the broken line.
|
|
33
|
+
var midX = x1 + (x2-x1)/2;
|
|
34
|
+
//var midY = y1 + (y2-y1)/2;
|
|
35
|
+
var gapWidth = 8;
|
|
36
|
+
var slope = (y2 - y1) / (x2 - x1);
|
|
37
|
+
var leftEndX = midX - gapWidth;
|
|
38
|
+
var leftEndY = y1 + (leftEndX - x1) * slope;
|
|
39
|
+
pathString += drawLine( x1, y1, leftEndX, leftEndY);
|
|
40
|
+
var rightStartX = midX + gapWidth;
|
|
41
|
+
var rightStartY = y1 + (rightStartX - x1) * slope;
|
|
42
|
+
pathString += drawLine( rightStartX, rightStartY, x2, y2);
|
|
43
|
+
printPath(renderer, {path: pathString, stroke: renderer.foregroundColor, "data-name": "triplet-bracket"});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = drawTriplet;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
var drawCrescendo = require('./crescendo');
|
|
2
|
+
var drawDynamics = require('./dynamics');
|
|
3
|
+
var drawTriplet = require('./triplet');
|
|
4
|
+
var drawEnding = require('./ending');
|
|
5
|
+
var drawTie = require('./tie');
|
|
6
|
+
var drawBeam = require('./beam');
|
|
7
|
+
var renderText = require('./text');
|
|
8
|
+
var drawAbsolute = require('./absolute');
|
|
9
|
+
|
|
10
|
+
function drawVoice(renderer, params, bartop, selectables, staffPos) {
|
|
11
|
+
var width = params.w-1;
|
|
12
|
+
renderer.staffbottom = params.staff.bottom;
|
|
13
|
+
|
|
14
|
+
if (params.header) { // print voice name
|
|
15
|
+
var textEl = renderText(renderer, {x: renderer.padding.left, y: renderer.calcY(params.headerPosition), text: params.header, type: 'voicefont', klass: 'staff-extra voice-name', anchor: 'start', centerVertically: true, name: "voice-name"}, true);
|
|
16
|
+
selectables.wrapSvgEl({ el_type: "voiceName", startChar: -1, endChar: -1, text: params.header }, textEl);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
var i;
|
|
20
|
+
var child;
|
|
21
|
+
var foundNote = false;
|
|
22
|
+
for (i=0; i < params.children.length; i++) {
|
|
23
|
+
child = params.children[i];
|
|
24
|
+
if (child.type === 'note' || child.type === 'rest')
|
|
25
|
+
foundNote = true;
|
|
26
|
+
var justInitializedMeasureNumber = false;
|
|
27
|
+
if (child.type !== 'staff-extra' && !renderer.controller.classes.isInMeasure()) {
|
|
28
|
+
renderer.controller.classes.startMeasure();
|
|
29
|
+
justInitializedMeasureNumber = true;
|
|
30
|
+
}
|
|
31
|
+
switch (child.type) {
|
|
32
|
+
// case "tempo":
|
|
33
|
+
// child.elemset = drawTempo(renderer, child);
|
|
34
|
+
// break;
|
|
35
|
+
default:
|
|
36
|
+
if (params.staff.isTabStaff) {
|
|
37
|
+
child.invisible = false;
|
|
38
|
+
if ( child.type == 'bar' ) {
|
|
39
|
+
if (child.abcelem.lastBar) {
|
|
40
|
+
bartop = params.topLine;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
drawAbsolute(renderer, child,(params.barto || i === params.children.length - 1) ? bartop : 0, selectables, staffPos);
|
|
45
|
+
}
|
|
46
|
+
if (child.type === 'note' || isNonSpacerRest(child))
|
|
47
|
+
renderer.controller.classes.incrNote();
|
|
48
|
+
if (child.type === 'bar' && !justInitializedMeasureNumber && foundNote) {
|
|
49
|
+
renderer.controller.classes.incrMeasure();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
renderer.controller.classes.startMeasure();
|
|
54
|
+
|
|
55
|
+
for (i = 0; i < params.beams.length; i++) {
|
|
56
|
+
var beam = params.beams[i];
|
|
57
|
+
if (beam === 'bar') {
|
|
58
|
+
renderer.controller.classes.incrMeasure();
|
|
59
|
+
} else
|
|
60
|
+
drawBeam(renderer, beam, selectables); // beams must be drawn first for proper printing of triplets, slurs and ties.
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
renderer.controller.classes.startMeasure();
|
|
64
|
+
for (i = 0; i < params.otherchildren.length; i++) {
|
|
65
|
+
child = params.otherchildren[i];
|
|
66
|
+
if (child === 'bar') {
|
|
67
|
+
renderer.controller.classes.incrMeasure();
|
|
68
|
+
} else {
|
|
69
|
+
switch (child.type) {
|
|
70
|
+
case "CrescendoElem":
|
|
71
|
+
child.elemset = drawCrescendo(renderer, child, selectables);
|
|
72
|
+
break;
|
|
73
|
+
case "DynamicDecoration":
|
|
74
|
+
child.elemset = drawDynamics(renderer, child, selectables);
|
|
75
|
+
break;
|
|
76
|
+
case "TripletElem":
|
|
77
|
+
drawTriplet(renderer, child, selectables);
|
|
78
|
+
break;
|
|
79
|
+
case "EndingElem":
|
|
80
|
+
child.elemset = drawEnding(renderer, child, params.startx + 10, width, selectables);
|
|
81
|
+
break;
|
|
82
|
+
case "TieElem":
|
|
83
|
+
child.elemset = drawTie(renderer, child, params.startx + 10, width, selectables);
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
console.log(child);
|
|
87
|
+
drawAbsolute(renderer, child, params.startx + 10, width, selectables, staffPos);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function isNonSpacerRest(elem) {
|
|
95
|
+
if (elem.type !== 'rest')
|
|
96
|
+
return false;
|
|
97
|
+
if (elem.abcelem && elem.abcelem.rest && elem.abcelem.rest.type !== 'spacer')
|
|
98
|
+
return true;
|
|
99
|
+
return false;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = drawVoice;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
function formatJazzChord(chordString) {
|
|
2
|
+
// This puts markers in the pieces of the chord that are read by the svg creator.
|
|
3
|
+
// After the main part of the chord (the letter, a sharp or flat, and "m") a marker is added. Before a slash a marker is added.
|
|
4
|
+
var lines = chordString.split("\n");
|
|
5
|
+
for (var i = 0; i < lines.length; i++) {
|
|
6
|
+
var chord = lines[i];
|
|
7
|
+
// If the chord isn't in a recognizable format then just skip the formatting.
|
|
8
|
+
var reg = chord.match(/^([ABCDEFG][♯♭]?)?([^\/]+)?(\/[ABCDEFG][#b]?)?/);
|
|
9
|
+
if (reg)
|
|
10
|
+
lines[i] = (reg[1]?reg[1]:'') + "\x03" + (reg[2]?reg[2]:'') + "\x03" + (reg[3]?reg[3]:'');
|
|
11
|
+
}
|
|
12
|
+
return lines.join("\n");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = formatJazzChord;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
function FreeText(info, vskip, getFontAndAttr, paddingLeft, width, getTextSize) {
|
|
2
|
+
var text = info.text;
|
|
3
|
+
this.rows = [];
|
|
4
|
+
var size;
|
|
5
|
+
if (vskip)
|
|
6
|
+
this.rows.push({move: vskip});
|
|
7
|
+
var hash = getFontAndAttr.calc('textfont', 'defined-text');
|
|
8
|
+
if (text === "") { // we do want to print out blank lines if they have been specified.
|
|
9
|
+
this.rows.push({move: hash.attr['font-size'] * 2}); // move the distance of the line, plus the distance of the margin, which is also one line.
|
|
10
|
+
} else if (typeof text === 'string') {
|
|
11
|
+
this.rows.push({move: hash.attr['font-size']/2}); // TODO-PER: move down some - the y location should be the top of the text, but we output text specifying the center line.
|
|
12
|
+
this.rows.push({left: paddingLeft, text: text, font: 'textfont', klass: 'defined-text', anchor: "start", startChar: info.startChar, endChar: info.endChar, absElemType: "freeText", name: "free-text"});
|
|
13
|
+
size = getTextSize.calc(text, 'textfont', 'defined-text');
|
|
14
|
+
this.rows.push({move: size.height});
|
|
15
|
+
} else if (text) {
|
|
16
|
+
var maxHeight = 0;
|
|
17
|
+
var leftSide = paddingLeft;
|
|
18
|
+
var currentFont = 'textfont';
|
|
19
|
+
for (var i = 0; i < text.length; i++) {
|
|
20
|
+
if (text[i].font) {
|
|
21
|
+
currentFont = text[i].font;
|
|
22
|
+
} else
|
|
23
|
+
currentFont = 'textfont';
|
|
24
|
+
this.rows.push({left: leftSide, text: text[i].text, font: currentFont, klass: 'defined-text', anchor: 'start', startChar: info.startChar, endChar: info.endChar, absElemType: "freeText", name: "free-text"});
|
|
25
|
+
size = getTextSize.calc(text[i].text, getFontAndAttr.calc(currentFont, 'defined-text').font, 'defined-text');
|
|
26
|
+
leftSide += size.width + size.height/2; // add a little padding to the right side. The height of the font is probably a close enough approximation.
|
|
27
|
+
maxHeight = Math.max(maxHeight, size.height)
|
|
28
|
+
}
|
|
29
|
+
this.rows.push({move: maxHeight});
|
|
30
|
+
} else {
|
|
31
|
+
// The structure is wrong here: it requires an array to do centering, but it shouldn't have.
|
|
32
|
+
if (info.length === 1) {
|
|
33
|
+
var x = width / 2;
|
|
34
|
+
this.rows.push({left: x, text: info[0].text, font: 'textfont', klass: 'defined-text', anchor: 'middle', startChar: info.startChar, endChar: info.endChar, absElemType: "freeText", name: "free-text"});
|
|
35
|
+
size = getTextSize.calc(info[0].text, 'textfont', 'defined-text');
|
|
36
|
+
this.rows.push({move: size.height});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
module.exports = FreeText;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var GetFontAndAttr = function GetFontAndAttr(formatting, classes) {
|
|
2
|
+
this.formatting = formatting;
|
|
3
|
+
this.classes = classes;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
GetFontAndAttr.prototype.updateFonts = function(fontOverrides) {
|
|
7
|
+
if (fontOverrides.gchordfont)
|
|
8
|
+
this.formatting.gchordfont = fontOverrides.gchordfont;
|
|
9
|
+
if (fontOverrides.tripletfont)
|
|
10
|
+
this.formatting.tripletfont = fontOverrides.tripletfont;
|
|
11
|
+
if (fontOverrides.annotationfont)
|
|
12
|
+
this.formatting.annotationfont = fontOverrides.annotationfont;
|
|
13
|
+
if (fontOverrides.vocalfont)
|
|
14
|
+
this.formatting.vocalfont = fontOverrides.vocalfont;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
GetFontAndAttr.prototype.calc = function(type, klass) {
|
|
18
|
+
var font;
|
|
19
|
+
if (typeof type === 'string') {
|
|
20
|
+
font = this.formatting[type];
|
|
21
|
+
// Raphael deliberately changes the font units to pixels for some reason, so we need to change points to pixels here.
|
|
22
|
+
if (font)
|
|
23
|
+
font = {face: font.face, size: Math.round(font.size * 4 / 3), decoration: font.decoration, style: font.style, weight: font.weight, box: font.box};
|
|
24
|
+
else
|
|
25
|
+
font = {face: "Arial", size: Math.round(12 * 4 / 3), decoration: "underline", style: "normal", weight: "normal"};
|
|
26
|
+
} else
|
|
27
|
+
font = {face: type.face, size: Math.round(type.size * 4 / 3), decoration: type.decoration, style: type.style, weight: type.weight, box: type.box};
|
|
28
|
+
var paddingPercent = this.formatting.fontboxpadding ? this.formatting.fontboxpadding : 0.1
|
|
29
|
+
font.padding = font.size * paddingPercent;
|
|
30
|
+
|
|
31
|
+
var attr = {"font-size": font.size, 'font-style': font.style,
|
|
32
|
+
"font-family": font.face, 'font-weight': font.weight, 'text-decoration': font.decoration,
|
|
33
|
+
'class': this.classes.generate(klass) };
|
|
34
|
+
return { font: font, attr: attr };
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
module.exports = GetFontAndAttr;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
var GetTextSize = function GetTextSize(getFontAndAttr, svg) {
|
|
2
|
+
this.getFontAndAttr = getFontAndAttr;
|
|
3
|
+
this.svg = svg;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
GetTextSize.prototype.updateFonts = function(fontOverrides) {
|
|
7
|
+
this.getFontAndAttr.updateFonts(fontOverrides);
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
GetTextSize.prototype.attr = function(type, klass) {
|
|
11
|
+
return this.getFontAndAttr.calc(type, klass);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
GetTextSize.prototype.calc = function(text, type, klass, el) {
|
|
15
|
+
var hash;
|
|
16
|
+
// This can be passed in either a string or a font. If it is a string it names one of the standard fonts.
|
|
17
|
+
if (typeof type === 'string')
|
|
18
|
+
hash = this.attr(type, klass);
|
|
19
|
+
else {
|
|
20
|
+
hash = {
|
|
21
|
+
font: {
|
|
22
|
+
face: type.face,
|
|
23
|
+
size: type.size,
|
|
24
|
+
decoration: type.decoration,
|
|
25
|
+
style: type.style,
|
|
26
|
+
weight: type.weight
|
|
27
|
+
},
|
|
28
|
+
attr: {
|
|
29
|
+
"font-size": type.size,
|
|
30
|
+
"font-style": type.style,
|
|
31
|
+
"font-family": type.face,
|
|
32
|
+
"font-weight": type.weight,
|
|
33
|
+
"text-decoration": type.decoration,
|
|
34
|
+
"class": this.getFontAndAttr.classes.generate(klass)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
var size = this.svg.getTextSize(text, hash.attr, el);
|
|
39
|
+
if (hash.font.box) {
|
|
40
|
+
// Add padding and an equal margin to each side.
|
|
41
|
+
return { height: size.height + hash.font.padding*4, width: size.width + hash.font.padding*4 };
|
|
42
|
+
}
|
|
43
|
+
return size;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
GetTextSize.prototype.baselineToCenter = function(text, type, klass, index, total) {
|
|
47
|
+
// This is for the case where SVG wants to use the baseline of the first line as the Y coordinate.
|
|
48
|
+
// If there are multiple lines of text or there is an array of text then that will not be centered so this adjusts it.
|
|
49
|
+
var height = this.calc(text, type, klass).height;
|
|
50
|
+
var fontHeight = this.attr(type, klass).font.size;
|
|
51
|
+
|
|
52
|
+
return height * 0.5 + (total - index - 2) * fontHeight;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
module.exports = GetTextSize;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
var setClass = require('./set-class');
|
|
2
|
+
|
|
3
|
+
var highlight = function (klass, color) {
|
|
4
|
+
if (klass === undefined)
|
|
5
|
+
klass = "abcjs-note_selected";
|
|
6
|
+
if (color === undefined)
|
|
7
|
+
color = "#ff0000";
|
|
8
|
+
setClass(this.elemset, klass, "", color);
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
module.exports = highlight;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
var VoiceElement = function VoiceElements() {}
|
|
2
|
+
|
|
3
|
+
VoiceElement.beginLayout = function (startx, voice) {
|
|
4
|
+
voice.i=0;
|
|
5
|
+
voice.durationindex=0;
|
|
6
|
+
//this.ii=this.children.length;
|
|
7
|
+
voice.startx=startx;
|
|
8
|
+
voice.minx=startx; // furthest left to where negatively positioned elements are allowed to go
|
|
9
|
+
voice.nextx=startx; // x position where the next element of this voice should be placed assuming no other voices and no fixed width constraints
|
|
10
|
+
voice.spacingduration=0; // duration left to be laid out in current iteration (omitting additional spacing due to other aspects, such as bars, dots, sharps and flats)
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
VoiceElement.layoutEnded = function (voice) {
|
|
14
|
+
return (voice.i>=voice.children.length);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
VoiceElement.getNextX = function (voice) {
|
|
18
|
+
return Math.max(voice.minx, voice.nextx);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
// number of spacing units expected for next positioning
|
|
22
|
+
VoiceElement.getSpacingUnits = function (voice) {
|
|
23
|
+
return Math.sqrt(voice.spacingduration*8);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Try to layout the element at index this.i
|
|
27
|
+
// x - position to try to layout the element at
|
|
28
|
+
// spacing - base spacing
|
|
29
|
+
// can't call this function more than once per iteration
|
|
30
|
+
VoiceElement.layoutOneItem = function (x, spacing, voice, minPadding, firstVoice) {
|
|
31
|
+
var child = voice.children[voice.i];
|
|
32
|
+
if (!child) return 0;
|
|
33
|
+
var er = x - voice.minx; // available extrawidth to the left
|
|
34
|
+
var pad = voice.durationindex + child.duration > 0 ? minPadding : 0; // only add padding to the items that aren't fixed to the left edge.
|
|
35
|
+
// See if this item overlaps the item in the first voice. If firstVoice is undefined then there's nothing to compare.
|
|
36
|
+
if (child.abcelem.el_type === "note" && !child.abcelem.rest && voice.voicenumber !== 0 && firstVoice) {
|
|
37
|
+
var firstChild = firstVoice.children[firstVoice.i];
|
|
38
|
+
// It overlaps if the either the child's top or bottom is inside the firstChild's or at least within 1
|
|
39
|
+
// A special case is if the element is on the same line then it can share a note head, if the notehead is the same
|
|
40
|
+
var overlaps = firstChild &&
|
|
41
|
+
((child.abcelem.maxpitch <= firstChild.abcelem.maxpitch+1 && child.abcelem.maxpitch >= firstChild.abcelem.minpitch-1) ||
|
|
42
|
+
(child.abcelem.minpitch <= firstChild.abcelem.maxpitch+1 && child.abcelem.minpitch >= firstChild.abcelem.minpitch-1))
|
|
43
|
+
// See if they can share a note head
|
|
44
|
+
if (overlaps && child.abcelem.minpitch === firstChild.abcelem.minpitch && child.abcelem.maxpitch === firstChild.abcelem.maxpitch &&
|
|
45
|
+
firstChild.heads && firstChild.heads.length > 0 && child.heads && child.heads.length > 0 &&
|
|
46
|
+
firstChild.heads[0].c === child.heads[0].c)
|
|
47
|
+
overlaps = false;
|
|
48
|
+
// If this note overlaps the note in the first voice and we haven't moved the note yet (this can be called multiple times)
|
|
49
|
+
if (overlaps) {
|
|
50
|
+
// I think that firstChild should always have at least one note head, but defensively make sure.
|
|
51
|
+
// There was a problem with this being called more than once so if a value is adjusted then it is saved so it is only adjusted once.
|
|
52
|
+
var firstChildNoteWidth = firstChild.heads && firstChild.heads.length > 0 ? firstChild.heads[0].realWidth : firstChild.fixed.w;
|
|
53
|
+
if (!child.adjustedWidth)
|
|
54
|
+
child.adjustedWidth = firstChildNoteWidth + child.w;
|
|
55
|
+
child.w = child.adjustedWidth
|
|
56
|
+
for (var j = 0; j < child.children.length; j++) {
|
|
57
|
+
var relativeChild = child.children[j];
|
|
58
|
+
if (relativeChild.name.indexOf("accidental") < 0) {
|
|
59
|
+
if (!relativeChild.adjustedWidth)
|
|
60
|
+
relativeChild.adjustedWidth = relativeChild.dx + firstChildNoteWidth;
|
|
61
|
+
relativeChild.dx = relativeChild.adjustedWidth
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
var extraWidth = getExtraWidth(child, pad);
|
|
68
|
+
if (er<extraWidth) { // shift right by needed amount
|
|
69
|
+
// There's an exception if a bar element is after a Part element, there is no shift.
|
|
70
|
+
if (voice.i === 0 || child.type !== 'bar' || (voice.children[voice.i-1].type !== 'part' && voice.children[voice.i-1].type !== 'tempo') )
|
|
71
|
+
x+=extraWidth-er;
|
|
72
|
+
}
|
|
73
|
+
child.setX(x);
|
|
74
|
+
|
|
75
|
+
voice.spacingduration = child.duration;
|
|
76
|
+
//update minx
|
|
77
|
+
voice.minx = x+getMinWidth(child); // add necessary layout space
|
|
78
|
+
if (voice.i!==voice.children.length-1) voice.minx+=child.minspacing; // add minimumspacing except on last elem
|
|
79
|
+
|
|
80
|
+
this.updateNextX(x, spacing, voice);
|
|
81
|
+
|
|
82
|
+
// contribute to staff y position
|
|
83
|
+
//this.staff.top = Math.max(child.top,this.staff.top);
|
|
84
|
+
//this.staff.bottom = Math.min(child.bottom,this.staff.bottom);
|
|
85
|
+
|
|
86
|
+
return x; // where we end up having placed the child
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
VoiceElement.shiftRight = function (dx, voice) {
|
|
90
|
+
var child = voice.children[voice.i];
|
|
91
|
+
if (!child) return;
|
|
92
|
+
child.setX(child.x+dx);
|
|
93
|
+
voice.minx+=dx;
|
|
94
|
+
voice.nextx+=dx;
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
// call when spacingduration has been updated
|
|
98
|
+
VoiceElement.updateNextX = function (x, spacing, voice) {
|
|
99
|
+
voice.nextx= x + (spacing*Math.sqrt(voice.spacingduration*8));
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
VoiceElement.updateIndices = function (voice) {
|
|
103
|
+
if (!this.layoutEnded(voice)) {
|
|
104
|
+
voice.durationindex += voice.children[voice.i].duration;
|
|
105
|
+
if (voice.children[voice.i].type === 'bar') voice.durationindex = Math.round(voice.durationindex*64)/64; // everytime we meet a barline, do rounding to nearest 64th
|
|
106
|
+
voice.i++;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
function getExtraWidth(child, minPadding) { // space needed to the left of the note
|
|
111
|
+
var padding = 0;
|
|
112
|
+
if (child.type === 'note' || child.type === 'bar')
|
|
113
|
+
padding = minPadding;
|
|
114
|
+
return -child.extraw + padding;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function getMinWidth(child) { // absolute space taken to the right of the note
|
|
118
|
+
return child.w;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = VoiceElement;
|