abcjs 6.0.0-beta.9 → 6.0.2

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 (197) 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 +88 -7
  6. package/RELEASE.md +961 -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 +28232 -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/index.js +27 -2
  16. package/{static-wrappers/license.js → license.js} +1 -1
  17. package/package.json +26 -29
  18. package/{src/plugin/abc_plugin.js → plugin.js} +31 -19
  19. package/src/api/abc_animation.js +1 -17
  20. package/src/api/abc_tablatures.js +144 -0
  21. package/src/api/abc_timing_callbacks.js +216 -117
  22. package/src/api/abc_tunebook.js +18 -67
  23. package/src/api/abc_tunebook_svg.js +40 -48
  24. package/src/data/abc_tune.js +232 -972
  25. package/src/data/deline-tune.js +199 -0
  26. package/src/edit/abc_editarea.js +112 -0
  27. package/src/edit/abc_editor.js +95 -221
  28. package/src/midi/abc_midi_create.js +48 -50
  29. package/src/parse/abc_common.js +0 -14
  30. package/src/parse/abc_parse.js +167 -1321
  31. package/src/parse/abc_parse_book.js +62 -0
  32. package/src/parse/abc_parse_directive.js +164 -41
  33. package/src/parse/abc_parse_header.js +116 -145
  34. package/src/parse/abc_parse_key_voice.js +26 -20
  35. package/src/parse/abc_parse_music.js +1337 -0
  36. package/src/parse/abc_tokenizer.js +21 -15
  37. package/src/parse/abc_transpose.js +3 -15
  38. package/src/parse/tune-builder.js +896 -0
  39. package/src/parse/wrap_lines.js +205 -453
  40. package/src/synth/abc_midi_flattener.js +1292 -0
  41. package/src/{midi → synth}/abc_midi_renderer.js +44 -17
  42. package/src/synth/abc_midi_sequencer.js +648 -0
  43. package/src/synth/active-audio-context.js +3 -14
  44. package/src/synth/cents-to-factor.js +10 -0
  45. package/src/synth/create-note-map.js +21 -32
  46. package/src/synth/create-synth-control.js +20 -103
  47. package/src/synth/create-synth.js +185 -77
  48. package/src/synth/download-buffer.js +7 -21
  49. package/src/synth/get-midi-file.js +13 -20
  50. package/src/synth/images/{loading.svg → loading.svg.js} +4 -0
  51. package/src/synth/images/loop.svg.js +65 -0
  52. package/src/synth/images/pause.svg.js +10 -0
  53. package/src/synth/images/play.svg.js +9 -0
  54. package/src/synth/images/{reset.svg → reset.svg.js} +5 -1
  55. package/src/synth/instrument-index-to-name.js +1 -16
  56. package/src/synth/load-note.js +37 -76
  57. package/src/synth/pitch-to-note-name.js +0 -15
  58. package/src/synth/pitches-to-perc.js +64 -0
  59. package/src/synth/place-note.js +78 -68
  60. package/src/synth/play-event.js +17 -18
  61. package/src/synth/register-audio-context.js +11 -23
  62. package/src/synth/sounds-cache.js +0 -15
  63. package/src/synth/supports-audio.js +9 -23
  64. package/src/synth/synth-controller.js +80 -49
  65. package/src/synth/synth-sequence.js +20 -34
  66. package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
  67. package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
  68. package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
  69. package/src/tablatures/instruments/string-patterns.js +277 -0
  70. package/src/tablatures/instruments/string-tablature.js +56 -0
  71. package/src/tablatures/instruments/tab-note.js +282 -0
  72. package/src/tablatures/instruments/tab-notes.js +41 -0
  73. package/src/tablatures/instruments/violin/tab-violin.js +47 -0
  74. package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
  75. package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
  76. package/src/tablatures/tab-absolute-elements.js +310 -0
  77. package/src/tablatures/tab-common.js +29 -0
  78. package/src/tablatures/tab-renderer.js +243 -0
  79. package/src/tablatures/transposer.js +110 -0
  80. package/src/test/abc_midi_lint.js +5 -22
  81. package/src/test/abc_midi_sequencer_lint.js +11 -14
  82. package/src/test/abc_parser_lint.js +136 -32
  83. package/src/test/abc_vertical_lint.js +94 -32
  84. package/src/test/rendering-lint.js +38 -5
  85. package/src/write/abc_absolute_element.js +112 -120
  86. package/src/write/abc_abstract_engraver.js +102 -253
  87. package/src/write/abc_beam_element.js +30 -290
  88. package/src/write/abc_brace_element.js +12 -121
  89. package/src/write/abc_create_clef.js +21 -32
  90. package/src/write/abc_create_key_signature.js +8 -26
  91. package/src/write/abc_create_note_head.js +107 -0
  92. package/src/write/abc_create_time_signature.js +2 -21
  93. package/src/write/abc_crescendo_element.js +3 -50
  94. package/src/write/abc_decoration.js +7 -30
  95. package/src/write/abc_dynamic_decoration.js +3 -37
  96. package/src/write/abc_ending_element.js +1 -57
  97. package/src/write/abc_engraver_controller.js +111 -234
  98. package/src/write/abc_glyphs.js +8 -18
  99. package/src/write/abc_relative_element.js +57 -97
  100. package/src/write/abc_renderer.js +10 -832
  101. package/src/write/abc_spacing.js +0 -15
  102. package/src/write/abc_staff_group_element.js +14 -349
  103. package/src/write/abc_tempo_element.js +9 -117
  104. package/src/write/abc_tie_element.js +5 -68
  105. package/src/write/abc_triplet_element.js +6 -124
  106. package/src/write/abc_voice_element.js +7 -222
  107. package/src/write/add-chord.js +103 -0
  108. package/src/write/add-text-if.js +33 -0
  109. package/src/write/bottom-text.js +79 -0
  110. package/src/write/calcHeight.js +17 -0
  111. package/src/write/classes.js +100 -0
  112. package/src/write/draw/absolute.js +68 -0
  113. package/src/write/draw/beam.js +56 -0
  114. package/src/write/draw/brace.js +106 -0
  115. package/src/write/draw/crescendo.js +38 -0
  116. package/src/write/draw/debug-box.js +8 -0
  117. package/src/write/draw/draw.js +56 -0
  118. package/src/write/draw/dynamics.js +20 -0
  119. package/src/write/draw/ending.js +46 -0
  120. package/src/write/draw/group-elements.js +66 -0
  121. package/src/write/draw/horizontal-line.js +25 -0
  122. package/src/write/draw/non-music.js +50 -0
  123. package/src/write/draw/print-line.js +24 -0
  124. package/src/write/draw/print-path.js +7 -0
  125. package/src/write/draw/print-stem.js +30 -0
  126. package/src/write/draw/print-symbol.js +59 -0
  127. package/src/write/draw/print-vertical-line.js +18 -0
  128. package/src/write/draw/relative.js +77 -0
  129. package/src/write/draw/round-number.js +5 -0
  130. package/src/write/draw/selectables.js +59 -0
  131. package/src/write/draw/separator.js +16 -0
  132. package/src/write/draw/set-paper-size.js +45 -0
  133. package/src/write/{sprintf.js → draw/sprintf.js} +0 -0
  134. package/src/write/draw/staff-group.js +226 -0
  135. package/src/write/draw/staff-line.js +9 -0
  136. package/src/write/draw/staff.js +33 -0
  137. package/src/write/draw/tab-line.js +40 -0
  138. package/src/write/draw/tempo.js +45 -0
  139. package/src/write/draw/text.js +71 -0
  140. package/src/write/draw/tie.js +97 -0
  141. package/src/write/draw/triplet.js +46 -0
  142. package/src/write/draw/voice.js +102 -0
  143. package/src/write/format-jazz-chord.js +15 -0
  144. package/src/write/free-text.js +41 -0
  145. package/src/write/get-font-and-attr.js +37 -0
  146. package/src/write/get-text-size.js +56 -0
  147. package/src/write/highlight.js +11 -0
  148. package/src/write/layout/VoiceElements.js +121 -0
  149. package/src/write/layout/beam.js +213 -0
  150. package/src/write/layout/get-left-edge-of-staff.js +56 -0
  151. package/src/write/layout/getBarYAt.js +6 -0
  152. package/src/write/layout/layout.js +94 -0
  153. package/src/write/layout/setUpperAndLowerElements.js +232 -0
  154. package/src/write/layout/staffGroup.js +146 -0
  155. package/src/write/layout/triplet.js +75 -0
  156. package/src/write/layout/voice.js +137 -0
  157. package/src/write/selection.js +188 -70
  158. package/src/write/separator.js +10 -0
  159. package/src/write/set-class.js +21 -0
  160. package/src/write/subtitle.js +12 -0
  161. package/src/write/svg.js +95 -43
  162. package/src/write/top-text.js +54 -0
  163. package/src/write/unhighlight.js +11 -0
  164. package/test.js +27 -64
  165. package/types/index.d.ts +1095 -0
  166. package/version.js +1 -1
  167. package/.babelrc +0 -5
  168. package/.eslintrc +0 -3
  169. package/.gitmodules +0 -3
  170. package/Dockerfile +0 -8
  171. package/abcjs-midi.css +0 -166
  172. package/build-utils/loadPresets.js +0 -14
  173. package/build-utils/presets/webpack.analyze.js +0 -6
  174. package/build-utils/presets/webpack.optimize.js +0 -30
  175. package/build-utils/webpack.development.js +0 -14
  176. package/build-utils/webpack.production.js +0 -35
  177. package/deploy-docs.sh +0 -25
  178. package/docker-compose.yml +0 -13
  179. package/docs/README.md +0 -33
  180. package/fix-versions.sh +0 -23
  181. package/midi.js +0 -62
  182. package/src/api/abc_tunebook_midi.js +0 -116
  183. package/src/midi/abc_midi_controls.js +0 -701
  184. package/src/midi/abc_midi_flattener.js +0 -1119
  185. package/src/midi/abc_midi_js_preparer.js +0 -243
  186. package/src/midi/abc_midi_sequencer.js +0 -401
  187. package/src/midi/abc_midi_ui_generator.js +0 -86
  188. package/src/plugin/abc_plugin_midi.js +0 -220
  189. package/src/synth/images/loop.svg +0 -61
  190. package/src/synth/images/pause.svg +0 -6
  191. package/src/synth/images/play.svg +0 -5
  192. package/src/transform/abc2abc_write.js +0 -395
  193. package/static-wrappers/basic.js +0 -2
  194. package/static-wrappers/midi.js +0 -2
  195. package/static-wrappers/plugin-midi.js +0 -6
  196. package/static-wrappers/plugin.js +0 -6
  197. package/webpack.config.js +0 -29
