abcjs 6.0.0-beta.35 → 6.0.0-beta.39

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 (73) hide show
  1. package/LICENSE.md +1 -1
  2. package/README.md +15 -6
  3. package/RELEASE.md +74 -0
  4. package/dist/abcjs-basic-min.js +2 -2
  5. package/dist/abcjs-basic-min.js.LICENSE +2 -2
  6. package/dist/abcjs-basic.js +2599 -328
  7. package/dist/abcjs-basic.js.map +1 -1
  8. package/dist/abcjs-plugin-min.js +2 -2
  9. package/dist/abcjs-plugin-min.js.LICENSE +2 -2
  10. package/dist/report-basic.html +37 -0
  11. package/dist/report-before-glyph-compress.html +37 -0
  12. package/dist/report-brown-ts-target-es5.html +37 -0
  13. package/dist/report-dev-orig-no-babel.html +37 -0
  14. package/dist/report-synth.html +37 -0
  15. package/docker-build.sh +1 -0
  16. package/glyphs.json +1 -0
  17. package/index.js +23 -1
  18. package/license.js +1 -1
  19. package/package.json +2 -1
  20. package/plugin.js +23 -1
  21. package/src/api/abc_tablatures.js +144 -0
  22. package/src/api/abc_tunebook.js +10 -1
  23. package/src/api/abc_tunebook_svg.js +18 -6
  24. package/src/data/abc_tune.js +26 -24
  25. package/src/edit/abc_editor.js +29 -11
  26. package/src/parse/abc_parse.js +4 -2
  27. package/src/parse/abc_parse_directive.js +12 -6
  28. package/src/parse/tune-builder.js +1 -1
  29. package/src/synth/abc_midi_flattener.js +11 -2
  30. package/src/synth/abc_midi_sequencer.js +4 -1
  31. package/src/synth/create-synth.js +105 -34
  32. package/src/synth/load-note.js +34 -65
  33. package/src/synth/place-note.js +63 -59
  34. package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
  35. package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
  36. package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
  37. package/src/tablatures/instruments/string-patterns.js +277 -0
  38. package/src/tablatures/instruments/string-tablature.js +56 -0
  39. package/src/tablatures/instruments/tab-note.js +282 -0
  40. package/src/tablatures/instruments/tab-notes.js +41 -0
  41. package/src/tablatures/instruments/violin/tab-violin.js +47 -0
  42. package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
  43. package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
  44. package/src/tablatures/tab-absolute-elements.js +310 -0
  45. package/src/tablatures/tab-common.js +29 -0
  46. package/src/tablatures/tab-renderer.js +243 -0
  47. package/src/tablatures/transposer.js +110 -0
  48. package/src/test/abc_parser_lint.js +3 -0
  49. package/src/write/abc_absolute_element.js +2 -2
  50. package/src/write/abc_engraver_controller.js +19 -11
  51. package/src/write/abc_glyphs.js +2 -0
  52. package/src/write/abc_relative_element.js +5 -3
  53. package/src/write/abc_renderer.js +5 -1
  54. package/src/write/draw/absolute.js +5 -1
  55. package/src/write/draw/draw.js +5 -6
  56. package/src/write/draw/non-music.js +3 -1
  57. package/src/write/draw/print-line.js +24 -0
  58. package/src/write/draw/relative.js +14 -2
  59. package/src/write/draw/selectables.js +9 -6
  60. package/src/write/draw/staff-group.js +44 -8
  61. package/src/write/draw/staff-line.js +3 -19
  62. package/src/write/draw/staff.js +15 -2
  63. package/src/write/draw/tab-line.js +40 -0
  64. package/src/write/draw/text.js +3 -0
  65. package/src/write/draw/voice.js +9 -1
  66. package/src/write/format-jazz-chord.js +2 -2
  67. package/src/write/layout/staffGroup.js +23 -1
  68. package/src/write/layout/voice.js +2 -1
  69. package/src/write/svg.js +2 -1
  70. package/temp.txt +0 -0
  71. package/test.js +23 -0
  72. package/types/index.d.ts +73 -25
  73. package/version.js +1 -1
@@ -17,8 +17,29 @@ return /******/ (function() { // webpackBootstrap
17
17
  \******************/
18
18
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
19
19
 
20
- __webpack_require__(/*! ./license */ "./license.js");
20
+ /**!
21
+ Copyright (c) 2009-2022 Paul Rosen and Gregory Dyke
22
+
23
+ Permission is hereby granted, free of charge, to any person obtaining a copy
24
+ of this software and associated documentation files (the "Software"), to deal
25
+ in the Software without restriction, including without limitation the rights
26
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
27
+ copies of the Software, and to permit persons to whom the Software is
28
+ furnished to do so, subject to the following conditions:
29
+
30
+ The above copyright notice and this permission notice shall be included in
31
+ all copies or substantial portions of the Software.
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
39
+ THE SOFTWARE.
21
40
 
41
+ **This text is from: http://opensource.org/licenses/MIT**
42
+ !**/
22
43
  var version = __webpack_require__(/*! ./version */ "./version.js");
23
44
 
24
45
  var animation = __webpack_require__(/*! ./src/api/abc_animation */ "./src/api/abc_animation.js");
@@ -84,38 +105,6 @@ module.exports = abcjs;
84
105
 
85
106
  /***/ }),
86
107
 
87
- /***/ "./license.js":
88
- /*!********************!*\
89
- !*** ./license.js ***!
90
- \********************/
91
- /***/ (function() {
92
-
93
- /**!
94
- Copyright (c) 2009-2021 Paul Rosen and Gregory Dyke
95
-
96
- Permission is hereby granted, free of charge, to any person obtaining a copy
97
- of this software and associated documentation files (the "Software"), to deal
98
- in the Software without restriction, including without limitation the rights
99
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
100
- copies of the Software, and to permit persons to whom the Software is
101
- furnished to do so, subject to the following conditions:
102
-
103
- The above copyright notice and this permission notice shall be included in
104
- all copies or substantial portions of the Software.
105
-
106
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
107
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
108
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
109
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
110
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
111
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
112
- THE SOFTWARE.
113
-
114
- **This text is from: http://opensource.org/licenses/MIT**
115
- !**/
116
-
117
- /***/ }),
118
-
119
108
  /***/ "./src/api/abc_animation.js":
120
109
  /*!**********************************!*\
121
110
  !*** ./src/api/abc_animation.js ***!
@@ -234,6 +223,161 @@ module.exports = animation;
234
223
 
235
224
  /***/ }),
236
225
 
226
+ /***/ "./src/api/abc_tablatures.js":
227
+ /*!***********************************!*\
228
+ !*** ./src/api/abc_tablatures.js ***!
229
+ \***********************************/
230
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
231
+
232
+ /*
233
+ * Tablature Plugins
234
+ * tablature are defined dynamically and registered inside abcjs
235
+ * by calling abcTablatures.register(plugin)
236
+ * where plugin represents a plugin instance
237
+ *
238
+ */
239
+ var ViolinTablature = __webpack_require__(/*! ../tablatures/instruments/violin/tab-violin */ "./src/tablatures/instruments/violin/tab-violin.js");
240
+
241
+ var GuitarTablature = __webpack_require__(/*! ../tablatures/instruments/guitar/tab-guitar */ "./src/tablatures/instruments/guitar/tab-guitar.js");
242
+ /* extend the table below when adding a new instrument plugin */
243
+ // Existing tab classes
244
+
245
+
246
+ var pluginTab = {
247
+ 'violin': 'ViolinTab',
248
+ 'guitar': 'GuitarTab'
249
+ };
250
+ var abcTablatures = {
251
+ inited: false,
252
+ plugins: {},
253
+
254
+ /**
255
+ * to be called once per plugin for registration
256
+ * @param {*} plugin
257
+ */
258
+ register: function register(plugin) {
259
+ var name = plugin.name;
260
+ var tablature = plugin.tablature;
261
+ this.plugins[name] = tablature;
262
+ },
263
+ setError: function setError(tune, msg) {
264
+ if (tune.warnings) {
265
+ tune.warning.push(msg);
266
+ } else {
267
+ tune.warnings = [msg];
268
+ }
269
+ },
270
+
271
+ /**
272
+ * handle params for current processed score
273
+ * @param {*} tune current tune
274
+ * @param {*} tuneNumber number in tune list
275
+ * @param {*} params params to be processed for tablature
276
+ * @return prepared tablatures plugin instances for current tune
277
+ */
278
+ preparePlugins: function preparePlugins(tune, tuneNumber, params) {
279
+ var returned = null;
280
+ var nbPlugins = 0;
281
+
282
+ if (params.tablature) {
283
+ // validate requested plugins
284
+ var tabs = params.tablature;
285
+ returned = [];
286
+
287
+ for (var ii = 0; ii < tabs.length; ii++) {
288
+ var args = tabs[ii];
289
+ var instrument = args['instrument'];
290
+
291
+ if (instrument == null) {
292
+ this.setError(tune, "tablature 'instrument' is missing");
293
+ return returned;
294
+ }
295
+
296
+ var tabName = pluginTab[instrument];
297
+ var plugin = null;
298
+
299
+ if (tabName) {
300
+ plugin = this.plugins[tabName];
301
+ }
302
+
303
+ if (plugin) {
304
+ if (params.visualTranspose != 0) {
305
+ // populate transposition request to tabs
306
+ args.visualTranspose = params.visualTranspose;
307
+ }
308
+
309
+ args.abcSrc = params.tablature.abcSrc;
310
+ var pluginInstance = {
311
+ classz: plugin,
312
+ tuneNumber: tuneNumber,
313
+ params: args,
314
+ instance: null
315
+ }; // proceed with tab plugin init
316
+ // plugin.init(tune, tuneNumber, args, ii);
317
+
318
+ returned.push(pluginInstance);
319
+ nbPlugins++;
320
+ } else {
321
+ // unknown tab plugin
322
+ //this.emit_error('Undefined tablature plugin: ' + tabName)
323
+ this.setError(tune, 'Undefined tablature plugin: ' + instrument);
324
+ return returned;
325
+ }
326
+ }
327
+ }
328
+
329
+ return returned;
330
+ },
331
+
332
+ /**
333
+ * Call requested plugin
334
+ * @param {*} renderer
335
+ * @param {*} abcTune
336
+ */
337
+ layoutTablatures: function layoutTablatures(renderer, abcTune) {
338
+ var tabs = abcTune.tablatures; // chack tabs request for each staffs
339
+
340
+ for (var ii = 0; ii < abcTune.lines.length; ii++) {
341
+ var line = abcTune.lines[ii];
342
+ var curStaff = line.staff;
343
+
344
+ if (curStaff) {
345
+ for (var jj = 0; jj < curStaff.length; jj++) {
346
+ if (tabs[jj]) {
347
+ // tablature requested for staff
348
+ var tabPlugin = tabs[jj];
349
+
350
+ if (tabPlugin.instance == null) {
351
+ tabPlugin.instance = new tabPlugin.classz(); // plugin.init(tune, tuneNumber, args, ii);
352
+ // call initer first
353
+
354
+ tabPlugin.instance.init(abcTune, tabPlugin.tuneNumber, tabPlugin.params, jj);
355
+ } // render next
356
+
357
+
358
+ tabPlugin.instance.render(renderer, line, jj);
359
+ }
360
+ }
361
+ }
362
+ }
363
+ },
364
+
365
+ /**
366
+ * called once internally to register internal plugins
367
+ */
368
+ init: function init() {
369
+ // just register plugin hosted by abcjs
370
+ if (!this.inited) {
371
+ this.register(new ViolinTablature());
372
+ this.register(new GuitarTablature());
373
+ this.inited = true;
374
+ }
375
+ }
376
+ };
377
+ module.exports = abcTablatures;
378
+
379
+ /***/ }),
380
+
237
381
  /***/ "./src/api/abc_timing_callbacks.js":
238
382
  /*!*****************************************!*\
239
383
  !*** ./src/api/abc_timing_callbacks.js ***!
@@ -611,13 +755,15 @@ module.exports = TimingCallbacks;
611
755
  \*********************************/
612
756
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
613
757
 
614
- function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
758
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
615
759
 
616
760
  // abc_tunebook.js: splits a string representing ABC Music Notation into individual tunes.
617
761
  var Parse = __webpack_require__(/*! ../parse/abc_parse */ "./src/parse/abc_parse.js");
618
762
 
619
763
  var bookParser = __webpack_require__(/*! ../parse/abc_parse_book */ "./src/parse/abc_parse_book.js");
620
764
 
765
+ var tablatures = __webpack_require__(/*! ./abc_tablatures */ "./src/api/abc_tablatures.js");
766
+
621
767
  var tunebook = {};
622
768
 
