@tspro/web-music-score 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! WebMusicScore v1.0.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
1
+ /*! WebMusicScore v1.1.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
2
2
  /******/ (function() { // webpackBootstrap
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -538,7 +538,7 @@ __webpack_require__.d(__webpack_exports__, {
538
538
  "default": function() { return /* binding */ index_full; }
539
539
  });
540
540
 
541
- // UNUSED EXPORTS: Annotation, ArcPos, Arpeggio, Audio, CellData, Chord, CircleOfFifthsComponent, DefaultGuitarNoteLabel, DefaultHandedness, DefaultPitchNotation, DefaultTuningName, DivRect, Fermata, GuitarComponent, GuitarContext, GuitarNote, GuitarNoteLabel, GuitarNoteLabelList, Interval, InvalidChordException, KeySignature, Label, MAccidental, MArc, MArpeggio, MBarLineLeft, MBarLineRight, MBeamGroup, MDocument, MEnding, MExtensionLine, MFermata, MHeader, MImage, MMeasure, MNoteGroup, MPlaybackButtons, MPlayer, MRenderer, MRest, MRhythmColumn, MScoreRow, MSignature, MSpecialText, MText, MaxNoteLength, MinNoteLength, MusicError, MusicInterface, MusicScoreView, Navigation, Note, NoteLength, PitchNotation, PitchNotationList, PlayState, PlaybackButtons, PlaybackButtonsLayout, RhythmProps, SamplePieces, Scale, ScaleFactory, ScaleType, StaffKind, Stem, SymbolSet, TieLength, TimeSignature, TuningNameList, alterTempoSpeed, getDefaultKeySignature, getDefaultScale, getDefaultTempo, getDefaultTimeSignature, getScale, getScaleFactory, getScaleFactoryList, getTempoString, validateGuitarNoteLabel, validateHandedness, validateIntervalQuality, validateNoteLength, validatePitchNotation, validateScaleType, validateTuningName
541
+ // UNUSED EXPORTS: Annotation, ArcPos, Arpeggio, Audio, CellData, Chord, CircleOfFifthsComponent, DefaultGuitarNoteLabel, DefaultHandedness, DefaultPitchNotation, DefaultTuningName, DivRect, Fermata, GuitarComponent, GuitarContext, GuitarNote, GuitarNoteLabel, GuitarNoteLabelList, Interval, InvalidChordException, KeySignature, Label, MAccidental, MArc, MArpeggio, MBarLineLeft, MBarLineRight, MBeamGroup, MDocument, MEnding, MExtensionLine, MFermata, MHeader, MImage, MMeasure, MNoteGroup, MPlaybackButtons, MPlayer, MRenderer, MRest, MRhythmColumn, MScoreRow, MSignature, MSpecialText, MText, MaxNoteLength, MinNoteLength, MusicError, MusicInterface, MusicScoreView, Navigation, Note, NoteLength, PitchNotation, PitchNotationList, PlayState, PlaybackButtons, PlaybackButtonsLayout, RhythmProps, SamplePieces, Scale, ScaleFactory, ScaleType, StaffKind, Stem, SymbolSet, TieLength, TimeSignature, TuningNameList, alterTempoSpeed, getDefaultKeySignature, getDefaultScale, getDefaultTempo, getDefaultTimeSignature, getScale, getScaleFactory, getScaleFactoryList, getTempoString, getTuningStrings, validateGuitarNoteLabel, validateHandedness, validateIntervalQuality, validateNoteLength, validatePitchNotation, validateScaleType, validateTuningName
542
542
 
543
543
  // NAMESPACE OBJECT: ./src/sample-pieces/exports.ts
544
544
  var exports_namespaceObject = {};
@@ -631,6 +631,7 @@ __webpack_require__.d(exports_full_namespaceObject, {
631
631
  getScaleFactory: function() { return getScaleFactory; },
632
632
  getScaleFactoryList: function() { return getScaleFactoryList; },
633
633
  getTempoString: function() { return getTempoString; },
634
+ getTuningStrings: function() { return getTuningStrings; },
634
635
  validateGuitarNoteLabel: function() { return validateGuitarNoteLabel; },
635
636
  validateHandedness: function() { return validateHandedness; },
636
637
  validateIntervalQuality: function() { return validateIntervalQuality; },
@@ -32740,6 +32741,7 @@ var DocumentSettings = {
32740
32741
  NoteHeadWidth: 2,
32741
32742
  NoteHeadHeight: 1.3,
32742
32743
  DiamondNoteHeadSize: 1.8,
32744
+ DotSize: 0.8,
32743
32745
  StemHeight: 7,
32744
32746
  // One octave
32745
32747
  FlagWidth: 1.5,
@@ -32749,7 +32751,8 @@ var DocumentSettings = {
32749
32751
  BeamAngleFactor: 0.5,
32750
32752
  RestDotSpace: 0.5,
32751
32753
  LedgerLineWidth: 3.6,
32752
- ShortTieLength: 5
32754
+ ShortTieLength: 5,
32755
+ GuitarTabHeight: 20
32753
32756
  };
32754
32757
  ;// ./src/music-score/engine/renderer.ts
32755
32758
 
@@ -32994,8 +32997,12 @@ class Renderer {
32994
32997
  var {
32995
32998
  row
32996
32999
  } = measure.getMusicObject();
33000
+ var staff = row.getStaff(pitch);
33001
+ if (!staff) {
33002
+ return;
33003
+ }
32997
33004
  ctx.fillStyle = HilightPitchRectColor;
32998
- ctx.fillRect(0, row.getPitchY(pitch) - unitSize, ctx.canvas.width, 2 * unitSize);
33005
+ ctx.fillRect(0, staff.getPitchY(pitch) - unitSize, ctx.canvas.width, 2 * unitSize);
32999
33006
  if (mousePos !== undefined) {
33000
33007
  this.drawLedgerLines(row, pitch, mousePos.x);
33001
33008
  }
@@ -33099,26 +33106,33 @@ class Renderer {
33099
33106
  }
33100
33107
  }
33101
33108
  drawLedgerLines(row, pitch, x) {
33109
+ var staff = row.getStaff(pitch);
33110
+ if (!staff) {
33111
+ return;
33112
+ }
33102
33113
  var {
33103
33114
  unitSize
33104
33115
  } = this;
33105
- var staffLine = row.getClosestStaffLine(pitch);
33106
33116
  var ledgerLineWidth = unitSize * DocumentSettings.LedgerLineWidth;
33107
- if (pitch >= staffLine.topLinePitch + 2) {
33108
- for (var linePitch = staffLine.topLinePitch + 2; linePitch <= pitch; linePitch += 2) {
33109
- var y = row.getPitchY(linePitch);
33110
- this.drawLine(x - ledgerLineWidth / 2, y, x + ledgerLineWidth / 2, y);
33117
+ if (pitch >= staff.topLinePitch + 2) {
33118
+ for (var linePitch = staff.topLinePitch + 2; linePitch <= pitch; linePitch += 2) {
33119
+ if (staff.containsPitch(linePitch)) {
33120
+ var y = staff.getPitchY(linePitch);
33121
+ this.drawLine(x - ledgerLineWidth / 2, y, x + ledgerLineWidth / 2, y);
33122
+ }
33111
33123
  }
33112
- } else if (pitch <= staffLine.bottomLinePitch - 2) {
33113
- for (var _linePitch = staffLine.bottomLinePitch - 2; _linePitch >= pitch; _linePitch -= 2) {
33114
- var _y = row.getPitchY(_linePitch);
33115
- this.drawLine(x - ledgerLineWidth / 2, _y, x + ledgerLineWidth / 2, _y);
33124
+ } else if (pitch <= staff.bottomLinePitch - 2) {
33125
+ for (var _linePitch = staff.bottomLinePitch - 2; _linePitch >= pitch; _linePitch -= 2) {
33126
+ if (staff.containsPitch(_linePitch)) {
33127
+ var _y = staff.getPitchY(_linePitch);
33128
+ this.drawLine(x - ledgerLineWidth / 2, _y, x + ledgerLineWidth / 2, _y);
33129
+ }
33116
33130
  }
33117
33131
  }
33118
33132
  }
33119
33133
  }
33120
- Renderer.DotSize = 0.8;
33121
- ;// ./src/music-score/engine/staff-line.ts
33134
+ ;// ./src/music-score/engine/staff-and-tab.ts
33135
+
33122
33136
 
33123
33137
 
33124
33138
  var ClefKind;
@@ -33126,19 +33140,65 @@ var ClefKind;
33126
33140
  ClefKind[ClefKind["Treble"] = 0] = "Treble";
33127
33141
  ClefKind[ClefKind["Bass"] = 1] = "Bass";
33128
33142
  })(ClefKind || (ClefKind = {}));
33129
- class StaffLine {
33130
- constructor(clefKind, clefLinePitch, middleLinePitch, middleLineOffset, minPitch, maxPitch) {
33143
+ class MusicStaff {
33144
+ constructor(clefKind, clefLinePitch, middleLinePitch, minPitch, maxPitch) {
33131
33145
  this.clefKind = clefKind;
33132
33146
  this.clefLinePitch = clefLinePitch;
33133
33147
  this.middleLinePitch = middleLinePitch;
33134
- this.middleLineOffset = middleLineOffset;
33135
33148
  this.minPitch = minPitch;
33136
33149
  this.maxPitch = maxPitch;
33150
+ this.topLineY = 0;
33151
+ this.bottomLineY = 0;
33137
33152
  this.clefImageAsset = clefKind === ClefKind.Treble ? ImageAsset.TrebleClefPng : ImageAsset.BassClefPng;
33138
33153
  this.topLinePitch = this.middleLinePitch + 4;
33139
33154
  this.bottomLinePitch = this.middleLinePitch - 4;
33140
33155
  this.octaveLower = this.clefLinePitch === Note.getNote("G3").pitch; // Guitar is played octave lower
33141
33156
  }
33157
+ get middleLineY() {
33158
+ return (this.topLineY + this.bottomLineY) / 2;
33159
+ }
33160
+ offset(dx, dy) {
33161
+ this.topLineY += dy;
33162
+ this.bottomLineY += dy;
33163
+ }
33164
+ getLineSpacing() {
33165
+ return (this.bottomLineY - this.topLineY) / 4;
33166
+ }
33167
+ getPitchSpacing() {
33168
+ return this.getLineSpacing() / 2;
33169
+ }
33170
+ containsPitch(pitch) {
33171
+ Note.validatePitch(pitch);
33172
+ return pitch >= this.minPitch && pitch <= this.maxPitch;
33173
+ }
33174
+ getPitchY(pitch) {
33175
+ Assert.assert(this.containsPitch(pitch), "getPitchY: staff does not contain pitch " + pitch);
33176
+ return this.bottomLineY + (this.bottomLinePitch - pitch) * this.getPitchSpacing();
33177
+ }
33178
+ getPitchAt(y) {
33179
+ var pitch = Math.round(this.bottomLinePitch - (y - this.bottomLineY) / this.getPitchSpacing());
33180
+ return this.containsPitch(pitch) ? pitch : undefined;
33181
+ }
33182
+ isPitchLine(pitch) {
33183
+ return pitch % 2 === this.middleLinePitch % 2;
33184
+ }
33185
+ isPitchSpace(pitch) {
33186
+ return pitch % 2 !== this.middleLinePitch % 2;
33187
+ }
33188
+ }
33189
+ class GuitarTab {
33190
+ constructor() {
33191
+ this.top = 0;
33192
+ this.bottom = 0;
33193
+ }
33194
+ /** Return Y coordinate of string. */
33195
+ getStringY(stringId) {
33196
+ return this.top + (this.bottom - this.top) / 6 * (stringId + 0.5);
33197
+ }
33198
+ offset(dx, dy) {
33199
+ this.top += dy;
33200
+ this.bottom += dy;
33201
+ }
33142
33202
  }
33143
33203
  ;// ./src/music-score/engine/acc-state.ts
33144
33204
  class AccidentalState {
@@ -33599,6 +33659,46 @@ function alterTempoSpeed(tempo, speed) {
33599
33659
  }
33600
33660
  };
33601
33661
  }
33662
+ ;// ./src/music-theory/assets/tunings.json
33663
+ var tunings_namespaceObject = /*#__PURE__*/JSON.parse('{"p":[{"name":"Standard","strings":["E2","A2","D3","G3","B3","E4"]},{"name":"B Standard","strings":["B1","E2","A2","D3","F#3","B3"]},{"name":"C Standard","strings":["C2","F2","A#2","D#3","G3","C4"]},{"name":"D Modal","strings":["D2","A2","D3","G3","A3","D4"]},{"name":"D Standard","strings":["D2","G2","C3","F3","A3","D4"]},{"name":"D# Standard","strings":["D#2","G#2","C#3","F#3","A#3","D#4"]},{"name":"Double Drop D","strings":["D2","A2","D3","G3","B3","D4"]},{"name":"Drop B","strings":["B1","F#2","B2","E3","G#3","C#4"]},{"name":"Drop C","strings":["C2","G2","C3","F3","A3","D4"]},{"name":"Drop D","strings":["D2","A2","D3","G3","B3","E4"]},{"name":"Low C","strings":["C2","G2","D3","G3","A3","D4"]},{"name":"New Standard","strings":["C2","G2","D3","A3","E4","G4"]},{"name":"Open A","strings":["E2","A2","C#3","E3","A3","E4"]},{"name":"Open A Minor","strings":["E2","A2","E3","A3","C4","E4"]},{"name":"Open C","strings":["C2","G2","C3","G3","C4","E4"]},{"name":"Open C Minor","strings":["C2","G2","C3","G3","C4","D#4"]},{"name":"Open D","strings":["D2","A2","D3","F#3","A3","D4"]},{"name":"Open D Minor","strings":["D2","A2","D3","F3","A3","D4"]},{"name":"Open E","strings":["E2","B2","E3","G#3","B3","E4"]},{"name":"Open E Minor","strings":["E2","B2","E3","G3","B3","E4"]},{"name":"Open G","strings":["D2","G2","D3","G3","B3","D4"]},{"name":"Open G Minor","strings":["D2","G2","D3","G3","A#3","D4"]}]}');
33664
+ ;// ./src/music-theory/tuning.ts
33665
+
33666
+
33667
+
33668
+ /*
33669
+ * | string | stringId | freq | fretboard (RH) | on tab |
33670
+ * |--------|----------|---------|----------------|---------------|
33671
+ * | 1 | 0 | highest | bottom string | top string |
33672
+ * | 6 | 5 | lowest | top string | bottom string |
33673
+ * |--------|----------|---------|----------------|---------------|
33674
+ */
33675
+ /** @public */
33676
+ var TuningNameList = tunings_namespaceObject.p.map(data => data.name);
33677
+ /** @public */
33678
+ var DefaultTuningName = TuningNameList[0];
33679
+ /** @public */
33680
+ function validateTuningName(tuningName) {
33681
+ if (TuningNameList.indexOf(tuningName) >= 0) {
33682
+ return tuningName;
33683
+ } else {
33684
+ return Assert.interrupt("Invalid tuning name: " + tuningName);
33685
+ }
33686
+ }
33687
+ var TuningStringsCache = new LRUCache(100);
33688
+ /**
33689
+ * @public
33690
+ * @returns Array of open string notes, note for each string.
33691
+ */
33692
+ function getTuningStrings(tuningName) {
33693
+ var tuningStrings = TuningStringsCache.get(tuningName);
33694
+ if (!tuningStrings) {
33695
+ var tuningData = Assert.require(tunings_namespaceObject.p.find(data => data.name === tuningName), "Invalid tuning name: " + tuningName);
33696
+ tuningStrings = tuningData.strings.slice().reverse().map(noteName => Note.getNote(noteName));
33697
+ Assert.int_eq(tuningStrings.length, 6, "Tuning should have 6 strings but has " + tuningStrings.length + " strings.");
33698
+ TuningStringsCache.set(tuningName, tuningStrings);
33699
+ }
33700
+ return tuningStrings;
33701
+ }
33602
33702
  ;// ./src/music-theory/index.ts
33603
33703
 
33604
33704
 
@@ -33609,6 +33709,7 @@ function alterTempoSpeed(tempo, speed) {
33609
33709
 
33610
33710
 
33611
33711
 
33712
+
33612
33713
  ;// ./src/music-score/engine/obj-image.ts
33613
33714
 
33614
33715
 
@@ -33814,6 +33915,7 @@ class ObjText extends MusicObject {
33814
33915
  this.italic = (_d = textProps.italic) !== null && _d !== void 0 ? _d : false;
33815
33916
  this.boxed = (_e = textProps.boxed) !== null && _e !== void 0 ? _e : false;
33816
33917
  this.padding = (_f = textProps.padding) !== null && _f !== void 0 ? _f : this.boxed ? DefaultBoxedPadding : 0;
33918
+ this.bgcolor = textProps.bgcolor;
33817
33919
  if (!isFinite(this.padding) || this.padding < 0) {
33818
33920
  this.padding = 0;
33819
33921
  }
@@ -33892,6 +33994,14 @@ class ObjText extends MusicObject {
33892
33994
  anchorY,
33893
33995
  italic
33894
33996
  } = this;
33997
+ if (this.bgcolor !== undefined) {
33998
+ ctx.save();
33999
+ ctx.fillStyle = this.bgcolor;
34000
+ ctx.beginPath();
34001
+ ctx.fillRect(rect.left, rect.top, rect.width, rect.height);
34002
+ ctx.fill();
34003
+ ctx.restore();
34004
+ }
33895
34005
  var lineCount = this.textLines.length;
33896
34006
  var textHeight = lineCount * lineHeight;
33897
34007
  var fixY = -lineHeight * (italic ? 0.25 : 0.175);
@@ -33931,10 +34041,10 @@ class ObjText extends MusicObject {
33931
34041
 
33932
34042
 
33933
34043
  class ObjSignature extends MusicObject {
33934
- constructor(measure, staffLine) {
34044
+ constructor(measure, staff) {
33935
34045
  super(measure);
33936
34046
  this.measure = measure;
33937
- this.staffLine = staffLine;
34047
+ this.staff = staff;
33938
34048
  this.ksNeutralizeAccidentals = [];
33939
34049
  this.ksNewAccidentals = [];
33940
34050
  this.mi = new MSignature(this);
@@ -33950,9 +34060,9 @@ class ObjSignature extends MusicObject {
33950
34060
  }
33951
34061
  updateClefImage(renderer, showClef) {
33952
34062
  if (showClef) {
33953
- var img = renderer.getImageAsset(this.staffLine.clefImageAsset);
34063
+ var img = renderer.getImageAsset(this.staff.clefImageAsset);
33954
34064
  this.clefImage = img ? new ObjImage(this, img, 0, 0.5, 0.1) : undefined;
33955
- this.eightBelowClef = this.clefImage && this.staffLine.octaveLower ? new ObjText(this, "8", 0.5, 0) : undefined;
34065
+ this.eightBelowClef = this.clefImage && this.staff.octaveLower ? new ObjText(this, "8", 0.5, 0) : undefined;
33956
34066
  } else {
33957
34067
  this.clefImage = undefined;
33958
34068
  }
@@ -34017,19 +34127,19 @@ class ObjSignature extends MusicObject {
34017
34127
  }
34018
34128
  }
34019
34129
  getAccidentalPitch(accNote) {
34020
- var clefKind = this.staffLine.clefKind;
34130
+ var clefKind = this.staff.clefKind;
34021
34131
  var lowestAccidentalPitch = undefined;
34022
34132
  if (clefKind === ClefKind.Treble) {
34023
34133
  if (accNote.accidental > 0) {
34024
- lowestAccidentalPitch = this.staffLine.bottomLinePitch + 3;
34134
+ lowestAccidentalPitch = this.staff.bottomLinePitch + 3;
34025
34135
  } else if (accNote.accidental < 0) {
34026
- lowestAccidentalPitch = this.staffLine.bottomLinePitch + 1;
34136
+ lowestAccidentalPitch = this.staff.bottomLinePitch + 1;
34027
34137
  }
34028
34138
  } else if (clefKind === ClefKind.Bass) {
34029
34139
  if (accNote.accidental > 0) {
34030
- lowestAccidentalPitch = this.staffLine.bottomLinePitch + 1;
34140
+ lowestAccidentalPitch = this.staff.bottomLinePitch + 1;
34031
34141
  } else if (accNote.accidental < 0) {
34032
- lowestAccidentalPitch = this.staffLine.bottomLinePitch - 1;
34142
+ lowestAccidentalPitch = this.staff.bottomLinePitch - 1;
34033
34143
  }
34034
34144
  }
34035
34145
  if (lowestAccidentalPitch !== undefined) {
@@ -34094,7 +34204,8 @@ class ObjSignature extends MusicObject {
34094
34204
  unitSize
34095
34205
  } = renderer;
34096
34206
  var {
34097
- measure
34207
+ measure,
34208
+ staff
34098
34209
  } = this;
34099
34210
  var {
34100
34211
  row
@@ -34105,7 +34216,7 @@ class ObjSignature extends MusicObject {
34105
34216
  if (this.clefImage) {
34106
34217
  x += paddingX;
34107
34218
  this.clefImage.layout(renderer);
34108
- this.clefImage.offset(x, row.getPitchY(this.staffLine.clefLinePitch));
34219
+ this.clefImage.offset(x, staff.getPitchY(staff.clefLinePitch));
34109
34220
  this.rect.expandInPlace(this.clefImage.getRect());
34110
34221
  x = this.rect.right;
34111
34222
  if (this.eightBelowClef) {
@@ -34117,7 +34228,7 @@ class ObjSignature extends MusicObject {
34117
34228
  }
34118
34229
  if (this.measureNumber) {
34119
34230
  this.measureNumber.layout(renderer);
34120
- var y = this.clefImage ? this.clefImage.getRect().top : row.getPitchY(this.staffLine.topLinePitch);
34231
+ var y = this.clefImage ? this.clefImage.getRect().top : staff.topLineY;
34121
34232
  this.measureNumber.offset(0, y);
34122
34233
  this.rect.expandInPlace(this.measureNumber.getRect());
34123
34234
  x = Math.max(x, this.rect.right);
@@ -34125,38 +34236,44 @@ class ObjSignature extends MusicObject {
34125
34236
  if (this.ksNeutralizeAccidentals.length > 0) {
34126
34237
  x += paddingX;
34127
34238
  this.ksNeutralizeAccidentals.forEach(acc => {
34128
- acc.obj.layout(renderer);
34129
- acc.obj.offset(x + acc.obj.getRect().leftw, row.getPitchY(acc.pitch));
34130
- this.rect.expandInPlace(acc.obj.getRect());
34131
- x = this.rect.right;
34239
+ var accStaff = row.getStaff(acc.pitch);
34240
+ if (accStaff) {
34241
+ acc.obj.layout(renderer);
34242
+ acc.obj.offset(x + acc.obj.getRect().leftw, accStaff.getPitchY(acc.pitch));
34243
+ this.rect.expandInPlace(acc.obj.getRect());
34244
+ x = this.rect.right;
34245
+ }
34132
34246
  });
34133
34247
  }
34134
34248
  if (this.ksNewAccidentals) {
34135
34249
  x += paddingX;
34136
34250
  this.ksNewAccidentals.forEach(acc => {
34137
- acc.obj.layout(renderer);
34138
- acc.obj.offset(x + acc.obj.getRect().leftw, row.getPitchY(acc.pitch));
34139
- this.rect.expandInPlace(acc.obj.getRect());
34140
- x = this.rect.right;
34251
+ var accStaff = row.getStaff(acc.pitch);
34252
+ if (accStaff) {
34253
+ acc.obj.layout(renderer);
34254
+ acc.obj.offset(x + acc.obj.getRect().leftw, accStaff.getPitchY(acc.pitch));
34255
+ this.rect.expandInPlace(acc.obj.getRect());
34256
+ x = this.rect.right;
34257
+ }
34141
34258
  });
34142
34259
  }
34143
34260
  var right = x;
34144
34261
  if (this.beatCountText) {
34145
34262
  this.beatCountText.layout(renderer);
34146
- this.beatCountText.offset(x + paddingX, row.getPitchY(this.staffLine.middleLinePitch + 2));
34263
+ this.beatCountText.offset(x + paddingX, staff.getPitchY(staff.middleLinePitch + 2));
34147
34264
  this.rect.expandInPlace(this.beatCountText.getRect());
34148
34265
  right = Math.max(right, this.rect.right);
34149
34266
  }
34150
34267
  if (this.beatSizeText) {
34151
34268
  this.beatSizeText.layout(renderer);
34152
- this.beatSizeText.offset(x + paddingX, row.getPitchY(this.staffLine.bottomLinePitch + 2));
34269
+ this.beatSizeText.offset(x + paddingX, staff.getPitchY(staff.bottomLinePitch + 2));
34153
34270
  this.rect.expandInPlace(this.beatSizeText.getRect());
34154
34271
  right = Math.max(right, this.rect.right);
34155
34272
  }
34156
34273
  x = right;
34157
34274
  if (this.tempoText) {
34158
34275
  this.tempoText.layout(renderer);
34159
- this.tempoText.offset(x, Math.min(this.rect.top, row.getPitchY(this.staffLine.topLinePitch)));
34276
+ this.tempoText.offset(x, Math.min(this.rect.top, staff.topLineY));
34160
34277
  this.rect.expandInPlace(this.tempoText.getRect());
34161
34278
  }
34162
34279
  this.rect.expandInPlace(new DivRect(this.rect.left, this.rect.right + paddingX, this.rect.centerY, this.rect.centerY));
@@ -34294,13 +34411,19 @@ ObjArpeggio.NumCycles = 5;
34294
34411
  var StaffKind;
34295
34412
  (function (StaffKind) {
34296
34413
  /** Treble staff has treble (G-) clef. */
34297
- StaffKind[StaffKind["Treble"] = 0] = "Treble";
34298
- /** TrebleForGuitar has treble clef but is one octave lower. */
34299
- StaffKind[StaffKind["TrebleForGuitar"] = 1] = "TrebleForGuitar";
34414
+ StaffKind[StaffKind["Treble"] = 1] = "Treble";
34300
34415
  /** Bass staff has bass (F-) clef. */
34301
34416
  StaffKind[StaffKind["Bass"] = 2] = "Bass";
34302
34417
  /** Grand staff has both treble and bass clefs. */
34303
34418
  StaffKind[StaffKind["Grand"] = 3] = "Grand";
34419
+ /** GuitarTreble has treble clef but is one octave lower. */
34420
+ StaffKind[StaffKind["GuitarTreble"] = 4] = "GuitarTreble";
34421
+ // /** GuitarTab has tab for guitar. */
34422
+ StaffKind[StaffKind["GuitarTab"] = 8] = "GuitarTab";
34423
+ // /** GuitarTrebleAndTab has treble clef and tab for guitar. */
34424
+ StaffKind[StaffKind["GuitarTrebleAndTab"] = 12] = "GuitarTrebleAndTab";
34425
+ /** @deprecated TrebleForGuitar was replaced by GuitarTreble. */
34426
+ StaffKind[StaffKind["TrebleForGuitar"] = 4] = "TrebleForGuitar";
34304
34427
  })(StaffKind || (StaffKind = {}));
34305
34428
  /** @public */
34306
34429
  var Stem;
@@ -34392,19 +34515,23 @@ var Label;
34392
34515
 
34393
34516
 
34394
34517
 
34395
-
34518
+ class RestStaffObjects {
34519
+ constructor() {
34520
+ this.dotRect = new DivRect();
34521
+ }
34522
+ }
34396
34523
  class ObjRest extends MusicObject {
34397
34524
  constructor(col, voiceId, noteLength, options) {
34398
34525
  var _a, _b;
34399
34526
  super(col);
34400
34527
  this.col = col;
34401
34528
  this.voiceId = voiceId;
34402
- this.dotRect = new DivRect();
34403
34529
  this.ownAvgPitch = this.measure.updateOwnAvgPitch(voiceId, options === null || options === void 0 ? void 0 : options.pitch);
34404
34530
  this.ownStemDir = this.measure.updateOwnStemDir(this /*, options?.stem*/);
34405
34531
  this.color = (_a = options === null || options === void 0 ? void 0 : options.color) !== null && _a !== void 0 ? _a : "black";
34406
34532
  this.hide = (_b = options === null || options === void 0 ? void 0 : options.hide) !== null && _b !== void 0 ? _b : false;
34407
34533
  this.rhythmProps = new RhythmProps(noteLength, options === null || options === void 0 ? void 0 : options.dotted, options === null || options === void 0 ? void 0 : options.triplet);
34534
+ this.staffObjs = this.row.hasStaff ? new RestStaffObjects() : undefined;
34408
34535
  this.mi = new MRest(this);
34409
34536
  }
34410
34537
  getMusicInterface() {
@@ -34426,7 +34553,11 @@ class ObjRest extends MusicObject {
34426
34553
  return this.rhythmProps.dotted;
34427
34554
  }
34428
34555
  get stemDir() {
34429
- return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
34556
+ if (this.staffObjs) {
34557
+ return this.staffObjs.beamGroup ? this.staffObjs.beamGroup.stemDir : this.ownStemDir;
34558
+ } else {
34559
+ return Stem.Up;
34560
+ }
34430
34561
  }
34431
34562
  get triplet() {
34432
34563
  return this.rhythmProps.triplet;
@@ -34435,13 +34566,18 @@ class ObjRest extends MusicObject {
34435
34566
  return this.rect.contains(x, y) ? [this] : [];
34436
34567
  }
34437
34568
  getBeamGroup() {
34438
- return this.beamGroup;
34569
+ var _a;
34570
+ return (_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.beamGroup;
34439
34571
  }
34440
34572
  setBeamGroup(beam) {
34441
- this.beamGroup = beam;
34573
+ if (this.staffObjs) {
34574
+ this.staffObjs.beamGroup = beam;
34575
+ }
34442
34576
  }
34443
34577
  resetBeamGroup() {
34444
- this.beamGroup = undefined;
34578
+ if (this.staffObjs) {
34579
+ this.staffObjs.beamGroup = undefined;
34580
+ }
34445
34581
  }
34446
34582
  getBeamX() {
34447
34583
  return this.rect.centerX;
@@ -34471,8 +34607,9 @@ class ObjRest extends MusicObject {
34471
34607
  }
34472
34608
  updateAccidentalState(accState) {}
34473
34609
  layout(renderer, accState) {
34474
- if (this.hide) {
34610
+ if (this.hide || !this.staffObjs) {
34475
34611
  this.rect = new DivRect();
34612
+ return;
34476
34613
  }
34477
34614
  var {
34478
34615
  unitSize
@@ -34512,30 +34649,32 @@ class ObjRest extends MusicObject {
34512
34649
  bottomh = unitSize * (1 + flagCount + adj);
34513
34650
  }
34514
34651
  if (dotted) {
34515
- var dotWidth = Renderer.DotSize * unitSize;
34516
- var dotX = rightw + (DocumentSettings.RestDotSpace + Renderer.DotSize / 2) * unitSize;
34652
+ var dotWidth = DocumentSettings.DotSize * unitSize;
34653
+ var dotX = rightw + (DocumentSettings.RestDotSpace + DocumentSettings.DotSize / 2) * unitSize;
34517
34654
  var dotY = this.getRestDotVerticalDisplacement(noteLength) * unitSize;
34518
- this.dotRect = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
34519
- toph = Math.max(toph, this.dotRect.toph);
34520
- bottomh = Math.max(bottomh, this.dotRect.bottomh);
34521
- rightw += (DocumentSettings.RestDotSpace + Renderer.DotSize) * unitSize;
34655
+ this.staffObjs.dotRect = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
34656
+ toph = Math.max(toph, this.staffObjs.dotRect.toph);
34657
+ bottomh = Math.max(bottomh, this.staffObjs.dotRect.bottomh);
34658
+ rightw += (DocumentSettings.RestDotSpace + DocumentSettings.DotSize) * unitSize;
34522
34659
  }
34523
34660
  this.rect = new DivRect(-leftw, 0, rightw, -toph, 0, bottomh);
34524
34661
  var restPitch = ownAvgPitch;
34525
34662
  // Make sure restPitch is line, not space
34526
- if (this.row.isPitchSpace(restPitch)) {
34527
- var staffLine = this.row.getClosestStaffLine(restPitch);
34528
- restPitch += restPitch >= staffLine.middleLinePitch ? 1 : -1;
34663
+ var staff = this.row.getStaff(restPitch);
34664
+ if (staff && staff.isPitchSpace(restPitch)) {
34665
+ restPitch += restPitch >= staff.middleLinePitch ? 1 : -1;
34666
+ this.offset(0, staff.getPitchY(restPitch));
34529
34667
  }
34530
- this.offset(0, this.row.getPitchY(restPitch));
34531
34668
  }
34532
34669
  offset(dx, dy) {
34533
- this.dotRect.offsetInPlace(dx, dy);
34670
+ if (this.staffObjs) {
34671
+ this.staffObjs.dotRect.offsetInPlace(dx, dy);
34672
+ }
34534
34673
  this.rect.offsetInPlace(dx, dy);
34535
34674
  }
34536
34675
  draw(renderer) {
34537
34676
  var ctx = renderer.getCanvasContext();
34538
- if (!ctx || this.hide) {
34677
+ if (!ctx || this.hide || !this.staffObjs) {
34539
34678
  return;
34540
34679
  }
34541
34680
  renderer.drawDebugRect(this.rect);
@@ -34594,7 +34733,7 @@ class ObjRest extends MusicObject {
34594
34733
  }
34595
34734
  }
34596
34735
  if (dotted) {
34597
- var r = this.dotRect;
34736
+ var r = this.staffObjs.dotRect;
34598
34737
  renderer.fillCircle(r.centerX, r.centerY, r.width / 2);
34599
34738
  }
34600
34739
  }
@@ -34608,8 +34747,9 @@ class ObjRest extends MusicObject {
34608
34747
 
34609
34748
 
34610
34749
  class ObjArc extends MusicObject {
34611
- constructor(arcData, measure, leftNoteGroup, leftNote) {
34750
+ constructor(arcProps, measure, leftNoteGroup, leftNote) {
34612
34751
  super(measure);
34752
+ this.arcProps = arcProps;
34613
34753
  this.lx = 0;
34614
34754
  this.ly = 0;
34615
34755
  this.rx = 0;
@@ -34620,7 +34760,6 @@ class ObjArc extends MusicObject {
34620
34760
  this.cp2y = 0;
34621
34761
  this.arcHeight = 0;
34622
34762
  this.measure = measure;
34623
- this.arcData = arcData;
34624
34763
  this.leftNoteGroup = leftNoteGroup;
34625
34764
  this.leftNote = leftNote;
34626
34765
  if ((arguments.length <= 4 ? undefined : arguments[4]) instanceof ObjNoteGroup && (arguments.length <= 5 ? undefined : arguments[5]) instanceof Note) {
@@ -34633,19 +34772,16 @@ class ObjArc extends MusicObject {
34633
34772
  this.tieLength = arguments.length <= 4 ? undefined : arguments[4];
34634
34773
  }
34635
34774
  this.mi = new MArc(this);
34636
- this.measure.addArc(this);
34775
+ this.measure.addArcObject(this);
34637
34776
  }
34638
34777
  getMusicInterface() {
34639
34778
  return this.mi;
34640
34779
  }
34641
- getArcData() {
34642
- return this.arcData;
34643
- }
34644
34780
  isTie() {
34645
- return this.arcData.arcType === "tie";
34781
+ return this.arcProps.arcType === "tie";
34646
34782
  }
34647
34783
  isSlur() {
34648
- return this.arcData.arcType === "slur";
34784
+ return this.arcProps.arcType === "slur";
34649
34785
  }
34650
34786
  isInsideMeasure() {
34651
34787
  return this.rightNoteGroup === undefined || this.leftNoteGroup.measure === this.rightNoteGroup.measure;
@@ -34673,17 +34809,15 @@ class ObjArc extends MusicObject {
34673
34809
  var {
34674
34810
  arcPos,
34675
34811
  arcDir
34676
- } = this.arcData;
34677
- var leftPos = leftNoteGroup.getArcAnchorPoint(renderer, leftNoteGroup, leftNote, arcPos, "left");
34678
- leftPos = Assert.require(leftPos, "Left arc anchor point is required!");
34679
- var rightPos = rightNoteGroup !== undefined && rightNote !== undefined ? rightNoteGroup.getArcAnchorPoint(renderer, rightNoteGroup, rightNote, arcPos, "right") : this.tieLength === TieLength.ToMeasureEnd ? {
34812
+ } = this.arcProps;
34813
+ var leftPos = leftNoteGroup.getArcAnchorPoint(leftNote, arcPos, "left");
34814
+ var rightPos = rightNoteGroup !== undefined && rightNote !== undefined ? rightNoteGroup.getArcAnchorPoint(rightNote, arcPos, "right") : this.tieLength === TieLength.ToMeasureEnd ? {
34680
34815
  x: measure.getColumnsContentRect().right,
34681
34816
  y: leftPos.y
34682
34817
  } : {
34683
34818
  x: leftPos.x + unitSize * DocumentSettings.ShortTieLength,
34684
34819
  y: leftPos.y
34685
34820
  };
34686
- rightPos = Assert.require(rightPos, "Right arc anchor point is required!");
34687
34821
  var lx, ly, rx, ry;
34688
34822
  if (rightNoteGroup === undefined) {
34689
34823
  // TieLength.Short | TieLength.ToMeasureEnd
@@ -34772,25 +34906,30 @@ class ObjArc extends MusicObject {
34772
34906
  ctx.fill();
34773
34907
  }
34774
34908
  }
34775
- ;// ./src/music-score/engine/arc-data.ts
34909
+ ;// ./src/music-score/engine/arc-props.ts
34776
34910
 
34777
34911
 
34778
34912
 
34779
- class CollectedArcData {
34913
+ class ArcProps {
34780
34914
  constructor(arcType, arcSpan, arcPos, startNoteGroup) {
34781
34915
  this.arcType = arcType;
34782
34916
  this.arcSpan = arcSpan;
34783
34917
  this.arcPos = arcPos;
34784
- this.noteGroups = [];
34785
34918
  this.arcDir = "down";
34786
- this.noteGroups.push(startNoteGroup);
34919
+ this.noteGroups = [startNoteGroup];
34920
+ }
34921
+ getStartNoteGroup() {
34922
+ return this.noteGroups[0];
34923
+ }
34924
+ startsWith(noteGroup) {
34925
+ return this.noteGroups[0] === noteGroup;
34787
34926
  }
34788
34927
  /**
34789
34928
  *
34790
34929
  * @param noteGroup -
34791
34930
  * @returns true if noteGroup was added, false if not.
34792
34931
  */
34793
- add(noteGroup) {
34932
+ addNoteGroup(noteGroup) {
34794
34933
  if (this.arcSpan === TieLength.Short || this.arcSpan === TieLength.ToMeasureEnd) {
34795
34934
  // Contains already 1 NoteGroup
34796
34935
  return false;
@@ -34801,9 +34940,6 @@ class CollectedArcData {
34801
34940
  return false;
34802
34941
  }
34803
34942
  }
34804
- startsWith(noteGroup) {
34805
- return this.noteGroups[0] === noteGroup;
34806
- }
34807
34943
  computeParams() {
34808
34944
  var stemDir = this.noteGroups[0].stemDir;
34809
34945
  if (this.arcPos === ArcPos.StemTip) {
@@ -34822,16 +34958,24 @@ class CollectedArcData {
34822
34958
  row
34823
34959
  } = this.noteGroups[0].measure;
34824
34960
  var notePitch = this.noteGroups[0].ownAvgPitch;
34825
- var staffLine = row.getClosestStaffLine(notePitch);
34826
- this.arcDir = notePitch < staffLine.middleLinePitch ? "down" : "up";
34961
+ var staff = row.getStaff(notePitch);
34962
+ this.arcDir = !staff || notePitch < staff.middleLinePitch ? "down" : "up";
34827
34963
  } else if (this.arcPos === ArcPos.Above) {
34828
34964
  this.arcDir = "up";
34829
34965
  } else if (this.arcPos === ArcPos.Below) {
34830
34966
  this.arcDir = "down";
34831
34967
  }
34832
34968
  }
34833
- createObjArcs() {
34969
+ removeArcs() {
34970
+ this.noteGroups.forEach(n => {
34971
+ n.measure.removeArcObjects();
34972
+ n.removeArcProps();
34973
+ });
34974
+ this.noteGroups.length = 1;
34975
+ }
34976
+ createArcs() {
34834
34977
  var _this = this;
34978
+ this.getStartNoteGroup().collectArcProps();
34835
34979
  this.computeParams();
34836
34980
  var {
34837
34981
  arcSpan,
@@ -34847,10 +34991,10 @@ class CollectedArcData {
34847
34991
  var _loop = function _loop() {
34848
34992
  var leftNoteGroup = _this.noteGroups[i];
34849
34993
  var rightNoteGroup = _this.noteGroups[i + 1];
34850
- leftNoteGroup.notes.forEach(note => {
34851
- // Create arc from left to right only if note is found in all note-groups so far.
34852
- if (_this.noteGroups.every(noteGroup => noteGroup.notes.some(n => n.equals(note)))) {
34853
- _this.createObjArc(leftNoteGroup, note, rightNoteGroup, note);
34994
+ leftNoteGroup.notes.forEach(leftNote => {
34995
+ var rightNote = rightNoteGroup.notes.find(rightNote => rightNote.equals(leftNote));
34996
+ if (rightNote) {
34997
+ _this.createObjArc(leftNoteGroup, leftNote, rightNoteGroup, leftNote);
34854
34998
  }
34855
34999
  });
34856
35000
  };
@@ -35137,6 +35281,36 @@ class ObjBeamGroup extends MusicObject {
35137
35281
 
35138
35282
 
35139
35283
 
35284
+ function sortNoteStringData(notes, strings) {
35285
+ var stringArr = Utils.Arr.isArray(strings) ? strings : strings !== undefined ? [strings] : [];
35286
+ var noteStringData = notes.map((note, i) => {
35287
+ return {
35288
+ note,
35289
+ string: stringArr[i]
35290
+ };
35291
+ });
35292
+ noteStringData = Utils.Arr.removeDuplicatesCmp(noteStringData, (a, b) => a.note.equals(b.note)).sort((a, b) => Note.compareFunc(a.note, b.note));
35293
+ return {
35294
+ notes: noteStringData.map(e => e.note),
35295
+ strings: noteStringData.every(e => e.string === undefined) ? undefined : noteStringData.map(e => e.string)
35296
+ };
35297
+ }
35298
+ function solveArpeggio(a) {
35299
+ return a === true || a === Arpeggio.Up ? Arpeggio.Up : a === Arpeggio.Down ? Arpeggio.Down : undefined;
35300
+ }
35301
+ class NoteStaffObjects {
35302
+ constructor() {
35303
+ this.noteHeadRects = [];
35304
+ this.dotRects = [];
35305
+ this.accidentals = [];
35306
+ this.flagRects = [];
35307
+ }
35308
+ }
35309
+ class NoteTabObjects {
35310
+ constructor() {
35311
+ this.fretNumbers = [];
35312
+ }
35313
+ }
35140
35314
  class ObjNoteGroup extends MusicObject {
35141
35315
  constructor(col, voiceId, notes, noteLength, options) {
35142
35316
  var _a, _b, _c, _d, _e;
@@ -35144,28 +35318,37 @@ class ObjNoteGroup extends MusicObject {
35144
35318
  this.col = col;
35145
35319
  this.voiceId = voiceId;
35146
35320
  this.notes = notes;
35147
- this.tieDatas = [];
35148
- this.slurDatas = [];
35149
- this.noteHeadRects = [];
35150
- this.dotRects = [];
35151
- this.accidentals = [];
35152
- this.flagRects = [];
35321
+ this.tieProps = [];
35322
+ this.slurProps = [];
35153
35323
  this.leftBeamCount = 0;
35154
35324
  this.rightBeamCount = 0;
35155
35325
  Assert.int_gte(notes.length, 1, "Cannot create note group object because notes array is empty.");
35156
- this.notes = Note.sort(Note.removeDuplicates(notes));
35326
+ var noteStringData = sortNoteStringData(notes, options === null || options === void 0 ? void 0 : options.string);
35327
+ this.notes = noteStringData.notes;
35157
35328
  this.minPitch = this.notes[0].pitch;
35158
35329
  this.maxPitch = this.notes[this.notes.length - 1].pitch;
35159
35330
  this.ownAvgPitch = this.measure.updateOwnAvgPitch(voiceId, Math.round((this.minPitch + this.maxPitch) / 2));
35160
35331
  this.ownStemDir = this.measure.updateOwnStemDir(this, options === null || options === void 0 ? void 0 : options.stem);
35332
+ this.ownString = this.measure.updateOwnString(this, noteStringData.strings);
35161
35333
  this.color = (_a = options === null || options === void 0 ? void 0 : options.color) !== null && _a !== void 0 ? _a : "black";
35162
35334
  this.staccato = (_b = options === null || options === void 0 ? void 0 : options.staccato) !== null && _b !== void 0 ? _b : false;
35163
35335
  this.diamond = (_c = options === null || options === void 0 ? void 0 : options.diamond) !== null && _c !== void 0 ? _c : false;
35164
- this.arpeggio = options === null || options === void 0 ? void 0 : options.arpeggio;
35165
- this.tieSpan = options === null || options === void 0 ? void 0 : options.tieSpan;
35166
- this.slurSpan = options === null || options === void 0 ? void 0 : options.slurSpan;
35167
- this.arcPos = (_e = (_d = options === null || options === void 0 ? void 0 : options.tiePos) !== null && _d !== void 0 ? _d : options === null || options === void 0 ? void 0 : options.slurPos) !== null && _e !== void 0 ? _e : ArcPos.Auto;
35336
+ this.arpeggio = solveArpeggio(options === null || options === void 0 ? void 0 : options.arpeggio);
35168
35337
  this.rhythmProps = new RhythmProps(noteLength, options === null || options === void 0 ? void 0 : options.dotted, options === null || options === void 0 ? void 0 : options.triplet);
35338
+ if ((options === null || options === void 0 ? void 0 : options.tieSpan) !== undefined) {
35339
+ this.startTie = new ArcProps("tie", options.tieSpan, (_d = options.tiePos) !== null && _d !== void 0 ? _d : ArcPos.Auto, this);
35340
+ this.doc.addArcProps(this.startTie);
35341
+ }
35342
+ if ((options === null || options === void 0 ? void 0 : options.slurSpan) !== undefined) {
35343
+ this.startSlur = new ArcProps("slur", options.slurSpan, (_e = options.slurPos) !== null && _e !== void 0 ? _e : ArcPos.Auto, this);
35344
+ this.doc.addArcProps(this.startSlur);
35345
+ }
35346
+ if (!this.row.hasStaff) {
35347
+ Assert.assert(this.startTie === undefined, "Ties not implemented for guitar tabs alone, staff is required!");
35348
+ Assert.assert(this.startSlur === undefined, "Slurs not implemented for guitar tabs alone, staff is required!");
35349
+ }
35350
+ this.staffObjs = this.row.hasStaff ? new NoteStaffObjects() : undefined;
35351
+ this.tabObjs = this.row.hasTab ? new NoteTabObjects() : undefined;
35169
35352
  this.mi = new MNoteGroup(this);
35170
35353
  }
35171
35354
  getMusicInterface() {
@@ -35181,7 +35364,11 @@ class ObjNoteGroup extends MusicObject {
35181
35364
  return this.col.row;
35182
35365
  }
35183
35366
  get stemDir() {
35184
- return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
35367
+ if (this.staffObjs) {
35368
+ return this.staffObjs.beamGroup ? this.staffObjs.beamGroup.stemDir : this.ownStemDir;
35369
+ } else {
35370
+ return Stem.Up;
35371
+ }
35185
35372
  }
35186
35373
  get triplet() {
35187
35374
  return this.rhythmProps.triplet;
@@ -35190,12 +35377,25 @@ class ObjNoteGroup extends MusicObject {
35190
35377
  if (!this.rect.contains(x, y)) {
35191
35378
  return [];
35192
35379
  }
35193
- for (var i = 0; i < this.accidentals.length; i++) {
35194
- var acc = this.accidentals[i];
35195
- if (acc) {
35196
- var arr = acc.pick(x, y);
35197
- if (arr.length > 0) {
35198
- return [this, ...arr];
35380
+ if (this.staffObjs) {
35381
+ for (var i = 0; i < this.staffObjs.accidentals.length; i++) {
35382
+ var acc = this.staffObjs.accidentals[i];
35383
+ if (acc) {
35384
+ var arr = acc.pick(x, y);
35385
+ if (arr.length > 0) {
35386
+ return [this, ...arr];
35387
+ }
35388
+ }
35389
+ }
35390
+ }
35391
+ if (this.tabObjs) {
35392
+ for (var _i = 0; _i < this.tabObjs.fretNumbers.length; _i++) {
35393
+ var fn = this.tabObjs.fretNumbers[_i];
35394
+ if (fn) {
35395
+ var _arr = fn.pick(x, y);
35396
+ if (_arr.length > 0) {
35397
+ return [this, ..._arr];
35398
+ }
35199
35399
  }
35200
35400
  }
35201
35401
  }
@@ -35207,120 +35407,124 @@ class ObjNoteGroup extends MusicObject {
35207
35407
  getBottomNote() {
35208
35408
  return this.notes[0];
35209
35409
  }
35210
- getArcAnchorPoint(renderer, noteGroup, note, arcPos, side) {
35211
- if (arcPos === ArcPos.Auto) {
35212
- arcPos = ArcPos.Below;
35213
- }
35214
- var hasStem = !!this.stemRect;
35215
- var stemSide = !hasStem ? undefined : this.stemDir === Stem.Up ? "right" : "left";
35216
- var stemDir = this.stemDir;
35410
+ getArcAnchorPoint(note, arcPos, side) {
35217
35411
  var noteId = this.notes.findIndex(note2 => note2.equals(note));
35218
- if (noteId < 0) {
35219
- return undefined;
35220
- }
35221
- var r = this.noteHeadRects[noteId];
35222
- if (!r) {
35223
- return undefined;
35224
- }
35225
- var {
35226
- unitSize
35227
- } = renderer;
35228
- if (arcPos === ArcPos.StemTip && !hasStem) {
35229
- arcPos = this.stemDir === Stem.Up ? ArcPos.Above : ArcPos.Below;
35230
- }
35231
- var centerX = r.centerX;
35232
- var centerY = r.centerY;
35233
- var leftX = centerX - unitSize * 1.5;
35234
- var rightX = centerX + unitSize * 1.5;
35235
- var aboveY = centerY - unitSize * 1.5;
35236
- var belowY = centerY + unitSize * 1.5;
35237
- if (arcPos === ArcPos.Middle) {
35238
- return side === "left" ? {
35239
- x: rightX,
35240
- y: centerY
35241
- } : {
35242
- x: leftX,
35243
- y: centerY
35412
+ if (!this.staffObjs || noteId < 0 || noteId >= this.staffObjs.noteHeadRects.length) {
35413
+ var r = this.getRect();
35414
+ return {
35415
+ x: r.centerX,
35416
+ y: r.bottom
35244
35417
  };
35245
- } else if (arcPos === ArcPos.Above) {
35246
- if (!hasStem || stemDir === Stem.Down) {
35247
- return {
35248
- x: centerX,
35249
- y: aboveY
35250
- };
35251
- } else {
35252
- return {
35253
- x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35254
- y: aboveY
35255
- };
35256
- }
35257
- } else if (arcPos === ArcPos.Below) {
35258
- if (!hasStem || stemDir === Stem.Up) {
35259
- return {
35260
- x: centerX,
35261
- y: belowY
35262
- };
35263
- } else {
35264
- return {
35265
- x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35266
- y: belowY
35267
- };
35268
- }
35269
- } else if (arcPos === ArcPos.StemTip) {
35270
- var stemRect = Assert.require(this.stemRect, "Cannot get stem tip arc anchort point because this note group has no stem.");
35271
- if (noteGroup.stemDir === Stem.Up) {
35272
- return {
35273
- x: centerX,
35274
- y: stemRect.top - unitSize
35275
- };
35276
- } else if (noteGroup.stemDir === Stem.Down) {
35277
- return {
35278
- x: centerX,
35279
- y: stemRect.bottom + unitSize
35418
+ }
35419
+ var noteHeadRect = this.staffObjs.noteHeadRects[noteId];
35420
+ var stemRect = this.staffObjs.stemRect;
35421
+ var stemDir = this.stemDir;
35422
+ var hasStem = stemRect !== undefined;
35423
+ var stemSide = !hasStem ? undefined : stemDir === Stem.Up ? "right" : "left";
35424
+ var padding = noteHeadRect.height / 2;
35425
+ var centerX = noteHeadRect.centerX;
35426
+ var centerY = noteHeadRect.centerY;
35427
+ var leftX = noteHeadRect.left - padding;
35428
+ var rightX = noteHeadRect.right + padding;
35429
+ var aboveY = noteHeadRect.top - padding;
35430
+ var belowY = noteHeadRect.bottom + padding;
35431
+ if (arcPos === ArcPos.Auto) {
35432
+ arcPos = ArcPos.Below;
35433
+ } else if (arcPos === ArcPos.StemTip && !hasStem) {
35434
+ arcPos = stemDir === Stem.Up ? ArcPos.Above : ArcPos.Below;
35435
+ }
35436
+ switch (arcPos) {
35437
+ case ArcPos.Middle:
35438
+ return side === "left" ? {
35439
+ x: rightX,
35440
+ y: centerY
35441
+ } : {
35442
+ x: leftX,
35443
+ y: centerY
35280
35444
  };
35281
- }
35445
+ case ArcPos.Above:
35446
+ if (!hasStem || stemDir === Stem.Down) {
35447
+ return {
35448
+ x: centerX,
35449
+ y: aboveY
35450
+ };
35451
+ } else {
35452
+ return {
35453
+ x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35454
+ y: aboveY
35455
+ };
35456
+ }
35457
+ case ArcPos.Below:
35458
+ if (!hasStem || stemDir === Stem.Up) {
35459
+ return {
35460
+ x: centerX,
35461
+ y: belowY
35462
+ };
35463
+ } else {
35464
+ return {
35465
+ x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35466
+ y: belowY
35467
+ };
35468
+ }
35469
+ case ArcPos.StemTip:
35470
+ // stemRect is defined.
35471
+ if (stemDir === Stem.Up) {
35472
+ return {
35473
+ x: centerX,
35474
+ y: stemRect.top - padding
35475
+ };
35476
+ } else if (stemDir === Stem.Down) {
35477
+ return {
35478
+ x: centerX,
35479
+ y: stemRect.bottom + padding
35480
+ };
35481
+ }
35482
+ default:
35483
+ Assert.interrupt("Invalid arcPos: " + arcPos);
35282
35484
  }
35283
- return undefined;
35284
35485
  }
35285
- getPrevNoteGroup() {
35486
+ getNextNoteGroup() {
35286
35487
  var voiceNoteGroups = this.measure.getVoiceSymbols(this.voiceId).filter(s => s instanceof ObjNoteGroup);
35287
35488
  var i = voiceNoteGroups.indexOf(this);
35288
- if (i > 0) {
35289
- return voiceNoteGroups[i - 1];
35489
+ if (i < 0) {
35490
+ return undefined;
35491
+ } else if (i < voiceNoteGroups.length - 1) {
35492
+ return voiceNoteGroups[i + 1];
35290
35493
  }
35291
- var m = this.measure.getPrevMeasure();
35494
+ var m = this.measure.getNextMeasure();
35292
35495
  while (m) {
35293
35496
  var _voiceNoteGroups = m.getVoiceSymbols(this.voiceId).filter(s => s instanceof ObjNoteGroup);
35294
35497
  if (_voiceNoteGroups.length > 0) {
35295
- return _voiceNoteGroups[_voiceNoteGroups.length - 1];
35498
+ return _voiceNoteGroups[0];
35296
35499
  }
35297
- m = m.getPrevMeasure();
35500
+ m = m.getNextMeasure();
35298
35501
  }
35299
35502
  return undefined;
35300
35503
  }
35301
- collectArcDatas() {
35302
- if (this.tieSpan !== undefined) {
35303
- this.tieDatas.push(new CollectedArcData("tie", this.tieSpan, this.arcPos, this));
35304
- }
35305
- if (this.slurSpan !== undefined) {
35306
- this.slurDatas.push(new CollectedArcData("slur", this.slurSpan, this.arcPos, this));
35504
+ collectArcProps() {
35505
+ if (this.startTie) {
35506
+ this.tieProps.push(this.startTie);
35507
+ var next = this.getNextNoteGroup();
35508
+ while (next && this.startTie.addNoteGroup(next)) {
35509
+ next.tieProps.push(this.startTie);
35510
+ next = next.getNextNoteGroup();
35511
+ }
35307
35512
  }
35308
- var prevNoteGroup = this.getPrevNoteGroup();
35309
- if (prevNoteGroup) {
35310
- prevNoteGroup.tieDatas.forEach(tieData => {
35311
- if (tieData.add(this)) {
35312
- this.tieDatas.push(tieData);
35313
- }
35314
- });
35315
- prevNoteGroup.slurDatas.forEach(slurData => {
35316
- if (slurData.add(this)) {
35317
- this.slurDatas.push(slurData);
35318
- }
35319
- });
35513
+ if (this.startSlur) {
35514
+ this.slurProps.push(this.startSlur);
35515
+ var _next = this.getNextNoteGroup();
35516
+ while (_next && this.startSlur.addNoteGroup(_next)) {
35517
+ _next.slurProps.push(this.startSlur);
35518
+ _next = _next.getNextNoteGroup();
35519
+ }
35320
35520
  }
35321
35521
  }
35522
+ removeArcProps() {
35523
+ this.tieProps = [];
35524
+ this.slurProps = [];
35525
+ }
35322
35526
  getPlaySlur() {
35323
- var slurs = this.slurDatas.map(slurData => slurData.startsWith(this) ? "first" : "slurred");
35527
+ var slurs = this.slurProps.map(slur => slur.startsWith(this) ? "first" : "slurred");
35324
35528
  if (slurs.indexOf("first") >= 0) {
35325
35529
  return "first";
35326
35530
  } else if (slurs.indexOf("slurred") >= 0) {
@@ -35329,26 +35533,29 @@ class ObjNoteGroup extends MusicObject {
35329
35533
  return undefined;
35330
35534
  }
35331
35535
  }
35332
- createObjArcs() {
35333
- this.tieDatas.forEach(tieData => tieData.createObjArcs());
35334
- this.slurDatas.forEach(slurData => slurData.createObjArcs());
35335
- }
35336
35536
  getBeamGroup() {
35337
- return this.beamGroup;
35537
+ var _a;
35538
+ return (_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.beamGroup;
35338
35539
  }
35339
35540
  setBeamGroup(beam) {
35340
- this.beamGroup = beam;
35541
+ if (this.staffObjs) {
35542
+ this.staffObjs.beamGroup = beam;
35543
+ }
35341
35544
  }
35342
35545
  resetBeamGroup() {
35343
- this.leftBeamCount = this.rightBeamCount = 0;
35344
- this.beamGroup = undefined;
35546
+ if (this.staffObjs) {
35547
+ this.leftBeamCount = this.rightBeamCount = 0;
35548
+ this.staffObjs.beamGroup = undefined;
35549
+ }
35345
35550
  }
35346
35551
  getBeamX() {
35347
- var stemRect = Assert.require(this.stemRect, "Cannot get beam x-coordinate because this note group has no stem.");
35552
+ var _a;
35553
+ var stemRect = Assert.require((_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.stemRect, "Cannot get beam x-coordinate because this note group has no stem.");
35348
35554
  return stemRect.centerX;
35349
35555
  }
35350
35556
  getBeamY() {
35351
- var stemRect = Assert.require(this.stemRect, "Cannot get beam y-coordinate because this note group has no stem.");
35557
+ var _a;
35558
+ var stemRect = Assert.require((_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.stemRect, "Cannot get beam y-coordinate because this note group has no stem.");
35352
35559
  return this.stemDir === Stem.Up ? stemRect.top : stemRect.bottom;
35353
35560
  }
35354
35561
  getStemHeight(renderer) {
@@ -35376,13 +35583,13 @@ class ObjNoteGroup extends MusicObject {
35376
35583
  return this.rightBeamCount;
35377
35584
  }
35378
35585
  getPlayTicks(note) {
35379
- var tiedTicks = this.tieDatas.map(tieData => {
35380
- var tieNoteGroups = tieData.noteGroups;
35586
+ var tiedTicks = this.tieProps.map(tie => {
35587
+ var tieNoteGroups = tie.noteGroups;
35381
35588
  var j = tieNoteGroups.indexOf(this);
35382
35589
  if (j < 0) {
35383
35590
  return 0;
35384
35591
  }
35385
- if (tieData.arcSpan === TieLength.Short || tieData.arcSpan === TieLength.ToMeasureEnd) {
35592
+ if (tie.arcSpan === TieLength.Short || tie.arcSpan === TieLength.ToMeasureEnd) {
35386
35593
  return Math.max(this.rhythmProps.ticks, this.measure.getMeasureTicks() - this.col.positionTicks);
35387
35594
  }
35388
35595
  var prev = tieNoteGroups[j - 1];
@@ -35406,6 +35613,7 @@ class ObjNoteGroup extends MusicObject {
35406
35613
  });
35407
35614
  }
35408
35615
  layout(renderer, accState) {
35616
+ var _a, _b;
35409
35617
  var {
35410
35618
  unitSize
35411
35619
  } = renderer;
@@ -35415,102 +35623,157 @@ class ObjNoteGroup extends MusicObject {
35415
35623
  } = this;
35416
35624
  var {
35417
35625
  dotted,
35418
- flagCount,
35419
- noteLength
35626
+ flagCount
35420
35627
  } = this.rhythmProps;
35421
- this.noteHeadRects = [];
35422
- this.dotRects = [];
35423
- this.accidentals = [];
35424
- this.stemRect = undefined;
35425
- var dotWidth = Renderer.DotSize * unitSize;
35628
+ if (this.staffObjs) {
35629
+ this.staffObjs.noteHeadRects = [];
35630
+ this.staffObjs.dotRects = [];
35631
+ this.staffObjs.accidentals = [];
35632
+ this.staffObjs.stemRect = undefined;
35633
+ }
35634
+ if (this.tabObjs) {
35635
+ this.tabObjs.fretNumbers = [];
35636
+ }
35637
+ var dotWidth = DocumentSettings.DotSize * unitSize;
35426
35638
  var noteHeadWidth = (this.diamond ? DocumentSettings.DiamondNoteHeadSize : DocumentSettings.NoteHeadWidth) * unitSize;
35427
35639
  var noteHeadHeight = (this.diamond ? DocumentSettings.DiamondNoteHeadSize : DocumentSettings.NoteHeadHeight) * unitSize;
35428
35640
  this.notes.forEach((note, noteId) => {
35429
- var noteX = this.col.getNoteHeadDisplacement(this, note) * noteHeadWidth;
35430
- var noteY = this.row.getPitchY(note.pitch);
35431
- // Setup note head
35432
- var noteHeadRect = this.noteHeadRects[noteId] = DivRect.createCentered(noteX, noteY, noteHeadWidth, noteHeadHeight);
35433
- if (accState.needAccidental(note)) {
35434
- var acc = this.accidentals[noteId] = new ObjAccidental(this, note.accidental, this.color);
35435
- if (acc) {
35436
- acc.layout(renderer);
35437
- acc.offset(-noteHeadRect.leftw - unitSize * DocumentSettings.NoteAccSpace - acc.getRect().rightw, noteY);
35641
+ var staff = row.getStaff(note.pitch);
35642
+ if (this.staffObjs && staff) {
35643
+ var noteX = this.col.getNoteHeadDisplacement(this, note) * noteHeadWidth;
35644
+ var noteY = staff.getPitchY(note.pitch);
35645
+ // Setup note head
35646
+ var noteHeadRect = this.staffObjs.noteHeadRects[noteId] = DivRect.createCentered(noteX, noteY, noteHeadWidth, noteHeadHeight);
35647
+ // Setup accidental
35648
+ if (accState.needAccidental(note)) {
35649
+ var acc = this.staffObjs.accidentals[noteId] = new ObjAccidental(this, note.accidental, this.color);
35650
+ if (acc) {
35651
+ acc.layout(renderer);
35652
+ acc.offset(-noteHeadRect.leftw - unitSize * DocumentSettings.NoteAccSpace - acc.getRect().rightw, noteY);
35653
+ }
35654
+ }
35655
+ // Setup dot
35656
+ if (dotted) {
35657
+ var dotX = noteHeadRect.right + DocumentSettings.NoteDotSpace * unitSize + dotWidth / 2;
35658
+ var dotY = noteY + this.getDotVerticalDisplacement(note.pitch, stemDir) * unitSize;
35659
+ this.staffObjs.dotRects[noteId] = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
35438
35660
  }
35439
- }
35440
- // Set dot
35441
- if (dotted) {
35442
- var dotX = noteHeadRect.right + DocumentSettings.NoteDotSpace * unitSize + dotWidth / 2;
35443
- var dotY = noteY + this.getDotVerticalDisplacement(note.pitch, stemDir) * unitSize;
35444
- this.dotRects[noteId] = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
35445
35661
  }
35446
35662
  });
35447
35663
  // Add staccato dot
35448
- if (this.staccato) {
35449
- var dotX = this.noteHeadRects[0].centerX;
35450
- var dotY = 0;
35664
+ if (this.staccato && this.staffObjs) {
35665
+ var dotX = this.staffObjs.noteHeadRects[0].centerX;
35451
35666
  if (stemDir === Stem.Up) {
35452
- var pitch = this.notes[0].pitch;
35453
- dotY = this.row.getPitchY(pitch) + unitSize * (row.isPitchLine(pitch) ? 3 : 2);
35667
+ var pitch = this.getBottomNote().pitch;
35668
+ var staff = row.getStaff(pitch);
35669
+ if (staff) {
35670
+ var dotY = staff.getPitchY(pitch) + unitSize * (staff.isPitchLine(pitch) ? 3 : 2);
35671
+ this.staffObjs.dotRects.push(DivRect.createCentered(dotX, dotY, dotWidth, dotWidth));
35672
+ }
35454
35673
  } else {
35455
- var _pitch = this.notes[this.notes.length - 1].pitch;
35456
- dotY = this.row.getPitchY(_pitch) - unitSize * (row.isPitchLine(_pitch) ? 3 : 2);
35457
- }
35458
- this.dotRects.push(DivRect.createCentered(dotX, dotY, dotWidth, dotWidth));
35459
- }
35460
- // Calculate stem
35461
- var bottomNoteY = this.row.getPitchY(this.getBottomNote().pitch);
35462
- var topNoteY = this.row.getPitchY(this.getTopNote().pitch);
35463
- var stemX = stemDir === Stem.Up ? noteHeadWidth / 2 : -noteHeadWidth / 2;
35464
- var stemHeight = this.getStemHeight(renderer);
35465
- var stemTipY = stemDir === Stem.Up ? topNoteY - stemHeight : bottomNoteY + stemHeight;
35466
- var stemBaseY = stemDir === Stem.Up ? bottomNoteY : topNoteY;
35467
- if (this.rhythmProps.hasStem()) {
35468
- this.stemRect = new DivRect(stemX, stemX, Math.min(stemBaseY, stemTipY), Math.max(stemBaseY, stemTipY));
35469
- }
35470
- // Setup flag rects
35471
- this.flagRects = [];
35472
- if (!this.hasBeamCount()) {
35473
- var flagWidth = flagCount === 0 ? 0 : DocumentSettings.FlagWidth * unitSize;
35474
- var flagHeight = flagCount === 0 ? 0 : DocumentSettings.FlagHeight * unitSize;
35475
- for (var i = 0; i < flagCount; i++) {
35476
- var flagAddY = i * unitSize * DocumentSettings.FlagSeparation;
35477
- this.flagRects[i] = stemDir === Stem.Up ? new DivRect(stemX, stemX + flagWidth, stemTipY + flagAddY, stemTipY + flagHeight + flagAddY) : new DivRect(stemX, stemX + flagWidth, stemTipY - flagHeight - flagAddY, stemTipY - flagAddY);
35674
+ var _pitch = this.getTopNote().pitch;
35675
+ var _staff = row.getStaff(_pitch);
35676
+ if (_staff) {
35677
+ var _dotY = _staff.getPitchY(_pitch) - unitSize * (_staff.isPitchLine(_pitch) ? 3 : 2);
35678
+ this.staffObjs.dotRects.push(DivRect.createCentered(dotX, _dotY, dotWidth, dotWidth));
35679
+ }
35478
35680
  }
35479
35681
  }
35682
+ if (this.staffObjs) {
35683
+ // Calculate stem
35684
+ var bottomNoteY = (_a = row.getStaff(this.getBottomNote().pitch)) === null || _a === void 0 ? void 0 : _a.getPitchY(this.getBottomNote().pitch);
35685
+ var topNoteY = (_b = row.getStaff(this.getTopNote().pitch)) === null || _b === void 0 ? void 0 : _b.getPitchY(this.getTopNote().pitch);
35686
+ if (bottomNoteY === undefined || topNoteY === undefined) {
35687
+ Assert.interrupt("Top or bottom note is undefined!");
35688
+ }
35689
+ var stemX = stemDir === Stem.Up ? noteHeadWidth / 2 : -noteHeadWidth / 2;
35690
+ var stemHeight = this.getStemHeight(renderer);
35691
+ var stemTipY = stemDir === Stem.Up ? topNoteY - stemHeight : bottomNoteY + stemHeight;
35692
+ var stemBaseY = stemDir === Stem.Up ? bottomNoteY : topNoteY;
35693
+ if (this.rhythmProps.hasStem()) {
35694
+ this.staffObjs.stemRect = new DivRect(stemX, stemX, Math.min(stemBaseY, stemTipY), Math.max(stemBaseY, stemTipY));
35695
+ }
35696
+ // Setup flag rects
35697
+ this.staffObjs.flagRects = [];
35698
+ if (!this.hasBeamCount()) {
35699
+ var flagWidth = flagCount === 0 ? 0 : DocumentSettings.FlagWidth * unitSize;
35700
+ var flagHeight = flagCount === 0 ? 0 : DocumentSettings.FlagHeight * unitSize;
35701
+ for (var i = 0; i < flagCount; i++) {
35702
+ var flagAddY = i * unitSize * DocumentSettings.FlagSeparation;
35703
+ this.staffObjs.flagRects[i] = stemDir === Stem.Up ? new DivRect(stemX, stemX + flagWidth, stemTipY + flagAddY, stemTipY + flagHeight + flagAddY) : new DivRect(stemX, stemX + flagWidth, stemTipY - flagHeight - flagAddY, stemTipY - flagAddY);
35704
+ }
35705
+ }
35706
+ }
35707
+ var tab = row.getTab();
35708
+ this.notes.forEach((note, noteId) => {
35709
+ var _a;
35710
+ // Add tab fret numbers
35711
+ if (tab && this.tabObjs && this.ownString[noteId] !== undefined) {
35712
+ var stringId = this.ownString[noteId] - 1;
35713
+ var fretId = note.noteId - this.doc.tuningStrings[stringId].noteId;
35714
+ var color = fretId < 0 ? "red" : "black";
35715
+ var fretNumber = new ObjText(this, {
35716
+ text: String(fretId),
35717
+ color,
35718
+ bgcolor: "white"
35719
+ }, 0.5, 0.5);
35720
+ this.tabObjs.fretNumbers.push(fretNumber);
35721
+ fretNumber.layout(renderer);
35722
+ var noteX = this.col.getNoteHeadDisplacement(this, note) * noteHeadWidth;
35723
+ var _stemX = ((_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.stemRect) ? this.staffObjs.stemRect.centerX : undefined;
35724
+ var x = _stemX !== null && _stemX !== void 0 ? _stemX : noteX;
35725
+ var y = tab.getStringY(stringId);
35726
+ fretNumber.offset(x, y);
35727
+ }
35728
+ });
35480
35729
  this.updateRect();
35481
35730
  }
35482
35731
  updateRect() {
35483
- this.rect = this.noteHeadRects[0].copy();
35484
- this.noteHeadRects.forEach(r => this.rect.expandInPlace(r));
35485
- if (this.stemRect) {
35486
- this.rect.expandInPlace(this.stemRect);
35732
+ if (this.staffObjs) {
35733
+ this.rect = this.staffObjs.noteHeadRects[0].copy();
35734
+ this.staffObjs.noteHeadRects.forEach(r => this.rect.expandInPlace(r));
35735
+ if (this.staffObjs.stemRect) {
35736
+ this.rect.expandInPlace(this.staffObjs.stemRect);
35737
+ }
35738
+ this.staffObjs.dotRects.forEach(r => this.rect.expandInPlace(r));
35739
+ this.staffObjs.flagRects.forEach(r => this.rect.expandInPlace(r));
35740
+ this.staffObjs.accidentals.forEach(a => this.rect.expandInPlace(a.getRect()));
35741
+ } else if (this.tabObjs && this.tabObjs.fretNumbers.length > 0) {
35742
+ this.rect = this.tabObjs.fretNumbers[0].getRect().copy();
35743
+ } else {
35744
+ this.rect = new DivRect();
35745
+ }
35746
+ if (this.tabObjs) {
35747
+ this.tabObjs.fretNumbers.forEach(fn => this.rect.expandInPlace(fn.getRect()));
35487
35748
  }
35488
- this.dotRects.forEach(r => this.rect.expandInPlace(r));
35489
- this.flagRects.forEach(r => this.rect.expandInPlace(r));
35490
- this.accidentals.forEach(acc => this.rect.expandInPlace(acc.getRect()));
35491
35749
  }
35492
35750
  setStemTipY(stemTipY) {
35493
- if (!this.stemRect) {
35751
+ if (!this.staffObjs || !this.staffObjs.stemRect) {
35494
35752
  return;
35495
35753
  }
35496
- var oldStemTipY = this.stemDir === Stem.Up ? this.stemRect.top : this.stemRect.bottom;
35754
+ var oldStemTipY = this.stemDir === Stem.Up ? this.staffObjs.stemRect.top : this.staffObjs.stemRect.bottom;
35497
35755
  if (stemTipY === oldStemTipY) {
35498
35756
  return;
35499
35757
  }
35500
- var r = this.stemRect;
35758
+ var r = this.staffObjs.stemRect;
35501
35759
  var top = this.stemDir === Stem.Up ? stemTipY : r.top;
35502
35760
  var bottom = this.stemDir === Stem.Up ? r.bottom : stemTipY;
35503
- this.stemRect = new DivRect(r.left, r.right, top, bottom);
35761
+ this.staffObjs.stemRect = new DivRect(r.left, r.right, top, bottom);
35504
35762
  this.updateRect();
35505
35763
  }
35506
35764
  offset(dx, dy) {
35507
- this.noteHeadRects.forEach(r => r.offsetInPlace(dx, dy));
35508
- this.dotRects.forEach(r => r.offsetInPlace(dx, dy));
35509
- this.accidentals.forEach(d => d.offset(dx, dy));
35510
- if (this.stemRect) {
35511
- this.stemRect.offsetInPlace(dx, dy);
35765
+ if (this.staffObjs) {
35766
+ this.staffObjs.noteHeadRects.forEach(r => r.offsetInPlace(dx, dy));
35767
+ this.staffObjs.dotRects.forEach(r => r.offsetInPlace(dx, dy));
35768
+ this.staffObjs.accidentals.forEach(d => d.offset(dx, dy));
35769
+ if (this.staffObjs.stemRect) {
35770
+ this.staffObjs.stemRect.offsetInPlace(dx, dy);
35771
+ }
35772
+ this.staffObjs.flagRects.forEach(r => r.offsetInPlace(dx, dy));
35773
+ }
35774
+ if (this.tabObjs) {
35775
+ this.tabObjs.fretNumbers.forEach(fn => fn.offset(dx, dy));
35512
35776
  }
35513
- this.flagRects.forEach(r => r.offsetInPlace(dx, dy));
35514
35777
  this.rect.offsetInPlace(dx, dy);
35515
35778
  }
35516
35779
  draw(renderer) {
@@ -35529,69 +35792,75 @@ class ObjNoteGroup extends MusicObject {
35529
35792
  var {
35530
35793
  noteLength
35531
35794
  } = this.rhythmProps;
35532
- // Draw accidentals
35533
- this.accidentals.forEach(d => d.draw(renderer));
35534
- ctx.strokeStyle = ctx.fillStyle = color;
35535
- ctx.lineWidth = lineWidth;
35536
- // Draw note heads
35537
- this.noteHeadRects.forEach(r => {
35538
- var outlinedNoteHead = noteLength >= NoteLength.Half;
35539
- if (this.diamond) {
35540
- if (outlinedNoteHead) {
35541
- ctx.beginPath();
35542
- ctx.lineWidth = lineWidth * 2.5;
35543
- ctx.moveTo(r.centerX, r.top);
35544
- ctx.lineTo(r.right, r.centerY);
35545
- ctx.moveTo(r.left, r.centerY);
35546
- ctx.lineTo(r.centerX, r.bottom);
35547
- ctx.stroke();
35548
- ctx.beginPath();
35549
- ctx.lineWidth = lineWidth;
35550
- ctx.moveTo(r.right, r.centerY);
35551
- ctx.lineTo(r.centerX, r.bottom);
35552
- ctx.moveTo(r.centerX, r.top);
35553
- ctx.lineTo(r.left, r.centerY);
35554
- ctx.stroke();
35795
+ if (this.staffObjs) {
35796
+ // Draw accidentals
35797
+ this.staffObjs.accidentals.forEach(d => d.draw(renderer));
35798
+ ctx.strokeStyle = ctx.fillStyle = color;
35799
+ ctx.lineWidth = lineWidth;
35800
+ // Draw note heads
35801
+ this.staffObjs.noteHeadRects.forEach(r => {
35802
+ var outlinedNoteHead = noteLength >= NoteLength.Half;
35803
+ if (this.diamond) {
35804
+ if (outlinedNoteHead) {
35805
+ ctx.beginPath();
35806
+ ctx.lineWidth = lineWidth * 2.5;
35807
+ ctx.moveTo(r.centerX, r.top);
35808
+ ctx.lineTo(r.right, r.centerY);
35809
+ ctx.moveTo(r.left, r.centerY);
35810
+ ctx.lineTo(r.centerX, r.bottom);
35811
+ ctx.stroke();
35812
+ ctx.beginPath();
35813
+ ctx.lineWidth = lineWidth;
35814
+ ctx.moveTo(r.right, r.centerY);
35815
+ ctx.lineTo(r.centerX, r.bottom);
35816
+ ctx.moveTo(r.centerX, r.top);
35817
+ ctx.lineTo(r.left, r.centerY);
35818
+ ctx.stroke();
35819
+ } else {
35820
+ ctx.beginPath();
35821
+ ctx.moveTo(r.centerX, r.top);
35822
+ ctx.lineTo(r.right, r.centerY);
35823
+ ctx.lineTo(r.centerX, r.bottom);
35824
+ ctx.lineTo(r.left, r.centerY);
35825
+ ctx.lineTo(r.centerX, r.top);
35826
+ ctx.fill();
35827
+ }
35555
35828
  } else {
35556
35829
  ctx.beginPath();
35557
- ctx.moveTo(r.centerX, r.top);
35558
- ctx.lineTo(r.right, r.centerY);
35559
- ctx.lineTo(r.centerX, r.bottom);
35560
- ctx.lineTo(r.left, r.centerY);
35561
- ctx.lineTo(r.centerX, r.top);
35562
- ctx.fill();
35830
+ ctx.ellipse(r.centerX, r.centerY, r.leftw, r.toph, -0.3, 0, Math.PI * 2);
35831
+ if (outlinedNoteHead) {
35832
+ ctx.stroke();
35833
+ } else {
35834
+ ctx.fill();
35835
+ }
35563
35836
  }
35564
- } else {
35837
+ });
35838
+ // Draw dots
35839
+ this.staffObjs.dotRects.forEach(r => renderer.fillCircle(r.centerX, r.centerY, r.width / 2));
35840
+ // Draw stem
35841
+ if (this.staffObjs.stemRect) {
35565
35842
  ctx.beginPath();
35566
- ctx.ellipse(r.centerX, r.centerY, r.leftw, r.toph, -0.3, 0, Math.PI * 2);
35567
- if (outlinedNoteHead) {
35568
- ctx.stroke();
35569
- } else {
35570
- ctx.fill();
35571
- }
35843
+ ctx.moveTo(this.staffObjs.stemRect.centerX, this.staffObjs.stemRect.bottom);
35844
+ ctx.lineTo(this.staffObjs.stemRect.centerX, this.staffObjs.stemRect.top);
35845
+ ctx.stroke();
35572
35846
  }
35573
- });
35574
- // Draw dots
35575
- this.dotRects.forEach(r => renderer.fillCircle(r.centerX, r.centerY, r.width / 2));
35576
- // Draw stem
35577
- if (this.stemRect) {
35578
- ctx.beginPath();
35579
- ctx.moveTo(this.stemRect.centerX, this.stemRect.bottom);
35580
- ctx.lineTo(this.stemRect.centerX, this.stemRect.top);
35581
- ctx.stroke();
35847
+ // Draw flags
35848
+ this.staffObjs.flagRects.forEach(rect => {
35849
+ var left = rect.left;
35850
+ var right = rect.right;
35851
+ var width = right - left;
35852
+ var top = stemDir === Stem.Up ? rect.top : rect.bottom;
35853
+ var bottom = stemDir === Stem.Up ? rect.bottom : rect.top;
35854
+ ctx.beginPath();
35855
+ ctx.moveTo(left, top);
35856
+ ctx.bezierCurveTo(left, top * 0.75 + bottom * 0.25, left + width * 1.5, top * 0.5 + bottom * 0.5, left + width * 0.5, bottom);
35857
+ ctx.stroke();
35858
+ });
35859
+ }
35860
+ if (this.tabObjs) {
35861
+ // Draw tab fret numbers
35862
+ this.tabObjs.fretNumbers.forEach(fn => fn.draw(renderer));
35582
35863
  }
35583
- // Draw flags
35584
- this.flagRects.forEach(rect => {
35585
- var left = rect.left;
35586
- var right = rect.right;
35587
- var width = right - left;
35588
- var top = stemDir === Stem.Up ? rect.top : rect.bottom;
35589
- var bottom = stemDir === Stem.Up ? rect.bottom : rect.top;
35590
- ctx.beginPath();
35591
- ctx.moveTo(left, top);
35592
- ctx.bezierCurveTo(left, top * 0.75 + bottom * 0.25, left + width * 1.5, top * 0.5 + bottom * 0.5, left + width * 0.5, bottom);
35593
- ctx.stroke();
35594
- });
35595
35864
  }
35596
35865
  static setBeamCounts(groupNotes) {
35597
35866
  var isADottedBHalf = (a, b) => {
@@ -35626,10 +35895,10 @@ class ObjNoteGroup extends MusicObject {
35626
35895
  var fixAgain;
35627
35896
  do {
35628
35897
  fixAgain = false;
35629
- for (var _i = 0; _i < groupNotes.length; _i++) {
35630
- var _center = groupNotes[_i];
35631
- var _left = groupNotes[_i - 1];
35632
- var _right = groupNotes[_i + 1];
35898
+ for (var _i2 = 0; _i2 < groupNotes.length; _i2++) {
35899
+ var _center = groupNotes[_i2];
35900
+ var _left = groupNotes[_i2 - 1];
35901
+ var _right = groupNotes[_i2 + 1];
35633
35902
  // If neither left or right beam count equals flag count, then reset beam counts.
35634
35903
  if (_center && _center.leftBeamCount !== _center.rhythmProps.flagCount && _center.rightBeamCount !== _center.rhythmProps.flagCount) {
35635
35904
  _center.leftBeamCount = _center.rightBeamCount = 0;
@@ -35666,7 +35935,8 @@ class ObjNoteGroup extends MusicObject {
35666
35935
  }
35667
35936
  }
35668
35937
  getDotVerticalDisplacement(pitch, stemDir) {
35669
- if (this.row.isPitchLine(pitch)) {
35938
+ var staff = this.row.getStaff(pitch);
35939
+ if (staff && staff.isPitchLine(pitch)) {
35670
35940
  return stemDir === Stem.Up ? -1 : 1;
35671
35941
  } else {
35672
35942
  return 0;
@@ -35697,6 +35967,7 @@ class ObjNoteGroup extends MusicObject {
35697
35967
 
35698
35968
 
35699
35969
 
35970
+
35700
35971
  var noteHeadDataCompareFunc = (a, b) => {
35701
35972
  var cmp = Note.compareFunc(a.note, b.note);
35702
35973
  if (cmp === 0) {
@@ -35814,15 +36085,16 @@ class ObjRhythmColumn extends MusicObject {
35814
36085
  }
35815
36086
  getMinWidth() {
35816
36087
  var maxNoteLength = Math.max(...this.voiceSymbol.map(s => s.rhythmProps.noteLength));
36088
+ var w = DocumentSettings.NoteHeadWidth;
35817
36089
  switch (maxNoteLength) {
35818
36090
  case NoteLength.Whole:
35819
- return 5;
36091
+ return w * 5;
35820
36092
  case NoteLength.Half:
35821
- return 4;
36093
+ return w * 3;
35822
36094
  case NoteLength.Quarter:
35823
- return 3;
36095
+ return w * 2;
35824
36096
  default:
35825
- return 2;
36097
+ return w;
35826
36098
  }
35827
36099
  }
35828
36100
  setupNoteHeadDisplacements() {
@@ -35871,6 +36143,11 @@ class ObjRhythmColumn extends MusicObject {
35871
36143
  return 0;
35872
36144
  }
35873
36145
  }
36146
+ getLowestNotePitch(pitch) {
36147
+ return Math.min(pitch, ...this.voiceSymbol.map(s => {
36148
+ return s instanceof ObjNoteGroup ? Math.min(...s.notes.map(n => n.pitch)) : s.ownAvgPitch;
36149
+ }));
36150
+ }
35874
36151
  getPlayerNotes() {
35875
36152
  var playerNotes = [];
35876
36153
  function addNote(note, ticks, staccato, slur) {
@@ -35925,16 +36202,13 @@ class ObjRhythmColumn extends MusicObject {
35925
36202
  return;
35926
36203
  }
35927
36204
  var {
35928
- row,
35929
- doc
36205
+ row
35930
36206
  } = this;
35931
36207
  var {
35932
36208
  unitSize
35933
36209
  } = renderer;
35934
36210
  // Set initially column's min width
35935
36211
  var halfMinWidth = this.getMinWidth() * unitSize / 2;
35936
- var staffTop = row.getTopStaffLineTop();
35937
- var staffBottom = row.getBottomStaffLineBottom();
35938
36212
  var initRect = true;
35939
36213
  // Layout voice symbols
35940
36214
  this.voiceSymbol.forEach(symbol => {
@@ -35947,13 +36221,15 @@ class ObjRhythmColumn extends MusicObject {
35947
36221
  this.rect.expandInPlace(r);
35948
36222
  });
35949
36223
  if (initRect) {
36224
+ var staffTop = row.hasStaff ? row.getTopStaff().topLineY : 0;
36225
+ var staffBottom = row.hasStaff ? row.getBottomStaff().bottomLineY : 0;
35950
36226
  this.rect = new DivRect(-halfMinWidth, 0, halfMinWidth, (staffTop + staffBottom) / 2, 0, (staffTop + staffBottom) / 2);
35951
36227
  }
35952
36228
  if (this.arpeggioDir !== undefined) {
35953
- this.arpeggios = row.getStaffLines().map(staffLine => {
36229
+ this.arpeggios = row.getStaves().map(staff => {
35954
36230
  var arpeggio = new ObjArpeggio(this, this.getArpeggioDir());
35955
36231
  arpeggio.layout(renderer);
35956
- arpeggio.offset(this.rect.left - arpeggio.getRect().width, staffLine.middleLineOffset * row.getLineSpacing());
36232
+ arpeggio.offset(this.rect.left - arpeggio.getRect().width, staff.middleLineY - arpeggio.getRect().centerY);
35957
36233
  return arpeggio;
35958
36234
  });
35959
36235
  this.arpeggios.forEach(arpeggio => this.rect.expandInPlace(arpeggio.getRect()));
@@ -36508,7 +36784,7 @@ class player_Player {
36508
36784
  curMeasure = segnoMeasure;
36509
36785
  } else if (curMeasure.hasNavigation(Navigation.EndRepeat)) {
36510
36786
  var _passage = curMeasure.getPassCount();
36511
- var repeatCount = curMeasure === null || curMeasure === void 0 ? void 0 : curMeasure.getEndRepeatCount();
36787
+ var repeatCount = (curMeasure === null || curMeasure === void 0 ? void 0 : curMeasure.getEndRepeatCount()) - 1;
36512
36788
  var cannotPassThrough = ((_a = curMeasure.getNextMeasure()) === null || _a === void 0 ? void 0 : _a.hasNavigation(Navigation.Ending)) === true;
36513
36789
  if (_passage <= repeatCount || cannotPassThrough) {
36514
36790
  curMeasure = startRepeatMeasure;
@@ -36789,6 +37065,7 @@ class ObjBarLine extends MusicObject {
36789
37065
  return this.rect.contains(x, y) ? [this] : [];
36790
37066
  }
36791
37067
  layout(renderer) {
37068
+ var _a, _b;
36792
37069
  this.barLineType = this.solveBarLineType();
36793
37070
  var {
36794
37071
  unitSize,
@@ -36804,23 +37081,35 @@ class ObjBarLine extends MusicObject {
36804
37081
  var thinW = lineWidth;
36805
37082
  var thicW = 0.7 * unitSize;
36806
37083
  var spaceW = 0.7 * unitSize;
36807
- var dotW = Renderer.DotSize * unitSize;
36808
- var lineSpacing = row.getLineSpacing();
37084
+ var dotW = DocumentSettings.DotSize * unitSize;
36809
37085
  var dotRadius = dotW / 2;
36810
- var dotOffset = this.measure.row.getPitchSpacing();
36811
- var top = (row.getTopStaffLine().middleLineOffset - 2) * lineSpacing;
36812
- var bottom = (row.getBottomStaffLine().middleLineOffset + 2) * lineSpacing;
37086
+ var lineCenterYs = row.getStaves().map(staff => staff.middleLineY);
37087
+ var lineDotOffs = row.getStaves().map(staff => staff.getPitchSpacing());
37088
+ var tab = row.getTab();
37089
+ if (tab) {
37090
+ lineCenterYs.push((tab.bottom + tab.top) / 2);
37091
+ lineDotOffs.push((tab.bottom - tab.top) / 6);
37092
+ }
37093
+ var top, bottom;
37094
+ if (row.hasStaff) {
37095
+ top = row.getTopStaff().topLineY;
37096
+ bottom = tab ? tab.getStringY(5) : row.getBottomStaff().bottomLineY;
37097
+ } else {
37098
+ // hasTab is true
37099
+ top = (_a = tab === null || tab === void 0 ? void 0 : tab.getStringY(0)) !== null && _a !== void 0 ? _a : 0;
37100
+ bottom = (_b = tab === null || tab === void 0 ? void 0 : tab.getStringY(5)) !== null && _b !== void 0 ? _b : 0;
37101
+ }
36813
37102
  this.lineRects = [];
36814
37103
  this.dotRects = [];
36815
37104
  var addRect = (left, width) => {
36816
37105
  this.lineRects.push(new DivRect(left, left + width / 2, left + width, top, 0, bottom));
36817
37106
  };
36818
37107
  var addDots = cx => {
36819
- row.getStaffLines().forEach(staffLine => {
36820
- var cy = staffLine.middleLineOffset * lineSpacing - dotOffset;
36821
- this.dotRects.push(new DivRect(cx - dotRadius, cx, cx + dotRadius, cy - dotRadius, cy, cy + dotRadius));
36822
- cy += 2 * dotOffset;
36823
- this.dotRects.push(new DivRect(cx - dotRadius, cx, cx + dotRadius, cy - dotRadius, cy, cy + dotRadius));
37108
+ lineCenterYs.forEach((cy, id) => {
37109
+ for (var i = -1; i <= 1; i += 2) {
37110
+ var y = cy + i * lineDotOffs[id];
37111
+ this.dotRects.push(new DivRect(cx - dotRadius, cx, cx + dotRadius, y - dotRadius, y, y + dotRadius));
37112
+ }
36824
37113
  });
36825
37114
  };
36826
37115
  switch (barLineType) {
@@ -37180,7 +37469,7 @@ class ObjExtensionLine extends MusicObject {
37180
37469
  // Draw tip end of last line
37181
37470
  var tails = this.extension.getTails();
37182
37471
  if (tails.length > 0 && this === tails[tails.length - 1]) {
37183
- var tipH = rect.centerY > this.measure.row.getBottomStaffLineBottom() ? -renderer.unitSize : renderer.unitSize;
37472
+ var tipH = rect.centerY > this.measure.row.getRect().centerY ? -renderer.unitSize : renderer.unitSize;
37184
37473
  renderer.drawLine(rect.right, rect.centerY, rect.right, rect.centerY + tipH, "black", renderer.lineWidth);
37185
37474
  }
37186
37475
  }
@@ -37226,8 +37515,9 @@ class ObjMeasure extends MusicObject {
37226
37515
  this.leftSolidAreaWidth = 0;
37227
37516
  this.minColumnsAreaWidth = 0;
37228
37517
  this.rightSolidAreaWidth = 0;
37229
- this.useStemDir = [];
37230
37518
  this.usePitch = [];
37519
+ this.useStemDir = [];
37520
+ this.useString = [];
37231
37521
  this.voiceSymbols = [];
37232
37522
  this.layoutObjects = [];
37233
37523
  this.postMeasureBreakWidth = 0;
@@ -37260,6 +37550,9 @@ class ObjMeasure extends MusicObject {
37260
37550
  isPartialMeasure() {
37261
37551
  return this.getConsumedTicks() < this.getMeasureTicks();
37262
37552
  }
37553
+ isUpBeat() {
37554
+ return this === this.doc.getFirstMeasure();
37555
+ }
37263
37556
  resetPassCount() {
37264
37557
  this.passCount = 0;
37265
37558
  }
@@ -37269,6 +37562,29 @@ class ObjMeasure extends MusicObject {
37269
37562
  getPassCount() {
37270
37563
  return this.passCount;
37271
37564
  }
37565
+ updateOwnAvgPitch(voiceId, setPitch) {
37566
+ if (typeof setPitch == "string") {
37567
+ this.usePitch[voiceId] = Note.getNote(setPitch).pitch;
37568
+ } else if (typeof setPitch == "number") {
37569
+ this.usePitch[voiceId] = setPitch;
37570
+ } else if (setPitch instanceof Note) {
37571
+ this.usePitch[voiceId] = setPitch.pitch;
37572
+ } else if (this.usePitch[voiceId] === undefined) {
37573
+ var prevMeasure = this.getPrevMeasure();
37574
+ if (prevMeasure && prevMeasure.usePitch[voiceId] !== undefined) {
37575
+ this.usePitch[voiceId] = prevMeasure.usePitch[voiceId];
37576
+ }
37577
+ }
37578
+ var pitch = this.usePitch[voiceId];
37579
+ if (pitch === undefined) {
37580
+ if (this.row.hasStaff) {
37581
+ pitch = this.row.getTopStaff().middleLinePitch;
37582
+ } else {
37583
+ pitch = Note.getNote("C4").pitch;
37584
+ }
37585
+ }
37586
+ return this.usePitch[voiceId] = Note.validatePitch(pitch);
37587
+ }
37272
37588
  updateOwnStemDir(symbol, setStemDir) {
37273
37589
  var _a, _b;
37274
37590
  var {
@@ -37281,28 +37597,27 @@ class ObjMeasure extends MusicObject {
37281
37597
  }
37282
37598
  var stemDir = this.useStemDir[voiceId];
37283
37599
  if (stemDir === Stem.Auto || stemDir === undefined) {
37284
- var staffLine = this.row.getClosestStaffLine(symbol.ownAvgPitch);
37285
- return symbol.ownAvgPitch > staffLine.middleLinePitch ? Stem.Down : Stem.Up;
37600
+ var staff = this.row.getStaff(symbol.ownAvgPitch);
37601
+ if (staff) {
37602
+ return symbol.ownAvgPitch > staff.middleLinePitch ? Stem.Down : Stem.Up;
37603
+ } else {
37604
+ return Stem.Up;
37605
+ }
37286
37606
  } else {
37287
37607
  return stemDir;
37288
37608
  }
37289
37609
  }
37290
- updateOwnAvgPitch(voiceId, setPitch) {
37291
- var _a;
37292
- if (typeof setPitch == "string") {
37293
- this.usePitch[voiceId] = Note.getNote(setPitch).pitch;
37294
- } else if (typeof setPitch == "number") {
37295
- this.usePitch[voiceId] = setPitch;
37296
- } else if (setPitch instanceof Note) {
37297
- this.usePitch[voiceId] = setPitch.pitch;
37298
- } else if (this.usePitch[voiceId] === undefined) {
37299
- var prevMeasure = this.getPrevMeasure();
37300
- if (prevMeasure && prevMeasure.usePitch[voiceId] !== undefined) {
37301
- this.usePitch[voiceId] = prevMeasure.usePitch[voiceId];
37302
- }
37610
+ updateOwnString(symbol, setString) {
37611
+ var _a, _b;
37612
+ var {
37613
+ voiceId
37614
+ } = symbol;
37615
+ if (setString !== undefined) {
37616
+ this.useString[voiceId] = setString;
37617
+ } else if (this.useString[voiceId] === undefined) {
37618
+ this.useString[voiceId] = (_b = (_a = this.getPrevMeasure()) === null || _a === void 0 ? void 0 : _a.useString[voiceId]) !== null && _b !== void 0 ? _b : [];
37303
37619
  }
37304
- var pitch = (_a = this.usePitch[voiceId]) !== null && _a !== void 0 ? _a : this.row.getTopStaffLine().middleLinePitch;
37305
- return this.usePitch[voiceId] = Note.validatePitch(pitch);
37620
+ return this.useString[voiceId];
37306
37621
  }
37307
37622
  pick(x, y) {
37308
37623
  if (!this.rect.contains(x, y)) {
@@ -37682,10 +37997,6 @@ class ObjMeasure extends MusicObject {
37682
37997
  this.voiceSymbols[voiceId].push(symbol);
37683
37998
  this.requestBeamsUpdate();
37684
37999
  this.lastAddedRhythmColumn = col;
37685
- // Collect arc data now that symbol is set
37686
- if (symbol instanceof ObjNoteGroup) {
37687
- this.onAddNoteGroup(symbol);
37688
- }
37689
38000
  }
37690
38001
  addNoteGroup(voiceId, notes, noteLength, options) {
37691
38002
  var notes2 = notes.map(note => typeof note === "string" ? Note.getNote(note) : note);
@@ -37719,16 +38030,11 @@ class ObjMeasure extends MusicObject {
37719
38030
  } else if (!_col || _col.positionTicks > positionTicks) {
37720
38031
  var _col2 = new ObjRhythmColumn(this, positionTicks);
37721
38032
  this.columns.splice(_i5, 0, _col2);
37722
- this.onAddRhythmColumn(_col2);
37723
38033
  return _col2;
37724
38034
  }
37725
38035
  }
37726
38036
  Assert.interrupt("Error in rhythm column. Should never get here.");
37727
38037
  }
37728
- onAddRhythmColumn(col) {}
37729
- onAddNoteGroup(noteGroup) {
37730
- noteGroup.collectArcDatas();
37731
- }
37732
38038
  getMeasureTicks() {
37733
38039
  return this.getTimeSignature().measureTicks;
37734
38040
  }
@@ -37774,8 +38080,8 @@ class ObjMeasure extends MusicObject {
37774
38080
  getStaffLineRight() {
37775
38081
  return this.barLineRight.getRect().centerX;
37776
38082
  }
37777
- forEachLayoutObject(fn) {
37778
- this.layoutObjects.forEach(layoutObj => fn(layoutObj));
38083
+ getStaticObjects() {
38084
+ return [...this.getColumns(), ...this.layoutObjects.filter(layoutObj => layoutObj.isPositionResolved()).map(layoutObj => layoutObj.musicObj)];
37779
38085
  }
37780
38086
  removeLayoutObjects(musicObj) {
37781
38087
  this.layoutObjects = this.layoutObjects.filter(layoutObj => {
@@ -37791,27 +38097,18 @@ class ObjMeasure extends MusicObject {
37791
38097
  }
37792
38098
  });
37793
38099
  }
37794
- addArc(arc) {
38100
+ addArcObject(arc) {
37795
38101
  this.arcs.push(arc);
37796
38102
  this.requestLayout();
37797
38103
  }
37798
- updateArcs() {
37799
- // Remove arcs
38104
+ removeArcObjects() {
37800
38105
  if (this.arcs.length > 0) {
37801
38106
  this.arcs = [];
37802
38107
  this.requestLayout();
37803
38108
  }
37804
- // Recreate arcs
37805
- ObjMeasure.VoiceIdList.forEach(voiceId => {
37806
- this.getVoiceSymbols(voiceId).forEach(symbol => {
37807
- if (symbol instanceof ObjNoteGroup) {
37808
- symbol.createObjArcs();
37809
- }
37810
- });
37811
- });
37812
38109
  }
37813
38110
  updateExtensions() {
37814
- this.forEachLayoutObject(layoutObj => {
38111
+ this.layoutObjects.forEach(layoutObj => {
37815
38112
  if (layoutObj.musicObj.getLink() instanceof Extension) {
37816
38113
  var extension = layoutObj.musicObj.getLink();
37817
38114
  if (extension.getHead() === layoutObj.musicObj) {
@@ -37840,7 +38137,7 @@ class ObjMeasure extends MusicObject {
37840
38137
  this.needBeamsUpdate = true;
37841
38138
  }
37842
38139
  updateBeams() {
37843
- if (!this.needBeamsUpdate) {
38140
+ if (!this.needBeamsUpdate || !this.row.hasStaff) {
37844
38141
  return;
37845
38142
  }
37846
38143
  // Remove old beams/triplets
@@ -37849,34 +38146,50 @@ class ObjMeasure extends MusicObject {
37849
38146
  });
37850
38147
  this.beamGroups = [];
37851
38148
  // Recreate beams/triplets
37852
- var ts = this.getTimeSignature();
37853
38149
  ObjMeasure.VoiceIdList.forEach(voiceId => {
37854
38150
  var symbols = this.getVoiceSymbols(voiceId);
37855
- ObjMeasure.createTriplets(symbols);
37856
- ObjMeasure.createBeams(symbols, ts);
37857
- });
37858
- this.needBeamsUpdate = false;
37859
- this.requestLayout();
37860
- }
37861
- static createBeams(symbols, ts) {
37862
- if (DebugSettings.DisableBeams || symbols.length < 2) {
37863
- return;
37864
- }
37865
- var groupSymbols = [];
37866
- var groupStartTicks = 0;
37867
- var groupEndTicks = 0;
37868
- symbols.forEach(symbol => {
37869
- groupSymbols.push(symbol);
37870
- groupEndTicks += symbol.rhythmProps.ticks;
37871
- if (groupStartTicks === 0 && groupEndTicks === ts.beamGroupLength) {
37872
- // Perfect group, setup beams
37873
- ObjMeasure.setupBeamGroup(groupSymbols);
38151
+ if (symbols.length <= 2) {
38152
+ return;
37874
38153
  }
37875
- while (groupEndTicks >= ts.beamGroupLength) {
37876
- groupSymbols = [];
37877
- groupStartTicks = groupEndTicks = groupEndTicks - ts.beamGroupLength;
38154
+ // Create triplets
38155
+ for (var i = 0; i < symbols.length;) {
38156
+ var s2 = symbols.slice(i, i + 2);
38157
+ var s3 = symbols.slice(i, i + 3);
38158
+ if (s2.length === 2 && ObjBeamGroup.createTriplet(s2)) {
38159
+ i += 2;
38160
+ } else if (s3.length === 3 && ObjBeamGroup.createTriplet(s3)) {
38161
+ i += 3;
38162
+ } else {
38163
+ i++;
38164
+ }
38165
+ }
38166
+ // Create beams
38167
+ if (!DebugSettings.DisableBeams) {
38168
+ var groupSymbols = [];
38169
+ var groupStartTicks = 0;
38170
+ var groupEndTicks = 0;
38171
+ // Is upbeat? Set starting ticks position.
38172
+ if (this.isUpBeat()) {
38173
+ var startTicks = Math.max(0, this.getMeasureTicks() - this.getConsumedTicks());
38174
+ groupStartTicks = groupEndTicks = startTicks;
38175
+ }
38176
+ var ts = this.getTimeSignature();
38177
+ symbols.forEach(symbol => {
38178
+ groupSymbols.push(symbol);
38179
+ groupEndTicks += symbol.rhythmProps.ticks;
38180
+ if (groupStartTicks === 0 && groupEndTicks === ts.beamGroupLength) {
38181
+ // Perfect group, setup beams
38182
+ ObjMeasure.setupBeamGroup(groupSymbols);
38183
+ }
38184
+ while (groupEndTicks >= ts.beamGroupLength) {
38185
+ groupSymbols = [];
38186
+ groupStartTicks = groupEndTicks = groupEndTicks - ts.beamGroupLength;
38187
+ }
38188
+ });
37878
38189
  }
37879
38190
  });
38191
+ this.needBeamsUpdate = false;
38192
+ this.requestLayout();
37880
38193
  }
37881
38194
  static setupBeamGroup(groupSymbols) {
37882
38195
  var groupNotes = groupSymbols.map(s => {
@@ -37896,19 +38209,6 @@ class ObjMeasure extends MusicObject {
37896
38209
  });
37897
38210
  ObjBeamGroup.createBeam(beamNotes);
37898
38211
  }
37899
- static createTriplets(symbols) {
37900
- for (var i = 0; i < symbols.length;) {
37901
- var s2 = symbols.slice(i, i + 2);
37902
- var s3 = symbols.slice(i, i + 3);
37903
- if (s2.length === 2 && ObjBeamGroup.createTriplet(s2)) {
37904
- i += 2;
37905
- } else if (s3.length === 3 && ObjBeamGroup.createTriplet(s3)) {
37906
- i += 3;
37907
- } else {
37908
- i++;
37909
- }
37910
- }
37911
- }
37912
38212
  static validateVoiceId(voiceId) {
37913
38213
  Assert.in_group(voiceId, ObjMeasure.VoiceIdList, "Invalid voice id: " + voiceId);
37914
38214
  return voiceId;
@@ -37966,6 +38266,9 @@ class ObjMeasure extends MusicObject {
37966
38266
  dotted: rest.dotted
37967
38267
  }));
37968
38268
  }
38269
+ getLowestNotePitch(pitch) {
38270
+ return Math.min(pitch, ...this.columns.map(c => c.getLowestNotePitch(pitch)));
38271
+ }
37969
38272
  requestLayout() {
37970
38273
  if (!this.needLayout) {
37971
38274
  this.needLayout = true;
@@ -37989,14 +38292,14 @@ class ObjMeasure extends MusicObject {
37989
38292
  var showTimeSignature = !!this.alterTimeSignature;
37990
38293
  var showTempo = !!this.alterTempo;
37991
38294
  if (showClef || showMeasureNumber || showKeySignature || showTimeSignature || showTempo) {
37992
- this.signatures = this.row.getStaffLines().map((staffLine, staffLineId) => {
38295
+ this.signatures = this.row.getStaves().map((staff, staffId) => {
37993
38296
  var _a;
37994
- var signature = (_a = this.signatures[staffLineId]) !== null && _a !== void 0 ? _a : new ObjSignature(this, staffLine);
38297
+ var signature = (_a = this.signatures[staffId]) !== null && _a !== void 0 ? _a : new ObjSignature(this, staff);
37995
38298
  signature.updateClefImage(renderer, showClef);
37996
- signature.updateMeasureNumber(showMeasureNumber && staffLineId === 0);
38299
+ signature.updateMeasureNumber(showMeasureNumber && staffId === 0);
37997
38300
  signature.updateKeySignature(showKeySignature);
37998
38301
  signature.updateTimeSignature(showTimeSignature);
37999
- signature.updateTempo(showTempo && staffLineId === 0);
38302
+ signature.updateTempo(showTempo && staffId === 0);
38000
38303
  signature.layout(renderer);
38001
38304
  return signature;
38002
38305
  });
@@ -38016,6 +38319,11 @@ class ObjMeasure extends MusicObject {
38016
38319
  // Calc top and bottom
38017
38320
  var top = Math.min(...this.signatures.map(signature => signature.getRect().top), this.barLineLeft.getRect().top, ...this.columns.map(col => col.getRect().top), this.barLineRight.getRect().top);
38018
38321
  var bottom = Math.max(...this.signatures.map(signature => signature.getRect().bottom), this.barLineLeft.getRect().bottom, ...this.columns.map(col => col.getRect().bottom), this.barLineRight.getRect().bottom);
38322
+ var tab = this.row.getTab();
38323
+ if (tab) {
38324
+ top = Math.min(top, tab.top);
38325
+ bottom = Math.max(bottom, tab.bottom);
38326
+ }
38019
38327
  // Set rect toph and bottomh
38020
38328
  this.rect = new DivRect(0, 0, 0, top, 0, bottom);
38021
38329
  var padding = renderer.unitSize;
@@ -38094,7 +38402,7 @@ class ObjMeasure extends MusicObject {
38094
38402
  }
38095
38403
  this.arcs.forEach(arc => arc.offset(dx, dy));
38096
38404
  this.beamGroups.forEach(beam => beam.offset(dx, dy));
38097
- this.forEachLayoutObject(layoutObj => layoutObj.musicObj.offset(dx, dy));
38405
+ this.layoutObjects.forEach(layoutObj => layoutObj.musicObj.offset(dx, dy));
38098
38406
  this.rect.offsetInPlace(dx, dy);
38099
38407
  }
38100
38408
  draw(renderer) {
@@ -38102,12 +38410,21 @@ class ObjMeasure extends MusicObject {
38102
38410
  // Draw staff lines
38103
38411
  var left = this.getStaffLineLeft();
38104
38412
  var right = this.getStaffLineRight();
38105
- this.row.getStaffLines().forEach(staffLine => {
38106
- for (var p = staffLine.bottomLinePitch; p <= staffLine.topLinePitch; p += 2) {
38107
- var y = this.row.getPitchY(p);
38108
- renderer.drawLine(left, y, right, y);
38413
+ var drawLine = y => renderer.drawLine(left, y, right, y);
38414
+ var {
38415
+ row
38416
+ } = this;
38417
+ row.getStaves().forEach(staff => {
38418
+ for (var p = staff.bottomLinePitch; p <= staff.topLinePitch; p += 2) {
38419
+ drawLine(staff.getPitchY(p));
38109
38420
  }
38110
38421
  });
38422
+ var tab = row.getTab();
38423
+ if (tab) {
38424
+ for (var stringId = 0; stringId < 6; stringId++) {
38425
+ drawLine(tab.getStringY(stringId));
38426
+ }
38427
+ }
38111
38428
  this.signatures.forEach(signature => signature.draw(renderer));
38112
38429
  this.barLineLeft.draw(renderer);
38113
38430
  this.columns.forEach(col => col.draw(renderer));
@@ -38116,7 +38433,7 @@ class ObjMeasure extends MusicObject {
38116
38433
  this.endRepeatCountText.draw(renderer);
38117
38434
  }
38118
38435
  this.arcs.forEach(arc => arc.draw(renderer));
38119
- this.forEachLayoutObject(layoutObj => layoutObj.musicObj.draw(renderer));
38436
+ this.layoutObjects.forEach(layoutObj => layoutObj.musicObj.draw(renderer));
38120
38437
  this.beamGroups.forEach(beam => beam.draw(renderer));
38121
38438
  }
38122
38439
  }
@@ -38182,16 +38499,14 @@ class LayoutObjectWrapper {
38182
38499
  measure,
38183
38500
  verticalPos
38184
38501
  } = this;
38185
- var staffTop = measure.row.getTopStaffLineTop();
38186
- var staffBottom = measure.row.getBottomStaffLineBottom();
38502
+ var {
38503
+ row
38504
+ } = measure;
38505
+ var staffTop = row.hasStaff ? row.getTopStaff().topLineY : row.getRect().centerY;
38506
+ var staffBottom = row.hasStaff ? row.getBottomStaff().bottomLineY : row.getRect().centerY;
38187
38507
  var staffPadding = renderer.unitSize * 2;
38188
38508
  var y = verticalPos === VerticalPos.BelowStaff ? staffBottom + staffPadding + musicObj.getRect().toph : staffTop - staffPadding - musicObj.getRect().bottomh;
38189
- var staticObjects = [...measure.getColumns()];
38190
- measure.forEachLayoutObject(layoutObj => {
38191
- if (layoutObj.isPositionResolved()) {
38192
- staticObjects.push(layoutObj.musicObj);
38193
- }
38194
- });
38509
+ var staticObjects = measure.getStaticObjects();
38195
38510
  var objShapeRects = musicObj.getShapeRects();
38196
38511
  staticObjects.forEach(resolveObj => {
38197
38512
  var staticShapeRects = resolveObj.getShapeRects();
@@ -38253,40 +38568,46 @@ class LayoutGroup {
38253
38568
 
38254
38569
 
38255
38570
 
38571
+
38572
+
38256
38573
  var p = noteName => Note.getNote(noteName).pitch;
38257
- var StaffLine_Treble = new StaffLine(ClefKind.Treble, p("G4"), p("B4"), 0, p("C3"), p("C7"));
38258
- var StaffLine_TrebleForGuitar = new StaffLine(ClefKind.Treble, p("G3"), p("B3"), 0, p("C2"), p("C6"));
38259
- var StaffLine_Bass = new StaffLine(ClefKind.Bass, p("F3"), p("D3"), 0, p("C1"), p("C5"));
38260
- var StaffLine_Grand_Treble = new StaffLine(ClefKind.Treble, p("G4"), p("B4"), -4, p("C4"), p("C7"));
38261
- var StaffLine_Grand_Bass = new StaffLine(ClefKind.Bass, p("F3"), p("D3"), 4, p("C1"), p("C4") - 1);
38574
+ var createStaff_Treble = () => new MusicStaff(ClefKind.Treble, p("G4"), p("B4"), p("C3"), p("C7"));
38575
+ var createStaff_GuitarTreble = () => new MusicStaff(ClefKind.Treble, p("G3"), p("B3"), p("C2"), p("C6"));
38576
+ var createStaff_Bass = () => new MusicStaff(ClefKind.Bass, p("F3"), p("D3"), p("C1"), p("C5"));
38577
+ var createStaff_Grand_Treble = () => new MusicStaff(ClefKind.Treble, p("G4"), p("B4"), p("C4"), p("C7"));
38578
+ var createStaff_Grand_Bass = () => new MusicStaff(ClefKind.Bass, p("F3"), p("D3"), p("C1"), p("C4") - 1);
38262
38579
  class ObjScoreRow extends MusicObject {
38263
38580
  constructor(doc) {
38264
38581
  super(doc);
38265
38582
  this.doc = doc;
38266
- this.pitchSpacing = 0;
38267
- this.lineSpacing = 0;
38268
38583
  this.minWidth = 0;
38269
- this.staffLines = [];
38584
+ this.staves = [];
38270
38585
  this.measures = [];
38271
- this.closestStaffLineCache = [];
38272
- this.cachedPitchY = [];
38273
38586
  this.needLayout = true;
38274
38587
  this.staffKind = doc.staffKind;
38275
38588
  switch (this.staffKind) {
38276
- case StaffKind.TrebleForGuitar:
38277
- this.staffLines[0] = StaffLine_TrebleForGuitar;
38278
- break;
38279
38589
  case StaffKind.Treble:
38280
- default:
38281
- this.staffLines[0] = StaffLine_Treble;
38590
+ this.staves[0] = createStaff_Treble();
38282
38591
  break;
38283
38592
  case StaffKind.Bass:
38284
- this.staffLines[0] = StaffLine_Bass;
38593
+ this.staves[0] = createStaff_Bass();
38285
38594
  break;
38286
38595
  case StaffKind.Grand:
38287
- this.staffLines[0] = StaffLine_Grand_Treble;
38288
- this.staffLines[1] = StaffLine_Grand_Bass;
38596
+ this.staves[0] = createStaff_Grand_Treble();
38597
+ this.staves[1] = createStaff_Grand_Bass();
38598
+ break;
38599
+ case StaffKind.GuitarTreble:
38600
+ this.staves[0] = createStaff_GuitarTreble();
38601
+ break;
38602
+ case StaffKind.GuitarTab:
38603
+ this.tab = new GuitarTab();
38604
+ break;
38605
+ case StaffKind.GuitarTrebleAndTab:
38606
+ this.staves[0] = createStaff_GuitarTreble();
38607
+ this.tab = new GuitarTab();
38289
38608
  break;
38609
+ default:
38610
+ Assert.assert("Invalid staffKind = " + this.staffKind);
38290
38611
  }
38291
38612
  // Set prevRow
38292
38613
  this.prevRow = doc.getLastRow();
@@ -38299,42 +38620,43 @@ class ObjScoreRow extends MusicObject {
38299
38620
  getMusicInterface() {
38300
38621
  return this.mi;
38301
38622
  }
38302
- get minPitch() {
38303
- return this.getBottomStaffLine().minPitch;
38623
+ get hasStaff() {
38624
+ return this.staves[0] !== undefined;
38625
+ }
38626
+ get hasTab() {
38627
+ return this.tab !== undefined;
38304
38628
  }
38305
- get maxPitch() {
38306
- return this.getTopStaffLine().maxPitch;
38629
+ getTab() {
38630
+ return this.tab;
38307
38631
  }
38308
- getStaffLines() {
38309
- return this.staffLines;
38632
+ getStaves() {
38633
+ return this.staves;
38310
38634
  }
38311
- getTopStaffLine() {
38312
- return this.staffLines[0];
38635
+ getTopStaff() {
38636
+ return Assert.require(this.staves[0], "Top staff line is required!");
38313
38637
  }
38314
- getBottomStaffLine() {
38315
- return this.staffLines[this.staffLines.length - 1];
38638
+ getBottomStaff() {
38639
+ return Assert.require(this.staves[this.staves.length - 1], "Bottom staff line is required!");
38316
38640
  }
38317
- getClosestStaffLine(pitch) {
38641
+ getStaff(pitch) {
38318
38642
  Note.validatePitch(pitch);
38319
- if (this.closestStaffLineCache[pitch] === undefined) {
38320
- var closestDistToPitch = Math.abs(pitch - this.staffLines[0].middleLinePitch);
38321
- var closestStaffLine = this.staffLines[0];
38322
- for (var i = 1; i < this.staffLines.length; i++) {
38323
- var dist = Math.abs(pitch - this.staffLines[i].middleLinePitch);
38324
- if (dist < closestDistToPitch) {
38325
- closestDistToPitch = dist;
38326
- closestStaffLine = this.staffLines[i];
38327
- }
38643
+ for (var i = 0; i < this.staves.length; i++) {
38644
+ var staff = this.staves[i];
38645
+ if (staff.containsPitch(pitch)) {
38646
+ return staff;
38328
38647
  }
38329
- this.closestStaffLineCache[pitch] = closestStaffLine;
38330
38648
  }
38331
- return this.closestStaffLineCache[pitch];
38332
- }
38333
- isPitchLine(pitch) {
38334
- return pitch % 2 === this.staffLines[0].middleLinePitch % 2;
38649
+ return undefined;
38335
38650
  }
38336
- isPitchSpace(pitch) {
38337
- return pitch % 2 !== this.staffLines[0].middleLinePitch % 2;
38651
+ getLowestNotePitch() {
38652
+ if (!this.hasStaff) {
38653
+ return undefined;
38654
+ } else if (this.doc.needFullPitchRange()) {
38655
+ return this.getBottomStaff().minPitch;
38656
+ } else {
38657
+ var pitch = this.getBottomStaff().bottomLinePitch;
38658
+ return Math.min(pitch, ...this.measures.map(m => m.getLowestNotePitch(pitch)));
38659
+ }
38338
38660
  }
38339
38661
  pick(x, y) {
38340
38662
  if (!this.rect.contains(x, y)) {
@@ -38354,35 +38676,10 @@ class ObjScoreRow extends MusicObject {
38354
38676
  var left = firstMeasure ? firstMeasure.getColumnsContentRect().left : r.left;
38355
38677
  return new DivRect(left, (left + r.right) / 2, r.right, r.top, r.centerY, r.bottom);
38356
38678
  }
38357
- getPitchSpacing() {
38358
- return this.pitchSpacing;
38359
- }
38360
- getLineSpacing() {
38361
- return this.lineSpacing;
38362
- }
38363
- getPitchY(pitch) {
38364
- Note.validatePitch(pitch);
38365
- if (this.cachedPitchY[pitch] === undefined) {
38366
- var staffLine = this.staffLines.length === 1 || pitch >= this.staffLines[0].minPitch ? this.staffLines[0] : this.staffLines[1];
38367
- var {
38368
- pitchSpacing,
38369
- lineSpacing
38370
- } = this;
38371
- var offsetY = staffLine.middleLineOffset * lineSpacing;
38372
- this.cachedPitchY[pitch] = offsetY - (pitch - staffLine.middleLinePitch) * pitchSpacing;
38373
- }
38374
- return this.cachedPitchY[pitch] + this.rect.centerY;
38375
- }
38376
38679
  getPitchAt(y) {
38377
- var {
38378
- pitchSpacing,
38379
- lineSpacing
38380
- } = this;
38381
- for (var i = 0; i < this.staffLines.length; i++) {
38382
- var staffLine = this.staffLines[i];
38383
- var offsetY = staffLine.middleLineOffset * lineSpacing;
38384
- var pitch = Math.round(staffLine.middleLinePitch - (y - this.rect.centerY - offsetY) / pitchSpacing);
38385
- if (pitch >= staffLine.minPitch && pitch <= staffLine.maxPitch) {
38680
+ for (var i = 0; i < this.staves.length; i++) {
38681
+ var pitch = this.staves[i].getPitchAt(y);
38682
+ if (pitch !== undefined) {
38386
38683
  return pitch;
38387
38684
  }
38388
38685
  }
@@ -38415,12 +38712,6 @@ class ObjScoreRow extends MusicObject {
38415
38712
  getMinWidth() {
38416
38713
  return this.minWidth;
38417
38714
  }
38418
- getTopStaffLineTop() {
38419
- return this.getPitchY(this.getTopStaffLine().topLinePitch);
38420
- }
38421
- getBottomStaffLineBottom() {
38422
- return this.getPitchY(this.getBottomStaffLine().bottomLinePitch);
38423
- }
38424
38715
  requestLayout() {
38425
38716
  if (!this.needLayout) {
38426
38717
  this.needLayout = true;
@@ -38428,6 +38719,7 @@ class ObjScoreRow extends MusicObject {
38428
38719
  }
38429
38720
  }
38430
38721
  layout(renderer) {
38722
+ var _a;
38431
38723
  if (!this.needLayout) {
38432
38724
  return;
38433
38725
  }
@@ -38435,32 +38727,45 @@ class ObjScoreRow extends MusicObject {
38435
38727
  unitSize
38436
38728
  } = renderer;
38437
38729
  this.rect = new DivRect();
38438
- if (this.pitchSpacing !== unitSize) {
38439
- this.pitchSpacing = unitSize;
38440
- this.lineSpacing = this.pitchSpacing * 2;
38441
- // pitch spacing changed, clear pitch y cache.
38442
- this.cachedPitchY.length = 0;
38730
+ var lineSpacing = unitSize * 2;
38731
+ // Compute staff top/bottom line y
38732
+ this.staves.forEach(staff => {
38733
+ staff.topLineY = -lineSpacing * 2;
38734
+ staff.bottomLineY = lineSpacing * 2;
38735
+ });
38736
+ if (this.staves.length === 2) {
38737
+ this.staves[0].topLineY -= lineSpacing * 4;
38738
+ this.staves[0].bottomLineY -= lineSpacing * 4;
38739
+ this.staves[1].topLineY += lineSpacing * 4;
38740
+ this.staves[1].bottomLineY += lineSpacing * 4;
38443
38741
  }
38444
- // Layout measures
38445
- this.measures.forEach(m => m.layout(renderer));
38446
38742
  // Compute toph and bottomh
38447
- var toph = 0,
38448
- bottomh = 0;
38449
- if (this.doc.needFullPitchRange()) {
38450
- toph = -this.getPitchY(this.maxPitch + 1);
38451
- bottomh = this.getPitchY(this.minPitch - 1);
38452
- } else {
38453
- toph = -this.getPitchY(this.getTopStaffLine().topLinePitch + 1);
38454
- bottomh = this.getPitchY(this.getBottomStaffLine().bottomLinePitch - 1);
38743
+ var rect = new DivRect();
38744
+ this.staves.forEach(staff => rect.expandInPlace(new DivRect(0, 0, staff.topLineY, staff.bottomLineY)));
38745
+ if (this.hasStaff && this.doc.needFullPitchRange()) {
38746
+ this.staves.forEach(staff => {
38747
+ var top = staff.getPitchY(staff.maxPitch) - staff.getLineSpacing();
38748
+ var bottom = staff.getPitchY(staff.minPitch) + staff.getLineSpacing();
38749
+ rect.expandInPlace(new DivRect(0, 0, top, bottom));
38750
+ });
38751
+ }
38752
+ if (this.tab) {
38753
+ var lowestPitch = this.getLowestNotePitch();
38754
+ var lowestY = lowestPitch !== undefined ? (_a = this.getStaff(lowestPitch)) === null || _a === void 0 ? void 0 : _a.getPitchY(lowestPitch) : undefined;
38755
+ this.tab.top = lowestY !== undefined ? lowestY + unitSize * 8 : 0;
38756
+ this.tab.bottom = this.tab.top + unitSize * DocumentSettings.GuitarTabHeight;
38757
+ rect.expandInPlace(new DivRect(0, 0, this.tab.top, this.tab.bottom));
38455
38758
  }
38759
+ // Calc min width
38456
38760
  this.minWidth = 0;
38761
+ // Layout measures
38457
38762
  this.measures.forEach(m => {
38458
- toph = Math.max(toph, m.getRect().toph);
38459
- bottomh = Math.max(bottomh, m.getRect().bottomh);
38763
+ m.layout(renderer);
38764
+ rect.expandInPlace(new DivRect(0, 0, m.getRect().top, m.getRect().bottom));
38460
38765
  this.minWidth += m.getMinWidth();
38461
38766
  this.minWidth += m.getPostMeasureBreakWidth();
38462
38767
  });
38463
- this.rect = new DivRect(0, 0, 0, -toph, 0, bottomh);
38768
+ this.rect = rect;
38464
38769
  }
38465
38770
  layoutWidth(renderer, width) {
38466
38771
  if (!this.needLayout) {
@@ -38572,6 +38877,10 @@ class ObjScoreRow extends MusicObject {
38572
38877
  offset(dx, dy) {
38573
38878
  this.measures.forEach(m => m.offset(dx, dy));
38574
38879
  this.rect.offsetInPlace(dx, dy);
38880
+ this.staves.forEach(s => s.offset(dx, dy));
38881
+ if (this.tab) {
38882
+ this.tab.offset(dx, dy);
38883
+ }
38575
38884
  }
38576
38885
  draw(renderer) {
38577
38886
  var ctx = renderer.getCanvasContext();
@@ -38584,10 +38893,18 @@ class ObjScoreRow extends MusicObject {
38584
38893
  ctx.rect(this.rect.left, this.rect.top, this.rect.width, this.rect.height);
38585
38894
  ctx.clip();
38586
38895
  // For multiple staff lines draw vertical start line (which is not drawn by measures)
38587
- if (this.getFirstMeasure() && this.staffLines.length > 1) {
38896
+ if (this.getFirstMeasure() && (this.staves.length > 1 || this.tab)) {
38588
38897
  var left = this.getFirstMeasure().getStaffLineLeft();
38589
- var top = this.getPitchY(this.getTopStaffLine().topLinePitch);
38590
- var bottom = this.getPitchY(this.getBottomStaffLine().bottomLinePitch);
38898
+ var top, bottom;
38899
+ if (this.hasStaff) {
38900
+ top = this.getTopStaff().topLineY;
38901
+ bottom = this.tab ? this.tab.getStringY(5) : this.getBottomStaff().bottomLineY;
38902
+ } else if (this.tab) {
38903
+ top = this.tab.getStringY(0);
38904
+ bottom = this.tab.getStringY(5);
38905
+ } else {
38906
+ top = bottom = 0;
38907
+ }
38591
38908
  renderer.drawLine(left, top, left, bottom);
38592
38909
  }
38593
38910
  // Draw measures
@@ -38601,6 +38918,7 @@ class ObjScoreRow extends MusicObject {
38601
38918
 
38602
38919
  class ObjHeader extends MusicObject {
38603
38920
  constructor(doc, title, composer, arranger) {
38921
+ var _a;
38604
38922
  super(doc);
38605
38923
  this.title = title;
38606
38924
  this.composer = composer;
@@ -38612,6 +38930,7 @@ class ObjHeader extends MusicObject {
38612
38930
  }, 0.5, 0) : undefined;
38613
38931
  this.composerText = this.composer ? new ObjText(this, this.composer, 1, 0) : undefined;
38614
38932
  this.arrangerText = this.arranger ? new ObjText(this, "Arr.: " + this.arranger, 1, 0) : undefined;
38933
+ this.tuningText = ((_a = doc.getFirstRow()) === null || _a === void 0 ? void 0 : _a.hasTab) === true ? new ObjText(this, doc.tuningName + " tuning:\n" + doc.tuningLabel, 0, 0) : undefined;
38615
38934
  }
38616
38935
  getMusicInterface() {
38617
38936
  return this.mi;
@@ -38638,15 +38957,23 @@ class ObjHeader extends MusicObject {
38638
38957
  return [this, ..._arr2];
38639
38958
  }
38640
38959
  }
38960
+ if (this.tuningText) {
38961
+ var _arr3 = this.tuningText.pick(x, y);
38962
+ if (_arr3) {
38963
+ return [this, ..._arr3];
38964
+ }
38965
+ }
38641
38966
  return [this];
38642
38967
  }
38643
38968
  layoutWidth(renderer, width) {
38644
38969
  var top = 0;
38970
+ var tuningTop = 0;
38645
38971
  this.rect = new DivRect(0, width, 0, 0);
38646
38972
  if (this.titleText) {
38647
38973
  this.titleText.layout(renderer);
38648
38974
  this.titleText.offset(width / 2, top);
38649
38975
  top += this.titleText.getRect().height;
38976
+ tuningTop = top;
38650
38977
  this.rect.expandInPlace(this.titleText.getRect());
38651
38978
  }
38652
38979
  if (this.composerText) {
@@ -38661,6 +38988,11 @@ class ObjHeader extends MusicObject {
38661
38988
  top += this.arrangerText.getRect().height;
38662
38989
  this.rect.expandInPlace(this.arrangerText.getRect());
38663
38990
  }
38991
+ if (this.tuningText) {
38992
+ this.tuningText.layout(renderer);
38993
+ this.tuningText.offset(0, tuningTop);
38994
+ this.rect.expandInPlace(this.tuningText.getRect());
38995
+ }
38664
38996
  }
38665
38997
  offset(dx, dy) {
38666
38998
  if (this.titleText) {
@@ -38672,6 +39004,9 @@ class ObjHeader extends MusicObject {
38672
39004
  if (this.arrangerText) {
38673
39005
  this.arrangerText.offset(dx, dy);
38674
39006
  }
39007
+ if (this.tuningText) {
39008
+ this.tuningText.offset(dx, dy);
39009
+ }
38675
39010
  this.rect.offsetInPlace(dx, dy);
38676
39011
  }
38677
39012
  draw(renderer) {
@@ -38684,6 +39019,9 @@ class ObjHeader extends MusicObject {
38684
39019
  if (this.arrangerText) {
38685
39020
  this.arrangerText.draw(renderer);
38686
39021
  }
39022
+ if (this.tuningText) {
39023
+ this.tuningText.draw(renderer);
39024
+ }
38687
39025
  }
38688
39026
  }
38689
39027
  ;// ./src/music-score/engine/obj-document.ts
@@ -38695,24 +39033,37 @@ class ObjHeader extends MusicObject {
38695
39033
 
38696
39034
 
38697
39035
 
39036
+
38698
39037
  class ObjDocument extends MusicObject {
38699
- constructor(mi, staffKind, measuresPerRow) {
39038
+ constructor(mi, staffKind, options) {
39039
+ var _a;
38700
39040
  super(undefined);
38701
39041
  this.mi = mi;
38702
39042
  this.staffKind = staffKind;
38703
- this.measuresPerRow = measuresPerRow;
39043
+ this.options = options;
38704
39044
  this.needLayout = true;
38705
39045
  this.needUpdate = true;
38706
39046
  this.rows = [];
38707
39047
  this.measures = [];
38708
39048
  this.layoutGroups = [];
38709
39049
  this.newRowRequested = false;
39050
+ this.allArcsProps = [];
39051
+ this.measuresPerRow = options === null || options === void 0 ? void 0 : options.measuresPerRow;
39052
+ if (this.measuresPerRow !== undefined) {
39053
+ Assert.int_gte(this.measuresPerRow, 1, "Invalid measuresPerRow = " + this.measuresPerRow);
39054
+ }
39055
+ this.tuningName = validateTuningName((_a = options === null || options === void 0 ? void 0 : options.tuning) !== null && _a !== void 0 ? _a : DefaultTuningName);
39056
+ this.tuningStrings = getTuningStrings(this.tuningName);
39057
+ this.tuningLabel = this.tuningStrings.slice().reverse().map(n => n.formatOmitOctave(SymbolSet.Ascii)).join("-");
38710
39058
  // There is always row
38711
39059
  this.rows.push(new ObjScoreRow(this));
38712
39060
  }
38713
39061
  getMusicInterface() {
38714
39062
  return this.mi;
38715
39063
  }
39064
+ addArcProps(arc) {
39065
+ this.allArcsProps.push(arc);
39066
+ }
38716
39067
  getLayoutGroup(lauoutGroupId) {
38717
39068
  var layoutGroup = this.layoutGroups[lauoutGroupId];
38718
39069
  if (!layoutGroup) {
@@ -38801,7 +39152,8 @@ class ObjDocument extends MusicObject {
38801
39152
  // Update extensions.
38802
39153
  this.forEachMeasure(m => m.updateExtensions());
38803
39154
  // Update arcs.
38804
- this.forEachMeasure(m => m.updateArcs());
39155
+ this.allArcsProps.forEach(arc => arc.removeArcs());
39156
+ this.allArcsProps.forEach(arc => arc.createArcs());
38805
39157
  this.needUpdate = false;
38806
39158
  }
38807
39159
  forEachMeasure(func) {
@@ -38899,6 +39251,11 @@ class ObjDocument extends MusicObject {
38899
39251
  }
38900
39252
  for (var ri = 0; ri < this.rows.length; ri++) {
38901
39253
  var row = this.rows[ri];
39254
+ if (!row.hasStaff) {
39255
+ continue;
39256
+ }
39257
+ var minPitch = row.getBottomStaff().minPitch;
39258
+ var maxPitch = row.getTopStaff().maxPitch;
38902
39259
  if (!row.getRect().contains(x, y)) {
38903
39260
  continue;
38904
39261
  }
@@ -38907,7 +39264,7 @@ class ObjDocument extends MusicObject {
38907
39264
  var rect = measure.getMusicObject().getRect();
38908
39265
  if (x >= rect.left && x <= rect.right) {
38909
39266
  var pitch = row.getPitchAt(y);
38910
- if (pitch !== undefined && pitch >= row.minPitch && pitch <= row.maxPitch) {
39267
+ if (pitch !== undefined && pitch >= minPitch && pitch <= maxPitch) {
38911
39268
  return {
38912
39269
  measure,
38913
39270
  pitch
@@ -39013,11 +39370,15 @@ class MBeamGroup extends MusicInterface {
39013
39370
  MBeamGroup.Name = "BeamGroup";
39014
39371
  /** @public */
39015
39372
  class MDocument extends MusicInterface {
39016
- constructor(staffKind, measuresPerRow) {
39373
+ constructor(staffKind, options) {
39017
39374
  super(MDocument.Name);
39018
- this.obj = new ObjDocument(this, staffKind, measuresPerRow);
39019
- if (measuresPerRow !== undefined) {
39020
- Assert.int_gte(measuresPerRow, 1, "Cannot create music document because invalid measures per row value: " + measuresPerRow);
39375
+ if (typeof options === "number") {
39376
+ // Deprecated: second argument was measuresPerRow.
39377
+ this.obj = new ObjDocument(this, staffKind, {
39378
+ measuresPerRow: options
39379
+ });
39380
+ } else {
39381
+ this.obj = new ObjDocument(this, staffKind, options);
39021
39382
  }
39022
39383
  }
39023
39384
  /** @internal */
@@ -40112,26 +40473,11 @@ class GuitarComponent extends external_react_namespaceObject.Component {
40112
40473
  }, components);
40113
40474
  }
40114
40475
  }
40115
- ;// ./src/react-components/assets/tuning.json
40116
- var tuning_namespaceObject = /*#__PURE__*/JSON.parse('{"p":[{"name":"Standard","strings":["E2","A2","D3","G3","B3","E4"]},{"name":"B Standard","strings":["B1","E2","A2","D3","F#3","B3"]},{"name":"C Standard","strings":["C2","F2","A#2","D#3","G3","C4"]},{"name":"D Modal","strings":["D2","A2","D3","G3","A3","D4"]},{"name":"D Standard","strings":["D2","G2","C3","F3","A3","D4"]},{"name":"D# Standard","strings":["D#2","G#2","C#3","F#3","A#3","D#4"]},{"name":"Double Drop D","strings":["D2","A2","D3","G3","B3","D4"]},{"name":"Drop B","strings":["B1","F#2","B2","E3","G#3","C#4"]},{"name":"Drop C","strings":["C2","G2","C3","F3","A3","D4"]},{"name":"Drop D","strings":["D2","A2","D3","G3","B3","E4"]},{"name":"Low C","strings":["C2","G2","D3","G3","A3","D4"]},{"name":"New Standard","strings":["C2","G2","D3","A3","E4","G4"]},{"name":"Open A","strings":["E2","A2","C#3","E3","A3","E4"]},{"name":"Open A Minor","strings":["E2","A2","E3","A3","C4","E4"]},{"name":"Open C","strings":["C2","G2","C3","G3","C4","E4"]},{"name":"Open C Minor","strings":["C2","G2","C3","G3","C4","D#4"]},{"name":"Open D","strings":["D2","A2","D3","F#3","A3","D4"]},{"name":"Open D Minor","strings":["D2","A2","D3","F3","A3","D4"]},{"name":"Open E","strings":["E2","B2","E3","G#3","B3","E4"]},{"name":"Open E Minor","strings":["E2","B2","E3","G3","B3","E4"]},{"name":"Open G","strings":["D2","G2","D3","G3","B3","D4"]},{"name":"Open G Minor","strings":["D2","G2","D3","G3","A#3","D4"]}]}');
40117
40476
  ;// ./src/react-components/guitar-context.ts
40118
40477
 
40119
40478
 
40120
40479
 
40121
40480
 
40122
-
40123
- /** @public */
40124
- var TuningNameList = tuning_namespaceObject.p.map(data => data.name);
40125
- /** @public */
40126
- var DefaultTuningName = TuningNameList[0];
40127
- /** @public */
40128
- function validateTuningName(tuningName) {
40129
- if (TuningNameList.indexOf(tuningName) >= 0) {
40130
- return tuningName;
40131
- } else {
40132
- return Assert.interrupt("Invalid tuning name: " + tuningName);
40133
- }
40134
- }
40135
40481
  /** @public */
40136
40482
  var DefaultHandedness = "rh";
40137
40483
  /** @public */
@@ -40209,11 +40555,10 @@ class GuitarContext {
40209
40555
  this.guitarNoteLabel = guitarNoteLabel;
40210
40556
  // Nut = fret0, FretCount = maxFret + 1
40211
40557
  this.maxFretId = guitar_namespaceObject.kl;
40212
- var tuningData = Assert.require(tuning_namespaceObject.p.find(data => data.name === tuningName), "Invalid tuning name: " + tuningName);
40213
- this.stringTunings = tuningData.strings.slice().reverse().map(noteName => Note.getNote(noteName));
40558
+ this.tuningStrings = getTuningStrings(tuningName);
40214
40559
  this.guitarNoteTable = [[], [], [], [], [], []];
40215
40560
  for (var stringId = 0; stringId < 6; stringId++) {
40216
- var openStringNoteId = this.stringTunings[stringId].noteId;
40561
+ var openStringNoteId = this.tuningStrings[stringId].noteId;
40217
40562
  for (var fretId = 0; fretId <= this.maxFretId; fretId++) {
40218
40563
  var noteId = openStringNoteId + fretId;
40219
40564
  this.guitarNoteTable[stringId][fretId] = new GuitarNote(this, stringId, fretId, noteId);
@@ -40226,10 +40571,10 @@ class GuitarContext {
40226
40571
  return this.guitarNoteTable[stringId][fretId];
40227
40572
  }
40228
40573
  getStringTuning(stringId) {
40229
- return this.stringTunings[stringId];
40574
+ return this.tuningStrings[stringId];
40230
40575
  }
40231
40576
  getTuningOverview() {
40232
- return this.stringTunings.slice().reverse().map(note => note.format(this.pitchNotation, SymbolSet.Unicode)).join(" - ");
40577
+ return this.tuningStrings.slice().reverse().map(note => note.format(this.pitchNotation, SymbolSet.Unicode)).join(" - ");
40233
40578
  }
40234
40579
  alterTuningName(tuningName) {
40235
40580
  return tuningName === this.tuningName ? this : new GuitarContext(tuningName, this.scale, this.handedness, this.pitchNotation, this.guitarNoteLabel);
@@ -40403,7 +40748,7 @@ class PlaybackButtons extends external_react_namespaceObject.Component {
40403
40748
 
40404
40749
  /** @public */
40405
40750
  function createFrereJacques() {
40406
- var doc = new MDocument(StaffKind.TrebleForGuitar);
40751
+ var doc = new MDocument(StaffKind.GuitarTreble);
40407
40752
  doc.setHeader("Frere Jacques");
40408
40753
  doc.addMeasure().setKeySignature("G", ScaleType.Major).setTimeSignature("4/4").addNote(0, "G3", NoteLength.Quarter).addNote(0, "A3", NoteLength.Quarter).addNote(0, "B3", NoteLength.Quarter).addNote(0, "G3", NoteLength.Quarter);
40409
40754
  doc.addMeasure().addNote(0, "G3", NoteLength.Quarter).addNote(0, "A3", NoteLength.Quarter).addNote(0, "B3", NoteLength.Quarter).addNote(0, "G3", NoteLength.Quarter);
@@ -40422,7 +40767,7 @@ function createFrereJacques() {
40422
40767
  // Greensleeves (https://musescore.com/aaron_dc/scores/6167495)
40423
40768
  /** @public */
40424
40769
  function createGreensleeves() {
40425
- var doc = new MDocument(StaffKind.TrebleForGuitar);
40770
+ var doc = new MDocument(StaffKind.GuitarTreble);
40426
40771
  doc.setHeader("Greensleeves");
40427
40772
  doc.addMeasure().setKeySignature("C", ScaleType.Major).setTimeSignature("6/8").setTempo(140).addNote(0, "A3", NoteLength.Eighth);
40428
40773
  doc.addMeasure().addNavigation(Navigation.StartRepeat).addNote(0, "C4", NoteLength.Quarter, {
@@ -40565,7 +40910,7 @@ function createGreensleeves() {
40565
40910
 
40566
40911
  /** @public */
40567
40912
  function createAndanteByDiabelli() {
40568
- var doc = new MDocument(StaffKind.TrebleForGuitar);
40913
+ var doc = new MDocument(StaffKind.GuitarTreble);
40569
40914
  doc.setHeader("Andante", "A. Diabelli");
40570
40915
  doc.addMeasure().setKeySignature("D", ScaleType.Major).setTimeSignature("3/4").setTempo(80).addRest(0, NoteLength.Eighth, {
40571
40916
  pitch: "G4"
@@ -40701,7 +41046,7 @@ function createAndanteByDiabelli() {
40701
41046
 
40702
41047
  /* harmony default export */ var index_full = (exports_full_namespaceObject);
40703
41048
  // Log lib loaded message.
40704
- console.log("%c" + "WebMusicScore v1.0.0 (cjs)", "background: black; color: white; padding: 2px 4px;");
41049
+ console.log("%c" + "WebMusicScore v1.1.0 (cjs)", "background: black; color: white; padding: 2px 4px;");
40705
41050
  }();
40706
41051
  module.exports = __webpack_exports__["default"];
40707
41052
  /******/ })()