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.
Files changed (204) hide show
  1. package/.github/workflows/tests.yml +29 -0
  2. package/CODE_OF_CONDUCT.md +76 -0
  3. package/CONTRIBUTING.md +1 -0
  4. package/LICENSE.md +1 -1
  5. package/README.md +92 -3
  6. package/RELEASE.md +957 -1
  7. package/abcjs-audio.css +14 -5
  8. package/dist/.gitignore +1 -2
  9. package/dist/abcjs-basic-min.js +3 -0
  10. package/dist/abcjs-basic-min.js.LICENSE +23 -0
  11. package/dist/abcjs-basic.js +28231 -0
  12. package/dist/abcjs-basic.js.map +1 -0
  13. package/dist/abcjs-plugin-min.js +3 -0
  14. package/dist/abcjs-plugin-min.js.LICENSE +23 -0
  15. package/dist/report-basic.html +37 -0
  16. package/dist/report-before-glyph-compress.html +37 -0
  17. package/dist/report-brown-ts-target-es5.html +37 -0
  18. package/dist/report-dev-orig-no-babel.html +37 -0
  19. package/dist/report-synth.html +37 -0
  20. package/docker-build.sh +1 -0
  21. package/glyphs.json +1 -0
  22. package/index.js +27 -2
  23. package/{static-wrappers/license.js → license.js} +1 -1
  24. package/package.json +26 -29
  25. package/{src/plugin/abc_plugin.js → plugin.js} +31 -19
  26. package/src/api/abc_animation.js +1 -17
  27. package/src/api/abc_tablatures.js +144 -0
  28. package/src/api/abc_timing_callbacks.js +234 -116
  29. package/src/api/abc_tunebook.js +18 -67
  30. package/src/api/abc_tunebook_svg.js +38 -46
  31. package/src/data/abc_tune.js +232 -972
  32. package/src/data/deline-tune.js +199 -0
  33. package/src/edit/abc_editarea.js +112 -0
  34. package/src/edit/abc_editor.js +95 -221
  35. package/src/midi/abc_midi_create.js +48 -50
  36. package/src/parse/abc_common.js +0 -14
  37. package/src/parse/abc_parse.js +167 -1321
  38. package/src/parse/abc_parse_book.js +62 -0
  39. package/src/parse/abc_parse_directive.js +164 -41
  40. package/src/parse/abc_parse_header.js +116 -145
  41. package/src/parse/abc_parse_key_voice.js +26 -20
  42. package/src/parse/abc_parse_music.js +1337 -0
  43. package/src/parse/abc_tokenizer.js +21 -15
  44. package/src/parse/abc_transpose.js +3 -15
  45. package/src/parse/tune-builder.js +896 -0
  46. package/src/parse/wrap_lines.js +205 -453
  47. package/src/synth/abc_midi_flattener.js +1292 -0
  48. package/src/{midi → synth}/abc_midi_renderer.js +44 -17
  49. package/src/synth/abc_midi_sequencer.js +648 -0
  50. package/src/synth/active-audio-context.js +3 -14
  51. package/src/synth/cents-to-factor.js +10 -0
  52. package/src/synth/create-note-map.js +21 -32
  53. package/src/synth/create-synth-control.js +20 -103
  54. package/src/synth/create-synth.js +185 -77
  55. package/src/synth/download-buffer.js +7 -21
  56. package/src/synth/get-midi-file.js +13 -20
  57. package/src/synth/images/{loading.svg → loading.svg.js} +4 -0
  58. package/src/synth/images/loop.svg.js +65 -0
  59. package/src/synth/images/pause.svg.js +10 -0
  60. package/src/synth/images/play.svg.js +9 -0
  61. package/src/synth/images/{reset.svg → reset.svg.js} +5 -1
  62. package/src/synth/instrument-index-to-name.js +1 -16
  63. package/src/synth/load-note.js +37 -76
  64. package/src/synth/pitch-to-note-name.js +0 -15
  65. package/src/synth/pitches-to-perc.js +64 -0
  66. package/src/synth/place-note.js +78 -68
  67. package/src/synth/play-event.js +17 -18
  68. package/src/synth/register-audio-context.js +11 -23
  69. package/src/synth/sounds-cache.js +0 -15
  70. package/src/synth/supports-audio.js +9 -23
  71. package/src/synth/synth-controller.js +80 -49
  72. package/src/synth/synth-sequence.js +20 -34
  73. package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
  74. package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
  75. package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
  76. package/src/tablatures/instruments/string-patterns.js +277 -0
  77. package/src/tablatures/instruments/string-tablature.js +56 -0
  78. package/src/tablatures/instruments/tab-note.js +282 -0
  79. package/src/tablatures/instruments/tab-notes.js +41 -0
  80. package/src/tablatures/instruments/violin/tab-violin.js +47 -0
  81. package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
  82. package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
  83. package/src/tablatures/tab-absolute-elements.js +310 -0
  84. package/src/tablatures/tab-common.js +29 -0
  85. package/src/tablatures/tab-renderer.js +243 -0
  86. package/src/tablatures/transposer.js +110 -0
  87. package/src/test/abc_midi_lint.js +5 -22
  88. package/src/test/abc_midi_sequencer_lint.js +11 -14
  89. package/src/test/abc_parser_lint.js +136 -32
  90. package/src/test/abc_vertical_lint.js +94 -32
  91. package/src/test/rendering-lint.js +38 -5
  92. package/src/write/abc_absolute_element.js +112 -120
  93. package/src/write/abc_abstract_engraver.js +102 -253
  94. package/src/write/abc_beam_element.js +30 -290
  95. package/src/write/abc_brace_element.js +12 -121
  96. package/src/write/abc_create_clef.js +21 -32
  97. package/src/write/abc_create_key_signature.js +8 -26
  98. package/src/write/abc_create_note_head.js +107 -0
  99. package/src/write/abc_create_time_signature.js +2 -21
  100. package/src/write/abc_crescendo_element.js +3 -50
  101. package/src/write/abc_decoration.js +7 -30
  102. package/src/write/abc_dynamic_decoration.js +3 -37
  103. package/src/write/abc_ending_element.js +1 -57
  104. package/src/write/abc_engraver_controller.js +111 -234
  105. package/src/write/abc_glyphs.js +9 -19
  106. package/src/write/abc_relative_element.js +57 -97
  107. package/src/write/abc_renderer.js +10 -832
  108. package/src/write/abc_spacing.js +0 -15
  109. package/src/write/abc_staff_group_element.js +14 -349
  110. package/src/write/abc_tempo_element.js +9 -117
  111. package/src/write/abc_tie_element.js +5 -68
  112. package/src/write/abc_triplet_element.js +6 -124
  113. package/src/write/abc_voice_element.js +7 -222
  114. package/src/write/add-chord.js +103 -0
  115. package/src/write/add-text-if.js +33 -0
  116. package/src/write/bottom-text.js +79 -0
  117. package/src/write/calcHeight.js +17 -0
  118. package/src/write/classes.js +100 -0
  119. package/src/write/draw/absolute.js +68 -0
  120. package/src/write/draw/beam.js +56 -0
  121. package/src/write/draw/brace.js +106 -0
  122. package/src/write/draw/crescendo.js +38 -0
  123. package/src/write/draw/debug-box.js +8 -0
  124. package/src/write/draw/draw.js +56 -0
  125. package/src/write/draw/dynamics.js +20 -0
  126. package/src/write/draw/ending.js +46 -0
  127. package/src/write/draw/group-elements.js +66 -0
  128. package/src/write/draw/horizontal-line.js +25 -0
  129. package/src/write/draw/non-music.js +50 -0
  130. package/src/write/draw/print-line.js +24 -0
  131. package/src/write/draw/print-path.js +7 -0
  132. package/src/write/draw/print-stem.js +30 -0
  133. package/src/write/draw/print-symbol.js +59 -0
  134. package/src/write/draw/print-vertical-line.js +18 -0
  135. package/src/write/draw/relative.js +77 -0
  136. package/src/write/draw/round-number.js +5 -0
  137. package/src/write/draw/selectables.js +59 -0
  138. package/src/write/draw/separator.js +16 -0
  139. package/src/write/draw/set-paper-size.js +45 -0
  140. package/src/write/{sprintf.js → draw/sprintf.js} +0 -0
  141. package/src/write/draw/staff-group.js +226 -0
  142. package/src/write/draw/staff-line.js +9 -0
  143. package/src/write/draw/staff.js +33 -0
  144. package/src/write/draw/tab-line.js +40 -0
  145. package/src/write/draw/tempo.js +45 -0
  146. package/src/write/draw/text.js +71 -0
  147. package/src/write/draw/tie.js +97 -0
  148. package/src/write/draw/triplet.js +46 -0
  149. package/src/write/draw/voice.js +102 -0
  150. package/src/write/format-jazz-chord.js +15 -0
  151. package/src/write/free-text.js +41 -0
  152. package/src/write/get-font-and-attr.js +37 -0
  153. package/src/write/get-text-size.js +56 -0
  154. package/src/write/highlight.js +11 -0
  155. package/src/write/layout/VoiceElements.js +121 -0
  156. package/src/write/layout/beam.js +213 -0
  157. package/src/write/layout/get-left-edge-of-staff.js +56 -0
  158. package/src/write/layout/getBarYAt.js +6 -0
  159. package/src/write/layout/layout.js +94 -0
  160. package/src/write/layout/setUpperAndLowerElements.js +232 -0
  161. package/src/write/layout/staffGroup.js +146 -0
  162. package/src/write/layout/triplet.js +75 -0
  163. package/src/write/layout/voice.js +137 -0
  164. package/src/write/selection.js +188 -70
  165. package/src/write/separator.js +10 -0
  166. package/src/write/set-class.js +21 -0
  167. package/src/write/subtitle.js +12 -0
  168. package/src/write/svg.js +95 -43
  169. package/src/write/top-text.js +54 -0
  170. package/src/write/unhighlight.js +11 -0
  171. package/temp.txt +17 -0
  172. package/test.js +27 -64
  173. package/types/index.d.ts +1095 -0
  174. package/version.js +1 -1
  175. package/.babelrc +0 -5
  176. package/.eslintrc +0 -3
  177. package/.gitmodules +0 -3
  178. package/abcjs-midi.css +0 -166
  179. package/build-utils/loadPresets.js +0 -14
  180. package/build-utils/presets/webpack.analyze.js +0 -6
  181. package/build-utils/presets/webpack.optimize.js +0 -30
  182. package/build-utils/webpack.development.js +0 -14
  183. package/build-utils/webpack.production.js +0 -35
  184. package/deploy-docs.sh +0 -25
  185. package/docs/README.md +0 -33
  186. package/fix-versions.sh +0 -23
  187. package/mei.js +0 -43
  188. package/midi.js +0 -62
  189. package/src/api/abc_tunebook_midi.js +0 -116
  190. package/src/midi/abc_midi_controls.js +0 -701
  191. package/src/midi/abc_midi_flattener.js +0 -1119
  192. package/src/midi/abc_midi_js_preparer.js +0 -243
  193. package/src/midi/abc_midi_sequencer.js +0 -401
  194. package/src/midi/abc_midi_ui_generator.js +0 -86
  195. package/src/plugin/abc_plugin_midi.js +0 -220
  196. package/src/synth/images/loop.svg +0 -61
  197. package/src/synth/images/pause.svg +0 -6
  198. package/src/synth/images/play.svg +0 -5
  199. package/src/transform/abc2abc_write.js +0 -395
  200. package/static-wrappers/basic.js +0 -2
  201. package/static-wrappers/midi.js +0 -2
  202. package/static-wrappers/plugin-midi.js +0 -6
  203. package/static-wrappers/plugin.js +0 -6
  204. package/webpack.config.js +0 -29
