abcjs 6.1.8 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/RELEASE.md +66 -0
  2. package/dist/abcjs-basic-min.js +2 -2
  3. package/dist/abcjs-basic.js +4373 -4424
  4. package/dist/abcjs-basic.js.map +1 -1
  5. package/dist/abcjs-plugin-min.js +2 -2
  6. package/index.js +1 -1
  7. package/package.json +6 -6
  8. package/plugin.js +1 -1
  9. package/src/api/abc_timing_callbacks.js +7 -3
  10. package/src/api/abc_tunebook_svg.js +1 -2
  11. package/src/data/abc_tune.js +2 -2
  12. package/src/midi/abc_midi_create.js +8 -2
  13. package/src/parse/abc_common.js +0 -47
  14. package/src/parse/abc_parse.js +16 -16
  15. package/src/parse/abc_parse_book.js +3 -3
  16. package/src/parse/abc_parse_directive.js +26 -7
  17. package/src/parse/abc_parse_header.js +11 -9
  18. package/src/parse/abc_parse_key_voice.js +17 -17
  19. package/src/parse/abc_parse_music.js +89 -106
  20. package/src/parse/abc_tokenizer.js +60 -60
  21. package/src/parse/abc_transpose.js +14 -3
  22. package/src/parse/tune-builder.js +19 -14
  23. package/src/synth/abc_midi_flattener.js +25 -9
  24. package/src/synth/abc_midi_sequencer.js +1 -1
  25. package/src/synth/create-synth.js +41 -0
  26. package/src/synth/note-to-midi.js +50 -0
  27. package/src/tablatures/instruments/guitar/tab-guitar.js +0 -2
  28. package/src/tablatures/instruments/string-patterns.js +46 -28
  29. package/src/tablatures/instruments/tab-note.js +26 -103
  30. package/src/tablatures/instruments/violin/tab-violin.js +0 -2
  31. package/src/tablatures/tab-absolute-elements.js +9 -31
  32. package/src/tablatures/tab-renderer.js +2 -2
  33. package/src/test/abc_parser_lint.js +8 -5
  34. package/src/write/README.md +31 -0
  35. package/src/write/creation/abstract-engraver.js +1036 -0
  36. package/src/write/creation/add-chord.js +102 -0
  37. package/src/write/{add-text-if.js → creation/add-text-if.js} +6 -6
  38. package/src/write/{calcHeight.js → creation/calc-height.js} +2 -2
  39. package/src/write/creation/create-clef.js +72 -0
  40. package/src/write/creation/create-key-signature.js +31 -0
  41. package/src/write/creation/create-note-head.js +107 -0
  42. package/src/write/creation/create-time-signature.js +55 -0
  43. package/src/write/creation/decoration.js +357 -0
  44. package/src/write/{abc_absolute_element.js → creation/elements/absolute-element.js} +14 -15
  45. package/src/write/creation/elements/beam-element.js +113 -0
  46. package/src/write/{bottom-text.js → creation/elements/bottom-text.js} +14 -15
  47. package/src/write/{abc_brace_element.js → creation/elements/brace-element.js} +5 -5
  48. package/src/write/creation/elements/free-text.js +41 -0
  49. package/src/write/{abc_relative_element.js → creation/elements/relative-element.js} +8 -7
  50. package/src/write/{separator.js → creation/elements/separator.js} +2 -2
  51. package/src/write/{abc_staff_group_element.js → creation/elements/staff-group-element.js} +4 -4
  52. package/src/write/{subtitle.js → creation/elements/subtitle.js} +3 -3
  53. package/src/write/creation/elements/tempo-element.js +63 -0
  54. package/src/write/{abc_tie_element.js → creation/elements/tie-element.js} +15 -11
  55. package/src/write/{top-text.js → creation/elements/top-text.js} +12 -12
  56. package/src/write/creation/elements/triplet-element.js +28 -0
  57. package/src/write/{abc_voice_element.js → creation/elements/voice-element.js} +3 -3
  58. package/src/write/creation/glyphs.js +226 -0
  59. package/src/write/creation/translate-chord.js +37 -0
  60. package/src/write/draw/absolute.js +5 -5
  61. package/src/write/draw/beam.js +8 -8
  62. package/src/write/draw/brace.js +33 -33
  63. package/src/write/draw/crescendo.js +4 -4
  64. package/src/write/draw/debug-box.js +1 -1
  65. package/src/write/draw/draw.js +7 -7
  66. package/src/write/draw/dynamics.js +2 -2
  67. package/src/write/draw/ending.js +6 -6
  68. package/src/write/draw/glissando.js +17 -17
  69. package/src/write/draw/group-elements.js +51 -51
  70. package/src/write/draw/horizontal-line.js +9 -9
  71. package/src/write/draw/non-music.js +1 -1
  72. package/src/write/draw/print-line.js +15 -16
  73. package/src/write/draw/print-stem.js +5 -5
  74. package/src/write/draw/print-symbol.js +12 -12
  75. package/src/write/draw/print-vertical-line.js +8 -8
  76. package/src/write/draw/relative.js +17 -16
  77. package/src/write/draw/selectables.js +5 -5
  78. package/src/write/draw/separator.js +4 -4
  79. package/src/write/draw/set-paper-size.js +2 -2
  80. package/src/write/draw/sprintf.js +31 -31
  81. package/src/write/draw/staff-group.js +36 -30
  82. package/src/write/draw/staff-line.js +2 -2
  83. package/src/write/draw/staff.js +4 -4
  84. package/src/write/draw/tab-line.js +26 -26
  85. package/src/write/draw/tempo.js +30 -30
  86. package/src/write/draw/text.js +5 -5
  87. package/src/write/draw/tie.js +18 -18
  88. package/src/write/draw/triplet.js +6 -6
  89. package/src/write/draw/voice.js +16 -17
  90. package/src/write/{abc_engraver_controller.js → engraver-controller.js} +58 -51
  91. package/src/write/{classes.js → helpers/classes.js} +6 -6
  92. package/src/write/{get-font-and-attr.js → helpers/get-font-and-attr.js} +9 -7
  93. package/src/write/{get-text-size.js → helpers/get-text-size.js} +5 -5
  94. package/src/write/{set-class.js → helpers/set-class.js} +1 -1
  95. package/src/write/{abc_spacing.js → helpers/spacing.js} +1 -1
  96. package/src/write/{highlight.js → interactive/highlight.js} +1 -1
  97. package/src/write/{selection.js → interactive/selection.js} +27 -27
  98. package/src/write/{unhighlight.js → interactive/unhighlight.js} +1 -1
  99. package/src/write/layout/beam.js +13 -13
  100. package/src/write/layout/get-left-edge-of-staff.js +4 -4
  101. package/src/write/layout/layout.js +74 -74
  102. package/src/write/layout/{setUpperAndLowerElements.js → set-upper-and-lower-elements.js} +8 -8
  103. package/src/write/layout/{staffGroup.js → staff-group.js} +32 -32
  104. package/src/write/layout/triplet.js +4 -4
  105. package/src/write/layout/{VoiceElements.js → voice-elements.js} +23 -23
  106. package/src/write/layout/voice.js +6 -6
  107. package/src/write/{abc_renderer.js → renderer.js} +35 -32
  108. package/src/write/svg.js +35 -35
  109. package/test.js +1 -1
  110. package/types/index.d.ts +99 -22
  111. package/version.js +1 -1
  112. package/src/tablatures/instruments/guitar/guitar-fonts.js +0 -19
  113. package/src/tablatures/instruments/violin/violin-fonts.js +0 -19
  114. package/src/tablatures/transposer.js +0 -110
  115. package/src/write/abc_abstract_engraver.js +0 -1026
  116. package/src/write/abc_beam_element.js +0 -113
  117. package/src/write/abc_create_clef.js +0 -72
  118. package/src/write/abc_create_key_signature.js +0 -33
  119. package/src/write/abc_create_note_head.js +0 -107
  120. package/src/write/abc_create_time_signature.js +0 -55
  121. package/src/write/abc_decoration.js +0 -341
  122. package/src/write/abc_glyphs.js +0 -224
  123. package/src/write/abc_tempo_element.js +0 -63
  124. package/src/write/abc_triplet_element.js +0 -28
  125. package/src/write/add-chord.js +0 -103
  126. package/src/write/format-jazz-chord.js +0 -15
  127. package/src/write/free-text.js +0 -41
  128. /package/src/write/{abc_crescendo_element.js → creation/elements/crescendo-element.js} +0 -0
  129. /package/src/write/{abc_dynamic_decoration.js → creation/elements/dynamic-decoration.js} +0 -0
  130. /package/src/write/{abc_ending_element.js → creation/elements/ending-element.js} +0 -0
  131. /package/src/write/{abc_glissando_element.js → creation/elements/glissando-element.js} +0 -0
  132. /package/src/write/layout/{getBarYAt.js → get-bar-y-at.js} +0 -0
