abcjs 6.2.2 → 6.2.3

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 (36) hide show
  1. package/RELEASE.md +39 -0
  2. package/abc2xml_239/abc2xml.html +769 -0
  3. package/abc2xml_239/abc2xml.py +2248 -0
  4. package/abc2xml_239/abc2xml_changelog.html +124 -0
  5. package/abc2xml_239/lazy-river.abc +26 -0
  6. package/abc2xml_239/lazy-river.xml +3698 -0
  7. package/abc2xml_239/mean-to-me.abc +22 -0
  8. package/abc2xml_239/mean-to-me.xml +2954 -0
  9. package/abc2xml_239/pyparsing.py +3672 -0
  10. package/abc2xml_239/pyparsing.pyc +0 -0
  11. package/dist/abcjs-basic-min.js +2 -2
  12. package/dist/abcjs-basic.js +160 -71
  13. package/dist/abcjs-basic.js.map +1 -1
  14. package/dist/abcjs-plugin-min.js +2 -2
  15. package/package.json +1 -1
  16. package/src/api/abc_tablatures.js +3 -0
  17. package/src/api/abc_tunebook_svg.js +5 -3
  18. package/src/parse/abc_parse_music.js +18 -53
  19. package/src/parse/abc_parse_settings.js +165 -0
  20. package/src/synth/create-synth.js +4 -0
  21. package/src/synth/place-note.js +6 -0
  22. package/src/synth/play-event.js +7 -5
  23. package/src/tablatures/tab-absolute-elements.js +3 -2
  24. package/src/tablatures/tab-renderer.js +2 -1
  25. package/src/test/abc_parser_lint.js +12 -12
  26. package/src/write/creation/abstract-engraver.js +6 -0
  27. package/src/write/creation/decoration.js +2 -0
  28. package/src/write/creation/glyphs.js +1 -1
  29. package/src/write/draw/glissando.js +1 -0
  30. package/src/write/draw/set-paper-size.js +1 -1
  31. package/src/write/draw/tie.js +9 -1
  32. package/src/write/engraver-controller.js +7 -1
  33. package/src/write/interactive/selection.js +6 -0
  34. package/src/write/layout/layout.js +33 -3
  35. package/types/index.d.ts +28 -20
  36. package/version.js +1 -1
