@tspro/web-music-score 3.0.0 → 3.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,7 +1,7 @@
1
- /* WebMusicScore v3.0.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
1
+ /* WebMusicScore v3.1.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
2
2
  import {
3
3
  __publicField
4
- } from "../chunk-ZWFAOHYM.mjs";
4
+ } from "../chunk-B4J3KED2.mjs";
5
5
 
6
6
  // src/score/pub/div-rect.ts
7
7
  import { Utils } from "@tspro/ts-utils-lib";
@@ -330,6 +330,13 @@ var Connective = /* @__PURE__ */ ((Connective3) => {
330
330
  Connective3[Connective3["Slide"] = 2] = "Slide";
331
331
  return Connective3;
332
332
  })(Connective || {});
333
+ var VerticalPosition = /* @__PURE__ */ ((VerticalPosition4) => {
334
+ VerticalPosition4[VerticalPosition4["Above"] = 0] = "Above";
335
+ VerticalPosition4[VerticalPosition4["Below"] = 1] = "Below";
336
+ VerticalPosition4[VerticalPosition4["Both"] = 2] = "Both";
337
+ VerticalPosition4[VerticalPosition4["Auto"] = 3] = "Auto";
338
+ return VerticalPosition4;
339
+ })(VerticalPosition || {});
333
340
  var PlayState = /* @__PURE__ */ ((PlayState2) => {
334
341
  PlayState2[PlayState2["Playing"] = 0] = "Playing";
335
342
  PlayState2[PlayState2["Paused"] = 1] = "Paused";
@@ -444,7 +451,7 @@ var MusicObject = class {
444
451
  import { Note as Note9 } from "@tspro/web-music-score/theory";
445
452
 
446
453
  // src/score/engine/obj-staff-and-tab.ts
447
- import { getTuningStrings, Note, validateTuningName } from "@tspro/web-music-score/theory";
454
+ import { getTuningStrings, Note as Note8, validateTuningName } from "@tspro/web-music-score/theory";
448
455
 
449
456
  // src/score/engine/renderer.ts
450
457
  import { Utils as Utils2, Vec2, Device } from "@tspro/ts-utils-lib";
@@ -862,260 +869,16 @@ var Renderer = class {
862
869
  };
863
870
 
864
871
  // src/score/engine/obj-staff-and-tab.ts
865
- import { MusicError as MusicError3, MusicErrorType as MusicErrorType3 } from "@tspro/web-music-score/core";
866
- import { Utils as Utils3 } from "@tspro/ts-utils-lib";
867
- var ObjStaff = class extends MusicObject {
868
- constructor(row, staffConfig) {
869
- super(row);
870
- this.row = row;
871
- this.staffConfig = staffConfig;
872
- __publicField(this, "clefImageAsset");
873
- __publicField(this, "clefLineDiatonicId");
874
- __publicField(this, "topLineDiatonicId");
875
- __publicField(this, "middleLineDiatonicId");
876
- __publicField(this, "bottomLineDiatonicId");
877
- __publicField(this, "minDiatonicId");
878
- __publicField(this, "maxDiatonicId");
879
- __publicField(this, "joinedGrandStaff");
880
- __publicField(this, "topLineY", 0);
881
- __publicField(this, "bottomLineY", 0);
882
- __publicField(this, "objects", []);
883
- __publicField(this, "mi");
884
- const getDiatonicId = (noteName, isOctaveDown) => Note.getNote(noteName).diatonicId - (isOctaveDown ? 7 : 0);
885
- if (staffConfig.clef === "G" /* G */) {
886
- this.clefImageAsset = 0 /* TrebleClefPng */;
887
- this.clefLineDiatonicId = getDiatonicId("G4", staffConfig.isOctaveDown === true);
888
- this.middleLineDiatonicId = this.clefLineDiatonicId + 2;
889
- } else {
890
- this.clefImageAsset = 1 /* BassClefPng */;
891
- this.clefLineDiatonicId = getDiatonicId("F3", staffConfig.isOctaveDown === true);
892
- this.middleLineDiatonicId = this.clefLineDiatonicId - 2;
893
- }
894
- this.topLineDiatonicId = this.middleLineDiatonicId + 4;
895
- this.bottomLineDiatonicId = this.middleLineDiatonicId - 4;
896
- this.minDiatonicId = staffConfig.minNote !== void 0 ? Math.min(getDiatonicId(staffConfig.minNote, false), this.bottomLineDiatonicId) : void 0;
897
- this.maxDiatonicId = staffConfig.maxNote !== void 0 ? Math.max(getDiatonicId(staffConfig.maxNote, false), this.topLineDiatonicId) : void 0;
898
- this.mi = new MStaff(this);
899
- }
900
- getMusicInterface() {
901
- return this.mi;
902
- }
903
- get isOctaveDown() {
904
- return this.staffConfig.isOctaveDown === true;
905
- }
906
- getTopLineY() {
907
- return this.topLineY;
908
- }
909
- getMiddleLineY() {
910
- return (this.topLineY + this.bottomLineY) / 2;
911
- }
912
- getBottomLineY() {
913
- return this.bottomLineY;
914
- }
915
- joinGrandStaff(staff) {
916
- if (staff !== this) {
917
- this.joinedGrandStaff = staff;
918
- }
919
- }
920
- getLineSpacing() {
921
- return (this.bottomLineY - this.topLineY) / 4;
922
- }
923
- getDiatonicSpacing() {
924
- return this.getLineSpacing() / 2;
925
- }
926
- containsDiatonicId(diatonicId) {
927
- Note.validateDiatonicId(diatonicId);
928
- return (this.minDiatonicId === void 0 || diatonicId >= this.minDiatonicId) && (this.maxDiatonicId === void 0 || diatonicId <= this.maxDiatonicId);
929
- }
930
- getDiatonicIdY(diatonicId) {
931
- if (this.containsDiatonicId(diatonicId)) {
932
- return this.bottomLineY + (this.bottomLineDiatonicId - diatonicId) * this.getDiatonicSpacing();
933
- } else if (this.joinedGrandStaff && this.joinedGrandStaff.containsDiatonicId(diatonicId)) {
934
- return this.joinedGrandStaff.getDiatonicIdY(diatonicId);
935
- } else {
936
- throw new MusicError3(MusicErrorType3.Score, "Staff does not contain diatonicId " + diatonicId);
937
- }
938
- }
939
- getActualStaff(diatonicId) {
940
- if (this.containsDiatonicId(diatonicId)) {
941
- return this;
942
- } else if (this.joinedGrandStaff && this.joinedGrandStaff.containsDiatonicId(diatonicId)) {
943
- return this.joinedGrandStaff;
944
- } else {
945
- throw new MusicError3(MusicErrorType3.Score, "Staff does not contain diatonicId " + diatonicId);
946
- }
947
- }
948
- getDiatonicIdAt(y) {
949
- let diatonicId = Math.round(this.bottomLineDiatonicId - (y - this.bottomLineY) / this.getDiatonicSpacing());
950
- return this.containsDiatonicId(diatonicId) ? diatonicId : void 0;
951
- }
952
- isLine(diatonicId) {
953
- return diatonicId % 2 === this.middleLineDiatonicId % 2;
954
- }
955
- isSpace(diatonicId) {
956
- return diatonicId % 2 !== this.middleLineDiatonicId % 2;
957
- }
958
- containsVoiceId(voiceId) {
959
- return !this.staffConfig.voiceIds || this.staffConfig.voiceIds.includes(voiceId);
960
- }
961
- isGrand() {
962
- return this.staffConfig.isGrand === true;
963
- }
964
- calcTop() {
965
- let top = this.topLineY;
966
- this.objects.forEach((o) => top = Math.min(top, o.getRect().top));
967
- if (this.maxDiatonicId !== void 0) {
968
- let y = this.getDiatonicIdY(this.maxDiatonicId);
969
- let y2 = this.getDiatonicIdY(this.maxDiatonicId - 1);
970
- top = Math.min(top, y - Math.abs(y2 - y) + 1);
971
- }
972
- return top;
973
- }
974
- calcBottom() {
975
- let bottom = this.bottomLineY;
976
- this.objects.forEach((o) => bottom = Math.max(bottom, o.getRect().bottom));
977
- if (this.minDiatonicId !== void 0) {
978
- let y = this.getDiatonicIdY(this.minDiatonicId);
979
- let y2 = this.getDiatonicIdY(this.minDiatonicId + 1);
980
- bottom = Math.max(bottom, y + Math.abs(y2 - y) - 1);
981
- }
982
- return bottom;
983
- }
984
- addObject(o) {
985
- this.objects.push(o);
986
- }
987
- removeObjects() {
988
- this.objects.length = 0;
989
- }
990
- pick(x, y) {
991
- return [this];
992
- }
993
- layoutHeight(renderer) {
994
- let { unitSize } = renderer;
995
- let h = unitSize * DocumentSettings.StaffHeight;
996
- this.topLineY = -h / 2;
997
- this.bottomLineY = h / 2;
998
- this.rect = new DivRect(0, 0, this.topLineY, this.bottomLineY);
999
- }
1000
- layoutWidth(renderer) {
1001
- this.rect.left = this.row.getRect().left;
1002
- this.rect.right = this.row.getRect().right;
1003
- }
1004
- offset(dx, dy) {
1005
- this.topLineY += dy;
1006
- this.bottomLineY += dy;
1007
- this.objects.forEach((o) => {
1008
- if (o.offsetInPlace) {
1009
- o.offsetInPlace(0, dy);
1010
- } else if (o.offset) {
1011
- o.offset(0, dy);
1012
- }
1013
- });
1014
- this.rect.offsetInPlace(dx, dy);
1015
- }
1016
- draw(renderer) {
1017
- }
1018
- };
1019
- var ObjTab = class extends MusicObject {
1020
- constructor(row, tabConfig) {
1021
- super(row);
1022
- this.row = row;
1023
- this.tabConfig = tabConfig;
1024
- __publicField(this, "top", 0);
1025
- __publicField(this, "bottom", 0);
1026
- __publicField(this, "objects", []);
1027
- __publicField(this, "tuningName");
1028
- __publicField(this, "tuningStrings");
1029
- __publicField(this, "mi");
1030
- if (Utils3.Is.isArray(tabConfig.tuning)) {
1031
- this.tuningName = void 0;
1032
- this.tuningStrings = tabConfig.tuning.map((noteName) => Note.getNote(noteName)).reverse();
1033
- } else if (typeof tabConfig.tuning === "string") {
1034
- this.tuningName = validateTuningName(tabConfig.tuning);
1035
- this.tuningStrings = getTuningStrings(this.tuningName);
1036
- } else {
1037
- this.tuningName = "Standard";
1038
- this.tuningStrings = getTuningStrings(this.tuningName);
1039
- }
1040
- this.mi = new MTab(this);
1041
- }
1042
- getMusicInterface() {
1043
- return this.mi;
1044
- }
1045
- getTuningName() {
1046
- return this.tuningName;
1047
- }
1048
- getTuningStrings() {
1049
- return this.tuningStrings;
1050
- }
1051
- /** Return Y coordinate of string. */
1052
- getStringY(stringId) {
1053
- return this.top + (this.bottom - this.top) / 6 * (stringId + 0.5);
1054
- }
1055
- getTopStringY() {
1056
- return this.getStringY(0);
1057
- }
1058
- getBottomStringY() {
1059
- return this.getStringY(5);
1060
- }
1061
- getTop() {
1062
- return this.top;
1063
- }
1064
- getBottom() {
1065
- return this.bottom;
1066
- }
1067
- containsVoiceId(voiceId) {
1068
- return !this.tabConfig.voiceIds || this.tabConfig.voiceIds.includes(voiceId);
1069
- }
1070
- calcTop() {
1071
- return this.top;
1072
- }
1073
- calcBottom() {
1074
- return this.bottom;
1075
- }
1076
- addObject(o) {
1077
- this.objects.push(o);
1078
- }
1079
- removeObjects() {
1080
- this.objects.length = 0;
1081
- }
1082
- pick(x, y) {
1083
- return [this];
1084
- }
1085
- layoutHeight(renderer) {
1086
- let { unitSize } = renderer;
1087
- let h = unitSize * DocumentSettings.TabHeight;
1088
- this.top = -h / 2;
1089
- this.bottom = h / 2;
1090
- this.rect = new DivRect(0, 0, this.top, this.bottom);
1091
- }
1092
- layoutWidth(renderer) {
1093
- this.rect.left = this.row.getRect().left;
1094
- this.rect.right = this.row.getRect().right;
1095
- }
1096
- offset(dx, dy) {
1097
- this.top += dy;
1098
- this.bottom += dy;
1099
- this.objects.forEach((o) => {
1100
- if (o.offsetInPlace) {
1101
- o.offsetInPlace(0, dy);
1102
- } else if (o.offset) {
1103
- o.offset(0, dy);
1104
- }
1105
- });
1106
- this.rect.offsetInPlace(dx, dy);
1107
- }
1108
- draw(renderer) {
1109
- }
1110
- };
872
+ import { MusicError as MusicError15, MusicErrorType as MusicErrorType15 } from "@tspro/web-music-score/core";
873
+ import { Utils as Utils9 } from "@tspro/ts-utils-lib";
1111
874
 
1112
875
  // src/score/engine/obj-measure.ts
1113
- import { Utils as Utils9 } from "@tspro/ts-utils-lib";
1114
- import { getScale, Scale, validateScaleType, Note as Note8, NoteLength as NoteLength6, RhythmProps as RhythmProps4, KeySignature as KeySignature2, getDefaultKeySignature, PitchNotation, SymbolSet } from "@tspro/web-music-score/theory";
876
+ import { Utils as Utils8 } from "@tspro/ts-utils-lib";
877
+ import { getScale, Scale, validateScaleType, Note as Note7, NoteLength as NoteLength6, RhythmProps as RhythmProps4, KeySignature as KeySignature2, getDefaultKeySignature, PitchNotation, SymbolSet } from "@tspro/web-music-score/theory";
1115
878
  import { getDefaultTempo, TimeSignature, getDefaultTimeSignature } from "@tspro/web-music-score/theory";
1116
879
 
1117
880
  // src/score/engine/acc-state.ts
1118
- import { Note as Note2 } from "@tspro/web-music-score/theory";
881
+ import { Note } from "@tspro/web-music-score/theory";
1119
882
  var AccidentalState = class {
1120
883
  constructor(measure) {
1121
884
  this.measure = measure;
@@ -1123,7 +886,7 @@ var AccidentalState = class {
1123
886
  }
1124
887
  getAccidentalFromKeySignature(diatonicId) {
1125
888
  let ks = this.measure.getKeySignature();
1126
- let accNote = ks.getOrderedAccidentalNotes().find((accNote2) => accNote2.diatonicClass === Note2.getDiatonicClass(diatonicId));
889
+ let accNote = ks.getOrderedAccidentalNotes().find((accNote2) => accNote2.diatonicClass === Note.getDiatonicClass(diatonicId));
1127
890
  return accNote ? accNote.accidental : void 0;
1128
891
  }
1129
892
  setAccidental(note) {
@@ -1137,7 +900,7 @@ var AccidentalState = class {
1137
900
  };
1138
901
 
1139
902
  // src/score/engine/obj-signature.ts
1140
- import { Note as Note3, getTempoString, KeySignature } from "@tspro/web-music-score/theory";
903
+ import { Note as Note2, getTempoString, KeySignature } from "@tspro/web-music-score/theory";
1141
904
 
1142
905
  // src/score/engine/obj-image.ts
1143
906
  var ObjImage = class extends MusicObject {
@@ -1185,7 +948,7 @@ var ObjImage = class extends MusicObject {
1185
948
  };
1186
949
 
1187
950
  // src/score/engine/obj-accidental.ts
1188
- import { MusicError as MusicError4, MusicErrorType as MusicErrorType4 } from "@tspro/web-music-score/core";
951
+ import { MusicError as MusicError3, MusicErrorType as MusicErrorType3 } from "@tspro/web-music-score/core";
1189
952
  var ObjAccidental = class extends MusicObject {
1190
953
  constructor(parent, diatonicId, accidental, color = "black") {
1191
954
  super(parent);
@@ -1220,7 +983,7 @@ var ObjAccidental = class extends MusicObject {
1220
983
  this.rect = DivRect.createSections(unitSize * 1, unitSize * 1, unitSize * 1, unitSize * 1);
1221
984
  break;
1222
985
  default:
1223
- throw new MusicError4(MusicErrorType4.Score, "Invalid accidental value: " + this.accidental);
986
+ throw new MusicError3(MusicErrorType3.Score, "Invalid accidental value: " + this.accidental);
1224
987
  }
1225
988
  }
1226
989
  offset(dx, dy) {
@@ -1433,7 +1196,7 @@ var ObjText = class extends MusicObject {
1433
1196
  };
1434
1197
 
1435
1198
  // src/score/engine/obj-signature.ts
1436
- import { MusicError as MusicError5, MusicErrorType as MusicErrorType5 } from "@tspro/web-music-score/core";
1199
+ import { MusicError as MusicError4, MusicErrorType as MusicErrorType4 } from "@tspro/web-music-score/core";
1437
1200
  var ObjSignature = class extends MusicObject {
1438
1201
  constructor(measure, staff) {
1439
1202
  super(measure);
@@ -1527,9 +1290,9 @@ var ObjSignature = class extends MusicObject {
1527
1290
  }
1528
1291
  }
1529
1292
  if (bottomAccidentalDiatonicId !== void 0) {
1530
- return Note3.findNextDiatonicIdAbove(accNote.diatonicId, bottomAccidentalDiatonicId, false);
1293
+ return Note2.findNextDiatonicIdAbove(accNote.diatonicId, bottomAccidentalDiatonicId, false);
1531
1294
  } else {
1532
- throw new MusicError5(MusicErrorType5.Score, "Cannot get accidental diatonicId because note has no accidental.");
1295
+ throw new MusicError4(MusicErrorType4.Score, "Cannot get accidental diatonicId because note has no accidental.");
1533
1296
  }
1534
1297
  }
1535
1298
  pick(x, y) {
@@ -1699,22 +1462,24 @@ var ObjSignature = class extends MusicObject {
1699
1462
  };
1700
1463
 
1701
1464
  // src/score/engine/player.ts
1702
- import { Utils as Utils6 } from "@tspro/ts-utils-lib";
1465
+ import { Utils as Utils5 } from "@tspro/ts-utils-lib";
1703
1466
  import { NoteLength as NoteLength5, RhythmProps as RhythmProps3, alterTempoSpeed } from "@tspro/web-music-score/theory";
1704
1467
  import * as Audio from "@tspro/web-music-score/audio";
1705
1468
 
1706
1469
  // src/score/engine/obj-rhythm-column.ts
1707
- import { Note as Note6, NoteLength as NoteLength4 } from "@tspro/web-music-score/theory";
1470
+ import { Note as Note5, NoteLength as NoteLength4 } from "@tspro/web-music-score/theory";
1708
1471
 
1709
1472
  // src/score/engine/obj-arpeggio.ts
1710
- var _ObjArpeggio = class _ObjArpeggio extends MusicObject {
1711
- constructor(col, arpeggioDir) {
1473
+ var ObjArpeggio = class extends MusicObject {
1474
+ constructor(col, line, arpeggioDir) {
1712
1475
  super(col);
1713
1476
  this.col = col;
1477
+ this.line = line;
1714
1478
  this.arpeggioDir = arpeggioDir;
1715
1479
  __publicField(this, "topArrowHeight", 0);
1716
1480
  __publicField(this, "bottomArrowHeight", 0);
1717
1481
  __publicField(this, "cycleHeight", 0);
1482
+ __publicField(this, "numCycles", 0);
1718
1483
  __publicField(this, "color", "black");
1719
1484
  __publicField(this, "mi");
1720
1485
  this.mi = new MArpeggio(this);
@@ -1729,10 +1494,13 @@ var _ObjArpeggio = class _ObjArpeggio extends MusicObject {
1729
1494
  let { unitSize } = renderer;
1730
1495
  this.topArrowHeight = this.arpeggioDir === 0 /* Up */ ? unitSize : 0;
1731
1496
  this.bottomArrowHeight = this.arpeggioDir === 1 /* Down */ ? unitSize : 0;
1497
+ let top = this.line.getTopLineY();
1498
+ let bottom = this.line.getBottomLineY();
1732
1499
  this.cycleHeight = unitSize * 2;
1500
+ this.numCycles = Math.ceil((bottom - top) / this.cycleHeight) + 2;
1733
1501
  let width = unitSize * 2;
1734
- let height = _ObjArpeggio.NumCycles * this.cycleHeight + this.topArrowHeight + this.bottomArrowHeight;
1735
- this.rect = new DivRect(-width / 2, width / 2, -height / 2, height / 2);
1502
+ let height = this.numCycles * this.cycleHeight;
1503
+ this.rect = new DivRect(-width / 2, width / 2, -height / 2 - this.topArrowHeight, height / 2 + this.bottomArrowHeight);
1736
1504
  }
1737
1505
  offset(dx, dy) {
1738
1506
  this.rect.offsetInPlace(dx, dy);
@@ -1742,14 +1510,13 @@ var _ObjArpeggio = class _ObjArpeggio extends MusicObject {
1742
1510
  if (!ctx) {
1743
1511
  return;
1744
1512
  }
1745
- let { lineWidth, unitSize } = renderer;
1513
+ let { lineWidth } = renderer;
1746
1514
  let { rect, topArrowHeight, bottomArrowHeight } = this;
1747
1515
  renderer.drawDebugRect(this.rect);
1748
1516
  ctx.strokeStyle = ctx.fillStyle = this.color;
1749
1517
  ctx.lineWidth = lineWidth * 2;
1750
1518
  ctx.beginPath();
1751
- for (let i = 0; i < _ObjArpeggio.NumCycles; i++) {
1752
- let y = rect.top + topArrowHeight + i * this.cycleHeight;
1519
+ for (let i = 0, y = rect.top + topArrowHeight; i < this.numCycles; i++, y += this.cycleHeight) {
1753
1520
  ctx.moveTo(rect.centerX, y);
1754
1521
  ctx.quadraticCurveTo(rect.left, y + this.cycleHeight / 4, rect.centerX, y + this.cycleHeight / 2);
1755
1522
  ctx.quadraticCurveTo(rect.right, y + this.cycleHeight * 3 / 4, rect.centerX, y + this.cycleHeight);
@@ -1758,31 +1525,29 @@ var _ObjArpeggio = class _ObjArpeggio extends MusicObject {
1758
1525
  if (topArrowHeight > 0) {
1759
1526
  ctx.beginPath();
1760
1527
  ctx.moveTo(rect.centerX, rect.top);
1761
- ctx.lineTo(rect.right, rect.top + unitSize);
1762
- ctx.lineTo(rect.left, rect.top + unitSize);
1528
+ ctx.lineTo(rect.right, rect.top + topArrowHeight);
1529
+ ctx.lineTo(rect.left, rect.top + topArrowHeight);
1763
1530
  ctx.fill();
1764
1531
  }
1765
1532
  if (bottomArrowHeight > 0) {
1766
1533
  ctx.beginPath();
1767
1534
  ctx.moveTo(rect.centerX, rect.bottom);
1768
- ctx.lineTo(rect.left, rect.bottom - unitSize);
1769
- ctx.lineTo(rect.right, rect.bottom - unitSize);
1535
+ ctx.lineTo(rect.left, rect.bottom - bottomArrowHeight);
1536
+ ctx.lineTo(rect.right, rect.bottom - bottomArrowHeight);
1770
1537
  ctx.fill();
1771
1538
  }
1772
1539
  }
1773
1540
  };
1774
- __publicField(_ObjArpeggio, "NumCycles", 5);
1775
- var ObjArpeggio = _ObjArpeggio;
1776
1541
 
1777
1542
  // src/score/engine/obj-rest.ts
1778
- import { Note as Note4, NoteLength, RhythmProps } from "@tspro/web-music-score/theory";
1779
- import { MusicError as MusicError6, MusicErrorType as MusicErrorType6 } from "@tspro/web-music-score/core";
1543
+ import { Note as Note3, NoteLength, RhythmProps } from "@tspro/web-music-score/theory";
1544
+ import { MusicError as MusicError5, MusicErrorType as MusicErrorType5 } from "@tspro/web-music-score/core";
1780
1545
  function getDiatonicIdFromStaffPos(staffPos) {
1781
1546
  if (typeof staffPos === "number") {
1782
- return Note4.getChromaticNote(staffPos).diatonicId;
1547
+ return Note3.getChromaticNote(staffPos).diatonicId;
1783
1548
  } else if (typeof staffPos === "string") {
1784
- return Note4.getNote(staffPos).diatonicId;
1785
- } else if (staffPos instanceof Note4) {
1549
+ return Note3.getNote(staffPos).diatonicId;
1550
+ } else if (staffPos instanceof Note3) {
1786
1551
  return staffPos.diatonicId;
1787
1552
  } else {
1788
1553
  return void 0;
@@ -1838,7 +1603,7 @@ var ObjRest = class extends MusicObject {
1838
1603
  let hasStaff = this.row.hasStaff;
1839
1604
  let staff2 = this.row.getStaff(diatonicId);
1840
1605
  if (hasStaff && !staff2) {
1841
- throw new MusicError6(MusicErrorType6.Score, "Rest staffPos is out of staff boundaries!");
1606
+ throw new MusicError5(MusicErrorType5.Score, "Rest staffPos is out of staff boundaries!");
1842
1607
  }
1843
1608
  }
1844
1609
  this.ownDiatonicId = this.measure.updateOwnDiatonicId(voiceId, diatonicId);
@@ -1879,6 +1644,15 @@ var ObjRest = class extends MusicObject {
1879
1644
  get triplet() {
1880
1645
  return this.rhythmProps.triplet;
1881
1646
  }
1647
+ getStaticObjects(line) {
1648
+ let staticObjects = [];
1649
+ this.staffObjects.forEach((obj) => {
1650
+ if (obj.staff === line) {
1651
+ staticObjects.push(obj);
1652
+ }
1653
+ });
1654
+ return staticObjects;
1655
+ }
1882
1656
  pick(x, y) {
1883
1657
  if (!this.getRect().contains(x, y)) {
1884
1658
  return [];
@@ -1932,7 +1706,7 @@ var ObjRest = class extends MusicObject {
1932
1706
  case NoteLength.SixtyFourth:
1933
1707
  return -3;
1934
1708
  default:
1935
- throw new MusicError6(MusicErrorType6.Score, "Cannot get rest dot vertical displacement because note length is invalid.");
1709
+ throw new MusicError5(MusicErrorType5.Score, "Cannot get rest dot vertical displacement because note length is invalid.");
1936
1710
  }
1937
1711
  }
1938
1712
  updateAccidentalState(accState) {
@@ -2089,13 +1863,13 @@ var ObjRest = class extends MusicObject {
2089
1863
  };
2090
1864
 
2091
1865
  // src/score/engine/obj-note-group.ts
2092
- import { Utils as Utils5 } from "@tspro/ts-utils-lib";
2093
- import { Note as Note5, NoteLength as NoteLength3, RhythmProps as RhythmProps2 } from "@tspro/web-music-score/theory";
1866
+ import { Utils as Utils4 } from "@tspro/ts-utils-lib";
1867
+ import { Note as Note4, NoteLength as NoteLength3, RhythmProps as RhythmProps2 } from "@tspro/web-music-score/theory";
2094
1868
 
2095
1869
  // src/score/engine/obj-beam-group.ts
2096
- import { Utils as Utils4 } from "@tspro/ts-utils-lib";
1870
+ import { Utils as Utils3 } from "@tspro/ts-utils-lib";
2097
1871
  import { MinNoteLength, NoteLength as NoteLength2 } from "@tspro/web-music-score/theory";
2098
- import { MusicError as MusicError7, MusicErrorType as MusicErrorType7 } from "@tspro/web-music-score/core";
1872
+ import { MusicError as MusicError6, MusicErrorType as MusicErrorType6 } from "@tspro/web-music-score/core";
2099
1873
  var adjustBeamAngle = (dx, dy) => {
2100
1874
  let T = DocumentSettings.BeamAngleFactor;
2101
1875
  if (!Number.isFinite(T) || T === 0) {
@@ -2172,13 +1946,13 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2172
1946
  __publicField(this, "staffObjects", []);
2173
1947
  this.mi = new MBeamGroup(this);
2174
1948
  if (!symbols.every((s) => s.measure === symbols[0].measure)) {
2175
- throw new MusicError7(MusicErrorType7.Score, "All beam group symbols are not in same measure.");
1949
+ throw new MusicError6(MusicErrorType6.Score, "All beam group symbols are not in same measure.");
2176
1950
  } else if (symbols.length < 2) {
2177
- throw new MusicError7(MusicErrorType7.Score, "Beam group need minimum 2 symbols, but " + symbols.length + " given.");
1951
+ throw new MusicError6(MusicErrorType6.Score, "Beam group need minimum 2 symbols, but " + symbols.length + " given.");
2178
1952
  }
2179
1953
  if (triplet) {
2180
1954
  if (!symbols.every((s) => s.triplet)) {
2181
- throw new MusicError7(MusicErrorType7.Score, "Not every symbol's triplet property is true.");
1955
+ throw new MusicError6(MusicErrorType6.Score, "Not every symbol's triplet property is true.");
2182
1956
  }
2183
1957
  let isGroup = symbols.length < 3 || symbols.some((s) => !(s instanceof ObjNoteGroup)) || symbols.some((s) => s.rhythmProps.flagCount !== symbols[0].rhythmProps.flagCount);
2184
1958
  if (symbols.length === 3 && symbols[0] instanceof ObjNoteGroup && symbols[symbols.length - 1] instanceof ObjNoteGroup && symbols[0].rhythmProps.flagCount === symbols[symbols.length - 1].rhythmProps.flagCount) {
@@ -2196,7 +1970,7 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2196
1970
  symbols.forEach((s) => s.setBeamGroup(this));
2197
1971
  symbols[0].measure.addBeamGroup(this);
2198
1972
  } else {
2199
- throw new MusicError7(MusicErrorType7.Score, "Cannot add beam group because some symbol already has one.");
1973
+ throw new MusicError6(MusicErrorType6.Score, "Cannot add beam group because some symbol already has one.");
2200
1974
  }
2201
1975
  }
2202
1976
  static createBeam(noteGroups) {
@@ -2335,7 +2109,7 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2335
2109
  symbolY.forEach((symY, i) => {
2336
2110
  let symX = symbolX[i];
2337
2111
  if (symX !== void 0 && symY !== void 0) {
2338
- let beamY = Utils4.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
2112
+ let beamY = Utils3.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
2339
2113
  let raiseY = symY - beamY;
2340
2114
  if (stemDir === 1 /* Up */ && raiseY < 0) {
2341
2115
  raiseBeamY = Math.min(raiseBeamY, raiseY);
@@ -2350,8 +2124,8 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2350
2124
  let obj = new ObjStaffBeamGroup(mainStaff, this);
2351
2125
  if (this.type === 2 /* TripletGroup */) {
2352
2126
  let ef = unitSize / (rightX - leftX);
2353
- let l = Utils4.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, -ef);
2354
- let r = Utils4.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, 1 + ef);
2127
+ let l = Utils3.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, -ef);
2128
+ let r = Utils3.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, 1 + ef);
2355
2129
  obj.points.push(new BeamPoint(leftStaff, this, leftSymbol, l.x, l.y));
2356
2130
  obj.points.push(new BeamPoint(rightStaff, this, rightSymbol, r.x, r.y));
2357
2131
  obj.tripletNumberOffsetY = 0;
@@ -2409,7 +2183,7 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2409
2183
  obj.points.forEach((pt) => {
2410
2184
  if (pt.symbol instanceof ObjNoteGroup) {
2411
2185
  if (pt !== left && pt !== right) {
2412
- pt.y = Utils4.Math.interpolateY(left.x, left.y, right.x, right.y, pt.x);
2186
+ pt.y = Utils3.Math.interpolateY(left.x, left.y, right.x, right.y, pt.x);
2413
2187
  }
2414
2188
  pt.symbol.setStemTipY(pt.staff, pt.y);
2415
2189
  }
@@ -2434,8 +2208,8 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2434
2208
  let r = obj.points[obj.points.length - 1];
2435
2209
  if (l && r) {
2436
2210
  let tf = obj.tripletNumber ? obj.tripletNumber.getRect().width / (r.x - l.x) * 1.2 : 0;
2437
- let lc = Utils4.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 - tf / 2);
2438
- let rc = Utils4.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 + tf / 2);
2211
+ let lc = Utils3.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 - tf / 2);
2212
+ let rc = Utils3.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 + tf / 2);
2439
2213
  let tipH = this.stemDir === 1 /* Up */ ? unitSize : -unitSize;
2440
2214
  renderer.drawLine(l.x, l.y, lc.x, lc.y, color, lineWidth);
2441
2215
  renderer.drawLine(rc.x, rc.y, r.x, r.y, color, lineWidth);
@@ -2478,13 +2252,13 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2478
2252
  };
2479
2253
 
2480
2254
  // src/score/engine/obj-note-group.ts
2481
- import { MusicError as MusicError8, MusicErrorType as MusicErrorType8 } from "@tspro/web-music-score/core";
2255
+ import { MusicError as MusicError7, MusicErrorType as MusicErrorType7 } from "@tspro/web-music-score/core";
2482
2256
  function sortNoteStringData(notes, strings) {
2483
- let stringArr = Utils5.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2257
+ let stringArr = Utils4.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2484
2258
  let noteStringData = notes.map((note, i) => {
2485
2259
  return { note, string: stringArr[i] };
2486
2260
  });
2487
- noteStringData = Utils5.Arr.removeDuplicatesCmp(noteStringData, (a, b) => Note5.equals(a.note, b.note)).sort((a, b) => Note5.compareFunc(a.note, b.note));
2261
+ noteStringData = Utils4.Arr.removeDuplicatesCmp(noteStringData, (a, b) => Note4.equals(a.note, b.note)).sort((a, b) => Note4.compareFunc(a.note, b.note));
2488
2262
  return {
2489
2263
  notes: noteStringData.map((e) => e.note),
2490
2264
  strings: noteStringData.every((e) => e.string === void 0) ? void 0 : noteStringData.map((e) => e.string)
@@ -2598,8 +2372,8 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2598
2372
  __publicField(this, "staffObjects", []);
2599
2373
  __publicField(this, "tabObjects", []);
2600
2374
  __publicField(this, "mi");
2601
- if (!Utils5.Is.isIntegerGte(notes.length, 1)) {
2602
- throw new MusicError8(MusicErrorType8.Score, "Cannot create note group object because notes array is empty.");
2375
+ if (!Utils4.Is.isIntegerGte(notes.length, 1)) {
2376
+ throw new MusicError7(MusicErrorType7.Score, "Cannot create note group object because notes array is empty.");
2603
2377
  }
2604
2378
  let noteStringData = sortNoteStringData(notes, options == null ? void 0 : options.string);
2605
2379
  this.notes = noteStringData.notes;
@@ -2638,13 +2412,27 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2638
2412
  }
2639
2413
  startConnective(connectiveProps) {
2640
2414
  if (!this.row.hasStaff && connectiveProps.connective === 0 /* Tie */) {
2641
- throw new MusicError8(MusicErrorType8.Score, "Ties not implemented for guitar tabs alone, staff is required!");
2415
+ throw new MusicError7(MusicErrorType7.Score, "Ties not implemented for guitar tabs alone, staff is required!");
2642
2416
  } else if (!this.row.hasStaff && connectiveProps.connective === 1 /* Slur */) {
2643
- throw new MusicError8(MusicErrorType8.Score, "Slurs not implemented for guitar tabs alone, staff is required!");
2417
+ throw new MusicError7(MusicErrorType7.Score, "Slurs not implemented for guitar tabs alone, staff is required!");
2644
2418
  }
2645
2419
  this.startConnnectives.push(connectiveProps);
2646
2420
  this.doc.addConnectiveProps(connectiveProps);
2647
2421
  }
2422
+ getStaticObjects(line) {
2423
+ let staticObjects = [];
2424
+ this.staffObjects.forEach((obj) => {
2425
+ if (obj.staff === line) {
2426
+ staticObjects.push(obj);
2427
+ }
2428
+ });
2429
+ this.tabObjects.forEach((obj) => {
2430
+ if (obj.tab === line) {
2431
+ staticObjects.push(obj);
2432
+ }
2433
+ });
2434
+ return staticObjects;
2435
+ }
2648
2436
  pick(x, y) {
2649
2437
  if (!this.getRect().contains(x, y)) {
2650
2438
  return [];
@@ -2673,7 +2461,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2673
2461
  if (line instanceof ObjStaff) {
2674
2462
  let staff = line;
2675
2463
  if (noteIndex < 0 || noteIndex >= this.notes.length) {
2676
- throw new MusicError8(MusicErrorType8.Score, "Invalid noteIndex: " + noteIndex);
2464
+ throw new MusicError7(MusicErrorType7.Score, "Invalid noteIndex: " + noteIndex);
2677
2465
  }
2678
2466
  let obj = this.staffObjects.find((obj2) => obj2.staff === staff);
2679
2467
  if (!obj || noteIndex < 0 || noteIndex >= obj.noteHeadRects.length) {
@@ -2721,7 +2509,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2721
2509
  case 4 /* StemTip */:
2722
2510
  return { x: centerX, y: stemTip.centerY + (stemDir === 1 /* Up */ ? -padding : padding) };
2723
2511
  default:
2724
- throw new MusicError8(MusicErrorType8.Score, "Invalid noteAnchor: " + noteAnchor);
2512
+ throw new MusicError7(MusicErrorType7.Score, "Invalid noteAnchor: " + noteAnchor);
2725
2513
  }
2726
2514
  } else {
2727
2515
  let tab = line;
@@ -2853,15 +2641,15 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2853
2641
  return Math.max(this.rhythmProps.ticks, this.measure.getMeasureTicks() - this.col.positionTicks);
2854
2642
  }
2855
2643
  let prev = tieNoteGroups[j - 1];
2856
- if (prev && prev.notes.some((n) => Note5.equals(n, note))) {
2644
+ if (prev && prev.notes.some((n) => Note4.equals(n, note))) {
2857
2645
  return 0;
2858
2646
  }
2859
2647
  tieNoteGroups = tieNoteGroups.slice(j);
2860
- j = tieNoteGroups.findIndex((ng) => ng.notes.every((n) => !Note5.equals(n, note)));
2648
+ j = tieNoteGroups.findIndex((ng) => ng.notes.every((n) => !Note4.equals(n, note)));
2861
2649
  if (j >= 0) {
2862
2650
  tieNoteGroups = tieNoteGroups.slice(0, j);
2863
2651
  }
2864
- return Utils5.Math.sum(tieNoteGroups.map((ng) => ng.rhythmProps.ticks));
2652
+ return Utils4.Math.sum(tieNoteGroups.map((ng) => ng.rhythmProps.ticks));
2865
2653
  });
2866
2654
  return tiedTicks.length === 0 ? this.rhythmProps.ticks : Math.max(...tiedTicks);
2867
2655
  }
@@ -3153,7 +2941,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
3153
2941
  }
3154
2942
  });
3155
2943
  } else {
3156
- throw new MusicError8(MusicErrorType8.Score, "Cannot set triplet beam count because triplet beam group type is invalid.");
2944
+ throw new MusicError7(MusicErrorType7.Score, "Cannot set triplet beam count because triplet beam group type is invalid.");
3157
2945
  }
3158
2946
  }
3159
2947
  getDotVerticalDisplacement(staff, diatonicId, stemDir) {
@@ -3179,9 +2967,9 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
3179
2967
  };
3180
2968
 
3181
2969
  // src/score/engine/obj-rhythm-column.ts
3182
- import { MusicError as MusicError9, MusicErrorType as MusicErrorType9 } from "@tspro/web-music-score/core";
2970
+ import { MusicError as MusicError8, MusicErrorType as MusicErrorType8 } from "@tspro/web-music-score/core";
3183
2971
  var noteHeadDataCompareFunc = (a, b) => {
3184
- let cmp = Note6.compareFunc(a.note, b.note);
2972
+ let cmp = Note5.compareFunc(a.note, b.note);
3185
2973
  if (cmp === 0) {
3186
2974
  cmp = a.noteGroup.stemDir === b.noteGroup.stemDir ? 0 : a.noteGroup.stemDir === 1 /* Up */ ? 1 : -1;
3187
2975
  }
@@ -3222,7 +3010,7 @@ var ObjRhythmColumn = class extends MusicObject {
3222
3010
  if (colId >= 0 && colId < this.measure.getColumnCount()) {
3223
3011
  return this.measure.getColumn(colId + 1);
3224
3012
  } else {
3225
- throw new MusicError9(MusicErrorType9.Score, "Cannot get next column in measure because current column's id in mesure is invalid.");
3013
+ throw new MusicError8(MusicErrorType8.Score, "Cannot get next column in measure because current column's id in mesure is invalid.");
3226
3014
  }
3227
3015
  }
3228
3016
  /**
@@ -3249,6 +3037,22 @@ var ObjRhythmColumn = class extends MusicObject {
3249
3037
  this.getRect();
3250
3038
  return this.shapeRects;
3251
3039
  }
3040
+ getStaticObjects(line) {
3041
+ let staticObjects = [];
3042
+ this.voiceSymbol.forEach((symbol) => {
3043
+ if (symbol) {
3044
+ symbol.getRect();
3045
+ symbol.getStaticObjects(line).forEach((obj) => staticObjects.push(obj));
3046
+ }
3047
+ });
3048
+ this.arpeggios.forEach((arpeggio) => {
3049
+ if (arpeggio.line === line) {
3050
+ arpeggio.getRect();
3051
+ staticObjects.push(arpeggio);
3052
+ }
3053
+ });
3054
+ return staticObjects;
3055
+ }
3252
3056
  get doc() {
3253
3057
  return this.measure.doc;
3254
3058
  }
@@ -3299,6 +3103,7 @@ var ObjRhythmColumn = class extends MusicObject {
3299
3103
  this.setupNoteHeadDisplacements();
3300
3104
  }
3301
3105
  this.requestLayout();
3106
+ this.requestRectUpdate();
3302
3107
  }
3303
3108
  getVoiceSymbol(voiceId) {
3304
3109
  return this.voiceSymbol[voiceId];
@@ -3353,7 +3158,7 @@ var ObjRhythmColumn = class extends MusicObject {
3353
3158
  }
3354
3159
  }
3355
3160
  getNoteHeadDisplacement(noteGroup, note) {
3356
- let data = this.noteHeadDisplacements.find((d) => d.noteGroup === noteGroup && Note6.equals(d.note, note));
3161
+ let data = this.noteHeadDisplacements.find((d) => d.noteGroup === noteGroup && Note5.equals(d.note, note));
3357
3162
  if ((data == null ? void 0 : data.displacement) !== void 0) {
3358
3163
  return data.displacement;
3359
3164
  } else {
@@ -3397,7 +3202,7 @@ var ObjRhythmColumn = class extends MusicObject {
3397
3202
  });
3398
3203
  }
3399
3204
  });
3400
- playerNotes.sort((a, b) => Note6.compareFunc(a.note, b.note));
3205
+ playerNotes.sort((a, b) => Note5.compareFunc(a.note, b.note));
3401
3206
  if (this.hasArpeggio() && this.getArpeggioDir() === 1 /* Down */) {
3402
3207
  playerNotes.reverse();
3403
3208
  }
@@ -3413,6 +3218,7 @@ var ObjRhythmColumn = class extends MusicObject {
3413
3218
  if (!this.needLayout) {
3414
3219
  return;
3415
3220
  }
3221
+ this.requestRectUpdate();
3416
3222
  this.rect = new DivRect();
3417
3223
  let { row } = this;
3418
3224
  let { unitSize } = renderer;
@@ -3427,12 +3233,12 @@ var ObjRhythmColumn = class extends MusicObject {
3427
3233
  });
3428
3234
  if (this.arpeggioDir !== void 0) {
3429
3235
  let arpeggioWidth = 0;
3430
- this.arpeggios = row.getStaves().map((staff) => {
3431
- let arpeggio = new ObjArpeggio(this, this.getArpeggioDir());
3236
+ this.arpeggios = row.getNotationLines().map((line) => {
3237
+ let arpeggio = new ObjArpeggio(this, line, this.getArpeggioDir());
3432
3238
  arpeggio.layout(renderer);
3433
- arpeggio.offset(-leftw - arpeggio.getRect().right, staff.getMiddleLineY() - arpeggio.getRect().centerY);
3239
+ arpeggio.offset(-leftw - arpeggio.getRect().right, line.getRect().centerY - arpeggio.getRect().centerY);
3434
3240
  arpeggioWidth = Math.max(arpeggioWidth, arpeggio.getRect().width);
3435
- staff.addObject(arpeggio);
3241
+ line.addObject(arpeggio);
3436
3242
  return arpeggio;
3437
3243
  });
3438
3244
  leftw += arpeggioWidth;
@@ -3450,7 +3256,6 @@ var ObjRhythmColumn = class extends MusicObject {
3450
3256
  this.rect.left = -leftw;
3451
3257
  this.rect.centerX = 0;
3452
3258
  this.rect.right = rightw;
3453
- this.requestRectUpdate();
3454
3259
  this.row.getStaves().forEach((staff) => {
3455
3260
  let minDiatonicId = void 0;
3456
3261
  let maxDiatonicId = void 0;
@@ -3645,7 +3450,7 @@ function isTempoText(text) {
3645
3450
  }
3646
3451
 
3647
3452
  // src/score/engine/extension.ts
3648
- import { MusicError as MusicError10, MusicErrorType as MusicErrorType10 } from "@tspro/web-music-score/core";
3453
+ import { MusicError as MusicError9, MusicErrorType as MusicErrorType9 } from "@tspro/web-music-score/core";
3649
3454
  function getTextAnchorY(linePos) {
3650
3455
  switch (linePos) {
3651
3456
  case "bottom":
@@ -3681,7 +3486,7 @@ var Extension = class extends MusicObjectLink {
3681
3486
  if (head instanceof ObjText) {
3682
3487
  head.updateAnchorY(getTextAnchorY(linePos));
3683
3488
  } else {
3684
- throw new MusicError10(MusicErrorType10.Score, "Update anchor's y-coordinate is only implemented for text objects.");
3489
+ throw new MusicError9(MusicErrorType9.Score, "Update anchor's y-coordinate is only implemented for text objects.");
3685
3490
  }
3686
3491
  }
3687
3492
  isVisible() {
@@ -3817,7 +3622,7 @@ var PlayerColumnProps = class {
3817
3622
  return this.speed;
3818
3623
  }
3819
3624
  getTempo() {
3820
- let speed = Utils6.Math.clamp(this.getSpeed(), 0.1, 10);
3625
+ let speed = Utils5.Math.clamp(this.getSpeed(), 0.1, 10);
3821
3626
  return alterTempoSpeed(this.measure.getTempo(), speed);
3822
3627
  }
3823
3628
  setVolume(volume) {
@@ -3842,7 +3647,7 @@ var PlayerColumnProps = class {
3842
3647
  if (symbolsTicks.length === 0) {
3843
3648
  return 0;
3844
3649
  } else {
3845
- return Utils6.Math.sum(symbolsTicks) / symbolsTicks.length;
3650
+ return Utils5.Math.sum(symbolsTicks) / symbolsTicks.length;
3846
3651
  }
3847
3652
  }
3848
3653
  }
@@ -3990,7 +3795,7 @@ var Player = class _Player {
3990
3795
  } else if (layoutObj.musicObj.getLink() instanceof Extension) {
3991
3796
  let extension = layoutObj.musicObj.getLink();
3992
3797
  let { columnRange, extensionBreakText } = extension.getExtensionRangeInfo();
3993
- let totalTicks = Utils6.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
3798
+ let totalTicks = Utils5.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
3994
3799
  switch (text) {
3995
3800
  case "accel." /* accel */: {
3996
3801
  let startSpeed = curSpeed;
@@ -4044,11 +3849,11 @@ var Player = class _Player {
4044
3849
  });
4045
3850
  let speedArr = (_a = speedMap.get(col)) != null ? _a : [];
4046
3851
  if (speedArr.length > 0) {
4047
- curSpeed = Utils6.Math.sum(speedArr) / speedArr.length;
3852
+ curSpeed = Utils5.Math.sum(speedArr) / speedArr.length;
4048
3853
  }
4049
3854
  let volumeArr = (_b = volumeMap.get(col)) != null ? _b : [];
4050
3855
  if (volumeArr.length > 0) {
4051
- curVolume = Utils6.Math.sum(volumeArr) / volumeArr.length;
3856
+ curVolume = Utils5.Math.sum(volumeArr) / volumeArr.length;
4052
3857
  }
4053
3858
  col.getPlayerProps().setSpeed(curSpeed);
4054
3859
  col.getPlayerProps().setVolume(curVolume);
@@ -4240,14 +4045,12 @@ var ObjBarLine = class extends MusicObject {
4240
4045
  if (line instanceof ObjStaff) {
4241
4046
  lineCenterY = line.getMiddleLineY();
4242
4047
  lineDotOff = line.getDiatonicSpacing();
4243
- top = line.getTopLineY();
4244
- bottom = line.getBottomLineY();
4245
4048
  } else {
4246
- lineCenterY = (line.getBottom() + line.getTop()) / 2;
4247
- lineDotOff = (line.getBottom() - line.getTop()) / 6;
4248
- top = line.getTopStringY();
4249
- bottom = line.getBottomStringY();
4049
+ lineCenterY = (line.getBottomLineY() + line.getTopLineY()) / 2;
4050
+ lineDotOff = (line.getBottomLineY() - line.getTopLineY()) / 6;
4250
4051
  }
4052
+ top = line.getTopLineY();
4053
+ bottom = line.getBottomLineY();
4251
4054
  switch (barLineType) {
4252
4055
  case 0 /* None */:
4253
4056
  obj.setRect(new DivRect(0, 0, 0, top, 0, bottom));
@@ -4379,8 +4182,8 @@ var ObjBarLineRight = class extends ObjBarLine {
4379
4182
  };
4380
4183
 
4381
4184
  // src/score/engine/obj-ending.ts
4382
- import { Utils as Utils7 } from "@tspro/ts-utils-lib";
4383
- import { MusicError as MusicError11, MusicErrorType as MusicErrorType11 } from "@tspro/web-music-score/core";
4185
+ import { Utils as Utils6 } from "@tspro/ts-utils-lib";
4186
+ import { MusicError as MusicError10, MusicErrorType as MusicErrorType10 } from "@tspro/web-music-score/core";
4384
4187
  var ObjEnding = class extends MusicObject {
4385
4188
  constructor(measure, passages) {
4386
4189
  super(measure);
@@ -4390,10 +4193,10 @@ var ObjEnding = class extends MusicObject {
4390
4193
  __publicField(this, "shapeRects", []);
4391
4194
  __publicField(this, "mi");
4392
4195
  this.mi = new MEnding(this);
4393
- if (!Utils7.Is.isIntegerGte(passages.length, 1)) {
4394
- throw new MusicError11(MusicErrorType11.Score, "Passages is empty.");
4395
- } else if (!this.passages.every((p) => Utils7.Is.isIntegerGte(p, 1))) {
4396
- throw new MusicError11(MusicErrorType11.Score, "Invalid passages: " + this.passages);
4196
+ if (!Utils6.Is.isIntegerGte(passages.length, 1)) {
4197
+ throw new MusicError10(MusicErrorType10.Score, "Passages is empty.");
4198
+ } else if (!this.passages.every((p) => Utils6.Is.isIntegerGte(p, 1))) {
4199
+ throw new MusicError10(MusicErrorType10.Score, "Invalid passages: " + this.passages);
4397
4200
  }
4398
4201
  this.passages.sort((a, b) => a - b);
4399
4202
  let text = this.passages.map((p) => p + ".").join("");
@@ -4482,9 +4285,9 @@ var ObjFermata = class extends MusicObject {
4482
4285
  let { measure } = anchor;
4483
4286
  let { row } = measure;
4484
4287
  if (row.getTopStaff() !== row.getBottomStaff()) {
4485
- return [0 /* AboveStaff */, 1 /* BelowStaff */];
4288
+ return [0 /* Above */, 1 /* Below */];
4486
4289
  } else {
4487
- return [0 /* AboveStaff */];
4290
+ return [0 /* Above */];
4488
4291
  }
4489
4292
  }
4490
4293
  pick(x, y) {
@@ -4505,7 +4308,7 @@ var ObjFermata = class extends MusicObject {
4505
4308
  return;
4506
4309
  }
4507
4310
  let { lineWidth, unitSize } = renderer;
4508
- let upsideDown = this.pos === 1 /* BelowStaff */;
4311
+ let upsideDown = this.pos === 1 /* Below */;
4509
4312
  let dy = (upsideDown ? unitSize : -unitSize) * 0.7;
4510
4313
  let left = this.rect.left;
4511
4314
  let right = this.rect.right;
@@ -4600,14 +4403,14 @@ var ObjExtensionLine = class extends MusicObject {
4600
4403
  };
4601
4404
 
4602
4405
  // src/score/engine/obj-measure.ts
4603
- import { MusicError as MusicError14, MusicErrorType as MusicErrorType14 } from "@tspro/web-music-score/core";
4406
+ import { MusicError as MusicError13, MusicErrorType as MusicErrorType13 } from "@tspro/web-music-score/core";
4604
4407
 
4605
4408
  // src/score/engine/connective-props.ts
4606
- import { Note as Note7 } from "@tspro/web-music-score/theory";
4409
+ import { Note as Note6 } from "@tspro/web-music-score/theory";
4607
4410
 
4608
4411
  // src/score/engine/obj-connective.ts
4609
- import { Utils as Utils8 } from "@tspro/ts-utils-lib";
4610
- import { MusicError as MusicError12, MusicErrorType as MusicErrorType12 } from "@tspro/web-music-score/core";
4412
+ import { Utils as Utils7 } from "@tspro/ts-utils-lib";
4413
+ import { MusicError as MusicError11, MusicErrorType as MusicErrorType11 } from "@tspro/web-music-score/core";
4611
4414
  var ObjConnective = class extends MusicObject {
4612
4415
  constructor(connectiveProps, line, measure, leftNoteGroup, leftNoteId, ...args) {
4613
4416
  super(measure);
@@ -4635,7 +4438,7 @@ var ObjConnective = class extends MusicObject {
4635
4438
  this.rightNoteGroup = args[0];
4636
4439
  this.rightNoteId = args[1];
4637
4440
  this.tieType = void 0;
4638
- } else if (Utils8.Is.isEnumValue(args[0], TieType)) {
4441
+ } else if (Utils7.Is.isEnumValue(args[0], TieType)) {
4639
4442
  this.rightNoteGroup = void 0;
4640
4443
  this.rightNoteId = void 0;
4641
4444
  this.tieType = args[0];
@@ -4696,7 +4499,7 @@ var ObjConnective = class extends MusicObject {
4696
4499
  rx = contentRect.right;
4697
4500
  ry = leftPos.y + (rightPos.y - leftPos.y) * tLeft / (tLeft + tRight);
4698
4501
  } else {
4699
- throw new MusicError12(MusicErrorType12.Score, "Cannot layout connective object because no valid left and right note groups.");
4502
+ throw new MusicError11(MusicErrorType11.Score, "Cannot layout connective object because no valid left and right note groups.");
4700
4503
  }
4701
4504
  let spanDy = arcDir === "up" ? -1 : 1;
4702
4505
  let arcHeight = spanDy * unitSize * Math.log2(rx - lx) / 3;
@@ -4705,7 +4508,7 @@ var ObjConnective = class extends MusicObject {
4705
4508
  this.rx = rx;
4706
4509
  this.ry = ry;
4707
4510
  this.arcHeight = this.connectiveProps.connective === 2 /* Slide */ ? 0 : arcHeight;
4708
- let { nx, ny } = Utils8.Math.calcNormal(lx, ly, rx, ry);
4511
+ let { nx, ny } = Utils7.Math.calcNormal(lx, ly, rx, ry);
4709
4512
  this.cp1x = lx * 0.7 + rx * 0.3 + nx * this.arcHeight;
4710
4513
  this.cp1y = ly * 0.7 + ry * 0.3 + ny * this.arcHeight;
4711
4514
  this.cp2x = lx * 0.3 + rx * 0.7 + nx * this.arcHeight;
@@ -4765,7 +4568,7 @@ var ObjConnective = class extends MusicObject {
4765
4568
  };
4766
4569
 
4767
4570
  // src/score/engine/connective-props.ts
4768
- import { MusicError as MusicError13, MusicErrorType as MusicErrorType13 } from "@tspro/web-music-score/core";
4571
+ import { MusicError as MusicError12, MusicErrorType as MusicErrorType12 } from "@tspro/web-music-score/core";
4769
4572
  var ConnectiveProps = class {
4770
4573
  constructor(connective, span, noteAnchor, startNoteGroup) {
4771
4574
  this.connective = connective;
@@ -4845,7 +4648,7 @@ var ConnectiveProps = class {
4845
4648
  let leftNoteGroup = this.noteGroups[i];
4846
4649
  let rightNoteGroup = this.noteGroups[i + 1];
4847
4650
  leftNoteGroup.notes.forEach((leftNote, leftNoteId) => {
4848
- let rightNoteId = rightNoteGroup.notes.findIndex((rightNote) => Note7.equals(rightNote, leftNote));
4651
+ let rightNoteId = rightNoteGroup.notes.findIndex((rightNote) => Note6.equals(rightNote, leftNote));
4849
4652
  if (rightNoteId >= 0) {
4850
4653
  this.createObjConnective(leftNoteGroup, leftNoteId, rightNoteGroup, rightNoteId);
4851
4654
  }
@@ -4900,7 +4703,7 @@ var ConnectiveProps = class {
4900
4703
  addConnective(leftNoteGroup.measure, leftNoteGroup, leftNoteId, rightNoteGroup, rightNoteId);
4901
4704
  addConnective(rightNoteGroup.measure, leftNoteGroup, leftNoteId, rightNoteGroup, rightNoteId);
4902
4705
  } else {
4903
- throw new MusicError13(MusicErrorType13.Score, "Cannot create connective because it is jumping measures.");
4706
+ throw new MusicError12(MusicErrorType12.Score, "Cannot create connective because it is jumping measures.");
4904
4707
  }
4905
4708
  }
4906
4709
  };
@@ -4908,7 +4711,7 @@ var ConnectiveProps = class {
4908
4711
  // src/score/engine/obj-measure.ts
4909
4712
  function validateVoiceId(voiceId) {
4910
4713
  if (getVoiceIds().indexOf(voiceId) < 0) {
4911
- throw new MusicError14(MusicErrorType14.Score, "Invalid voiceId: " + voiceId);
4714
+ throw new MusicError13(MusicErrorType13.Score, "Invalid voiceId: " + voiceId);
4912
4715
  } else {
4913
4716
  return voiceId;
4914
4717
  }
@@ -4944,7 +4747,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
4944
4747
  __publicField(this, "voiceSymbols", []);
4945
4748
  __publicField(this, "lastAddedRhythmColumn");
4946
4749
  __publicField(this, "lastAddedRhythmSymbol");
4947
- __publicField(this, "addExtensionToMusicObject");
4750
+ __publicField(this, "addExtensionToMusicObjects", []);
4948
4751
  __publicField(this, "layoutObjects", []);
4949
4752
  __publicField(this, "postMeasureBreakWidth", 0);
4950
4753
  __publicField(this, "passCount", 0);
@@ -4956,6 +4759,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
4956
4759
  __publicField(this, "endRepeatPlayCount", 2);
4957
4760
  // play twice.
4958
4761
  __publicField(this, "endRepeatPlayCountText");
4762
+ __publicField(this, "staticObjectsCache", /* @__PURE__ */ new Map());
4959
4763
  __publicField(this, "mi");
4960
4764
  this.mi = new MMeasure(this);
4961
4765
  this.prevMeasure = row.doc.getLastMeasure();
@@ -5004,10 +4808,10 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5004
4808
  if (this.row.hasStaff) {
5005
4809
  diatonicId = this.row.getTopStaff().middleLineDiatonicId;
5006
4810
  } else {
5007
- diatonicId = Note8.getNote("C4").diatonicId;
4811
+ diatonicId = Note7.getNote("C4").diatonicId;
5008
4812
  }
5009
4813
  }
5010
- return this.useDiatonicId[voiceId] = Note8.validateDiatonicId(diatonicId);
4814
+ return this.useDiatonicId[voiceId] = Note7.validateDiatonicId(diatonicId);
5011
4815
  }
5012
4816
  updateOwnStemDir(symbol, setStemDir) {
5013
4817
  var _a, _b;
@@ -5144,7 +4948,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5144
4948
  let scaleType = validateScaleType("" + args[1]);
5145
4949
  this.alterKeySignature = getScale(tonic, scaleType);
5146
4950
  } catch (e) {
5147
- throw new MusicError14(MusicErrorType14.Score, "Cannot set key signature because invalid args: " + args);
4951
+ throw new MusicError13(MusicErrorType13.Score, "Cannot set key signature because invalid args: " + args);
5148
4952
  }
5149
4953
  }
5150
4954
  this.updateKeySignature();
@@ -5218,25 +5022,18 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5218
5022
  getPostMeasureBreakWidth() {
5219
5023
  return this.postMeasureBreakWidth;
5220
5024
  }
5221
- addLayoutObject(musicObj, layoutGroupId, verticalPos) {
5222
- let w = new LayoutObjectWrapper(musicObj, layoutGroupId, verticalPos);
5223
- this.layoutObjects.push(w);
5025
+ addLayoutObject(musicObj, line, layoutGroupId, verticalPos) {
5026
+ this.layoutObjects.push(new LayoutObjectWrapper(musicObj, line, layoutGroupId, verticalPos));
5224
5027
  this.requestLayout();
5028
+ this.requestRectUpdate();
5225
5029
  }
5226
- addFermata(fermata) {
5030
+ addFermata(staffTabOrGroup, fermata) {
5227
5031
  let anchor = fermata === 1 /* AtMeasureEnd */ ? this.barLineRight : this.lastAddedRhythmColumn;
5228
5032
  if (!anchor) {
5229
- throw new MusicError14(MusicErrorType14.Score, "Cannot add Fermata because anchor is undefined.");
5033
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add Fermata because anchor is undefined.");
5230
5034
  }
5231
- let fermataObjArr = anchor.getAnchoredLayoutObjects().map((layoutObj) => layoutObj.musicObj).filter((musicObj) => musicObj instanceof ObjFermata);
5232
- let hasAbove = fermataObjArr.some((obj) => obj.pos === 0 /* AboveStaff */);
5233
- let hasBelow = fermataObjArr.some((obj) => obj.pos === 1 /* BelowStaff */);
5234
- ObjFermata.getFermataPositions(anchor).forEach((fermataPos) => {
5235
- if (fermataPos === 0 /* AboveStaff */ && !hasAbove) {
5236
- this.addLayoutObject(new ObjFermata(anchor, fermataPos), 0 /* Fermata */, fermataPos);
5237
- } else if (fermataPos === 1 /* BelowStaff */ && !hasBelow) {
5238
- this.addLayoutObject(new ObjFermata(anchor, fermataPos), 0 /* Fermata */, fermataPos);
5239
- }
5035
+ this.forEachStaffGroup(staffTabOrGroup, 0 /* Above */, (line, vpos) => {
5036
+ this.addLayoutObject(new ObjFermata(anchor, vpos), line, 0 /* Fermata */, vpos);
5240
5037
  });
5241
5038
  this.disableExtension();
5242
5039
  this.requestLayout();
@@ -5244,15 +5041,20 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5244
5041
  hasFermata(anchor) {
5245
5042
  return this.layoutObjects.some((layoutObj) => layoutObj.musicObj instanceof ObjFermata && layoutObj.anchor === anchor);
5246
5043
  }
5247
- addNavigation(navigation, ...args) {
5044
+ addNavigation(staffTabOrGroup, navigation, ...args) {
5045
+ let addLayoutObjectProps = void 0;
5248
5046
  switch (navigation) {
5249
5047
  case 10 /* Ending */:
5250
5048
  if (this.navigationSet.has(navigation)) {
5251
- throw new MusicError14(MusicErrorType14.Score, "Cannot add ending beasure measure already has one.");
5049
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add ending beasure measure already has one.");
5252
5050
  }
5253
5051
  let anchor = this;
5254
5052
  let passages = args;
5255
- this.addLayoutObject(new ObjEnding(anchor, passages), 3 /* Ending */, 0 /* AboveStaff */);
5053
+ addLayoutObjectProps = {
5054
+ createObj: () => new ObjEnding(anchor, passages),
5055
+ layoutGroupId: 3 /* Ending */,
5056
+ defaultVerticalPos: 0 /* Above */
5057
+ };
5256
5058
  break;
5257
5059
  case 1 /* DC_al_Coda */:
5258
5060
  case 0 /* DC_al_Fine */:
@@ -5260,37 +5062,53 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5260
5062
  case 2 /* DS_al_Fine */: {
5261
5063
  let anchor2 = this.barLineRight;
5262
5064
  let text = getNavigationString(navigation);
5263
- this.addLayoutObject(new ObjText(anchor2, text, 1, 1), 2 /* Navigation */, 0 /* AboveStaff */);
5264
- this.addNavigation(9 /* EndRepeat */);
5065
+ addLayoutObjectProps = {
5066
+ createObj: () => new ObjText(anchor2, text, 1, 1),
5067
+ layoutGroupId: 2 /* Navigation */,
5068
+ defaultVerticalPos: 0 /* Above */
5069
+ };
5070
+ this.addNavigation(staffTabOrGroup, 9 /* EndRepeat */);
5265
5071
  this.endSong();
5266
5072
  break;
5267
5073
  }
5268
5074
  case 7 /* Fine */: {
5269
5075
  let anchor2 = this.barLineRight;
5270
5076
  let text = getNavigationString(navigation);
5271
- this.addLayoutObject(new ObjText(anchor2, text, 1, 1), 2 /* Navigation */, 0 /* AboveStaff */);
5077
+ addLayoutObjectProps = {
5078
+ createObj: () => new ObjText(anchor2, text, 1, 1),
5079
+ layoutGroupId: 2 /* Navigation */,
5080
+ defaultVerticalPos: 0 /* Above */
5081
+ };
5272
5082
  break;
5273
5083
  }
5274
5084
  case 6 /* Segno */:
5275
5085
  case 4 /* Coda */: {
5276
5086
  let anchor2 = this.barLineLeft;
5277
5087
  let text = getNavigationString(navigation);
5278
- this.addLayoutObject(new ObjSpecialText(anchor2, text), 2 /* Navigation */, 0 /* AboveStaff */);
5088
+ addLayoutObjectProps = {
5089
+ createObj: () => new ObjSpecialText(anchor2, text),
5090
+ layoutGroupId: 2 /* Navigation */,
5091
+ defaultVerticalPos: 0 /* Above */
5092
+ };
5279
5093
  break;
5280
5094
  }
5281
5095
  case 5 /* toCoda */: {
5282
5096
  let anchor2 = this.barLineRight;
5283
5097
  let text = getNavigationString(navigation);
5284
- this.addLayoutObject(new ObjSpecialText(anchor2, text), 2 /* Navigation */, 0 /* AboveStaff */);
5098
+ addLayoutObjectProps = {
5099
+ createObj: () => new ObjSpecialText(anchor2, text),
5100
+ layoutGroupId: 2 /* Navigation */,
5101
+ defaultVerticalPos: 0 /* Above */
5102
+ };
5285
5103
  break;
5286
5104
  }
5287
5105
  case 9 /* EndRepeat */:
5288
5106
  if (args.length === 0) {
5289
5107
  this.endRepeatPlayCount = 2;
5290
- } else if (Utils9.Is.isIntegerGte(args[0], 2)) {
5108
+ } else if (Utils8.Is.isIntegerGte(args[0], 2)) {
5291
5109
  this.endRepeatPlayCount = args[0];
5292
5110
  } else {
5293
- throw new MusicError14(MusicErrorType14.Score, "Invalid end repeat play count (should be 2 or greater integer): " + args[0]);
5111
+ throw new MusicError13(MusicErrorType13.Score, "Invalid end repeat play count (should be 2 or greater integer): " + args[0]);
5294
5112
  }
5295
5113
  if (this.endRepeatPlayCount !== 2) {
5296
5114
  let textProps = {
@@ -5301,6 +5119,11 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5301
5119
  }
5302
5120
  break;
5303
5121
  }
5122
+ if (addLayoutObjectProps) {
5123
+ this.forEachStaffGroup(staffTabOrGroup, addLayoutObjectProps.defaultVerticalPos, (line, vpos) => {
5124
+ this.addLayoutObject(addLayoutObjectProps.createObj(), line, addLayoutObjectProps.layoutGroupId, vpos);
5125
+ });
5126
+ }
5304
5127
  this.navigationSet.add(navigation);
5305
5128
  this.disableExtension();
5306
5129
  }
@@ -5316,70 +5139,125 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5316
5139
  addConnective(connective, ...args) {
5317
5140
  let anchor = this.lastAddedRhythmSymbol;
5318
5141
  if (!(anchor instanceof ObjNoteGroup)) {
5319
- throw new MusicError14(MusicErrorType14.Score, "Connective can be added to note group only.");
5142
+ throw new MusicError13(MusicErrorType13.Score, "Connective can be added to note group only.");
5320
5143
  }
5321
5144
  if (connective === 0 /* Tie */) {
5322
- let tieSpan = Utils9.Is.isInteger(args[0]) || Utils9.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
5323
- let noteAnchor = Utils9.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5145
+ let tieSpan = Utils8.Is.isInteger(args[0]) || Utils8.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
5146
+ let noteAnchor = Utils8.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5324
5147
  anchor.startConnective(new ConnectiveProps(0 /* Tie */, tieSpan, noteAnchor, anchor));
5325
5148
  } else if (connective === 1 /* Slur */) {
5326
- let slurSpan = Utils9.Is.isInteger(args[0]) ? args[0] : 2;
5327
- let noteAnchor = Utils9.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5149
+ let slurSpan = Utils8.Is.isInteger(args[0]) ? args[0] : 2;
5150
+ let noteAnchor = Utils8.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5328
5151
  anchor.startConnective(new ConnectiveProps(1 /* Slur */, slurSpan, noteAnchor, anchor));
5329
5152
  } else if (connective === 2 /* Slide */) {
5330
- let noteAnchor = Utils9.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : 0 /* Auto */;
5153
+ let noteAnchor = Utils8.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : 0 /* Auto */;
5331
5154
  anchor.startConnective(new ConnectiveProps(2 /* Slide */, 2, noteAnchor, anchor));
5332
5155
  }
5333
5156
  }
5334
- addLabel(label, text) {
5157
+ forEachStaffGroup(staffTabOrGroup, defaultVerticalPos, add) {
5158
+ const lines = this.row.getNotationLines();
5159
+ const performAdd = (lineId, vpos, depth) => {
5160
+ if (depth >= 5) {
5161
+ return;
5162
+ }
5163
+ let success = false;
5164
+ if (typeof lineId === "number") {
5165
+ if (lines[lineId]) {
5166
+ add(lines[lineId], vpos);
5167
+ success = true;
5168
+ }
5169
+ } else if (typeof lineId === "string" && lineId.length > 0) {
5170
+ lines.filter((l) => l.name === lineId).forEach((line) => {
5171
+ add(line, vpos);
5172
+ success = true;
5173
+ });
5174
+ }
5175
+ if (typeof lineId === "string" && !success) {
5176
+ let grp = this.doc.getStaffGroup(lineId);
5177
+ if (grp) {
5178
+ (Utils8.Is.isArray(grp.staffsTabsAndGroups) ? grp.staffsTabsAndGroups : [grp.staffsTabsAndGroups]).forEach((lineId2) => {
5179
+ switch (grp.verticalPosition) {
5180
+ case 0 /* Above */:
5181
+ performAdd(lineId2, 0 /* Above */, depth + 1);
5182
+ break;
5183
+ case 1 /* Below */:
5184
+ performAdd(lineId2, 1 /* Below */, depth + 1);
5185
+ break;
5186
+ case 2 /* Both */:
5187
+ performAdd(lineId2, 0 /* Above */, depth + 1);
5188
+ performAdd(lineId2, 1 /* Below */, depth + 1);
5189
+ break;
5190
+ case 3 /* Auto */:
5191
+ performAdd(lineId2, defaultVerticalPos, depth + 1);
5192
+ break;
5193
+ }
5194
+ });
5195
+ }
5196
+ }
5197
+ };
5198
+ if (staffTabOrGroup === void 0) {
5199
+ if (lines.length >= 2 && lines[0] instanceof ObjStaff && lines[0].staffConfig.clef === "G" /* G */ && lines[0].isGrand() && lines[1] instanceof ObjStaff && lines[1].staffConfig.clef === "F" /* F */ && lines[1].isGrand()) {
5200
+ performAdd(defaultVerticalPos === 1 /* Below */ ? 1 : 0, defaultVerticalPos, 0);
5201
+ } else {
5202
+ performAdd(0, defaultVerticalPos, 0);
5203
+ }
5204
+ } else {
5205
+ performAdd(staffTabOrGroup, defaultVerticalPos, 0);
5206
+ }
5207
+ }
5208
+ addLabel(staffTabOrGroup, label, text) {
5335
5209
  let anchor = this.lastAddedRhythmColumn;
5336
5210
  if (!anchor) {
5337
- throw new MusicError14(MusicErrorType14.Score, "Cannot add label because anchor is undefined.");
5211
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add label because anchor is undefined.");
5338
5212
  } else if (text.length === 0) {
5339
- throw new MusicError14(MusicErrorType14.Score, "Cannot add label because label text is empty.");
5213
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add label because label text is empty.");
5340
5214
  }
5341
5215
  let textProps = { text };
5342
5216
  let layoutGroupId;
5343
- let verticalPos;
5217
+ let defaultVerticalPos;
5344
5218
  switch (label) {
5345
5219
  case 0 /* Note */:
5346
5220
  layoutGroupId = 1 /* NoteLabel */;
5347
- verticalPos = 1 /* BelowStaff */;
5221
+ defaultVerticalPos = 1 /* Below */;
5348
5222
  break;
5349
5223
  case 1 /* Chord */:
5350
5224
  layoutGroupId = 6 /* ChordLabel */;
5351
- verticalPos = 0 /* AboveStaff */;
5225
+ defaultVerticalPos = 0 /* Above */;
5352
5226
  break;
5353
5227
  }
5354
- let textObj = new ObjText(anchor, textProps, 0.5, 1);
5355
- this.addLayoutObject(textObj, layoutGroupId, verticalPos);
5356
- this.enableExtension(textObj);
5228
+ this.forEachStaffGroup(staffTabOrGroup, defaultVerticalPos, (line, vpos) => {
5229
+ let textObj = new ObjText(anchor, textProps, 0.5, 1);
5230
+ this.addLayoutObject(textObj, line, layoutGroupId, vpos);
5231
+ this.enableExtension(textObj);
5232
+ });
5357
5233
  }
5358
- addAnnotation(annotation, text) {
5234
+ addAnnotation(staffTabOrGroup, annotation, text) {
5359
5235
  let anchor = this.lastAddedRhythmColumn;
5360
5236
  if (!anchor) {
5361
- throw new MusicError14(MusicErrorType14.Score, "Cannot add annotation because anchor is undefined.");
5237
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add annotation because anchor is undefined.");
5362
5238
  } else if (text.length === 0) {
5363
- throw new MusicError14(MusicErrorType14.Score, "Cannot add annotation because annotation text is empty.");
5239
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add annotation because annotation text is empty.");
5364
5240
  }
5365
5241
  let textProps = { text };
5366
5242
  let layoutGroupId;
5367
- let verticalPos;
5243
+ let defaultVerticalPos;
5368
5244
  switch (annotation) {
5369
5245
  case 0 /* Dynamics */:
5370
5246
  layoutGroupId = 5 /* DynamicsAnnotation */;
5371
- verticalPos = 0 /* AboveStaff */;
5247
+ defaultVerticalPos = 0 /* Above */;
5372
5248
  textProps.italic = true;
5373
5249
  break;
5374
5250
  case 1 /* Tempo */:
5375
5251
  layoutGroupId = 4 /* TempoAnnotation */;
5376
- verticalPos = 0 /* AboveStaff */;
5252
+ defaultVerticalPos = 0 /* Above */;
5377
5253
  textProps.italic = true;
5378
5254
  break;
5379
5255
  }
5380
- let textObj = new ObjText(anchor, textProps, 0.5, 1);
5381
- this.addLayoutObject(textObj, layoutGroupId, verticalPos);
5382
- this.enableExtension(textObj);
5256
+ this.forEachStaffGroup(staffTabOrGroup, defaultVerticalPos, (line, vpos) => {
5257
+ let textObj = new ObjText(anchor, textProps, 0.5, 1);
5258
+ this.addLayoutObject(textObj, line, layoutGroupId, vpos);
5259
+ this.enableExtension(textObj);
5260
+ });
5383
5261
  }
5384
5262
  endSong() {
5385
5263
  this.isEndSong = true;
@@ -5401,27 +5279,29 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5401
5279
  this.doc.requestNewRow();
5402
5280
  this.disableExtension();
5403
5281
  }
5404
- enableExtension(musicObj) {
5405
- this.addExtensionToMusicObject = musicObj;
5282
+ enableExtension(musicObject) {
5283
+ this.addExtensionToMusicObjects.push(musicObject);
5406
5284
  }
5407
5285
  disableExtension() {
5408
- this.addExtensionToMusicObject = void 0;
5286
+ this.addExtensionToMusicObjects = [];
5409
5287
  }
5410
5288
  addExtension(extensionLength, extensionVisible) {
5411
- let musicObj = this.addExtensionToMusicObject;
5412
- let anchor = musicObj == null ? void 0 : musicObj.getParent();
5413
- if (musicObj instanceof ObjText && anchor instanceof ObjRhythmColumn) {
5414
- let lineStyle = "dashed";
5415
- let linePos = "bottom";
5416
- let extension = new Extension(musicObj, anchor, extensionLength, extensionVisible, lineStyle, linePos);
5417
- musicObj.setLink(extension);
5418
- this.disableExtension();
5419
- this.requestLayout();
5420
- } else if (musicObj === void 0) {
5421
- throw new MusicError14(MusicErrorType14.Score, "Cannot add extension because music object to attach it to is undefined.");
5422
- } else {
5423
- throw new MusicError14(MusicErrorType14.Score, "Cannot add extension becaue no compatible music object to attach it to.");
5289
+ this.addExtensionToMusicObjects.forEach((musicObj) => {
5290
+ let anchor = musicObj.getParent();
5291
+ if (musicObj instanceof ObjText && anchor instanceof ObjRhythmColumn) {
5292
+ let lineStyle = "dashed";
5293
+ let linePos = "bottom";
5294
+ let extension = new Extension(musicObj, anchor, extensionLength, extensionVisible, lineStyle, linePos);
5295
+ musicObj.setLink(extension);
5296
+ } else {
5297
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add extension becaue no compatible music object to attach it to.");
5298
+ }
5299
+ });
5300
+ if (this.addExtensionToMusicObjects.length === 0) {
5301
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add extension because music object to attach it to is undefined.");
5424
5302
  }
5303
+ this.disableExtension();
5304
+ this.requestLayout();
5425
5305
  }
5426
5306
  addRhythmSymbol(voiceId, symbol) {
5427
5307
  let { col } = symbol;
@@ -5433,7 +5313,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5433
5313
  this.lastAddedRhythmSymbol = symbol;
5434
5314
  }
5435
5315
  addNoteGroup(voiceId, notes, noteLength, options) {
5436
- let notes2 = notes.map((note) => typeof note === "string" ? Note8.getNote(note) : note);
5316
+ let notes2 = notes.map((note) => typeof note === "string" ? Note7.getNote(note) : note);
5437
5317
  let col = this.getRhythmColumn(voiceId);
5438
5318
  this.addRhythmSymbol(voiceId, new ObjNoteGroup(col, voiceId, notes2, noteLength, options));
5439
5319
  }
@@ -5465,7 +5345,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5465
5345
  return col2;
5466
5346
  }
5467
5347
  }
5468
- throw new MusicError14(MusicErrorType14.Score, "Error in rhythm column. Should never get here.");
5348
+ throw new MusicError13(MusicErrorType13.Score, "Error in rhythm column. Should never get here.");
5469
5349
  }
5470
5350
  getMeasureTicks() {
5471
5351
  return this.getTimeSignature().measureTicks;
@@ -5517,11 +5397,15 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5517
5397
  getStaffLineRight() {
5518
5398
  return this.barLineRight.getRect().centerX;
5519
5399
  }
5520
- getStaticObjects() {
5521
- return [
5522
- ...this.getColumns(),
5523
- ...this.layoutObjects.filter((layoutObj) => layoutObj.isPositionResolved()).map((layoutObj) => layoutObj.musicObj)
5524
- ];
5400
+ getStaticObjects(line) {
5401
+ let staticObjects = this.staticObjectsCache.get(line);
5402
+ if (!staticObjects) {
5403
+ staticObjects = [];
5404
+ this.getColumns().forEach((col) => col.getStaticObjects(line).forEach((obj) => staticObjects == null ? void 0 : staticObjects.push(obj)));
5405
+ this.staticObjectsCache.set(line, staticObjects);
5406
+ }
5407
+ let layoutObjects = this.layoutObjects.filter((layoutObj) => layoutObj.line === line && layoutObj.isPositionResolved()).map((layoutObj) => layoutObj.musicObj);
5408
+ return layoutObjects.length > 0 ? [...staticObjects, ...layoutObjects] : staticObjects;
5525
5409
  }
5526
5410
  removeLayoutObjects(musicObj) {
5527
5411
  this.layoutObjects = this.layoutObjects.filter((layoutObj) => {
@@ -5549,16 +5433,22 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5549
5433
  }
5550
5434
  createExtensions() {
5551
5435
  this.layoutObjects.forEach((layoutObj) => {
5552
- if (layoutObj.musicObj.getLink() instanceof Extension) {
5553
- let extension = layoutObj.musicObj.getLink();
5554
- if (extension.getHead() === layoutObj.musicObj) {
5555
- extension.getTails().forEach((musicObj) => layoutObj.measure.removeLayoutObjects(musicObj));
5436
+ var _a;
5437
+ let { musicObj, measure, layoutGroupId, verticalPos, line } = layoutObj;
5438
+ if (musicObj.getLink() instanceof Extension) {
5439
+ let extension = musicObj.getLink();
5440
+ if (extension.getHead() === musicObj) {
5441
+ extension.getTails().forEach((musicObj2) => measure.removeLayoutObjects(musicObj2));
5556
5442
  let { startColumn, endColumn } = extension.getExtensionRangeInfo();
5557
5443
  if (extension.isVisible() && startColumn !== endColumn) {
5558
5444
  for (let m = startColumn.measure; m !== void 0; m = m === endColumn.measure ? void 0 : m.getNextMeasure()) {
5559
5445
  let leftObj = m === startColumn.measure ? extension.getHead() : m.getBarLineLeft();
5560
5446
  let rightObj = m === endColumn.measure ? endColumn : m.getBarLineRight();
5561
- m.addLayoutObject(new ObjExtensionLine(m, extension, leftObj, rightObj), layoutObj.layoutGroupId, layoutObj.verticalPos);
5447
+ const lines = m.row.getNotationLines();
5448
+ let line2 = (_a = lines.find((l) => l.name !== "" && l.name === line.name)) != null ? _a : lines[line.id];
5449
+ if (line2) {
5450
+ m.addLayoutObject(new ObjExtensionLine(m, extension, leftObj, rightObj), line2, layoutGroupId, verticalPos);
5451
+ }
5562
5452
  }
5563
5453
  }
5564
5454
  }
@@ -5665,7 +5555,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5665
5555
  let consumedTicks = this.getConsumedTicks(voiceId);
5666
5556
  let remainingTicks = measureTicks - consumedTicks;
5667
5557
  let rests = [];
5668
- let noteLengthValues = Utils9.Enum.getEnumValues(NoteLength6);
5558
+ let noteLengthValues = Utils8.Enum.getEnumValues(NoteLength6);
5669
5559
  while (remainingTicks > 0) {
5670
5560
  noteLengthValues.forEach((restLength) => {
5671
5561
  let restValue = new RhythmProps4(restLength, false);
@@ -5695,6 +5585,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5695
5585
  if (!this.needLayout) {
5696
5586
  return;
5697
5587
  }
5588
+ this.staticObjectsCache.clear();
5698
5589
  this.requestRectUpdate();
5699
5590
  let { unitSize } = renderer;
5700
5591
  this.postMeasureBreakWidth = this.hasPostMeasureBreak() ? DocumentSettings.PostMeasureBreakWidth * unitSize : 0;
@@ -5742,6 +5633,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5742
5633
  if (this.endRepeatPlayCountText) {
5743
5634
  this.endRepeatPlayCountText.layout(renderer);
5744
5635
  }
5636
+ this.layoutObjects.forEach((layoutObj) => layoutObj.layout(renderer));
5745
5637
  let padding = renderer.unitSize;
5746
5638
  this.leftSolidAreaWidth = this.tabStringNotesWidth + Math.max(0, ...this.signatures.map((signature) => signature.getRect().width)) + this.barLineLeft.getRect().width + padding;
5747
5639
  this.rightSolidAreaWidth = padding + this.barLineRight.getRect().width;
@@ -5773,7 +5665,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5773
5665
  let columnsAreaLeft = this.rect.left + this.leftSolidAreaWidth;
5774
5666
  let columnsAreaRight = this.rect.right - this.rightSolidAreaWidth;
5775
5667
  let columnsAreaWidth = columnsAreaRight - columnsAreaLeft;
5776
- let columnsWidth = Utils9.Math.sum(this.columns.map((col) => col.getRect().width));
5668
+ let columnsWidth = Utils8.Math.sum(this.columns.map((col) => col.getRect().width));
5777
5669
  let columnScale = columnsAreaWidth / columnsWidth;
5778
5670
  let columnLeft = columnsAreaLeft;
5779
5671
  this.columns.forEach((col) => {
@@ -5818,7 +5710,8 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5818
5710
  ...this.columns.filter((col) => !col.isEmpty()).map((col) => col.getRect().top),
5819
5711
  this.barLineRight.getRect().top,
5820
5712
  ...this.connectives.map((c) => c.getRect().top),
5821
- ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().top)
5713
+ ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().top),
5714
+ ...this.layoutObjects.filter((o) => o.isPositionResolved()).map((o) => o.musicObj.getRect().top)
5822
5715
  );
5823
5716
  this.rect.bottom = Math.max(
5824
5717
  ...this.signatures.map((s) => s.getRect().bottom),
@@ -5827,12 +5720,20 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5827
5720
  ...this.columns.filter((col) => !col.isEmpty()).map((col) => col.getRect().bottom),
5828
5721
  this.barLineRight.getRect().bottom,
5829
5722
  ...this.connectives.map((c) => c.getRect().bottom),
5830
- ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().bottom)
5723
+ ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().bottom),
5724
+ ...this.layoutObjects.filter((o) => o.isPositionResolved()).map((o) => o.musicObj.getRect().bottom)
5831
5725
  );
5726
+ if (this === this.row.getLastMeasure()) {
5727
+ this.rect.right = Math.max(
5728
+ this.rect.right,
5729
+ ...this.layoutObjects.filter((o) => o.isPositionResolved() && o.musicObj instanceof ObjFermata).map((o) => o.musicObj.getRect().right)
5730
+ );
5731
+ }
5832
5732
  this.row.getNotationLines().forEach((line) => {
5833
5733
  this.rect.top = Math.min(this.rect.top, line.calcTop());
5834
5734
  this.rect.bottom = Math.max(this.rect.bottom, line.calcBottom());
5835
5735
  });
5736
+ this.row.requestRectUpdate();
5836
5737
  }
5837
5738
  offset(dx, dy) {
5838
5739
  this.signatures.forEach((signature) => signature.offset(dx, 0));
@@ -5845,7 +5746,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5845
5746
  }
5846
5747
  this.connectives.forEach((connective) => connective.offset(dx, 0));
5847
5748
  this.beamGroups.forEach((beam) => beam.offset(dx, dy));
5848
- this.layoutObjects.forEach((layoutObj) => layoutObj.musicObj.offset(dx, dy));
5749
+ this.layoutObjects.forEach((layoutObj) => layoutObj.offset(dx, 0));
5849
5750
  this.rect.offsetInPlace(dx, dy);
5850
5751
  this.requestRectUpdate();
5851
5752
  }
@@ -5860,7 +5761,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5860
5761
  for (let p = line.bottomLineDiatonicId; p <= line.topLineDiatonicId; p += 2) {
5861
5762
  drawLine(line.getDiatonicIdY(p));
5862
5763
  }
5863
- } else {
5764
+ } else if (line instanceof ObjTab) {
5864
5765
  for (let stringId = 0; stringId < 6; stringId++) {
5865
5766
  drawLine(line.getStringY(stringId));
5866
5767
  }
@@ -5883,7 +5784,7 @@ __publicField(_ObjMeasure, "MinFlexContentWidth", 10);
5883
5784
  var ObjMeasure2 = _ObjMeasure;
5884
5785
 
5885
5786
  // src/score/engine/layout-object.ts
5886
- import { MusicError as MusicError15, MusicErrorType as MusicErrorType15 } from "@tspro/web-music-score/core";
5787
+ import { MusicError as MusicError14, MusicErrorType as MusicErrorType14 } from "@tspro/web-music-score/core";
5887
5788
  var WidenColumnList = [1 /* NoteLabel */, 6 /* ChordLabel */];
5888
5789
  var RowAlignList = [2 /* Navigation */, 3 /* Ending */, 4 /* TempoAnnotation */, 5 /* DynamicsAnnotation */, 6 /* ChordLabel */];
5889
5790
  function requireParentMeasure(p) {
@@ -5893,11 +5794,19 @@ function requireParentMeasure(p) {
5893
5794
  }
5894
5795
  p = p.getParent();
5895
5796
  }
5896
- throw new MusicError15(MusicErrorType15.Score, "Parent measure is required but not found!");
5797
+ throw new MusicError14(MusicErrorType14.Score, "Parent measure is required but not found!");
5897
5798
  }
5799
+ var StaffGroup = class {
5800
+ constructor(groupName, staffsTabsAndGroups, verticalPosition) {
5801
+ this.groupName = groupName;
5802
+ this.staffsTabsAndGroups = staffsTabsAndGroups;
5803
+ this.verticalPosition = verticalPosition;
5804
+ }
5805
+ };
5898
5806
  var LayoutObjectWrapper = class {
5899
- constructor(musicObj, layoutGroupId, verticalPos) {
5807
+ constructor(musicObj, line, layoutGroupId, verticalPos) {
5900
5808
  this.musicObj = musicObj;
5809
+ this.line = line;
5901
5810
  this.layoutGroupId = layoutGroupId;
5902
5811
  this.verticalPos = verticalPos;
5903
5812
  __publicField(this, "anchor");
@@ -5905,15 +5814,15 @@ var LayoutObjectWrapper = class {
5905
5814
  __publicField(this, "row");
5906
5815
  __publicField(this, "layoutGroup");
5907
5816
  __publicField(this, "positionResolved", true);
5908
- this.measure = requireParentMeasure(musicObj);
5817
+ this.measure = requireParentMeasure(this.musicObj);
5909
5818
  this.row = this.measure.row;
5910
5819
  let anchor = this.musicObj.getParent();
5911
5820
  if (!anchor) {
5912
- throw new MusicError15(MusicErrorType15.Score, "Parent music object is required as an anchor.");
5821
+ throw new MusicError14(MusicErrorType14.Score, "Parent music object is required as an anchor.");
5913
5822
  }
5914
5823
  this.anchor = anchor;
5915
5824
  this.anchor.addAnchoredLayoutObject(this);
5916
- this.layoutGroup = this.measure.doc.getLayoutGroup(layoutGroupId);
5825
+ this.layoutGroup = this.line.getLayoutGroup(layoutGroupId);
5917
5826
  this.layoutGroup.add(this);
5918
5827
  }
5919
5828
  clearPositionResolved() {
@@ -5926,20 +5835,19 @@ var LayoutObjectWrapper = class {
5926
5835
  return this.positionResolved;
5927
5836
  }
5928
5837
  resolveClosestToStaffY(renderer) {
5929
- let { musicObj, measure, verticalPos } = this;
5930
- let { row } = measure;
5931
- let staffTop = row.hasStaff ? row.getTopStaff().getTopLineY() : row.getRect().centerY;
5932
- let staffBottom = row.hasStaff ? row.getBottomStaff().getBottomLineY() : row.getRect().centerY;
5933
- let staffPadding = renderer.unitSize * 2;
5934
- let y = verticalPos === 1 /* BelowStaff */ ? staffBottom + staffPadding + musicObj.getRect().toph : staffTop - staffPadding - musicObj.getRect().bottomh;
5935
- let staticObjects = measure.getStaticObjects();
5838
+ let { musicObj, measure, verticalPos, line } = this;
5839
+ let lineTop = line.getTopLineY();
5840
+ let lineBottom = line.getBottomLineY();
5841
+ let linePadding = renderer.unitSize * 2;
5842
+ let y = verticalPos === 1 /* Below */ ? lineBottom + linePadding + musicObj.getRect().toph : lineTop - linePadding - musicObj.getRect().bottomh;
5843
+ let staticObjects = measure.getStaticObjects(line);
5936
5844
  let objShapeRects = musicObj.getShapeRects();
5937
5845
  staticObjects.forEach((staticObj) => {
5938
5846
  let staticShapeRects = staticObj.getShapeRects();
5939
5847
  objShapeRects.forEach((objR) => {
5940
5848
  staticShapeRects.forEach((staticR) => {
5941
5849
  if (DivRect.overlapX(objR, staticR)) {
5942
- y = verticalPos === 1 /* BelowStaff */ ? Math.max(y, staticR.bottom + objR.toph + objR.centerY) : Math.min(y, staticR.top - objR.bottomh - objR.centerY);
5850
+ y = verticalPos === 1 /* Below */ ? Math.max(y, staticR.bottom + objR.toph + objR.centerY) : Math.min(y, staticR.top - objR.bottomh - objR.centerY);
5943
5851
  }
5944
5852
  });
5945
5853
  });
@@ -5953,6 +5861,15 @@ var LayoutObjectWrapper = class {
5953
5861
  return void 0;
5954
5862
  }
5955
5863
  }
5864
+ layout(renderer) {
5865
+ this.line.addObject(this);
5866
+ }
5867
+ offset(dx, dy) {
5868
+ this.musicObj.offset(dx, dy);
5869
+ }
5870
+ getRect() {
5871
+ return this.musicObj.getRect();
5872
+ }
5956
5873
  };
5957
5874
  var LayoutGroup = class {
5958
5875
  constructor(layoutGroupId) {
@@ -5960,8 +5877,8 @@ var LayoutGroup = class {
5960
5877
  __publicField(this, "layoutObjectTable", []);
5961
5878
  __publicField(this, "rowAlign");
5962
5879
  __publicField(this, "widensColumn");
5963
- this.layoutObjectTable[0 /* AboveStaff */] = [];
5964
- this.layoutObjectTable[1 /* BelowStaff */] = [];
5880
+ this.layoutObjectTable[0 /* Above */] = [];
5881
+ this.layoutObjectTable[1 /* Below */] = [];
5965
5882
  this.rowAlign = RowAlignList.indexOf(layoutGroupId) >= 0;
5966
5883
  this.widensColumn = WidenColumnList.indexOf(layoutGroupId) >= 0;
5967
5884
  }
@@ -5989,6 +5906,333 @@ var LayoutGroup = class {
5989
5906
  }
5990
5907
  };
5991
5908
 
5909
+ // src/score/engine/obj-staff-and-tab.ts
5910
+ var ObjNotationLine4 = class extends MusicObject {
5911
+ constructor(parent) {
5912
+ super(parent);
5913
+ __publicField(this, "objects", []);
5914
+ __publicField(this, "layoutGroups", []);
5915
+ }
5916
+ addObject(o) {
5917
+ this.objects.push(o);
5918
+ }
5919
+ removeObjects() {
5920
+ this.objects.length = 0;
5921
+ }
5922
+ getLayoutGroup(lauoutGroupId) {
5923
+ let layoutGroup = this.layoutGroups[lauoutGroupId];
5924
+ if (!layoutGroup) {
5925
+ layoutGroup = this.layoutGroups[lauoutGroupId] = new LayoutGroup(lauoutGroupId);
5926
+ }
5927
+ return layoutGroup;
5928
+ }
5929
+ resetLayoutGroups(renderer) {
5930
+ this.layoutGroups.forEach((layoutGroup) => {
5931
+ if (layoutGroup) {
5932
+ layoutGroup.clearPositionAndLayout(renderer);
5933
+ }
5934
+ });
5935
+ }
5936
+ layoutLayoutGroups(renderer) {
5937
+ this.layoutGroups.forEach((layoutGroup) => {
5938
+ if (layoutGroup) {
5939
+ this.layoutLayoutGroup(renderer, layoutGroup, 0 /* Above */);
5940
+ this.layoutLayoutGroup(renderer, layoutGroup, 1 /* Below */);
5941
+ }
5942
+ });
5943
+ }
5944
+ setObjectY(layoutObj, y) {
5945
+ if (y === void 0) {
5946
+ return;
5947
+ }
5948
+ layoutObj.offset(0, y - layoutObj.getRect().centerY);
5949
+ layoutObj.setPositionResolved();
5950
+ }
5951
+ alignObjectsY(renderer, layoutObjArr) {
5952
+ layoutObjArr = layoutObjArr.filter((layoutObj) => !layoutObj.isPositionResolved());
5953
+ let rowY;
5954
+ layoutObjArr.forEach((layoutObj) => {
5955
+ let y = layoutObj.resolveClosestToStaffY(renderer);
5956
+ rowY = layoutObj.verticalPos === 1 /* Below */ ? Math.max(y, rowY != null ? rowY : y) : Math.min(y, rowY != null ? rowY : y);
5957
+ });
5958
+ layoutObjArr.forEach((layoutObj) => this.setObjectY(layoutObj, rowY));
5959
+ }
5960
+ layoutLayoutGroup(renderer, layoutGroup, verticalPos) {
5961
+ let rowLayoutObjs = layoutGroup.getLayoutObjects(verticalPos).filter((layoutObj) => !layoutObj.isPositionResolved());
5962
+ rowLayoutObjs.forEach((layoutObj) => {
5963
+ let { musicObj, anchor } = layoutObj;
5964
+ if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine) {
5965
+ musicObj.layoutFitToMeasure(renderer);
5966
+ } else {
5967
+ musicObj.offset(anchor.getRect().centerX - musicObj.getRect().centerX, 0);
5968
+ }
5969
+ });
5970
+ if (layoutGroup.rowAlign) {
5971
+ this.alignObjectsY(renderer, rowLayoutObjs);
5972
+ } else {
5973
+ rowLayoutObjs.forEach((layoutObj) => {
5974
+ let link = layoutObj.musicObj.getLink();
5975
+ if (link && link.getHead() === layoutObj.musicObj) {
5976
+ let objectParts = [link.getHead(), ...link.getTails()];
5977
+ let layoutObjs = rowLayoutObjs.filter((layoutObj2) => objectParts.some((o) => o === layoutObj2.musicObj));
5978
+ this.alignObjectsY(renderer, layoutObjs);
5979
+ } else {
5980
+ this.alignObjectsY(renderer, [layoutObj]);
5981
+ }
5982
+ });
5983
+ }
5984
+ }
5985
+ };
5986
+ var ObjStaff = class extends ObjNotationLine4 {
5987
+ constructor(row, staffConfig, id) {
5988
+ super(row);
5989
+ this.row = row;
5990
+ this.staffConfig = staffConfig;
5991
+ this.id = id;
5992
+ __publicField(this, "clefImageAsset");
5993
+ __publicField(this, "clefLineDiatonicId");
5994
+ __publicField(this, "topLineDiatonicId");
5995
+ __publicField(this, "middleLineDiatonicId");
5996
+ __publicField(this, "bottomLineDiatonicId");
5997
+ __publicField(this, "minDiatonicId");
5998
+ __publicField(this, "maxDiatonicId");
5999
+ __publicField(this, "joinedGrandStaff");
6000
+ __publicField(this, "topLineY", 0);
6001
+ __publicField(this, "bottomLineY", 0);
6002
+ __publicField(this, "mi");
6003
+ const getDiatonicId = (noteName, isOctaveDown) => Note8.getNote(noteName).diatonicId - (isOctaveDown ? 7 : 0);
6004
+ if (staffConfig.clef === "G" /* G */) {
6005
+ this.clefImageAsset = 0 /* TrebleClefPng */;
6006
+ this.clefLineDiatonicId = getDiatonicId("G4", staffConfig.isOctaveDown === true);
6007
+ this.middleLineDiatonicId = this.clefLineDiatonicId + 2;
6008
+ } else {
6009
+ this.clefImageAsset = 1 /* BassClefPng */;
6010
+ this.clefLineDiatonicId = getDiatonicId("F3", staffConfig.isOctaveDown === true);
6011
+ this.middleLineDiatonicId = this.clefLineDiatonicId - 2;
6012
+ }
6013
+ this.topLineDiatonicId = this.middleLineDiatonicId + 4;
6014
+ this.bottomLineDiatonicId = this.middleLineDiatonicId - 4;
6015
+ this.minDiatonicId = staffConfig.minNote !== void 0 ? Math.min(getDiatonicId(staffConfig.minNote, false), this.bottomLineDiatonicId) : void 0;
6016
+ this.maxDiatonicId = staffConfig.maxNote !== void 0 ? Math.max(getDiatonicId(staffConfig.maxNote, false), this.topLineDiatonicId) : void 0;
6017
+ this.mi = new MStaff(this);
6018
+ }
6019
+ getMusicInterface() {
6020
+ return this.mi;
6021
+ }
6022
+ get isOctaveDown() {
6023
+ return this.staffConfig.isOctaveDown === true;
6024
+ }
6025
+ get name() {
6026
+ var _a;
6027
+ return (_a = this.staffConfig.name) != null ? _a : "";
6028
+ }
6029
+ getTopLineY() {
6030
+ return this.topLineY;
6031
+ }
6032
+ getMiddleLineY() {
6033
+ return (this.topLineY + this.bottomLineY) / 2;
6034
+ }
6035
+ getBottomLineY() {
6036
+ return this.bottomLineY;
6037
+ }
6038
+ joinGrandStaff(staff) {
6039
+ if (staff !== this) {
6040
+ this.joinedGrandStaff = staff;
6041
+ }
6042
+ }
6043
+ getLineSpacing() {
6044
+ return (this.bottomLineY - this.topLineY) / 4;
6045
+ }
6046
+ getDiatonicSpacing() {
6047
+ return this.getLineSpacing() / 2;
6048
+ }
6049
+ containsDiatonicId(diatonicId) {
6050
+ Note8.validateDiatonicId(diatonicId);
6051
+ return (this.minDiatonicId === void 0 || diatonicId >= this.minDiatonicId) && (this.maxDiatonicId === void 0 || diatonicId <= this.maxDiatonicId);
6052
+ }
6053
+ getDiatonicIdY(diatonicId) {
6054
+ if (this.containsDiatonicId(diatonicId)) {
6055
+ return this.bottomLineY + (this.bottomLineDiatonicId - diatonicId) * this.getDiatonicSpacing();
6056
+ } else if (this.joinedGrandStaff && this.joinedGrandStaff.containsDiatonicId(diatonicId)) {
6057
+ return this.joinedGrandStaff.getDiatonicIdY(diatonicId);
6058
+ } else {
6059
+ throw new MusicError15(MusicErrorType15.Score, "Staff does not contain diatonicId " + diatonicId);
6060
+ }
6061
+ }
6062
+ getActualStaff(diatonicId) {
6063
+ if (this.containsDiatonicId(diatonicId)) {
6064
+ return this;
6065
+ } else if (this.joinedGrandStaff && this.joinedGrandStaff.containsDiatonicId(diatonicId)) {
6066
+ return this.joinedGrandStaff;
6067
+ } else {
6068
+ throw new MusicError15(MusicErrorType15.Score, "Staff does not contain diatonicId " + diatonicId);
6069
+ }
6070
+ }
6071
+ getDiatonicIdAt(y) {
6072
+ let diatonicId = Math.round(this.bottomLineDiatonicId - (y - this.bottomLineY) / this.getDiatonicSpacing());
6073
+ return this.containsDiatonicId(diatonicId) ? diatonicId : void 0;
6074
+ }
6075
+ isLine(diatonicId) {
6076
+ return diatonicId % 2 === this.middleLineDiatonicId % 2;
6077
+ }
6078
+ isSpace(diatonicId) {
6079
+ return diatonicId % 2 !== this.middleLineDiatonicId % 2;
6080
+ }
6081
+ containsVoiceId(voiceId) {
6082
+ return !this.staffConfig.voiceIds || this.staffConfig.voiceIds.includes(voiceId);
6083
+ }
6084
+ isGrand() {
6085
+ return this.staffConfig.isGrand === true;
6086
+ }
6087
+ calcTop() {
6088
+ let top = this.topLineY;
6089
+ this.objects.forEach((o) => top = Math.min(top, o.getRect().top));
6090
+ if (this.maxDiatonicId !== void 0) {
6091
+ let y = this.getDiatonicIdY(this.maxDiatonicId);
6092
+ let y2 = this.getDiatonicIdY(this.maxDiatonicId - 1);
6093
+ top = Math.min(top, y - Math.abs(y2 - y) + 1);
6094
+ }
6095
+ return top;
6096
+ }
6097
+ calcBottom() {
6098
+ let bottom = this.bottomLineY;
6099
+ this.objects.forEach((o) => bottom = Math.max(bottom, o.getRect().bottom));
6100
+ if (this.minDiatonicId !== void 0) {
6101
+ let y = this.getDiatonicIdY(this.minDiatonicId);
6102
+ let y2 = this.getDiatonicIdY(this.minDiatonicId + 1);
6103
+ bottom = Math.max(bottom, y + Math.abs(y2 - y) - 1);
6104
+ }
6105
+ return bottom;
6106
+ }
6107
+ pick(x, y) {
6108
+ return [this];
6109
+ }
6110
+ layoutHeight(renderer) {
6111
+ let { unitSize } = renderer;
6112
+ let h = unitSize * DocumentSettings.StaffHeight;
6113
+ this.topLineY = -h / 2;
6114
+ this.bottomLineY = h / 2;
6115
+ this.rect = new DivRect(0, 0, this.topLineY, this.bottomLineY);
6116
+ }
6117
+ layoutWidth(renderer) {
6118
+ this.rect.left = this.row.getRect().left;
6119
+ this.rect.right = this.row.getRect().right;
6120
+ }
6121
+ offset(dx, dy) {
6122
+ this.topLineY += dy;
6123
+ this.bottomLineY += dy;
6124
+ this.objects.forEach((o) => {
6125
+ if (o.offsetInPlace) {
6126
+ o.offsetInPlace(0, dy);
6127
+ } else if (o.offset) {
6128
+ o.offset(0, dy);
6129
+ }
6130
+ });
6131
+ this.rect.offsetInPlace(dx, dy);
6132
+ }
6133
+ draw(renderer) {
6134
+ }
6135
+ };
6136
+ var ObjTab = class extends ObjNotationLine4 {
6137
+ constructor(row, tabConfig, id) {
6138
+ super(row);
6139
+ this.row = row;
6140
+ this.tabConfig = tabConfig;
6141
+ this.id = id;
6142
+ __publicField(this, "top", 0);
6143
+ __publicField(this, "bottom", 0);
6144
+ __publicField(this, "tuningName");
6145
+ __publicField(this, "tuningStrings");
6146
+ __publicField(this, "mi");
6147
+ if (Utils9.Is.isArray(tabConfig.tuning)) {
6148
+ this.tuningName = void 0;
6149
+ this.tuningStrings = tabConfig.tuning.map((noteName) => Note8.getNote(noteName)).reverse();
6150
+ } else if (typeof tabConfig.tuning === "string") {
6151
+ this.tuningName = validateTuningName(tabConfig.tuning);
6152
+ this.tuningStrings = getTuningStrings(this.tuningName);
6153
+ } else {
6154
+ this.tuningName = "Standard";
6155
+ this.tuningStrings = getTuningStrings(this.tuningName);
6156
+ }
6157
+ this.mi = new MTab(this);
6158
+ }
6159
+ getMusicInterface() {
6160
+ return this.mi;
6161
+ }
6162
+ get name() {
6163
+ var _a;
6164
+ return (_a = this.tabConfig.name) != null ? _a : "";
6165
+ }
6166
+ getTuningName() {
6167
+ return this.tuningName;
6168
+ }
6169
+ getTuningStrings() {
6170
+ return this.tuningStrings;
6171
+ }
6172
+ /** Return Y coordinate of string. */
6173
+ getStringY(stringId) {
6174
+ return this.top + (this.bottom - this.top) / 6 * (stringId + 0.5);
6175
+ }
6176
+ getTopStringY() {
6177
+ return this.getStringY(0);
6178
+ }
6179
+ getBottomStringY() {
6180
+ return this.getStringY(5);
6181
+ }
6182
+ getTopLineY() {
6183
+ return this.getTopStringY();
6184
+ }
6185
+ getBottomLineY() {
6186
+ return this.getBottomStringY();
6187
+ }
6188
+ getTop() {
6189
+ return this.top;
6190
+ }
6191
+ getBottom() {
6192
+ return this.bottom;
6193
+ }
6194
+ containsVoiceId(voiceId) {
6195
+ return !this.tabConfig.voiceIds || this.tabConfig.voiceIds.includes(voiceId);
6196
+ }
6197
+ containsDiatonicId(diatonicId) {
6198
+ return true;
6199
+ }
6200
+ calcTop() {
6201
+ return this.top;
6202
+ }
6203
+ calcBottom() {
6204
+ return this.bottom;
6205
+ }
6206
+ pick(x, y) {
6207
+ return [this];
6208
+ }
6209
+ layoutHeight(renderer) {
6210
+ let { unitSize } = renderer;
6211
+ let h = unitSize * DocumentSettings.TabHeight;
6212
+ this.top = -h / 2;
6213
+ this.bottom = h / 2;
6214
+ this.rect = new DivRect(0, 0, this.top, this.bottom);
6215
+ }
6216
+ layoutWidth(renderer) {
6217
+ this.rect.left = this.row.getRect().left;
6218
+ this.rect.right = this.row.getRect().right;
6219
+ }
6220
+ offset(dx, dy) {
6221
+ this.top += dy;
6222
+ this.bottom += dy;
6223
+ this.objects.forEach((o) => {
6224
+ if (o.offsetInPlace) {
6225
+ o.offsetInPlace(0, dy);
6226
+ } else if (o.offset) {
6227
+ o.offset(0, dy);
6228
+ }
6229
+ });
6230
+ this.rect.offsetInPlace(dx, dy);
6231
+ }
6232
+ draw(renderer) {
6233
+ }
6234
+ };
6235
+
5992
6236
  // src/score/engine/obj-score-row.ts
5993
6237
  import { MusicError as MusicError16, MusicErrorType as MusicErrorType16 } from "@tspro/web-music-score/core";
5994
6238
  var ObjScoreRow = class extends MusicObject {
@@ -6017,7 +6261,7 @@ var ObjScoreRow = class extends MusicObject {
6017
6261
  return this.mi;
6018
6262
  }
6019
6263
  createNotationLines() {
6020
- let notationLines = this.scoreConfig.map((cfg) => cfg.type === "staff" ? new ObjStaff(this, cfg) : new ObjTab(this, cfg));
6264
+ let notationLines = this.scoreConfig.map((cfg, index) => cfg.type === "staff" ? new ObjStaff(this, cfg, index) : new ObjTab(this, cfg, index));
6021
6265
  for (let i = 0; i < notationLines.length - 1; i++) {
6022
6266
  let treble = notationLines[i];
6023
6267
  let bass = notationLines[i + 1];
@@ -6069,6 +6313,12 @@ var ObjScoreRow = class extends MusicObject {
6069
6313
  }
6070
6314
  return void 0;
6071
6315
  }
6316
+ resetLayoutGroups(renderer) {
6317
+ this.notationLines.forEach((line) => line.resetLayoutGroups(renderer));
6318
+ }
6319
+ layoutLayoutGroups(renderer) {
6320
+ this.notationLines.forEach((line) => line.layoutLayoutGroups(renderer));
6321
+ }
6072
6322
  pick(x, y) {
6073
6323
  if (!this.getRect().contains(x, y)) {
6074
6324
  return [];
@@ -6149,7 +6399,6 @@ var ObjScoreRow = class extends MusicObject {
6149
6399
  this.minWidth = 0;
6150
6400
  this.measures.forEach((m) => {
6151
6401
  m.layout(renderer);
6152
- this.rect.expandInPlace(new DivRect(0, 0, m.getRect().top, m.getRect().bottom));
6153
6402
  this.minWidth += m.getMinWidth();
6154
6403
  this.minWidth += m.getPostMeasureBreakWidth();
6155
6404
  });
@@ -6183,6 +6432,13 @@ var ObjScoreRow = class extends MusicObject {
6183
6432
  m.layoutBeams(renderer);
6184
6433
  });
6185
6434
  }
6435
+ updateRect() {
6436
+ let left = this.measures.length > 0 ? this.measures[0].getRect().left : 0;
6437
+ let right = this.measures.length > 0 ? this.measures[this.measures.length - 1].getRect().right : 0;
6438
+ let top = Math.min(0, ...this.measures.map((m) => m.getRect().top));
6439
+ let bottom = Math.max(0, ...this.measures.map((m) => m.getRect().bottom));
6440
+ this.rect = new DivRect(left, right, top, bottom);
6441
+ }
6186
6442
  alignStemsToBeams() {
6187
6443
  this.measures.forEach((m) => m.alignStemsToBeams());
6188
6444
  }
@@ -6199,7 +6455,6 @@ var ObjScoreRow = class extends MusicObject {
6199
6455
  cur.offset(0, prev.calcBottom() - cur.calcTop() + sep);
6200
6456
  }
6201
6457
  }
6202
- this.requestRectUpdate();
6203
6458
  this.measures.forEach((m) => {
6204
6459
  m.requestRectUpdate();
6205
6460
  m.getBarLineLeft().requestRectUpdate();
@@ -6212,59 +6467,12 @@ var ObjScoreRow = class extends MusicObject {
6212
6467
  });
6213
6468
  });
6214
6469
  });
6215
- let lines = this.getNotationLines();
6216
- this.rect.top = lines[0].calcTop();
6217
- this.rect.bottom = lines[lines.length - 1].calcBottom();
6218
6470
  this.alignStemsToBeams();
6219
- }
6220
- updateRect() {
6221
- }
6222
- setObjectY(layoutObj, y) {
6223
- if (y === void 0) {
6224
- return;
6225
- }
6226
- let { measure, musicObj } = layoutObj;
6227
- musicObj.offset(0, y - musicObj.getRect().centerY);
6228
- layoutObj.setPositionResolved();
6229
- measure.getRect().expandInPlace(musicObj.getRect());
6230
- this.rect.expandInPlace(measure.getRect());
6231
- }
6232
- alignObjectsY(renderer, layoutObjArr) {
6233
- layoutObjArr = layoutObjArr.filter((layoutObj) => !layoutObj.isPositionResolved());
6234
- let rowY;
6235
- layoutObjArr.forEach((layoutObj) => {
6236
- let y = layoutObj.resolveClosestToStaffY(renderer);
6237
- rowY = layoutObj.verticalPos === 1 /* BelowStaff */ ? Math.max(y, rowY != null ? rowY : y) : Math.min(y, rowY != null ? rowY : y);
6238
- });
6239
- layoutObjArr.forEach((layoutObj) => this.setObjectY(layoutObj, rowY));
6240
- }
6241
- layoutLayoutGroup(renderer, layoutGroup, verticalPos) {
6242
- let rowLayoutObjs = layoutGroup.getLayoutObjects(verticalPos).filter((layoutObj) => layoutObj.row === this && !layoutObj.isPositionResolved());
6243
- rowLayoutObjs.forEach((layoutObj) => {
6244
- let { musicObj, anchor } = layoutObj;
6245
- if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine) {
6246
- musicObj.layoutFitToMeasure(renderer);
6247
- } else {
6248
- musicObj.offset(anchor.getRect().centerX - musicObj.getRect().centerX, 0);
6249
- }
6250
- });
6251
- if (layoutGroup.rowAlign) {
6252
- this.alignObjectsY(renderer, rowLayoutObjs);
6253
- } else {
6254
- rowLayoutObjs.forEach((layoutObj) => {
6255
- let link = layoutObj.musicObj.getLink();
6256
- if (link && link.getHead() === layoutObj.musicObj) {
6257
- let objectParts = [link.getHead(), ...link.getTails()];
6258
- let layoutObjs = rowLayoutObjs.filter((layoutObj2) => objectParts.some((o) => o === layoutObj2.musicObj));
6259
- this.alignObjectsY(renderer, layoutObjs);
6260
- } else {
6261
- this.alignObjectsY(renderer, [layoutObj]);
6262
- }
6263
- });
6264
- }
6471
+ this.requestRectUpdate();
6265
6472
  }
6266
6473
  layoutPadding(renderer) {
6267
6474
  let p = renderer.unitSize / 2;
6475
+ this.getRect();
6268
6476
  this.rect.left -= p;
6269
6477
  this.rect.right += p;
6270
6478
  this.rect.top -= p;
@@ -6288,21 +6496,10 @@ var ObjScoreRow = class extends MusicObject {
6288
6496
  ctx.save();
6289
6497
  ctx.rect(this.getRect().left, this.getRect().top, this.getRect().width, this.getRect().height);
6290
6498
  ctx.clip();
6291
- if (this.getFirstMeasure() && this.notationLines.length > 1 || this.notationLines.length === 1 && this.notationLines[0] instanceof ObjTab) {
6499
+ if (this.getFirstMeasure() && (this.notationLines.length > 1 || this.notationLines[0] instanceof ObjTab)) {
6292
6500
  let left = this.getFirstMeasure().getStaffLineLeft();
6293
- let tops = [];
6294
- let bottoms = [];
6295
- this.notationLines.forEach((line) => {
6296
- if (line instanceof ObjStaff) {
6297
- tops.push(line.getTopLineY());
6298
- bottoms.push(line.getBottomLineY());
6299
- } else {
6300
- tops.push(line.getTopStringY());
6301
- bottoms.push(line.getBottomStringY());
6302
- }
6303
- });
6304
- let top = Math.min(...tops);
6305
- let bottom = Math.max(...bottoms);
6501
+ let top = Math.min(...this.notationLines.map((line) => line.getTopLineY()));
6502
+ let bottom = Math.max(...this.notationLines.map((line) => line.getBottomLineY()));
6306
6503
  renderer.drawLine(left, top, left, bottom);
6307
6504
  }
6308
6505
  this.measures.forEach((m) => m.draw(renderer));
@@ -6413,9 +6610,9 @@ var ObjDocument = class extends MusicObject {
6413
6610
  __publicField(this, "measuresPerRow", Infinity);
6414
6611
  __publicField(this, "curScoreConfig", [{ type: "staff", clef: "G" /* G */ }]);
6415
6612
  __publicField(this, "header");
6416
- __publicField(this, "layoutGroups", []);
6417
6613
  __publicField(this, "newRowRequested", false);
6418
6614
  __publicField(this, "allConnectiveProps", []);
6615
+ __publicField(this, "staffGroups", /* @__PURE__ */ new Map());
6419
6616
  __publicField(this, "mi");
6420
6617
  this.mi = new MDocument2(this);
6421
6618
  }
@@ -6481,13 +6678,6 @@ var ObjDocument = class extends MusicObject {
6481
6678
  addConnectiveProps(connectiveProps) {
6482
6679
  this.allConnectiveProps.push(connectiveProps);
6483
6680
  }
6484
- getLayoutGroup(lauoutGroupId) {
6485
- let layoutGroup = this.layoutGroups[lauoutGroupId];
6486
- if (!layoutGroup) {
6487
- layoutGroup = this.layoutGroups[lauoutGroupId] = new LayoutGroup(lauoutGroupId);
6488
- }
6489
- return layoutGroup;
6490
- }
6491
6681
  setRenderer(renderer) {
6492
6682
  if (this.renderer === renderer) {
6493
6683
  return;
@@ -6553,6 +6743,12 @@ var ObjDocument = class extends MusicObject {
6553
6743
  this.requestLayout();
6554
6744
  return measure;
6555
6745
  }
6746
+ addStaffGroup(groupName, layoutElements, verticalPosition) {
6747
+ this.staffGroups.set(groupName, new StaffGroup(groupName, layoutElements, verticalPosition));
6748
+ }
6749
+ getStaffGroup(groupName) {
6750
+ return this.staffGroups.get(groupName);
6751
+ }
6556
6752
  getVoiceSymbols(voiceId) {
6557
6753
  let voiceSymbols = [];
6558
6754
  this.forEachMeasure((m) => voiceSymbols = voiceSymbols.concat(m.getVoiceSymbols(voiceId)));
@@ -6600,21 +6796,15 @@ var ObjDocument = class extends MusicObject {
6600
6796
  this.forEachMeasure((m) => m.createExtensions());
6601
6797
  this.allConnectiveProps.forEach((props) => props.removeConnectives());
6602
6798
  this.allConnectiveProps.forEach((props) => props.createConnectives());
6603
- let layoutGroups = this.layoutGroups.filter((layoutGroup) => !!layoutGroup);
6604
- layoutGroups.forEach((layoutGroup) => layoutGroup.clearPositionAndLayout(renderer));
6799
+ this.rows.forEach((row) => row.resetLayoutGroups(renderer));
6605
6800
  this.rows.forEach((row) => row.layout(renderer));
6606
6801
  let rowWidth = Math.max(
6607
6802
  DocumentSettings.DocumentMinWidth * unitSize,
6608
6803
  ...this.rows.map((row) => 1.4 * row.getMinWidth())
6609
6804
  );
6610
6805
  this.rows.forEach((row) => row.layoutWidth(renderer, rowWidth));
6806
+ this.rows.forEach((row) => row.layoutLayoutGroups(renderer));
6611
6807
  this.rows.forEach((row) => row.layoutPositionLines(renderer));
6612
- layoutGroups.forEach((layoutGroup) => {
6613
- this.rows.forEach((row) => {
6614
- row.layoutLayoutGroup(renderer, layoutGroup, 0 /* AboveStaff */);
6615
- row.layoutLayoutGroup(renderer, layoutGroup, 1 /* BelowStaff */);
6616
- });
6617
- });
6618
6808
  this.rows.forEach((row) => row.layoutPadding(renderer));
6619
6809
  this.rect = new DivRect();
6620
6810
  if (this.header) {
@@ -6839,21 +7029,64 @@ var DocumentBuilder = class {
6839
7029
  this.getMeasure().addRest(voiceId, restLength, options);
6840
7030
  return this;
6841
7031
  }
6842
- addFermata(fermata) {
6843
- assertArg(Utils11.Is.isEnumValueOrUndefined(fermata, Fermata), "fermata", fermata);
6844
- this.getMeasure().addFermata(fermata != null ? fermata : 0 /* AtNote */);
7032
+ addFermataInternal(staffTabOrGroup, fermata) {
7033
+ assertArg(Utils11.Is.isStringOrUndefined(staffTabOrGroup) || Utils11.Is.isIntegerGte(staffTabOrGroup, 0), "staffTabOrGroup", staffTabOrGroup);
7034
+ assertArg(Utils11.Is.isEnumValue(fermata, Fermata), "fermata", fermata);
7035
+ this.getMeasure().addFermata(staffTabOrGroup, fermata);
6845
7036
  return this;
6846
7037
  }
6847
- addNavigation(navigation, ...args) {
7038
+ addFermata(fermata = 0 /* AtNote */) {
7039
+ return this.addFermataInternal(void 0, fermata);
7040
+ }
7041
+ /** @param staffTabOrGroup - staff/tab index (0=top), staff/tab name, or staff group name. */
7042
+ addFermataTo(staffTabOrGroup, fermata = 0 /* AtNote */) {
7043
+ return this.addFermataInternal(staffTabOrGroup, fermata);
7044
+ }
7045
+ addNavigationInternal(staffTabOrGroup, navigation, ...args) {
7046
+ assertArg(Utils11.Is.isStringOrUndefined(staffTabOrGroup) || Utils11.Is.isIntegerGte(staffTabOrGroup, 0), "staffTabOrGroup", staffTabOrGroup);
6848
7047
  assertArg(Utils11.Is.isEnumValue(navigation, Navigation), "navigation", navigation);
6849
7048
  if (navigation === 9 /* EndRepeat */ && args.length > 0) {
6850
7049
  assertArg(Utils11.Is.isIntegerGte(args[0], 1), "playCount", args[0]);
6851
7050
  } else if (navigation === 10 /* Ending */ && args.length > 0) {
6852
7051
  assertArg(args.every((passage) => Utils11.Is.isIntegerGte(passage, 1)), "passages", args);
6853
7052
  }
6854
- this.getMeasure().addNavigation(navigation, ...args);
7053
+ this.getMeasure().addNavigation(staffTabOrGroup, navigation, ...args);
6855
7054
  return this;
6856
7055
  }
7056
+ addNavigation(navigation, ...args) {
7057
+ return this.addNavigationInternal(void 0, navigation, ...args);
7058
+ }
7059
+ addNavigationTo(staffTabOrGroup, navigation, ...args) {
7060
+ return this.addNavigationInternal(staffTabOrGroup, navigation, ...args);
7061
+ }
7062
+ addLabelInternal(staffTabOrGroup, label, text) {
7063
+ assertArg(Utils11.Is.isStringOrUndefined(staffTabOrGroup) || Utils11.Is.isIntegerGte(staffTabOrGroup, 0), "staffTabOrGroup", staffTabOrGroup);
7064
+ assertArg(Utils11.Is.isEnumValue(label, Label), "label", label);
7065
+ assertArg(Utils11.Is.isString(text), "text", text);
7066
+ this.getMeasure().addLabel(staffTabOrGroup, label, text);
7067
+ return this;
7068
+ }
7069
+ addLabel(label, text) {
7070
+ return this.addLabelInternal(void 0, label, text);
7071
+ }
7072
+ /** @param staffTabOrGroup - staff/tab index (0=top), staff/tab name, or staff group name. */
7073
+ addLabelTo(staffTabOrGroup, label, text) {
7074
+ return this.addLabelInternal(staffTabOrGroup, label, text);
7075
+ }
7076
+ addAnnotationInternal(staffTabOrGroup, annotation, text) {
7077
+ assertArg(Utils11.Is.isStringOrUndefined(staffTabOrGroup) || Utils11.Is.isIntegerGte(staffTabOrGroup, 0), "staffTabOrGroup", staffTabOrGroup);
7078
+ assertArg(Utils11.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
7079
+ assertArg(Utils11.Is.isString(text), "text", text);
7080
+ this.getMeasure().addAnnotation(staffTabOrGroup, annotation, text);
7081
+ return this;
7082
+ }
7083
+ addAnnotation(annotation, text) {
7084
+ return this.addAnnotationInternal(void 0, annotation, text);
7085
+ }
7086
+ /** @param staffTabOrGroup - staff/tab index (0=top), staff/tab name, or staff group name. */
7087
+ addAnnotationTo(staffTabOrGroup, annotation, text) {
7088
+ return this.addAnnotationInternal(staffTabOrGroup, annotation, text);
7089
+ }
6857
7090
  addConnective(connective, ...args) {
6858
7091
  assertArg(Utils11.Is.isEnumValue(connective, Connective), "connective", connective);
6859
7092
  if (connective === 0 /* Tie */) {
@@ -6875,24 +7108,30 @@ var DocumentBuilder = class {
6875
7108
  }
6876
7109
  return this;
6877
7110
  }
6878
- addLabel(label, text) {
6879
- assertArg(Utils11.Is.isEnumValue(label, Label), "label", label);
6880
- assertArg(Utils11.Is.isString(text), "text", text);
6881
- this.getMeasure().addLabel(label, text);
6882
- return this;
6883
- }
6884
- addAnnotation(annotation, text) {
6885
- assertArg(Utils11.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
6886
- assertArg(Utils11.Is.isString(text), "text", text);
6887
- this.getMeasure().addAnnotation(annotation, text);
6888
- return this;
6889
- }
6890
7111
  addExtension(extensionLength, extensionVisible) {
6891
7112
  assertArg(Utils11.Is.isIntegerGte(extensionLength, 0) || extensionLength === Infinity || Utils11.Is.isEnumValue(extensionLength, NoteLength7), "extendionLength", extensionLength);
6892
7113
  assertArg(Utils11.Is.isBooleanOrUndefined(extensionVisible), "extensionVisible", extensionVisible);
6893
7114
  this.getMeasure().addExtension(extensionLength, extensionVisible != null ? extensionVisible : true);
6894
7115
  return this;
6895
7116
  }
7117
+ /**
7118
+ *
7119
+ * @param groupName - Name of staff group.
7120
+ * @param staffsTabsAndGroups - staff/tab index (0=top), staff/tab name, or staff group name. Single value or array.
7121
+ * @param verticalPosition - Vertical position, are elements added above, below or both.
7122
+ * @returns
7123
+ */
7124
+ addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition = 3 /* Auto */) {
7125
+ assertArg(Utils11.Is.isString(groupName) && groupName.length > 0, "groupName", groupName);
7126
+ assertArg(
7127
+ Utils11.Is.isString(staffsTabsAndGroups) && staffsTabsAndGroups.length > 0 || Utils11.Is.isIntegerGte(staffsTabsAndGroups, 0) || Utils11.Is.isArray(staffsTabsAndGroups) && staffsTabsAndGroups.every((line) => Utils11.Is.isString(line) && line.length > 0 || Utils11.Is.isIntegerGte(line, 0)),
7128
+ "staffsTabsAndGroups",
7129
+ staffsTabsAndGroups
7130
+ );
7131
+ assertArg(Utils11.Is.isEnumValue(verticalPosition, VerticalPosition), "verticalPosition", verticalPosition);
7132
+ this.doc.addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition);
7133
+ return this;
7134
+ }
6896
7135
  endSong() {
6897
7136
  this.getMeasure().endSong();
6898
7137
  return this;
@@ -7663,6 +7902,7 @@ export {
7663
7902
  StaffPreset,
7664
7903
  Stem,
7665
7904
  TieType,
7905
+ VerticalPosition,
7666
7906
  getStringNumbers,
7667
7907
  getVoiceIds
7668
7908
  };