@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.
@@ -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
  import * as __WEBPACK_EXTERNAL_MODULE_react__ from "react";
3
3
  /******/ var __webpack_modules__ = ({
4
4
 
@@ -621,6 +621,7 @@ __webpack_require__.d(exports_full_namespaceObject, {
621
621
  getScaleFactory: function() { return getScaleFactory; },
622
622
  getScaleFactoryList: function() { return getScaleFactoryList; },
623
623
  getTempoString: function() { return getTempoString; },
624
+ getTuningStrings: function() { return getTuningStrings; },
624
625
  validateGuitarNoteLabel: function() { return validateGuitarNoteLabel; },
625
626
  validateHandedness: function() { return validateHandedness; },
626
627
  validateIntervalQuality: function() { return validateIntervalQuality; },
@@ -32730,6 +32731,7 @@ var DocumentSettings = {
32730
32731
  NoteHeadWidth: 2,
32731
32732
  NoteHeadHeight: 1.3,
32732
32733
  DiamondNoteHeadSize: 1.8,
32734
+ DotSize: 0.8,
32733
32735
  StemHeight: 7,
32734
32736
  // One octave
32735
32737
  FlagWidth: 1.5,
@@ -32739,7 +32741,8 @@ var DocumentSettings = {
32739
32741
  BeamAngleFactor: 0.5,
32740
32742
  RestDotSpace: 0.5,
32741
32743
  LedgerLineWidth: 3.6,
32742
- ShortTieLength: 5
32744
+ ShortTieLength: 5,
32745
+ GuitarTabHeight: 20
32743
32746
  };
32744
32747
  ;// ./src/music-score/engine/renderer.ts
32745
32748
 
@@ -32984,8 +32987,12 @@ class Renderer {
32984
32987
  var {
32985
32988
  row
32986
32989
  } = measure.getMusicObject();
32990
+ var staff = row.getStaff(pitch);
32991
+ if (!staff) {
32992
+ return;
32993
+ }
32987
32994
  ctx.fillStyle = HilightPitchRectColor;
32988
- ctx.fillRect(0, row.getPitchY(pitch) - unitSize, ctx.canvas.width, 2 * unitSize);
32995
+ ctx.fillRect(0, staff.getPitchY(pitch) - unitSize, ctx.canvas.width, 2 * unitSize);
32989
32996
  if (mousePos !== undefined) {
32990
32997
  this.drawLedgerLines(row, pitch, mousePos.x);
32991
32998
  }
@@ -33089,26 +33096,33 @@ class Renderer {
33089
33096
  }
33090
33097
  }
33091
33098
  drawLedgerLines(row, pitch, x) {
33099
+ var staff = row.getStaff(pitch);
33100
+ if (!staff) {
33101
+ return;
33102
+ }
33092
33103
  var {
33093
33104
  unitSize
33094
33105
  } = this;
33095
- var staffLine = row.getClosestStaffLine(pitch);
33096
33106
  var ledgerLineWidth = unitSize * DocumentSettings.LedgerLineWidth;
33097
- if (pitch >= staffLine.topLinePitch + 2) {
33098
- for (var linePitch = staffLine.topLinePitch + 2; linePitch <= pitch; linePitch += 2) {
33099
- var y = row.getPitchY(linePitch);
33100
- this.drawLine(x - ledgerLineWidth / 2, y, x + ledgerLineWidth / 2, y);
33107
+ if (pitch >= staff.topLinePitch + 2) {
33108
+ for (var linePitch = staff.topLinePitch + 2; linePitch <= pitch; linePitch += 2) {
33109
+ if (staff.containsPitch(linePitch)) {
33110
+ var y = staff.getPitchY(linePitch);
33111
+ this.drawLine(x - ledgerLineWidth / 2, y, x + ledgerLineWidth / 2, y);
33112
+ }
33101
33113
  }
33102
- } else if (pitch <= staffLine.bottomLinePitch - 2) {
33103
- for (var _linePitch = staffLine.bottomLinePitch - 2; _linePitch >= pitch; _linePitch -= 2) {
33104
- var _y = row.getPitchY(_linePitch);
33105
- this.drawLine(x - ledgerLineWidth / 2, _y, x + ledgerLineWidth / 2, _y);
33114
+ } else if (pitch <= staff.bottomLinePitch - 2) {
33115
+ for (var _linePitch = staff.bottomLinePitch - 2; _linePitch >= pitch; _linePitch -= 2) {
33116
+ if (staff.containsPitch(_linePitch)) {
33117
+ var _y = staff.getPitchY(_linePitch);
33118
+ this.drawLine(x - ledgerLineWidth / 2, _y, x + ledgerLineWidth / 2, _y);
33119
+ }
33106
33120
  }
33107
33121
  }
33108
33122
  }
33109
33123
  }
33110
- Renderer.DotSize = 0.8;
33111
- ;// ./src/music-score/engine/staff-line.ts
33124
+ ;// ./src/music-score/engine/staff-and-tab.ts
33125
+
33112
33126
 
33113
33127
 
33114
33128
  var ClefKind;
@@ -33116,19 +33130,65 @@ var ClefKind;
33116
33130
  ClefKind[ClefKind["Treble"] = 0] = "Treble";
33117
33131
  ClefKind[ClefKind["Bass"] = 1] = "Bass";
33118
33132
  })(ClefKind || (ClefKind = {}));
33119
- class StaffLine {
33120
- constructor(clefKind, clefLinePitch, middleLinePitch, middleLineOffset, minPitch, maxPitch) {
33133
+ class MusicStaff {
33134
+ constructor(clefKind, clefLinePitch, middleLinePitch, minPitch, maxPitch) {
33121
33135
  this.clefKind = clefKind;
33122
33136
  this.clefLinePitch = clefLinePitch;
33123
33137
  this.middleLinePitch = middleLinePitch;
33124
- this.middleLineOffset = middleLineOffset;
33125
33138
  this.minPitch = minPitch;
33126
33139
  this.maxPitch = maxPitch;
33140
+ this.topLineY = 0;
33141
+ this.bottomLineY = 0;
33127
33142
  this.clefImageAsset = clefKind === ClefKind.Treble ? ImageAsset.TrebleClefPng : ImageAsset.BassClefPng;
33128
33143
  this.topLinePitch = this.middleLinePitch + 4;
33129
33144
  this.bottomLinePitch = this.middleLinePitch - 4;
33130
33145
  this.octaveLower = this.clefLinePitch === Note.getNote("G3").pitch; // Guitar is played octave lower
33131
33146
  }
33147
+ get middleLineY() {
33148
+ return (this.topLineY + this.bottomLineY) / 2;
33149
+ }
33150
+ offset(dx, dy) {
33151
+ this.topLineY += dy;
33152
+ this.bottomLineY += dy;
33153
+ }
33154
+ getLineSpacing() {
33155
+ return (this.bottomLineY - this.topLineY) / 4;
33156
+ }
33157
+ getPitchSpacing() {
33158
+ return this.getLineSpacing() / 2;
33159
+ }
33160
+ containsPitch(pitch) {
33161
+ Note.validatePitch(pitch);
33162
+ return pitch >= this.minPitch && pitch <= this.maxPitch;
33163
+ }
33164
+ getPitchY(pitch) {
33165
+ Assert.assert(this.containsPitch(pitch), "getPitchY: staff does not contain pitch " + pitch);
33166
+ return this.bottomLineY + (this.bottomLinePitch - pitch) * this.getPitchSpacing();
33167
+ }
33168
+ getPitchAt(y) {
33169
+ var pitch = Math.round(this.bottomLinePitch - (y - this.bottomLineY) / this.getPitchSpacing());
33170
+ return this.containsPitch(pitch) ? pitch : undefined;
33171
+ }
33172
+ isPitchLine(pitch) {
33173
+ return pitch % 2 === this.middleLinePitch % 2;
33174
+ }
33175
+ isPitchSpace(pitch) {
33176
+ return pitch % 2 !== this.middleLinePitch % 2;
33177
+ }
33178
+ }
33179
+ class GuitarTab {
33180
+ constructor() {
33181
+ this.top = 0;
33182
+ this.bottom = 0;
33183
+ }
33184
+ /** Return Y coordinate of string. */
33185
+ getStringY(stringId) {
33186
+ return this.top + (this.bottom - this.top) / 6 * (stringId + 0.5);
33187
+ }
33188
+ offset(dx, dy) {
33189
+ this.top += dy;
33190
+ this.bottom += dy;
33191
+ }
33132
33192
  }
33133
33193
  ;// ./src/music-score/engine/acc-state.ts
33134
33194
  class AccidentalState {
@@ -33589,6 +33649,46 @@ function alterTempoSpeed(tempo, speed) {
33589
33649
  }
33590
33650
  };
33591
33651
  }
33652
+ ;// ./src/music-theory/assets/tunings.json
33653
+ 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"]}]}');
33654
+ ;// ./src/music-theory/tuning.ts
33655
+
33656
+
33657
+
33658
+ /*
33659
+ * | string | stringId | freq | fretboard (RH) | on tab |
33660
+ * |--------|----------|---------|----------------|---------------|
33661
+ * | 1 | 0 | highest | bottom string | top string |
33662
+ * | 6 | 5 | lowest | top string | bottom string |
33663
+ * |--------|----------|---------|----------------|---------------|
33664
+ */
33665
+ /** @public */
33666
+ var TuningNameList = tunings_namespaceObject.p.map(data => data.name);
33667
+ /** @public */
33668
+ var DefaultTuningName = TuningNameList[0];
33669
+ /** @public */
33670
+ function validateTuningName(tuningName) {
33671
+ if (TuningNameList.indexOf(tuningName) >= 0) {
33672
+ return tuningName;
33673
+ } else {
33674
+ return Assert.interrupt("Invalid tuning name: " + tuningName);
33675
+ }
33676
+ }
33677
+ var TuningStringsCache = new LRUCache(100);
33678
+ /**
33679
+ * @public
33680
+ * @returns Array of open string notes, note for each string.
33681
+ */
33682
+ function getTuningStrings(tuningName) {
33683
+ var tuningStrings = TuningStringsCache.get(tuningName);
33684
+ if (!tuningStrings) {
33685
+ var tuningData = Assert.require(tunings_namespaceObject.p.find(data => data.name === tuningName), "Invalid tuning name: " + tuningName);
33686
+ tuningStrings = tuningData.strings.slice().reverse().map(noteName => Note.getNote(noteName));
33687
+ Assert.int_eq(tuningStrings.length, 6, "Tuning should have 6 strings but has " + tuningStrings.length + " strings.");
33688
+ TuningStringsCache.set(tuningName, tuningStrings);
33689
+ }
33690
+ return tuningStrings;
33691
+ }
33592
33692
  ;// ./src/music-theory/index.ts
33593
33693
 
33594
33694
 
@@ -33599,6 +33699,7 @@ function alterTempoSpeed(tempo, speed) {
33599
33699
 
33600
33700
 
33601
33701
 
33702
+
33602
33703
  ;// ./src/music-score/engine/obj-image.ts
33603
33704
 
33604
33705
 
@@ -33804,6 +33905,7 @@ class ObjText extends MusicObject {
33804
33905
  this.italic = (_d = textProps.italic) !== null && _d !== void 0 ? _d : false;
33805
33906
  this.boxed = (_e = textProps.boxed) !== null && _e !== void 0 ? _e : false;
33806
33907
  this.padding = (_f = textProps.padding) !== null && _f !== void 0 ? _f : this.boxed ? DefaultBoxedPadding : 0;
33908
+ this.bgcolor = textProps.bgcolor;
33807
33909
  if (!isFinite(this.padding) || this.padding < 0) {
33808
33910
  this.padding = 0;
33809
33911
  }
@@ -33882,6 +33984,14 @@ class ObjText extends MusicObject {
33882
33984
  anchorY,
33883
33985
  italic
33884
33986
  } = this;
33987
+ if (this.bgcolor !== undefined) {
33988
+ ctx.save();
33989
+ ctx.fillStyle = this.bgcolor;
33990
+ ctx.beginPath();
33991
+ ctx.fillRect(rect.left, rect.top, rect.width, rect.height);
33992
+ ctx.fill();
33993
+ ctx.restore();
33994
+ }
33885
33995
  var lineCount = this.textLines.length;
33886
33996
  var textHeight = lineCount * lineHeight;
33887
33997
  var fixY = -lineHeight * (italic ? 0.25 : 0.175);
@@ -33921,10 +34031,10 @@ class ObjText extends MusicObject {
33921
34031
 
33922
34032
 
33923
34033
  class ObjSignature extends MusicObject {
33924
- constructor(measure, staffLine) {
34034
+ constructor(measure, staff) {
33925
34035
  super(measure);
33926
34036
  this.measure = measure;
33927
- this.staffLine = staffLine;
34037
+ this.staff = staff;
33928
34038
  this.ksNeutralizeAccidentals = [];
33929
34039
  this.ksNewAccidentals = [];
33930
34040
  this.mi = new MSignature(this);
@@ -33940,9 +34050,9 @@ class ObjSignature extends MusicObject {
33940
34050
  }
33941
34051
  updateClefImage(renderer, showClef) {
33942
34052
  if (showClef) {
33943
- var img = renderer.getImageAsset(this.staffLine.clefImageAsset);
34053
+ var img = renderer.getImageAsset(this.staff.clefImageAsset);
33944
34054
  this.clefImage = img ? new ObjImage(this, img, 0, 0.5, 0.1) : undefined;
33945
- this.eightBelowClef = this.clefImage && this.staffLine.octaveLower ? new ObjText(this, "8", 0.5, 0) : undefined;
34055
+ this.eightBelowClef = this.clefImage && this.staff.octaveLower ? new ObjText(this, "8", 0.5, 0) : undefined;
33946
34056
  } else {
33947
34057
  this.clefImage = undefined;
33948
34058
  }
@@ -34007,19 +34117,19 @@ class ObjSignature extends MusicObject {
34007
34117
  }
34008
34118
  }
34009
34119
  getAccidentalPitch(accNote) {
34010
- var clefKind = this.staffLine.clefKind;
34120
+ var clefKind = this.staff.clefKind;
34011
34121
  var lowestAccidentalPitch = undefined;
34012
34122
  if (clefKind === ClefKind.Treble) {
34013
34123
  if (accNote.accidental > 0) {
34014
- lowestAccidentalPitch = this.staffLine.bottomLinePitch + 3;
34124
+ lowestAccidentalPitch = this.staff.bottomLinePitch + 3;
34015
34125
  } else if (accNote.accidental < 0) {
34016
- lowestAccidentalPitch = this.staffLine.bottomLinePitch + 1;
34126
+ lowestAccidentalPitch = this.staff.bottomLinePitch + 1;
34017
34127
  }
34018
34128
  } else if (clefKind === ClefKind.Bass) {
34019
34129
  if (accNote.accidental > 0) {
34020
- lowestAccidentalPitch = this.staffLine.bottomLinePitch + 1;
34130
+ lowestAccidentalPitch = this.staff.bottomLinePitch + 1;
34021
34131
  } else if (accNote.accidental < 0) {
34022
- lowestAccidentalPitch = this.staffLine.bottomLinePitch - 1;
34132
+ lowestAccidentalPitch = this.staff.bottomLinePitch - 1;
34023
34133
  }
34024
34134
  }
34025
34135
  if (lowestAccidentalPitch !== undefined) {
@@ -34084,7 +34194,8 @@ class ObjSignature extends MusicObject {
34084
34194
  unitSize
34085
34195
  } = renderer;
34086
34196
  var {
34087
- measure
34197
+ measure,
34198
+ staff
34088
34199
  } = this;
34089
34200
  var {
34090
34201
  row
@@ -34095,7 +34206,7 @@ class ObjSignature extends MusicObject {
34095
34206
  if (this.clefImage) {
34096
34207
  x += paddingX;
34097
34208
  this.clefImage.layout(renderer);
34098
- this.clefImage.offset(x, row.getPitchY(this.staffLine.clefLinePitch));
34209
+ this.clefImage.offset(x, staff.getPitchY(staff.clefLinePitch));
34099
34210
  this.rect.expandInPlace(this.clefImage.getRect());
34100
34211
  x = this.rect.right;
34101
34212
  if (this.eightBelowClef) {
@@ -34107,7 +34218,7 @@ class ObjSignature extends MusicObject {
34107
34218
  }
34108
34219
  if (this.measureNumber) {
34109
34220
  this.measureNumber.layout(renderer);
34110
- var y = this.clefImage ? this.clefImage.getRect().top : row.getPitchY(this.staffLine.topLinePitch);
34221
+ var y = this.clefImage ? this.clefImage.getRect().top : staff.topLineY;
34111
34222
  this.measureNumber.offset(0, y);
34112
34223
  this.rect.expandInPlace(this.measureNumber.getRect());
34113
34224
  x = Math.max(x, this.rect.right);
@@ -34115,38 +34226,44 @@ class ObjSignature extends MusicObject {
34115
34226
  if (this.ksNeutralizeAccidentals.length > 0) {
34116
34227
  x += paddingX;
34117
34228
  this.ksNeutralizeAccidentals.forEach(acc => {
34118
- acc.obj.layout(renderer);
34119
- acc.obj.offset(x + acc.obj.getRect().leftw, row.getPitchY(acc.pitch));
34120
- this.rect.expandInPlace(acc.obj.getRect());
34121
- x = this.rect.right;
34229
+ var accStaff = row.getStaff(acc.pitch);
34230
+ if (accStaff) {
34231
+ acc.obj.layout(renderer);
34232
+ acc.obj.offset(x + acc.obj.getRect().leftw, accStaff.getPitchY(acc.pitch));
34233
+ this.rect.expandInPlace(acc.obj.getRect());
34234
+ x = this.rect.right;
34235
+ }
34122
34236
  });
34123
34237
  }
34124
34238
  if (this.ksNewAccidentals) {
34125
34239
  x += paddingX;
34126
34240
  this.ksNewAccidentals.forEach(acc => {
34127
- acc.obj.layout(renderer);
34128
- acc.obj.offset(x + acc.obj.getRect().leftw, row.getPitchY(acc.pitch));
34129
- this.rect.expandInPlace(acc.obj.getRect());
34130
- x = this.rect.right;
34241
+ var accStaff = row.getStaff(acc.pitch);
34242
+ if (accStaff) {
34243
+ acc.obj.layout(renderer);
34244
+ acc.obj.offset(x + acc.obj.getRect().leftw, accStaff.getPitchY(acc.pitch));
34245
+ this.rect.expandInPlace(acc.obj.getRect());
34246
+ x = this.rect.right;
34247
+ }
34131
34248
  });
34132
34249
  }
34133
34250
  var right = x;
34134
34251
  if (this.beatCountText) {
34135
34252
  this.beatCountText.layout(renderer);
34136
- this.beatCountText.offset(x + paddingX, row.getPitchY(this.staffLine.middleLinePitch + 2));
34253
+ this.beatCountText.offset(x + paddingX, staff.getPitchY(staff.middleLinePitch + 2));
34137
34254
  this.rect.expandInPlace(this.beatCountText.getRect());
34138
34255
  right = Math.max(right, this.rect.right);
34139
34256
  }
34140
34257
  if (this.beatSizeText) {
34141
34258
  this.beatSizeText.layout(renderer);
34142
- this.beatSizeText.offset(x + paddingX, row.getPitchY(this.staffLine.bottomLinePitch + 2));
34259
+ this.beatSizeText.offset(x + paddingX, staff.getPitchY(staff.bottomLinePitch + 2));
34143
34260
  this.rect.expandInPlace(this.beatSizeText.getRect());
34144
34261
  right = Math.max(right, this.rect.right);
34145
34262
  }
34146
34263
  x = right;
34147
34264
  if (this.tempoText) {
34148
34265
  this.tempoText.layout(renderer);
34149
- this.tempoText.offset(x, Math.min(this.rect.top, row.getPitchY(this.staffLine.topLinePitch)));
34266
+ this.tempoText.offset(x, Math.min(this.rect.top, staff.topLineY));
34150
34267
  this.rect.expandInPlace(this.tempoText.getRect());
34151
34268
  }
34152
34269
  this.rect.expandInPlace(new DivRect(this.rect.left, this.rect.right + paddingX, this.rect.centerY, this.rect.centerY));
@@ -34284,13 +34401,19 @@ ObjArpeggio.NumCycles = 5;
34284
34401
  var StaffKind;
34285
34402
  (function (StaffKind) {
34286
34403
  /** Treble staff has treble (G-) clef. */
34287
- StaffKind[StaffKind["Treble"] = 0] = "Treble";
34288
- /** TrebleForGuitar has treble clef but is one octave lower. */
34289
- StaffKind[StaffKind["TrebleForGuitar"] = 1] = "TrebleForGuitar";
34404
+ StaffKind[StaffKind["Treble"] = 1] = "Treble";
34290
34405
  /** Bass staff has bass (F-) clef. */
34291
34406
  StaffKind[StaffKind["Bass"] = 2] = "Bass";
34292
34407
  /** Grand staff has both treble and bass clefs. */
34293
34408
  StaffKind[StaffKind["Grand"] = 3] = "Grand";
34409
+ /** GuitarTreble has treble clef but is one octave lower. */
34410
+ StaffKind[StaffKind["GuitarTreble"] = 4] = "GuitarTreble";
34411
+ // /** GuitarTab has tab for guitar. */
34412
+ StaffKind[StaffKind["GuitarTab"] = 8] = "GuitarTab";
34413
+ // /** GuitarTrebleAndTab has treble clef and tab for guitar. */
34414
+ StaffKind[StaffKind["GuitarTrebleAndTab"] = 12] = "GuitarTrebleAndTab";
34415
+ /** @deprecated TrebleForGuitar was replaced by GuitarTreble. */
34416
+ StaffKind[StaffKind["TrebleForGuitar"] = 4] = "TrebleForGuitar";
34294
34417
  })(StaffKind || (StaffKind = {}));
34295
34418
  /** @public */
34296
34419
  var Stem;
@@ -34382,19 +34505,23 @@ var Label;
34382
34505
 
34383
34506
 
34384
34507
 
34385
-
34508
+ class RestStaffObjects {
34509
+ constructor() {
34510
+ this.dotRect = new DivRect();
34511
+ }
34512
+ }
34386
34513
  class ObjRest extends MusicObject {
34387
34514
  constructor(col, voiceId, noteLength, options) {
34388
34515
  var _a, _b;
34389
34516
  super(col);
34390
34517
  this.col = col;
34391
34518
  this.voiceId = voiceId;
34392
- this.dotRect = new DivRect();
34393
34519
  this.ownAvgPitch = this.measure.updateOwnAvgPitch(voiceId, options === null || options === void 0 ? void 0 : options.pitch);
34394
34520
  this.ownStemDir = this.measure.updateOwnStemDir(this /*, options?.stem*/);
34395
34521
  this.color = (_a = options === null || options === void 0 ? void 0 : options.color) !== null && _a !== void 0 ? _a : "black";
34396
34522
  this.hide = (_b = options === null || options === void 0 ? void 0 : options.hide) !== null && _b !== void 0 ? _b : false;
34397
34523
  this.rhythmProps = new RhythmProps(noteLength, options === null || options === void 0 ? void 0 : options.dotted, options === null || options === void 0 ? void 0 : options.triplet);
34524
+ this.staffObjs = this.row.hasStaff ? new RestStaffObjects() : undefined;
34398
34525
  this.mi = new MRest(this);
34399
34526
  }
34400
34527
  getMusicInterface() {
@@ -34416,7 +34543,11 @@ class ObjRest extends MusicObject {
34416
34543
  return this.rhythmProps.dotted;
34417
34544
  }
34418
34545
  get stemDir() {
34419
- return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
34546
+ if (this.staffObjs) {
34547
+ return this.staffObjs.beamGroup ? this.staffObjs.beamGroup.stemDir : this.ownStemDir;
34548
+ } else {
34549
+ return Stem.Up;
34550
+ }
34420
34551
  }
34421
34552
  get triplet() {
34422
34553
  return this.rhythmProps.triplet;
@@ -34425,13 +34556,18 @@ class ObjRest extends MusicObject {
34425
34556
  return this.rect.contains(x, y) ? [this] : [];
34426
34557
  }
34427
34558
  getBeamGroup() {
34428
- return this.beamGroup;
34559
+ var _a;
34560
+ return (_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.beamGroup;
34429
34561
  }
34430
34562
  setBeamGroup(beam) {
34431
- this.beamGroup = beam;
34563
+ if (this.staffObjs) {
34564
+ this.staffObjs.beamGroup = beam;
34565
+ }
34432
34566
  }
34433
34567
  resetBeamGroup() {
34434
- this.beamGroup = undefined;
34568
+ if (this.staffObjs) {
34569
+ this.staffObjs.beamGroup = undefined;
34570
+ }
34435
34571
  }
34436
34572
  getBeamX() {
34437
34573
  return this.rect.centerX;
@@ -34461,8 +34597,9 @@ class ObjRest extends MusicObject {
34461
34597
  }
34462
34598
  updateAccidentalState(accState) {}
34463
34599
  layout(renderer, accState) {
34464
- if (this.hide) {
34600
+ if (this.hide || !this.staffObjs) {
34465
34601
  this.rect = new DivRect();
34602
+ return;
34466
34603
  }
34467
34604
  var {
34468
34605
  unitSize
@@ -34502,30 +34639,32 @@ class ObjRest extends MusicObject {
34502
34639
  bottomh = unitSize * (1 + flagCount + adj);
34503
34640
  }
34504
34641
  if (dotted) {
34505
- var dotWidth = Renderer.DotSize * unitSize;
34506
- var dotX = rightw + (DocumentSettings.RestDotSpace + Renderer.DotSize / 2) * unitSize;
34642
+ var dotWidth = DocumentSettings.DotSize * unitSize;
34643
+ var dotX = rightw + (DocumentSettings.RestDotSpace + DocumentSettings.DotSize / 2) * unitSize;
34507
34644
  var dotY = this.getRestDotVerticalDisplacement(noteLength) * unitSize;
34508
- this.dotRect = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
34509
- toph = Math.max(toph, this.dotRect.toph);
34510
- bottomh = Math.max(bottomh, this.dotRect.bottomh);
34511
- rightw += (DocumentSettings.RestDotSpace + Renderer.DotSize) * unitSize;
34645
+ this.staffObjs.dotRect = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
34646
+ toph = Math.max(toph, this.staffObjs.dotRect.toph);
34647
+ bottomh = Math.max(bottomh, this.staffObjs.dotRect.bottomh);
34648
+ rightw += (DocumentSettings.RestDotSpace + DocumentSettings.DotSize) * unitSize;
34512
34649
  }
34513
34650
  this.rect = new DivRect(-leftw, 0, rightw, -toph, 0, bottomh);
34514
34651
  var restPitch = ownAvgPitch;
34515
34652
  // Make sure restPitch is line, not space
34516
- if (this.row.isPitchSpace(restPitch)) {
34517
- var staffLine = this.row.getClosestStaffLine(restPitch);
34518
- restPitch += restPitch >= staffLine.middleLinePitch ? 1 : -1;
34653
+ var staff = this.row.getStaff(restPitch);
34654
+ if (staff && staff.isPitchSpace(restPitch)) {
34655
+ restPitch += restPitch >= staff.middleLinePitch ? 1 : -1;
34656
+ this.offset(0, staff.getPitchY(restPitch));
34519
34657
  }
34520
- this.offset(0, this.row.getPitchY(restPitch));
34521
34658
  }
34522
34659
  offset(dx, dy) {
34523
- this.dotRect.offsetInPlace(dx, dy);
34660
+ if (this.staffObjs) {
34661
+ this.staffObjs.dotRect.offsetInPlace(dx, dy);
34662
+ }
34524
34663
  this.rect.offsetInPlace(dx, dy);
34525
34664
  }
34526
34665
  draw(renderer) {
34527
34666
  var ctx = renderer.getCanvasContext();
34528
- if (!ctx || this.hide) {
34667
+ if (!ctx || this.hide || !this.staffObjs) {
34529
34668
  return;
34530
34669
  }
34531
34670
  renderer.drawDebugRect(this.rect);
@@ -34584,7 +34723,7 @@ class ObjRest extends MusicObject {
34584
34723
  }
34585
34724
  }
34586
34725
  if (dotted) {
34587
- var r = this.dotRect;
34726
+ var r = this.staffObjs.dotRect;
34588
34727
  renderer.fillCircle(r.centerX, r.centerY, r.width / 2);
34589
34728
  }
34590
34729
  }
@@ -34598,8 +34737,9 @@ class ObjRest extends MusicObject {
34598
34737
 
34599
34738
 
34600
34739
  class ObjArc extends MusicObject {
34601
- constructor(arcData, measure, leftNoteGroup, leftNote) {
34740
+ constructor(arcProps, measure, leftNoteGroup, leftNote) {
34602
34741
  super(measure);
34742
+ this.arcProps = arcProps;
34603
34743
  this.lx = 0;
34604
34744
  this.ly = 0;
34605
34745
  this.rx = 0;
@@ -34610,7 +34750,6 @@ class ObjArc extends MusicObject {
34610
34750
  this.cp2y = 0;
34611
34751
  this.arcHeight = 0;
34612
34752
  this.measure = measure;
34613
- this.arcData = arcData;
34614
34753
  this.leftNoteGroup = leftNoteGroup;
34615
34754
  this.leftNote = leftNote;
34616
34755
  if ((arguments.length <= 4 ? undefined : arguments[4]) instanceof ObjNoteGroup && (arguments.length <= 5 ? undefined : arguments[5]) instanceof Note) {
@@ -34623,19 +34762,16 @@ class ObjArc extends MusicObject {
34623
34762
  this.tieLength = arguments.length <= 4 ? undefined : arguments[4];
34624
34763
  }
34625
34764
  this.mi = new MArc(this);
34626
- this.measure.addArc(this);
34765
+ this.measure.addArcObject(this);
34627
34766
  }
34628
34767
  getMusicInterface() {
34629
34768
  return this.mi;
34630
34769
  }
34631
- getArcData() {
34632
- return this.arcData;
34633
- }
34634
34770
  isTie() {
34635
- return this.arcData.arcType === "tie";
34771
+ return this.arcProps.arcType === "tie";
34636
34772
  }
34637
34773
  isSlur() {
34638
- return this.arcData.arcType === "slur";
34774
+ return this.arcProps.arcType === "slur";
34639
34775
  }
34640
34776
  isInsideMeasure() {
34641
34777
  return this.rightNoteGroup === undefined || this.leftNoteGroup.measure === this.rightNoteGroup.measure;
@@ -34663,17 +34799,15 @@ class ObjArc extends MusicObject {
34663
34799
  var {
34664
34800
  arcPos,
34665
34801
  arcDir
34666
- } = this.arcData;
34667
- var leftPos = leftNoteGroup.getArcAnchorPoint(renderer, leftNoteGroup, leftNote, arcPos, "left");
34668
- leftPos = Assert.require(leftPos, "Left arc anchor point is required!");
34669
- var rightPos = rightNoteGroup !== undefined && rightNote !== undefined ? rightNoteGroup.getArcAnchorPoint(renderer, rightNoteGroup, rightNote, arcPos, "right") : this.tieLength === TieLength.ToMeasureEnd ? {
34802
+ } = this.arcProps;
34803
+ var leftPos = leftNoteGroup.getArcAnchorPoint(leftNote, arcPos, "left");
34804
+ var rightPos = rightNoteGroup !== undefined && rightNote !== undefined ? rightNoteGroup.getArcAnchorPoint(rightNote, arcPos, "right") : this.tieLength === TieLength.ToMeasureEnd ? {
34670
34805
  x: measure.getColumnsContentRect().right,
34671
34806
  y: leftPos.y
34672
34807
  } : {
34673
34808
  x: leftPos.x + unitSize * DocumentSettings.ShortTieLength,
34674
34809
  y: leftPos.y
34675
34810
  };
34676
- rightPos = Assert.require(rightPos, "Right arc anchor point is required!");
34677
34811
  var lx, ly, rx, ry;
34678
34812
  if (rightNoteGroup === undefined) {
34679
34813
  // TieLength.Short | TieLength.ToMeasureEnd
@@ -34762,25 +34896,30 @@ class ObjArc extends MusicObject {
34762
34896
  ctx.fill();
34763
34897
  }
34764
34898
  }
34765
- ;// ./src/music-score/engine/arc-data.ts
34899
+ ;// ./src/music-score/engine/arc-props.ts
34766
34900
 
34767
34901
 
34768
34902
 
34769
- class CollectedArcData {
34903
+ class ArcProps {
34770
34904
  constructor(arcType, arcSpan, arcPos, startNoteGroup) {
34771
34905
  this.arcType = arcType;
34772
34906
  this.arcSpan = arcSpan;
34773
34907
  this.arcPos = arcPos;
34774
- this.noteGroups = [];
34775
34908
  this.arcDir = "down";
34776
- this.noteGroups.push(startNoteGroup);
34909
+ this.noteGroups = [startNoteGroup];
34910
+ }
34911
+ getStartNoteGroup() {
34912
+ return this.noteGroups[0];
34913
+ }
34914
+ startsWith(noteGroup) {
34915
+ return this.noteGroups[0] === noteGroup;
34777
34916
  }
34778
34917
  /**
34779
34918
  *
34780
34919
  * @param noteGroup -
34781
34920
  * @returns true if noteGroup was added, false if not.
34782
34921
  */
34783
- add(noteGroup) {
34922
+ addNoteGroup(noteGroup) {
34784
34923
  if (this.arcSpan === TieLength.Short || this.arcSpan === TieLength.ToMeasureEnd) {
34785
34924
  // Contains already 1 NoteGroup
34786
34925
  return false;
@@ -34791,9 +34930,6 @@ class CollectedArcData {
34791
34930
  return false;
34792
34931
  }
34793
34932
  }
34794
- startsWith(noteGroup) {
34795
- return this.noteGroups[0] === noteGroup;
34796
- }
34797
34933
  computeParams() {
34798
34934
  var stemDir = this.noteGroups[0].stemDir;
34799
34935
  if (this.arcPos === ArcPos.StemTip) {
@@ -34812,16 +34948,24 @@ class CollectedArcData {
34812
34948
  row
34813
34949
  } = this.noteGroups[0].measure;
34814
34950
  var notePitch = this.noteGroups[0].ownAvgPitch;
34815
- var staffLine = row.getClosestStaffLine(notePitch);
34816
- this.arcDir = notePitch < staffLine.middleLinePitch ? "down" : "up";
34951
+ var staff = row.getStaff(notePitch);
34952
+ this.arcDir = !staff || notePitch < staff.middleLinePitch ? "down" : "up";
34817
34953
  } else if (this.arcPos === ArcPos.Above) {
34818
34954
  this.arcDir = "up";
34819
34955
  } else if (this.arcPos === ArcPos.Below) {
34820
34956
  this.arcDir = "down";
34821
34957
  }
34822
34958
  }
34823
- createObjArcs() {
34959
+ removeArcs() {
34960
+ this.noteGroups.forEach(n => {
34961
+ n.measure.removeArcObjects();
34962
+ n.removeArcProps();
34963
+ });
34964
+ this.noteGroups.length = 1;
34965
+ }
34966
+ createArcs() {
34824
34967
  var _this = this;
34968
+ this.getStartNoteGroup().collectArcProps();
34825
34969
  this.computeParams();
34826
34970
  var {
34827
34971
  arcSpan,
@@ -34837,10 +34981,10 @@ class CollectedArcData {
34837
34981
  var _loop = function _loop() {
34838
34982
  var leftNoteGroup = _this.noteGroups[i];
34839
34983
  var rightNoteGroup = _this.noteGroups[i + 1];
34840
- leftNoteGroup.notes.forEach(note => {
34841
- // Create arc from left to right only if note is found in all note-groups so far.
34842
- if (_this.noteGroups.every(noteGroup => noteGroup.notes.some(n => n.equals(note)))) {
34843
- _this.createObjArc(leftNoteGroup, note, rightNoteGroup, note);
34984
+ leftNoteGroup.notes.forEach(leftNote => {
34985
+ var rightNote = rightNoteGroup.notes.find(rightNote => rightNote.equals(leftNote));
34986
+ if (rightNote) {
34987
+ _this.createObjArc(leftNoteGroup, leftNote, rightNoteGroup, leftNote);
34844
34988
  }
34845
34989
  });
34846
34990
  };
@@ -35127,6 +35271,36 @@ class ObjBeamGroup extends MusicObject {
35127
35271
 
35128
35272
 
35129
35273
 
35274
+ function sortNoteStringData(notes, strings) {
35275
+ var stringArr = Utils.Arr.isArray(strings) ? strings : strings !== undefined ? [strings] : [];
35276
+ var noteStringData = notes.map((note, i) => {
35277
+ return {
35278
+ note,
35279
+ string: stringArr[i]
35280
+ };
35281
+ });
35282
+ noteStringData = Utils.Arr.removeDuplicatesCmp(noteStringData, (a, b) => a.note.equals(b.note)).sort((a, b) => Note.compareFunc(a.note, b.note));
35283
+ return {
35284
+ notes: noteStringData.map(e => e.note),
35285
+ strings: noteStringData.every(e => e.string === undefined) ? undefined : noteStringData.map(e => e.string)
35286
+ };
35287
+ }
35288
+ function solveArpeggio(a) {
35289
+ return a === true || a === Arpeggio.Up ? Arpeggio.Up : a === Arpeggio.Down ? Arpeggio.Down : undefined;
35290
+ }
35291
+ class NoteStaffObjects {
35292
+ constructor() {
35293
+ this.noteHeadRects = [];
35294
+ this.dotRects = [];
35295
+ this.accidentals = [];
35296
+ this.flagRects = [];
35297
+ }
35298
+ }
35299
+ class NoteTabObjects {
35300
+ constructor() {
35301
+ this.fretNumbers = [];
35302
+ }
35303
+ }
35130
35304
  class ObjNoteGroup extends MusicObject {
35131
35305
  constructor(col, voiceId, notes, noteLength, options) {
35132
35306
  var _a, _b, _c, _d, _e;
@@ -35134,28 +35308,37 @@ class ObjNoteGroup extends MusicObject {
35134
35308
  this.col = col;
35135
35309
  this.voiceId = voiceId;
35136
35310
  this.notes = notes;
35137
- this.tieDatas = [];
35138
- this.slurDatas = [];
35139
- this.noteHeadRects = [];
35140
- this.dotRects = [];
35141
- this.accidentals = [];
35142
- this.flagRects = [];
35311
+ this.tieProps = [];
35312
+ this.slurProps = [];
35143
35313
  this.leftBeamCount = 0;
35144
35314
  this.rightBeamCount = 0;
35145
35315
  Assert.int_gte(notes.length, 1, "Cannot create note group object because notes array is empty.");
35146
- this.notes = Note.sort(Note.removeDuplicates(notes));
35316
+ var noteStringData = sortNoteStringData(notes, options === null || options === void 0 ? void 0 : options.string);
35317
+ this.notes = noteStringData.notes;
35147
35318
  this.minPitch = this.notes[0].pitch;
35148
35319
  this.maxPitch = this.notes[this.notes.length - 1].pitch;
35149
35320
  this.ownAvgPitch = this.measure.updateOwnAvgPitch(voiceId, Math.round((this.minPitch + this.maxPitch) / 2));
35150
35321
  this.ownStemDir = this.measure.updateOwnStemDir(this, options === null || options === void 0 ? void 0 : options.stem);
35322
+ this.ownString = this.measure.updateOwnString(this, noteStringData.strings);
35151
35323
  this.color = (_a = options === null || options === void 0 ? void 0 : options.color) !== null && _a !== void 0 ? _a : "black";
35152
35324
  this.staccato = (_b = options === null || options === void 0 ? void 0 : options.staccato) !== null && _b !== void 0 ? _b : false;
35153
35325
  this.diamond = (_c = options === null || options === void 0 ? void 0 : options.diamond) !== null && _c !== void 0 ? _c : false;
35154
- this.arpeggio = options === null || options === void 0 ? void 0 : options.arpeggio;
35155
- this.tieSpan = options === null || options === void 0 ? void 0 : options.tieSpan;
35156
- this.slurSpan = options === null || options === void 0 ? void 0 : options.slurSpan;
35157
- 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;
35326
+ this.arpeggio = solveArpeggio(options === null || options === void 0 ? void 0 : options.arpeggio);
35158
35327
  this.rhythmProps = new RhythmProps(noteLength, options === null || options === void 0 ? void 0 : options.dotted, options === null || options === void 0 ? void 0 : options.triplet);
35328
+ if ((options === null || options === void 0 ? void 0 : options.tieSpan) !== undefined) {
35329
+ this.startTie = new ArcProps("tie", options.tieSpan, (_d = options.tiePos) !== null && _d !== void 0 ? _d : ArcPos.Auto, this);
35330
+ this.doc.addArcProps(this.startTie);
35331
+ }
35332
+ if ((options === null || options === void 0 ? void 0 : options.slurSpan) !== undefined) {
35333
+ this.startSlur = new ArcProps("slur", options.slurSpan, (_e = options.slurPos) !== null && _e !== void 0 ? _e : ArcPos.Auto, this);
35334
+ this.doc.addArcProps(this.startSlur);
35335
+ }
35336
+ if (!this.row.hasStaff) {
35337
+ Assert.assert(this.startTie === undefined, "Ties not implemented for guitar tabs alone, staff is required!");
35338
+ Assert.assert(this.startSlur === undefined, "Slurs not implemented for guitar tabs alone, staff is required!");
35339
+ }
35340
+ this.staffObjs = this.row.hasStaff ? new NoteStaffObjects() : undefined;
35341
+ this.tabObjs = this.row.hasTab ? new NoteTabObjects() : undefined;
35159
35342
  this.mi = new MNoteGroup(this);
35160
35343
  }
35161
35344
  getMusicInterface() {
@@ -35171,7 +35354,11 @@ class ObjNoteGroup extends MusicObject {
35171
35354
  return this.col.row;
35172
35355
  }
35173
35356
  get stemDir() {
35174
- return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
35357
+ if (this.staffObjs) {
35358
+ return this.staffObjs.beamGroup ? this.staffObjs.beamGroup.stemDir : this.ownStemDir;
35359
+ } else {
35360
+ return Stem.Up;
35361
+ }
35175
35362
  }
35176
35363
  get triplet() {
35177
35364
  return this.rhythmProps.triplet;
@@ -35180,12 +35367,25 @@ class ObjNoteGroup extends MusicObject {
35180
35367
  if (!this.rect.contains(x, y)) {
35181
35368
  return [];
35182
35369
  }
35183
- for (var i = 0; i < this.accidentals.length; i++) {
35184
- var acc = this.accidentals[i];
35185
- if (acc) {
35186
- var arr = acc.pick(x, y);
35187
- if (arr.length > 0) {
35188
- return [this, ...arr];
35370
+ if (this.staffObjs) {
35371
+ for (var i = 0; i < this.staffObjs.accidentals.length; i++) {
35372
+ var acc = this.staffObjs.accidentals[i];
35373
+ if (acc) {
35374
+ var arr = acc.pick(x, y);
35375
+ if (arr.length > 0) {
35376
+ return [this, ...arr];
35377
+ }
35378
+ }
35379
+ }
35380
+ }
35381
+ if (this.tabObjs) {
35382
+ for (var _i = 0; _i < this.tabObjs.fretNumbers.length; _i++) {
35383
+ var fn = this.tabObjs.fretNumbers[_i];
35384
+ if (fn) {
35385
+ var _arr = fn.pick(x, y);
35386
+ if (_arr.length > 0) {
35387
+ return [this, ..._arr];
35388
+ }
35189
35389
  }
35190
35390
  }
35191
35391
  }
@@ -35197,120 +35397,124 @@ class ObjNoteGroup extends MusicObject {
35197
35397
  getBottomNote() {
35198
35398
  return this.notes[0];
35199
35399
  }
35200
- getArcAnchorPoint(renderer, noteGroup, note, arcPos, side) {
35201
- if (arcPos === ArcPos.Auto) {
35202
- arcPos = ArcPos.Below;
35203
- }
35204
- var hasStem = !!this.stemRect;
35205
- var stemSide = !hasStem ? undefined : this.stemDir === Stem.Up ? "right" : "left";
35206
- var stemDir = this.stemDir;
35400
+ getArcAnchorPoint(note, arcPos, side) {
35207
35401
  var noteId = this.notes.findIndex(note2 => note2.equals(note));
35208
- if (noteId < 0) {
35209
- return undefined;
35210
- }
35211
- var r = this.noteHeadRects[noteId];
35212
- if (!r) {
35213
- return undefined;
35214
- }
35215
- var {
35216
- unitSize
35217
- } = renderer;
35218
- if (arcPos === ArcPos.StemTip && !hasStem) {
35219
- arcPos = this.stemDir === Stem.Up ? ArcPos.Above : ArcPos.Below;
35220
- }
35221
- var centerX = r.centerX;
35222
- var centerY = r.centerY;
35223
- var leftX = centerX - unitSize * 1.5;
35224
- var rightX = centerX + unitSize * 1.5;
35225
- var aboveY = centerY - unitSize * 1.5;
35226
- var belowY = centerY + unitSize * 1.5;
35227
- if (arcPos === ArcPos.Middle) {
35228
- return side === "left" ? {
35229
- x: rightX,
35230
- y: centerY
35231
- } : {
35232
- x: leftX,
35233
- y: centerY
35402
+ if (!this.staffObjs || noteId < 0 || noteId >= this.staffObjs.noteHeadRects.length) {
35403
+ var r = this.getRect();
35404
+ return {
35405
+ x: r.centerX,
35406
+ y: r.bottom
35234
35407
  };
35235
- } else if (arcPos === ArcPos.Above) {
35236
- if (!hasStem || stemDir === Stem.Down) {
35237
- return {
35238
- x: centerX,
35239
- y: aboveY
35240
- };
35241
- } else {
35242
- return {
35243
- x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35244
- y: aboveY
35245
- };
35246
- }
35247
- } else if (arcPos === ArcPos.Below) {
35248
- if (!hasStem || stemDir === Stem.Up) {
35249
- return {
35250
- x: centerX,
35251
- y: belowY
35252
- };
35253
- } else {
35254
- return {
35255
- x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35256
- y: belowY
35257
- };
35258
- }
35259
- } else if (arcPos === ArcPos.StemTip) {
35260
- var stemRect = Assert.require(this.stemRect, "Cannot get stem tip arc anchort point because this note group has no stem.");
35261
- if (noteGroup.stemDir === Stem.Up) {
35262
- return {
35263
- x: centerX,
35264
- y: stemRect.top - unitSize
35265
- };
35266
- } else if (noteGroup.stemDir === Stem.Down) {
35267
- return {
35268
- x: centerX,
35269
- y: stemRect.bottom + unitSize
35408
+ }
35409
+ var noteHeadRect = this.staffObjs.noteHeadRects[noteId];
35410
+ var stemRect = this.staffObjs.stemRect;
35411
+ var stemDir = this.stemDir;
35412
+ var hasStem = stemRect !== undefined;
35413
+ var stemSide = !hasStem ? undefined : stemDir === Stem.Up ? "right" : "left";
35414
+ var padding = noteHeadRect.height / 2;
35415
+ var centerX = noteHeadRect.centerX;
35416
+ var centerY = noteHeadRect.centerY;
35417
+ var leftX = noteHeadRect.left - padding;
35418
+ var rightX = noteHeadRect.right + padding;
35419
+ var aboveY = noteHeadRect.top - padding;
35420
+ var belowY = noteHeadRect.bottom + padding;
35421
+ if (arcPos === ArcPos.Auto) {
35422
+ arcPos = ArcPos.Below;
35423
+ } else if (arcPos === ArcPos.StemTip && !hasStem) {
35424
+ arcPos = stemDir === Stem.Up ? ArcPos.Above : ArcPos.Below;
35425
+ }
35426
+ switch (arcPos) {
35427
+ case ArcPos.Middle:
35428
+ return side === "left" ? {
35429
+ x: rightX,
35430
+ y: centerY
35431
+ } : {
35432
+ x: leftX,
35433
+ y: centerY
35270
35434
  };
35271
- }
35435
+ case ArcPos.Above:
35436
+ if (!hasStem || stemDir === Stem.Down) {
35437
+ return {
35438
+ x: centerX,
35439
+ y: aboveY
35440
+ };
35441
+ } else {
35442
+ return {
35443
+ x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35444
+ y: aboveY
35445
+ };
35446
+ }
35447
+ case ArcPos.Below:
35448
+ if (!hasStem || stemDir === Stem.Up) {
35449
+ return {
35450
+ x: centerX,
35451
+ y: belowY
35452
+ };
35453
+ } else {
35454
+ return {
35455
+ x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
35456
+ y: belowY
35457
+ };
35458
+ }
35459
+ case ArcPos.StemTip:
35460
+ // stemRect is defined.
35461
+ if (stemDir === Stem.Up) {
35462
+ return {
35463
+ x: centerX,
35464
+ y: stemRect.top - padding
35465
+ };
35466
+ } else if (stemDir === Stem.Down) {
35467
+ return {
35468
+ x: centerX,
35469
+ y: stemRect.bottom + padding
35470
+ };
35471
+ }
35472
+ default:
35473
+ Assert.interrupt("Invalid arcPos: " + arcPos);
35272
35474
  }
35273
- return undefined;
35274
35475
  }
35275
- getPrevNoteGroup() {
35476
+ getNextNoteGroup() {
35276
35477
  var voiceNoteGroups = this.measure.getVoiceSymbols(this.voiceId).filter(s => s instanceof ObjNoteGroup);
35277
35478
  var i = voiceNoteGroups.indexOf(this);
35278
- if (i > 0) {
35279
- return voiceNoteGroups[i - 1];
35479
+ if (i < 0) {
35480
+ return undefined;
35481
+ } else if (i < voiceNoteGroups.length - 1) {
35482
+ return voiceNoteGroups[i + 1];
35280
35483
  }
35281
- var m = this.measure.getPrevMeasure();
35484
+ var m = this.measure.getNextMeasure();
35282
35485
  while (m) {
35283
35486
  var _voiceNoteGroups = m.getVoiceSymbols(this.voiceId).filter(s => s instanceof ObjNoteGroup);
35284
35487
  if (_voiceNoteGroups.length > 0) {
35285
- return _voiceNoteGroups[_voiceNoteGroups.length - 1];
35488
+ return _voiceNoteGroups[0];
35286
35489
  }
35287
- m = m.getPrevMeasure();
35490
+ m = m.getNextMeasure();
35288
35491
  }
35289
35492
  return undefined;
35290
35493
  }
35291
- collectArcDatas() {
35292
- if (this.tieSpan !== undefined) {
35293
- this.tieDatas.push(new CollectedArcData("tie", this.tieSpan, this.arcPos, this));
35294
- }
35295
- if (this.slurSpan !== undefined) {
35296
- this.slurDatas.push(new CollectedArcData("slur", this.slurSpan, this.arcPos, this));
35494
+ collectArcProps() {
35495
+ if (this.startTie) {
35496
+ this.tieProps.push(this.startTie);
35497
+ var next = this.getNextNoteGroup();
35498
+ while (next && this.startTie.addNoteGroup(next)) {
35499
+ next.tieProps.push(this.startTie);
35500
+ next = next.getNextNoteGroup();
35501
+ }
35297
35502
  }
35298
- var prevNoteGroup = this.getPrevNoteGroup();
35299
- if (prevNoteGroup) {
35300
- prevNoteGroup.tieDatas.forEach(tieData => {
35301
- if (tieData.add(this)) {
35302
- this.tieDatas.push(tieData);
35303
- }
35304
- });
35305
- prevNoteGroup.slurDatas.forEach(slurData => {
35306
- if (slurData.add(this)) {
35307
- this.slurDatas.push(slurData);
35308
- }
35309
- });
35503
+ if (this.startSlur) {
35504
+ this.slurProps.push(this.startSlur);
35505
+ var _next = this.getNextNoteGroup();
35506
+ while (_next && this.startSlur.addNoteGroup(_next)) {
35507
+ _next.slurProps.push(this.startSlur);
35508
+ _next = _next.getNextNoteGroup();
35509
+ }
35310
35510
  }
35311
35511
  }
35512
+ removeArcProps() {
35513
+ this.tieProps = [];
35514
+ this.slurProps = [];
35515
+ }
35312
35516
  getPlaySlur() {
35313
- var slurs = this.slurDatas.map(slurData => slurData.startsWith(this) ? "first" : "slurred");
35517
+ var slurs = this.slurProps.map(slur => slur.startsWith(this) ? "first" : "slurred");
35314
35518
  if (slurs.indexOf("first") >= 0) {
35315
35519
  return "first";
35316
35520
  } else if (slurs.indexOf("slurred") >= 0) {
@@ -35319,26 +35523,29 @@ class ObjNoteGroup extends MusicObject {
35319
35523
  return undefined;
35320
35524
  }
35321
35525
  }
35322
- createObjArcs() {
35323
- this.tieDatas.forEach(tieData => tieData.createObjArcs());
35324
- this.slurDatas.forEach(slurData => slurData.createObjArcs());
35325
- }
35326
35526
  getBeamGroup() {
35327
- return this.beamGroup;
35527
+ var _a;
35528
+ return (_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.beamGroup;
35328
35529
  }
35329
35530
  setBeamGroup(beam) {
35330
- this.beamGroup = beam;
35531
+ if (this.staffObjs) {
35532
+ this.staffObjs.beamGroup = beam;
35533
+ }
35331
35534
  }
35332
35535
  resetBeamGroup() {
35333
- this.leftBeamCount = this.rightBeamCount = 0;
35334
- this.beamGroup = undefined;
35536
+ if (this.staffObjs) {
35537
+ this.leftBeamCount = this.rightBeamCount = 0;
35538
+ this.staffObjs.beamGroup = undefined;
35539
+ }
35335
35540
  }
35336
35541
  getBeamX() {
35337
- var stemRect = Assert.require(this.stemRect, "Cannot get beam x-coordinate because this note group has no stem.");
35542
+ var _a;
35543
+ 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.");
35338
35544
  return stemRect.centerX;
35339
35545
  }
35340
35546
  getBeamY() {
35341
- var stemRect = Assert.require(this.stemRect, "Cannot get beam y-coordinate because this note group has no stem.");
35547
+ var _a;
35548
+ 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.");
35342
35549
  return this.stemDir === Stem.Up ? stemRect.top : stemRect.bottom;
35343
35550
  }
35344
35551
  getStemHeight(renderer) {
@@ -35366,13 +35573,13 @@ class ObjNoteGroup extends MusicObject {
35366
35573
  return this.rightBeamCount;
35367
35574
  }
35368
35575
  getPlayTicks(note) {
35369
- var tiedTicks = this.tieDatas.map(tieData => {
35370
- var tieNoteGroups = tieData.noteGroups;
35576
+ var tiedTicks = this.tieProps.map(tie => {
35577
+ var tieNoteGroups = tie.noteGroups;
35371
35578
  var j = tieNoteGroups.indexOf(this);
35372
35579
  if (j < 0) {
35373
35580
  return 0;
35374
35581
  }
35375
- if (tieData.arcSpan === TieLength.Short || tieData.arcSpan === TieLength.ToMeasureEnd) {
35582
+ if (tie.arcSpan === TieLength.Short || tie.arcSpan === TieLength.ToMeasureEnd) {
35376
35583
  return Math.max(this.rhythmProps.ticks, this.measure.getMeasureTicks() - this.col.positionTicks);
35377
35584
  }
35378
35585
  var prev = tieNoteGroups[j - 1];
@@ -35396,6 +35603,7 @@ class ObjNoteGroup extends MusicObject {
35396
35603
  });
35397
35604
  }
35398
35605
  layout(renderer, accState) {
35606
+ var _a, _b;
35399
35607
  var {
35400
35608
  unitSize
35401
35609
  } = renderer;
@@ -35405,102 +35613,157 @@ class ObjNoteGroup extends MusicObject {
35405
35613
  } = this;
35406
35614
  var {
35407
35615
  dotted,
35408
- flagCount,
35409
- noteLength
35616
+ flagCount
35410
35617
  } = this.rhythmProps;
35411
- this.noteHeadRects = [];
35412
- this.dotRects = [];
35413
- this.accidentals = [];
35414
- this.stemRect = undefined;
35415
- var dotWidth = Renderer.DotSize * unitSize;
35618
+ if (this.staffObjs) {
35619
+ this.staffObjs.noteHeadRects = [];
35620
+ this.staffObjs.dotRects = [];
35621
+ this.staffObjs.accidentals = [];
35622
+ this.staffObjs.stemRect = undefined;
35623
+ }
35624
+ if (this.tabObjs) {
35625
+ this.tabObjs.fretNumbers = [];
35626
+ }
35627
+ var dotWidth = DocumentSettings.DotSize * unitSize;
35416
35628
  var noteHeadWidth = (this.diamond ? DocumentSettings.DiamondNoteHeadSize : DocumentSettings.NoteHeadWidth) * unitSize;
35417
35629
  var noteHeadHeight = (this.diamond ? DocumentSettings.DiamondNoteHeadSize : DocumentSettings.NoteHeadHeight) * unitSize;
35418
35630
  this.notes.forEach((note, noteId) => {
35419
- var noteX = this.col.getNoteHeadDisplacement(this, note) * noteHeadWidth;
35420
- var noteY = this.row.getPitchY(note.pitch);
35421
- // Setup note head
35422
- var noteHeadRect = this.noteHeadRects[noteId] = DivRect.createCentered(noteX, noteY, noteHeadWidth, noteHeadHeight);
35423
- if (accState.needAccidental(note)) {
35424
- var acc = this.accidentals[noteId] = new ObjAccidental(this, note.accidental, this.color);
35425
- if (acc) {
35426
- acc.layout(renderer);
35427
- acc.offset(-noteHeadRect.leftw - unitSize * DocumentSettings.NoteAccSpace - acc.getRect().rightw, noteY);
35631
+ var staff = row.getStaff(note.pitch);
35632
+ if (this.staffObjs && staff) {
35633
+ var noteX = this.col.getNoteHeadDisplacement(this, note) * noteHeadWidth;
35634
+ var noteY = staff.getPitchY(note.pitch);
35635
+ // Setup note head
35636
+ var noteHeadRect = this.staffObjs.noteHeadRects[noteId] = DivRect.createCentered(noteX, noteY, noteHeadWidth, noteHeadHeight);
35637
+ // Setup accidental
35638
+ if (accState.needAccidental(note)) {
35639
+ var acc = this.staffObjs.accidentals[noteId] = new ObjAccidental(this, note.accidental, this.color);
35640
+ if (acc) {
35641
+ acc.layout(renderer);
35642
+ acc.offset(-noteHeadRect.leftw - unitSize * DocumentSettings.NoteAccSpace - acc.getRect().rightw, noteY);
35643
+ }
35644
+ }
35645
+ // Setup dot
35646
+ if (dotted) {
35647
+ var dotX = noteHeadRect.right + DocumentSettings.NoteDotSpace * unitSize + dotWidth / 2;
35648
+ var dotY = noteY + this.getDotVerticalDisplacement(note.pitch, stemDir) * unitSize;
35649
+ this.staffObjs.dotRects[noteId] = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
35428
35650
  }
35429
- }
35430
- // Set dot
35431
- if (dotted) {
35432
- var dotX = noteHeadRect.right + DocumentSettings.NoteDotSpace * unitSize + dotWidth / 2;
35433
- var dotY = noteY + this.getDotVerticalDisplacement(note.pitch, stemDir) * unitSize;
35434
- this.dotRects[noteId] = DivRect.createCentered(dotX, dotY, dotWidth, dotWidth);
35435
35651
  }
35436
35652
  });
35437
35653
  // Add staccato dot
35438
- if (this.staccato) {
35439
- var dotX = this.noteHeadRects[0].centerX;
35440
- var dotY = 0;
35654
+ if (this.staccato && this.staffObjs) {
35655
+ var dotX = this.staffObjs.noteHeadRects[0].centerX;
35441
35656
  if (stemDir === Stem.Up) {
35442
- var pitch = this.notes[0].pitch;
35443
- dotY = this.row.getPitchY(pitch) + unitSize * (row.isPitchLine(pitch) ? 3 : 2);
35657
+ var pitch = this.getBottomNote().pitch;
35658
+ var staff = row.getStaff(pitch);
35659
+ if (staff) {
35660
+ var dotY = staff.getPitchY(pitch) + unitSize * (staff.isPitchLine(pitch) ? 3 : 2);
35661
+ this.staffObjs.dotRects.push(DivRect.createCentered(dotX, dotY, dotWidth, dotWidth));
35662
+ }
35444
35663
  } else {
35445
- var _pitch = this.notes[this.notes.length - 1].pitch;
35446
- dotY = this.row.getPitchY(_pitch) - unitSize * (row.isPitchLine(_pitch) ? 3 : 2);
35447
- }
35448
- this.dotRects.push(DivRect.createCentered(dotX, dotY, dotWidth, dotWidth));
35449
- }
35450
- // Calculate stem
35451
- var bottomNoteY = this.row.getPitchY(this.getBottomNote().pitch);
35452
- var topNoteY = this.row.getPitchY(this.getTopNote().pitch);
35453
- var stemX = stemDir === Stem.Up ? noteHeadWidth / 2 : -noteHeadWidth / 2;
35454
- var stemHeight = this.getStemHeight(renderer);
35455
- var stemTipY = stemDir === Stem.Up ? topNoteY - stemHeight : bottomNoteY + stemHeight;
35456
- var stemBaseY = stemDir === Stem.Up ? bottomNoteY : topNoteY;
35457
- if (this.rhythmProps.hasStem()) {
35458
- this.stemRect = new DivRect(stemX, stemX, Math.min(stemBaseY, stemTipY), Math.max(stemBaseY, stemTipY));
35459
- }
35460
- // Setup flag rects
35461
- this.flagRects = [];
35462
- if (!this.hasBeamCount()) {
35463
- var flagWidth = flagCount === 0 ? 0 : DocumentSettings.FlagWidth * unitSize;
35464
- var flagHeight = flagCount === 0 ? 0 : DocumentSettings.FlagHeight * unitSize;
35465
- for (var i = 0; i < flagCount; i++) {
35466
- var flagAddY = i * unitSize * DocumentSettings.FlagSeparation;
35467
- 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);
35664
+ var _pitch = this.getTopNote().pitch;
35665
+ var _staff = row.getStaff(_pitch);
35666
+ if (_staff) {
35667
+ var _dotY = _staff.getPitchY(_pitch) - unitSize * (_staff.isPitchLine(_pitch) ? 3 : 2);
35668
+ this.staffObjs.dotRects.push(DivRect.createCentered(dotX, _dotY, dotWidth, dotWidth));
35669
+ }
35468
35670
  }
35469
35671
  }
35672
+ if (this.staffObjs) {
35673
+ // Calculate stem
35674
+ var bottomNoteY = (_a = row.getStaff(this.getBottomNote().pitch)) === null || _a === void 0 ? void 0 : _a.getPitchY(this.getBottomNote().pitch);
35675
+ var topNoteY = (_b = row.getStaff(this.getTopNote().pitch)) === null || _b === void 0 ? void 0 : _b.getPitchY(this.getTopNote().pitch);
35676
+ if (bottomNoteY === undefined || topNoteY === undefined) {
35677
+ Assert.interrupt("Top or bottom note is undefined!");
35678
+ }
35679
+ var stemX = stemDir === Stem.Up ? noteHeadWidth / 2 : -noteHeadWidth / 2;
35680
+ var stemHeight = this.getStemHeight(renderer);
35681
+ var stemTipY = stemDir === Stem.Up ? topNoteY - stemHeight : bottomNoteY + stemHeight;
35682
+ var stemBaseY = stemDir === Stem.Up ? bottomNoteY : topNoteY;
35683
+ if (this.rhythmProps.hasStem()) {
35684
+ this.staffObjs.stemRect = new DivRect(stemX, stemX, Math.min(stemBaseY, stemTipY), Math.max(stemBaseY, stemTipY));
35685
+ }
35686
+ // Setup flag rects
35687
+ this.staffObjs.flagRects = [];
35688
+ if (!this.hasBeamCount()) {
35689
+ var flagWidth = flagCount === 0 ? 0 : DocumentSettings.FlagWidth * unitSize;
35690
+ var flagHeight = flagCount === 0 ? 0 : DocumentSettings.FlagHeight * unitSize;
35691
+ for (var i = 0; i < flagCount; i++) {
35692
+ var flagAddY = i * unitSize * DocumentSettings.FlagSeparation;
35693
+ 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);
35694
+ }
35695
+ }
35696
+ }
35697
+ var tab = row.getTab();
35698
+ this.notes.forEach((note, noteId) => {
35699
+ var _a;
35700
+ // Add tab fret numbers
35701
+ if (tab && this.tabObjs && this.ownString[noteId] !== undefined) {
35702
+ var stringId = this.ownString[noteId] - 1;
35703
+ var fretId = note.noteId - this.doc.tuningStrings[stringId].noteId;
35704
+ var color = fretId < 0 ? "red" : "black";
35705
+ var fretNumber = new ObjText(this, {
35706
+ text: String(fretId),
35707
+ color,
35708
+ bgcolor: "white"
35709
+ }, 0.5, 0.5);
35710
+ this.tabObjs.fretNumbers.push(fretNumber);
35711
+ fretNumber.layout(renderer);
35712
+ var noteX = this.col.getNoteHeadDisplacement(this, note) * noteHeadWidth;
35713
+ var _stemX = ((_a = this.staffObjs) === null || _a === void 0 ? void 0 : _a.stemRect) ? this.staffObjs.stemRect.centerX : undefined;
35714
+ var x = _stemX !== null && _stemX !== void 0 ? _stemX : noteX;
35715
+ var y = tab.getStringY(stringId);
35716
+ fretNumber.offset(x, y);
35717
+ }
35718
+ });
35470
35719
  this.updateRect();
35471
35720
  }
35472
35721
  updateRect() {
35473
- this.rect = this.noteHeadRects[0].copy();
35474
- this.noteHeadRects.forEach(r => this.rect.expandInPlace(r));
35475
- if (this.stemRect) {
35476
- this.rect.expandInPlace(this.stemRect);
35722
+ if (this.staffObjs) {
35723
+ this.rect = this.staffObjs.noteHeadRects[0].copy();
35724
+ this.staffObjs.noteHeadRects.forEach(r => this.rect.expandInPlace(r));
35725
+ if (this.staffObjs.stemRect) {
35726
+ this.rect.expandInPlace(this.staffObjs.stemRect);
35727
+ }
35728
+ this.staffObjs.dotRects.forEach(r => this.rect.expandInPlace(r));
35729
+ this.staffObjs.flagRects.forEach(r => this.rect.expandInPlace(r));
35730
+ this.staffObjs.accidentals.forEach(a => this.rect.expandInPlace(a.getRect()));
35731
+ } else if (this.tabObjs && this.tabObjs.fretNumbers.length > 0) {
35732
+ this.rect = this.tabObjs.fretNumbers[0].getRect().copy();
35733
+ } else {
35734
+ this.rect = new DivRect();
35735
+ }
35736
+ if (this.tabObjs) {
35737
+ this.tabObjs.fretNumbers.forEach(fn => this.rect.expandInPlace(fn.getRect()));
35477
35738
  }
35478
- this.dotRects.forEach(r => this.rect.expandInPlace(r));
35479
- this.flagRects.forEach(r => this.rect.expandInPlace(r));
35480
- this.accidentals.forEach(acc => this.rect.expandInPlace(acc.getRect()));
35481
35739
  }
35482
35740
  setStemTipY(stemTipY) {
35483
- if (!this.stemRect) {
35741
+ if (!this.staffObjs || !this.staffObjs.stemRect) {
35484
35742
  return;
35485
35743
  }
35486
- var oldStemTipY = this.stemDir === Stem.Up ? this.stemRect.top : this.stemRect.bottom;
35744
+ var oldStemTipY = this.stemDir === Stem.Up ? this.staffObjs.stemRect.top : this.staffObjs.stemRect.bottom;
35487
35745
  if (stemTipY === oldStemTipY) {
35488
35746
  return;
35489
35747
  }
35490
- var r = this.stemRect;
35748
+ var r = this.staffObjs.stemRect;
35491
35749
  var top = this.stemDir === Stem.Up ? stemTipY : r.top;
35492
35750
  var bottom = this.stemDir === Stem.Up ? r.bottom : stemTipY;
35493
- this.stemRect = new DivRect(r.left, r.right, top, bottom);
35751
+ this.staffObjs.stemRect = new DivRect(r.left, r.right, top, bottom);
35494
35752
  this.updateRect();
35495
35753
  }
35496
35754
  offset(dx, dy) {
35497
- this.noteHeadRects.forEach(r => r.offsetInPlace(dx, dy));
35498
- this.dotRects.forEach(r => r.offsetInPlace(dx, dy));
35499
- this.accidentals.forEach(d => d.offset(dx, dy));
35500
- if (this.stemRect) {
35501
- this.stemRect.offsetInPlace(dx, dy);
35755
+ if (this.staffObjs) {
35756
+ this.staffObjs.noteHeadRects.forEach(r => r.offsetInPlace(dx, dy));
35757
+ this.staffObjs.dotRects.forEach(r => r.offsetInPlace(dx, dy));
35758
+ this.staffObjs.accidentals.forEach(d => d.offset(dx, dy));
35759
+ if (this.staffObjs.stemRect) {
35760
+ this.staffObjs.stemRect.offsetInPlace(dx, dy);
35761
+ }
35762
+ this.staffObjs.flagRects.forEach(r => r.offsetInPlace(dx, dy));
35763
+ }
35764
+ if (this.tabObjs) {
35765
+ this.tabObjs.fretNumbers.forEach(fn => fn.offset(dx, dy));
35502
35766
  }
35503
- this.flagRects.forEach(r => r.offsetInPlace(dx, dy));
35504
35767
  this.rect.offsetInPlace(dx, dy);
35505
35768
  }
35506
35769
  draw(renderer) {
@@ -35519,69 +35782,75 @@ class ObjNoteGroup extends MusicObject {
35519
35782
  var {
35520
35783
  noteLength
35521
35784
  } = this.rhythmProps;
35522
- // Draw accidentals
35523
- this.accidentals.forEach(d => d.draw(renderer));
35524
- ctx.strokeStyle = ctx.fillStyle = color;
35525
- ctx.lineWidth = lineWidth;
35526
- // Draw note heads
35527
- this.noteHeadRects.forEach(r => {
35528
- var outlinedNoteHead = noteLength >= NoteLength.Half;
35529
- if (this.diamond) {
35530
- if (outlinedNoteHead) {
35531
- ctx.beginPath();
35532
- ctx.lineWidth = lineWidth * 2.5;
35533
- ctx.moveTo(r.centerX, r.top);
35534
- ctx.lineTo(r.right, r.centerY);
35535
- ctx.moveTo(r.left, r.centerY);
35536
- ctx.lineTo(r.centerX, r.bottom);
35537
- ctx.stroke();
35538
- ctx.beginPath();
35539
- ctx.lineWidth = lineWidth;
35540
- ctx.moveTo(r.right, r.centerY);
35541
- ctx.lineTo(r.centerX, r.bottom);
35542
- ctx.moveTo(r.centerX, r.top);
35543
- ctx.lineTo(r.left, r.centerY);
35544
- ctx.stroke();
35785
+ if (this.staffObjs) {
35786
+ // Draw accidentals
35787
+ this.staffObjs.accidentals.forEach(d => d.draw(renderer));
35788
+ ctx.strokeStyle = ctx.fillStyle = color;
35789
+ ctx.lineWidth = lineWidth;
35790
+ // Draw note heads
35791
+ this.staffObjs.noteHeadRects.forEach(r => {
35792
+ var outlinedNoteHead = noteLength >= NoteLength.Half;
35793
+ if (this.diamond) {
35794
+ if (outlinedNoteHead) {
35795
+ ctx.beginPath();
35796
+ ctx.lineWidth = lineWidth * 2.5;
35797
+ ctx.moveTo(r.centerX, r.top);
35798
+ ctx.lineTo(r.right, r.centerY);
35799
+ ctx.moveTo(r.left, r.centerY);
35800
+ ctx.lineTo(r.centerX, r.bottom);
35801
+ ctx.stroke();
35802
+ ctx.beginPath();
35803
+ ctx.lineWidth = lineWidth;
35804
+ ctx.moveTo(r.right, r.centerY);
35805
+ ctx.lineTo(r.centerX, r.bottom);
35806
+ ctx.moveTo(r.centerX, r.top);
35807
+ ctx.lineTo(r.left, r.centerY);
35808
+ ctx.stroke();
35809
+ } else {
35810
+ ctx.beginPath();
35811
+ ctx.moveTo(r.centerX, r.top);
35812
+ ctx.lineTo(r.right, r.centerY);
35813
+ ctx.lineTo(r.centerX, r.bottom);
35814
+ ctx.lineTo(r.left, r.centerY);
35815
+ ctx.lineTo(r.centerX, r.top);
35816
+ ctx.fill();
35817
+ }
35545
35818
  } else {
35546
35819
  ctx.beginPath();
35547
- ctx.moveTo(r.centerX, r.top);
35548
- ctx.lineTo(r.right, r.centerY);
35549
- ctx.lineTo(r.centerX, r.bottom);
35550
- ctx.lineTo(r.left, r.centerY);
35551
- ctx.lineTo(r.centerX, r.top);
35552
- ctx.fill();
35820
+ ctx.ellipse(r.centerX, r.centerY, r.leftw, r.toph, -0.3, 0, Math.PI * 2);
35821
+ if (outlinedNoteHead) {
35822
+ ctx.stroke();
35823
+ } else {
35824
+ ctx.fill();
35825
+ }
35553
35826
  }
35554
- } else {
35827
+ });
35828
+ // Draw dots
35829
+ this.staffObjs.dotRects.forEach(r => renderer.fillCircle(r.centerX, r.centerY, r.width / 2));
35830
+ // Draw stem
35831
+ if (this.staffObjs.stemRect) {
35555
35832
  ctx.beginPath();
35556
- ctx.ellipse(r.centerX, r.centerY, r.leftw, r.toph, -0.3, 0, Math.PI * 2);
35557
- if (outlinedNoteHead) {
35558
- ctx.stroke();
35559
- } else {
35560
- ctx.fill();
35561
- }
35833
+ ctx.moveTo(this.staffObjs.stemRect.centerX, this.staffObjs.stemRect.bottom);
35834
+ ctx.lineTo(this.staffObjs.stemRect.centerX, this.staffObjs.stemRect.top);
35835
+ ctx.stroke();
35562
35836
  }
35563
- });
35564
- // Draw dots
35565
- this.dotRects.forEach(r => renderer.fillCircle(r.centerX, r.centerY, r.width / 2));
35566
- // Draw stem
35567
- if (this.stemRect) {
35568
- ctx.beginPath();
35569
- ctx.moveTo(this.stemRect.centerX, this.stemRect.bottom);
35570
- ctx.lineTo(this.stemRect.centerX, this.stemRect.top);
35571
- ctx.stroke();
35837
+ // Draw flags
35838
+ this.staffObjs.flagRects.forEach(rect => {
35839
+ var left = rect.left;
35840
+ var right = rect.right;
35841
+ var width = right - left;
35842
+ var top = stemDir === Stem.Up ? rect.top : rect.bottom;
35843
+ var bottom = stemDir === Stem.Up ? rect.bottom : rect.top;
35844
+ ctx.beginPath();
35845
+ ctx.moveTo(left, top);
35846
+ ctx.bezierCurveTo(left, top * 0.75 + bottom * 0.25, left + width * 1.5, top * 0.5 + bottom * 0.5, left + width * 0.5, bottom);
35847
+ ctx.stroke();
35848
+ });
35849
+ }
35850
+ if (this.tabObjs) {
35851
+ // Draw tab fret numbers
35852
+ this.tabObjs.fretNumbers.forEach(fn => fn.draw(renderer));
35572
35853
  }
35573
- // Draw flags
35574
- this.flagRects.forEach(rect => {
35575
- var left = rect.left;
35576
- var right = rect.right;
35577
- var width = right - left;
35578
- var top = stemDir === Stem.Up ? rect.top : rect.bottom;
35579
- var bottom = stemDir === Stem.Up ? rect.bottom : rect.top;
35580
- ctx.beginPath();
35581
- ctx.moveTo(left, top);
35582
- ctx.bezierCurveTo(left, top * 0.75 + bottom * 0.25, left + width * 1.5, top * 0.5 + bottom * 0.5, left + width * 0.5, bottom);
35583
- ctx.stroke();
35584
- });
35585
35854
  }
35586
35855
  static setBeamCounts(groupNotes) {
35587
35856
  var isADottedBHalf = (a, b) => {
@@ -35616,10 +35885,10 @@ class ObjNoteGroup extends MusicObject {
35616
35885
  var fixAgain;
35617
35886
  do {
35618
35887
  fixAgain = false;
35619
- for (var _i = 0; _i < groupNotes.length; _i++) {
35620
- var _center = groupNotes[_i];
35621
- var _left = groupNotes[_i - 1];
35622
- var _right = groupNotes[_i + 1];
35888
+ for (var _i2 = 0; _i2 < groupNotes.length; _i2++) {
35889
+ var _center = groupNotes[_i2];
35890
+ var _left = groupNotes[_i2 - 1];
35891
+ var _right = groupNotes[_i2 + 1];
35623
35892
  // If neither left or right beam count equals flag count, then reset beam counts.
35624
35893
  if (_center && _center.leftBeamCount !== _center.rhythmProps.flagCount && _center.rightBeamCount !== _center.rhythmProps.flagCount) {
35625
35894
  _center.leftBeamCount = _center.rightBeamCount = 0;
@@ -35656,7 +35925,8 @@ class ObjNoteGroup extends MusicObject {
35656
35925
  }
35657
35926
  }
35658
35927
  getDotVerticalDisplacement(pitch, stemDir) {
35659
- if (this.row.isPitchLine(pitch)) {
35928
+ var staff = this.row.getStaff(pitch);
35929
+ if (staff && staff.isPitchLine(pitch)) {
35660
35930
  return stemDir === Stem.Up ? -1 : 1;
35661
35931
  } else {
35662
35932
  return 0;
@@ -35687,6 +35957,7 @@ class ObjNoteGroup extends MusicObject {
35687
35957
 
35688
35958
 
35689
35959
 
35960
+
35690
35961
  var noteHeadDataCompareFunc = (a, b) => {
35691
35962
  var cmp = Note.compareFunc(a.note, b.note);
35692
35963
  if (cmp === 0) {
@@ -35804,15 +36075,16 @@ class ObjRhythmColumn extends MusicObject {
35804
36075
  }
35805
36076
  getMinWidth() {
35806
36077
  var maxNoteLength = Math.max(...this.voiceSymbol.map(s => s.rhythmProps.noteLength));
36078
+ var w = DocumentSettings.NoteHeadWidth;
35807
36079
  switch (maxNoteLength) {
35808
36080
  case NoteLength.Whole:
35809
- return 5;
36081
+ return w * 5;
35810
36082
  case NoteLength.Half:
35811
- return 4;
36083
+ return w * 3;
35812
36084
  case NoteLength.Quarter:
35813
- return 3;
36085
+ return w * 2;
35814
36086
  default:
35815
- return 2;
36087
+ return w;
35816
36088
  }
35817
36089
  }
35818
36090
  setupNoteHeadDisplacements() {
@@ -35861,6 +36133,11 @@ class ObjRhythmColumn extends MusicObject {
35861
36133
  return 0;
35862
36134
  }
35863
36135
  }
36136
+ getLowestNotePitch(pitch) {
36137
+ return Math.min(pitch, ...this.voiceSymbol.map(s => {
36138
+ return s instanceof ObjNoteGroup ? Math.min(...s.notes.map(n => n.pitch)) : s.ownAvgPitch;
36139
+ }));
36140
+ }
35864
36141
  getPlayerNotes() {
35865
36142
  var playerNotes = [];
35866
36143
  function addNote(note, ticks, staccato, slur) {
@@ -35915,16 +36192,13 @@ class ObjRhythmColumn extends MusicObject {
35915
36192
  return;
35916
36193
  }
35917
36194
  var {
35918
- row,
35919
- doc
36195
+ row
35920
36196
  } = this;
35921
36197
  var {
35922
36198
  unitSize
35923
36199
  } = renderer;
35924
36200
  // Set initially column's min width
35925
36201
  var halfMinWidth = this.getMinWidth() * unitSize / 2;
35926
- var staffTop = row.getTopStaffLineTop();
35927
- var staffBottom = row.getBottomStaffLineBottom();
35928
36202
  var initRect = true;
35929
36203
  // Layout voice symbols
35930
36204
  this.voiceSymbol.forEach(symbol => {
@@ -35937,13 +36211,15 @@ class ObjRhythmColumn extends MusicObject {
35937
36211
  this.rect.expandInPlace(r);
35938
36212
  });
35939
36213
  if (initRect) {
36214
+ var staffTop = row.hasStaff ? row.getTopStaff().topLineY : 0;
36215
+ var staffBottom = row.hasStaff ? row.getBottomStaff().bottomLineY : 0;
35940
36216
  this.rect = new DivRect(-halfMinWidth, 0, halfMinWidth, (staffTop + staffBottom) / 2, 0, (staffTop + staffBottom) / 2);
35941
36217
  }
35942
36218
  if (this.arpeggioDir !== undefined) {
35943
- this.arpeggios = row.getStaffLines().map(staffLine => {
36219
+ this.arpeggios = row.getStaves().map(staff => {
35944
36220
  var arpeggio = new ObjArpeggio(this, this.getArpeggioDir());
35945
36221
  arpeggio.layout(renderer);
35946
- arpeggio.offset(this.rect.left - arpeggio.getRect().width, staffLine.middleLineOffset * row.getLineSpacing());
36222
+ arpeggio.offset(this.rect.left - arpeggio.getRect().width, staff.middleLineY - arpeggio.getRect().centerY);
35947
36223
  return arpeggio;
35948
36224
  });
35949
36225
  this.arpeggios.forEach(arpeggio => this.rect.expandInPlace(arpeggio.getRect()));
@@ -36498,7 +36774,7 @@ class player_Player {
36498
36774
  curMeasure = segnoMeasure;
36499
36775
  } else if (curMeasure.hasNavigation(Navigation.EndRepeat)) {
36500
36776
  var _passage = curMeasure.getPassCount();
36501
- var repeatCount = curMeasure === null || curMeasure === void 0 ? void 0 : curMeasure.getEndRepeatCount();
36777
+ var repeatCount = (curMeasure === null || curMeasure === void 0 ? void 0 : curMeasure.getEndRepeatCount()) - 1;
36502
36778
  var cannotPassThrough = ((_a = curMeasure.getNextMeasure()) === null || _a === void 0 ? void 0 : _a.hasNavigation(Navigation.Ending)) === true;
36503
36779
  if (_passage <= repeatCount || cannotPassThrough) {
36504
36780
  curMeasure = startRepeatMeasure;
@@ -36779,6 +37055,7 @@ class ObjBarLine extends MusicObject {
36779
37055
  return this.rect.contains(x, y) ? [this] : [];
36780
37056
  }
36781
37057
  layout(renderer) {
37058
+ var _a, _b;
36782
37059
  this.barLineType = this.solveBarLineType();
36783
37060
  var {
36784
37061
  unitSize,
@@ -36794,23 +37071,35 @@ class ObjBarLine extends MusicObject {
36794
37071
  var thinW = lineWidth;
36795
37072
  var thicW = 0.7 * unitSize;
36796
37073
  var spaceW = 0.7 * unitSize;
36797
- var dotW = Renderer.DotSize * unitSize;
36798
- var lineSpacing = row.getLineSpacing();
37074
+ var dotW = DocumentSettings.DotSize * unitSize;
36799
37075
  var dotRadius = dotW / 2;
36800
- var dotOffset = this.measure.row.getPitchSpacing();
36801
- var top = (row.getTopStaffLine().middleLineOffset - 2) * lineSpacing;
36802
- var bottom = (row.getBottomStaffLine().middleLineOffset + 2) * lineSpacing;
37076
+ var lineCenterYs = row.getStaves().map(staff => staff.middleLineY);
37077
+ var lineDotOffs = row.getStaves().map(staff => staff.getPitchSpacing());
37078
+ var tab = row.getTab();
37079
+ if (tab) {
37080
+ lineCenterYs.push((tab.bottom + tab.top) / 2);
37081
+ lineDotOffs.push((tab.bottom - tab.top) / 6);
37082
+ }
37083
+ var top, bottom;
37084
+ if (row.hasStaff) {
37085
+ top = row.getTopStaff().topLineY;
37086
+ bottom = tab ? tab.getStringY(5) : row.getBottomStaff().bottomLineY;
37087
+ } else {
37088
+ // hasTab is true
37089
+ top = (_a = tab === null || tab === void 0 ? void 0 : tab.getStringY(0)) !== null && _a !== void 0 ? _a : 0;
37090
+ bottom = (_b = tab === null || tab === void 0 ? void 0 : tab.getStringY(5)) !== null && _b !== void 0 ? _b : 0;
37091
+ }
36803
37092
  this.lineRects = [];
36804
37093
  this.dotRects = [];
36805
37094
  var addRect = (left, width) => {
36806
37095
  this.lineRects.push(new DivRect(left, left + width / 2, left + width, top, 0, bottom));
36807
37096
  };
36808
37097
  var addDots = cx => {
36809
- row.getStaffLines().forEach(staffLine => {
36810
- var cy = staffLine.middleLineOffset * lineSpacing - dotOffset;
36811
- this.dotRects.push(new DivRect(cx - dotRadius, cx, cx + dotRadius, cy - dotRadius, cy, cy + dotRadius));
36812
- cy += 2 * dotOffset;
36813
- this.dotRects.push(new DivRect(cx - dotRadius, cx, cx + dotRadius, cy - dotRadius, cy, cy + dotRadius));
37098
+ lineCenterYs.forEach((cy, id) => {
37099
+ for (var i = -1; i <= 1; i += 2) {
37100
+ var y = cy + i * lineDotOffs[id];
37101
+ this.dotRects.push(new DivRect(cx - dotRadius, cx, cx + dotRadius, y - dotRadius, y, y + dotRadius));
37102
+ }
36814
37103
  });
36815
37104
  };
36816
37105
  switch (barLineType) {
@@ -37170,7 +37459,7 @@ class ObjExtensionLine extends MusicObject {
37170
37459
  // Draw tip end of last line
37171
37460
  var tails = this.extension.getTails();
37172
37461
  if (tails.length > 0 && this === tails[tails.length - 1]) {
37173
- var tipH = rect.centerY > this.measure.row.getBottomStaffLineBottom() ? -renderer.unitSize : renderer.unitSize;
37462
+ var tipH = rect.centerY > this.measure.row.getRect().centerY ? -renderer.unitSize : renderer.unitSize;
37174
37463
  renderer.drawLine(rect.right, rect.centerY, rect.right, rect.centerY + tipH, "black", renderer.lineWidth);
37175
37464
  }
37176
37465
  }
@@ -37216,8 +37505,9 @@ class ObjMeasure extends MusicObject {
37216
37505
  this.leftSolidAreaWidth = 0;
37217
37506
  this.minColumnsAreaWidth = 0;
37218
37507
  this.rightSolidAreaWidth = 0;
37219
- this.useStemDir = [];
37220
37508
  this.usePitch = [];
37509
+ this.useStemDir = [];
37510
+ this.useString = [];
37221
37511
  this.voiceSymbols = [];
37222
37512
  this.layoutObjects = [];
37223
37513
  this.postMeasureBreakWidth = 0;
@@ -37250,6 +37540,9 @@ class ObjMeasure extends MusicObject {
37250
37540
  isPartialMeasure() {
37251
37541
  return this.getConsumedTicks() < this.getMeasureTicks();
37252
37542
  }
37543
+ isUpBeat() {
37544
+ return this === this.doc.getFirstMeasure();
37545
+ }
37253
37546
  resetPassCount() {
37254
37547
  this.passCount = 0;
37255
37548
  }
@@ -37259,6 +37552,29 @@ class ObjMeasure extends MusicObject {
37259
37552
  getPassCount() {
37260
37553
  return this.passCount;
37261
37554
  }
37555
+ updateOwnAvgPitch(voiceId, setPitch) {
37556
+ if (typeof setPitch == "string") {
37557
+ this.usePitch[voiceId] = Note.getNote(setPitch).pitch;
37558
+ } else if (typeof setPitch == "number") {
37559
+ this.usePitch[voiceId] = setPitch;
37560
+ } else if (setPitch instanceof Note) {
37561
+ this.usePitch[voiceId] = setPitch.pitch;
37562
+ } else if (this.usePitch[voiceId] === undefined) {
37563
+ var prevMeasure = this.getPrevMeasure();
37564
+ if (prevMeasure && prevMeasure.usePitch[voiceId] !== undefined) {
37565
+ this.usePitch[voiceId] = prevMeasure.usePitch[voiceId];
37566
+ }
37567
+ }
37568
+ var pitch = this.usePitch[voiceId];
37569
+ if (pitch === undefined) {
37570
+ if (this.row.hasStaff) {
37571
+ pitch = this.row.getTopStaff().middleLinePitch;
37572
+ } else {
37573
+ pitch = Note.getNote("C4").pitch;
37574
+ }
37575
+ }
37576
+ return this.usePitch[voiceId] = Note.validatePitch(pitch);
37577
+ }
37262
37578
  updateOwnStemDir(symbol, setStemDir) {
37263
37579
  var _a, _b;
37264
37580
  var {
@@ -37271,28 +37587,27 @@ class ObjMeasure extends MusicObject {
37271
37587
  }
37272
37588
  var stemDir = this.useStemDir[voiceId];
37273
37589
  if (stemDir === Stem.Auto || stemDir === undefined) {
37274
- var staffLine = this.row.getClosestStaffLine(symbol.ownAvgPitch);
37275
- return symbol.ownAvgPitch > staffLine.middleLinePitch ? Stem.Down : Stem.Up;
37590
+ var staff = this.row.getStaff(symbol.ownAvgPitch);
37591
+ if (staff) {
37592
+ return symbol.ownAvgPitch > staff.middleLinePitch ? Stem.Down : Stem.Up;
37593
+ } else {
37594
+ return Stem.Up;
37595
+ }
37276
37596
  } else {
37277
37597
  return stemDir;
37278
37598
  }
37279
37599
  }
37280
- updateOwnAvgPitch(voiceId, setPitch) {
37281
- var _a;
37282
- if (typeof setPitch == "string") {
37283
- this.usePitch[voiceId] = Note.getNote(setPitch).pitch;
37284
- } else if (typeof setPitch == "number") {
37285
- this.usePitch[voiceId] = setPitch;
37286
- } else if (setPitch instanceof Note) {
37287
- this.usePitch[voiceId] = setPitch.pitch;
37288
- } else if (this.usePitch[voiceId] === undefined) {
37289
- var prevMeasure = this.getPrevMeasure();
37290
- if (prevMeasure && prevMeasure.usePitch[voiceId] !== undefined) {
37291
- this.usePitch[voiceId] = prevMeasure.usePitch[voiceId];
37292
- }
37600
+ updateOwnString(symbol, setString) {
37601
+ var _a, _b;
37602
+ var {
37603
+ voiceId
37604
+ } = symbol;
37605
+ if (setString !== undefined) {
37606
+ this.useString[voiceId] = setString;
37607
+ } else if (this.useString[voiceId] === undefined) {
37608
+ this.useString[voiceId] = (_b = (_a = this.getPrevMeasure()) === null || _a === void 0 ? void 0 : _a.useString[voiceId]) !== null && _b !== void 0 ? _b : [];
37293
37609
  }
37294
- var pitch = (_a = this.usePitch[voiceId]) !== null && _a !== void 0 ? _a : this.row.getTopStaffLine().middleLinePitch;
37295
- return this.usePitch[voiceId] = Note.validatePitch(pitch);
37610
+ return this.useString[voiceId];
37296
37611
  }
37297
37612
  pick(x, y) {
37298
37613
  if (!this.rect.contains(x, y)) {
@@ -37672,10 +37987,6 @@ class ObjMeasure extends MusicObject {
37672
37987
  this.voiceSymbols[voiceId].push(symbol);
37673
37988
  this.requestBeamsUpdate();
37674
37989
  this.lastAddedRhythmColumn = col;
37675
- // Collect arc data now that symbol is set
37676
- if (symbol instanceof ObjNoteGroup) {
37677
- this.onAddNoteGroup(symbol);
37678
- }
37679
37990
  }
37680
37991
  addNoteGroup(voiceId, notes, noteLength, options) {
37681
37992
  var notes2 = notes.map(note => typeof note === "string" ? Note.getNote(note) : note);
@@ -37709,16 +38020,11 @@ class ObjMeasure extends MusicObject {
37709
38020
  } else if (!_col || _col.positionTicks > positionTicks) {
37710
38021
  var _col2 = new ObjRhythmColumn(this, positionTicks);
37711
38022
  this.columns.splice(_i5, 0, _col2);
37712
- this.onAddRhythmColumn(_col2);
37713
38023
  return _col2;
37714
38024
  }
37715
38025
  }
37716
38026
  Assert.interrupt("Error in rhythm column. Should never get here.");
37717
38027
  }
37718
- onAddRhythmColumn(col) {}
37719
- onAddNoteGroup(noteGroup) {
37720
- noteGroup.collectArcDatas();
37721
- }
37722
38028
  getMeasureTicks() {
37723
38029
  return this.getTimeSignature().measureTicks;
37724
38030
  }
@@ -37764,8 +38070,8 @@ class ObjMeasure extends MusicObject {
37764
38070
  getStaffLineRight() {
37765
38071
  return this.barLineRight.getRect().centerX;
37766
38072
  }
37767
- forEachLayoutObject(fn) {
37768
- this.layoutObjects.forEach(layoutObj => fn(layoutObj));
38073
+ getStaticObjects() {
38074
+ return [...this.getColumns(), ...this.layoutObjects.filter(layoutObj => layoutObj.isPositionResolved()).map(layoutObj => layoutObj.musicObj)];
37769
38075
  }
37770
38076
  removeLayoutObjects(musicObj) {
37771
38077
  this.layoutObjects = this.layoutObjects.filter(layoutObj => {
@@ -37781,27 +38087,18 @@ class ObjMeasure extends MusicObject {
37781
38087
  }
37782
38088
  });
37783
38089
  }
37784
- addArc(arc) {
38090
+ addArcObject(arc) {
37785
38091
  this.arcs.push(arc);
37786
38092
  this.requestLayout();
37787
38093
  }
37788
- updateArcs() {
37789
- // Remove arcs
38094
+ removeArcObjects() {
37790
38095
  if (this.arcs.length > 0) {
37791
38096
  this.arcs = [];
37792
38097
  this.requestLayout();
37793
38098
  }
37794
- // Recreate arcs
37795
- ObjMeasure.VoiceIdList.forEach(voiceId => {
37796
- this.getVoiceSymbols(voiceId).forEach(symbol => {
37797
- if (symbol instanceof ObjNoteGroup) {
37798
- symbol.createObjArcs();
37799
- }
37800
- });
37801
- });
37802
38099
  }
37803
38100
  updateExtensions() {
37804
- this.forEachLayoutObject(layoutObj => {
38101
+ this.layoutObjects.forEach(layoutObj => {
37805
38102
  if (layoutObj.musicObj.getLink() instanceof Extension) {
37806
38103
  var extension = layoutObj.musicObj.getLink();
37807
38104
  if (extension.getHead() === layoutObj.musicObj) {
@@ -37830,7 +38127,7 @@ class ObjMeasure extends MusicObject {
37830
38127
  this.needBeamsUpdate = true;
37831
38128
  }
37832
38129
  updateBeams() {
37833
- if (!this.needBeamsUpdate) {
38130
+ if (!this.needBeamsUpdate || !this.row.hasStaff) {
37834
38131
  return;
37835
38132
  }
37836
38133
  // Remove old beams/triplets
@@ -37839,34 +38136,50 @@ class ObjMeasure extends MusicObject {
37839
38136
  });
37840
38137
  this.beamGroups = [];
37841
38138
  // Recreate beams/triplets
37842
- var ts = this.getTimeSignature();
37843
38139
  ObjMeasure.VoiceIdList.forEach(voiceId => {
37844
38140
  var symbols = this.getVoiceSymbols(voiceId);
37845
- ObjMeasure.createTriplets(symbols);
37846
- ObjMeasure.createBeams(symbols, ts);
37847
- });
37848
- this.needBeamsUpdate = false;
37849
- this.requestLayout();
37850
- }
37851
- static createBeams(symbols, ts) {
37852
- if (DebugSettings.DisableBeams || symbols.length < 2) {
37853
- return;
37854
- }
37855
- var groupSymbols = [];
37856
- var groupStartTicks = 0;
37857
- var groupEndTicks = 0;
37858
- symbols.forEach(symbol => {
37859
- groupSymbols.push(symbol);
37860
- groupEndTicks += symbol.rhythmProps.ticks;
37861
- if (groupStartTicks === 0 && groupEndTicks === ts.beamGroupLength) {
37862
- // Perfect group, setup beams
37863
- ObjMeasure.setupBeamGroup(groupSymbols);
38141
+ if (symbols.length <= 2) {
38142
+ return;
37864
38143
  }
37865
- while (groupEndTicks >= ts.beamGroupLength) {
37866
- groupSymbols = [];
37867
- groupStartTicks = groupEndTicks = groupEndTicks - ts.beamGroupLength;
38144
+ // Create triplets
38145
+ for (var i = 0; i < symbols.length;) {
38146
+ var s2 = symbols.slice(i, i + 2);
38147
+ var s3 = symbols.slice(i, i + 3);
38148
+ if (s2.length === 2 && ObjBeamGroup.createTriplet(s2)) {
38149
+ i += 2;
38150
+ } else if (s3.length === 3 && ObjBeamGroup.createTriplet(s3)) {
38151
+ i += 3;
38152
+ } else {
38153
+ i++;
38154
+ }
38155
+ }
38156
+ // Create beams
38157
+ if (!DebugSettings.DisableBeams) {
38158
+ var groupSymbols = [];
38159
+ var groupStartTicks = 0;
38160
+ var groupEndTicks = 0;
38161
+ // Is upbeat? Set starting ticks position.
38162
+ if (this.isUpBeat()) {
38163
+ var startTicks = Math.max(0, this.getMeasureTicks() - this.getConsumedTicks());
38164
+ groupStartTicks = groupEndTicks = startTicks;
38165
+ }
38166
+ var ts = this.getTimeSignature();
38167
+ symbols.forEach(symbol => {
38168
+ groupSymbols.push(symbol);
38169
+ groupEndTicks += symbol.rhythmProps.ticks;
38170
+ if (groupStartTicks === 0 && groupEndTicks === ts.beamGroupLength) {
38171
+ // Perfect group, setup beams
38172
+ ObjMeasure.setupBeamGroup(groupSymbols);
38173
+ }
38174
+ while (groupEndTicks >= ts.beamGroupLength) {
38175
+ groupSymbols = [];
38176
+ groupStartTicks = groupEndTicks = groupEndTicks - ts.beamGroupLength;
38177
+ }
38178
+ });
37868
38179
  }
37869
38180
  });
38181
+ this.needBeamsUpdate = false;
38182
+ this.requestLayout();
37870
38183
  }
37871
38184
  static setupBeamGroup(groupSymbols) {
37872
38185
  var groupNotes = groupSymbols.map(s => {
@@ -37886,19 +38199,6 @@ class ObjMeasure extends MusicObject {
37886
38199
  });
37887
38200
  ObjBeamGroup.createBeam(beamNotes);
37888
38201
  }
37889
- static createTriplets(symbols) {
37890
- for (var i = 0; i < symbols.length;) {
37891
- var s2 = symbols.slice(i, i + 2);
37892
- var s3 = symbols.slice(i, i + 3);
37893
- if (s2.length === 2 && ObjBeamGroup.createTriplet(s2)) {
37894
- i += 2;
37895
- } else if (s3.length === 3 && ObjBeamGroup.createTriplet(s3)) {
37896
- i += 3;
37897
- } else {
37898
- i++;
37899
- }
37900
- }
37901
- }
37902
38202
  static validateVoiceId(voiceId) {
37903
38203
  Assert.in_group(voiceId, ObjMeasure.VoiceIdList, "Invalid voice id: " + voiceId);
37904
38204
  return voiceId;
@@ -37956,6 +38256,9 @@ class ObjMeasure extends MusicObject {
37956
38256
  dotted: rest.dotted
37957
38257
  }));
37958
38258
  }
38259
+ getLowestNotePitch(pitch) {
38260
+ return Math.min(pitch, ...this.columns.map(c => c.getLowestNotePitch(pitch)));
38261
+ }
37959
38262
  requestLayout() {
37960
38263
  if (!this.needLayout) {
37961
38264
  this.needLayout = true;
@@ -37979,14 +38282,14 @@ class ObjMeasure extends MusicObject {
37979
38282
  var showTimeSignature = !!this.alterTimeSignature;
37980
38283
  var showTempo = !!this.alterTempo;
37981
38284
  if (showClef || showMeasureNumber || showKeySignature || showTimeSignature || showTempo) {
37982
- this.signatures = this.row.getStaffLines().map((staffLine, staffLineId) => {
38285
+ this.signatures = this.row.getStaves().map((staff, staffId) => {
37983
38286
  var _a;
37984
- var signature = (_a = this.signatures[staffLineId]) !== null && _a !== void 0 ? _a : new ObjSignature(this, staffLine);
38287
+ var signature = (_a = this.signatures[staffId]) !== null && _a !== void 0 ? _a : new ObjSignature(this, staff);
37985
38288
  signature.updateClefImage(renderer, showClef);
37986
- signature.updateMeasureNumber(showMeasureNumber && staffLineId === 0);
38289
+ signature.updateMeasureNumber(showMeasureNumber && staffId === 0);
37987
38290
  signature.updateKeySignature(showKeySignature);
37988
38291
  signature.updateTimeSignature(showTimeSignature);
37989
- signature.updateTempo(showTempo && staffLineId === 0);
38292
+ signature.updateTempo(showTempo && staffId === 0);
37990
38293
  signature.layout(renderer);
37991
38294
  return signature;
37992
38295
  });
@@ -38006,6 +38309,11 @@ class ObjMeasure extends MusicObject {
38006
38309
  // Calc top and bottom
38007
38310
  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);
38008
38311
  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);
38312
+ var tab = this.row.getTab();
38313
+ if (tab) {
38314
+ top = Math.min(top, tab.top);
38315
+ bottom = Math.max(bottom, tab.bottom);
38316
+ }
38009
38317
  // Set rect toph and bottomh
38010
38318
  this.rect = new DivRect(0, 0, 0, top, 0, bottom);
38011
38319
  var padding = renderer.unitSize;
@@ -38084,7 +38392,7 @@ class ObjMeasure extends MusicObject {
38084
38392
  }
38085
38393
  this.arcs.forEach(arc => arc.offset(dx, dy));
38086
38394
  this.beamGroups.forEach(beam => beam.offset(dx, dy));
38087
- this.forEachLayoutObject(layoutObj => layoutObj.musicObj.offset(dx, dy));
38395
+ this.layoutObjects.forEach(layoutObj => layoutObj.musicObj.offset(dx, dy));
38088
38396
  this.rect.offsetInPlace(dx, dy);
38089
38397
  }
38090
38398
  draw(renderer) {
@@ -38092,12 +38400,21 @@ class ObjMeasure extends MusicObject {
38092
38400
  // Draw staff lines
38093
38401
  var left = this.getStaffLineLeft();
38094
38402
  var right = this.getStaffLineRight();
38095
- this.row.getStaffLines().forEach(staffLine => {
38096
- for (var p = staffLine.bottomLinePitch; p <= staffLine.topLinePitch; p += 2) {
38097
- var y = this.row.getPitchY(p);
38098
- renderer.drawLine(left, y, right, y);
38403
+ var drawLine = y => renderer.drawLine(left, y, right, y);
38404
+ var {
38405
+ row
38406
+ } = this;
38407
+ row.getStaves().forEach(staff => {
38408
+ for (var p = staff.bottomLinePitch; p <= staff.topLinePitch; p += 2) {
38409
+ drawLine(staff.getPitchY(p));
38099
38410
  }
38100
38411
  });
38412
+ var tab = row.getTab();
38413
+ if (tab) {
38414
+ for (var stringId = 0; stringId < 6; stringId++) {
38415
+ drawLine(tab.getStringY(stringId));
38416
+ }
38417
+ }
38101
38418
  this.signatures.forEach(signature => signature.draw(renderer));
38102
38419
  this.barLineLeft.draw(renderer);
38103
38420
  this.columns.forEach(col => col.draw(renderer));
@@ -38106,7 +38423,7 @@ class ObjMeasure extends MusicObject {
38106
38423
  this.endRepeatCountText.draw(renderer);
38107
38424
  }
38108
38425
  this.arcs.forEach(arc => arc.draw(renderer));
38109
- this.forEachLayoutObject(layoutObj => layoutObj.musicObj.draw(renderer));
38426
+ this.layoutObjects.forEach(layoutObj => layoutObj.musicObj.draw(renderer));
38110
38427
  this.beamGroups.forEach(beam => beam.draw(renderer));
38111
38428
  }
38112
38429
  }
@@ -38172,16 +38489,14 @@ class LayoutObjectWrapper {
38172
38489
  measure,
38173
38490
  verticalPos
38174
38491
  } = this;
38175
- var staffTop = measure.row.getTopStaffLineTop();
38176
- var staffBottom = measure.row.getBottomStaffLineBottom();
38492
+ var {
38493
+ row
38494
+ } = measure;
38495
+ var staffTop = row.hasStaff ? row.getTopStaff().topLineY : row.getRect().centerY;
38496
+ var staffBottom = row.hasStaff ? row.getBottomStaff().bottomLineY : row.getRect().centerY;
38177
38497
  var staffPadding = renderer.unitSize * 2;
38178
38498
  var y = verticalPos === VerticalPos.BelowStaff ? staffBottom + staffPadding + musicObj.getRect().toph : staffTop - staffPadding - musicObj.getRect().bottomh;
38179
- var staticObjects = [...measure.getColumns()];
38180
- measure.forEachLayoutObject(layoutObj => {
38181
- if (layoutObj.isPositionResolved()) {
38182
- staticObjects.push(layoutObj.musicObj);
38183
- }
38184
- });
38499
+ var staticObjects = measure.getStaticObjects();
38185
38500
  var objShapeRects = musicObj.getShapeRects();
38186
38501
  staticObjects.forEach(resolveObj => {
38187
38502
  var staticShapeRects = resolveObj.getShapeRects();
@@ -38243,40 +38558,46 @@ class LayoutGroup {
38243
38558
 
38244
38559
 
38245
38560
 
38561
+
38562
+
38246
38563
  var p = noteName => Note.getNote(noteName).pitch;
38247
- var StaffLine_Treble = new StaffLine(ClefKind.Treble, p("G4"), p("B4"), 0, p("C3"), p("C7"));
38248
- var StaffLine_TrebleForGuitar = new StaffLine(ClefKind.Treble, p("G3"), p("B3"), 0, p("C2"), p("C6"));
38249
- var StaffLine_Bass = new StaffLine(ClefKind.Bass, p("F3"), p("D3"), 0, p("C1"), p("C5"));
38250
- var StaffLine_Grand_Treble = new StaffLine(ClefKind.Treble, p("G4"), p("B4"), -4, p("C4"), p("C7"));
38251
- var StaffLine_Grand_Bass = new StaffLine(ClefKind.Bass, p("F3"), p("D3"), 4, p("C1"), p("C4") - 1);
38564
+ var createStaff_Treble = () => new MusicStaff(ClefKind.Treble, p("G4"), p("B4"), p("C3"), p("C7"));
38565
+ var createStaff_GuitarTreble = () => new MusicStaff(ClefKind.Treble, p("G3"), p("B3"), p("C2"), p("C6"));
38566
+ var createStaff_Bass = () => new MusicStaff(ClefKind.Bass, p("F3"), p("D3"), p("C1"), p("C5"));
38567
+ var createStaff_Grand_Treble = () => new MusicStaff(ClefKind.Treble, p("G4"), p("B4"), p("C4"), p("C7"));
38568
+ var createStaff_Grand_Bass = () => new MusicStaff(ClefKind.Bass, p("F3"), p("D3"), p("C1"), p("C4") - 1);
38252
38569
  class ObjScoreRow extends MusicObject {
38253
38570
  constructor(doc) {
38254
38571
  super(doc);
38255
38572
  this.doc = doc;
38256
- this.pitchSpacing = 0;
38257
- this.lineSpacing = 0;
38258
38573
  this.minWidth = 0;
38259
- this.staffLines = [];
38574
+ this.staves = [];
38260
38575
  this.measures = [];
38261
- this.closestStaffLineCache = [];
38262
- this.cachedPitchY = [];
38263
38576
  this.needLayout = true;
38264
38577
  this.staffKind = doc.staffKind;
38265
38578
  switch (this.staffKind) {
38266
- case StaffKind.TrebleForGuitar:
38267
- this.staffLines[0] = StaffLine_TrebleForGuitar;
38268
- break;
38269
38579
  case StaffKind.Treble:
38270
- default:
38271
- this.staffLines[0] = StaffLine_Treble;
38580
+ this.staves[0] = createStaff_Treble();
38272
38581
  break;
38273
38582
  case StaffKind.Bass:
38274
- this.staffLines[0] = StaffLine_Bass;
38583
+ this.staves[0] = createStaff_Bass();
38275
38584
  break;
38276
38585
  case StaffKind.Grand:
38277
- this.staffLines[0] = StaffLine_Grand_Treble;
38278
- this.staffLines[1] = StaffLine_Grand_Bass;
38586
+ this.staves[0] = createStaff_Grand_Treble();
38587
+ this.staves[1] = createStaff_Grand_Bass();
38588
+ break;
38589
+ case StaffKind.GuitarTreble:
38590
+ this.staves[0] = createStaff_GuitarTreble();
38591
+ break;
38592
+ case StaffKind.GuitarTab:
38593
+ this.tab = new GuitarTab();
38594
+ break;
38595
+ case StaffKind.GuitarTrebleAndTab:
38596
+ this.staves[0] = createStaff_GuitarTreble();
38597
+ this.tab = new GuitarTab();
38279
38598
  break;
38599
+ default:
38600
+ Assert.assert("Invalid staffKind = " + this.staffKind);
38280
38601
  }
38281
38602
  // Set prevRow
38282
38603
  this.prevRow = doc.getLastRow();
@@ -38289,42 +38610,43 @@ class ObjScoreRow extends MusicObject {
38289
38610
  getMusicInterface() {
38290
38611
  return this.mi;
38291
38612
  }
38292
- get minPitch() {
38293
- return this.getBottomStaffLine().minPitch;
38613
+ get hasStaff() {
38614
+ return this.staves[0] !== undefined;
38615
+ }
38616
+ get hasTab() {
38617
+ return this.tab !== undefined;
38294
38618
  }
38295
- get maxPitch() {
38296
- return this.getTopStaffLine().maxPitch;
38619
+ getTab() {
38620
+ return this.tab;
38297
38621
  }
38298
- getStaffLines() {
38299
- return this.staffLines;
38622
+ getStaves() {
38623
+ return this.staves;
38300
38624
  }
38301
- getTopStaffLine() {
38302
- return this.staffLines[0];
38625
+ getTopStaff() {
38626
+ return Assert.require(this.staves[0], "Top staff line is required!");
38303
38627
  }
38304
- getBottomStaffLine() {
38305
- return this.staffLines[this.staffLines.length - 1];
38628
+ getBottomStaff() {
38629
+ return Assert.require(this.staves[this.staves.length - 1], "Bottom staff line is required!");
38306
38630
  }
38307
- getClosestStaffLine(pitch) {
38631
+ getStaff(pitch) {
38308
38632
  Note.validatePitch(pitch);
38309
- if (this.closestStaffLineCache[pitch] === undefined) {
38310
- var closestDistToPitch = Math.abs(pitch - this.staffLines[0].middleLinePitch);
38311
- var closestStaffLine = this.staffLines[0];
38312
- for (var i = 1; i < this.staffLines.length; i++) {
38313
- var dist = Math.abs(pitch - this.staffLines[i].middleLinePitch);
38314
- if (dist < closestDistToPitch) {
38315
- closestDistToPitch = dist;
38316
- closestStaffLine = this.staffLines[i];
38317
- }
38633
+ for (var i = 0; i < this.staves.length; i++) {
38634
+ var staff = this.staves[i];
38635
+ if (staff.containsPitch(pitch)) {
38636
+ return staff;
38318
38637
  }
38319
- this.closestStaffLineCache[pitch] = closestStaffLine;
38320
38638
  }
38321
- return this.closestStaffLineCache[pitch];
38322
- }
38323
- isPitchLine(pitch) {
38324
- return pitch % 2 === this.staffLines[0].middleLinePitch % 2;
38639
+ return undefined;
38325
38640
  }
38326
- isPitchSpace(pitch) {
38327
- return pitch % 2 !== this.staffLines[0].middleLinePitch % 2;
38641
+ getLowestNotePitch() {
38642
+ if (!this.hasStaff) {
38643
+ return undefined;
38644
+ } else if (this.doc.needFullPitchRange()) {
38645
+ return this.getBottomStaff().minPitch;
38646
+ } else {
38647
+ var pitch = this.getBottomStaff().bottomLinePitch;
38648
+ return Math.min(pitch, ...this.measures.map(m => m.getLowestNotePitch(pitch)));
38649
+ }
38328
38650
  }
38329
38651
  pick(x, y) {
38330
38652
  if (!this.rect.contains(x, y)) {
@@ -38344,35 +38666,10 @@ class ObjScoreRow extends MusicObject {
38344
38666
  var left = firstMeasure ? firstMeasure.getColumnsContentRect().left : r.left;
38345
38667
  return new DivRect(left, (left + r.right) / 2, r.right, r.top, r.centerY, r.bottom);
38346
38668
  }
38347
- getPitchSpacing() {
38348
- return this.pitchSpacing;
38349
- }
38350
- getLineSpacing() {
38351
- return this.lineSpacing;
38352
- }
38353
- getPitchY(pitch) {
38354
- Note.validatePitch(pitch);
38355
- if (this.cachedPitchY[pitch] === undefined) {
38356
- var staffLine = this.staffLines.length === 1 || pitch >= this.staffLines[0].minPitch ? this.staffLines[0] : this.staffLines[1];
38357
- var {
38358
- pitchSpacing,
38359
- lineSpacing
38360
- } = this;
38361
- var offsetY = staffLine.middleLineOffset * lineSpacing;
38362
- this.cachedPitchY[pitch] = offsetY - (pitch - staffLine.middleLinePitch) * pitchSpacing;
38363
- }
38364
- return this.cachedPitchY[pitch] + this.rect.centerY;
38365
- }
38366
38669
  getPitchAt(y) {
38367
- var {
38368
- pitchSpacing,
38369
- lineSpacing
38370
- } = this;
38371
- for (var i = 0; i < this.staffLines.length; i++) {
38372
- var staffLine = this.staffLines[i];
38373
- var offsetY = staffLine.middleLineOffset * lineSpacing;
38374
- var pitch = Math.round(staffLine.middleLinePitch - (y - this.rect.centerY - offsetY) / pitchSpacing);
38375
- if (pitch >= staffLine.minPitch && pitch <= staffLine.maxPitch) {
38670
+ for (var i = 0; i < this.staves.length; i++) {
38671
+ var pitch = this.staves[i].getPitchAt(y);
38672
+ if (pitch !== undefined) {
38376
38673
  return pitch;
38377
38674
  }
38378
38675
  }
@@ -38405,12 +38702,6 @@ class ObjScoreRow extends MusicObject {
38405
38702
  getMinWidth() {
38406
38703
  return this.minWidth;
38407
38704
  }
38408
- getTopStaffLineTop() {
38409
- return this.getPitchY(this.getTopStaffLine().topLinePitch);
38410
- }
38411
- getBottomStaffLineBottom() {
38412
- return this.getPitchY(this.getBottomStaffLine().bottomLinePitch);
38413
- }
38414
38705
  requestLayout() {
38415
38706
  if (!this.needLayout) {
38416
38707
  this.needLayout = true;
@@ -38418,6 +38709,7 @@ class ObjScoreRow extends MusicObject {
38418
38709
  }
38419
38710
  }
38420
38711
  layout(renderer) {
38712
+ var _a;
38421
38713
  if (!this.needLayout) {
38422
38714
  return;
38423
38715
  }
@@ -38425,32 +38717,45 @@ class ObjScoreRow extends MusicObject {
38425
38717
  unitSize
38426
38718
  } = renderer;
38427
38719
  this.rect = new DivRect();
38428
- if (this.pitchSpacing !== unitSize) {
38429
- this.pitchSpacing = unitSize;
38430
- this.lineSpacing = this.pitchSpacing * 2;
38431
- // pitch spacing changed, clear pitch y cache.
38432
- this.cachedPitchY.length = 0;
38720
+ var lineSpacing = unitSize * 2;
38721
+ // Compute staff top/bottom line y
38722
+ this.staves.forEach(staff => {
38723
+ staff.topLineY = -lineSpacing * 2;
38724
+ staff.bottomLineY = lineSpacing * 2;
38725
+ });
38726
+ if (this.staves.length === 2) {
38727
+ this.staves[0].topLineY -= lineSpacing * 4;
38728
+ this.staves[0].bottomLineY -= lineSpacing * 4;
38729
+ this.staves[1].topLineY += lineSpacing * 4;
38730
+ this.staves[1].bottomLineY += lineSpacing * 4;
38433
38731
  }
38434
- // Layout measures
38435
- this.measures.forEach(m => m.layout(renderer));
38436
38732
  // Compute toph and bottomh
38437
- var toph = 0,
38438
- bottomh = 0;
38439
- if (this.doc.needFullPitchRange()) {
38440
- toph = -this.getPitchY(this.maxPitch + 1);
38441
- bottomh = this.getPitchY(this.minPitch - 1);
38442
- } else {
38443
- toph = -this.getPitchY(this.getTopStaffLine().topLinePitch + 1);
38444
- bottomh = this.getPitchY(this.getBottomStaffLine().bottomLinePitch - 1);
38733
+ var rect = new DivRect();
38734
+ this.staves.forEach(staff => rect.expandInPlace(new DivRect(0, 0, staff.topLineY, staff.bottomLineY)));
38735
+ if (this.hasStaff && this.doc.needFullPitchRange()) {
38736
+ this.staves.forEach(staff => {
38737
+ var top = staff.getPitchY(staff.maxPitch) - staff.getLineSpacing();
38738
+ var bottom = staff.getPitchY(staff.minPitch) + staff.getLineSpacing();
38739
+ rect.expandInPlace(new DivRect(0, 0, top, bottom));
38740
+ });
38741
+ }
38742
+ if (this.tab) {
38743
+ var lowestPitch = this.getLowestNotePitch();
38744
+ var lowestY = lowestPitch !== undefined ? (_a = this.getStaff(lowestPitch)) === null || _a === void 0 ? void 0 : _a.getPitchY(lowestPitch) : undefined;
38745
+ this.tab.top = lowestY !== undefined ? lowestY + unitSize * 8 : 0;
38746
+ this.tab.bottom = this.tab.top + unitSize * DocumentSettings.GuitarTabHeight;
38747
+ rect.expandInPlace(new DivRect(0, 0, this.tab.top, this.tab.bottom));
38445
38748
  }
38749
+ // Calc min width
38446
38750
  this.minWidth = 0;
38751
+ // Layout measures
38447
38752
  this.measures.forEach(m => {
38448
- toph = Math.max(toph, m.getRect().toph);
38449
- bottomh = Math.max(bottomh, m.getRect().bottomh);
38753
+ m.layout(renderer);
38754
+ rect.expandInPlace(new DivRect(0, 0, m.getRect().top, m.getRect().bottom));
38450
38755
  this.minWidth += m.getMinWidth();
38451
38756
  this.minWidth += m.getPostMeasureBreakWidth();
38452
38757
  });
38453
- this.rect = new DivRect(0, 0, 0, -toph, 0, bottomh);
38758
+ this.rect = rect;
38454
38759
  }
38455
38760
  layoutWidth(renderer, width) {
38456
38761
  if (!this.needLayout) {
@@ -38562,6 +38867,10 @@ class ObjScoreRow extends MusicObject {
38562
38867
  offset(dx, dy) {
38563
38868
  this.measures.forEach(m => m.offset(dx, dy));
38564
38869
  this.rect.offsetInPlace(dx, dy);
38870
+ this.staves.forEach(s => s.offset(dx, dy));
38871
+ if (this.tab) {
38872
+ this.tab.offset(dx, dy);
38873
+ }
38565
38874
  }
38566
38875
  draw(renderer) {
38567
38876
  var ctx = renderer.getCanvasContext();
@@ -38574,10 +38883,18 @@ class ObjScoreRow extends MusicObject {
38574
38883
  ctx.rect(this.rect.left, this.rect.top, this.rect.width, this.rect.height);
38575
38884
  ctx.clip();
38576
38885
  // For multiple staff lines draw vertical start line (which is not drawn by measures)
38577
- if (this.getFirstMeasure() && this.staffLines.length > 1) {
38886
+ if (this.getFirstMeasure() && (this.staves.length > 1 || this.tab)) {
38578
38887
  var left = this.getFirstMeasure().getStaffLineLeft();
38579
- var top = this.getPitchY(this.getTopStaffLine().topLinePitch);
38580
- var bottom = this.getPitchY(this.getBottomStaffLine().bottomLinePitch);
38888
+ var top, bottom;
38889
+ if (this.hasStaff) {
38890
+ top = this.getTopStaff().topLineY;
38891
+ bottom = this.tab ? this.tab.getStringY(5) : this.getBottomStaff().bottomLineY;
38892
+ } else if (this.tab) {
38893
+ top = this.tab.getStringY(0);
38894
+ bottom = this.tab.getStringY(5);
38895
+ } else {
38896
+ top = bottom = 0;
38897
+ }
38581
38898
  renderer.drawLine(left, top, left, bottom);
38582
38899
  }
38583
38900
  // Draw measures
@@ -38591,6 +38908,7 @@ class ObjScoreRow extends MusicObject {
38591
38908
 
38592
38909
  class ObjHeader extends MusicObject {
38593
38910
  constructor(doc, title, composer, arranger) {
38911
+ var _a;
38594
38912
  super(doc);
38595
38913
  this.title = title;
38596
38914
  this.composer = composer;
@@ -38602,6 +38920,7 @@ class ObjHeader extends MusicObject {
38602
38920
  }, 0.5, 0) : undefined;
38603
38921
  this.composerText = this.composer ? new ObjText(this, this.composer, 1, 0) : undefined;
38604
38922
  this.arrangerText = this.arranger ? new ObjText(this, "Arr.: " + this.arranger, 1, 0) : undefined;
38923
+ 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;
38605
38924
  }
38606
38925
  getMusicInterface() {
38607
38926
  return this.mi;
@@ -38628,15 +38947,23 @@ class ObjHeader extends MusicObject {
38628
38947
  return [this, ..._arr2];
38629
38948
  }
38630
38949
  }
38950
+ if (this.tuningText) {
38951
+ var _arr3 = this.tuningText.pick(x, y);
38952
+ if (_arr3) {
38953
+ return [this, ..._arr3];
38954
+ }
38955
+ }
38631
38956
  return [this];
38632
38957
  }
38633
38958
  layoutWidth(renderer, width) {
38634
38959
  var top = 0;
38960
+ var tuningTop = 0;
38635
38961
  this.rect = new DivRect(0, width, 0, 0);
38636
38962
  if (this.titleText) {
38637
38963
  this.titleText.layout(renderer);
38638
38964
  this.titleText.offset(width / 2, top);
38639
38965
  top += this.titleText.getRect().height;
38966
+ tuningTop = top;
38640
38967
  this.rect.expandInPlace(this.titleText.getRect());
38641
38968
  }
38642
38969
  if (this.composerText) {
@@ -38651,6 +38978,11 @@ class ObjHeader extends MusicObject {
38651
38978
  top += this.arrangerText.getRect().height;
38652
38979
  this.rect.expandInPlace(this.arrangerText.getRect());
38653
38980
  }
38981
+ if (this.tuningText) {
38982
+ this.tuningText.layout(renderer);
38983
+ this.tuningText.offset(0, tuningTop);
38984
+ this.rect.expandInPlace(this.tuningText.getRect());
38985
+ }
38654
38986
  }
38655
38987
  offset(dx, dy) {
38656
38988
  if (this.titleText) {
@@ -38662,6 +38994,9 @@ class ObjHeader extends MusicObject {
38662
38994
  if (this.arrangerText) {
38663
38995
  this.arrangerText.offset(dx, dy);
38664
38996
  }
38997
+ if (this.tuningText) {
38998
+ this.tuningText.offset(dx, dy);
38999
+ }
38665
39000
  this.rect.offsetInPlace(dx, dy);
38666
39001
  }
38667
39002
  draw(renderer) {
@@ -38674,6 +39009,9 @@ class ObjHeader extends MusicObject {
38674
39009
  if (this.arrangerText) {
38675
39010
  this.arrangerText.draw(renderer);
38676
39011
  }
39012
+ if (this.tuningText) {
39013
+ this.tuningText.draw(renderer);
39014
+ }
38677
39015
  }
38678
39016
  }
38679
39017
  ;// ./src/music-score/engine/obj-document.ts
@@ -38685,24 +39023,37 @@ class ObjHeader extends MusicObject {
38685
39023
 
38686
39024
 
38687
39025
 
39026
+
38688
39027
  class ObjDocument extends MusicObject {
38689
- constructor(mi, staffKind, measuresPerRow) {
39028
+ constructor(mi, staffKind, options) {
39029
+ var _a;
38690
39030
  super(undefined);
38691
39031
  this.mi = mi;
38692
39032
  this.staffKind = staffKind;
38693
- this.measuresPerRow = measuresPerRow;
39033
+ this.options = options;
38694
39034
  this.needLayout = true;
38695
39035
  this.needUpdate = true;
38696
39036
  this.rows = [];
38697
39037
  this.measures = [];
38698
39038
  this.layoutGroups = [];
38699
39039
  this.newRowRequested = false;
39040
+ this.allArcsProps = [];
39041
+ this.measuresPerRow = options === null || options === void 0 ? void 0 : options.measuresPerRow;
39042
+ if (this.measuresPerRow !== undefined) {
39043
+ Assert.int_gte(this.measuresPerRow, 1, "Invalid measuresPerRow = " + this.measuresPerRow);
39044
+ }
39045
+ this.tuningName = validateTuningName((_a = options === null || options === void 0 ? void 0 : options.tuning) !== null && _a !== void 0 ? _a : DefaultTuningName);
39046
+ this.tuningStrings = getTuningStrings(this.tuningName);
39047
+ this.tuningLabel = this.tuningStrings.slice().reverse().map(n => n.formatOmitOctave(SymbolSet.Ascii)).join("-");
38700
39048
  // There is always row
38701
39049
  this.rows.push(new ObjScoreRow(this));
38702
39050
  }
38703
39051
  getMusicInterface() {
38704
39052
  return this.mi;
38705
39053
  }
39054
+ addArcProps(arc) {
39055
+ this.allArcsProps.push(arc);
39056
+ }
38706
39057
  getLayoutGroup(lauoutGroupId) {
38707
39058
  var layoutGroup = this.layoutGroups[lauoutGroupId];
38708
39059
  if (!layoutGroup) {
@@ -38791,7 +39142,8 @@ class ObjDocument extends MusicObject {
38791
39142
  // Update extensions.
38792
39143
  this.forEachMeasure(m => m.updateExtensions());
38793
39144
  // Update arcs.
38794
- this.forEachMeasure(m => m.updateArcs());
39145
+ this.allArcsProps.forEach(arc => arc.removeArcs());
39146
+ this.allArcsProps.forEach(arc => arc.createArcs());
38795
39147
  this.needUpdate = false;
38796
39148
  }
38797
39149
  forEachMeasure(func) {
@@ -38889,6 +39241,11 @@ class ObjDocument extends MusicObject {
38889
39241
  }
38890
39242
  for (var ri = 0; ri < this.rows.length; ri++) {
38891
39243
  var row = this.rows[ri];
39244
+ if (!row.hasStaff) {
39245
+ continue;
39246
+ }
39247
+ var minPitch = row.getBottomStaff().minPitch;
39248
+ var maxPitch = row.getTopStaff().maxPitch;
38892
39249
  if (!row.getRect().contains(x, y)) {
38893
39250
  continue;
38894
39251
  }
@@ -38897,7 +39254,7 @@ class ObjDocument extends MusicObject {
38897
39254
  var rect = measure.getMusicObject().getRect();
38898
39255
  if (x >= rect.left && x <= rect.right) {
38899
39256
  var pitch = row.getPitchAt(y);
38900
- if (pitch !== undefined && pitch >= row.minPitch && pitch <= row.maxPitch) {
39257
+ if (pitch !== undefined && pitch >= minPitch && pitch <= maxPitch) {
38901
39258
  return {
38902
39259
  measure,
38903
39260
  pitch
@@ -39003,11 +39360,15 @@ class MBeamGroup extends MusicInterface {
39003
39360
  MBeamGroup.Name = "BeamGroup";
39004
39361
  /** @public */
39005
39362
  class MDocument extends MusicInterface {
39006
- constructor(staffKind, measuresPerRow) {
39363
+ constructor(staffKind, options) {
39007
39364
  super(MDocument.Name);
39008
- this.obj = new ObjDocument(this, staffKind, measuresPerRow);
39009
- if (measuresPerRow !== undefined) {
39010
- Assert.int_gte(measuresPerRow, 1, "Cannot create music document because invalid measures per row value: " + measuresPerRow);
39365
+ if (typeof options === "number") {
39366
+ // Deprecated: second argument was measuresPerRow.
39367
+ this.obj = new ObjDocument(this, staffKind, {
39368
+ measuresPerRow: options
39369
+ });
39370
+ } else {
39371
+ this.obj = new ObjDocument(this, staffKind, options);
39011
39372
  }
39012
39373
  }
39013
39374
  /** @internal */
@@ -40106,26 +40467,11 @@ class GuitarComponent extends external_react_namespaceObject.Component {
40106
40467
  }, components);
40107
40468
  }
40108
40469
  }
40109
- ;// ./src/react-components/assets/tuning.json
40110
- 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"]}]}');
40111
40470
  ;// ./src/react-components/guitar-context.ts
40112
40471
 
40113
40472
 
40114
40473
 
40115
40474
 
40116
-
40117
- /** @public */
40118
- var TuningNameList = tuning_namespaceObject.p.map(data => data.name);
40119
- /** @public */
40120
- var DefaultTuningName = TuningNameList[0];
40121
- /** @public */
40122
- function validateTuningName(tuningName) {
40123
- if (TuningNameList.indexOf(tuningName) >= 0) {
40124
- return tuningName;
40125
- } else {
40126
- return Assert.interrupt("Invalid tuning name: " + tuningName);
40127
- }
40128
- }
40129
40475
  /** @public */
40130
40476
  var DefaultHandedness = "rh";
40131
40477
  /** @public */
@@ -40203,11 +40549,10 @@ class GuitarContext {
40203
40549
  this.guitarNoteLabel = guitarNoteLabel;
40204
40550
  // Nut = fret0, FretCount = maxFret + 1
40205
40551
  this.maxFretId = guitar_namespaceObject.kl;
40206
- var tuningData = Assert.require(tuning_namespaceObject.p.find(data => data.name === tuningName), "Invalid tuning name: " + tuningName);
40207
- this.stringTunings = tuningData.strings.slice().reverse().map(noteName => Note.getNote(noteName));
40552
+ this.tuningStrings = getTuningStrings(tuningName);
40208
40553
  this.guitarNoteTable = [[], [], [], [], [], []];
40209
40554
  for (var stringId = 0; stringId < 6; stringId++) {
40210
- var openStringNoteId = this.stringTunings[stringId].noteId;
40555
+ var openStringNoteId = this.tuningStrings[stringId].noteId;
40211
40556
  for (var fretId = 0; fretId <= this.maxFretId; fretId++) {
40212
40557
  var noteId = openStringNoteId + fretId;
40213
40558
  this.guitarNoteTable[stringId][fretId] = new GuitarNote(this, stringId, fretId, noteId);
@@ -40220,10 +40565,10 @@ class GuitarContext {
40220
40565
  return this.guitarNoteTable[stringId][fretId];
40221
40566
  }
40222
40567
  getStringTuning(stringId) {
40223
- return this.stringTunings[stringId];
40568
+ return this.tuningStrings[stringId];
40224
40569
  }
40225
40570
  getTuningOverview() {
40226
- return this.stringTunings.slice().reverse().map(note => note.format(this.pitchNotation, SymbolSet.Unicode)).join(" - ");
40571
+ return this.tuningStrings.slice().reverse().map(note => note.format(this.pitchNotation, SymbolSet.Unicode)).join(" - ");
40227
40572
  }
40228
40573
  alterTuningName(tuningName) {
40229
40574
  return tuningName === this.tuningName ? this : new GuitarContext(tuningName, this.scale, this.handedness, this.pitchNotation, this.guitarNoteLabel);
@@ -40397,7 +40742,7 @@ class PlaybackButtons extends external_react_namespaceObject.Component {
40397
40742
 
40398
40743
  /** @public */
40399
40744
  function createFrereJacques() {
40400
- var doc = new MDocument(StaffKind.TrebleForGuitar);
40745
+ var doc = new MDocument(StaffKind.GuitarTreble);
40401
40746
  doc.setHeader("Frere Jacques");
40402
40747
  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);
40403
40748
  doc.addMeasure().addNote(0, "G3", NoteLength.Quarter).addNote(0, "A3", NoteLength.Quarter).addNote(0, "B3", NoteLength.Quarter).addNote(0, "G3", NoteLength.Quarter);
@@ -40416,7 +40761,7 @@ function createFrereJacques() {
40416
40761
  // Greensleeves (https://musescore.com/aaron_dc/scores/6167495)
40417
40762
  /** @public */
40418
40763
  function createGreensleeves() {
40419
- var doc = new MDocument(StaffKind.TrebleForGuitar);
40764
+ var doc = new MDocument(StaffKind.GuitarTreble);
40420
40765
  doc.setHeader("Greensleeves");
40421
40766
  doc.addMeasure().setKeySignature("C", ScaleType.Major).setTimeSignature("6/8").setTempo(140).addNote(0, "A3", NoteLength.Eighth);
40422
40767
  doc.addMeasure().addNavigation(Navigation.StartRepeat).addNote(0, "C4", NoteLength.Quarter, {
@@ -40559,7 +40904,7 @@ function createGreensleeves() {
40559
40904
 
40560
40905
  /** @public */
40561
40906
  function createAndanteByDiabelli() {
40562
- var doc = new MDocument(StaffKind.TrebleForGuitar);
40907
+ var doc = new MDocument(StaffKind.GuitarTreble);
40563
40908
  doc.setHeader("Andante", "A. Diabelli");
40564
40909
  doc.addMeasure().setKeySignature("D", ScaleType.Major).setTimeSignature("3/4").setTempo(80).addRest(0, NoteLength.Eighth, {
40565
40910
  pitch: "G4"
@@ -40695,5 +41040,5 @@ function createAndanteByDiabelli() {
40695
41040
 
40696
41041
  /* harmony default export */ var index_full = (exports_full_namespaceObject);
40697
41042
  // Log lib loaded message.
40698
- console.log("%c" + "WebMusicScore v1.0.0 (esm)", "background: black; color: white; padding: 2px 4px;");
40699
- export { types_Annotation as 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, exports_namespaceObject as SamplePieces, Scale, ScaleFactory, ScaleType, StaffKind, Stem, SymbolSet, TieLength, TimeSignature, TuningNameList, alterTempoSpeed, index_full as default, getDefaultKeySignature, getDefaultScale, getDefaultTempo, getDefaultTimeSignature, getScale, getScaleFactory, getScaleFactoryList, getTempoString, validateGuitarNoteLabel, validateHandedness, validateIntervalQuality, validateNoteLength, validatePitchNotation, validateScaleType, validateTuningName };
41043
+ console.log("%c" + "WebMusicScore v1.1.0 (esm)", "background: black; color: white; padding: 2px 4px;");
41044
+ export { types_Annotation as 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, exports_namespaceObject as SamplePieces, Scale, ScaleFactory, ScaleType, StaffKind, Stem, SymbolSet, TieLength, TimeSignature, TuningNameList, alterTempoSpeed, index_full as default, getDefaultKeySignature, getDefaultScale, getDefaultTempo, getDefaultTimeSignature, getScale, getScaleFactory, getScaleFactoryList, getTempoString, getTuningStrings, validateGuitarNoteLabel, validateHandedness, validateIntervalQuality, validateNoteLength, validatePitchNotation, validateScaleType, validateTuningName };