623
769
  (function () {
@@ -692,7 +838,15 @@ var tunebook = {};
692
838
  if (div) {
693
839
  if (currentTune >= 0 && currentTune < book.tunes.length) {
694
840
  abcParser.parse(book.tunes[currentTune].abc, params, book.tunes[currentTune].startPos - book.header.length);
695
- var tune = abcParser.getTune();
841
+ var tune = abcParser.getTune(); //
842
+ // Init tablatures plugins
843
+ //
844
+
845
+ if (params.tablature) {
846
+ tablatures.init();
847
+ tune.tablatures = tablatures.preparePlugins(tune, currentTune, params);
848
+ }
849
+
696
850
  var warnings = abcParser.getWarnings();
697
851
  if (warnings) tune.warnings = warnings;
698
852
  var override = callback(div, tune, i, book.tunes[currentTune].abc);
@@ -890,7 +1044,8 @@ var Parse = __webpack_require__(/*! ../parse/abc_parse */ "./src/parse/abc_parse
890
1044
 
891
1045
  var wrap = __webpack_require__(/*! ../parse/wrap_lines */ "./src/parse/wrap_lines.js");
892
1046
 
893
- var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/abc_common.js");
1047
+ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/abc_common.js"); // var tablatures = require('./abc_tablatures');
1048
+
894
1049
 
895
1050
  var resizeDivs = {};
896
1051
 
@@ -913,7 +1068,7 @@ try {
913
1068
  } catch (e) {// if we aren't in a browser, this code will crash, but it is not needed then either.
914
1069
  }
915
1070
 
916
- function renderOne(div, tune, params, tuneNumber) {
1071
+ function renderOne(div, tune, params, tuneNumber, lineOffset) {
917
1072
  if (params.viewportHorizontal) {
918
1073
  // Create an inner div that holds the music, so that the passed in div will be the viewport.
919
1074
  div.innerHTML = '<div class="abcjs-inner"></div>';
@@ -935,7 +1090,7 @@ function renderOne(div, tune, params, tuneNumber) {
935
1090
  } else div.innerHTML = "";
936
1091
 
937
1092
  var engraver_controller = new EngraverController(div, params);
938
- engraver_controller.engraveABC(tune, tuneNumber);
1093
+ engraver_controller.engraveABC(tune, tuneNumber, lineOffset);
939
1094
  tune.engraver = engraver_controller;
940
1095
 
941
1096
  if (params.viewportVertical || params.viewportHorizontal) {
@@ -1001,7 +1156,11 @@ function renderEachLineSeparately(div, tune, params, tuneNumber) {
1001
1156
 
1002
1157
  var origPaddingTop = ep.paddingtop;
1003
1158
  var origPaddingBottom = ep.paddingbottom;
1159
+ var currentScrollY = div.parentNode.scrollTop; // If there is scrolling it will be lost during the redraw so remember it.
1160
+
1161
+ var currentScrollX = div.parentNode.scrollLeft;
1004
1162
  div.innerHTML = "";
1163
+ var lineCount = 0;
1005
1164
 
1006
1165
  for (var k = 0; k < tunes.length; k++) {
1007
1166
  var lineEl = document.createElement("div");
@@ -1024,11 +1183,16 @@ function renderEachLineSeparately(div, tune, params, tuneNumber) {
1024
1183
  tunes[k].formatting.stretchlast = true;
1025
1184
  }
1026
1185
 
1027
- renderOne(lineEl, tunes[k], ep, tuneNumber);
1186
+ renderOne(lineEl, tunes[k], ep, tuneNumber, lineCount);
1187
+ lineCount += tunes[k].lines.length;
1028
1188
  if (k === 0) tune.engraver = tunes[k].engraver;else {
1029
1189
  if (!tune.engraver.staffgroups) tune.engraver.staffgroups = tunes[k].engraver.staffgroups;else if (tunes[k].engraver.staffgroups.length > 0) tune.engraver.staffgroups.push(tunes[k].engraver.staffgroups[0]);
1030
1190
  }
1031
1191
  }
1192
+
1193
+ if (currentScrollX || currentScrollY) {
1194
+ div.parentNode.scrollTo(currentScrollX, currentScrollY);
1195
+ }
1032
1196
  } // A quick way to render a tune from javascript when interactivity is not required.
1033
1197
  // This is used when a javascript routine has some abc text that it wants to render
1034
1198
  // in a div or collection of divs. One tune or many can be rendered.
@@ -1059,6 +1223,10 @@ var renderAbc = function renderAbc(output, abc, parserParams, engraverParams, re
1059
1223
  params[key] = parserParams[key];
1060
1224
  }
1061
1225
  }
1226
+
1227
+ if (params.warnings_id && params.tablature) {
1228
+ params.tablature.warning_id = params.warnings_id;
1229
+ }
1062
1230
  }
1063
1231
 
1064
1232
  if (engraverParams) {
@@ -1095,7 +1263,7 @@ var renderAbc = function renderAbc(output, abc, parserParams, engraverParams, re
1095
1263
  if (!removeDiv && params.wrap && params.staffwidth) {
1096
1264
  tune = doLineWrapping(div, tune, tuneNumber, abcString, params);
1097
1265
  return tune;
1098
- } else if (removeDiv || !params.oneSvgPerLine || tune.lines.length < 2) renderOne(div, tune, params, tuneNumber);else renderEachLineSeparately(div, tune, params, tuneNumber);
1266
+ } else if (removeDiv || !params.oneSvgPerLine || tune.lines.length < 2) renderOne(div, tune, params, tuneNumber, 0);else renderEachLineSeparately(div, tune, params, tuneNumber);
1099
1267
 
1100
1268
  if (removeDiv) div.parentNode.removeChild(div);
1101
1269
  return null;
@@ -1117,7 +1285,7 @@ function doLineWrapping(div, tune, tuneNumber, abcString, params) {
1117
1285
  if (warnings) tune.warnings = warnings;
1118
1286
  }
1119
1287
 
1120
- if (!params.oneSvgPerLine || tune.lines.length < 2) renderOne(div, tune, ret.revisedParams, tuneNumber);else renderEachLineSeparately(div, tune, ret.revisedParams, tuneNumber);
1288
+ if (!params.oneSvgPerLine || tune.lines.length < 2) renderOne(div, tune, ret.revisedParams, tuneNumber, 0);else renderEachLineSeparately(div, tune, ret.revisedParams, tuneNumber);
1121
1289
  tune.explanation = ret.explanation;
1122
1290
  return tune;
1123
1291
  }
@@ -1534,33 +1702,36 @@ var Tune = function Tune() {
1534
1702
 
1535
1703
  for (var line = 0; line < this.engraver.staffgroups.length; line++) {
1536
1704
  var group = this.engraver.staffgroups[line];
1537
- var firstStaff = group.staffs[0];
1538
- var middleC = firstStaff.absoluteY;
1539
- var top = middleC - firstStaff.top * spacing.STEP;
1540
- var lastStaff = group.staffs[group.staffs.length - 1];
1541
- middleC = lastStaff.absoluteY;
1542
- var bottom = middleC - lastStaff.bottom * spacing.STEP;
1543
- var height = bottom - top;
1544
- var voices = group.voices;
1545
-
1546
- for (var v = 0; v < voices.length; v++) {
1547
- var noteFound = false;
1548
- if (!voicesArr[v]) voicesArr[v] = [];
1549
- if (measureNumber[v] === undefined) measureNumber[v] = 0;
1550
- var elements = voices[v].children;
1551
-
1552
- for (var elem = 0; elem < elements.length; elem++) {
1553
- if (elements[elem].type === "tempo") tempos[measureNumber[v]] = this.getBpm(elements[elem].abcelem);
1554
- voicesArr[v].push({
1555
- top: top,
1556
- height: height,
1557
- line: group.line,
1558
- measureNumber: measureNumber[v],
1559
- elem: elements[elem]
1560
- });
1561
- if (elements[elem].type === 'bar' && noteFound) // Count the measures by counting the bar lines, but skip a bar line that appears at the left of the music, before any notes.
1562
- measureNumber[v]++;
1563
- if (elements[elem].type === 'note' || elements[elem].type === 'rest') noteFound = true;
1705
+
1706
+ if (group && group.staffs && group.staffs.length > 0) {
1707
+ var firstStaff = group.staffs[0];
1708
+ var middleC = firstStaff.absoluteY;
1709
+ var top = middleC - firstStaff.top * spacing.STEP;
1710
+ var lastStaff = group.staffs[group.staffs.length - 1];
1711
+ middleC = lastStaff.absoluteY;
1712
+ var bottom = middleC - lastStaff.bottom * spacing.STEP;
1713
+ var height = bottom - top;
1714
+ var voices = group.voices;
1715
+
1716
+ for (var v = 0; v < voices.length; v++) {
1717
+ var noteFound = false;
1718
+ if (!voicesArr[v]) voicesArr[v] = [];
1719
+ if (measureNumber[v] === undefined) measureNumber[v] = 0;
1720
+ var elements = voices[v].children;
1721
+
1722
+ for (var elem = 0; elem < elements.length; elem++) {
1723
+ if (elements[elem].type === "tempo") tempos[measureNumber[v]] = this.getBpm(elements[elem].abcelem);
1724
+ voicesArr[v].push({
1725
+ top: top,
1726
+ height: height,
1727
+ line: group.line,
1728
+ measureNumber: measureNumber[v],
1729
+ elem: elements[elem]
1730
+ });
1731
+ if (elements[elem].type === 'bar' && noteFound) // Count the measures by counting the bar lines, but skip a bar line that appears at the left of the music, before any notes.
1732
+ measureNumber[v]++;
1733
+ if (elements[elem].type === 'note' || elements[elem].type === 'rest') noteFound = true;
1734
+ }
1564
1735
  }
1565
1736
  }
1566
1737
  }
@@ -2242,6 +2413,19 @@ function gatherAbcParams(params) {
2242
2413
  }
2243
2414
  }
2244
2415
  }
2416
+ /*
2417
+ if (params.tablature_options) {
2418
+ abcjsParams['tablatures'] = params.tablature_options;
2419
+ }
2420
+ */
2421
+
2422
+
2423
+ if (abcjsParams.tablature) {
2424
+ if (params.warnings_id) {
2425
+ // store for plugin error handling
2426
+ abcjsParams.tablature.warnings_id = params.warnings_id;
2427
+ }
2428
+ }
2245
2429
 
2246
2430
  return abcjsParams;
2247
2431
  }
@@ -2378,15 +2562,22 @@ Editor.prototype.modelChanged = function () {
2378
2562
  if (this.bReentry) return; // TODO is this likely? maybe, if we rewrite abc immediately w/ abc2abc
2379
2563
 
2380
2564
  this.bReentry = true;
2381
- this.timerId = null;
2382
- if (this.synth && this.synth.synthControl) this.synth.synthControl.disable(true);
2383
- this.tunes = renderAbc(this.div, this.currentAbc, this.abcjsParams);
2384
2565
 
2385
- if (this.tunes.length > 0) {
2386
- this.warnings = this.tunes[0].warnings;
2387
- }
2566
+ try {
2567
+ this.timerId = null;
2568
+ if (this.synth && this.synth.synthControl) this.synth.synthControl.disable(true);
2569
+ this.tunes = renderAbc(this.div, this.currentAbc, this.abcjsParams);
2570
+
2571
+ if (this.tunes.length > 0) {
2572
+ this.warnings = this.tunes[0].warnings;
2573
+ }
2388
2574
 
2389
- this.redrawMidi();
2575
+ this.redrawMidi();
2576
+ } catch (error) {
2577
+ console.error("ABCJS error: ", error);
2578
+ if (!this.warnings) this.warnings = [];
2579
+ this.warnings.push(error.message);
2580
+ }
2390
2581
 
2391
2582
  if (this.warningsdiv) {
2392
2583
  this.warningsdiv.innerHTML = this.warnings ? this.warnings.join("<br />") : "No errors";
@@ -2944,8 +3135,11 @@ var Parse = function Parse() {
2944
3135
  for (var i = 0; i < this.inTie.length; i++) {
2945
3136
  this.endingHoldOver.inTie.push([]);
2946
3137
 
2947
- for (var j = 0; j < this.inTie[i].length; j++) {
2948
- this.endingHoldOver.inTie[i].push(this.inTie[i][j]);
3138
+ if (this.inTie[i]) {
3139
+ // if a voice is suppressed there might be a gap in the array.
3140
+ for (var j = 0; j < this.inTie[i].length; j++) {
3141
+ this.endingHoldOver.inTie[i].push(this.inTie[i][j]);
3142
+ }
2949
3143
  }
2950
3144
  }
2951
3145
 
@@ -3699,6 +3893,27 @@ var parseDirective = {};
3699
3893
  weight: "bold",
3700
3894
  style: "normal",
3701
3895
  decoration: "none"
3896
+ };
3897
+ tune.formatting.tablabelfont = {
3898
+ face: "\"Trebuchet MS\"",
3899
+ size: 16,
3900
+ weight: "normal",
3901
+ style: "normal",
3902
+ decoration: "none"
3903
+ };
3904
+ tune.formatting.tabnumberfont = {
3905
+ face: "\"Arial\"",
3906
+ size: 11,
3907
+ weight: "normal",
3908
+ style: "normal",
3909
+ decoration: "none"
3910
+ };
3911
+ tune.formatting.tabgracefont = {
3912
+ face: "\"Arial\"",
3913
+ size: 8,
3914
+ weight: "normal",
3915
+ style: "normal",
3916
+ decoration: "none"
3702
3917
  }; // these are the default fonts for these element types. In the printer, these fonts might change as the tune progresses.
3703
3918
 
3704
3919
  tune.formatting.annotationfont = multilineVars.annotationfont;
@@ -4989,6 +5204,9 @@ var parseDirective = {};
4989
5204
  case "vocalfont":
4990
5205
  case "wordsfont":
4991
5206
  case "annotationfont":
5207
+ case "tablabelfont":
5208
+ case "tabnumberfont":
5209
+ case "tabgracefont":
4992
5210
  getChangingFont(cmd, tokens, value);
4993
5211
  break;
4994
5212
 
@@ -10958,7 +11176,7 @@ var TuneBuilder = function TuneBuilder(tune) {
10958
11176
 
10959
11177
  this.containsNotesStrict = function (voice) {
10960
11178
  for (var i = 0; i < voice.length; i++) {
10961
- if (voice[i].el_type === 'note' && voice[i].rest === undefined) return true;
11179
+ if (voice[i].el_type === 'note' && (voice[i].rest === undefined || voice[i].chord !== undefined)) return true;
10962
11180
  }
10963
11181
 
10964
11182
  return false;
@@ -11958,7 +12176,7 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
11958
12176
  if (currentTrack[0].instrument === undefined) currentTrack[0].instrument = instrument ? instrument : 0;
11959
12177
  if (currentTrackName) currentTrack.unshift(currentTrackName);
11960
12178
  tracks.push(currentTrack);
11961
- if (chordTrack.length > 0) // Don't do chords on more than one track, so turn off chord detection after we create it.
12179
+ if (!chordTrackEmpty()) // Don't do chords on more than one track, so turn off chord detection after we create it.
11962
12180
  chordTrackFinished = true;
11963
12181
  if (drumTrack.length > 0) // Don't do drums on more than one track, so turn off drum after we create it.
11964
12182
  drumTrackFinished = true;
@@ -11966,7 +12184,7 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
11966
12184
 
11967
12185
 
11968
12186
  if (options.detuneOctave) findOctaves(tracks, parseInt(options.detuneOctave, 10));
11969
- if (chordTrack.length > 0) tracks.push(chordTrack);
12187
+ if (!chordTrackEmpty()) tracks.push(chordTrack);
11970
12188
  if (drumTrack.length > 0) tracks.push(drumTrack);
11971
12189
  return {
11972
12190
  tempo: startingTempo,
@@ -11985,6 +12203,16 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
11985
12203
  }
11986
12204
  }
11987
12205
 
12206
+ function chordTrackEmpty() {
12207
+ var isEmpty = true;
12208
+
12209
+ for (var i = 0; i < chordTrack.length && isEmpty; i++) {
12210
+ if (chordTrack[i].cmd === 'note') isEmpty = false;
12211
+ }
12212
+
12213
+ return isEmpty;
12214
+ }
12215
+
11988
12216
  function timeToRealTime(time) {
11989
12217
  return time / 1000000;
11990
12218
  }
@@ -13833,7 +14061,8 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
13833
14061
  var voiceNumber = 0;
13834
14062
 
13835
14063
  for (var j = 0; j < staves.length; j++) {
13836
- var staff = staves[j]; // For each staff line
14064
+ var staff = staves[j];
14065
+ if (staff.clef && staff.clef.type === "TAB") continue; // For each staff line
13837
14066
 
13838
14067
  for (var k = 0; k < staff.voices.length; k++) {
13839
14068
  // For each voice in a staff line
@@ -13962,7 +14191,7 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
13962
14191
  tripletMultiplier = elem.tripletMultiplier;
13963
14192
  tripletDurationTotal = elem.startTriplet * tripletMultiplier * elem.duration;
13964
14193
 
13965
- if (elem.startTriplet != elem.tripletR) {
14194
+ if (elem.startTriplet !== elem.tripletR) {
13966
14195
  // most commonly (3:2:2
13967
14196
  if (v + elem.tripletR <= voice.length) {
13968
14197
  var durationTotal = 0;
@@ -14835,10 +15064,10 @@ var soundsCache = __webpack_require__(/*! ./sounds-cache */ "./src/synth/sounds-
14835
15064
 
14836
15065
 
14837
15066
  var notSupportedMessage = "MIDI is not supported in this browser.";
14838
- var defaultSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/abcjs/"; // These are the original soundfonts supplied. They will need a volume boost:
15067
+ var originalSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/abcjs/"; // These are the original soundfonts supplied. They will need a volume boost:
14839
15068
 
14840
- var alternateSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/FluidR3_GM/";
14841
- var alternateSoundFontUrl2 = "https://paulrosen.github.io/midi-js-soundfonts/MusyngKite/";
15069
+ var defaultSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/FluidR3_GM/";
15070
+ var alternateSoundFontUrl = "https://paulrosen.github.io/midi-js-soundfonts/MusyngKite/";
14842
15071
 
14843
15072
  function CreateSynth() {
14844
15073
  var self = this;
@@ -14871,10 +15100,51 @@ function CreateSynth() {
14871
15100
  var params = options.options ? options.options : {};
14872
15101
  self.soundFontUrl = params.soundFontUrl ? params.soundFontUrl : defaultSoundFontUrl;
14873
15102
  if (self.soundFontUrl[self.soundFontUrl.length - 1] !== '/') self.soundFontUrl += '/';
14874
- if (params.soundFontVolumeMultiplier) self.soundFontVolumeMultiplier = params.soundFontVolumeMultiplier;else if (self.soundFontUrl === alternateSoundFontUrl || self.soundFontUrl === alternateSoundFontUrl2) self.soundFontVolumeMultiplier = 5.0;else if (self.soundFontUrl === defaultSoundFontUrl) self.soundFontVolumeMultiplier = 0.5;else self.soundFontVolumeMultiplier = 1.0;
14875
- if (params.programOffsets) self.programOffsets = params.programOffsets;else if (self.soundFontUrl === defaultSoundFontUrl) self.programOffsets = {
14876
- "violin": 113,
14877
- "trombone": 200
15103
+ if (params.soundFontVolumeMultiplier || params.soundFontVolumeMultiplier === 0) self.soundFontVolumeMultiplier = params.soundFontVolumeMultiplier;else if (self.soundFontUrl === defaultSoundFontUrl || self.soundFontUrl === alternateSoundFontUrl) self.soundFontVolumeMultiplier = 3.0;else if (self.soundFontUrl === originalSoundFontUrl) self.soundFontVolumeMultiplier = 0.4;else self.soundFontVolumeMultiplier = 1.0;
15104
+ if (params.programOffsets) self.programOffsets = params.programOffsets;else if (self.soundFontUrl === originalSoundFontUrl) self.programOffsets = {
15105
+ "bright_acoustic_piano": 20,
15106
+ "honkytonk_piano": 20,
15107
+ "electric_piano_1": 30,
15108
+ "electric_piano_2": 30,
15109
+ "harpsichord": 40,
15110
+ "clavinet": 20,
15111
+ "celesta": 20,
15112
+ "glockenspiel": 40,
15113
+ "vibraphone": 30,
15114
+ "marimba": 35,
15115
+ "xylophone": 30,
15116
+ "tubular_bells": 35,
15117
+ "dulcimer": 30,
15118
+ "drawbar_organ": 20,
15119
+ "percussive_organ": 25,
15120
+ "rock_organ": 20,
15121
+ "church_organ": 40,
15122
+ "reed_organ": 40,
15123
+ "accordion": 40,
15124
+ "harmonica": 40,
15125
+ "acoustic_guitar_nylon": 20,
15126
+ "acoustic_guitar_steel": 30,
15127
+ "electric_guitar_jazz": 25,
15128
+ "electric_guitar_clean": 15,
15129
+ "electric_guitar_muted": 35,
15130
+ "overdriven_guitar": 25,
15131
+ "distortion_guitar": 20,
15132
+ "guitar_harmonics": 30,
15133
+ "electric_bass_finger": 15,
15134
+ "electric_bass_pick": 30,
15135
+ "fretless_bass": 40,
15136
+ "violin": 105,
15137
+ "viola": 50,
15138
+ "cello": 40,
15139
+ "contrabass": 60,
15140
+ "trumpet": 10,
15141
+ "trombone": 90,
15142
+ "alto_sax": 20,
15143
+ "tenor_sax": 20,
15144
+ "clarinet": 20,
15145
+ "flute": 50,
15146
+ "banjo": 50,
15147
+ "woodblock": 20
14878
15148
  };else self.programOffsets = {};
14879
15149
  var p = params.fadeLength !== undefined ? parseInt(params.fadeLength, 10) : NaN;
14880
15150
  self.fadeLength = isNaN(p) ? 200 : p;
@@ -14896,6 +15166,7 @@ function CreateSynth() {
14896
15166
  self.onEnded = params.onEnded;
14897
15167
  var allNotes = {};
14898
15168
  var cached = [];
15169
+ var errorNotes = [];
14899
15170
  var currentInstrument = instrumentIndexToName[0];
14900
15171
  self.flattened.tracks.forEach(function (track) {
14901
15172
  track.forEach(function (event) {
@@ -14907,8 +15178,15 @@ function CreateSynth() {
14907
15178
 
14908
15179
  if (noteName) {
14909
15180
  if (!allNotes[currentInstrument]) allNotes[currentInstrument] = {};
14910
- if (!soundsCache[currentInstrument] || !soundsCache[currentInstrument][noteName]) allNotes[currentInstrument][noteName] = true;else cached.push(currentInstrument + ":" + noteName);
14911
- } else console.log("Can't find note: ", pitchNumber);
15181
+ if (!soundsCache[currentInstrument] || !soundsCache[currentInstrument][noteName]) allNotes[currentInstrument][noteName] = true;else {
15182
+ var label2 = currentInstrument + ":" + noteName;
15183
+ if (cached.indexOf(label2) < 0) cached.push(label2);
15184
+ }
15185
+ } else {
15186
+ var label = currentInstrument + ":" + noteName;
15187
+ console.log("Can't find note: ", pitchNumber, label);
15188
+ if (errorNotes.indexOf(label) < 0) errorNotes.push(label);
15189
+ }
14912
15190
  }
14913
15191
  });
14914
15192
  });
@@ -14934,7 +15212,7 @@ function CreateSynth() {
14934
15212
  return new Promise(function (resolve, reject) {
14935
15213
  var results = {
14936
15214
  cached: cached,
14937
- error: [],
15215
+ error: errorNotes,
14938
15216
  loaded: []
14939
15217
  };
14940
15218
  var index = 0;
@@ -15056,7 +15334,7 @@ function CreateSynth() {
15056
15334
  noteMapTracks.forEach(function (noteMap, trackNumber) {
15057
15335
  var panDistance = panDistances && panDistances.length > trackNumber ? panDistances[trackNumber] : 0;
15058
15336
  noteMap.forEach(function (note) {
15059
- var key = note.instrument + ':' + note.pitch + ':' + note.volume + ':' + Math.round((note.end - note.start) * 1000) / 1000 + ':' + panDistance + ':' + tempoMultiplier + ':' + note.cents;
15337
+ var key = note.instrument + ':' + note.pitch + ':' + note.volume + ':' + Math.round((note.end - note.start) * 1000) / 1000 + ':' + panDistance + ':' + tempoMultiplier + ':' + (note.cents ? note.cents : 0);
15060
15338
  if (!uniqueSounds[key]) uniqueSounds[key] = [];
15061
15339
  uniqueSounds[key].push(note.start);
15062
15340
  });
@@ -15089,30 +15367,53 @@ function CreateSynth() {
15089
15367
  self.debugCallback("creationTime = " + Math.floor((activeAudioContext().currentTime - startTime) * 1000) + "ms");
15090
15368
  }
15091
15369
 
15370
+ function resolveData(me) {
15371
+ var duration = me && me.audioBuffers && me.audioBuffers.length > 0 ? me.audioBuffers[0].duration : 0;
15372
+ return {
15373
+ status: activeAudioContext().state,
15374
+ duration: duration
15375
+ };
15376
+ }
15377
+
15092
15378
  Promise.all(allPromises).then(function () {
15093
- resolve({
15094
- status: "ok",
15095
- seconds: 0
15096
- });
15379
+ // Safari iOS can mess with the audioContext state, so resume if needed.
15380
+ if (activeAudioContext().state === "suspended") {
15381
+ activeAudioContext().resume().then(function () {
15382
+ resolve(resolveData(self));
15383
+ });
15384
+ } else if (activeAudioContext().state === "interrupted") {
15385
+ activeAudioContext().suspend().then(function () {
15386
+ activeAudioContext().resume().then(function () {
15387
+ resolve(resolveData(self));
15388
+ });
15389
+ });
15390
+ } else {
15391
+ resolve(resolveData(self));
15392
+ }
15097
15393
  });
15098
15394
  });
15099
15395
  };
15100
15396
 
15101
15397
  function setPan(numTracks, panParam) {
15398
+ // panParam, if it is set, can be either a number representing the separation between each track,
15399
+ // or an array, which is the absolute pan position for each track.
15102
15400
  if (panParam === null || panParam === undefined) return null;
15103
15401
  var panDistances = [];
15104
15402
 
15105
15403
  if (panParam.length) {
15106
- if (numTracks === panParam.length) {
15107
- var ok = true;
15108
-
15109
- for (var pp = 0; pp < panParam.length; pp++) {
15404
+ // We received an array. If there are the same number of items in the pan array as the number of tracks,
15405
+ // it all lines up perfectly. If there are more items in the pan array than the tracks then the excess items are ignored.
15406
+ // If there are more tracks than items in the pan array then the remaining tracks are placed in the middle.
15407
+ // If any of the pan numbers are out of range then they are adjusted.
15408
+ for (var pp = 0; pp < numTracks; pp++) {
15409
+ if (pp < panParam.length) {
15110
15410
  var x = parseFloat(panParam[pp]);
15111
- if (x >= -1 && x <= 1) panDistances.push(x);else ok = false;
15112
- }
15113
-
15114
- if (ok) return panDistances;
15411
+ if (x < -1) x = -1;else if (x > 1) x = 1;
15412
+ panDistances.push(x);
15413
+ } else panDistances.push(0);
15115
15414
  }
15415
+
15416
+ return panDistances;
15116
15417
  } else {
15117
15418
  var panNumber = parseFloat(panParam); // the separation needs to be no further than 2 (i.e. -1 to 1) so test to see if there are too many tracks for the passed in distance
15118
15419
 
@@ -15157,8 +15458,8 @@ function CreateSynth() {
15157
15458
  self.pause = function () {
15158
15459
  if (!self.audioBufferPossible) throw new Error(notSupportedMessage);
15159
15460
  if (self.debugCallback) self.debugCallback("pause called");
15160
- self.stop();
15161
- self.pausedTimeSec = activeAudioContext().currentTime - self.startTimeSec;
15461
+ self.pausedTimeSec = self.stop();
15462
+ return self.pausedTimeSec;
15162
15463
  };
15163
15464
 
15164
15465
  self.resume = function () {
@@ -15210,6 +15511,8 @@ function CreateSynth() {
15210
15511
  }
15211
15512
  });
15212
15513
  self.directSource = [];
15514
+ var elapsed = activeAudioContext().currentTime - self.startTimeSec;
15515
+ return elapsed;
15213
15516
  };
15214
15517
 
15215
15518
  self.finished = function () {
@@ -15503,104 +15806,46 @@ module.exports = instrumentIndexToName;
15503
15806
  var soundsCache = __webpack_require__(/*! ./sounds-cache */ "./src/synth/sounds-cache.js");
15504
15807
 
15505
15808
  var getNote = function getNote(url, instrument, name, audioContext) {
15506
- return new Promise(function (resolve, reject) {
15507
- if (!soundsCache[instrument]) soundsCache[instrument] = {};
15508
- var instrumentCache = soundsCache[instrument];
15509
-
15510
- if (instrumentCache[name] === 'error') {
15511
- return resolve({
15512
- instrument: instrument,
15513
- name: name,
15514
- status: "error",
15515
- message: "Unable to load sound font" + ' ' + url + ' ' + instrument + ' ' + name
15516
- });
15517
- }
15518
-
15519
- if (instrumentCache[name] === 'pending') {
15520
- return resolve({
15521
- instrument: instrument,
15522
- name: name,
15523
- status: "pending"
15524
- });
15525
- }
15526
-
15527
- if (instrumentCache[name]) {
15528
- return resolve({
15529
- instrument: instrument,
15530
- name: name,
15531
- status: "cached"
15532
- });
15533
- } // if (this.debugCallback)
15534
- // this.debugCallback(`Loading sound: ${instrument} ${name}`);
15535
-
15536
-
15537
- instrumentCache[name] = "pending"; // This can be called in parallel, so don't call it a second time before the first one has loaded.
15538
-
15809
+ if (!soundsCache[instrument]) soundsCache[instrument] = {};
15810
+ var instrumentCache = soundsCache[instrument];
15811
+ if (!instrumentCache[name]) instrumentCache[name] = new Promise(function (resolve, reject) {
15539
15812
  var xhr = new XMLHttpRequest();
15540
- xhr.open('GET', url + instrument + '-mp3/' + name + '.mp3', true);
15541
- xhr.responseType = 'arraybuffer';
15542
- var self = this;
15543
-
15544
- function onSuccess(audioBuffer) {
15545
- instrumentCache[name] = audioBuffer; // if (self.debugCallback)
15546
- // self.debugCallback(`Sound loaded: ${instrument} ${name} ${url}`);
15547
-
15548
- resolve({
15549
- instrument: instrument,
15550
- name: name,
15551
- status: "loaded"
15552
- });
15553
- }
15554
-
15555
- function onFailure(error) {
15556
- error = "Can't decode sound. " + url + ' ' + instrument + ' ' + name + ' ' + error;
15557
- if (self.debugCallback) self.debugCallback(error);
15558
- return resolve({
15559
- instrument: instrument,
15560
- name: name,
15561
- status: "error",
15562
- message: error
15563
- });
15564
- }
15813
+ var noteUrl = url + instrument + "-mp3/" + name + ".mp3";
15814
+ xhr.open("GET", noteUrl, true);
15815
+ xhr.responseType = "arraybuffer";
15565
15816
 
15566
- xhr.onload = function (e) {
15567
- if (this.status === 200) {
15568
- try {
15569
- var promise = audioContext.decodeAudioData(this.response, onSuccess, onFailure); // older browsers only have the callback. Newer ones will report an unhandled
15570
- // rejection if catch isn't handled so we need both. We don't need to report it twice, though.
15571
-
15572
- if (promise && promise["catch"]) promise["catch"](function () {});
15573
- } catch (error) {
15574
- reject(error);
15575
- }
15576
- } else {
15577
- instrumentCache[name] = "error"; // To keep this from trying to load repeatedly.
15817
+ xhr.onload = function () {
15818
+ if (xhr.status !== 200) {
15819
+ reject(Error("Can't load sound at " + noteUrl));
15820
+ return;
15821
+ }
15578
15822
 
15579
- var cantLoadMp3 = "Onload error loading sound: " + name + " " + url + " " + e.currentTarget.status + " " + e.currentTarget.statusText;
15580
- if (self.debugCallback) self.debugCallback(cantLoadMp3);
15581
- return resolve({
15823
+ var noteDecoded = function noteDecoded(audioBuffer) {
15824
+ resolve({
15582
15825
  instrument: instrument,
15583
15826
  name: name,
15584
- status: "error",
15585
- message: cantLoadMp3
15827
+ status: "loaded",
15828
+ audioBuffer: audioBuffer
15586
15829
  });
15587
- }
15830
+ };
15831
+
15832
+ var maybePromise = audioContext.decodeAudioData(xhr.response, noteDecoded, function () {
15833
+ reject(Error("Can't decode sound at " + noteUrl));
15834
+ }); // In older browsers `BaseAudioContext.decodeAudio()` did not return a promise
15835
+
15836
+ if (maybePromise && typeof maybePromise["catch"] === "function") maybePromise["catch"](reject);
15588
15837
  };
15589
15838
 
15590
- xhr.addEventListener("error", function () {
15591
- instrumentCache[name] = "error"; // To keep this from trying to load repeatedly.
15839
+ xhr.onerror = function () {
15840
+ reject(Error("Can't load sound at " + noteUrl));
15841
+ };
15592
15842
 
15593
- var cantLoadMp3 = "Error in loading sound: " + " " + url;
15594
- if (self.debugCallback) self.debugCallback(cantLoadMp3);
15595
- return resolve({
15596
- instrument: instrument,
15597
- name: name,
15598
- status: "error",
15599
- message: cantLoadMp3
15600
- });
15601
- }, false);
15602
15843
  xhr.send();
15844
+ })["catch"](function (err) {
15845
+ console.error("Didn't load note", instrument, name, ":", err.message);
15846
+ throw err;
15603
15847
  });
15848
+ return instrumentCache[name];
15604
15849
  };
15605
15850
 
15606
15851
  module.exports = getNote;
@@ -15818,80 +16063,80 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
15818
16063
 
15819
16064
  var offlineCtx = new OfflineAC(2, Math.floor((len + fadeTimeSec) * sampleRate), sampleRate);
15820
16065
  var noteName = pitchToNoteName[sound.pitch];
15821
- var noteBuffer = soundsCache[sound.instrument][noteName];
15822
-
15823
- if (noteBuffer === "error" || noteBuffer === "pending") {
15824
- // If the note isn't available, just leave a blank spot
15825
- // If the note is still pending by now that means an error happened when loading. There was probably a timeout.
15826
- console.log("Didn't load note", sound.instrument, noteName, noteBuffer);
15827
- return;
15828
- } // create audio buffer
16066
+ var noteBufferPromise = soundsCache[sound.instrument][noteName];
15829
16067
 
16068
+ if (!noteBufferPromise) {
16069
+ // if the note isn't present then just skip it - it will leave a blank spot in the audio.
16070
+ return Promise.resolve();
16071
+ }
15830
16072
 
15831
- var source = offlineCtx.createBufferSource();
15832
- source.buffer = noteBuffer; // add gain
15833
- // volume can be between 1 to 127. This translation to gain is just trial and error.
15834
- // The smaller the first number, the more dynamic range between the quietest to loudest.
15835
- // The larger the second number, the louder it will be in general.
16073
+ return noteBufferPromise.then(function (response) {
16074
+ // create audio buffer
16075
+ var source = offlineCtx.createBufferSource();
16076
+ source.buffer = response.audioBuffer; // add gain
16077
+ // volume can be between 1 to 127. This translation to gain is just trial and error.
16078
+ // The smaller the first number, the more dynamic range between the quietest to loudest.
16079
+ // The larger the second number, the louder it will be in general.
15836
16080
 
15837
- var volume = sound.volume / 96 * volumeMultiplier;
15838
- source.gainNode = offlineCtx.createGain(); // add pan if supported and present
16081
+ var volume = sound.volume / 96 * volumeMultiplier;
16082
+ source.gainNode = offlineCtx.createGain(); // add pan if supported and present
15839
16083
 
15840
- if (sound.pan && offlineCtx.createStereoPanner) {
15841
- source.panNode = offlineCtx.createStereoPanner();
15842
- source.panNode.pan.setValueAtTime(sound.pan, 0);
15843
- }
16084
+ if (sound.pan && offlineCtx.createStereoPanner) {
16085
+ source.panNode = offlineCtx.createStereoPanner();
16086
+ source.panNode.pan.setValueAtTime(sound.pan, 0);
16087
+ }
15844
16088
 
15845
- source.gainNode.gain.value = volume; // Math.min(2, Math.max(0, volume));
16089
+ source.gainNode.gain.value = volume; // Math.min(2, Math.max(0, volume));
15846
16090
 
15847
- source.gainNode.gain.linearRampToValueAtTime(source.gainNode.gain.value, len);
15848
- source.gainNode.gain.linearRampToValueAtTime(0.0, len + fadeTimeSec);
16091
+ source.gainNode.gain.linearRampToValueAtTime(source.gainNode.gain.value, len);
16092
+ source.gainNode.gain.linearRampToValueAtTime(0.0, len + fadeTimeSec);
15849
16093
 
15850
- if (sound.cents) {
15851
- source.playbackRate.value = centsToFactor(sound.cents);
15852
- } // connect all the nodes
16094
+ if (sound.cents) {
16095
+ source.playbackRate.value = centsToFactor(sound.cents);
16096
+ } // connect all the nodes
15853
16097
 
15854
16098
 
15855
- if (source.panNode) {
15856
- source.panNode.connect(offlineCtx.destination);
15857
- source.gainNode.connect(source.panNode);
15858
- } else {
15859
- source.gainNode.connect(offlineCtx.destination);
15860
- }
16099
+ if (source.panNode) {
16100
+ source.panNode.connect(offlineCtx.destination);
16101
+ source.gainNode.connect(source.panNode);
16102
+ } else {
16103
+ source.gainNode.connect(offlineCtx.destination);
16104
+ }
15861
16105
 
15862
- source.connect(source.gainNode); // Do the process of creating the sound and placing it in the buffer
16106
+ source.connect(source.gainNode); // Do the process of creating the sound and placing it in the buffer
15863
16107
 
15864
- source.start(0);
16108
+ source.start(0);
15865
16109
 
15866
- if (source.noteOff) {
15867
- source.noteOff(len + fadeTimeSec);
15868
- } else {
15869
- source.stop(len + fadeTimeSec);
15870
- }
16110
+ if (source.noteOff) {
16111
+ source.noteOff(len + fadeTimeSec);
16112
+ } else {
16113
+ source.stop(len + fadeTimeSec);
16114
+ }
15871
16115
 
15872
- var fnResolve;
16116
+ var fnResolve;
15873
16117
 
15874
- offlineCtx.oncomplete = function (e) {
15875
- if (e.renderedBuffer) {
15876
- // If the system gets overloaded then this can start failing. Just drop the note if so.
15877
- for (var i = 0; i < startArray.length; i++) {
15878
- //Math.floor(startArray[i] * sound.tempoMultiplier * sampleRate)
15879
- var start = startArray[i] * sound.tempoMultiplier;
15880
- if (ofsMs) start -= ofsMs / 1000;
15881
- if (start < 0) start = 0; // If the item that is moved back is at the very beginning of the buffer then don't move it back. To do that would be to push everything else forward. TODO-PER: this should probably be done at some point but then it would change timing in existing apps.
16118
+ offlineCtx.oncomplete = function (e) {
16119
+ if (e.renderedBuffer) {
16120
+ // If the system gets overloaded then this can start failing. Just drop the note if so.
16121
+ for (var i = 0; i < startArray.length; i++) {
16122
+ //Math.floor(startArray[i] * sound.tempoMultiplier * sampleRate)
16123
+ var start = startArray[i] * sound.tempoMultiplier;
16124
+ if (ofsMs) start -= ofsMs / 1000;
16125
+ if (start < 0) start = 0; // If the item that is moved back is at the very beginning of the buffer then don't move it back. To do that would be to push everything else forward. TODO-PER: this should probably be done at some point but then it would change timing in existing apps.
15882
16126
 
15883
- start = Math.floor(start * sampleRate);
15884
- copyToChannel(outputAudioBuffer, e.renderedBuffer, start);
16127
+ start = Math.floor(start * sampleRate);
16128
+ copyToChannel(outputAudioBuffer, e.renderedBuffer, start);
16129
+ }
15885
16130
  }
15886
- }
15887
16131
 
15888
- fnResolve();
15889
- };
16132
+ fnResolve();
16133
+ };
15890
16134
 
15891
- offlineCtx.startRendering();
15892
- return new Promise(function (resolve, reject) {
15893
- fnResolve = resolve;
15894
- });
16135
+ offlineCtx.startRendering();
16136
+ return new Promise(function (resolve) {
16137
+ fnResolve = resolve;
16138
+ });
16139
+ })["catch"](function () {});
15895
16140
  }
15896
16141
 
15897
16142
  var copyToChannel = function copyToChannel(toBuffer, fromBuffer, start) {
@@ -16391,33 +16636,1873 @@ module.exports = SynthSequence;
16391
16636
 
16392
16637
  /***/ }),
16393
16638
 
16394
- /***/ "./src/write/abc_absolute_element.js":
16395
- /*!*******************************************!*\
16396
- !*** ./src/write/abc_absolute_element.js ***!
16397
- \*******************************************/
16639
+ /***/ "./src/tablatures/instruments/guitar/guitar-fonts.js":
16640
+ /*!***********************************************************!*\
16641
+ !*** ./src/tablatures/instruments/guitar/guitar-fonts.js ***!
16642
+ \***********************************************************/
16643
+ /***/ (function(module) {
16644
+
16645
+ /**
16646
+ * Dedicated fonts for violin tabs
16647
+ */
16648
+
16649
+ /**
16650
+ * Set here the fonts used by renderer/drawer
16651
+ * for the violin plugin
16652
+ * @param {} tune
16653
+ */
16654
+ // eslint-disable-next-line no-unused-vars
16655
+ function setGuitarFonts(tune) {
16656
+ /* enhance or change instrument fonts here */
16657
+ // tune.formatting.tabnumberfont = { face: "\"Times New Roman\"", size: 9, weight: "normal", style: "normal", decoration: "none" };
16658
+ // tune.formatting.tabgracefont = { face: "\"Times New Roman\"", size: 7, weight: "normal", style: "normal", decoration: "none" };
16659
+ }
16660
+
16661
+ module.exports = setGuitarFonts;
16662
+
16663
+ /***/ }),
16664
+
16665
+ /***/ "./src/tablatures/instruments/guitar/guitar-patterns.js":
16666
+ /*!**************************************************************!*\
16667
+ !*** ./src/tablatures/instruments/guitar/guitar-patterns.js ***!
16668
+ \**************************************************************/
16398
16669
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
16399
16670
 
16400
- // abc_absolute_element.js: Definition of the AbsoluteElement class.
16401
- var setClass = __webpack_require__(/*! ./set-class */ "./src/write/set-class.js");
16671
+ var StringPatterns = __webpack_require__(/*! ../string-patterns */ "./src/tablatures/instruments/string-patterns.js");
16402
16672
 
16403
- var highlight = __webpack_require__(/*! ./highlight */ "./src/write/highlight.js");
16673
+ function GuitarPatterns(plugin) {
16674
+ this.tuning = plugin._super.params.tuning;
16404
16675
 
16405
- var unhighlight = __webpack_require__(/*! ./unhighlight */ "./src/write/unhighlight.js"); // Everything that is placed in the SVG is first created as an absolute element. This is one unit of graphic information.
16406
- // That is, it embodies a concept: a clef, a time signature, a bar line,etc. or most complexly:
16407
- // a note with its accidental, grace note, chord symbol, trill, stem, eighth flags, etc.
16408
- // In the largest sense, these are placed on the page at a particular place that is determined during the layout phase.
16409
- // This object doesn't contain any of the drawing information, though. That information is contained in an array of
16410
- // RelativeElements as the "children" of this class.
16411
- // During the layout phase, the width of all the children is calculated and the X coordinate of the absolute element is set.
16412
- //
16413
- // So, after the AbsoluteElement is placed, then its children can be placed relative to that. There are different types of
16414
- // relative elements that are placed with different rules:
16415
- // 1) Fixed - these elements don't move relative to the absolute element's coordinates. These are things like the notehead,
16416
- // any ledger lines, accidentals, etc.
16417
- // 2) Slotted - these elements can move vertically and don't get Y coordinates until after the absolute element is placed.
16418
- // These are things like the chord symbol, many decorations, the lyrics, etc.
16419
- //
16420
- // Relative elements are also classified by how they are related. This could be:
16676
+ if (!this.tuning) {
16677
+ this.tuning = ['E,', 'A', 'D', 'G', 'B', 'e'];
16678
+ }
16679
+
16680
+ plugin.tuning = this.tuning;
16681
+ this.strings = new StringPatterns(plugin);
16682
+ }
16683
+
16684
+ GuitarPatterns.prototype.notesToNumber = function (notes, graces) {
16685
+ var converter = this.strings;
16686
+ return converter.notesToNumber(notes, graces);
16687
+ };
16688
+
16689
+ GuitarPatterns.prototype.stringToPitch = function (stringNumber) {
16690
+ var converter = this.strings;
16691
+ return converter.stringToPitch(stringNumber);
16692
+ };
16693
+
16694
+ module.exports = GuitarPatterns;
16695
+
16696
+ /***/ }),
16697
+
16698
+ /***/ "./src/tablatures/instruments/guitar/tab-guitar.js":
16699
+ /*!*********************************************************!*\
16700
+ !*** ./src/tablatures/instruments/guitar/tab-guitar.js ***!
16701
+ \*********************************************************/
16702
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
16703
+
16704
+ /*
16705
+ Emit tab for Guitar staff
16706
+ */
16707
+ var StringTablature = __webpack_require__(/*! ../string-tablature */ "./src/tablatures/instruments/string-tablature.js");
16708
+
16709
+ var TabCommon = __webpack_require__(/*! ../../tab-common */ "./src/tablatures/tab-common.js");
16710
+
16711
+ var TabRenderer = __webpack_require__(/*! ../../tab-renderer */ "./src/tablatures/tab-renderer.js");
16712
+
16713
+ var GuitarPatterns = __webpack_require__(/*! ./guitar-patterns */ "./src/tablatures/instruments/guitar/guitar-patterns.js");
16714
+
16715
+ var setGuitarFonts = __webpack_require__(/*! ./guitar-fonts */ "./src/tablatures/instruments/guitar/guitar-fonts.js");
16716
+ /**
16717
+ * upon init mainly store provided instances for later usage
16718
+ * @param {*} abcTune the parsed tune AST tree
16719
+ * @param {*} tuneNumber the parsed tune AST tree
16720
+ * @param {*} params complementary args provided to Tablature Plugin
16721
+ */
16722
+
16723
+
16724
+ Plugin.prototype.init = function (abcTune, tuneNumber, params) {
16725
+ var _super = new TabCommon(abcTune, tuneNumber, params);
16726
+
16727
+ this._super = _super;
16728
+ this.abcTune = abcTune;
16729
+ this.linePitch = 3;
16730
+ this.nbLines = 6;
16731
+ this.isTabBig = true;
16732
+ this.capo = params.capo;
16733
+ this.transpose = params.visualTranspose;
16734
+ this.tablature = new StringTablature(this.nbLines, this.linePitch);
16735
+ var semantics = new GuitarPatterns(this);
16736
+ this.semantics = semantics;
16737
+ };
16738
+
16739
+ Plugin.prototype.render = function (renderer, line, staffIndex) {
16740
+ if (this._super.inError) return;
16741
+ if (this.tablature.bypass(line)) return;
16742
+ setGuitarFonts(this.abcTune);
16743
+ var rndrer = new TabRenderer(this, renderer, line, staffIndex);
16744
+ rndrer.doLayout();
16745
+ };
16746
+
16747
+ function Plugin() {} //
16748
+ // Tablature plugin definition
16749
+ //
16750
+
16751
+
16752
+ var AbcGuitarTab = function AbcGuitarTab() {
16753
+ return {
16754
+ name: 'GuitarTab',
16755
+ tablature: Plugin
16756
+ };
16757
+ };
16758
+
16759
+ module.exports = AbcGuitarTab;
16760
+
16761
+ /***/ }),
16762
+
16763
+ /***/ "./src/tablatures/instruments/string-patterns.js":
16764
+ /*!*******************************************************!*\
16765
+ !*** ./src/tablatures/instruments/string-patterns.js ***!
16766
+ \*******************************************************/
16767
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
16768
+
16769
+ var TabNote = __webpack_require__(/*! ./tab-note */ "./src/tablatures/instruments/tab-note.js");
16770
+
16771
+ var TabNotes = __webpack_require__(/*! ./tab-notes */ "./src/tablatures/instruments/tab-notes.js");
16772
+
16773
+ function buildCapo(self) {
16774
+ var capoTuning = null;
16775
+ var tuning = self.tuning;
16776
+
16777
+ if (self.capo > 0) {
16778
+ capoTuning = [];
16779
+
16780
+ for (var iii = 0; iii < tuning.length; iii++) {
16781
+ var curNote = new TabNote.TabNote(tuning[iii]);
16782
+
16783
+ for (var jjj = 0; jjj < self.capo; jjj++) {
16784
+ curNote = curNote.nextNote();
16785
+ }
16786
+
16787
+ capoTuning[iii] = curNote.emit();
16788
+ }
16789
+ }
16790
+
16791
+ return capoTuning;
16792
+ }
16793
+
16794
+ function buildPatterns(self) {
16795
+ var strings = [];
16796
+ var tuning = self.tuning;
16797
+
16798
+ if (self.capo > 0) {
16799
+ tuning = self.capoTuning;
16800
+ }
16801
+
16802
+ var pos = tuning.length - 1;
16803
+
16804
+ for (var iii = 0; iii < tuning.length; iii++) {
16805
+ var nextNote = self.highestNote; // highest handled note
16806
+
16807
+ if (iii != tuning.length - 1) {
16808
+ nextNote = tuning[iii + 1];
16809
+ }
16810
+
16811
+ var tabNotes = new TabNotes(tuning[iii], nextNote);
16812
+ var stringNotes = tabNotes.build();
16813
+
16814
+ if (stringNotes.error) {
16815
+ return stringNotes;
16816
+ }
16817
+
16818
+ strings[pos--] = stringNotes;
16819
+ }
16820
+
16821
+ return strings;
16822
+ }
16823
+
16824
+ function buildSecond(first) {
16825
+ var seconds = [];
16826
+ seconds[0] = [];
16827
+ var strings = first.strings;
16828
+
16829
+ for (var iii = 1; iii < strings.length; iii++) {
16830
+ seconds[iii] = strings[iii - 1];
16831
+ }
16832
+
16833
+ return seconds;
16834
+ }
16835
+
16836
+ function sameString(self, chord) {
16837
+ for (var jjjj = 0; jjjj < chord.length - 1; jjjj++) {
16838
+ var curPos = chord[jjjj];
16839
+ var nextPos = chord[jjjj + 1];
16840
+
16841
+ if (curPos.str == nextPos.str) {
16842
+ // same String
16843
+ // => change lower pos
16844
+ if (curPos.str == self.strings.length - 1) {
16845
+ // Invalid tab Chord position for instrument
16846
+ curPos.num = "?";
16847
+ nextPos.num = "?";
16848
+ return;
16849
+ } // change lower pitch on lowest string
16850
+
16851
+
16852
+ if (nextPos.num < curPos.num) {
16853
+ nextPos.str++;
16854
+ nextPos = noteToNumber(self, nextPos.note, nextPos.str, self.secondPos, self.strings[nextPos.str].length);
16855
+ } else {
16856
+ curPos.str++;
16857
+ curPos = noteToNumber(self, curPos.note, curPos.str, self.secondPos, self.strings[curPos.str].length);
16858
+ } // update table
16859
+
16860
+
16861
+ chord[jjjj] = curPos;
16862
+ chord[jjjj + 1] = nextPos;
16863
+ }
16864
+ }
16865
+
16866
+ return null;
16867
+ }
16868
+
16869
+ function handleChordNotes(self, notes) {
16870
+ var retNotes = [];
16871
+
16872
+ for (var iiii = 0; iiii < notes.length; iiii++) {
16873
+ var note = new TabNote.TabNote(notes[iiii].name);
16874
+ var curPos = toNumber(self, note);
16875
+ retNotes.push(curPos);
16876
+ }
16877
+
16878
+ sameString(self, retNotes);
16879
+ return retNotes;
16880
+ }
16881
+
16882
+ function noteToNumber(self, note, stringNumber, secondPosition, firstSize) {
16883
+ var strings = self.strings;
16884
+ note.checkKeyAccidentals(self.accidentals);
16885
+
16886
+ if (secondPosition) {
16887
+ strings = secondPosition;
16888
+ }
16889
+
16890
+ var noteName = note.emitNoAccidentals();
16891
+ var num = strings[stringNumber].indexOf(noteName);
16892
+ var acc = note.acc;
16893
+
16894
+ if (num != -1) {
16895
+ if (secondPosition) {
16896
+ num += firstSize;
16897
+ }
16898
+
16899
+ if ((note.isFlat || note.acc == -1) && num == 0) {
16900
+ // flat on 0 pos => previous string 7th position
16901
+ var noteEquiv = note.getAccidentalEquiv();
16902
+ stringNumber++;
16903
+ num = strings[stringNumber].indexOf(noteEquiv.emit());
16904
+ acc = 0;
16905
+ }
16906
+
16907
+ return {
16908
+ num: num + acc,
16909
+ str: stringNumber,
16910
+ note: note
16911
+ };
16912
+ }
16913
+
16914
+ return null;
16915
+ }
16916
+
16917
+ function toNumber(self, note) {
16918
+ var num = null;
16919
+ var str = 0;
16920
+ var lowestString = self.strings[self.strings.length - 1];
16921
+ var lowestNote = new TabNote.TabNote(lowestString[0]);
16922
+
16923
+ if (note.isLowerThan(lowestNote)) {
16924
+ return {
16925
+ num: "?",
16926
+ str: self.strings.length - 1,
16927
+ note: note,
16928
+ error: note.emit() + ': unexpected note for instrument'
16929
+ };
16930
+ }
16931
+
16932
+ while (str < self.strings.length) {
16933
+ num = noteToNumber(self, note, str);
16934
+
16935
+ if (num) {
16936
+ return num;
16937
+ }
16938
+
16939
+ str++;
16940
+ }
16941
+
16942
+ return null; // not found
16943
+ }
16944
+
16945
+ StringPatterns.prototype.stringToPitch = function (stringNumber) {
16946
+ var startingPitch = 5.3;
16947
+ var bottom = this.strings.length - 1;
16948
+ return startingPitch + (bottom - stringNumber) * this.linePitch;
16949
+ };
16950
+
16951
+ function invalidNumber(retNotes, note) {
16952
+ var number = {
16953
+ num: "?",
16954
+ str: 0,
16955
+ note: note
16956
+ };
16957
+ retNotes.push(number);
16958
+ retNotes.error = note.emit() + ': unexpected note for instrument';
16959
+ }
16960
+
16961
+ StringPatterns.prototype.notesToNumber = function (notes, graces) {
16962
+ var note;
16963
+ var number;
16964
+ var error = null;
16965
+ var retNotes = null;
16966
+
16967
+ if (notes) {
16968
+ retNotes = [];
16969
+
16970
+ if (notes.length > 1) {
16971
+ retNotes = handleChordNotes(this, notes);
16972
+
16973
+ if (retNotes.error) {
16974
+ error = retNotes.error;
16975
+ }
16976
+ } else {
16977
+ note = new TabNote.TabNote(notes[0].name);
16978
+ number = toNumber(this, note);
16979
+
16980
+ if (number) {
16981
+ retNotes.push(number);
16982
+ } else {
16983
+ invalidNumber(retNotes, note);
16984
+ error = retNotes.error;
16985
+ }
16986
+ }
16987
+ }
16988
+
16989
+ if (error) return retNotes;
16990
+ var retGraces = null;
16991
+
16992
+ if (graces) {
16993
+ retGraces = [];
16994
+
16995
+ for (var iiii = 0; iiii < graces.length; iiii++) {
16996
+ note = new TabNote.TabNote(graces[iiii].name);
16997
+ number = toNumber(this, note);
16998
+
16999
+ if (number) {
17000
+ retGraces.push(number);
17001
+ } else {
17002
+ invalidNumber(retGraces, note);
17003
+ error = retNotes.error;
17004
+ }
17005
+ }
17006
+ }
17007
+
17008
+ return {
17009
+ notes: retNotes,
17010
+ graces: retGraces,
17011
+ error: error
17012
+ };
17013
+ };
17014
+
17015
+ StringPatterns.prototype.toString = function () {
17016
+ return this.tuning.join('').replaceAll(',', '').toUpperCase();
17017
+ };
17018
+
17019
+ StringPatterns.prototype.tabInfos = function (plugin) {
17020
+ var _super = plugin._super;
17021
+ var name = _super.params.label;
17022
+
17023
+ if (name) {
17024
+ var tunePos = name.indexOf('%T');
17025
+ var tuning = "";
17026
+
17027
+ if (tunePos != -1) {
17028
+ tuning = this.toString();
17029
+
17030
+ if (plugin.capo > 0) {
17031
+ tuning += ' capo:' + plugin.capo;
17032
+ }
17033
+
17034
+ name = name.replace('%T', tuning);
17035
+ }
17036
+
17037
+ return name;
17038
+ }
17039
+
17040
+ return '';
17041
+ };
17042
+ /**
17043
+ * Common patterns for all string instruments
17044
+ * @param {} plugin
17045
+ * @param {} tuning
17046
+ * @param {*} capo
17047
+ * @param {*} highestNote
17048
+ */
17049
+
17050
+
17051
+ function StringPatterns(plugin) {
17052
+ var tuning = plugin.tuning;
17053
+ var capo = plugin.capo;
17054
+ var highestNote = plugin._super.params.highestNote;
17055
+ this.linePitch = plugin.linePitch;
17056
+ this.highestNote = "a'";
17057
+
17058
+ if (highestNote) {
17059
+ // override default
17060
+ this.highestNote = highestNote;
17061
+ }
17062
+
17063
+ this.capo = 0;
17064
+
17065
+ if (capo) {
17066
+ this.capo = capo;
17067
+ }
17068
+
17069
+ this.tuning = tuning;
17070
+
17071
+ if (this.capo > 0) {
17072
+ this.capoTuning = buildCapo(this);
17073
+ }
17074
+
17075
+ this.strings = buildPatterns(this);
17076
+
17077
+ if (this.strings.error) {
17078
+ plugin._super.setError(this.strings.error);
17079
+
17080
+ plugin.inError = true;
17081
+ return;
17082
+ } // second position pattern per string
17083
+
17084
+
17085
+ this.secondPos = buildSecond(this);
17086
+ }
17087
+
17088
+ module.exports = StringPatterns;
17089
+
17090
+ /***/ }),
17091
+
17092
+ /***/ "./src/tablatures/instruments/string-tablature.js":
17093
+ /*!********************************************************!*\
17094
+ !*** ./src/tablatures/instruments/string-tablature.js ***!
17095
+ \********************************************************/
17096
+ /***/ (function(module) {
17097
+
17098
+ /**
17099
+ * Layout tablature informations for draw
17100
+ * @param {*} numLines
17101
+ * @param {*} lineSpace
17102
+ */
17103
+ function StringTablature(numLines, lineSpace) {
17104
+ this.numLines = numLines;
17105
+ this.lineSpace = lineSpace;
17106
+ this.verticalSize = this.numLines * this.lineSpace;
17107
+ var pitch = 3;
17108
+ this.bar = {
17109
+ pitch: pitch,
17110
+ pitch2: lineSpace * numLines,
17111
+ height: 5
17112
+ };
17113
+ }
17114
+ /**
17115
+ * return true if current line should not produce a tab
17116
+ * @param {} line
17117
+ */
17118
+
17119
+
17120
+ StringTablature.prototype.bypass = function (line) {
17121
+ var voices = line.staffGroup.voices;
17122
+
17123
+ if (voices.length > 0) {
17124
+ if (voices[0].isPercussion) return true;
17125
+ }
17126
+
17127
+ return false;
17128
+ };
17129
+
17130
+ StringTablature.prototype.setRelative = function (child, relative, first) {
17131
+ switch (child.type) {
17132
+ case 'bar':
17133
+ relative.pitch = this.bar.pitch;
17134
+ relative.pitch2 = this.bar.pitch2;
17135
+ relative.height = this.height;
17136
+ break;
17137
+
17138
+ case 'symbol':
17139
+ var top = this.bar.pitch2 / 2;
17140
+
17141
+ if (child.name == 'dots.dot') {
17142
+ if (first) {
17143
+ relative.pitch = top;
17144
+ return false;
17145
+ } else {
17146
+ relative.pitch = top + this.lineSpace;
17147
+ return true;
17148
+ }
17149
+ }
17150
+
17151
+ break;
17152
+ }
17153
+
17154
+ return first;
17155
+ };
17156
+
17157
+ module.exports = StringTablature;
17158
+
17159
+ /***/ }),
17160
+
17161
+ /***/ "./src/tablatures/instruments/tab-note.js":
17162
+ /*!************************************************!*\
17163
+ !*** ./src/tablatures/instruments/tab-note.js ***!
17164
+ \************************************************/
17165
+ /***/ (function(module) {
17166
+
17167
+ /**
17168
+ *
17169
+ * Note structure for Tabs
17170
+ *
17171
+ */
17172
+ var notes = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
17173
+
17174
+ function TabNote(note) {
17175
+ var isFlat = false;
17176
+ var newNote = note;
17177
+ var isSharp = false;
17178
+ var isAltered = false;
17179
+ var natural = null;
17180
+ var quarter = null;
17181
+ var isDouble = false;
17182
+ var acc = 0;
17183
+
17184
+ if (note.startsWith('_')) {
17185
+ isFlat = true;
17186
+ acc = -1; // check quarter flat
17187
+
17188
+ if (note[1] == '/') {
17189
+ isFlat = false;
17190
+ quarter = "v";
17191
+ acc = 0;
17192
+ } else if (note[1] == '_') {
17193
+ // double flat
17194
+ isDouble = true;
17195
+ acc -= 1;
17196
+ }
17197
+ } else if (note.startsWith('^')) {
17198
+ isSharp = true;
17199
+ acc = +1; // check quarter sharp
17200
+
17201
+ if (note[1] == '/') {
17202
+ isSharp = false;
17203
+ quarter = "^";
17204
+ acc = 0;
17205
+ } else if (note[1] == '^') {
17206
+ // double sharp
17207
+ isDouble = true;
17208
+ acc += 1;
17209
+ }
17210
+ } else if (note.startsWith('=')) {
17211
+ natural = true;
17212
+ acc = 0;
17213
+ }
17214
+
17215
+ isAltered = isFlat || isSharp || quarter != null;
17216
+
17217
+ if (isAltered || natural) {
17218
+ if (quarter != null || isDouble) {
17219
+ newNote = note.slice(2);
17220
+ } else {
17221
+ newNote = note.slice(1);
17222
+ }
17223
+ }
17224
+
17225
+ var hasComma = (note.match(/,/g) || []).length;
17226
+ var hasQuote = (note.match(/'/g) || []).length;
17227
+ this.name = newNote;
17228
+ this.acc = acc;
17229
+ this.isSharp = isSharp;
17230
+ this.isKeySharp = false;
17231
+ this.isDouble = isDouble;
17232
+ this.isAltered = isAltered;
17233
+ this.isFlat = isFlat;
17234
+ this.isKeyFlat = false;
17235
+ this.natural = natural;
17236
+ this.quarter = quarter;
17237
+ this.isLower = this.name == this.name.toLowerCase();
17238
+ this.name = this.name[0].toUpperCase();
17239
+ this.hasComma = hasComma;
17240
+ this.isQuoted = hasQuote;
17241
+ }
17242
+
17243
+ function cloneNote(self) {
17244
+ var newNote = self.name;
17245
+ var newTabNote = new TabNote(newNote);
17246
+ newTabNote.hasComma = self.hasComma;
17247
+ newTabNote.isLower = self.isLower;
17248
+ newTabNote.isQuoted = self.isQuoted;
17249
+ newTabNote.isSharp = self.isSharp;
17250
+ newTabNote.isKeySharp = self.isKeySharp;
17251
+ newTabNote.isFlat = self.isFlat;
17252
+ newTabNote.isKeyFlat = self.isKeyFlat;
17253
+ return newTabNote;
17254
+ }
17255
+
17256
+ TabNote.prototype.sameNoteAs = function (note) {
17257
+ if (this.name == note.name && this.hasComma == note.hasComma && this.isLower == note.isLower && this.isQuoted == note.isQuoted && this.isSharp == note.isSharp && this.isFlat == note.isFlat) {
17258
+ return true;
17259
+ } else {
17260
+ return false;
17261
+ }
17262
+ };
17263
+
17264
+ TabNote.prototype.isLowerThan = function (note) {
17265
+ var noteComparator = ['C', 'D', 'E', 'F', 'G', 'A', 'B'];
17266
+ if (this.hasComma > note.hasComma) return true;
17267
+ if (note.hasComma > this.hasComma) return false;
17268
+ if (this.isQuoted > note.isQuoted) return false;
17269
+ if (note.isQuoted > this.isQuoted) return true;
17270
+
17271
+ if (this.isLower) {
17272
+ if (!note.isLower) return false;
17273
+ } else {
17274
+ if (note.isLower) return true;
17275
+ }
17276
+
17277
+ var noteName = note.name[0].toUpperCase();
17278
+ var thisName = this.name[0].toUpperCase();
17279
+ if (noteComparator.indexOf(thisName) < noteComparator.indexOf(noteName)) return true;
17280
+ return false;
17281
+ };
17282
+
17283
+ TabNote.prototype.checkKeyAccidentals = function (accidentals) {
17284
+ if (accidentals) {
17285
+ var curNote = this.name;
17286
+
17287
+ for (var iii = 0; iii < accidentals.length; iii++) {
17288
+ var curAccidentals = accidentals[iii];
17289
+
17290
+ if (curNote == curAccidentals.note.toUpperCase()) {
17291
+ if (curAccidentals.acc == 'flat') {
17292
+ this.acc = -1;
17293
+ this.isKeyFlat = true;
17294
+ }
17295
+
17296
+ if (curAccidentals.acc == 'sharp') {
17297
+ this.acc = +1;
17298
+ this.isKeySharp = true;
17299
+ }
17300
+ }
17301
+ }
17302
+ }
17303
+ };
17304
+
17305
+ TabNote.prototype.getAccidentalEquiv = function () {
17306
+ var cloned = cloneNote(this);
17307
+
17308
+ if (cloned.isSharp || cloned.isKeySharp) {
17309
+ cloned = cloned.nextNote();
17310
+ cloned.isFlat = true;
17311
+ cloned.isSharp = false;
17312
+ cloned.isKeySharp = false;
17313
+ } else if (cloned.isFlat || cloned.isKeyFlat) {
17314
+ cloned = cloned.prevNote();
17315
+ cloned.isSharp = true;
17316
+ cloned.isFlat = false;
17317
+ cloned.isKeyFlat = false;
17318
+ }
17319
+
17320
+ return cloned;
17321
+ };
17322
+
17323
+ TabNote.prototype.nextNote = function () {
17324
+ var newTabNote = cloneNote(this);
17325
+
17326
+ if (!this.isSharp && !this.isKeySharp) {
17327
+ if (this.name != 'E' && this.name != 'B') {
17328
+ newTabNote.isSharp = true;
17329
+ return newTabNote;
17330
+ }
17331
+ } else {
17332
+ // cleanup
17333
+ newTabNote.isSharp = false;
17334
+ newTabNote.isKeySharp = false;
17335
+ }
17336
+
17337
+ var noteIndex = notes.indexOf(this.name);
17338
+
17339
+ if (noteIndex == notes.length - 1) {
17340
+ noteIndex = 0;
17341
+ } else {
17342
+ noteIndex++;
17343
+ }
17344
+
17345
+ newTabNote.name = notes[noteIndex];
17346
+
17347
+ if (newTabNote.name == 'C') {
17348
+ if (newTabNote.hasComma > 0) {
17349
+ newTabNote.hasComma--;
17350
+ } else {
17351
+ if (!newTabNote.isLower) {
17352
+ newTabNote.isLower = true;
17353
+ } else {
17354
+ newTabNote.isQuoted = true;
17355
+ }
17356
+ }
17357
+ }
17358
+
17359
+ return newTabNote;
17360
+ };
17361
+
17362
+ TabNote.prototype.prevNote = function () {
17363
+ var newTabNote = cloneNote(this);
17364
+
17365
+ if (this.isSharp) {
17366
+ newTabNote.isSharp = false;
17367
+ return newTabNote;
17368
+ }
17369
+
17370
+ var noteIndex = notes.indexOf(this.name);
17371
+
17372
+ if (noteIndex == 0) {
17373
+ noteIndex = notes.length - 1;
17374
+ } else {
17375
+ noteIndex--;
17376
+ }
17377
+
17378
+ newTabNote.name = notes[noteIndex];
17379
+
17380
+ if (newTabNote.name == 'B') {
17381
+ if (newTabNote.isLower) {
17382
+ newTabNote.hasComma = 1;
17383
+ } else {
17384
+ if (newTabNote.hasComma > 0) {
17385
+ newTabNote.hasComma++;
17386
+ } else {
17387
+ if (newTabNote.isQuoted > 0) {
17388
+ newTabNote.isQuoted -= 1;
17389
+ } else {
17390
+ newTabNote.isLower = true;
17391
+ }
17392
+ }
17393
+ }
17394
+ }
17395
+
17396
+ if (this.isFlat) {
17397
+ newTabNote.isFlat = false;
17398
+ return newTabNote;
17399
+ } else {
17400
+ if (this.name != 'E' && this.name != 'B') {
17401
+ newTabNote.isSharp = true;
17402
+ }
17403
+ }
17404
+
17405
+ return newTabNote;
17406
+ };
17407
+
17408
+ TabNote.prototype.emitNoAccidentals = function () {
17409
+ var returned = this.name;
17410
+
17411
+ if (this.isLower) {
17412
+ returned = returned.toLowerCase();
17413
+ }
17414
+
17415
+ for (var ii = 0; ii < this.isQuoted; ii++) {
17416
+ returned += "'";
17417
+ }
17418
+
17419
+ for (var jj = 0; jj < this.hasComma; jj++) {
17420
+ returned += ",";
17421
+ }
17422
+
17423
+ return returned;
17424
+ };
17425
+
17426
+ TabNote.prototype.emit = function () {
17427
+ var returned = this.name;
17428
+
17429
+ if (this.isSharp || this.isKeySharp) {
17430
+ returned = '^' + returned;
17431
+
17432
+ if (this.isDouble) {
17433
+ returned = '^' + returned;
17434
+ }
17435
+ }
17436
+
17437
+ if (this.isFlat || this.isKeyFlat) {
17438
+ returned = '_' + returned;
17439
+
17440
+ if (this.isDouble) {
17441
+ returned = '_' + returned;
17442
+ }
17443
+ }
17444
+
17445
+ if (this.quarter) {
17446
+ if (this.quarter == "^") {
17447
+ returned = "^/" + returned;
17448
+ } else {
17449
+ returned = "_/" + returned;
17450
+ }
17451
+ }
17452
+
17453
+ if (this.natural) {
17454
+ returned = '=' + returned;
17455
+ }
17456
+
17457
+ for (var ii = 1; ii <= this.hasComma; ii++) {
17458
+ returned += ',';
17459
+ }
17460
+
17461
+ if (this.isLower) {
17462
+ returned = returned.toLowerCase();
17463
+
17464
+ for (var jj = 1; jj <= this.isQuoted; jj++) {
17465
+ returned += "'";
17466
+ }
17467
+ }
17468
+
17469
+ return returned;
17470
+ };
17471
+
17472
+ module.exports = {
17473
+ 'TabNote': TabNote,
17474
+ 'notes': notes
17475
+ };
17476
+
17477
+ /***/ }),
17478
+
17479
+ /***/ "./src/tablatures/instruments/tab-notes.js":
17480
+ /*!*************************************************!*\
17481
+ !*** ./src/tablatures/instruments/tab-notes.js ***!
17482
+ \*************************************************/
17483
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
17484
+
17485
+ var TabNote = __webpack_require__(/*! ./tab-note */ "./src/tablatures/instruments/tab-note.js");
17486
+
17487
+ var notes = TabNote.notes;
17488
+
17489
+ function TabNotes(fromNote, toNote) {
17490
+ this.fromN = new TabNote.TabNote(fromNote);
17491
+ this.toN = new TabNote.TabNote(toNote);
17492
+ }
17493
+
17494
+ TabNotes.prototype.build = function () {
17495
+ var fromN = this.fromN;
17496
+ var toN = this.toN; // check that toN is not lower than fromN
17497
+
17498
+ if (toN.isLowerThan(fromN)) {
17499
+ var from = fromN.emit();
17500
+ var tn = toN.emit();
17501
+ return {
17502
+ error: 'Invalid string Instrument tuning : ' + tn + ' string lower than ' + from + ' string'
17503
+ };
17504
+ }
17505
+
17506
+ var buildReturned = [];
17507
+ var startIndex = notes.indexOf(fromN.name);
17508
+ var toIndex = notes.indexOf(toN.name);
17509
+
17510
+ if (startIndex == -1 || toIndex == -1) {
17511
+ return buildReturned;
17512
+ }
17513
+
17514
+ var finished = false;
17515
+
17516
+ while (!finished) {
17517
+ buildReturned.push(fromN.emit());
17518
+ fromN = fromN.nextNote();
17519
+
17520
+ if (fromN.sameNoteAs(toN)) {
17521
+ finished = true;
17522
+ }
17523
+ }
17524
+
17525
+ return buildReturned;
17526
+ };
17527
+
17528
+ module.exports = TabNotes;
17529
+
17530
+ /***/ }),
17531
+
17532
+ /***/ "./src/tablatures/instruments/violin/tab-violin.js":
17533
+ /*!*********************************************************!*\
17534
+ !*** ./src/tablatures/instruments/violin/tab-violin.js ***!
17535
+ \*********************************************************/
17536
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
17537
+
17538
+ var StringTablature = __webpack_require__(/*! ../string-tablature */ "./src/tablatures/instruments/string-tablature.js");
17539
+
17540
+ var TabCommon = __webpack_require__(/*! ../../tab-common */ "./src/tablatures/tab-common.js");
17541
+
17542
+ var TabRenderer = __webpack_require__(/*! ../../tab-renderer */ "./src/tablatures/tab-renderer.js");
17543
+
17544
+ var ViolinPatterns = __webpack_require__(/*! ./violin-patterns */ "./src/tablatures/instruments/violin/violin-patterns.js");
17545
+
17546
+ var setViolinFonts = __webpack_require__(/*! ./violin-fonts */ "./src/tablatures/instruments/violin/violin-fonts.js");
17547
+ /**
17548
+ * upon init mainly store provided instances for later usage
17549
+ * @param {*} abcTune the parsed tune AST tree
17550
+ * @param {*} tuneNumber the parsed tune AST tree
17551
+ * @param {*} params complementary args provided to Tablature Plugin
17552
+ */
17553
+
17554
+
17555
+ Plugin.prototype.init = function (abcTune, tuneNumber, params) {
17556
+ var _super = new TabCommon(abcTune, tuneNumber, params);
17557
+
17558
+ this.abcTune = abcTune;
17559
+ this._super = _super;
17560
+ this.linePitch = 3;
17561
+ this.nbLines = 4;
17562
+ this.isTabBig = false;
17563
+ this.capo = params.capo;
17564
+ this.transpose = params.visualTranspose;
17565
+ this.tablature = new StringTablature(this.nbLines, this.linePitch);
17566
+ var semantics = new ViolinPatterns(this);
17567
+ this.semantics = semantics;
17568
+ };
17569
+
17570
+ Plugin.prototype.render = function (renderer, line, staffIndex) {
17571
+ if (this._super.inError) return;
17572
+ if (this.tablature.bypass(line)) return;
17573
+ setViolinFonts(this.abcTune);
17574
+ var rndrer = new TabRenderer(this, renderer, line, staffIndex);
17575
+ rndrer.doLayout();
17576
+ };
17577
+
17578
+ function Plugin() {} //
17579
+ // Tablature plugin definition
17580
+ //
17581
+
17582
+
17583
+ var AbcViolinTab = function AbcViolinTab() {
17584
+ return {
17585
+ name: 'ViolinTab',
17586
+ tablature: Plugin
17587
+ };
17588
+ };
17589
+
17590
+ module.exports = AbcViolinTab;
17591
+
17592
+ /***/ }),
17593
+
17594
+ /***/ "./src/tablatures/instruments/violin/violin-fonts.js":
17595
+ /*!***********************************************************!*\
17596
+ !*** ./src/tablatures/instruments/violin/violin-fonts.js ***!
17597
+ \***********************************************************/
17598
+ /***/ (function(module) {
17599
+
17600
+ /**
17601
+ * Dedicated fonts for violin tabs
17602
+ */
17603
+
17604
+ /**
17605
+ * Set here the fonts used by renderer/drawer
17606
+ * for the violin plugin
17607
+ * @param {} tune
17608
+ */
17609
+ // eslint-disable-next-line no-unused-vars
17610
+ function setViolinFonts(tune) {
17611
+ /* enhance or change instrument fonts here */
17612
+ // tune.formatting.tabnumberfont = { face: "\"Times New Roman\"", size: 9, weight: "normal", style: "normal", decoration: "none" };
17613
+ // tune.formatting.tabgracefont = { face: "\"Times New Roman\"", size: 7, weight: "normal", style: "normal", decoration: "none" };
17614
+ }
17615
+
17616
+ module.exports = setViolinFonts;
17617
+
17618
+ /***/ }),
17619
+
17620
+ /***/ "./src/tablatures/instruments/violin/violin-patterns.js":
17621
+ /*!**************************************************************!*\
17622
+ !*** ./src/tablatures/instruments/violin/violin-patterns.js ***!
17623
+ \**************************************************************/
17624
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
17625
+
17626
+ var StringPatterns = __webpack_require__(/*! ../string-patterns */ "./src/tablatures/instruments/string-patterns.js");
17627
+
17628
+ function ViolinPatterns(plugin) {
17629
+ this.tuning = plugin._super.params.tuning;
17630
+
17631
+ if (!this.tuning) {
17632
+ this.tuning = ['G,', 'D', 'A', 'e'];
17633
+ }
17634
+
17635
+ plugin.tuning = this.tuning;
17636
+ this.strings = new StringPatterns(plugin);
17637
+ }
17638
+
17639
+ ViolinPatterns.prototype.notesToNumber = function (notes, graces) {
17640
+ var converter = this.strings;
17641
+ return converter.notesToNumber(notes, graces);
17642
+ };
17643
+
17644
+ ViolinPatterns.prototype.stringToPitch = function (stringNumber) {
17645
+ var converter = this.strings;
17646
+ return converter.stringToPitch(stringNumber);
17647
+ };
17648
+
17649
+ module.exports = ViolinPatterns;
17650
+
17651
+ /***/ }),
17652
+
17653
+ /***/ "./src/tablatures/tab-absolute-elements.js":
17654
+ /*!*************************************************!*\
17655
+ !*** ./src/tablatures/tab-absolute-elements.js ***!
17656
+ \*************************************************/
17657
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
17658
+
17659
+ /**
17660
+ * Tablature Absolute elements factory
17661
+ */
17662
+ var AbsoluteElement = __webpack_require__(/*! ../write/abc_absolute_element */ "./src/write/abc_absolute_element.js");
17663
+
17664
+ var RelativeElement = __webpack_require__(/*! ../write/abc_relative_element */ "./src/write/abc_relative_element.js");
17665
+
17666
+ var Transposer = __webpack_require__(/*! ./transposer */ "./src/tablatures/transposer.js");
17667
+
17668
+ function isObject(a) {
17669
+ return a != null && a.constructor === Object;
17670
+ }
17671
+
17672
+ function cloneObject(dest, src) {
17673
+ for (var prop in src) {
17674
+ if (src.hasOwnProperty(prop)) {
17675
+ if (!(Array.isArray(src[prop]) || isObject(src[prop]))) {
17676
+ dest[prop] = src[prop];
17677
+ }
17678
+ }
17679
+ }
17680
+ }
17681
+
17682
+ function cloneAbsolute(absSrc) {
17683
+ var returned = new AbsoluteElement('', 0, 0, '', 0);
17684
+ cloneObject(returned, absSrc);
17685
+ returned.top = 0;
17686
+ returned.bottom = -1;
17687
+
17688
+ if (absSrc.abcelem) {
17689
+ returned.abcelem = {};
17690
+ cloneObject(returned.abcelem, absSrc.abcelem);
17691
+ if (returned.abcelem.el_type === "note") returned.abcelem.el_type = 'tabNumber';
17692
+ }
17693
+
17694
+ return returned;
17695
+ }
17696
+
17697
+ function cloneAbsoluteAndRelatives(absSrc, plugin) {
17698
+ var returned = cloneAbsolute(absSrc);
17699
+
17700
+ if (plugin) {
17701
+ var children = absSrc.children; // proceed with relative as well
17702
+
17703
+ var first = true;
17704
+
17705
+ for (var ii = 0; ii < children.length; ii++) {
17706
+ var child = children[ii];
17707
+ var relative = new RelativeElement('', 0, 0, 0, '');
17708
+ cloneObject(relative, child);
17709
+ first = plugin.tablature.setRelative(child, relative, first);
17710
+ returned.children.push(relative);
17711
+ }
17712
+ }
17713
+
17714
+ return returned;
17715
+ }
17716
+
17717
+ function buildTabAbsolute(plugin, absX, relX) {
17718
+ var tabIcon = 'tab.tiny';
17719
+ var tabYPos = 7.5;
17720
+
17721
+ if (plugin.isTabBig) {
17722
+ tabIcon = 'tab.big';
17723
+ tabYPos = 10;
17724
+ }
17725
+
17726
+ var element = {
17727
+ el_type: "tab",
17728
+ icon: tabIcon,
17729
+ Ypos: tabYPos
17730
+ };
17731
+ var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0);
17732
+ tabAbsolute.x = absX;
17733
+ var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab");
17734
+ tabRelative.x = relX;
17735
+ tabAbsolute.children.push(tabRelative);
17736
+
17737
+ if (tabAbsolute.abcelem.el_type == 'tab') {
17738
+ tabRelative.pitch = tabYPos;
17739
+ }
17740
+
17741
+ return tabAbsolute;
17742
+ }
17743
+
17744
+ function lyricsDim(abs) {
17745
+ if (abs.extra) {
17746
+ for (var ii = 0; ii < abs.extra.length; ii++) {
17747
+ var extra = abs.extra[ii];
17748
+
17749
+ if (extra.type == 'lyric') {
17750
+ return {
17751
+ bottom: extra.bottom,
17752
+ height: extra.height
17753
+ };
17754
+ }
17755
+ }
17756
+ }
17757
+
17758
+ return null;
17759
+ }
17760
+
17761
+ function TabAbsoluteElements() {
17762
+ this.accidentals = null;
17763
+ }
17764
+
17765
+ function getInitialStaffSize(staffGroup) {
17766
+ var returned = 0;
17767
+
17768
+ for (var ii = 0; ii < staffGroup.length; ii++) {
17769
+ if (!staffGroup[ii].tabNameInfos) returned++;
17770
+ }
17771
+
17772
+ return returned;
17773
+ }
17774
+
17775
+ function buildRelativeTabNote(plugin, relX, def, curNote, isGrace) {
17776
+ var strNote = curNote.num;
17777
+
17778
+ if (curNote.note.quarter != null) {
17779
+ // add tab quarter => needs to string conversion then
17780
+ strNote = strNote.toString();
17781
+ strNote += curNote.note.quarter;
17782
+ }
17783
+
17784
+ var pitch = plugin.semantics.stringToPitch(curNote.str);
17785
+ def.notes.push({
17786
+ num: strNote,
17787
+ str: curNote.str,
17788
+ pitch: curNote.note.emit()
17789
+ });
17790
+ var opt = {
17791
+ type: 'tabNumber'
17792
+ };
17793
+ var tabNoteRelative = new RelativeElement(strNote, 0, 0, pitch + 0.3, opt);
17794
+ tabNoteRelative.x = relX;
17795
+ tabNoteRelative.isGrace = isGrace;
17796
+ tabNoteRelative.isAltered = curNote.note.isAltered;
17797
+ return tabNoteRelative;
17798
+ }
17799
+
17800
+ function getXGrace(abs, index) {
17801
+ var found = 0;
17802
+
17803
+ if (abs.extra) {
17804
+ for (var ii = 0; ii < abs.extra.length; ii++) {
17805
+ if (abs.extra[ii].c.indexOf('noteheads') >= 0) {
17806
+ if (found === index) {
17807
+ return abs.extra[ii].x + abs.extra[ii].w / 2;
17808
+ } else {
17809
+ found++;
17810
+ }
17811
+ }
17812
+ }
17813
+ }
17814
+
17815
+ return -1;
17816
+ }
17817
+
17818
+ function graceInRest(absElem) {
17819
+ if (absElem.abcelem) {
17820
+ var elem = absElem.abcelem;
17821
+
17822
+ if (elem.rest) {
17823
+ return elem.gracenotes;
17824
+ }
17825
+ }
17826
+
17827
+ return null;
17828
+ }
17829
+
17830
+ function checkTransposition(plugin, transposer, pitches, graceNotes) {
17831
+ if (plugin.transpose) {
17832
+ //transposer.transpose(plugin.transpose);
17833
+ for (var jj = 0; jj < pitches.length; jj++) {
17834
+ pitches[jj] = transposer.transposeNote(pitches[jj]);
17835
+ }
17836
+
17837
+ if (graceNotes) {
17838
+ for (var kk = 0; kk < graceNotes.length; kk++) {
17839
+ graceNotes[kk] = transposer.transposeNote(graceNotes[kk]);
17840
+ }
17841
+ }
17842
+ }
17843
+ }
17844
+
17845
+ function convertToNumber(plugin, pitches, graceNotes) {
17846
+ var tabPos = plugin.semantics.notesToNumber(pitches, graceNotes);
17847
+
17848
+ if (tabPos.error) {
17849
+ plugin._super.setError(tabPos.error);
17850
+
17851
+ return tabPos; // give up on error here
17852
+ }
17853
+
17854
+ if (tabPos.graces && tabPos.notes) {
17855
+ // add graces to last note in notes
17856
+ var posNote = tabPos.notes.length - 1;
17857
+ tabPos.notes[posNote].graces = tabPos.graces;
17858
+ }
17859
+
17860
+ return tabPos;
17861
+ }
17862
+
17863
+ function buildGraceRelativesForRest(plugin, abs, absChild, graceNotes, tabVoice) {
17864
+ for (var mm = 0; mm < graceNotes.length; mm++) {
17865
+ var defGrace = {
17866
+ el_type: "note",
17867
+ startChar: absChild.abcelem.startChar,
17868
+ endChar: absChild.abcelem.endChar,
17869
+ notes: [],
17870
+ grace: true
17871
+ };
17872
+ var graceX = getXGrace(absChild, mm);
17873
+ var curGrace = graceNotes[mm];
17874
+ var tabGraceRelative = buildRelativeTabNote(plugin, graceX, defGrace, curGrace, true);
17875
+ abs.children.push(tabGraceRelative);
17876
+ tabVoice.push(defGrace);
17877
+ }
17878
+ }
17879
+ /**
17880
+ * Build tab absolutes by scanning current staff line absolute array
17881
+ * @param {*} staffAbsolute
17882
+ */
17883
+
17884
+
17885
+ TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice, voiceIndex, staffIndex, keySig) {
17886
+ var staffSize = getInitialStaffSize(staffAbsolute);
17887
+ var source = staffAbsolute[staffIndex + voiceIndex];
17888
+ var dest = staffAbsolute[staffSize + staffIndex + voiceIndex];
17889
+ var transposer = null;
17890
+ var tabPos = null;
17891
+ var defNote = null;
17892
+
17893
+ if (source.children[0].abcelem.el_type != 'clef') {
17894
+ // keysig missing => provide one for tabs
17895
+ if (keySig != 'none') {
17896
+ source.children.splice(0, 0, keySig);
17897
+ }
17898
+ }
17899
+
17900
+ for (var ii = 0; ii < source.children.length; ii++) {
17901
+ var absChild = source.children[ii];
17902
+ var absX = absChild.x;
17903
+ var relX = absX; // if (absChild.children.length > 0) {
17904
+ // relX = absChild.children[0].x;
17905
+ // }
17906
+
17907
+ if (absChild.isClef) {
17908
+ dest.children.push(buildTabAbsolute(plugin, absX, relX));
17909
+ }
17910
+
17911
+ switch (absChild.type) {
17912
+ case 'staff-extra key-signature':
17913
+ // refresh key accidentals
17914
+ this.accidentals = absChild.abcelem.accidentals;
17915
+ plugin.semantics.strings.accidentals = this.accidentals;
17916
+
17917
+ if (plugin.transpose) {
17918
+ transposer = new Transposer(absChild.abcelem.accidentals, plugin.transpose);
17919
+ }
17920
+
17921
+ break;
17922
+
17923
+ case 'bar':
17924
+ var lastBar = false;
17925
+
17926
+ if (ii === source.children.length - 1) {
17927
+ // used for final line bar drawing
17928
+ // for multi tabs / multi staves
17929
+ lastBar = true;
17930
+ }
17931
+
17932
+ var cloned = cloneAbsoluteAndRelatives(absChild, plugin);
17933
+
17934
+ if (cloned.abcelem.barNumber) {
17935
+ delete cloned.abcelem.barNumber;
17936
+
17937
+ for (var bn = 0; bn < cloned.children.length; bn++) {
17938
+ if (cloned.children[bn].type === "barNumber") {
17939
+ cloned.children.splice(bn, 1);
17940
+ break;
17941
+ }
17942
+ }
17943
+ }
17944
+
17945
+ cloned.abcelem.lastBar = lastBar;
17946
+ dest.children.push(cloned);
17947
+ tabVoice.push({
17948
+ el_type: absChild.abcelem.el_type,
17949
+ type: absChild.abcelem.type,
17950
+ endChar: absChild.abcelem.endChar,
17951
+ startChar: absChild.abcelem.startChar,
17952
+ abselem: cloned
17953
+ });
17954
+ break;
17955
+
17956
+ case 'rest':
17957
+ var restGraces = graceInRest(absChild);
17958
+
17959
+ if (restGraces) {
17960
+ // check transpose
17961
+ checkTransposition(plugin, transposer, null, restGraces); // to number conversion
17962
+
17963
+ tabPos = convertToNumber(plugin, null, restGraces);
17964
+ if (tabPos.error) return; // build relative for grace
17965
+
17966
+ defGrace = {
17967
+ el_type: "note",
17968
+ startChar: absChild.abcelem.startChar,
17969
+ endChar: absChild.abcelem.endChar,
17970
+ notes: [],
17971
+ grace: true
17972
+ };
17973
+ buildGraceRelativesForRest(plugin, abs, absChild, tabPos.graces, tabVoice);
17974
+ }
17975
+
17976
+ break;
17977
+
17978
+ case 'note':
17979
+ var abs = cloneAbsolute(absChild);
17980
+ abs.x = absChild.heads[0].x + absChild.heads[0].w / 2; // center the number
17981
+
17982
+ abs.lyricDim = lyricsDim(absChild);
17983
+ var pitches = absChild.abcelem.pitches;
17984
+ var graceNotes = absChild.abcelem.gracenotes; // check transpose
17985
+
17986
+ abs.type = 'tabNumber';
17987
+ checkTransposition(plugin, transposer, pitches, graceNotes); // to number conversion
17988
+
17989
+ tabPos = convertToNumber(plugin, pitches, graceNotes);
17990
+ if (tabPos.error) return;
17991
+
17992
+ if (tabPos.graces) {
17993
+ // add graces to last note in notes
17994
+ var posNote = tabPos.notes.length - 1;
17995
+ tabPos.notes[posNote].graces = tabPos.graces;
17996
+ } // build relative
17997
+
17998
+
17999
+ defNote = {
18000
+ el_type: "note",
18001
+ startChar: absChild.abcelem.startChar,
18002
+ endChar: absChild.abcelem.endChar,
18003
+ notes: []
18004
+ };
18005
+
18006
+ for (var ll = 0; ll < tabPos.notes.length; ll++) {
18007
+ var curNote = tabPos.notes[ll];
18008
+
18009
+ if (curNote.graces) {
18010
+ for (var mm = 0; mm < curNote.graces.length; mm++) {
18011
+ var defGrace = {
18012
+ el_type: "note",
18013
+ startChar: absChild.abcelem.startChar,
18014
+ endChar: absChild.abcelem.endChar,
18015
+ notes: [],
18016
+ grace: true
18017
+ };
18018
+ var graceX = getXGrace(absChild, mm);
18019
+ var curGrace = curNote.graces[mm];
18020
+ var tabGraceRelative = buildRelativeTabNote(plugin, graceX, defGrace, curGrace, true);
18021
+ abs.children.push(tabGraceRelative);
18022
+ tabVoice.push(defGrace);
18023
+ }
18024
+ }
18025
+
18026
+ var tabNoteRelative = buildRelativeTabNote(plugin, abs.x + absChild.heads[ll].dx, defNote, curNote, false);
18027
+ abs.children.push(tabNoteRelative);
18028
+ }
18029
+
18030
+ defNote.abselem = abs;
18031
+ tabVoice.push(defNote);
18032
+ dest.children.push(abs);
18033
+ break;
18034
+ }
18035
+ }
18036
+ };
18037
+
18038
+ module.exports = TabAbsoluteElements;
18039
+
18040
+ /***/ }),
18041
+
18042
+ /***/ "./src/tablatures/tab-common.js":
18043
+ /*!**************************************!*\
18044
+ !*** ./src/tablatures/tab-common.js ***!
18045
+ \**************************************/
18046
+ /***/ (function(module) {
18047
+
18048
+ /**
18049
+ *
18050
+ * Common Class/Method available for all instruments
18051
+ *
18052
+ */
18053
+ function TabCommon(abcTune, tuneNumber, params) {
18054
+ this.tune = abcTune;
18055
+ this.params = params;
18056
+ this.tuneNumber = tuneNumber;
18057
+ this.inError = false;
18058
+ }
18059
+
18060
+ TabCommon.prototype.setError = function (error) {
18061
+ var tune = this.tune;
18062
+
18063
+ if (error) {
18064
+ this.error = error;
18065
+ this.inError = true;
18066
+
18067
+ if (tune.warnings) {
18068
+ tune.warnings.push(error);
18069
+ } else {
18070
+ tune.warnings = [error];
18071
+ }
18072
+ }
18073
+ };
18074
+
18075
+ module.exports = TabCommon;
18076
+
18077
+ /***/ }),
18078
+
18079
+ /***/ "./src/tablatures/tab-renderer.js":
18080
+ /*!****************************************!*\
18081
+ !*** ./src/tablatures/tab-renderer.js ***!
18082
+ \****************************************/
18083
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
18084
+
18085
+ /* eslint-disable no-debugger */
18086
+ var VoiceElement = __webpack_require__(/*! ../write/abc_voice_element */ "./src/write/abc_voice_element.js");
18087
+
18088
+ var TabAbsoluteElements = __webpack_require__(/*! ./tab-absolute-elements */ "./src/tablatures/tab-absolute-elements.js");
18089
+
18090
+ var spacing = __webpack_require__(/*! ../write/abc_spacing */ "./src/write/abc_spacing.js");
18091
+
18092
+ function initSpecialY() {
18093
+ return {
18094
+ tempoHeightAbove: 0,
18095
+ partHeightAbove: 0,
18096
+ volumeHeightAbove: 0,
18097
+ dynamicHeightAbove: 0,
18098
+ endingHeightAbove: 0,
18099
+ chordHeightAbove: 0,
18100
+ lyricHeightAbove: 0,
18101
+ lyricHeightBelow: 0,
18102
+ chordHeightBelow: 0,
18103
+ volumeHeightBelow: 0,
18104
+ dynamicHeightBelow: 0
18105
+ };
18106
+ }
18107
+
18108
+ function getLyricHeight(voice) {
18109
+ var maxLyricHeight = 0;
18110
+
18111
+ for (var ii = 0; ii < voice.children.length; ii++) {
18112
+ var curAbs = voice.children[ii];
18113
+
18114
+ if (curAbs.specialY) {
18115
+ if (curAbs.specialY.lyricHeightBelow > maxLyricHeight) {
18116
+ maxLyricHeight = curAbs.specialY.lyricHeightBelow;
18117
+ }
18118
+ }
18119
+ }
18120
+
18121
+ return maxLyricHeight; // add spacing
18122
+ }
18123
+
18124
+ function buildTabName(self, dest) {
18125
+ var stringSemantics = self.plugin.semantics.strings;
18126
+ var controller = self.renderer.controller;
18127
+ var textSize = controller.getTextSize;
18128
+ var tabName = stringSemantics.tabInfos(self.plugin);
18129
+ var size = textSize.calc(tabName, 'tablabelfont', 'text instrumentname');
18130
+ dest.tabNameInfos = {
18131
+ textSize: size,
18132
+ name: tabName
18133
+ };
18134
+ return size.height;
18135
+ }
18136
+ /**
18137
+ * Laying out tabs
18138
+ * @param {*} renderer
18139
+ * @param {*} line
18140
+ * @param {*} staffIndex
18141
+ * @param {*} tablatureLayout
18142
+ */
18143
+
18144
+
18145
+ function TabRenderer(plugin, renderer, line, staffIndex) {
18146
+ this.renderer = renderer;
18147
+ this.plugin = plugin;
18148
+ this.line = line;
18149
+ this.absolutes = new TabAbsoluteElements();
18150
+ this.staffIndex = staffIndex;
18151
+ this.tabStaff = {
18152
+ clef: {
18153
+ type: 'TAB'
18154
+ }
18155
+ };
18156
+ this.tabSize = plugin.linePitch * plugin.nbLines;
18157
+ }
18158
+
18159
+ function islastTabInStaff(index, staffGroup) {
18160
+ if (staffGroup[index].isTabStaff) {
18161
+ if (index === staffGroup.length - 1) return true;
18162
+
18163
+ if (staffGroup[index + 1].isTabStaff) {
18164
+ return false;
18165
+ } else {
18166
+ return true;
18167
+ }
18168
+ }
18169
+
18170
+ return false;
18171
+ }
18172
+
18173
+ function getStaffNumbers(staffs) {
18174
+ var nbStaffs = 0;
18175
+
18176
+ for (var ii = 0; ii < staffs.length; ii++) {
18177
+ if (!staffs[ii].isTabStaff) {
18178
+ nbStaffs++;
18179
+ }
18180
+ }
18181
+
18182
+ return nbStaffs;
18183
+ }
18184
+
18185
+ function getParentStaffIndex(staffs, index) {
18186
+ for (var ii = index; ii >= 0; ii--) {
18187
+ if (!staffs[ii].isTabStaff) {
18188
+ return ii;
18189
+ }
18190
+ }
18191
+
18192
+ return -1;
18193
+ }
18194
+
18195
+ function linkStaffAndTabs(staffs) {
18196
+ for (var ii = 0; ii < staffs.length; ii++) {
18197
+ if (staffs[ii].isTabStaff) {
18198
+ // link to parent staff
18199
+ var parentIndex = getParentStaffIndex(staffs, ii);
18200
+ staffs[ii].hasStaff = staffs[parentIndex];
18201
+ if (!staffs[parentIndex].hasTab) staffs[parentIndex].hasTab = [];
18202
+ staffs[parentIndex].hasTab.push(staffs[ii]);
18203
+ }
18204
+ }
18205
+ }
18206
+
18207
+ function isMultiVoiceSingleStaff(staffs, parent) {
18208
+ if (getStaffNumbers(staffs) === 1) {
18209
+ if (parent.voices.length > 1) return true;
18210
+ }
18211
+
18212
+ return false;
18213
+ }
18214
+
18215
+ function getNextTabPos(self, staffGroup) {
18216
+ var tabIndex = self.staffIndex;
18217
+ var startIndex = 0;
18218
+ var handledVoices = 0;
18219
+ var inProgress = true;
18220
+ var nbVoices = 0;
18221
+
18222
+ while (inProgress) {
18223
+ //for (var ii = 0; ii < staffGroup.length; ii++) {
18224
+ if (!staffGroup[startIndex]) return -1;
18225
+
18226
+ if (!staffGroup[startIndex].isTabStaff) {
18227
+ nbVoices = staffGroup[startIndex].voices.length; // get number of staff voices
18228
+ }
18229
+
18230
+ if (staffGroup[startIndex].isTabStaff) {
18231
+ handledVoices++;
18232
+
18233
+ if (islastTabInStaff(startIndex, staffGroup)) {
18234
+ if (handledVoices < nbVoices) return startIndex + 1;
18235
+ }
18236
+ } else {
18237
+ handledVoices = 0;
18238
+
18239
+ if (startIndex >= tabIndex) {
18240
+ if (startIndex + 1 == staffGroup.length) return startIndex + 1;
18241
+ if (!staffGroup[startIndex + 1].isTabStaff) return startIndex + 1;
18242
+ }
18243
+ }
18244
+
18245
+ startIndex++; // out of space case
18246
+
18247
+ if (startIndex > staffGroup.length) return -1;
18248
+ }
18249
+ }
18250
+
18251
+ function getLastStaff(staffs, lastTab) {
18252
+ for (var ii = lastTab; ii >= 0; ii--) {
18253
+ if (!staffs[ii].isTabStaff) {
18254
+ return staffs[ii];
18255
+ }
18256
+ }
18257
+
18258
+ return null;
18259
+ }
18260
+
18261
+ function checkVoiceKeySig(voices, ii) {
18262
+ var curVoice = voices[ii]; // on multivoice multistaff only the first voice has key signature
18263
+ // folling consecutive do not have one => we should provide the first voice key sig back then
18264
+
18265
+ var elem0 = curVoice.children[0].abcelem;
18266
+ if (elem0.el_type === 'clef') return null;
18267
+
18268
+ if (ii == 0) {
18269
+ // not found => clef=none case
18270
+ return 'none';
18271
+ }
18272
+
18273
+ return voices[ii - 1].children[0];
18274
+ }
18275
+
18276
+ TabRenderer.prototype.doLayout = function () {
18277
+ var staffs = this.line.staff;
18278
+
18279
+ if (staffs) {
18280
+ // give up on staffline=0 in key
18281
+ var firstStaff = staffs[0];
18282
+
18283
+ if (firstStaff) {
18284
+ if (firstStaff.clef) {
18285
+ if (firstStaff.clef.stafflines == 0) {
18286
+ this.plugin._super.setError("No tablatures when stafflines=0");
18287
+
18288
+ return;
18289
+ }
18290
+ }
18291
+ }
18292
+
18293
+ staffs.splice(staffs.length, 0, this.tabStaff);
18294
+ }
18295
+
18296
+ var staffGroup = this.line.staffGroup;
18297
+ var voices = staffGroup.voices;
18298
+ var firstVoice = voices[0]; // take lyrics into account if any
18299
+
18300
+ var lyricsHeight = getLyricHeight(firstVoice);
18301
+ var padd = 3;
18302
+ var prevIndex = this.staffIndex;
18303
+ var previousStaff = staffGroup.staffs[prevIndex];
18304
+ var tabTop = previousStaff.top + padd + lyricsHeight;
18305
+
18306
+ if (previousStaff.isTabStaff) {
18307
+ tabTop = previousStaff.top;
18308
+ }
18309
+
18310
+ var staffGroupInfos = {
18311
+ bottom: -1,
18312
+ isTabStaff: true,
18313
+ specialY: initSpecialY(),
18314
+ lines: this.plugin.nbLines,
18315
+ linePitch: this.plugin.linePitch,
18316
+ dy: 0.15,
18317
+ top: tabTop
18318
+ };
18319
+ var nextTabPos = getNextTabPos(this, staffGroup.staffs);
18320
+ if (nextTabPos === -1) return;
18321
+ staffGroupInfos.parentIndex = nextTabPos - 1;
18322
+ staffGroup.staffs.splice(nextTabPos, 0, staffGroupInfos); // staffGroup.staffs.push(staffGroupInfos);
18323
+
18324
+ staffGroup.height += this.tabSize + padd;
18325
+ var parentStaff = getLastStaff(staffGroup.staffs, nextTabPos);
18326
+ var nbVoices = 1;
18327
+
18328
+ if (isMultiVoiceSingleStaff(staffGroup.staffs, parentStaff)) {
18329
+ nbVoices = parentStaff.voices.length;
18330
+ } // build from staff
18331
+
18332
+
18333
+ this.tabStaff.voices = [];
18334
+
18335
+ for (var ii = 0; ii < nbVoices; ii++) {
18336
+ var tabVoice = new VoiceElement(0, 0);
18337
+ var nameHeight = buildTabName(this, tabVoice) / spacing.STEP;
18338
+ staffGroup.staffs[this.staffIndex].top += nameHeight;
18339
+ staffGroup.height += nameHeight * spacing.STEP;
18340
+ tabVoice.staff = staffGroupInfos;
18341
+ voices.splice(voices.length, 0, tabVoice);
18342
+ var keySig = checkVoiceKeySig(voices, ii + this.staffIndex);
18343
+ this.tabStaff.voices[ii] = [];
18344
+ this.absolutes.build(this.plugin, voices, this.tabStaff.voices[ii], ii, this.staffIndex, keySig);
18345
+ }
18346
+
18347
+ linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
18348
+ };
18349
+
18350
+ module.exports = TabRenderer;
18351
+
18352
+ /***/ }),
18353
+
18354
+ /***/ "./src/tablatures/transposer.js":
18355
+ /*!**************************************!*\
18356
+ !*** ./src/tablatures/transposer.js ***!
18357
+ \**************************************/
18358
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
18359
+
18360
+ /**
18361
+ *
18362
+ * generic transposer
18363
+ *
18364
+ */
18365
+ var TabNote = __webpack_require__(/*! ./instruments/tab-note */ "./src/tablatures/instruments/tab-note.js");
18366
+
18367
+ function buildAccEquiv(acc, note) {
18368
+ var equiv = note.getAccidentalEquiv();
18369
+
18370
+ if (acc.note.toUpperCase() == equiv.name.toUpperCase()) {
18371
+ equiv.isSharp = false;
18372
+ equiv.isFlat = false;
18373
+ return equiv;
18374
+ }
18375
+
18376
+ return note;
18377
+ }
18378
+
18379
+ function adjustNoteToKey(acc, note) {
18380
+ if (acc.acc == 'sharp') {
18381
+ if (note.isFlat) {
18382
+ return buildAccEquiv(acc, note);
18383
+ } else if (note.isSharp) {
18384
+ if (acc.note.toUpperCase() == note.name.toUpperCase()) {
18385
+ note.isSharp = false;
18386
+ note.isKeySharp = true;
18387
+ } else {
18388
+ if (acc.note.toUpperCase() == note.name.toUpperCase()) {
18389
+ note.natural = true;
18390
+ }
18391
+ }
18392
+ }
18393
+ } else if (acc.acc == 'flat') {
18394
+ if (note.isSharp) {
18395
+ return buildAccEquiv(acc, note);
18396
+ } else if (note.isFlat) {
18397
+ if (acc.note.toUpperCase() == note.name.toUpperCase()) {
18398
+ note.isFlat = false;
18399
+ note.isKeyFlat = true;
18400
+ }
18401
+ } else {
18402
+ if (acc.note.toUpperCase() == note.name.toUpperCase()) {
18403
+ note.natural = true;
18404
+ }
18405
+ }
18406
+ }
18407
+
18408
+ return note;
18409
+ }
18410
+
18411
+ function replaceNote(self, newNote, start, end) {
18412
+ if (self.lastEnd) {
18413
+ while (start > self.lastEnd) {
18414
+ self.updatedSrc.push(self.abcSrc[self.lastEnd]);
18415
+ self.lastEnd++;
18416
+ }
18417
+ }
18418
+
18419
+ var nNote = newNote.split('');
18420
+
18421
+ for (var ii = 0; ii < nNote.length; ii++) {
18422
+ self.updatedSrc.push(nNote[ii]);
18423
+ }
18424
+
18425
+ var curPos = start + ii;
18426
+
18427
+ while (end >= curPos) {
18428
+ self.updatedSrc.push(nNote[curPos]);
18429
+ curPos++;
18430
+ }
18431
+
18432
+ self.lastEnd = end;
18433
+ }
18434
+
18435
+ function checkKeys(self, note) {
18436
+ var accs = self.transposedKey;
18437
+
18438
+ for (var ii = 0; ii < accs.length; ii++) {
18439
+ note = adjustNoteToKey(accs[ii], note);
18440
+ }
18441
+
18442
+ return note;
18443
+ }
18444
+
18445
+ Transposer.prototype.transposeNote = function (note) {
18446
+ var returned = note;
18447
+ var curNote = new TabNote.TabNote(returned.name);
18448
+
18449
+ if (this.transposeBy > 0) {
18450
+ for (var ii = 0; ii < this.transposeBy; ii++) {
18451
+ curNote = checkKeys(this, curNote.nextNote());
18452
+ }
18453
+ } else if (this.transposeBy < 0) {
18454
+ for (var jj = this.transposeBy; jj < 0; jj++) {
18455
+ curNote = checkKeys(this, curNote.prevNote());
18456
+ }
18457
+ }
18458
+
18459
+ returned.name = curNote.emit();
18460
+ return returned;
18461
+ };
18462
+
18463
+ Transposer.prototype.upgradeSource = function (note, startChar, endChar) {
18464
+ var n = new TabNote.TabNote(note.name);
18465
+ var newNote = n.emit();
18466
+ replaceNote(this, newNote, startChar, endChar - 1);
18467
+ };
18468
+
18469
+ function Transposer(transposedKey, transposeBy) {
18470
+ this.transposeBy = transposeBy;
18471
+ this.transposedKey = transposedKey;
18472
+ this.lastEnd = this.kEnd + 1;
18473
+ }
18474
+
18475
+ module.exports = Transposer;
18476
+
18477
+ /***/ }),
18478
+
18479
+ /***/ "./src/write/abc_absolute_element.js":
18480
+ /*!*******************************************!*\
18481
+ !*** ./src/write/abc_absolute_element.js ***!
18482
+ \*******************************************/
18483
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
18484
+
18485
+ // abc_absolute_element.js: Definition of the AbsoluteElement class.
18486
+ var setClass = __webpack_require__(/*! ./set-class */ "./src/write/set-class.js");
18487
+
18488
+ var highlight = __webpack_require__(/*! ./highlight */ "./src/write/highlight.js");
18489
+
18490
+ var unhighlight = __webpack_require__(/*! ./unhighlight */ "./src/write/unhighlight.js"); // Everything that is placed in the SVG is first created as an absolute element. This is one unit of graphic information.
18491
+ // That is, it embodies a concept: a clef, a time signature, a bar line,etc. or most complexly:
18492
+ // a note with its accidental, grace note, chord symbol, trill, stem, eighth flags, etc.
18493
+ // In the largest sense, these are placed on the page at a particular place that is determined during the layout phase.
18494
+ // This object doesn't contain any of the drawing information, though. That information is contained in an array of
18495
+ // RelativeElements as the "children" of this class.
18496
+ // During the layout phase, the width of all the children is calculated and the X coordinate of the absolute element is set.
18497
+ //
18498
+ // So, after the AbsoluteElement is placed, then its children can be placed relative to that. There are different types of
18499
+ // relative elements that are placed with different rules:
18500
+ // 1) Fixed - these elements don't move relative to the absolute element's coordinates. These are things like the notehead,
18501
+ // any ledger lines, accidentals, etc.
18502
+ // 2) Slotted - these elements can move vertically and don't get Y coordinates until after the absolute element is placed.
18503
+ // These are things like the chord symbol, many decorations, the lyrics, etc.
18504
+ //
18505
+ // Relative elements are also classified by how they are related. This could be:
16421
18506
  // 1) Increases the absolute element's width to the left. This doesn't change the center point of
16422
18507
  // the absolute element, so adding a sharp to the note won't move it to the right. However, if the elements
16423
18508
  // are close together then this enforces a minimum distance.
@@ -16541,9 +18626,10 @@ AbsoluteElement.prototype.addRight = function (right) {
16541
18626
 
16542
18627
  if (right.bottom !== undefined) {
16543
18628
  if (this.fixed.b === undefined) this.fixed.b = right.bottom;else this.fixed.b = Math.min(this.fixed.b, right.bottom);
16544
- }
18629
+ } // if (isNaN(this.fixed.t) || isNaN(this.fixed.b))
18630
+ // debugger;
18631
+
16545
18632
 
16546
- if (isNaN(this.fixed.t) || isNaN(this.fixed.b)) debugger;
16547
18633
  if (right.dx + right.w > this.w) this.w = right.dx + right.w;
16548
18634
  this.right[this.right.length] = right;
16549
18635
 
@@ -19058,7 +21144,7 @@ var GetTextSize = __webpack_require__(/*! ./get-text-size */ "./src/write/get-te
19058
21144
 
19059
21145
  var draw = __webpack_require__(/*! ./draw/draw */ "./src/write/draw/draw.js");
19060
21146
 
19061
- var calcHeight = __webpack_require__(/*! ./calcHeight */ "./src/write/calcHeight.js");
21147
+ var tablatures = __webpack_require__(/*! ../api/abc_tablatures */ "./src/api/abc_tablatures.js");
19062
21148
  /**
19063
21149
  * @class
19064
21150
  * Controls the engraving process, from ABCJS Abstract Syntax Tree (ABCJS AST) to rendered score sheet
@@ -19132,7 +21218,7 @@ EngraverController.prototype.reset = function () {
19132
21218
  */
19133
21219
 
19134
21220
 
19135
- EngraverController.prototype.engraveABC = function (abctunes, tuneNumber) {
21221
+ EngraverController.prototype.engraveABC = function (abctunes, tuneNumber, lineOffset) {
19136
21222
  if (abctunes[0] === undefined) {
19137
21223
  abctunes = [abctunes];
19138
21224
  }
@@ -19143,7 +21229,7 @@ EngraverController.prototype.engraveABC = function (abctunes, tuneNumber) {
19143
21229
  if (tuneNumber === undefined) tuneNumber = i;
19144
21230
  this.getFontAndAttr = new GetFontAndAttr(abctunes[i].formatting, this.classes);
19145
21231
  this.getTextSize = new GetTextSize(this.getFontAndAttr, this.renderer.paper);
19146
- this.engraveTune(abctunes[i], tuneNumber);
21232
+ this.engraveTune(abctunes[i], tuneNumber, lineOffset);
19147
21233
  }
19148
21234
  };
19149
21235
  /**
@@ -19215,6 +21301,7 @@ EngraverController.prototype.getMeasureWidths = function (abcTune) {
19215
21301
 
19216
21302
  EngraverController.prototype.setupTune = function (abcTune, tuneNumber) {
19217
21303
  this.classes.reset();
21304
+ if (abcTune.formatting.jazzchords !== undefined) this.jazzchords = abcTune.formatting.jazzchords;
19218
21305
  this.renderer.newTune(abcTune);
19219
21306
  this.engraver = new AbstractEngraver(this.getTextSize, tuneNumber, {
19220
21307
  bagpipes: abcTune.formatting.bagpipes,
@@ -19275,14 +21362,19 @@ EngraverController.prototype.constructTuneElements = function (abcTune) {
19275
21362
  abcTune.bottomText = new BottomText(abcTune.metaText, this.width, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize);
19276
21363
  };
19277
21364
 
19278
- EngraverController.prototype.engraveTune = function (abcTune, tuneNumber) {
21365
+ EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOffset) {
19279
21366
  var scale = this.setupTune(abcTune, tuneNumber); // Create all of the element objects that will appear on the page.
19280
21367
 
19281
21368
  this.constructTuneElements(abcTune); // Do all the positioning, both horizontally and vertically
19282
21369
 
19283
- var maxWidth = layout(this.renderer, abcTune, this.width, this.space); // Do all the writing to the SVG
21370
+ var maxWidth = layout(this.renderer, abcTune, this.width, this.space); // Deal with tablature for staff
21371
+
21372
+ if (abcTune.tablatures) {
21373
+ tablatures.layoutTablatures(this.renderer, abcTune);
21374
+ } // Do all the writing to the SVG
19284
21375
 
19285
- var ret = draw(this.renderer, this.classes, abcTune, this.width, maxWidth, this.responsive, scale, this.selectTypes, tuneNumber);
21376
+
21377
+ var ret = draw(this.renderer, this.classes, abcTune, this.width, maxWidth, this.responsive, scale, this.selectTypes, tuneNumber, lineOffset);
19286
21378
  this.staffgroups = ret.staffgroups;
19287
21379
  this.selectables = ret.selectables;
19288
21380
  setupSelection(this);
@@ -19654,6 +21746,16 @@ var glyphs = {
19654
21746
  w: 21,
19655
21747
  h: 14.97
19656
21748
  },
21749
+ 'tab.big': {
21750
+ d: [['M', 20.16, -21.66], ['c', 0.24, -0.09, 0.66, 0.09, 0.78, 0.36], ['c', 0.09, 0.21, 0.09, 0.24, -0.18, 0.54], ['c', -0.78, 0.81, -1.86, 1.44, -2.94, 1.71], ['c', -0.87, 0.24, -1.71, 0.24, -2.55, 0.03], ['l', -0.06, -0.03], ['l', -0.18, 0.99], ['c', -0.33, 1.98, -0.75, 4.26, -0.96, 5.04], ['c', -0.42, 1.65, -1.26, 3.18, -2.28, 4.14], ['c', -0.57, 0.57, -1.17, 0.90, -1.86, 1.08], ['c', -0.18, 0.06, -0.33, 0.06, -0.66, 0.06], ['c', -0.54, 0.00, -0.78, -0.03, -1.23, -0.27], ['c', -0.39, -0.18, -0.66, -0.39, -1.38, -0.99], ['c', -0.30, -0.24, -0.66, -0.51, -0.75, -0.57], ['c', -0.21, -0.15, -0.27, -0.24, -0.24, -0.45], ['c', 0.06, -0.27, 0.36, -0.60, 0.60, -0.66], ['c', 0.18, -0.03, 0.33, 0.06, 0.90, 0.57], ['c', 0.48, 0.42, 0.72, 0.57, 0.93, 0.69], ['c', 0.66, 0.33, 1.38, 0.21, 1.95, -0.36], ['c', 0.63, -0.60, 1.05, -1.62, 1.23, -3.00], ['c', 0.03, -0.18, 0.09, -0.66, 0.09, -1.11], ['c', 0.09, -1.56, 0.33, -3.81, 0.57, -5.49], ['c', 0.06, -0.33, 0.09, -0.63, 0.09, -0.63], ['c', -0.03, -0.03, -0.81, -0.12, -1.02, -0.12], ['c', -0.57, 0.00, -1.32, 0.12, -1.80, 0.33], ['c', -0.87, 0.30, -1.35, 0.78, -1.50, 1.41], ['c', -0.18, 0.63, 0.09, 1.26, 0.66, 1.65], ['c', 0.12, 0.06, 0.15, 0.12, 0.18, 0.24], ['c', 0.09, 0.27, 0.06, 0.57, -0.09, 0.75], ['c', -0.03, 0.06, -0.12, 0.09, -0.27, 0.15], ['c', -0.72, 0.21, -1.44, 0.15, -2.10, -0.18], ['c', -0.54, -0.27, -0.96, -0.66, -1.20, -1.14], ['c', -0.39, -0.75, -0.33, -1.74, 0.15, -2.52], ['c', 0.27, -0.42, 0.84, -0.93, 1.41, -1.23], ['c', 1.17, -0.57, 2.88, -0.90, 4.80, -0.90], ['c', 0.69, 0.00, 0.78, 0.00, 1.08, 0.06], ['c', 0.45, 0.09, 1.11, 0.30, 2.07, 0.60], ['c', 1.47, 0.48, 1.83, 0.57, 2.55, 0.54], ['c', 1.02, -0.06, 2.04, -0.45, 2.94, -1.11], ['c', 0.12, -0.09, 0.24, -0.18, 0.27, -0.18], ['z'], ['m', -5.88, 13.05], ['c', 0.21, -0.03, 0.81, 0.00, 1.08, 0.06], ['c', 0.48, 0.12, 0.90, 0.42, 0.99, 0.69], ['c', 0.03, 0.09, 0.03, 0.15, 0.00, 0.27], ['c', 0.00, 0.09, -0.03, 0.57, -0.06, 1.08], ['c', -0.09, 2.19, -0.24, 5.76, -0.39, 8.28], ['c', -0.06, 1.53, -0.06, 1.77, 0.03, 2.01], ['c', 0.09, 0.18, 0.15, 0.24, 0.30, 0.30], ['c', 0.24, 0.12, 0.54, 0.06, 1.23, -0.27], ['c', 0.57, -0.27, 0.66, -0.30, 0.75, -0.24], ['c', 0.09, 0.06, 0.18, 0.30, 0.18, 0.45], ['c', 0.00, 0.33, -0.15, 0.51, -0.45, 0.63], ['c', -0.12, 0.03, -0.39, 0.15, -0.60, 0.27], ['c', -1.17, 0.60, -1.38, 0.69, -1.80, 0.72], ['c', -0.45, 0.03, -0.78, -0.09, -1.08, -0.39], ['c', -0.39, -0.42, -0.66, -1.20, -1.02, -3.12], ['c', -0.24, -1.23, -0.36, -2.07, -0.54, -3.75], ['l', 0.00, -0.18], ['l', -0.36, 0.45], ['c', -0.60, 0.75, -1.32, 1.59, -1.95, 2.25], ['c', -0.15, 0.18, -0.27, 0.30, -0.27, 0.33], ['c', 0.00, 0.00, 0.06, 0.09, 0.15, 0.18], ['c', 0.24, 0.33, 0.60, 0.57, 1.05, 0.69], ['c', 0.18, 0.06, 0.30, 0.06, 0.69, 0.06], ['l', 0.48, 0.03], ['l', 0.06, 0.12], ['c', 0.15, 0.27, 0.03, 0.72, -0.21, 0.90], ['c', -0.18, 0.12, -0.93, 0.27, -1.41, 0.27], ['c', -0.84, 0.00, -1.59, -0.30, -1.98, -0.84], ['l', -0.12, -0.15], ['l', -0.45, 0.42], ['c', -0.99, 0.87, -1.53, 1.32, -2.16, 1.74], ['c', -0.78, 0.51, -1.50, 0.84, -2.10, 0.93], ['c', -0.69, 0.12, -1.20, 0.03, -1.95, -0.42], ['c', -0.21, -0.12, -0.51, -0.27, -0.66, -0.36], ['c', -0.24, -0.12, -0.30, -0.18, -0.33, -0.24], ['c', -0.12, -0.27, 0.15, -0.78, 0.45, -0.93], ['c', 0.24, -0.12, 0.33, -0.09, 0.90, 0.18], ['c', 0.60, 0.30, 0.84, 0.39, 1.20, 0.36], ['c', 0.87, -0.09, 1.77, -0.69, 3.24, -2.31], ['c', 2.67, -2.85, 4.59, -5.94, 5.70, -9.15], ['c', 0.15, -0.45, 0.24, -0.63, 0.42, -0.81], ['c', 0.21, -0.24, 0.60, -0.45, 0.99, -0.51], ['z'], ['m', -3.99, 16.05], ['c', 0.18, 0.00, 0.69, -0.03, 1.17, 0.00], ['c', 3.27, 0.03, 5.37, 0.75, 6.00, 2.07], ['c', 0.45, 0.99, 0.12, 2.40, -0.81, 3.42], ['c', -0.24, 0.27, -0.57, 0.57, -0.84, 0.75], ['c', -0.09, 0.06, -0.18, 0.09, -0.18, 0.12], ['c', 0.00, 0.00, 0.18, 0.03, 0.42, 0.09], ['c', 1.23, 0.30, 2.01, 0.81, 2.37, 1.59], ['c', 0.27, 0.54, 0.30, 1.32, 0.09, 2.10], ['c', -0.12, 0.36, -0.45, 1.05, -0.69, 1.35], ['c', -0.87, 1.17, -2.10, 1.92, -3.54, 2.25], ['c', -0.36, 0.06, -0.48, 0.06, -0.96, 0.06], ['c', -0.45, 0.00, -0.66, 0.00, -0.84, -0.03], ['c', -0.84, -0.18, -1.47, -0.51, -2.07, -1.11], ['c', -0.33, -0.33, -0.45, -0.51, -0.45, -0.63], ['c', 0.00, -0.06, 0.03, -0.15, 0.06, -0.24], ['c', 0.18, -0.33, 0.69, -0.60, 0.93, -0.48], ['c', 0.03, 0.03, 0.15, 0.12, 0.27, 0.24], ['c', 0.39, 0.42, 0.99, 0.57, 1.62, 0.45], ['c', 1.05, -0.21, 1.98, -1.02, 2.31, -2.01], ['c', 0.48, -1.53, -0.48, -2.55, -2.58, -2.67], ['c', -0.21, 0.00, -0.36, -0.03, -0.42, -0.06], ['c', -0.15, -0.09, -0.21, -0.51, -0.06, -0.78], ['c', 0.12, -0.27, 0.24, -0.33, 0.60, -0.36], ['c', 0.57, -0.06, 1.11, -0.42, 1.50, -0.99], ['c', 0.48, -0.72, 0.54, -1.59, 0.18, -2.31], ['c', -0.12, -0.21, -0.45, -0.54, -0.69, -0.69], ['c', -0.33, -0.21, -0.93, -0.45, -1.35, -0.51], ['l', -0.12, -0.03], ['l', -0.06, 0.48], ['c', -0.54, 2.94, -1.14, 6.24, -1.29, 6.75], ['c', -0.33, 1.35, -0.93, 2.61, -1.65, 3.60], ['c', -0.30, 0.36, -0.81, 0.90, -1.14, 1.14], ['c', -0.30, 0.24, -0.84, 0.48, -1.14, 0.57], ['c', -0.33, 0.09, -0.96, 0.09, -1.26, 0.03], ['c', -0.45, -0.12, -0.87, -0.39, -1.53, -0.96], ['c', -0.24, -0.15, -0.51, -0.39, -0.63, -0.48], ['c', -0.30, -0.21, -0.33, -0.33, -0.21, -0.63], ['c', 0.12, -0.18, 0.27, -0.36, 0.42, -0.45], ['c', 0.27, -0.12, 0.36, -0.09, 0.87, 0.33], ['c', 0.78, 0.60, 1.08, 0.75, 1.65, 0.72], ['c', 0.45, -0.03, 0.81, -0.21, 1.17, -0.54], ['c', 0.87, -0.90, 1.38, -2.85, 1.38, -5.37], ['c', 0.00, -0.60, 0.03, -1.11, 0.12, -2.04], ['c', 0.06, -0.69, 0.24, -2.01, 0.33, -2.58], ['c', 0.06, -0.24, 0.06, -0.42, 0.06, -0.42], ['c', 0.00, 0.00, -0.12, 0.03, -0.21, 0.09], ['c', -1.44, 0.57, -2.16, 1.65, -1.74, 2.55], ['c', 0.09, 0.15, 0.18, 0.24, 0.27, 0.33], ['c', 0.24, 0.21, 0.30, 0.27, 0.33, 0.39], ['c', 0.06, 0.24, 0.00, 0.63, -0.15, 0.78], ['c', -0.09, 0.12, -0.54, 0.21, -0.96, 0.24], ['c', -1.02, 0.03, -2.01, -0.48, -2.43, -1.32], ['c', -0.21, -0.45, -0.27, -0.90, -0.15, -1.44], ['c', 0.06, -0.27, 0.21, -0.66, 0.39, -0.93], ['c', 0.87, -1.29, 3.00, -2.22, 5.64, -2.43], ['z']],
21751
+ w: 19.643,
21752
+ h: 43.325
21753
+ },
21754
+ 'tab.tiny': {
21755
+ d: [['M', 16.02, -17.25], ['c', 0.12, -0.09, 0.15, -0.09, 0.27, -0.09], ['c', 0.21, 0.03, 0.51, 0.30, 0.51, 0.45], ['c', 0.00, 0.06, -0.12, 0.18, -0.30, 0.36], ['c', -1.11, 1.08, -2.55, 1.59, -3.84, 1.41], ['c', -0.15, -0.03, -0.33, -0.06, -0.39, -0.09], ['c', -0.06, -0.03, -0.09, -0.03, -0.12, -0.03], ['c', 0.00, 0.00, -0.06, 0.42, -0.15, 0.93], ['c', -0.33, 2.01, -0.66, 3.69, -0.84, 4.26], ['c', -0.42, 1.41, -1.23, 2.67, -2.16, 3.33], ['c', -0.27, 0.18, -0.75, 0.42, -0.99, 0.48], ['c', -0.30, 0.09, -0.72, 0.09, -1.02, 0.06], ['c', -0.45, -0.09, -0.84, -0.33, -1.53, -0.90], ['c', -0.21, -0.18, -0.51, -0.39, -0.63, -0.48], ['c', -0.27, -0.21, -0.30, -0.24, -0.30, -0.36], ['c', 0.00, -0.12, 0.09, -0.36, 0.18, -0.45], ['c', 0.09, -0.09, 0.27, -0.18, 0.36, -0.18], ['c', 0.12, 0.00, 0.30, 0.12, 0.66, 0.45], ['c', 0.57, 0.51, 0.87, 0.69, 1.23, 0.72], ['c', 0.93, 0.06, 1.68, -0.78, 1.98, -2.37], ['c', 0.09, -0.39, 0.15, -0.75, 0.18, -1.53], ['c', 0.06, -0.99, 0.24, -2.79, 0.42, -4.05], ['c', 0.03, -0.30, 0.06, -0.57, 0.06, -0.60], ['c', 0.00, -0.06, -0.03, -0.09, -0.15, -0.12], ['c', -0.90, -0.18, -2.13, 0.06, -2.76, 0.57], ['c', -0.36, 0.30, -0.51, 0.60, -0.51, 1.02], ['c', 0.00, 0.45, 0.15, 0.75, 0.48, 0.99], ['c', 0.06, 0.06, 0.15, 0.18, 0.18, 0.24], ['c', 0.12, 0.24, 0.03, 0.63, -0.15, 0.69], ['c', -0.24, 0.12, -0.60, 0.15, -0.90, 0.15], ['c', -0.36, -0.03, -0.57, -0.09, -0.87, -0.24], ['c', -0.78, -0.36, -1.23, -1.11, -1.20, -1.92], ['c', 0.12, -1.53, 1.74, -2.49, 4.62, -2.70], ['c', 1.20, -0.09, 1.47, -0.03, 3.33, 0.57], ['c', 0.90, 0.30, 1.14, 0.36, 1.56, 0.39], ['c', 0.45, 0.00, 0.93, -0.06, 1.38, -0.21], ['c', 0.51, -0.18, 0.81, -0.33, 1.41, -0.75], ['z'], ['m', -4.68, 10.38], ['c', 0.39, -0.06, 0.84, 0.00, 1.20, 0.15], ['c', 0.24, 0.12, 0.36, 0.21, 0.45, 0.36], ['l', 0.09, 0.09], ['l', -0.06, 1.41], ['c', -0.09, 2.19, -0.18, 3.96, -0.27, 5.49], ['c', -0.03, 0.78, -0.06, 1.59, -0.06, 1.86], ['c', 0.00, 0.42, 0.00, 0.48, 0.06, 0.57], ['c', 0.06, 0.18, 0.18, 0.24, 0.36, 0.27], ['c', 0.18, 0.00, 0.39, -0.06, 0.84, -0.27], ['c', 0.45, -0.21, 0.54, -0.24, 0.63, -0.18], ['c', 0.12, 0.12, 0.15, 0.54, 0.03, 0.69], ['c', -0.03, 0.03, -0.15, 0.12, -0.27, 0.18], ['c', -0.15, 0.03, -0.30, 0.12, -0.36, 0.15], ['c', -0.87, 0.45, -1.02, 0.51, -1.26, 0.57], ['c', -0.33, 0.09, -0.60, 0.06, -0.84, -0.06], ['c', -0.42, -0.18, -0.63, -0.60, -0.87, -1.44], ['c', -0.30, -1.23, -0.57, -2.97, -0.66, -4.08], ['c', 0.00, -0.18, -0.03, -0.30, -0.03, -0.33], ['l', -0.06, 0.06], ['c', -0.18, 0.27, -1.11, 1.38, -1.68, 2.01], ['l', -0.33, 0.33], ['l', 0.06, 0.09], ['c', 0.06, 0.15, 0.27, 0.33, 0.48, 0.42], ['c', 0.27, 0.18, 0.51, 0.24, 0.96, 0.27], ['l', 0.39, 0.00], ['l', 0.03, 0.12], ['c', 0.12, 0.21, 0.03, 0.57, -0.15, 0.69], ['c', -0.03, 0.03, -0.21, 0.09, -0.36, 0.15], ['c', -0.27, 0.06, -0.39, 0.06, -0.75, 0.06], ['c', -0.48, 0.00, -0.75, -0.03, -1.08, -0.21], ['c', -0.21, -0.12, -0.51, -0.36, -0.57, -0.48], ['l', -0.03, -0.09], ['l', -0.39, 0.36], ['c', -1.47, 1.35, -2.49, 1.98, -3.42, 2.13], ['c', -0.54, 0.09, -0.96, -0.03, -1.62, -0.39], ['c', -0.21, -0.15, -0.45, -0.27, -0.54, -0.30], ['c', -0.18, -0.09, -0.21, -0.21, -0.12, -0.45], ['c', 0.06, -0.27, 0.33, -0.48, 0.54, -0.48], ['c', 0.03, 0.00, 0.27, 0.09, 0.48, 0.21], ['c', 0.48, 0.24, 0.69, 0.27, 0.99, 0.27], ['c', 0.60, -0.06, 1.17, -0.42, 2.10, -1.35], ['c', 2.22, -2.22, 4.02, -4.98, 4.95, -7.59], ['c', 0.21, -0.57, 0.30, -0.78, 0.48, -0.93], ['c', 0.15, -0.15, 0.42, -0.27, 0.66, -0.33], ['z'], ['m', -3.06, 12.84], ['c', 0.27, -0.03, 1.68, 0.00, 2.01, 0.03], ['c', 1.92, 0.18, 3.15, 0.69, 3.63, 1.50], ['c', 0.18, 0.33, 0.24, 0.51, 0.21, 0.93], ['c', 0.00, 0.45, -0.06, 0.72, -0.24, 1.11], ['c', -0.24, 0.51, -0.69, 1.02, -1.17, 1.35], ['c', -0.21, 0.15, -0.21, 0.15, -0.12, 0.18], ['c', 0.72, 0.15, 1.11, 0.30, 1.50, 0.57], ['c', 0.39, 0.24, 0.63, 0.57, 0.75, 0.96], ['c', 0.09, 0.30, 0.09, 0.96, 0.00, 1.29], ['c', -0.15, 0.57, -0.39, 1.05, -0.78, 1.50], ['c', -0.66, 0.75, -1.62, 1.32, -2.61, 1.53], ['c', -0.27, 0.06, -0.42, 0.06, -0.84, 0.06], ['c', -0.48, 0.00, -0.57, 0.00, -0.81, -0.06], ['c', -0.60, -0.18, -1.05, -0.42, -1.47, -0.81], ['c', -0.36, -0.39, -0.42, -0.51, -0.30, -0.75], ['c', 0.12, -0.21, 0.39, -0.39, 0.60, -0.39], ['c', 0.09, 0.00, 0.15, 0.03, 0.33, 0.18], ['c', 0.12, 0.12, 0.27, 0.24, 0.36, 0.27], ['c', 0.96, 0.48, 2.46, -0.33, 2.82, -1.50], ['c', 0.24, -0.81, -0.03, -1.44, -0.69, -1.77], ['c', -0.39, -0.21, -1.02, -0.33, -1.53, -0.33], ['c', -0.18, 0.00, -0.21, 0.00, -0.27, -0.09], ['c', -0.06, -0.09, -0.06, -0.30, -0.03, -0.48], ['c', 0.06, -0.18, 0.18, -0.36, 0.33, -0.36], ['c', 0.39, -0.06, 0.51, -0.09, 0.72, -0.18], ['c', 0.69, -0.36, 1.11, -1.23, 0.99, -2.01], ['c', -0.09, -0.51, -0.42, -0.90, -0.93, -1.17], ['c', -0.24, -0.12, -0.60, -0.27, -0.87, -0.30], ['c', -0.09, -0.03, -0.09, -0.03, -0.12, 0.12], ['c', 0.00, 0.09, -0.21, 1.11, -0.42, 2.25], ['c', -0.66, 3.75, -0.72, 3.99, -1.26, 5.07], ['c', -0.90, 1.89, -2.25, 2.85, -3.48, 2.61], ['c', -0.39, -0.09, -0.69, -0.27, -1.38, -0.84], ['c', -0.63, -0.51, -0.63, -0.48, -0.63, -0.60], ['c', 0.00, -0.18, 0.18, -0.48, 0.39, -0.57], ['c', 0.21, -0.12, 0.30, -0.09, 0.81, 0.33], ['c', 0.15, 0.15, 0.39, 0.30, 0.54, 0.36], ['c', 0.18, 0.12, 0.27, 0.12, 0.48, 0.15], ['c', 0.99, 0.06, 1.71, -0.78, 2.04, -2.46], ['c', 0.12, -0.66, 0.18, -1.14, 0.21, -2.22], ['c', 0.03, -1.23, 0.12, -2.25, 0.36, -3.63], ['c', 0.03, -0.24, 0.06, -0.45, 0.06, -0.48], ['c', -0.06, -0.03, -0.66, 0.27, -0.90, 0.42], ['c', -0.06, 0.06, -0.21, 0.18, -0.33, 0.30], ['c', -0.57, 0.57, -0.60, 1.35, -0.06, 1.74], ['c', 0.18, 0.12, 0.24, 0.24, 0.21, 0.51], ['c', -0.03, 0.30, -0.15, 0.42, -0.57, 0.48], ['c', -1.11, 0.24, -2.22, -0.42, -2.43, -1.38], ['c', -0.09, -0.45, 0.03, -1.02, 0.30, -1.47], ['c', 0.18, -0.24, 0.60, -0.63, 0.90, -0.84], ['c', 0.90, -0.60, 2.28, -1.02, 3.69, -1.11], ['z']],
21756
+ w: 15.709,
21757
+ h: 34.656
21758
+ },
19657
21759
  'timesig.common': {
19658
21760
  d: [['M', 6.66, -7.83], ['c', 0.72, -0.06, 1.41, -0.03, 1.98, 0.09], ['c', 1.20, 0.27, 2.34, 0.96, 3.09, 1.92], ['c', 0.63, 0.81, 1.08, 1.86, 1.14, 2.73], ['c', 0.06, 1.02, -0.51, 1.92, -1.44, 2.22], ['c', -0.24, 0.09, -0.30, 0.09, -0.63, 0.09], ['c', -0.33, 0.00, -0.42, 0.00, -0.63, -0.06], ['c', -0.66, -0.24, -1.14, -0.63, -1.41, -1.20], ['c', -0.15, -0.30, -0.21, -0.51, -0.24, -0.90], ['c', -0.06, -1.08, 0.57, -2.04, 1.56, -2.37], ['c', 0.18, -0.06, 0.27, -0.06, 0.63, -0.06], ['l', 0.45, 0.00], ['c', 0.06, 0.03, 0.09, 0.03, 0.09, 0.00], ['c', 0.00, 0.00, -0.09, -0.12, -0.24, -0.27], ['c', -1.02, -1.11, -2.55, -1.68, -4.08, -1.50], ['c', -1.29, 0.15, -2.04, 0.69, -2.40, 1.74], ['c', -0.36, 0.93, -0.42, 1.89, -0.42, 5.37], ['c', 0.00, 2.97, 0.06, 3.96, 0.24, 4.77], ['c', 0.24, 1.08, 0.63, 1.68, 1.41, 2.07], ['c', 0.81, 0.39, 2.16, 0.45, 3.18, 0.09], ['c', 1.29, -0.45, 2.37, -1.53, 3.03, -2.97], ['c', 0.15, -0.33, 0.33, -0.87, 0.39, -1.17], ['c', 0.09, -0.24, 0.15, -0.36, 0.30, -0.39], ['c', 0.21, -0.03, 0.42, 0.15, 0.39, 0.36], ['c', -0.06, 0.39, -0.42, 1.38, -0.69, 1.89], ['c', -0.96, 1.80, -2.49, 2.94, -4.23, 3.18], ['c', -0.99, 0.12, -2.58, -0.06, -3.63, -0.45], ['c', -0.96, -0.36, -1.71, -0.84, -2.40, -1.50], ['c', -1.11, -1.11, -1.80, -2.61, -2.04, -4.56], ['c', -0.06, -0.60, -0.06, -2.01, 0.00, -2.61], ['c', 0.24, -1.95, 0.90, -3.45, 2.01, -4.56], ['c', 0.69, -0.66, 1.44, -1.11, 2.37, -1.47], ['c', 0.63, -0.24, 1.47, -0.42, 2.22, -0.48], ['z']],
19659
21761
  w: 13.038,
@@ -20023,11 +22125,14 @@ var RelativeElement = function RelativeElement(c, dx, w, pitch, opt) {
20023
22125
  RelativeElement.prototype.getChordDim = function () {
20024
22126
  if (this.type === "debug") return null;
20025
22127
  if (!this.chordHeightAbove && !this.chordHeightBelow) return null; // Chords are centered, annotations are left justified.
22128
+ // NOTE: the font reports extra space to the left and right anyway, so there is a built in margin.
20026
22129
  // We add a little margin so that items can't touch - we use half the font size as the margin, so that is 1/4 on each side.
20027
22130
  // if there is only one character that we're printing, use half of that margin.
22131
+ // var margin = this.dim.font.size/4;
22132
+ // if (this.c.length === 1)
22133
+ // margin = margin / 2;
20028
22134
 
20029
- var margin = this.dim.font.size / 4;
20030
- if (this.c.length === 1) margin = margin / 2;
22135
+ var margin = 0;
20031
22136
  var offset = this.type === "chord" ? this.realWidth / 2 : 0;
20032
22137
  var left = this.x - offset - margin;
20033
22138
  var right = left + this.realWidth + margin;
@@ -20250,6 +22355,10 @@ Renderer.prototype.moveY = function (em, numLines) {
20250
22355
  this.y += em * numLines;
20251
22356
  };
20252
22357
 
22358
+ Renderer.prototype.absolutemoveY = function (y) {
22359
+ this.y = y;
22360
+ };
22361
+
20253
22362
  module.exports = Renderer;
20254
22363
 
20255
22364
  /***/ }),
@@ -21298,7 +23407,13 @@ function drawAbsolute(renderer, params, bartop, selectables, staffPos) {
21298
23407
  selectables.add(params, g, false, staffPos);
21299
23408
  } else {
21300
23409
  params.elemset.push(g);
21301
- selectables.add(params, g, params.type === 'note', staffPos);
23410
+ var isSelectable = false;
23411
+
23412
+ if (params.type === 'note' || params.type === 'tabNumber') {
23413
+ isSelectable = true;
23414
+ }
23415
+
23416
+ selectables.add(params, g, isSelectable, staffPos);
21302
23417
  }
21303
23418
  } else if (params.elemset.length > 0) selectables.add(params, params.elemset[0], params.type === 'note', staffPos); // If there was no output, then don't add to the selectables. This happens when using the "y" spacer, for instance.
21304
23419
 
@@ -21596,7 +23711,7 @@ var spacing = __webpack_require__(/*! ../abc_spacing */ "./src/write/abc_spacing
21596
23711
 
21597
23712
  var Selectables = __webpack_require__(/*! ./selectables */ "./src/write/draw/selectables.js");
21598
23713
 
21599
- function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, selectTypes, tuneNumber) {
23714
+ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, selectTypes, tuneNumber, lineOffset) {
21600
23715
  var selectables = new Selectables(renderer.paper, selectTypes, tuneNumber);
21601
23716
  renderer.moveY(renderer.padding.top);
21602
23717
  nonMusic(renderer, abcTune.topText, selectables);
@@ -21613,8 +23728,8 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
21613
23728
  }
21614
23729
 
21615
23730
  if (staffgroups.length >= 1) addStaffPadding(renderer, renderer.spacing.staffSeparation, staffgroups[staffgroups.length - 1], abcLine.staffGroup);
21616
- var staffgroup = engraveStaffLine(renderer, abcLine.staffGroup, selectables);
21617
- staffgroup.line = line; // If there are non-music lines then the staffgroup array won't line up with the line array, so this keeps track.
23731
+ var staffgroup = engraveStaffLine(renderer, abcLine.staffGroup, selectables, line);
23732
+ staffgroup.line = lineOffset + line; // If there are non-music lines then the staffgroup array won't line up with the line array, so this keeps track.
21618
23733
 
21619
23734
  staffgroups.push(staffgroup);
21620
23735
  } else if (abcLine.nonMusic) {
@@ -21633,8 +23748,8 @@ function draw(renderer, classes, abcTune, width, maxWidth, responsive, scale, se
21633
23748
  };
21634
23749
  }
21635
23750
 
21636
- function engraveStaffLine(renderer, staffGroup, selectables) {
21637
- drawStaffGroup(renderer, staffGroup, selectables);
23751
+ function engraveStaffLine(renderer, staffGroup, selectables, lineNumber) {
23752
+ drawStaffGroup(renderer, staffGroup, selectables, lineNumber);
21638
23753
  var height = staffGroup.height * spacing.STEP;
21639
23754
  renderer.y += height;
21640
23755
  return staffGroup;
@@ -21847,7 +23962,9 @@ function nonMusic(renderer, obj, selectables) {
21847
23962
  for (var i = 0; i < obj.rows.length; i++) {
21848
23963
  var row = obj.rows[i];
21849
23964
 
21850
- if (row.move) {
23965
+ if (row.absmove) {
23966
+ renderer.absolutemoveY(row.absmove);
23967
+ } else if (row.move) {
21851
23968
  renderer.moveY(row.move);
21852
23969
  } else if (row.text) {
21853
23970
  var x = row.left ? row.left : 0;
@@ -21895,6 +24012,39 @@ module.exports = nonMusic;
21895
24012
 
21896
24013
  /***/ }),
21897
24014
 
24015
+ /***/ "./src/write/draw/print-line.js":
24016
+ /*!**************************************!*\
24017
+ !*** ./src/write/draw/print-line.js ***!
24018
+ \**************************************/
24019
+ /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
24020
+
24021
+ var sprintf = __webpack_require__(/*! ./sprintf */ "./src/write/draw/sprintf.js");
24022
+
24023
+ var roundNumber = __webpack_require__(/*! ./round-number */ "./src/write/draw/round-number.js");
24024
+
24025
+ function printLine(renderer, x1, x2, y, klass, name, dy) {
24026
+ if (!dy) dy = 0.35;
24027
+ var fill = renderer.foregroundColor;
24028
+ x1 = roundNumber(x1);
24029
+ x2 = roundNumber(x2);
24030
+ var y1 = roundNumber(y - dy);
24031
+ var y2 = roundNumber(y + dy);
24032
+ var pathString = sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y1, x2, y1, x2, y2, x1, y2);
24033
+ var options = {
24034
+ path: pathString,
24035
+ stroke: "none",
24036
+ fill: fill
24037
+ };
24038
+ if (name) options['data-name'] = name;
24039
+ if (klass) options['class'] = klass;
24040
+ var ret = renderer.paper.pathToBack(options);
24041
+ return ret;
24042
+ }
24043
+
24044
+ module.exports = printLine;
24045
+
24046
+ /***/ }),
24047
+
21898
24048
  /***/ "./src/write/draw/print-path.js":
21899
24049
  /*!**************************************!*\
21900
24050
  !*** ./src/write/draw/print-path.js ***!
@@ -22104,6 +24254,30 @@ function drawRelativeElement(renderer, params, bartop) {
22104
24254
  }, false);
22105
24255
  break;
22106
24256
 
24257
+ case "tabNumber":
24258
+ var hAnchor = "middle";
24259
+ var tabFont = "tabnumberfont";
24260
+ var tabClass = 'tab-number';
24261
+
24262
+ if (params.isGrace) {
24263
+ tabFont = "tabgracefont";
24264
+ y += 2.5;
24265
+ tabClass = 'tab-grace';
24266
+ }
24267
+
24268
+ params.graphelem = renderText(renderer, {
24269
+ x: params.x,
24270
+ y: y,
24271
+ text: "" + params.c,
24272
+ type: tabFont,
24273
+ klass: renderer.controller.classes.generate(tabClass),
24274
+ anchor: hAnchor,
24275
+ centerVertically: false,
24276
+ dim: params.dim,
24277
+ cursor: 'default'
24278
+ }, false);
24279
+ break;
24280
+
22107
24281
  case "barNumber":
22108
24282
  params.graphelem = renderText(renderer, {
22109
24283
  x: params.x,
@@ -22265,7 +24439,7 @@ Selectables.prototype.getElements = function () {
22265
24439
  return this.elements;
22266
24440
  };
22267
24441
 
22268
- Selectables.prototype.add = function (absEl, svgEl, isNote, staffPos) {
24442
+ Selectables.prototype.add = function (absEl, svgEl, isNoteOrTabNumber, staffPos) {
22269
24443
  if (!this.canSelect(absEl)) return;
22270
24444
  var params;
22271
24445
  if (this.selectTypes === undefined) params = {
@@ -22281,7 +24455,7 @@ Selectables.prototype.add = function (absEl, svgEl, isNote, staffPos) {
22281
24455
  var sel = {
22282
24456
  absEl: absEl,
22283
24457
  svgEl: svgEl,
22284
- isDraggable: isNote
24458
+ isDraggable: isNoteOrTabNumber
22285
24459
  };
22286
24460
  if (staffPos !== undefined) sel.staffPos = staffPos;
22287
24461
  this.elements.push(sel);
@@ -22293,8 +24467,12 @@ Selectables.prototype.canSelect = function (absEl) {
22293
24467
  if (this.selectTypes === true) return true;
22294
24468
 
22295
24469
  if (this.selectTypes === undefined) {
22296
- // by default, only notes can be clicked.
22297
- return absEl.abcelem.el_type === 'note';
24470
+ // by default, only notes and tab numbers can be clicked.
24471
+ if (absEl.abcelem.el_type === 'note' || absEl.abcelem.el_type === 'tabNumber') {
24472
+ return true;
24473
+ }
24474
+
24475
+ return false;
22298
24476
  }
22299
24477
 
22300
24478
  return this.selectTypes.indexOf(absEl.abcelem.el_type) >= 0;
@@ -22392,7 +24570,7 @@ module.exports = setPaperSize;
22392
24570
  \***********************************/
22393
24571
  /***/ (function(module) {
22394
24572
 
22395
- function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
24573
+ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }
22396
24574
 
22397
24575
  /**
22398
24576
  * sprintf() for JavaScript v.0.4
@@ -22514,7 +24692,9 @@ var printDebugBox = __webpack_require__(/*! ./debug-box */ "./src/write/draw/deb
22514
24692
 
22515
24693
  var printStem = __webpack_require__(/*! ./print-stem */ "./src/write/draw/print-stem.js");
22516
24694
 
22517
- function drawStaffGroup(renderer, params, selectables) {
24695
+ var nonMusic = __webpack_require__(/*! ./non-music */ "./src/write/draw/non-music.js");
24696
+
24697
+ function drawStaffGroup(renderer, params, selectables, lineNumber) {
22518
24698
  // We enter this method with renderer.y pointing to the topmost coordinate that we're allowed to draw.
22519
24699
  // All of the children that will be drawn have a relative "pitch" set, where zero is the first ledger line below the staff.
22520
24700
  // renderer.y will be offset at the beginning of each staff by the amount required to make the relative pitch work.
@@ -22587,10 +24767,12 @@ function drawStaffGroup(renderer, params, selectables) {
22587
24767
  var topLine; // these are to connect multiple staves. We need to remember where they are.
22588
24768
 
22589
24769
  var bottomLine;
24770
+ var linePitch = 2;
22590
24771
  var bartop = 0;
22591
24772
 
22592
24773
  for (var i = 0; i < params.voices.length; i++) {
22593
24774
  var staff = params.voices[i].staff;
24775
+ var tabName = params.voices[i].tabNameInfos;
22594
24776
  renderer.y = staff.absoluteY;
22595
24777
  renderer.controller.classes.incrVoice(); //renderer.y = staff.y;
22596
24778
  // offset for starting the counting at middle C
@@ -22598,11 +24780,30 @@ function drawStaffGroup(renderer, params, selectables) {
22598
24780
  if (!params.voices[i].duplicate) {
22599
24781
  // renderer.moveY(spacing.STEP, staff.top);
22600
24782
  if (!topLine) topLine = renderer.calcY(10);
22601
- bottomLine = renderer.calcY(2);
24783
+ bottomLine = renderer.calcY(linePitch);
22602
24784
 
22603
24785
  if (staff.lines !== 0) {
24786
+ if (staff.linePitch) {
24787
+ linePitch = staff.linePitch;
24788
+ }
24789
+
22604
24790
  renderer.controller.classes.newMeasure();
22605
- printStaff(renderer, params.startx, params.w, staff.lines);
24791
+ var lines = printStaff(renderer, params.startx, params.w, staff.lines, staff.linePitch, staff.dy);
24792
+ bottomLine = lines[1];
24793
+ staff.bottomLine = bottomLine;
24794
+ staff.topLine = lines[0]; // rework bartop when tabs are present with current staff
24795
+
24796
+ if (staff.hasTab) {
24797
+ // do not link to staff above (ugly looking)
24798
+ bartop = staff.topLine;
24799
+ }
24800
+
24801
+ if (staff.hasStaff) {
24802
+ // this is a tab
24803
+ bartop = staff.hasStaff.topLine;
24804
+ params.voices[i].barto = true;
24805
+ params.voices[i].topLine = topLine;
24806
+ }
22606
24807
  }
22607
24808
 
22608
24809
  printBrace(renderer, staff.absoluteY, params.brace, i, selectables);
@@ -22614,10 +24815,35 @@ function drawStaffGroup(renderer, params, selectables) {
22614
24815
  zero: renderer.y,
22615
24816
  height: params.height * spacing.STEP
22616
24817
  });
24818
+ var tabNameHeight = 0;
24819
+
24820
+ if (tabName) {
24821
+ // print tab infos on staffBottom
24822
+ var r = {
24823
+ rows: []
24824
+ };
24825
+ r.rows.push({
24826
+ absmove: bottomLine + 2
24827
+ });
24828
+ var leftMargin = 8;
24829
+ r.rows.push({
24830
+ left: params.startx + leftMargin,
24831
+ text: tabName.name,
24832
+ font: 'tablabelfont',
24833
+ klass: 'text instrument-name',
24834
+ anchor: 'start'
24835
+ });
24836
+ r.rows.push({
24837
+ move: tabName.textSize.height
24838
+ });
24839
+ nonMusic(renderer, r);
24840
+ tabNameHeight = tabName.textSize.height;
24841
+ }
24842
+
22617
24843
  renderer.controller.classes.newMeasure();
22618
24844
 
22619
24845
  if (!params.voices[i].duplicate) {
22620
- bartop = renderer.calcY(2); // This connects the bar lines between two different staves.
24846
+ bartop = renderer.calcY(2 + tabNameHeight); // This connects the bar lines between two different staves.
22621
24847
  // if (staff.bottom < 0)
22622
24848
  // renderer.moveY(spacing.STEP, -staff.bottom);
22623
24849
  }
@@ -22625,7 +24851,11 @@ function drawStaffGroup(renderer, params, selectables) {
22625
24851
 
22626
24852
  renderer.controller.classes.newMeasure(); // connect all the staves together with a vertical line
22627
24853
 
22628
- if (params.staffs.length > 1) {
24854
+ var staffSize = params.staffs.length;
24855
+
24856
+ if (staffSize > 1) {
24857
+ topLine = params.staffs[0].topLine;
24858
+ bottomLine = params.staffs[staffSize - 1].bottomLine;
22629
24859
  printStem(renderer, params.startx, 0.6, topLine, bottomLine, null);
22630
24860
  }
22631
24861
 
@@ -22730,28 +24960,11 @@ module.exports = drawStaffGroup;
22730
24960
  \**************************************/
22731
24961
  /***/ (function(module, __unused_webpack_exports, __webpack_require__) {
22732
24962
 
22733
- var sprintf = __webpack_require__(/*! ./sprintf */ "./src/write/draw/sprintf.js");
22734
-
22735
- var roundNumber = __webpack_require__(/*! ./round-number */ "./src/write/draw/round-number.js");
24963
+ var printLine = __webpack_require__(/*! ./print-line */ "./src/write/draw/print-line.js");
22736
24964
 
22737
- function printStaffLine(renderer, x1, x2, pitch, klass, name) {
22738
- var dy = 0.35;
22739
- var fill = renderer.foregroundColor;
24965
+ function printStaffLine(renderer, x1, x2, pitch, klass, name, dy) {
22740
24966
  var y = renderer.calcY(pitch);
22741
- x1 = roundNumber(x1);
22742
- x2 = roundNumber(x2);
22743
- var y1 = roundNumber(y - dy);
22744
- var y2 = roundNumber(y + dy);
22745
- var pathString = sprintf("M %f %f L %f %f L %f %f L %f %f z", x1, y1, x2, y1, x2, y2, x1, y2);
22746
- var options = {
22747
- path: pathString,
22748
- stroke: "none",
22749
- fill: fill
22750
- };
22751
- if (name) options['data-name'] = name;
22752
- if (klass) options['class'] = klass;
22753
- var ret = renderer.paper.pathToBack(options);
22754
- return ret;
24967
+ return printLine(renderer, x1, x2, y, klass, name, dy);
22755
24968
  }
22756
24969
 
22757
24970
  module.exports = printStaffLine;
@@ -22766,23 +24979,40 @@ module.exports = printStaffLine;
22766
24979
 
22767
24980
  var printStaffLine = __webpack_require__(/*! ./staff-line */ "./src/write/draw/staff-line.js");
22768
24981
 
22769
- function printStaff(renderer, startx, endx, numLines) {
24982
+ function printStaff(renderer, startx, endx, numLines, linePitch, dy) {
22770
24983
  var klass = "abcjs-top-line";
24984
+ var pitch = 2;
24985
+
24986
+ if (linePitch) {
24987
+ pitch = linePitch;
24988
+ }
24989
+
22771
24990
  renderer.paper.openGroup({
22772
24991
  prepend: true,
22773
24992
  klass: renderer.controller.classes.generate("abcjs-staff")
22774
24993
  }); // If there is one line, it is the B line. Otherwise, the bottom line is the E line.
22775
24994
 
24995
+ var firstYLine = 0;
24996
+ var lastYLine = 0;
24997
+
22776
24998
  if (numLines === 1) {
22777
24999
  printStaffLine(renderer, startx, endx, 6, klass);
22778
25000
  } else {
22779
25001
  for (var i = numLines - 1; i >= 0; i--) {
22780
- printStaffLine(renderer, startx, endx, (i + 1) * 2, klass);
25002
+ var curpitch = (i + 1) * pitch;
25003
+ lastYLine = renderer.calcY(curpitch);
25004
+
25005
+ if (firstYLine == 0) {
25006
+ firstYLine = lastYLine;
25007
+ }
25008
+
25009
+ printStaffLine(renderer, startx, endx, curpitch, klass, null, dy);
22781
25010
  klass = undefined;
22782
25011
  }
22783
25012
  }
22784
25013
 
22785
25014
  renderer.paper.closeGroup();
25015
+ return [firstYLine, lastYLine];
22786
25016
  }
22787
25017
 
22788
25018
  module.exports = printStaff;
@@ -22911,6 +25141,10 @@ function renderText(renderer, params, alreadyInGroup) {
22911
25141
  hash.attr.stroke = "#ff0000";
22912
25142
  }
22913
25143
 
25144
+ if (params.cursor) {
25145
+ hash.attr.cursor = params.cursor;
25146
+ }
25147
+
22914
25148
  var text = params.text.replace(/\n\n/g, "\n \n");
22915
25149
  text = text.replace(/^\n/, "\xA0\n");
22916
25150
 
@@ -23224,6 +25458,16 @@ function drawVoice(renderer, params, bartop, selectables, staffPos) {
23224
25458
  // child.elemset = drawTempo(renderer, child);
23225
25459
  // break;
23226
25460
  default:
25461
+ if (params.staff.isTabStaff) {
25462
+ child.invisible = false;
25463
+
25464
+ if (child.type == 'bar') {
25465
+ if (child.abcelem.lastBar) {
25466
+ bartop = params.topLine;
25467
+ }
25468
+ }
25469
+ }
25470
+
23227
25471
  drawAbsolute(renderer, child, params.barto || i === params.children.length - 1 ? bartop : 0, selectables, staffPos);
23228
25472
  }
23229
25473
 
@@ -23306,8 +25550,8 @@ function formatJazzChord(chordString) {
23306
25550
  for (var i = 0; i < lines.length; i++) {
23307
25551
  var chord = lines[i]; // If the chord isn't in a recognizable format then just skip the formatting.
23308
25552
 
23309
- var reg = chord.match(/([ABCDEFG][♯♭]?)([^\/]+)?(\/[ABCDEFG][#b]?)?/);
23310
- if (reg) lines[i] = reg[1] + "\x03" + (reg[2] ? reg[2] : '') + "\x03" + (reg[3] ? reg[3] : '');
25553
+ var reg = chord.match(/^([ABCDEFG][♯♭]?)?([^\/]+)?(\/[ABCDEFG][#b]?)?/);
25554
+ if (reg) lines[i] = (reg[1] ? reg[1] : '') + "\x03" + (reg[2] ? reg[2] : '') + "\x03" + (reg[3] ? reg[3] : '');
23311
25555
  }
23312
25556
 
23313
25557
  return lines.join("\n");
@@ -24408,6 +26652,29 @@ module.exports = setUpperAndLowerElements;
24408
26652
 
24409
26653
  var layoutVoiceElements = __webpack_require__(/*! ./VoiceElements */ "./src/write/layout/VoiceElements.js");
24410
26654
 
26655
+ function checkLastBarX(voices) {
26656
+ var maxX = 0;
26657
+
26658
+ for (var i = 0; i < voices.length; i++) {
26659
+ var curVoice = voices[i];
26660
+
26661
+ if (curVoice.children.length > 0) {
26662
+ var lastChild = curVoice.children.length - 1;
26663
+ var maxChild = curVoice.children[lastChild];
26664
+
26665
+ if (maxChild.abcelem.el_type === 'bar') {
26666
+ var barX = maxChild.children[0].x;
26667
+
26668
+ if (barX > maxX) {
26669
+ maxX = barX;
26670
+ } else {
26671
+ maxChild.children[0].x = maxX;
26672
+ }
26673
+ }
26674
+ }
26675
+ }
26676
+ }
26677
+
24411
26678
  var layoutStaffGroup = function layoutStaffGroup(spacing, renderer, debug, staffGroup, leftEdge) {
24412
26679
  var epsilon = 0.0000001; // Fudging for inexactness of floating point math.
24413
26680
 
@@ -24506,8 +26773,10 @@ var layoutStaffGroup = function layoutStaffGroup(spacing, renderer, debug, staff
24506
26773
  x = layoutVoiceElements.getNextX(staffGroup.voices[i]);
24507
26774
  spacingunit = layoutVoiceElements.getSpacingUnits(staffGroup.voices[i]);
24508
26775
  }
24509
- } //console.log("greatest remaining",spacingunit,x);
26776
+ } // adjust lastBar when needed (multi staves)
26777
+
24510
26778
 
26779
+ checkLastBarX(staffGroup.voices); //console.log("greatest remaining",spacingunit,x);
24511
26780
 
24512
26781
  spacingunits += spacingunit;
24513
26782
  staffGroup.setWidth(x);
@@ -24691,7 +26960,8 @@ function moveDecorations(beam) {
24691
26960
  }
24692
26961
 
24693
26962
  function placeInLane(rightMost, relElem) {
24694
- // These items are centered so figure the coordinates accordingly and add a little margin.
26963
+ // These items are centered so figure the coordinates accordingly.
26964
+ // The font reports some extra space so the margin is built in.
24695
26965
  var xCoords = relElem.getChordDim();
24696
26966
 
24697
26967
  if (xCoords) {
@@ -25523,8 +27793,9 @@ Svg.prototype.text = function (text, attr, target) {
25523
27793
  }
25524
27794
 
25525
27795
  if (parts[2]) {
27796
+ var dist = parts[1] ? "0.4em" : "0.1em";
25526
27797
  var ts3 = document.createElementNS(svgNS, 'tspan');
25527
- ts3.setAttribute("dy", "0.1em");
27798
+ ts3.setAttribute("dy", dist);
25528
27799
  ts3.setAttribute("style", "font-size:0.7em");
25529
27800
  ts3.textContent = parts[2];
25530
27801
  line.appendChild(ts3);
@@ -25878,7 +28149,7 @@ module.exports = unhighlight;
25878
28149
  \********************/
25879
28150
  /***/ (function(module) {
25880
28151
 
25881
- var version = '6.0.0-beta.34';
28152
+ var version = '6.0.0-beta.39';
25882
28153
  module.exports = version;
25883
28154
 
25884
28155
  /***/ })