@@ -0,0 +1,146 @@
1
+ var layoutVoiceElements = require('./VoiceElements');
2
+
3
+ function checkLastBarX(voices) {
4
+ var maxX = 0;
5
+ for (var i = 0; i < voices.length; i++) {
6
+ var curVoice = voices[i];
7
+ if (curVoice.children.length > 0) {
8
+ var lastChild = curVoice.children.length - 1;
9
+ var maxChild = curVoice.children[lastChild];
10
+ if (maxChild.abcelem.el_type === 'bar') {
11
+ var barX = maxChild.children[0].x;
12
+ if (barX > maxX) {
13
+ maxX = barX;
14
+ } else {
15
+ maxChild.children[0].x = maxX;
16
+ }
17
+ }
18
+ }
19
+ }
20
+ }
21
+
22
+ var layoutStaffGroup = function(spacing, renderer, debug, staffGroup, leftEdge) {
23
+ var epsilon = 0.0000001; // Fudging for inexactness of floating point math.
24
+ var spacingunits = 0; // number of times we will have ended up using the spacing distance (as opposed to fixed width distances)
25
+ var minspace = 1000; // a big number to start off with - used to find out what the smallest space between two notes is -- GD 2014.1.7
26
+
27
+ var x = leftEdge;
28
+ staffGroup.startx=x;
29
+ var i;
30
+
31
+ var currentduration = 0;
32
+ if (debug) console.log("init layout", spacing);
33
+ for (i=0;i<staffGroup.voices.length;i++) {
34
+ layoutVoiceElements.beginLayout(x, staffGroup.voices[i]);
35
+ }
36
+
37
+ var spacingunit = 0; // number of spacingunits coming from the previously laid out element to this one
38
+ while (!finished(staffGroup.voices)) {
39
+ // find first duration level to be laid out among candidates across voices
40
+ currentduration= null; // candidate smallest duration level
41
+ for (i=0;i<staffGroup.voices.length;i++) {
42
+ if (!layoutVoiceElements.layoutEnded(staffGroup.voices[i]) && (!currentduration || getDurationIndex(staffGroup.voices[i])<currentduration))
43
+ currentduration=getDurationIndex(staffGroup.voices[i]);
44
+ }
45
+
46
+
47
+ // isolate voices at current duration level
48
+ var currentvoices = [];
49
+ var othervoices = [];
50
+ for (i=0;i<staffGroup.voices.length;i++) {
51
+ var durationIndex = getDurationIndex(staffGroup.voices[i]);
52
+ // PER: Because of the inexactness of JS floating point math, we just get close.
53
+ if (durationIndex - currentduration > epsilon) {
54
+ othervoices.push(staffGroup.voices[i]);
55
+ //console.log("out: voice ",i);
56
+ } else {
57
+ currentvoices.push(staffGroup.voices[i]);
58
+ //if (debug) console.log("in: voice ",i);
59
+ }
60
+ }
61
+
62
+ // among the current duration level find the one which needs starting furthest right
63
+ spacingunit = 0; // number of spacingunits coming from the previously laid out element to this one
64
+ var spacingduration = 0;
65
+ for (i=0;i<currentvoices.length;i++) {
66
+ //console.log("greatest spacing unit", x, layoutVoiceElements.getNextX(currentvoices[i]), layoutVoiceElements.getSpacingUnits(currentvoices[i]), currentvoices[i].spacingduration);
67
+ if (layoutVoiceElements.getNextX(currentvoices[i])>x) {
68
+ x=layoutVoiceElements.getNextX(currentvoices[i]);
69
+ spacingunit=layoutVoiceElements.getSpacingUnits(currentvoices[i]);
70
+ spacingduration = currentvoices[i].spacingduration;
71
+ }
72
+ }
73
+ spacingunits+=spacingunit;
74
+ minspace = Math.min(minspace,spacingunit);
75
+ if (debug) console.log("currentduration: ",currentduration, spacingunits, minspace);
76
+
77
+ var lastTopVoice = undefined;
78
+ for (i=0;i<currentvoices.length;i++) {
79
+ var v = currentvoices[i];
80
+ if (v.voicenumber === 0)
81
+ lastTopVoice = i;
82
+ var topVoice = (lastTopVoice !== undefined && currentvoices[lastTopVoice].voicenumber !== v.voicenumber) ? currentvoices[lastTopVoice] : undefined;
83
+ if (!isSameStaff(v, topVoice))
84
+ topVoice = undefined;
85
+ var voicechildx = layoutVoiceElements.layoutOneItem(x,spacing, v, renderer.minPadding, topVoice);
86
+ var dx = voicechildx-x;
87
+ if (dx>0) {
88
+ x = voicechildx; //update x
89
+ for (var j=0;j<i;j++) { // shift over all previously laid out elements
90
+ layoutVoiceElements.shiftRight(dx, currentvoices[j]);
91
+ }
92
+ }
93
+ }
94
+
95
+ // remove the value of already counted spacing units in other voices (e.g. if a voice had planned to use up 5 spacing units but is not in line to be laid out at this duration level - where we've used 2 spacing units - then we must use up 3 spacing units, not 5)
96
+ for (i=0;i<othervoices.length;i++) {
97
+ othervoices[i].spacingduration-=spacingduration;
98
+ layoutVoiceElements.updateNextX(x,spacing, othervoices[i]); // adjust other voices expectations
99
+ }
100
+
101
+ // update indexes of currently laid out elems
102
+ for (i=0;i<currentvoices.length;i++) {
103
+ var voice = currentvoices[i];
104
+ layoutVoiceElements.updateIndices(voice);
105
+ }
106
+ } // finished laying out
107
+
108
+
109
+ // find the greatest remaining x as a base for the width
110
+ for (i=0;i<staffGroup.voices.length;i++) {
111
+ if (layoutVoiceElements.getNextX(staffGroup.voices[i])>x) {
112
+ x=layoutVoiceElements.getNextX(staffGroup.voices[i]);
113
+ spacingunit=layoutVoiceElements.getSpacingUnits(staffGroup.voices[i]);
114
+ }
115
+ }
116
+
117
+ // adjust lastBar when needed (multi staves)
118
+ checkLastBarX(staffGroup.voices);
119
+ //console.log("greatest remaining",spacingunit,x);
120
+ spacingunits+=spacingunit;
121
+ staffGroup.setWidth(x);
122
+
123
+ return { spacingUnits: spacingunits, minSpace: minspace };
124
+ };
125
+
126
+
127
+ function finished(voices) {
128
+ for (var i=0;i<voices.length;i++) {
129
+ if (!layoutVoiceElements.layoutEnded(voices[i])) return false;
130
+ }
131
+ return true;
132
+ }
133
+
134
+ function getDurationIndex(element) {
135
+ return element.durationindex - (element.children[element.i] && (element.children[element.i].duration>0)?0:0.0000005); // if the ith element doesn't have a duration (is not a note), its duration index is fractionally before. This enables CLEF KEYSIG TIMESIG PART, etc. to be laid out before we get to the first note of other voices
136
+ }
137
+
138
+ function isSameStaff(voice1, voice2) {
139
+ if (!voice1 || !voice1.staff || !voice1.staff.voices || voice1.staff.voices.length === 0)
140
+ return false;
141
+ if (!voice2 || !voice2.staff || !voice2.staff.voices || voice2.staff.voices.length === 0)
142
+ return false;
143
+ return (voice1.staff.voices[0] === voice2.staff.voices[0]);
144
+ }
145
+
146
+ module.exports = layoutStaffGroup;
@@ -0,0 +1,75 @@
1
+ var getBarYAt = require('./getBarYAt');
2
+
3
+ function layoutTriplet(element) {
4
+ // TODO end and beginning of line (PER: P.S. I'm not sure this can happen: I think the parser will always specify both the start and end points.)
5
+ if (element.anchor1 && element.anchor2) {
6
+ element.hasBeam = !!element.anchor1.parent.beam && element.anchor1.parent.beam === element.anchor2.parent.beam;
7
+ var beam = element.anchor1.parent.beam;
8
+ // if hasBeam is true, then the first and last element in the triplet have the same beam.
9
+ // We also need to check if the beam doesn't contain other notes so that `(3 dcdcc` will do a bracket.
10
+ if (element.hasBeam && (beam.elems[0] !== element.anchor1.parent || beam.elems[beam.elems.length-1] !== element.anchor2.parent))
11
+ element.hasBeam = false;
12
+
13
+ if (element.hasBeam) {
14
+ // If there is a beam then we don't need to draw anything except the text. The beam could either be above or below.
15
+ var left = isAbove(beam) ? element.anchor1.x + element.anchor1.w : element.anchor1.x;
16
+ element.yTextPos = heightAtMidpoint(left, element.anchor2.x, beam);
17
+ element.yTextPos += isAbove(beam) ? 3 : -2; // This creates some space between the beam and the number.
18
+ element.xTextPos = xAtMidpoint(left, element.anchor2.x);
19
+ element.top = element.yTextPos + 1;
20
+ element.bottom = element.yTextPos - 2;
21
+ if (isAbove(beam))
22
+ element.endingHeightAbove = 4;
23
+ } else {
24
+ // If there isn't a beam, then we need to draw the bracket and the text. The bracket is always above.
25
+ // The bracket is never lower than the 'a' line, but is 4 pitches above the first and last notes. If there is
26
+ // a tall note in the middle, the bracket is horizontal and above the highest note.
27
+ element.startNote = Math.max(element.anchor1.parent.top, 9) + 4;
28
+ element.endNote = Math.max(element.anchor2.parent.top, 9) + 4;
29
+ // If it starts or ends on a rest, make the beam horizontal
30
+ if (element.anchor1.parent.type === "rest" && element.anchor2.parent.type !== "rest")
31
+ element.startNote = element.endNote;
32
+ else if (element.anchor2.parent.type === "rest" && element.anchor1.parent.type !== "rest")
33
+ element.endNote = element.startNote;
34
+ // See if the middle note is really high.
35
+ var max = 0;
36
+ for (var i = 0; i < element.middleElems.length; i++) {
37
+ max = Math.max(max, element.middleElems[i].top);
38
+ }
39
+ max += 4;
40
+ if (max > element.startNote || max > element.endNote) {
41
+ element.startNote = max;
42
+ element.endNote = max;
43
+ }
44
+ if (element.flatBeams) {
45
+ element.startNote = Math.max(element.startNote, element.endNote);
46
+ element.endNote = Math.max(element.startNote, element.endNote);
47
+ }
48
+
49
+ element.yTextPos = element.startNote + (element.endNote - element.startNote) / 2;
50
+ element.xTextPos = element.anchor1.x + (element.anchor2.x + element.anchor2.w - element.anchor1.x) / 2;
51
+ element.top = element.yTextPos + 1;
52
+ }
53
+ }
54
+ delete element.middleElems;
55
+ delete element.flatBeams;
56
+ }
57
+
58
+ function isAbove(beam) {
59
+ return beam.stemsUp;
60
+ }
61
+
62
+ // We can't just use the entire beam for the calculation. The range has to be passed in, because the beam might extend into some unrelated notes. for instance, (3_a'f'e'f'2 when L:16
63
+ function heightAtMidpoint(startX, endX, beam) {
64
+ if (beam.beams.length === 0)
65
+ return 0;
66
+ beam = beam.beams[0];
67
+ var midPoint = startX + (endX - startX) / 2;
68
+ return getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, midPoint);
69
+ }
70
+
71
+ function xAtMidpoint(startX, endX) {
72
+ return startX + (endX - startX)/2;
73
+ }
74
+
75
+ module.exports = layoutTriplet;
@@ -0,0 +1,137 @@
1
+ var layoutBeam = require('./beam');
2
+ var getBarYAt = require('./getBarYAt');
3
+ var layoutTriplet = require('./triplet');
4
+
5
+ var layoutVoice = function(voice) {
6
+ for (var i = 0; i < voice.beams.length; i++) {
7
+ if (voice.beams[i].type === 'BeamElem') {
8
+ layoutBeam(voice.beams[i]);
9
+ moveDecorations(voice.beams[i]);
10
+ // The above will change the top and bottom of the abselem children, so see if we need to expand our range.
11
+ for (var j = 0; j < voice.beams[i].elems.length; j++) {
12
+ voice.adjustRange(voice.beams[i].elems[j]);
13
+ }
14
+ }
15
+ }
16
+ voice.staff.specialY.chordLines = setLaneForChord(voice.children);
17
+
18
+ // Now we can layout the triplets
19
+ for (i = 0; i < voice.otherchildren.length; i++) {
20
+ var child = voice.otherchildren[i];
21
+ if (child.type === 'TripletElem') {
22
+ layoutTriplet(child);
23
+ voice.adjustRange(child);
24
+ }
25
+ }
26
+ voice.staff.top = Math.max(voice.staff.top, voice.top);
27
+ voice.staff.bottom = Math.min(voice.staff.bottom, voice.bottom);
28
+ };
29
+
30
+ function moveDecorations(beam) {
31
+ var padding = 1.5; // This is the vertical padding between elements, in pitches.
32
+ for (var ch = 0; ch < beam.elems.length; ch++) {
33
+ var child = beam.elems[ch];
34
+ if (child.top) {
35
+ // We now know where the ornaments should have been placed, so move them if they would overlap.
36
+ var top = yAtNote(child, beam);
37
+ for (var i = 0; i < child.children.length; i++) {
38
+ var el = child.children[i];
39
+ if (el.klass === 'ornament') {
40
+ if (el.bottom - padding < top) {
41
+ var distance = top - el.bottom + padding; // Find the distance that it needs to move and add a little margin so the element doesn't touch the beam.
42
+ el.bottom += distance;
43
+ el.top += distance;
44
+ el.pitch += distance;
45
+ top = child.top = el.top;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ function placeInLane(rightMost, relElem) {
54
+ // These items are centered so figure the coordinates accordingly.
55
+ // The font reports some extra space so the margin is built in.
56
+ var xCoords = relElem.getChordDim();
57
+ if (xCoords) {
58
+ for (var i = 0; i < rightMost.length; i++) {
59
+ var fits = rightMost[i] < xCoords.left;
60
+ if (fits) {
61
+ if (i > 0)
62
+ relElem.putChordInLane(i);
63
+ rightMost[i] = xCoords.right;
64
+ return;
65
+ }
66
+ }
67
+ // If we didn't return early, then we need a new row
68
+ rightMost.push(xCoords.right);
69
+ relElem.putChordInLane(rightMost.length-1);
70
+ }
71
+ }
72
+
73
+ function setLaneForChord(absElems) {
74
+ // Criteria:
75
+ // 1) lane numbers start from the bottom so that as many items as possible are in lane 0, closest to the music.
76
+ // 2) a chord can have more than one line (for instance "C\nD") each line is a lane.
77
+ // 3) if two adjoining items would touch then push the second one to the next lane.
78
+ // 4) use as many lanes as is necessary to get everything to not touch.
79
+ // 5) leave a margin between items, so use another lane if the chords would have less than a character's width.
80
+ // 6) if the chord only has one character, allow it to be closer than if the chord has more than one character.
81
+ var rightMostAbove = [0];
82
+ var rightMostBelow = [0];
83
+ var i;
84
+ var j;
85
+ var relElem;
86
+ for (i = 0; i < absElems.length; i++) {
87
+ for (j = 0; j < absElems[i].children.length; j++) {
88
+ relElem = absElems[i].children[j];
89
+ if (relElem.chordHeightAbove) {
90
+ placeInLane(rightMostAbove, relElem);
91
+ }
92
+ }
93
+ for (j = absElems[i].children.length-1; j >=0; j--) {
94
+ relElem = absElems[i].children[j];
95
+ if (relElem.chordHeightBelow) {
96
+ placeInLane(rightMostBelow, relElem);
97
+ }
98
+ }
99
+ }
100
+ // If we used a second line, then we need to go back and set the first lines.
101
+ // Also we need to flip the indexes of the names so that we can count from the top line.
102
+ if (rightMostAbove.length > 1 || rightMostBelow.length > 1)
103
+ setLane(absElems, rightMostAbove.length, rightMostBelow.length);
104
+ return { above: rightMostAbove.length, below: rightMostBelow.length };
105
+ }
106
+
107
+ function numAnnotationsBelow(absElem) {
108
+ var count = 0;
109
+ for (var j = 0; j < absElem.children.length; j++) {
110
+ var relElem = absElem.children[j];
111
+ if (relElem.chordHeightBelow)
112
+ count++;
113
+ }
114
+ return count;
115
+ }
116
+
117
+ function setLane(absElems, numLanesAbove, numLanesBelow) {
118
+ for (var i = 0; i < absElems.length; i++) {
119
+ var below = numAnnotationsBelow(absElems[i]);
120
+ for (var j = 0; j < absElems[i].children.length; j++) {
121
+ var relElem = absElems[i].children[j];
122
+ if (relElem.chordHeightAbove) {
123
+ relElem.invertLane(numLanesAbove);
124
+ // } else if (relElem.chordHeightBelow) {
125
+ // relElem.invertLane(below);
126
+ }
127
+ }
128
+ }
129
+ }
130
+
131
+ function yAtNote(element, beam) {
132
+ beam = beam.beams[0];
133
+ return getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, element.x);
134
+ }
135
+
136
+
137
+ module.exports = layoutVoice;