@@ -1,27 +1,7 @@
1
1
  // abc_triplet_element.js: Definition of the TripletElem class.
2
- // Copyright (C) 2010-2020 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
3
- //
4
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5
- // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
6
- // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
7
- // to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
- //
9
- // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
- //
11
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
12
- // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
14
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
2
 
17
- var sprintf = require('./sprintf');
18
-
19
- var TripletElem;
20
-
21
- (function() {
22
- "use strict";
23
-
24
- TripletElem = function TripletElem(number, anchor1, options) {
3
+ var TripletElem = function TripletElem(number, anchor1, options) {
4
+ this.type = "TripletElem";
25
5
  this.anchor1 = anchor1; // must have a .x and a .parent property or be null (means starts at the "beginning" of the line - after key signature)
26
6
  this.number = number;
27
7
  this.durationClass = ('d'+(Math.round(anchor1.parent.durationClass*1000)/1000)).replace(/\./, '-');
@@ -30,7 +10,7 @@ var TripletElem;
30
10
  };
31
11
 
32
12
  TripletElem.prototype.isClosed = function() {
33
- return this.anchor2;
13
+ return !!this.anchor2;
34
14
  };
35
15
 
36
16
  TripletElem.prototype.middleNote = function(elem) {
@@ -39,108 +19,10 @@ var TripletElem;
39
19
 
40
20
  TripletElem.prototype.setCloseAnchor = function(anchor2) {
41
21
  this.anchor2 = anchor2;
42
- // TODO-PER: Unfortunately, I don't know if there is a beam above until after the vertical positioning is done,
43
- // so I don't know whether to leave room for the number above. Therefore, If there is a beam on the first note, I'll leave room just in case.
44
- if (this.anchor1.parent.beam)
22
+ // TODO-PER: This used to be just for beamed triplets but it looks like bracketed triplets need extra room, too. The only one that doesn't is stem down and beamed
23
+ //if (this.anchor1.parent.beam)
24
+ if (!this.anchor1.parent.beam || this.anchor1.stemDir === 'up')
45
25
  this.endingHeightAbove = 4;
46
26
  };
47
27
 
48
- TripletElem.prototype.setUpperAndLowerElements = function(/*positionY*/) {
49
- };
50
-
51
- TripletElem.prototype.layout = function() {
52
- // 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.)
53
- if (this.anchor1 && this.anchor2) {
54
- this.hasBeam = !!this.anchor1.parent.beam && this.anchor1.parent.beam === this.anchor2.parent.beam;
55
-
56
- if (this.hasBeam) {
57
- // If there is a beam then we don't need to draw anything except the text. The beam could either be above or below.
58
- var beam = this.anchor1.parent.beam;
59
- var left = beam.isAbove() ? this.anchor1.x + this.anchor1.w : this.anchor1.x;
60
- this.yTextPos = beam.heightAtMidpoint(left, this.anchor2.x);
61
- this.yTextPos += beam.isAbove() ? 3 : -2; // This creates some space between the beam and the number.
62
- this.top = this.yTextPos + 1;
63
- this.bottom = this.yTextPos - 2;
64
- if (beam.isAbove())
65
- this.endingHeightAbove = 4;
66
- } else {
67
- // If there isn't a beam, then we need to draw the bracket and the text. The bracket is always above.
68
- // The bracket is never lower than the 'a' line, but is 4 pitches above the first and last notes. If there is
69
- // a tall note in the middle, the bracket is horizontal and above the highest note.
70
- this.startNote = Math.max(this.anchor1.parent.top, 9) + 4;
71
- this.endNote = Math.max(this.anchor2.parent.top, 9) + 4;
72
- // If it starts or ends on a rest, make the beam horizontal
73
- if (this.anchor1.parent.type === "rest" && this.anchor2.parent.type !== "rest")
74
- this.startNote = this.endNote;
75
- else if (this.anchor2.parent.type === "rest" && this.anchor1.parent.type !== "rest")
76
- this.endNote = this.startNote;
77
- // See if the middle note is really high.
78
- var max = 0;
79
- for (var i = 0; i < this.middleElems.length; i++) {
80
- max = Math.max(max, this.middleElems[i].top);
81
- }
82
- max += 4;
83
- if (max > this.startNote || max > this.endNote) {
84
- this.startNote = max;
85
- this.endNote = max;
86
- }
87
- if (this.flatBeams) {
88
- this.startNote = Math.max(this.startNote, this.endNote);
89
- this.endNote = Math.max(this.startNote, this.endNote);
90
- }
91
-
92
- this.yTextPos = this.startNote + (this.endNote - this.startNote) / 2;
93
- this.top = this.yTextPos + 1;
94
- }
95
- }
96
- delete this.middleElems;
97
- delete this.flatBeams;
98
- };
99
-
100
- TripletElem.prototype.draw = function(renderer) {
101
- var xTextPos;
102
- renderer.controller.currentAbsEl = { tuneNumber: renderer.controller.engraver.tuneNumber, elemset: [], abcelem: { el_type: "triplet", startChar: -1, endChar: -1 }};
103
- renderer.createElemSet({ klass: renderer.addClasses('triplet '+this.durationClass)});
104
- if (this.hasBeam) {
105
- var left = this.anchor1.parent.beam.isAbove() ? this.anchor1.x + this.anchor1.w : this.anchor1.x;
106
- xTextPos = this.anchor1.parent.beam.xAtMidpoint(left, this.anchor2.x);
107
- } else {
108
- xTextPos = this.anchor1.x + (this.anchor2.x + this.anchor2.w - this.anchor1.x) / 2;
109
- drawBracket(renderer, this.anchor1.x, this.startNote, this.anchor2.x + this.anchor2.w, this.endNote);
110
- }
111
- renderer.renderText({x: xTextPos, y: renderer.calcY(this.yTextPos), text: "" + this.number, type: 'tripletfont', anchor: "middle", centerVertically: true, history: 'ignore', noClass: true});
112
- var g = renderer.closeElemSet();
113
- renderer.controller.currentAbsEl.elemset.push(g);
114
- renderer.controller.recordHistory(g, true);
115
- };
116
-
117
- function drawLine(renderer, l, t, r, b) {
118
- return sprintf("M %f %f L %f %f", l, t, r, b);
119
- }
120
-
121
- function drawBracket(renderer, x1, y1, x2, y2) {
122
- y1 = renderer.calcY(y1);
123
- y2 = renderer.calcY(y2);
124
- var bracketHeight = 5;
125
-
126
- // Draw vertical lines at the beginning and end
127
- var pathString = "";
128
- pathString += drawLine(renderer, x1, y1, x1, y1 + bracketHeight);
129
- pathString += drawLine(renderer, x2, y2, x2, y2 + bracketHeight);
130
-
131
- // figure out midpoints to draw the broken line.
132
- var midX = x1 + (x2-x1)/2;
133
- //var midY = y1 + (y2-y1)/2;
134
- var gapWidth = 8;
135
- var slope = (y2 - y1) / (x2 - x1);
136
- var leftEndX = midX - gapWidth;
137
- var leftEndY = y1 + (leftEndX - x1) * slope;
138
- pathString += drawLine(renderer, x1, y1, leftEndX, leftEndY);
139
- var rightStartX = midX + gapWidth;
140
- var rightStartY = y1 + (rightStartX - x1) * slope;
141
- pathString += drawLine(renderer, rightStartX, rightStartY, x2, y2);
142
- renderer.printPath({path: pathString, stroke: "#000000"});
143
- }
144
- })();
145
-
146
28
  module.exports = TripletElem;
@@ -1,20 +1,4 @@
1
1
  // abc_voice_element.js: Definition of the VoiceElement class.
2
- // Copyright (C) 2010-2020 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
3
- //
4
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5
- // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
6
- // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
7
- // to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
- //
9
- // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
- //
11
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
12
- // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
14
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
-
17
- var parseCommon = require('../parse/abc_common');
18
2
 
19
3
  var VoiceElement = function VoiceElement(voicenumber, voicetotal) {
20
4
  this.children = [];
@@ -42,8 +26,9 @@ var VoiceElement = function VoiceElement(voicenumber, voicetotal) {
42
26
  };
43
27
  };
44
28
 
45
- VoiceElement.prototype.addChild = function (child) {
46
- if (child.type === 'bar') {
29
+ VoiceElement.prototype.addChild = function (absElem) {
30
+ // This is always passed an AbsoluteElement
31
+ if (absElem.type === 'bar') {
47
32
  var firstItem = true;
48
33
  for (var i = 0; firstItem && i < this.children.length; i++) {
49
34
  if (this.children[i].type.indexOf("staff-extra") < 0 && this.children[i].type !== "tempo")
@@ -54,8 +39,8 @@ VoiceElement.prototype.addChild = function (child) {
54
39
  this.otherchildren.push("bar");
55
40
  }
56
41
  }
57
- this.children[this.children.length] = child;
58
- this.setRange(child);
42
+ this.children[this.children.length] = absElem;
43
+ this.setRange(absElem);
59
44
  };
60
45
 
61
46
  VoiceElement.prototype.setLimit = function(member, child) {
@@ -71,29 +56,6 @@ VoiceElement.prototype.setLimit = function(member, child) {
71
56
  this.specialY[member] = Math.max(this.specialY[member], specialY[member]);
72
57
  };
73
58
 
74
- VoiceElement.prototype.moveDecorations = function(beam) {
75
- var padding = 1.5; // This is the vertical padding between elements, in pitches.
76
- for (var ch = 0; ch < beam.elems.length; ch++) {
77
- var child = beam.elems[ch];
78
- if (child.top) {
79
- // We now know where the ornaments should have been placed, so move them if they would overlap.
80
- var top = beam.yAtNote(child);
81
- for (var i = 0; i < child.children.length; i++) {
82
- var el = child.children[i];
83
- if (el.klass === 'ornament') {
84
- if (el.bottom - padding < top) {
85
- 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.
86
- el.bottom += distance;
87
- el.top += distance;
88
- el.pitch += distance;
89
- top = child.top = el.top;
90
- }
91
- }
92
- }
93
- }
94
- }
95
- };
96
-
97
59
  VoiceElement.prototype.adjustRange = function(child) {
98
60
  if (child.bottom !== undefined)
99
61
  this.bottom = Math.min(this.bottom, child.bottom);
@@ -116,19 +78,6 @@ VoiceElement.prototype.setRange = function(child) {
116
78
  this.setLimit('dynamicHeightBelow', child);
117
79
  };
118
80
 
119
- VoiceElement.prototype.setUpperAndLowerElements = function(positionY) {
120
- var i;
121
- for (i = 0; i < this.children.length; i++) {
122
- var abselem = this.children[i];
123
- abselem.setUpperAndLowerElements(positionY);
124
- }
125
- for (i = 0; i < this.otherchildren.length; i++) {
126
- var abselem = this.otherchildren[i];
127
- if (typeof abselem !== 'string')
128
- abselem.setUpperAndLowerElements(positionY);
129
- }
130
- };
131
-
132
81
  VoiceElement.prototype.addOther = function (child) {
133
82
  this.otherchildren.push(child);
134
83
  this.setRange(child);
@@ -138,172 +87,8 @@ VoiceElement.prototype.addBeam = function (child) {
138
87
  this.beams.push(child);
139
88
  };
140
89
 
141
- VoiceElement.prototype.updateIndices = function () {
142
- if (!this.layoutEnded()) {
143
- this.durationindex += this.children[this.i].duration;
144
- if (this.children[this.i].type === 'bar') this.durationindex = Math.round(this.durationindex*64)/64; // everytime we meet a barline, do rounding to nearest 64th
145
- this.i++;
146
- }
147
- };
148
-
149
- VoiceElement.prototype.layoutEnded = function () {
150
- return (this.i>=this.children.length);
151
- };
152
-
153
- VoiceElement.prototype.getDurationIndex = function () {
154
- return this.durationindex - (this.children[this.i] && (this.children[this.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
155
- };
156
-
157
- // number of spacing units expected for next positioning
158
- VoiceElement.prototype.getSpacingUnits = function () {
159
- return Math.sqrt(this.spacingduration*8);
160
- // TODO-PER: On short lines, this would never trigger, so the spacing was wrong. I just changed this line empirically, though, so I don't know if there are other ramifications.
161
- //return (this.minx<this.nextx) ? Math.sqrt(this.spacingduration*8) : 0; // we haven't used any spacing units if we end up using minx
162
- };
163
-
164
- //
165
- VoiceElement.prototype.getNextX = function () {
166
- return Math.max(this.minx, this.nextx);
167
- };
168
-
169
- VoiceElement.prototype.beginLayout = function (startx) {
170
- this.i=0;
171
- this.durationindex=0;
172
- //this.ii=this.children.length;
173
- this.startx=startx;
174
- this.minx=startx; // furthest left to where negatively positioned elements are allowed to go
175
- this.nextx=startx; // x position where the next element of this voice should be placed assuming no other voices and no fixed width constraints
176
- this.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)
177
- };
178
-
179
- // Try to layout the element at index this.i
180
- // x - position to try to layout the element at
181
- // spacing - base spacing
182
- // can't call this function more than once per iteration
183
- VoiceElement.prototype.layoutOneItem = function (x, spacing) {
184
- var child = this.children[this.i];
185
- if (!child) return 0;
186
- var er = x - this.minx; // available extrawidth to the left
187
- var extraWidth = child.getExtraWidth();
188
- if (er<extraWidth) { // shift right by needed amount
189
- // There's an exception if a bar element is after a Part element, there is no shift.
190
- if (this.i === 0 || child.type !== 'bar' || (this.children[this.i-1].type !== 'part' && this.children[this.i-1].type !== 'tempo') )
191
- x+=extraWidth-er;
192
- }
193
- child.setX(x);
194
-
195
- this.spacingduration = child.duration;
196
- //update minx
197
- this.minx = x+child.getMinWidth(); // add necessary layout space
198
- if (this.i!==this.children.length-1) this.minx+=child.minspacing; // add minimumspacing except on last elem
199
-
200
- this.updateNextX(x, spacing);
201
-
202
- // contribute to staff y position
203
- //this.staff.top = Math.max(child.top,this.staff.top);
204
- //this.staff.bottom = Math.min(child.bottom,this.staff.bottom);
205
-
206
- return x; // where we end up having placed the child
207
- };
208
-
209
- // call when spacingduration has been updated
210
- VoiceElement.prototype.updateNextX = function (x, spacing) {
211
- this.nextx= x + (spacing*Math.sqrt(this.spacingduration*8));
212
- };
213
-
214
- VoiceElement.prototype.shiftRight = function (dx) {
215
- var child = this.children[this.i];
216
- if (!child) return;
217
- child.setX(child.x+dx);
218
- this.minx+=dx;
219
- this.nextx+=dx;
220
- };
221
-
222
- function isNonSpacerRest(elem) {
223
- if (elem.type !== 'rest')
224
- return false;
225
- if (elem.abcelem && elem.abcelem.rest && elem.abcelem.rest.type !== 'spacer')
226
- return true;
227
- return false;
228
- }
229
- VoiceElement.prototype.draw = function (renderer, bartop) {
230
- var width = this.w-1;
231
- renderer.staffbottom = this.staff.bottom;
232
- //this.barbottom = renderer.calcY(2);
233
-
234
- renderer.measureNumber = null;
235
- renderer.noteNumber = null;
236
- if (this.header) { // print voice name
237
- var textpitch = 14 - (this.voicenumber+1)*(12/(this.voicetotal+1));
238
- var self = this;
239
- renderer.wrapInAbsElem({ el_type: "voice-name", startChar: -1, endChar: -1, text: this.header }, 'meta-bottom extra-text', function() {
240
- var textEl = renderer.renderText({x: renderer.padding.left, y: renderer.calcY(textpitch), text: self.header, type: 'voicefont', klass: 'staff-extra voice-name', anchor: 'start'});
241
- return textEl;
242
- });
243
- }
244
-
245
- for (var i=0, ii=this.children.length; i<ii; i++) {
246
- var child = this.children[i];
247
- var justInitializedMeasureNumber = false;
248
- if (child.type !== 'staff-extra' && renderer.measureNumber === null) {
249
- renderer.measureNumber = 0;
250
- renderer.noteNumber = 0;
251
- justInitializedMeasureNumber = true;
252
- }
253
- renderer.controller.currentAbsEl = child;
254
- child.draw(renderer, (this.barto || i===ii-1)?bartop:0);
255
- if (child.type === 'note' || isNonSpacerRest(child))
256
- renderer.noteNumber++;
257
- if (child.type === 'bar' && !justInitializedMeasureNumber) {
258
- renderer.measureNumber++;
259
- renderer.noteNumber = 0;
260
- }
261
- }
262
-
263
- renderer.measureNumber = 0;
264
- renderer.noteNumber = 0;
265
- parseCommon.each(this.beams, function(beam) {
266
- if (beam === 'bar') {
267
- renderer.measureNumber++;
268
- renderer.noteNumber = 0;
269
- } else
270
- beam.draw(renderer); // beams must be drawn first for proper printing of triplets, slurs and ties.
271
- });
272
-
273
- renderer.measureNumber = 0;
274
- renderer.noteNumber = 0;
275
- var self = this;
276
- parseCommon.each(this.otherchildren, function(child) {
277
- if (child === 'bar') {
278
- renderer.measureNumber++;
279
- renderer.noteNumber = 0;
280
- } else
281
- child.draw(renderer,self.startx+10,width);
282
- });
283
-
284
- };
285
-
286
- VoiceElement.prototype.layoutBeams = function() {
287
- for (var i = 0; i < this.beams.length; i++) {
288
- if (this.beams[i].layout) {
289
- this.beams[i].layout();
290
- this.moveDecorations(this.beams[i]);
291
- // The above will change the top and bottom of the abselem children, so see if we need to expand our range.
292
- for (var j = 0; j < this.beams[i].elems.length; j++) {
293
- this.adjustRange(this.beams[i].elems[j]);
294
- }
295
- }
296
- }
297
- // Now we can layout the triplets
298
- for (i = 0; i < this.otherchildren.length; i++) {
299
- var child = this.otherchildren[i];
300
- if (child.layout) {
301
- child.layout();
302
- this.adjustRange(child);
303
- }
304
- }
305
- this.staff.top = Math.max(this.staff.top, this.top);
306
- this.staff.bottom = Math.min(this.staff.bottom, this.bottom);
90
+ VoiceElement.prototype.setWidth = function (width) {
91
+ this.w = width;
307
92
  };
308
93
 
309
94
  module.exports = VoiceElement;
@@ -0,0 +1,103 @@
1
+ var RelativeElement = require('./abc_relative_element');
2
+ var spacing = require('./abc_spacing');
3
+ const formatJazzChord = require("./format-jazz-chord");
4
+
5
+ var addChord = function (getTextSize, abselem, elem, roomTaken, roomTakenRight, noteheadWidth, jazzchords) {
6
+ for (var i = 0; i < elem.chord.length; i++) {
7
+ var pos = elem.chord[i].position;
8
+ var rel_position = elem.chord[i].rel_position;
9
+ var chords = elem.chord[i].name.split("\n");
10
+ for (var j = chords.length-1; j >= 0; j--) { // parse these in opposite order because we place them from bottom to top.
11
+ var chord = chords[j];
12
+ var x = 0;
13
+ var y;
14
+ var font;
15
+ var klass;
16
+ if (pos === "left" || pos === "right" || pos === "below" || pos === "above" || !!rel_position) {
17
+ font = 'annotationfont';
18
+ klass = "annotation";
19
+ } else {
20
+ font = 'gchordfont';
21
+ klass = "chord";
22
+ if (jazzchords)
23
+ chord = formatJazzChord(chord);
24
+ }
25
+ var attr = getTextSize.attr(font, klass);
26
+ var dim = getTextSize.calc(chord, font, klass);
27
+ var chordWidth = dim.width;
28
+ var chordHeight = dim.height / spacing.STEP;
29
+ switch (pos) {
30
+ case "left":
31
+ roomTaken += chordWidth + 7;
32
+ x = -roomTaken; // TODO-PER: This is just a guess from trial and error
33
+ y = elem.averagepitch;
34
+ abselem.addExtra(new RelativeElement(chord, x, chordWidth + 4, y, {
35
+ type: "text",
36
+ height: chordHeight,
37
+ dim: attr,
38
+ position: "left"
39
+ }));
40
+ break;
41
+ case "right":
42
+ roomTakenRight += 4;
43
+ x = roomTakenRight;// TODO-PER: This is just a guess from trial and error
44
+ y = elem.averagepitch;
45
+ abselem.addRight(new RelativeElement(chord, x, chordWidth + 4, y, {
46
+ type: "text",
47
+ height: chordHeight,
48
+ dim: attr,
49
+ position: "right"
50
+ }));
51
+ break;
52
+ case "below":
53
+ // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
54
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
55
+ type: "text",
56
+ position: "below",
57
+ height: chordHeight,
58
+ dim: attr,
59
+ realWidth: chordWidth
60
+ }));
61
+ break;
62
+ case "above":
63
+ // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
64
+ abselem.addRight(new RelativeElement(chord, 0, 0, undefined, {
65
+ type: "text",
66
+ position: "above",
67
+ height: chordHeight,
68
+ dim: attr,
69
+ realWidth: chordWidth
70
+ }));
71
+ break;
72
+ default:
73
+ if (rel_position) {
74
+ var relPositionY = rel_position.y + 3 * spacing.STEP; // TODO-PER: this is a fudge factor to make it line up with abcm2ps
75
+ abselem.addRight(new RelativeElement(chord, x + rel_position.x, 0, elem.minpitch + relPositionY / spacing.STEP, {
76
+ position: "relative",
77
+ type: "text",
78
+ height: chordHeight,
79
+ dim: attr
80
+ }));
81
+ } else {
82
+ // setting the y-coordinate to undefined for now: it will be overwritten later on, after we figure out what the highest element on the line is.
83
+ var pos2 = 'above';
84
+ if (elem.positioning && elem.positioning.chordPosition)
85
+ pos2 = elem.positioning.chordPosition;
86
+
87
+ if (pos2 !== 'hidden') {
88
+ abselem.addCentered(new RelativeElement(chord, noteheadWidth/2, chordWidth, undefined, {
89
+ type: "chord",
90
+ position: pos2,
91
+ height: chordHeight,
92
+ dim: attr,
93
+ realWidth: chordWidth
94
+ }));
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ return {roomTaken: roomTaken, roomTakenRight: roomTakenRight};
101
+ };
102
+
103
+ module.exports = addChord;
@@ -0,0 +1,33 @@
1
+ function addTextIf(rows, params, getTextSize) {
2
+ if (!params.text)
3
+ return;
4
+ if (!params.marginLeft) params.marginLeft = 0;
5
+ if (!params.klass) params.klass = '';
6
+ if (!params.anchor) params.anchor = 'start';
7
+ if (!params.info) params.info = { startChar: -2, endChar: -2}
8
+
9
+ if (params.marginTop)
10
+ rows.push({move: params.marginTop});
11
+ var attr = {left: params.marginLeft, text: params.text, font: params.font, anchor: params.anchor, startChar: params.info.startChar, endChar: params.info.endChar};
12
+ if (params.absElemType)
13
+ attr.absElemType = params.absElemType;
14
+ if (!params.inGroup)
15
+ attr.klass = params.klass;
16
+ if (params.name)
17
+ attr.name = params.name;
18
+
19
+ rows.push(attr);
20
+ // If there are blank lines they won't be counted by getTextSize, so just get the height of one line and multiply
21
+ var size = getTextSize.calc("A", params.font, params.klass);
22
+ var numLines = params.text.split("\n").length;
23
+ if (params.text[params.text.length-1] === '\n')
24
+ numLines--; // If there is a new line at the end of the string, then an extra line will be counted.
25
+ if (!params.noMove) {
26
+ var h = (size.height * 1.1) * numLines;
27
+ rows.push({move: Math.round(h)});
28
+ if (params.marginBottom)
29
+ rows.push({move: params.marginBottom});
30
+ }
31
+ }
32
+
33
+ module.exports = addTextIf;
@@ -0,0 +1,79 @@
1
+ const addTextIf = require("./add-text-if");
2
+
3
+ function BottomText(metaText, width, isPrint, paddingLeft, spacing, getTextSize) {
4
+ this.rows = [];
5
+ if (metaText.unalignedWords && metaText.unalignedWords.length > 0)
6
+ this.unalignedWords(metaText.unalignedWords, paddingLeft, spacing, getTextSize);
7
+ this.extraText(metaText, paddingLeft, spacing, getTextSize);
8
+ if (metaText.footer && isPrint)
9
+ this.footer(metaText.footer, width, paddingLeft, getTextSize);
10
+ }
11
+
12
+ BottomText.prototype.unalignedWords = function (unalignedWords, paddingLeft, spacing, getTextSize) {
13
+ var indent = 50;
14
+ var klass = 'meta-bottom unaligned-words';
15
+ var defFont = 'wordsfont';
16
+ this.rows.push({startGroup: "unalignedWords", klass: 'abcjs-meta-bottom abcjs-unaligned-words', name: "words"});
17
+ var space = getTextSize.calc("i", defFont, klass);
18
+
19
+ this.rows.push({move: spacing.words});
20
+
21
+ for (var j = 0; j < unalignedWords.length; j++) {
22
+ if (unalignedWords[j] === '')
23
+ this.rows.push({move: space.height});
24
+ else if (typeof unalignedWords[j] === 'string') {
25
+ addTextIf(this.rows, { marginLeft: paddingLeft + indent, text: unalignedWords[j], font: defFont, klass: klass, inGroup: true, name: "words"}, getTextSize);
26
+ } else {
27
+ var largestY = 0;
28
+ var offsetX = 0;
29
+ for (var k = 0; k < unalignedWords[j].length; k++) {
30
+ var thisWord = unalignedWords[j][k];
31
+ var font = (thisWord.font) ? thisWord.font : defFont;
32
+ this.rows.push({
33
+ left: paddingLeft + indent + offsetX,
34
+ text: thisWord.text,
35
+ font: font,
36
+ anchor: 'start'
37
+ });
38
+ var size = getTextSize.calc(thisWord.text, defFont, klass);
39
+ largestY = Math.max(largestY, size.height);
40
+ offsetX += size.width;
41
+ // If the phrase ends in a space, then that is not counted in the width, so we need to add that in ourselves.
42
+ if (thisWord.text[thisWord.text.length - 1] === ' ') {
43
+ offsetX += space.width;
44
+ }
45
+ }
46
+ this.rows.push({move: largestY});
47
+ }
48
+ }
49
+ this.rows.push({move: space.height * 2});
50
+ this.rows.push({endGroup: "unalignedWords", absElemType: "unalignedWords", startChar: -1, endChar: -1, name: "unalignedWords"});
51
+ }
52
+
53
+ BottomText.prototype.extraText = function (metaText, marginLeft, spacing, getTextSize) {
54
+ var extraText = "";
55
+ if (metaText.book) extraText += "Book: " + metaText.book + "\n";
56
+ if (metaText.source) extraText += "Source: " + metaText.source + "\n";
57
+ if (metaText.discography) extraText += "Discography: " + metaText.discography + "\n";
58
+ if (metaText.notes) extraText += "Notes: " + metaText.notes + "\n";
59
+ if (metaText.transcription) extraText += "Transcription: " + metaText.transcription + "\n";
60
+ if (metaText.history) extraText += "History: " + metaText.history + "\n";
61
+ if (metaText['abc-copyright']) extraText += "Copyright: " + metaText['abc-copyright'] + "\n";
62
+ if (metaText['abc-creator']) extraText += "Creator: " + metaText['abc-creator'] + "\n";
63
+ if (metaText['abc-edited-by']) extraText += "Edited By: " + metaText['abc-edited-by'] + "\n";
64
+ if (extraText.length > 0) {
65
+ addTextIf(this.rows, { marginLeft: marginLeft, text: extraText, font: 'historyfont', klass: 'meta-bottom extra-text', marginTop: spacing.info, absElemType: "extraText", name: "description"}, getTextSize);
66
+ }
67
+ }
68
+
69
+ BottomText.prototype.footer = function (footer, width, paddingLeft, getTextSize) {
70
+ var klass = 'header meta-bottom';
71
+ var font = "footerfont";
72
+ this.rows.push({startGroup: "footer", klass: klass});
73
+ // Note: whether there is a footer or not doesn't change any other positioning, so this doesn't change the Y-coordinate.
74
+ addTextIf(this.rows, { marginLeft: paddingLeft, text: footer.left, font: font, klass: klass, name: "footer"}, getTextSize);
75
+ addTextIf(this.rows, { marginLeft: paddingLeft + width / 2, text: footer.center, font: font, klass: klass, anchor: 'middle', name: "footer"} , getTextSize);
76
+ addTextIf(this.rows, { marginLeft: paddingLeft + width, text: footer.right, font: font, klass: klass, anchor: 'end', name: "footer"}, getTextSize);
77
+ }
78
+
79
+ module.exports = BottomText;
@@ -0,0 +1,17 @@
1
+ var calcHeight = function (staffGroup) {
2
+ // the height is calculated here in a parallel way to the drawing below in hopes that both of these functions will be modified together.
3
+ // TODO-PER: also add the space between staves. (That's systemStaffSeparation, which is the minimum distance between the staff LINES.)
4
+ var height = 0;
5
+ for (var i=0;i<staffGroup.voices.length;i++) {
6
+ var staff = staffGroup.voices[i].staff;
7
+ if (!staffGroup.voices[i].duplicate) {
8
+ height += staff.top;
9
+ //if (staff.bottom < 0)
10
+ height += -staff.bottom;
11
+ }
12
+ }
13
+ return height;
14
+ };
15
+
16
+ module.exports = calcHeight;
17
+