@@ -276,6 +276,9 @@ var abcTablatures = {
276
276
  // plugin.init(tune, tuneNumber, args, ii);
277
277
  returned.push(pluginInstance);
278
278
  nbPlugins++;
279
+ } else if (instrument === '') {
280
+ // create a placeholder - there is no tab for this staff
281
+ returned.push(null);
279
282
  } else {
280
283
  // unknown tab plugin
281
284
  //this.emit_error('Undefined tablature plugin: ' + tabName)
@@ -997,11 +1000,11 @@ var renderAbc = function renderAbc(output, abc, parserParams, engraverParams, re
997
1000
  div.setAttribute("style", "visibility: hidden;");
998
1001
  document.body.appendChild(div);
999
1002
  }
1000
- if (params.afterParsing) params.afterParsing(tune, tuneNumber, abcString);
1001
1003
  if (!removeDiv && params.wrap && params.staffwidth) {
1002
1004
  tune = doLineWrapping(div, tune, tuneNumber, abcString, params);
1003
1005
  return tune;
1004
1006
  }
1007
+ if (params.afterParsing) params.afterParsing(tune, tuneNumber, abcString);
1005
1008
  renderOne(div, tune, params, tuneNumber, 0);
1006
1009
  if (removeDiv) div.parentNode.removeChild(div);
1007
1010
  return null;
@@ -1019,6 +1022,7 @@ function doLineWrapping(div, tune, tuneNumber, abcString, params) {
1019
1022
  var warnings = abcParser.getWarnings();
1020
1023
  if (warnings) tune.warnings = warnings;
1021
1024
  }
1025
+ if (params.afterParsing) params.afterParsing(tune, tuneNumber, abcString);
1022
1026
  renderOne(div, tune, ret.revisedParams, tuneNumber, 0);
1023
1027
  tune.explanation = ret.explanation;
1024
1028
  return tune;
@@ -6341,6 +6345,18 @@ var multilineVars;
6341
6345
  var tune;
6342
6346
  var tuneBuilder;
6343
6347
  var header;
6348
+ var _require = __webpack_require__(/*! ./abc_parse_settings */ "./src/parse/abc_parse_settings.js"),
6349
+ legalAccents = _require.legalAccents,
6350
+ volumeDecorations = _require.volumeDecorations,
6351
+ dynamicDecorations = _require.dynamicDecorations,
6352
+ accentPseudonyms = _require.accentPseudonyms,
6353
+ accentDynamicPseudonyms = _require.accentDynamicPseudonyms,
6354
+ nonDecorations = _require.nonDecorations,
6355
+ durations = _require.durations,
6356
+ pitches = _require.pitches,
6357
+ rests = _require.rests,
6358
+ accMap = _require.accMap,
6359
+ tripletQ = _require.tripletQ;
6344
6360
  var MusicParser = function MusicParser(_tokenizer, _warn, _multilineVars, _tune, _tuneBuilder, _header) {
6345
6361
  tokenizer = _tokenizer;
6346
6362
  warn = _warn;
@@ -6408,7 +6424,6 @@ var MusicParser = function MusicParser(_tokenizer, _warn, _multilineVars, _tune,
6408
6424
  // double-quote: chord symbol
6409
6425
  // less-than, greater-than, slash: duration
6410
6426
  // back-tick, space, tab: space
6411
- var nonDecorations = "ABCDEFGabcdefgxyzZ[]|^_{"; // use this to prescreen so we don't have to look for a decoration at every note.
6412
6427
 
6413
6428
  var isInTie = function isInTie(multilineVars, overlayLevel, el) {
6414
6429
  if (multilineVars.inTie[overlayLevel] === undefined) return false;
@@ -6817,7 +6832,7 @@ MusicParser.prototype.parseMusic = function (line) {
6817
6832
  // Create a warning if this is not a displayable duration.
6818
6833
  // The first item on a line is a regular note value, each item after that represents a dot placed after the previous note.
6819
6834
  // Only durations less than a whole note are tested because whole note durations have some tricky rules.
6820
- var durations = [0.5, 0.75, 0.875, 0.9375, 0.96875, 0.984375, 0.25, 0.375, 0.4375, 0.46875, 0.484375, 0.4921875, 0.125, 0.1875, 0.21875, 0.234375, 0.2421875, 0.24609375, 0.0625, 0.09375, 0.109375, 0.1171875, 0.12109375, 0.123046875, 0.03125, 0.046875, 0.0546875, 0.05859375, 0.060546875, 0.0615234375, 0.015625, 0.0234375, 0.02734375, 0.029296875, 0.0302734375, 0.03076171875];
6835
+
6821
6836
  if (el.duration < 1 && durations.indexOf(el.duration) === -1 && el.duration !== 0) {
6822
6837
  if (!el.rest || el.rest.type !== 'spacer') warn("Duration not representable: " + line.substring(startI, i), line, i);
6823
6838
  }
@@ -6965,11 +6980,6 @@ function durationOfMeasure(multilineVars) {
6965
6980
  if (!meter.value || meter.value.length === 0) return 1;
6966
6981
  return parseInt(meter.value[0].num, 10) / parseInt(meter.value[0].den, 10);
6967
6982
  }
6968
- var legalAccents = ["trill", "lowermordent", "uppermordent", "mordent", "pralltriller", "accent", "fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge", "open", "thumb", "snap", "turn", "roll", "breath", "shortphrase", "mediumphrase", "longphrase", "segno", "coda", "D.S.", "D.C.", "fine", "beambr1", "beambr2", "slide", "marcato", "upbow", "downbow", "/", "//", "///", "////", "trem1", "trem2", "trem3", "trem4", "turnx", "invertedturn", "invertedturnx", "trill(", "trill)", "arpeggio", "xstem", "mark", "umarcato", "style=normal", "style=harmonic", "style=rhythm", "style=x", "style=triangle", "D.C.alcoda", "D.C.alfine", "D.S.alcoda", "D.S.alfine", "editorial", "courtesy"];
6969
- var volumeDecorations = ["p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz"];
6970
- var dynamicDecorations = ["crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)"];
6971
- var accentPseudonyms = [["<", "accent"], [">", "accent"], ["tr", "trill"], ["plus", "+"], ["emphasis", "accent"], ["^", "umarcato"], ["marcato", "umarcato"]];
6972
- var accentDynamicPseudonyms = [["<(", "crescendo("], ["<)", "crescendo)"], [">(", "diminuendo("], [">)", "diminuendo)"]];
6973
6983
  var letter_to_accent = function letter_to_accent(line, i) {
6974
6984
  var macro = multilineVars.macros[line[i]];
6975
6985
  if (macro !== undefined) {
@@ -7096,19 +7106,6 @@ var letter_to_bar = function letter_to_bar(line, curr_pos) {
7096
7106
  if (retRep.len === 0 || retRep.token[0] === '-') return [orig_bar_len, ret.token];
7097
7107
  return [ret.len + retRep.len, ret.token, retRep.token];
7098
7108
  };
7099
- var tripletQ = {
7100
- 2: 3,
7101
- 3: 2,
7102
- 4: 3,
7103
- 5: 2,
7104
- // TODO-PER: not handling 6/8 rhythm yet
7105
- 6: 2,
7106
- 7: 2,
7107
- // TODO-PER: not handling 6/8 rhythm yet
7108
- 8: 3,
7109
- 9: 2 // TODO-PER: not handling 6/8 rhythm yet
7110
- };
7111
-
7112
7109
  var letter_to_open_slurs_and_triplets = function letter_to_open_slurs_and_triplets(line, i) {
7113
7110
  // consume spaces, and look for all the open parens. If there is a number after the open paren,
7114
7111
  // that is a triplet. Otherwise that is a slur. Collect all the slurs and the first triplet.
@@ -7242,38 +7239,6 @@ var addEndBeam = function addEndBeam(el) {
7242
7239
  if (el.duration !== undefined && el.duration < 0.25) el.end_beam = true;
7243
7240
  return el;
7244
7241
  };
7245
- var pitches = {
7246
- A: 5,
7247
- B: 6,
7248
- C: 0,
7249
- D: 1,
7250
- E: 2,
7251
- F: 3,
7252
- G: 4,
7253
- a: 12,
7254
- b: 13,
7255
- c: 7,
7256
- d: 8,
7257
- e: 9,
7258
- f: 10,
7259
- g: 11
7260
- };
7261
- var rests = {
7262
- x: 'invisible',
7263
- X: 'invisible-multimeasure',
7264
- y: 'spacer',
7265
- z: 'rest',
7266
- Z: 'multimeasure'
7267
- };
7268
- var accMap = {
7269
- 'dblflat': '__',
7270
- 'flat': '_',
7271
- 'natural': '=',
7272
- 'sharp': '^',
7273
- 'dblsharp': '^^',
7274
- 'quarterflat': '_/',
7275
- 'quartersharp': '^/'
7276
- };
7277
7242
  var getCoreNote = function getCoreNote(line, index, el, canHaveBrokenRhythm) {
7278
7243
  //var el = { startChar: index };
7279
7244
  var isComplete = function isComplete(state) {
@@ -7561,6 +7526,67 @@ module.exports = MusicParser;
7561
7526
 
7562
7527
  /***/ }),
7563
7528
 
7529
+ /***/ "./src/parse/abc_parse_settings.js":
7530
+ /*!*****************************************!*\
7531
+ !*** ./src/parse/abc_parse_settings.js ***!
7532
+ \*****************************************/
7533
+ /***/ (function(module) {
7534
+
7535
+ module.exports.legalAccents = ['trill', 'lowermordent', 'uppermordent', 'mordent', 'pralltriller', 'accent', 'fermata', 'invertedfermata', 'tenuto', '0', '1', '2', '3', '4', '5', '+', 'wedge', 'open', 'thumb', 'snap', 'turn', 'roll', 'breath', 'shortphrase', 'mediumphrase', 'longphrase', 'segno', 'coda', 'D.S.', 'D.C.', 'fine', 'beambr1', 'beambr2', 'slide', 'marcato', 'upbow', 'downbow', '/', '//', '///', '////', 'trem1', 'trem2', 'trem3', 'trem4', 'turnx', 'invertedturn', 'invertedturnx', 'trill(', 'trill)', 'arpeggio', 'xstem', 'mark', 'umarcato', 'style=normal', 'style=harmonic', 'style=rhythm', 'style=x', 'style=triangle', 'D.C.alcoda', 'D.C.alfine', 'D.S.alcoda', 'D.S.alfine', 'editorial', 'courtesy'];
7536
+ module.exports.volumeDecorations = ['p', 'pp', 'f', 'ff', 'mf', 'mp', 'ppp', 'pppp', 'fff', 'ffff', 'sfz'];
7537
+ module.exports.dynamicDecorations = ['crescendo(', 'crescendo)', 'diminuendo(', 'diminuendo)', 'glissando(', 'glissando)', '~(', '~)'];
7538
+ module.exports.accentPseudonyms = [['<', 'accent'], ['>', 'accent'], ['tr', 'trill'], ['plus', '+'], ['emphasis', 'accent'], ['^', 'umarcato'], ['marcato', 'umarcato']];
7539
+ module.exports.accentDynamicPseudonyms = [['<(', 'crescendo('], ['<)', 'crescendo)'], ['>(', 'diminuendo('], ['>)', 'diminuendo)']];
7540
+ module.exports.nonDecorations = 'ABCDEFGabcdefgxyzZ[]|^_{'; // use this to prescreen so we don't have to look for a decoration at every note.
7541
+
7542
+ module.exports.durations = [0.5, 0.75, 0.875, 0.9375, 0.96875, 0.984375, 0.25, 0.375, 0.4375, 0.46875, 0.484375, 0.4921875, 0.125, 0.1875, 0.21875, 0.234375, 0.2421875, 0.24609375, 0.0625, 0.09375, 0.109375, 0.1171875, 0.12109375, 0.123046875, 0.03125, 0.046875, 0.0546875, 0.05859375, 0.060546875, 0.0615234375, 0.015625, 0.0234375, 0.02734375, 0.029296875, 0.0302734375, 0.03076171875];
7543
+ module.exports.pitches = {
7544
+ A: 5,
7545
+ B: 6,
7546
+ C: 0,
7547
+ D: 1,
7548
+ E: 2,
7549
+ F: 3,
7550
+ G: 4,
7551
+ a: 12,
7552
+ b: 13,
7553
+ c: 7,
7554
+ d: 8,
7555
+ e: 9,
7556
+ f: 10,
7557
+ g: 11
7558
+ };
7559
+ module.exports.rests = {
7560
+ x: 'invisible',
7561
+ X: 'invisible-multimeasure',
7562
+ y: 'spacer',
7563
+ z: 'rest',
7564
+ Z: 'multimeasure'
7565
+ };
7566
+ module.exports.accMap = {
7567
+ dblflat: '__',
7568
+ flat: '_',
7569
+ natural: '=',
7570
+ sharp: '^',
7571
+ dblsharp: '^^',
7572
+ quarterflat: '_/',
7573
+ quartersharp: '^/'
7574
+ };
7575
+ module.exports.tripletQ = {
7576
+ 2: 3,
7577
+ 3: 2,
7578
+ 4: 3,
7579
+ 5: 2,
7580
+ // TODO-PER: not handling 6/8 rhythm yet
7581
+ 6: 2,
7582
+ 7: 2,
7583
+ // TODO-PER: not handling 6/8 rhythm yet
7584
+ 8: 3,
7585
+ 9: 2 // TODO-PER: not handling 6/8 rhythm yet
7586
+ };
7587
+
7588
+ /***/ }),
7589
+
7564
7590
  /***/ "./src/parse/abc_tokenizer.js":
7565
7591
  /*!************************************!*\
7566
7592
  !*** ./src/parse/abc_tokenizer.js ***!
@@ -14188,6 +14214,9 @@ function CreateSynth() {
14188
14214
  self.getAudioBuffer = function () {
14189
14215
  return self.audioBuffers[0];
14190
14216
  };
14217
+ self.getIsRunning = function () {
14218
+ return self.isRunning;
14219
+ };
14191
14220
 
14192
14221
  /////////////// Private functions //////////////
14193
14222
 
@@ -14784,6 +14813,11 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
14784
14813
  if (len < 0) len = 0.005; // Have some small audible length no matter how short the note is.
14785
14814
  var offlineCtx = new OfflineAC(2, Math.floor((len + fadeTimeSec) * sampleRate), sampleRate);
14786
14815
  var noteName = pitchToNoteName[sound.pitch];
14816
+ if (!soundsCache[sound.instrument]) {
14817
+ // It shouldn't happen that the entire instrument cache wasn't created, but this has been seen in practice, so guard against it.
14818
+ if (debugCallback) debugCallback('placeNote skipped (instrument empty): ' + sound.instrument + ':' + noteName);
14819
+ return Promise.resolve();
14820
+ }
14787
14821
  var noteBufferPromise = soundsCache[sound.instrument][noteName];
14788
14822
  if (!noteBufferPromise) {
14789
14823
  // if the note isn't present then just skip it - it will leave a blank spot in the audio.
@@ -14879,7 +14913,7 @@ module.exports = placeNote;
14879
14913
  var SynthSequence = __webpack_require__(/*! ./synth-sequence */ "./src/synth/synth-sequence.js");
14880
14914
  var CreateSynth = __webpack_require__(/*! ./create-synth */ "./src/synth/create-synth.js");
14881
14915
  var activeAudioContext = __webpack_require__(/*! ./active-audio-context */ "./src/synth/active-audio-context.js");
14882
- function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure) {
14916
+ function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure, soundFontUrl, debugCallback) {
14883
14917
  var sequence = new SynthSequence();
14884
14918
  for (var i = 0; i < midiPitches.length; i++) {
14885
14919
  var note = midiPitches[i];
@@ -14896,17 +14930,21 @@ function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure) {
14896
14930
  var ac = activeAudioContext();
14897
14931
  if (ac.state === "suspended") {
14898
14932
  return ac.resume().then(function () {
14899
- return doPlay(sequence, millisecondsPerMeasure);
14933
+ return doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback);
14900
14934
  });
14901
14935
  } else {
14902
- return doPlay(sequence, millisecondsPerMeasure);
14936
+ return doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback);
14903
14937
  }
14904
14938
  }
14905
- function doPlay(sequence, millisecondsPerMeasure) {
14939
+ function doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback) {
14906
14940
  var buffer = new CreateSynth();
14907
14941
  return buffer.init({
14908
14942
  sequence: sequence,
14909
- millisecondsPerMeasure: millisecondsPerMeasure
14943
+ millisecondsPerMeasure: millisecondsPerMeasure,
14944
+ options: {
14945
+ soundFontUrl: soundFontUrl
14946
+ },
14947
+ debugCallback: debugCallback
14910
14948
  }).then(function () {
14911
14949
  return buffer.prime();
14912
14950
  }).then(function () {
@@ -16252,10 +16290,10 @@ function buildGraceRelativesForRest(plugin, abs, absChild, graceNotes, tabVoice)
16252
16290
  * Build tab absolutes by scanning current staff line absolute array
16253
16291
  * @param {*} staffAbsolute
16254
16292
  */
16255
- TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice, voiceIndex, staffIndex, keySig) {
16293
+ TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice, voiceIndex, staffIndex, keySig, tabVoiceIndex) {
16256
16294
  var staffSize = getInitialStaffSize(staffAbsolute);
16257
16295
  var source = staffAbsolute[staffIndex + voiceIndex];
16258
- var dest = staffAbsolute[staffSize + staffIndex + voiceIndex];
16296
+ var dest = staffAbsolute[tabVoiceIndex];
16259
16297
  var tabPos = null;
16260
16298
  var defNote = null;
16261
16299
  if (source.children[0].abcelem.el_type != 'clef') {
@@ -16640,10 +16678,11 @@ TabRenderer.prototype.doLayout = function () {
16640
16678
  staffGroup.staffs[this.staffIndex].top += nameHeight;
16641
16679
  staffGroup.height += nameHeight * spacing.STEP;
16642
16680
  tabVoice.staff = staffGroupInfos;
16681
+ var tabVoiceIndex = voices.length;
16643
16682
  voices.splice(voices.length, 0, tabVoice);
16644
16683
  var keySig = checkVoiceKeySig(voices, ii + this.staffIndex);
16645
16684
  this.tabStaff.voices[ii] = [];
16646
- this.absolutes.build(this.plugin, voices, this.tabStaff.voices[ii], ii, this.staffIndex, keySig);
16685
+ this.absolutes.build(this.plugin, voices, this.tabStaff.voices[ii], ii, this.staffIndex, keySig, tabVoiceIndex);
16647
16686
  }
16648
16687
  linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
16649
16688
  };
@@ -17487,6 +17526,9 @@ AbstractEngraver.prototype.addNoteToAbcElement = function (abselem, elem, dot, s
17487
17526
  if (noteHead && noteHead.c === 'noteheads.slash.quarter') {
17488
17527
  if (dir === 'down') p2 -= 1;else p1 += 1;
17489
17528
  }
17529
+ if (noteHead && noteHead.c === 'noteheads.triangle.quarter') {
17530
+ if (dir === 'down') p2 -= 0.7;else p1 -= 1.2;
17531
+ }
17490
17532
  abselem.addRight(new RelativeElement(null, dx, 0, p1, {
17491
17533
  "type": "stem",
17492
17534
  "pitch2": p2,
@@ -18699,10 +18741,12 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
18699
18741
  };
18700
18742
  this.startCrescendoX = undefined;
18701
18743
  break;
18744
+ case '~(':
18702
18745
  case "glissando(":
18703
18746
  this.startGlissandoX = abselem;
18704
18747
  glissando = undefined;
18705
18748
  break;
18749
+ case '~)':
18706
18750
  case "glissando)":
18707
18751
  glissando = {
18708
18752
  start: this.startGlissandoX,
@@ -20695,7 +20739,7 @@ glyphs['noteheads.harmonic.quarter'] = {
20695
20739
  h: 8.165
20696
20740
  };
20697
20741
  glyphs['noteheads.triangle.quarter'] = {
20698
- d: [['M', 0, 0], ['l', 9, 0], ['l', -4.5, -9], ['z']],
20742
+ d: [['M', 0, 4], ['l', 9, 0], ['l', -4.5, -9], ['z']],
20699
20743
  w: 9,
20700
20744
  h: 9
20701
20745
  };
@@ -22039,7 +22083,7 @@ module.exports = drawSeparator;
22039
22083
  /***/ (function(module) {
22040
22084
 
22041
22085
  function setPaperSize(renderer, maxwidth, scale, responsive) {
22042
- var w = (maxwidth + renderer.padding.right) * scale;
22086
+ var w = (maxwidth + renderer.padding.left + renderer.padding.right) * scale;
22043
22087
  var h = (renderer.y + renderer.padding.bottom) * scale;
22044
22088
  if (renderer.isPrint) h = Math.max(h, 1056); // 11in x 72pt/in x 1.33px/pt
22045
22089
  // TODO-PER: We are letting the page get as long as it needs now, but eventually that should go to a second page.
@@ -22652,10 +22696,15 @@ function drawTie(renderer, params, linestartx, lineendx, selectables) {
22652
22696
  if (params.hint) klass = "abcjs-hint";
22653
22697
  var fudgeY = params.fixedY ? 1.5 : 0; // TODO-PER: This just compensates for drawArc, which contains too much knowledge of ties and slurs.
22654
22698
  var el = drawArc(renderer, params.startX, params.endX, params.startY + fudgeY, params.endY + fudgeY, params.above, klass, params.isTie, params.dotted);
22699
+ var startChar = -1;
22700
+ // This gets the start and end points of the contents of the slur. We assume that the parenthesis are just to the outside of that.
22701
+ if (params.anchor1 && !params.isTie) startChar = params.anchor1.parent.abcelem.startChar - 1;
22702
+ var endChar = -1;
22703
+ if (params.anchor2 && !params.isTie) endChar = params.anchor2.parent.abcelem.endChar + 1;
22655
22704
  selectables.wrapSvgEl({
22656
22705
  el_type: "slur",
22657
- startChar: -1,
22658
- endChar: -1
22706
+ startChar: startChar,
22707
+ endChar: endChar
22659
22708
  }, el);
22660
22709
  return [el];
22661
22710
  }
@@ -22965,6 +23014,7 @@ var EngraverController = function EngraverController(paper, params) {
22965
23014
  this.responsive = params.responsive;
22966
23015
  this.space = 3 * spacing.SPACE;
22967
23016
  this.initialClef = params.initialClef;
23017
+ this.expandToWidest = !!params.expandToWidest;
22968
23018
  this.scale = params.scale ? parseFloat(params.scale) : 0;
22969
23019
  this.classes = new Classes({
22970
23020
  shouldAddClasses: params.add_classes
@@ -23148,7 +23198,12 @@ EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOf
23148
23198
  this.constructTuneElements(abcTune);
23149
23199
 
23150
23200
  // Do all the positioning, both horizontally and vertically
23151
- var maxWidth = layout(this.renderer, abcTune, this.width, this.space);
23201
+ var maxWidth = layout(this.renderer, abcTune, this.width, this.space, this.expandToWidest);
23202
+
23203
+ //Set the top text now that we know the width
23204
+ if (this.expandToWidest && maxWidth > this.width + 1) {
23205
+ abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, maxWidth, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize);
23206
+ }
23152
23207
 
23153
23208
  // Deal with tablature for staff
23154
23209
  if (abcTune.tablatures) {
@@ -23651,6 +23706,7 @@ function keyboardSelection(ev) {
23651
23706
  if (handled) ev.preventDefault();
23652
23707
  }
23653
23708
  function findElementInHistory(selectables, el) {
23709
+ if (!el) return -1;
23654
23710
  for (var i = 0; i < selectables.length; i++) {
23655
23711
  if (el.dataset.index === selectables[i].svgEl.dataset.index) return i;
23656
23712
  }
@@ -23709,7 +23765,9 @@ function getBestMatchCoordinates(dim, ev, scale) {
23709
23765
  }
23710
23766
  function getTarget(target) {
23711
23767
  // This searches up the dom for the first item containing the attribute "selectable", or stopping at the SVG.
23768
+ if (!target) return null;
23712
23769
  if (target.tagName === "svg") return target;
23770
+ if (!target.getAttribute) return null;
23713
23771
  var found = target.getAttribute("selectable");
23714
23772
  while (!found) {
23715
23773
  if (!target.parentElement) found = true;else {
@@ -24248,7 +24306,7 @@ var layoutVoice = __webpack_require__(/*! ./voice */ "./src/write/layout/voice.j
24248
24306
  var setUpperAndLowerElements = __webpack_require__(/*! ./set-upper-and-lower-elements */ "./src/write/layout/set-upper-and-lower-elements.js");
24249
24307
  var layoutStaffGroup = __webpack_require__(/*! ./staff-group */ "./src/write/layout/staff-group.js");
24250
24308
  var getLeftEdgeOfStaff = __webpack_require__(/*! ./get-left-edge-of-staff */ "./src/write/layout/get-left-edge-of-staff.js");
24251
- var layout = function layout(renderer, abctune, width, space) {
24309
+ var layout = function layout(renderer, abctune, width, space, expandToWidest) {
24252
24310
  var i;
24253
24311
  var abcLine;
24254
24312
  // Adjust the x-coordinates to their absolute positions
@@ -24256,8 +24314,14 @@ var layout = function layout(renderer, abctune, width, space) {
24256
24314
  for (i = 0; i < abctune.lines.length; i++) {
24257
24315
  abcLine = abctune.lines[i];
24258
24316
  if (abcLine.staff) {
24259
- setXSpacing(renderer, width, space, abcLine.staffGroup, abctune.formatting, i === abctune.lines.length - 1, false);
24260
- if (abcLine.staffGroup.w > maxWidth) maxWidth = abcLine.staffGroup.w;
24317
+ // console.log("=== line", i)
24318
+ var thisWidth = setXSpacing(renderer, maxWidth, space, abcLine.staffGroup, abctune.formatting, i === abctune.lines.length - 1, false);
24319
+ // console.log(thisWidth, maxWidth)
24320
+ if (Math.round(thisWidth) > Math.round(maxWidth)) {
24321
+ // to take care of floating point weirdness
24322
+ maxWidth = thisWidth;
24323
+ if (expandToWidest) i = -1; // do the calculations over with the new width
24324
+ }
24261
24325
  }
24262
24326
  }
24263
24327
 
@@ -24288,13 +24352,38 @@ var setXSpacing = function setXSpacing(renderer, width, space, staffGroup, forma
24288
24352
  var newspace = space;
24289
24353
  for (var it = 0; it < 8; it++) {
24290
24354
  // TODO-PER: shouldn't need multiple passes, but each pass gets it closer to the right spacing. (Only affects long lines: normal lines break out of this loop quickly.)
24355
+ // console.log("iteration", it)
24356
+ // dumpGroup("before", staffGroup)
24291
24357
  var ret = layoutStaffGroup(newspace, renderer, debug, staffGroup, leftEdge);
24358
+ // dumpGroup("after",staffGroup)
24292
24359
  newspace = calcHorizontalSpacing(isLastLine, formatting.stretchlast, width + renderer.padding.left, staffGroup.w, newspace, ret.spacingUnits, ret.minSpace, renderer.padding.left + renderer.padding.right);
24293
24360
  if (debug) console.log("setXSpace", it, staffGroup.w, newspace, staffGroup.minspace);
24294
24361
  if (newspace === null) break;
24295
24362
  }
24296
24363
  centerWholeRests(staffGroup.voices);
24297
- };
24364
+ return staffGroup.w - leftEdge;
24365
+ };
24366
+
24367
+ // function dumpGroup(label, staffGroup) {
24368
+ // var output = {
24369
+ // line: staffGroup.line,
24370
+ // w: staffGroup.w,
24371
+ // voice: {
24372
+ // i: staffGroup.voices[0].i,
24373
+ // minx: staffGroup.voices[0].minx,
24374
+ // nextx: staffGroup.voices[0].nextx,
24375
+ // spacingduration: staffGroup.voices[0].spacingduration,
24376
+ // w: staffGroup.voices[0].w,
24377
+ // children: [],
24378
+ // }
24379
+ // }
24380
+ // for (var i = 0; i < staffGroup.voices[0].children.length; i++) {
24381
+ // var child = staffGroup.voices[0].children[i]
24382
+ // output.voice.children.push({ fixedW: child.fixed.w, w: child.w, x: child.x, type: child.type })
24383
+ // }
24384
+ // console.log(label,output)
24385
+ // }
24386
+
24298
24387
  function calcHorizontalSpacing(isLastLine, stretchLast, targetWidth, lineWidth, spacing, spacingUnits, minSpace, padding) {
24299
24388
  if (isLastLine) {
24300
24389
  if (stretchLast === undefined) {
@@ -25546,7 +25635,7 @@ module.exports = Svg;
25546
25635
  \********************/
25547
25636
  /***/ (function(module) {
25548
25637
 
25549
- var version = '6.2.2';
25638
+ var version = '6.2.3';
25550
25639
  module.exports = version;
25551
25640
 
25552
25641
  /***/ })