@@ -1,4 +1,4 @@
1
- var spacing = require('./abc_spacing');
1
+ var spacing = require('../helpers/spacing');
2
2
 
3
3
  function setupSelection(engraver, svgs) {
4
4
  engraver.rangeHighlight = rangeHighlight;
@@ -15,9 +15,9 @@ function setupSelection(engraver, svgs) {
15
15
  }
16
16
  }
17
17
  for (var i = 0; i < svgs.length; i++) {
18
- svgs[i].addEventListener('touchstart', mouseDown.bind(engraver));
19
- svgs[i].addEventListener('touchmove', mouseMove.bind(engraver));
20
- svgs[i].addEventListener('touchend', mouseUp.bind(engraver));
18
+ svgs[i].addEventListener('touchstart', mouseDown.bind(engraver), { passive: true });
19
+ svgs[i].addEventListener('touchmove', mouseMove.bind(engraver), { passive: true });
20
+ svgs[i].addEventListener('touchend', mouseUp.bind(engraver), { passive: true });
21
21
  svgs[i].addEventListener('mousedown', mouseDown.bind(engraver));
22
22
  svgs[i].addEventListener('mousemove', mouseMove.bind(engraver));
23
23
  svgs[i].addEventListener('mouseup', mouseUp.bind(engraver));
@@ -56,7 +56,7 @@ function getCoord(ev) {
56
56
  y = y * scaleY;
57
57
  //console.log(x, y)
58
58
 
59
- return [x, y+yOffset];
59
+ return [x, y + yOffset];
60
60
  }
61
61
 
62
62
  function elementFocused(ev) {
@@ -69,7 +69,7 @@ function elementFocused(ev) {
69
69
 
70
70
  function keyboardDown(ev) {
71
71
  // Swallow the up and down arrow events - they will be used for dragging with the keyboard
72
- switch(ev.keyCode) {
72
+ switch (ev.keyCode) {
73
73
  case 38:
74
74
  case 40:
75
75
  ev.preventDefault();
@@ -80,7 +80,7 @@ function keyboardSelection(ev) {
80
80
  // "this" is the EngraverController because of the bind(this) when setting the event listener.
81
81
  var handled = false;
82
82
  var index = ev.target.dataset.index;
83
- switch(ev.keyCode) {
83
+ switch (ev.keyCode) {
84
84
  case 13:
85
85
  case 32:
86
86
  handled = true;
@@ -163,7 +163,7 @@ function findElementByCoord(self, x, y) {
163
163
  // figure out the distance to this element.
164
164
  var dx = Math.abs(x - el.dim.left) > Math.abs(x - el.dim.right) ? Math.abs(x - el.dim.right) : Math.abs(x - el.dim.left);
165
165
  var dy = Math.abs(y - el.dim.top) > Math.abs(y - el.dim.bottom) ? Math.abs(y - el.dim.bottom) : Math.abs(y - el.dim.top);
166
- var hypotenuse = Math.sqrt(dx*dx + dy*dy);
166
+ var hypotenuse = Math.sqrt(dx * dx + dy * dy);
167
167
  if (hypotenuse < minDistance) {
168
168
  minDistance = hypotenuse;
169
169
  closestIndex = i;
@@ -177,20 +177,20 @@ function getBestMatchCoordinates(dim, ev, scale) {
177
177
  // Different browsers have conflicting meanings for the coordinates that are returned.
178
178
  // If the item we want is clicked on directly, then we will just see what is the best match.
179
179
  // This seems like less of a hack than browser sniffing.
180
- if (dim.x <= ev.offsetX && dim.x+dim.width >= ev.offsetX &&
181
- dim.y <= ev.offsetY && dim.y+dim.height >= ev.offsetY)
182
- return [ ev.offsetX, ev.offsetY];
180
+ if (dim.x <= ev.offsetX && dim.x + dim.width >= ev.offsetX &&
181
+ dim.y <= ev.offsetY && dim.y + dim.height >= ev.offsetY)
182
+ return [ev.offsetX, ev.offsetY];
183
183
  // Firefox returns a weird value for offset, but layer is correct.
184
184
  // Safari and Chrome return the correct value for offset, but layer is multiplied by the scale (that is, if it were rendered with { scale: 2 })
185
185
  // For instance (if scale is 2):
186
186
  // Firefox: { offsetY: 5, layerY: 335 }
187
187
  // Others: {offsetY: 335, layerY: 670} (there could be a little rounding, so the number might not be exactly 2x)
188
188
  // So, if layerY/scale is approx. offsetY, then use offsetY, otherwise use layerY
189
- var epsilon = Math.abs(ev.layerY/scale - ev.offsetY);
189
+ var epsilon = Math.abs(ev.layerY / scale - ev.offsetY);
190
190
  if (epsilon < 3)
191
- return [ ev.offsetX, ev.offsetY];
191
+ return [ev.offsetX, ev.offsetY];
192
192
  else
193
- return [ ev.layerX, ev.layerY];
193
+ return [ev.layerX, ev.layerY];
194
194
  }
195
195
 
196
196
  function getTarget(target) {
@@ -202,7 +202,7 @@ function getTarget(target) {
202
202
  while (!found) {
203
203
  if (!target.parentElement)
204
204
  found = true;
205
- else {
205
+ else {
206
206
  target = target.parentElement;
207
207
  if (target.tagName === "svg")
208
208
  found = true;
@@ -290,7 +290,7 @@ function mouseMove(ev) {
290
290
 
291
291
  var positioning = getMousePosition(this, _ev);
292
292
 
293
- var yDist = Math.round((positioning.y - this.dragMouseStart.y)/spacing.STEP);
293
+ var yDist = Math.round((positioning.y - this.dragMouseStart.y) / spacing.STEP);
294
294
  if (yDist !== this.dragYStep) {
295
295
  this.dragYStep = yDist;
296
296
  this.dragTarget.svgEl.setAttribute("transform", "translate(0," + (yDist * spacing.STEP) + ")");
@@ -329,7 +329,7 @@ function setSelection(dragIndex) {
329
329
  this.dragTarget = this.selectables[dragIndex];
330
330
  this.dragIndex = dragIndex;
331
331
  this.dragMechanism = "keyboard";
332
- mouseUp.bind(this)({target: this.dragTarget.svgEl});
332
+ mouseUp.bind(this)({ target: this.dragTarget.svgEl });
333
333
  }
334
334
  }
335
335
 
@@ -368,8 +368,8 @@ function notifySelect(target, dragStep, dragMax, dragIndex, ev) {
368
368
  analysis.clickedClasses = closest.classList;
369
369
  analysis.selectableElement = target.svgEl;
370
370
 
371
- for (var i=0; i<this.listeners.length;i++) {
372
- this.listeners[i](target.absEl.abcelem, target.absEl.tuneNumber, classes.join(' '), analysis, { step: dragStep, max: dragMax, index: dragIndex, setSelection: setSelection.bind(this)}, ev);
371
+ for (var i = 0; i < this.listeners.length; i++) {
372
+ this.listeners[i](target.absEl.abcelem, target.absEl.tuneNumber, classes.join(' '), analysis, { step: dragStep, max: dragMax, index: dragIndex, setSelection: setSelection.bind(this) }, ev);
373
373
  }
374
374
  }
375
375
 
@@ -377,32 +377,32 @@ function findNumber(klass, match, target, name) {
377
377
  if (klass.indexOf(match) === 0) {
378
378
  var value = klass.replace(match, '');
379
379
  var num = parseInt(value, 10);
380
- if (''+num === value)
380
+ if ('' + num === value)
381
381
  target[name] = num;
382
382
  }
383
383
  }
384
384
 
385
385
  function clearSelection() {
386
- for (var i=0;i<this.selected.length;i++) {
386
+ for (var i = 0; i < this.selected.length; i++) {
387
387
  this.selected[i].unhighlight(undefined, this.renderer.foregroundColor);
388
388
  }
389
389
  this.selected = [];
390
390
  }
391
391
 
392
- function rangeHighlight(start,end) {
392
+ function rangeHighlight(start, end) {
393
393
  clearSelection.bind(this)();
394
- for (var line=0;line<this.staffgroups.length; line++) {
394
+ for (var line = 0; line < this.staffgroups.length; line++) {
395
395
  var voices = this.staffgroups[line].voices;
396
- for (var voice=0;voice<voices.length;voice++) {
396
+ for (var voice = 0; voice < voices.length; voice++) {
397
397
  var elems = voices[voice].children;
398
- for (var elem=0; elem<elems.length; elem++) {
398
+ for (var elem = 0; elem < elems.length; elem++) {
399
399
  // Since the user can highlight more than an element, or part of an element, a hit is if any of the endpoints
400
400
  // is inside the other range.
401
401
  var elStart = elems[elem].abcelem.startChar;
402
402
  var elEnd = elems[elem].abcelem.endChar;
403
- if ((end>elStart && start<elEnd) || ((end===start) && end===elEnd)) {
403
+ if ((end > elStart && start < elEnd) || ((end === start) && end === elEnd)) {
404
404
  // if (elems[elem].abcelem.startChar>=start && elems[elem].abcelem.endChar<=end) {
405
- this.selected[this.selected.length]=elems[elem];
405
+ this.selected[this.selected.length] = elems[elem];
406
406
  elems[elem].highlight(undefined, this.selectionColor);
407
407
  }
408
408
  }
@@ -1,4 +1,4 @@
1
- var setClass = require('./set-class');
1
+ var setClass = require('../helpers/set-class');
2
2
 
3
3
  var unhighlight = function (klass, color) {
4
4
  if (klass === undefined)
@@ -1,8 +1,8 @@
1
- var RelativeElement = require('../abc_relative_element');
2
- var spacing = require('../abc_spacing');
3
- var getBarYAt = require('./getBarYAt');
1
+ var RelativeElement = require('../creation/elements/relative-element');
2
+ var spacing = require('../helpers/spacing');
3
+ var getBarYAt = require('./get-bar-y-at');
4
4
 
5
- var layoutBeam = function(beam) {
5
+ var layoutBeam = function (beam) {
6
6
  if (beam.elems.length === 0 || beam.allrests) return;
7
7
 
8
8
  var dy = calcDy(beam.stemsUp, beam.isgrace); // This is the width of the beam line.
@@ -28,14 +28,14 @@ var layoutBeam = function(beam) {
28
28
  createStems(beam.elems, beam.stemsUp, beam.beams[0], dy, beam.mainNote);
29
29
  };
30
30
 
31
- var getDurlog = function(duration) {
31
+ var getDurlog = function (duration) {
32
32
  // TODO-PER: This is a hack to prevent a Chrome lockup. Duration should have been defined already,
33
33
  // but there's definitely a case where it isn't. [Probably something to do with triplets.]
34
34
  if (duration === undefined) {
35
35
  return 0;
36
36
  }
37
37
  // console.log("getDurlog: " + duration);
38
- return Math.floor(Math.log(duration)/Math.log(2));
38
+ return Math.floor(Math.log(duration) / Math.log(2));
39
39
  };
40
40
 
41
41
  //
@@ -78,7 +78,7 @@ function calcXPos(asc, firstElement, lastElement) {
78
78
  if (asc) startX += starthead.w - 0.6;
79
79
  var endX = endhead.x;
80
80
  endX += (asc) ? endhead.w : 0.6;
81
- return [ startX, endX ];
81
+ return [startX, endX];
82
82
  }
83
83
 
84
84
  function calcYPos(average, numElements, stemHeight, asc, firstAveragePitch, lastAveragePitch, isFlat, minPitch, maxPitch, isGrace) {
@@ -101,7 +101,7 @@ function calcYPos(average, numElements, stemHeight, asc, firstAveragePitch, last
101
101
  }
102
102
  }
103
103
 
104
- return [ startY, endY];
104
+ return [startY, endY];
105
105
  }
106
106
 
107
107
  function createStems(elems, asc, beam, dy, mainNote) {
@@ -168,11 +168,11 @@ function createAdditionalBeams(elems, asc, beam, isGrace, dy) {
168
168
  durlog: durlog, single: true
169
169
  };
170
170
  }
171
- if (i > 0 && elem.abcelem.beambr && elem.abcelem.beambr <= (index+1)) {
171
+ if (i > 0 && elem.abcelem.beambr && elem.abcelem.beambr <= (index + 1)) {
172
172
  if (!auxBeams[index].split)
173
173
  auxBeams[index].split = [auxBeams[index].x];
174
- var xPos = calcXPos(asc, elems[i-1], elem);
175
- if (auxBeams[index].split[auxBeams[index].split.length-1] >= xPos[0]) {
174
+ var xPos = calcXPos(asc, elems[i - 1], elem);
175
+ if (auxBeams[index].split[auxBeams[index].split.length - 1] >= xPos[0]) {
176
176
  // the reduction in beams leaves a note unattached so create a small flag for it.
177
177
  xPos[0] += elem.w;
178
178
  }
@@ -195,9 +195,9 @@ function createAdditionalBeams(elems, asc, beam, isGrace, dy) {
195
195
  var b = { startX: auxBeams[j].x, endX: auxBeamEndX, startY: auxBeams[j].y, endY: auxBeamEndY, dy: dy }
196
196
  if (auxBeams[j].split !== undefined) {
197
197
  var split = auxBeams[j].split;
198
- if (b.endX <= split[split.length-1]) {
198
+ if (b.endX <= split[split.length - 1]) {
199
199
  // the reduction in beams leaves the last note by itself, so create a little flag for it
200
- split[split.length-1] -= elem.w;
200
+ split[split.length - 1] -= elem.w;
201
201
  }
202
202
  split.push(b.endX);
203
203
  b.split = auxBeams[j].split;
@@ -5,10 +5,10 @@ function getLeftEdgeOfStaff(renderer, getTextSize, voices, brace, bracket) {
5
5
  var voiceheaderw = 0;
6
6
  var i;
7
7
  var size;
8
- for (i=0;i<voices.length;i++) {
9
- if(voices[i].header) {
8
+ for (i = 0; i < voices.length; i++) {
9
+ if (voices[i].header) {
10
10
  size = getTextSize.calc(voices[i].header, 'voicefont', '');
11
- voiceheaderw = Math.max(voiceheaderw,size.width);
11
+ voiceheaderw = Math.max(voiceheaderw, size.width);
12
12
  }
13
13
  }
14
14
  voiceheaderw = addBraceSize(voiceheaderw, brace, getTextSize);
@@ -32,7 +32,7 @@ function addBraceSize(voiceheaderw, brace, getTextSize) {
32
32
  for (var i = 0; i < brace.length; i++) {
33
33
  if (brace[i].header) {
34
34
  var size = getTextSize.calc(brace[i].header, 'voicefont', '');
35
- voiceheaderw = Math.max(voiceheaderw,size.width);
35
+ voiceheaderw = Math.max(voiceheaderw, size.width);
36
36
  }
37
37
  }
38
38
  }
@@ -1,94 +1,94 @@
1
1
  var layoutVoice = require('./voice');
2
- var setUpperAndLowerElements = require('./setUpperAndLowerElements');
3
- var layoutStaffGroup = require('./staffGroup');
2
+ var setUpperAndLowerElements = require('./set-upper-and-lower-elements');
3
+ var layoutStaffGroup = require('./staff-group');
4
4
  var getLeftEdgeOfStaff = require('./get-left-edge-of-staff');
5
5
 
6
6
  var layout = function (renderer, abctune, width, space) {
7
- var i;
8
- var abcLine;
9
- // Adjust the x-coordinates to their absolute positions
10
- var maxWidth = width;
11
- for(i=0; i<abctune.lines.length; i++) {
12
- abcLine = abctune.lines[i];
13
- if (abcLine.staff) {
14
- setXSpacing(renderer, width, space, abcLine.staffGroup, abctune.formatting, i === abctune.lines.length - 1, false);
15
- if (abcLine.staffGroup.w > maxWidth) maxWidth = abcLine.staffGroup.w;
16
- }
7
+ var i;
8
+ var abcLine;
9
+ // Adjust the x-coordinates to their absolute positions
10
+ var maxWidth = width;
11
+ for (i = 0; i < abctune.lines.length; i++) {
12
+ abcLine = abctune.lines[i];
13
+ if (abcLine.staff) {
14
+ setXSpacing(renderer, width, space, abcLine.staffGroup, abctune.formatting, i === abctune.lines.length - 1, false);
15
+ if (abcLine.staffGroup.w > maxWidth) maxWidth = abcLine.staffGroup.w;
17
16
  }
17
+ }
18
18
 
19
- // Layout the beams and add the stems to the beamed notes.
20
- for(i=0; i<abctune.lines.length; i++) {
21
- abcLine = abctune.lines[i];
22
- if (abcLine.staffGroup && abcLine.staffGroup.voices) {
23
- for (var j = 0; j < abcLine.staffGroup.voices.length; j++)
24
- layoutVoice(abcLine.staffGroup.voices[j]);
25
- setUpperAndLowerElements(renderer, abcLine.staffGroup);
26
- }
19
+ // Layout the beams and add the stems to the beamed notes.
20
+ for (i = 0; i < abctune.lines.length; i++) {
21
+ abcLine = abctune.lines[i];
22
+ if (abcLine.staffGroup && abcLine.staffGroup.voices) {
23
+ for (var j = 0; j < abcLine.staffGroup.voices.length; j++)
24
+ layoutVoice(abcLine.staffGroup.voices[j]);
25
+ setUpperAndLowerElements(renderer, abcLine.staffGroup);
27
26
  }
27
+ }
28
28
 
29
- // Set the staff spacing
30
- // TODO-PER: we should have been able to do this by the time we called setUpperAndLowerElements, but for some reason the "bottom" element seems to be set as a side effect of setting the X spacing.
31
- for(i=0; i<abctune.lines.length; i++) {
32
- abcLine = abctune.lines[i];
33
- if (abcLine.staffGroup) {
34
- abcLine.staffGroup.setHeight();
35
- }
29
+ // Set the staff spacing
30
+ // TODO-PER: we should have been able to do this by the time we called setUpperAndLowerElements, but for some reason the "bottom" element seems to be set as a side effect of setting the X spacing.
31
+ for (i = 0; i < abctune.lines.length; i++) {
32
+ abcLine = abctune.lines[i];
33
+ if (abcLine.staffGroup) {
34
+ abcLine.staffGroup.setHeight();
36
35
  }
37
- return maxWidth;
38
36
  }
39
- // Do the x-axis positioning for a single line (a group of related staffs)
40
- var setXSpacing = function (renderer, width, space, staffGroup, formatting, isLastLine, debug) {
41
- var leftEdge = getLeftEdgeOfStaff(renderer, staffGroup.getTextSize, staffGroup.voices, staffGroup.brace, staffGroup.bracket);
42
- var newspace = space;
43
- for (var it = 0; it < 8; it++) { // TODO-PER: shouldn't need multiple passes, but each pass gets it closer to the right spacing. (Only affects long lines: normal lines break out of this loop quickly.)
44
- var ret = layoutStaffGroup(newspace, renderer, debug, staffGroup, leftEdge);
45
- newspace = calcHorizontalSpacing(isLastLine, formatting.stretchlast, width+renderer.padding.left, staffGroup.w, newspace, ret.spacingUnits, ret.minSpace, renderer.padding.left+renderer.padding.right);
46
- if (debug)
47
- console.log("setXSpace", it, staffGroup.w, newspace, staffGroup.minspace);
48
- if (newspace === null) break;
49
- }
50
- centerWholeRests(staffGroup.voices);
51
- };
37
+ return maxWidth;
38
+ }
39
+ // Do the x-axis positioning for a single line (a group of related staffs)
40
+ var setXSpacing = function (renderer, width, space, staffGroup, formatting, isLastLine, debug) {
41
+ var leftEdge = getLeftEdgeOfStaff(renderer, staffGroup.getTextSize, staffGroup.voices, staffGroup.brace, staffGroup.bracket);
42
+ var newspace = space;
43
+ for (var it = 0; it < 8; it++) { // TODO-PER: shouldn't need multiple passes, but each pass gets it closer to the right spacing. (Only affects long lines: normal lines break out of this loop quickly.)
44
+ var ret = layoutStaffGroup(newspace, renderer, debug, staffGroup, leftEdge);
45
+ newspace = calcHorizontalSpacing(isLastLine, formatting.stretchlast, width + renderer.padding.left, staffGroup.w, newspace, ret.spacingUnits, ret.minSpace, renderer.padding.left + renderer.padding.right);
46
+ if (debug)
47
+ console.log("setXSpace", it, staffGroup.w, newspace, staffGroup.minspace);
48
+ if (newspace === null) break;
49
+ }
50
+ centerWholeRests(staffGroup.voices);
51
+ };
52
52
 
53
- function calcHorizontalSpacing(isLastLine, stretchLast, targetWidth, lineWidth, spacing, spacingUnits, minSpace, padding) {
54
- if (isLastLine) {
55
- if (stretchLast === undefined) {
56
- if (lineWidth / targetWidth < 0.66) return null; // keep this for backward compatibility. The break isn't quite the same for some reason.
57
- } else {
58
- // "Stretch the last music line of a tune when it lacks less than the float fraction of the page width."
59
- var lack = 1 - (lineWidth+padding) / targetWidth;
60
- var stretch = lack < stretchLast;
61
- if (!stretch) return null; // don't stretch last line too much
62
- }
53
+ function calcHorizontalSpacing(isLastLine, stretchLast, targetWidth, lineWidth, spacing, spacingUnits, minSpace, padding) {
54
+ if (isLastLine) {
55
+ if (stretchLast === undefined) {
56
+ if (lineWidth / targetWidth < 0.66) return null; // keep this for backward compatibility. The break isn't quite the same for some reason.
57
+ } else {
58
+ // "Stretch the last music line of a tune when it lacks less than the float fraction of the page width."
59
+ var lack = 1 - (lineWidth + padding) / targetWidth;
60
+ var stretch = lack < stretchLast;
61
+ if (!stretch) return null; // don't stretch last line too much
63
62
  }
64
- if (Math.abs(targetWidth-lineWidth) < 2) return null; // if we are already near the target width, we're done.
65
- var relSpace = spacingUnits * spacing;
66
- var constSpace = lineWidth - relSpace;
67
- if (spacingUnits > 0) {
68
- spacing = (targetWidth - constSpace) / spacingUnits;
69
- if (spacing * minSpace > 50) {
70
- spacing = 50 / minSpace;
71
- }
72
- return spacing;
63
+ }
64
+ if (Math.abs(targetWidth - lineWidth) < 2) return null; // if we are already near the target width, we're done.
65
+ var relSpace = spacingUnits * spacing;
66
+ var constSpace = lineWidth - relSpace;
67
+ if (spacingUnits > 0) {
68
+ spacing = (targetWidth - constSpace) / spacingUnits;
69
+ if (spacing * minSpace > 50) {
70
+ spacing = 50 / minSpace;
73
71
  }
74
- return null;
72
+ return spacing;
75
73
  }
74
+ return null;
75
+ }
76
76
 
77
- function centerWholeRests(voices) {
78
- // whole rests are a special case: if they are by themselves in a measure, then they should be centered.
79
- // (If they are not by themselves, that is probably a user error, but we'll just center it between the two items to either side of it.)
80
- for (var i = 0; i < voices.length; i++) {
81
- var voice = voices[i];
82
- // Look through all of the elements except for the first and last. If the whole note appears there then there isn't anything to center it between anyway.
83
- for (var j = 1; j < voice.children.length-1; j++) {
84
- var absElem = voice.children[j];
85
- if (absElem.abcelem.rest && (absElem.abcelem.rest.type === 'whole' || absElem.abcelem.rest.type === 'multimeasure')) {
86
- var before = voice.children[j-1];
87
- var after = voice.children[j+1];
88
- absElem.center(before, after);
89
- }
77
+ function centerWholeRests(voices) {
78
+ // whole rests are a special case: if they are by themselves in a measure, then they should be centered.
79
+ // (If they are not by themselves, that is probably a user error, but we'll just center it between the two items to either side of it.)
80
+ for (var i = 0; i < voices.length; i++) {
81
+ var voice = voices[i];
82
+ // Look through all of the elements except for the first and last. If the whole note appears there then there isn't anything to center it between anyway.
83
+ for (var j = 1; j < voice.children.length - 1; j++) {
84
+ var absElem = voice.children[j];
85
+ if (absElem.abcelem.rest && (absElem.abcelem.rest.type === 'whole' || absElem.abcelem.rest.type === 'multimeasure')) {
86
+ var before = voice.children[j - 1];
87
+ var after = voice.children[j + 1];
88
+ absElem.center(before, after);
90
89
  }
91
90
  }
92
91
  }
92
+ }
93
93
 
94
94
  module.exports = layout;
@@ -1,6 +1,6 @@
1
- var spacing = require('../abc_spacing');
1
+ var spacing = require('../helpers/spacing');
2
2
 
3
- var setUpperAndLowerElements = function(renderer, staffGroup) {
3
+ var setUpperAndLowerElements = function (renderer, staffGroup) {
4
4
  // Each staff already has the top and bottom set, now we see if there are elements that are always on top and bottom, and resolve their pitch.
5
5
  // Also, get the overall height of all the staves in this group.
6
6
  var lastStaffBottom;
@@ -49,7 +49,7 @@ var setUpperAndLowerElements = function(renderer, staffGroup) {
49
49
  incTop(staff, positionY, 'tempoHeightAbove');
50
50
 
51
51
  if (staff.specialY.lyricHeightBelow) {
52
- staff.specialY.lyricHeightBelow += renderer.spacing.vocal/spacing.STEP;
52
+ staff.specialY.lyricHeightBelow += renderer.spacing.vocal / spacing.STEP;
53
53
  positionY.lyricHeightBelow = staff.bottom;
54
54
  staff.bottom -= (staff.specialY.lyricHeightBelow + margin);
55
55
  }
@@ -82,7 +82,7 @@ var setUpperAndLowerElements = function(renderer, staffGroup) {
82
82
  if (lastStaffBottom !== undefined) {
83
83
  var thisStaffTop = staff.top - 10;
84
84
  var forcedSpacingBetween = lastStaffBottom + thisStaffTop;
85
- var minSpacingInPitches = renderer.spacing.systemStaffSeparation/spacing.STEP;
85
+ var minSpacingInPitches = renderer.spacing.systemStaffSeparation / spacing.STEP;
86
86
  var addedSpace = minSpacingInPitches - forcedSpacingBetween;
87
87
  if (addedSpace > 0)
88
88
  staff.top += addedSpace;
@@ -195,7 +195,7 @@ function setUpperAndLowerTempoElement(positionY, element) {
195
195
  }
196
196
 
197
197
  function setUpperAndLowerRelativeElements(positionY, element, renderSpacing) {
198
- switch(element.type) {
198
+ switch (element.type) {
199
199
  case "part":
200
200
  element.top = positionY.partHeightAbove + element.height;
201
201
  element.bottom = positionY.partHeightAbove;
@@ -215,9 +215,9 @@ function setUpperAndLowerRelativeElements(positionY, element, renderSpacing) {
215
215
  element.top = positionY.lyricHeightAbove;
216
216
  element.bottom = positionY.lyricHeightAbove;
217
217
  } else {
218
- element.top = positionY.lyricHeightBelow + renderSpacing.vocal/spacing.STEP;
219
- element.bottom = positionY.lyricHeightBelow + renderSpacing.vocal/spacing.STEP;
220
- element.pitch -= renderSpacing.vocal/spacing.STEP;
218
+ element.top = positionY.lyricHeightBelow + renderSpacing.vocal / spacing.STEP;
219
+ element.bottom = positionY.lyricHeightBelow + renderSpacing.vocal / spacing.STEP;
220
+ element.pitch -= renderSpacing.vocal / spacing.STEP;
221
221
  }
222
222
  break;
223
223
  case "debug":
@@ -1,4 +1,4 @@
1
- var layoutVoiceElements = require('./VoiceElements');
1
+ var layoutVoiceElements = require('./voice-elements');
2
2
 
3
3
  function checkLastBarX(voices) {
4
4
  var maxX = 0;
@@ -19,35 +19,35 @@ function checkLastBarX(voices) {
19
19
  }
20
20
  }
21
21
 
22
- var layoutStaffGroup = function(spacing, renderer, debug, staffGroup, leftEdge) {
22
+ var layoutStaffGroup = function (spacing, renderer, debug, staffGroup, leftEdge) {
23
23
  var epsilon = 0.0000001; // Fudging for inexactness of floating point math.
24
24
  var spacingunits = 0; // number of times we will have ended up using the spacing distance (as opposed to fixed width distances)
25
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
26
 
27
27
  var x = leftEdge;
28
- staffGroup.startx=x;
28
+ staffGroup.startx = x;
29
29
  var i;
30
30
 
31
31
  var currentduration = 0;
32
32
  if (debug) console.log("init layout", spacing);
33
- for (i=0;i<staffGroup.voices.length;i++) {
33
+ for (i = 0; i < staffGroup.voices.length; i++) {
34
34
  layoutVoiceElements.beginLayout(x, staffGroup.voices[i]);
35
35
  }
36
36
 
37
37
  var spacingunit = 0; // number of spacingunits coming from the previously laid out element to this one
38
38
  while (!finished(staffGroup.voices)) {
39
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]);
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
44
  }
45
45
 
46
46
 
47
47
  // isolate voices at current duration level
48
48
  var currentvoices = [];
49
49
  var othervoices = [];
50
- for (i=0;i<staffGroup.voices.length;i++) {
50
+ for (i = 0; i < staffGroup.voices.length; i++) {
51
51
  var durationIndex = getDurationIndex(staffGroup.voices[i]);
52
52
  // PER: Because of the inexactness of JS floating point math, we just get close.
53
53
  if (durationIndex - currentduration > epsilon) {
@@ -62,44 +62,44 @@ var layoutStaffGroup = function(spacing, renderer, debug, staffGroup, leftEdge)
62
62
  // among the current duration level find the one which needs starting furthest right
63
63
  spacingunit = 0; // number of spacingunits coming from the previously laid out element to this one
64
64
  var spacingduration = 0;
65
- for (i=0;i<currentvoices.length;i++) {
65
+ for (i = 0; i < currentvoices.length; i++) {
66
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]);
67
+ if (layoutVoiceElements.getNextX(currentvoices[i]) > x) {
68
+ x = layoutVoiceElements.getNextX(currentvoices[i]);
69
+ spacingunit = layoutVoiceElements.getSpacingUnits(currentvoices[i]);
70
70
  spacingduration = currentvoices[i].spacingduration;
71
71
  }
72
72
  }
73
- spacingunits+=spacingunit;
74
- minspace = Math.min(minspace,spacingunit);
75
- if (debug) console.log("currentduration: ",currentduration, spacingunits, minspace);
73
+ spacingunits += spacingunit;
74
+ minspace = Math.min(minspace, spacingunit);
75
+ if (debug) console.log("currentduration: ", currentduration, spacingunits, minspace);
76
76
 
77
77
  var lastTopVoice = undefined;
78
- for (i=0;i<currentvoices.length;i++) {
78
+ for (i = 0; i < currentvoices.length; i++) {
79
79
  var v = currentvoices[i];
80
80
  if (v.voicenumber === 0)
81
81
  lastTopVoice = i;
82
82
  var topVoice = (lastTopVoice !== undefined && currentvoices[lastTopVoice].voicenumber !== v.voicenumber) ? currentvoices[lastTopVoice] : undefined;
83
83
  if (!isSameStaff(v, topVoice))
84
84
  topVoice = undefined;
85
- var voicechildx = layoutVoiceElements.layoutOneItem(x,spacing, v, renderer.minPadding, topVoice);
86
- var dx = voicechildx-x;
87
- if (dx>0) {
85
+ var voicechildx = layoutVoiceElements.layoutOneItem(x, spacing, v, renderer.minPadding, topVoice);
86
+ var dx = voicechildx - x;
87
+ if (dx > 0) {
88
88
  x = voicechildx; //update x
89
- for (var j=0;j<i;j++) { // shift over all previously laid out elements
89
+ for (var j = 0; j < i; j++) { // shift over all previously laid out elements
90
90
  layoutVoiceElements.shiftRight(dx, currentvoices[j]);
91
91
  }
92
92
  }
93
93
  }
94
94
 
95
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
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
99
  }
100
100
 
101
101
  // update indexes of currently laid out elems
102
- for (i=0;i<currentvoices.length;i++) {
102
+ for (i = 0; i < currentvoices.length; i++) {
103
103
  var voice = currentvoices[i];
104
104
  layoutVoiceElements.updateIndices(voice);
105
105
  }
@@ -107,17 +107,17 @@ var layoutStaffGroup = function(spacing, renderer, debug, staffGroup, leftEdge)
107
107
 
108
108
 
109
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]);
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
114
  }
115
115
  }
116
116
 
117
117
  // adjust lastBar when needed (multi staves)
118
118
  checkLastBarX(staffGroup.voices);
119
119
  //console.log("greatest remaining",spacingunit,x);
120
- spacingunits+=spacingunit;
120
+ spacingunits += spacingunit;
121
121
  staffGroup.setWidth(x);
122
122
 
123
123
  return { spacingUnits: spacingunits, minSpace: minspace };
@@ -125,14 +125,14 @@ var layoutStaffGroup = function(spacing, renderer, debug, staffGroup, leftEdge)
125
125
 
126
126
 
127
127
  function finished(voices) {
128
- for (var i=0;i<voices.length;i++) {
128
+ for (var i = 0; i < voices.length; i++) {
129
129
  if (!layoutVoiceElements.layoutEnded(voices[i])) return false;
130
130
  }
131
131
  return true;
132
132
  }
133
133
 
134
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
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
136
  }
137
137
 
138
138
  function isSameStaff(voice1, voice2) {