@tspro/web-music-score 3.0.1 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/README.md +63 -20
  3. package/dist/audio/index.d.mts +1 -8
  4. package/dist/audio/index.d.ts +1 -8
  5. package/dist/audio/index.js +1 -1
  6. package/dist/audio/index.mjs +2 -2
  7. package/dist/audio-cg/index.d.mts +0 -1
  8. package/dist/audio-cg/index.d.ts +0 -1
  9. package/dist/audio-cg/index.js +1 -1
  10. package/dist/audio-cg/index.mjs +2 -2
  11. package/dist/{chunk-4AS76G4O.mjs → chunk-PU4J7K4Z.mjs} +2 -2
  12. package/dist/core/index.d.mts +0 -3
  13. package/dist/core/index.d.ts +0 -3
  14. package/dist/core/index.js +2 -2
  15. package/dist/core/index.mjs +3 -3
  16. package/dist/{guitar-BIFwFT31.d.ts → guitar-C2Cp71NZ.d.ts} +1 -8
  17. package/dist/{guitar-zASF7B1g.d.mts → guitar-DggbM2UL.d.mts} +1 -8
  18. package/dist/iife/index.global.js +11 -11
  19. package/dist/{interface-DkUnsAjj.d.mts → interface-Bz_525zj.d.mts} +94 -104
  20. package/dist/{interface-1TQHxSpb.d.ts → interface-Fn8ufBQx.d.ts} +94 -104
  21. package/dist/{note-B5ZtlHc8.d.mts → note-BFa43I86.d.mts} +0 -14
  22. package/dist/{note-B5ZtlHc8.d.ts → note-BFa43I86.d.ts} +0 -14
  23. package/dist/pieces/index.d.mts +3 -6
  24. package/dist/pieces/index.d.ts +3 -6
  25. package/dist/pieces/index.js +1 -1
  26. package/dist/pieces/index.mjs +2 -2
  27. package/dist/react-ui/index.d.mts +5 -23
  28. package/dist/react-ui/index.d.ts +5 -23
  29. package/dist/react-ui/index.js +1 -1
  30. package/dist/react-ui/index.mjs +2 -2
  31. package/dist/{scale-B_2MZaT9.d.ts → scale-DRR-t4Kr.d.mts} +2 -15
  32. package/dist/{scale-C-YS5iVG.d.mts → scale-ebJm37q1.d.ts} +2 -15
  33. package/dist/score/index.d.mts +32 -8
  34. package/dist/score/index.d.ts +32 -8
  35. package/dist/score/index.js +919 -675
  36. package/dist/score/index.mjs +893 -650
  37. package/dist/{tempo-TjQKn46X.d.mts → tempo-B4h5Ktob.d.mts} +1 -17
  38. package/dist/{tempo-DoJd-UYT.d.ts → tempo-DgqDEsn0.d.ts} +1 -17
  39. package/dist/theory/index.d.mts +6 -8
  40. package/dist/theory/index.d.ts +6 -8
  41. package/dist/theory/index.js +1 -1
  42. package/dist/theory/index.mjs +2 -2
  43. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
- /* WebMusicScore v3.0.1 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
1
+ /* WebMusicScore v3.1.1 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
2
2
  import {
3
3
  __publicField
4
- } from "../chunk-4AS76G4O.mjs";
4
+ } from "../chunk-PU4J7K4Z.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,12 +1462,12 @@ 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
1473
  var ObjArpeggio = class extends MusicObject {
@@ -1731,8 +1494,8 @@ var ObjArpeggio = class extends MusicObject {
1731
1494
  let { unitSize } = renderer;
1732
1495
  this.topArrowHeight = this.arpeggioDir === 0 /* Up */ ? unitSize : 0;
1733
1496
  this.bottomArrowHeight = this.arpeggioDir === 1 /* Down */ ? unitSize : 0;
1734
- let top = this.line instanceof ObjStaff ? this.line.getTopLineY() : this.line.getTopStringY();
1735
- let bottom = this.line instanceof ObjStaff ? this.line.getBottomLineY() : this.line.getBottomStringY();
1497
+ let top = this.line.getTopLineY();
1498
+ let bottom = this.line.getBottomLineY();
1736
1499
  this.cycleHeight = unitSize * 2;
1737
1500
  this.numCycles = Math.ceil((bottom - top) / this.cycleHeight) + 2;
1738
1501
  let width = unitSize * 2;
@@ -1777,14 +1540,14 @@ var ObjArpeggio = class extends MusicObject {
1777
1540
  };
1778
1541
 
1779
1542
  // src/score/engine/obj-rest.ts
1780
- import { Note as Note4, NoteLength, RhythmProps } from "@tspro/web-music-score/theory";
1781
- 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";
1782
1545
  function getDiatonicIdFromStaffPos(staffPos) {
1783
1546
  if (typeof staffPos === "number") {
1784
- return Note4.getChromaticNote(staffPos).diatonicId;
1547
+ return Note3.getChromaticNote(staffPos).diatonicId;
1785
1548
  } else if (typeof staffPos === "string") {
1786
- return Note4.getNote(staffPos).diatonicId;
1787
- } else if (staffPos instanceof Note4) {
1549
+ return Note3.getNote(staffPos).diatonicId;
1550
+ } else if (staffPos instanceof Note3) {
1788
1551
  return staffPos.diatonicId;
1789
1552
  } else {
1790
1553
  return void 0;
@@ -1840,7 +1603,7 @@ var ObjRest = class extends MusicObject {
1840
1603
  let hasStaff = this.row.hasStaff;
1841
1604
  let staff2 = this.row.getStaff(diatonicId);
1842
1605
  if (hasStaff && !staff2) {
1843
- 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!");
1844
1607
  }
1845
1608
  }
1846
1609
  this.ownDiatonicId = this.measure.updateOwnDiatonicId(voiceId, diatonicId);
@@ -1881,6 +1644,15 @@ var ObjRest = class extends MusicObject {
1881
1644
  get triplet() {
1882
1645
  return this.rhythmProps.triplet;
1883
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
+ }
1884
1656
  pick(x, y) {
1885
1657
  if (!this.getRect().contains(x, y)) {
1886
1658
  return [];
@@ -1934,7 +1706,7 @@ var ObjRest = class extends MusicObject {
1934
1706
  case NoteLength.SixtyFourth:
1935
1707
  return -3;
1936
1708
  default:
1937
- 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.");
1938
1710
  }
1939
1711
  }
1940
1712
  updateAccidentalState(accState) {
@@ -2091,13 +1863,13 @@ var ObjRest = class extends MusicObject {
2091
1863
  };
2092
1864
 
2093
1865
  // src/score/engine/obj-note-group.ts
2094
- import { Utils as Utils5 } from "@tspro/ts-utils-lib";
2095
- 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";
2096
1868
 
2097
1869
  // src/score/engine/obj-beam-group.ts
2098
- import { Utils as Utils4 } from "@tspro/ts-utils-lib";
1870
+ import { Utils as Utils3 } from "@tspro/ts-utils-lib";
2099
1871
  import { MinNoteLength, NoteLength as NoteLength2 } from "@tspro/web-music-score/theory";
2100
- 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";
2101
1873
  var adjustBeamAngle = (dx, dy) => {
2102
1874
  let T = DocumentSettings.BeamAngleFactor;
2103
1875
  if (!Number.isFinite(T) || T === 0) {
@@ -2174,13 +1946,13 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2174
1946
  __publicField(this, "staffObjects", []);
2175
1947
  this.mi = new MBeamGroup(this);
2176
1948
  if (!symbols.every((s) => s.measure === symbols[0].measure)) {
2177
- 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.");
2178
1950
  } else if (symbols.length < 2) {
2179
- 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.");
2180
1952
  }
2181
1953
  if (triplet) {
2182
1954
  if (!symbols.every((s) => s.triplet)) {
2183
- 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.");
2184
1956
  }
2185
1957
  let isGroup = symbols.length < 3 || symbols.some((s) => !(s instanceof ObjNoteGroup)) || symbols.some((s) => s.rhythmProps.flagCount !== symbols[0].rhythmProps.flagCount);
2186
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) {
@@ -2198,7 +1970,7 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2198
1970
  symbols.forEach((s) => s.setBeamGroup(this));
2199
1971
  symbols[0].measure.addBeamGroup(this);
2200
1972
  } else {
2201
- 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.");
2202
1974
  }
2203
1975
  }
2204
1976
  static createBeam(noteGroups) {
@@ -2337,7 +2109,7 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2337
2109
  symbolY.forEach((symY, i) => {
2338
2110
  let symX = symbolX[i];
2339
2111
  if (symX !== void 0 && symY !== void 0) {
2340
- let beamY = Utils4.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
2112
+ let beamY = Utils3.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
2341
2113
  let raiseY = symY - beamY;
2342
2114
  if (stemDir === 1 /* Up */ && raiseY < 0) {
2343
2115
  raiseBeamY = Math.min(raiseBeamY, raiseY);
@@ -2352,8 +2124,8 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2352
2124
  let obj = new ObjStaffBeamGroup(mainStaff, this);
2353
2125
  if (this.type === 2 /* TripletGroup */) {
2354
2126
  let ef = unitSize / (rightX - leftX);
2355
- let l = Utils4.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, -ef);
2356
- 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);
2357
2129
  obj.points.push(new BeamPoint(leftStaff, this, leftSymbol, l.x, l.y));
2358
2130
  obj.points.push(new BeamPoint(rightStaff, this, rightSymbol, r.x, r.y));
2359
2131
  obj.tripletNumberOffsetY = 0;
@@ -2411,7 +2183,7 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2411
2183
  obj.points.forEach((pt) => {
2412
2184
  if (pt.symbol instanceof ObjNoteGroup) {
2413
2185
  if (pt !== left && pt !== right) {
2414
- 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);
2415
2187
  }
2416
2188
  pt.symbol.setStemTipY(pt.staff, pt.y);
2417
2189
  }
@@ -2436,8 +2208,8 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2436
2208
  let r = obj.points[obj.points.length - 1];
2437
2209
  if (l && r) {
2438
2210
  let tf = obj.tripletNumber ? obj.tripletNumber.getRect().width / (r.x - l.x) * 1.2 : 0;
2439
- let lc = Utils4.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 - tf / 2);
2440
- 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);
2441
2213
  let tipH = this.stemDir === 1 /* Up */ ? unitSize : -unitSize;
2442
2214
  renderer.drawLine(l.x, l.y, lc.x, lc.y, color, lineWidth);
2443
2215
  renderer.drawLine(rc.x, rc.y, r.x, r.y, color, lineWidth);
@@ -2480,13 +2252,13 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2480
2252
  };
2481
2253
 
2482
2254
  // src/score/engine/obj-note-group.ts
2483
- 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";
2484
2256
  function sortNoteStringData(notes, strings) {
2485
- let stringArr = Utils5.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2257
+ let stringArr = Utils4.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2486
2258
  let noteStringData = notes.map((note, i) => {
2487
2259
  return { note, string: stringArr[i] };
2488
2260
  });
2489
- 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));
2490
2262
  return {
2491
2263
  notes: noteStringData.map((e) => e.note),
2492
2264
  strings: noteStringData.every((e) => e.string === void 0) ? void 0 : noteStringData.map((e) => e.string)
@@ -2600,8 +2372,8 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2600
2372
  __publicField(this, "staffObjects", []);
2601
2373
  __publicField(this, "tabObjects", []);
2602
2374
  __publicField(this, "mi");
2603
- if (!Utils5.Is.isIntegerGte(notes.length, 1)) {
2604
- 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.");
2605
2377
  }
2606
2378
  let noteStringData = sortNoteStringData(notes, options == null ? void 0 : options.string);
2607
2379
  this.notes = noteStringData.notes;
@@ -2640,13 +2412,27 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2640
2412
  }
2641
2413
  startConnective(connectiveProps) {
2642
2414
  if (!this.row.hasStaff && connectiveProps.connective === 0 /* Tie */) {
2643
- 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!");
2644
2416
  } else if (!this.row.hasStaff && connectiveProps.connective === 1 /* Slur */) {
2645
- 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!");
2646
2418
  }
2647
2419
  this.startConnnectives.push(connectiveProps);
2648
2420
  this.doc.addConnectiveProps(connectiveProps);
2649
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
+ }
2650
2436
  pick(x, y) {
2651
2437
  if (!this.getRect().contains(x, y)) {
2652
2438
  return [];
@@ -2675,7 +2461,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2675
2461
  if (line instanceof ObjStaff) {
2676
2462
  let staff = line;
2677
2463
  if (noteIndex < 0 || noteIndex >= this.notes.length) {
2678
- throw new MusicError8(MusicErrorType8.Score, "Invalid noteIndex: " + noteIndex);
2464
+ throw new MusicError7(MusicErrorType7.Score, "Invalid noteIndex: " + noteIndex);
2679
2465
  }
2680
2466
  let obj = this.staffObjects.find((obj2) => obj2.staff === staff);
2681
2467
  if (!obj || noteIndex < 0 || noteIndex >= obj.noteHeadRects.length) {
@@ -2723,7 +2509,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2723
2509
  case 4 /* StemTip */:
2724
2510
  return { x: centerX, y: stemTip.centerY + (stemDir === 1 /* Up */ ? -padding : padding) };
2725
2511
  default:
2726
- throw new MusicError8(MusicErrorType8.Score, "Invalid noteAnchor: " + noteAnchor);
2512
+ throw new MusicError7(MusicErrorType7.Score, "Invalid noteAnchor: " + noteAnchor);
2727
2513
  }
2728
2514
  } else {
2729
2515
  let tab = line;
@@ -2855,15 +2641,15 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2855
2641
  return Math.max(this.rhythmProps.ticks, this.measure.getMeasureTicks() - this.col.positionTicks);
2856
2642
  }
2857
2643
  let prev = tieNoteGroups[j - 1];
2858
- if (prev && prev.notes.some((n) => Note5.equals(n, note))) {
2644
+ if (prev && prev.notes.some((n) => Note4.equals(n, note))) {
2859
2645
  return 0;
2860
2646
  }
2861
2647
  tieNoteGroups = tieNoteGroups.slice(j);
2862
- 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)));
2863
2649
  if (j >= 0) {
2864
2650
  tieNoteGroups = tieNoteGroups.slice(0, j);
2865
2651
  }
2866
- return Utils5.Math.sum(tieNoteGroups.map((ng) => ng.rhythmProps.ticks));
2652
+ return Utils4.Math.sum(tieNoteGroups.map((ng) => ng.rhythmProps.ticks));
2867
2653
  });
2868
2654
  return tiedTicks.length === 0 ? this.rhythmProps.ticks : Math.max(...tiedTicks);
2869
2655
  }
@@ -3155,7 +2941,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
3155
2941
  }
3156
2942
  });
3157
2943
  } else {
3158
- 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.");
3159
2945
  }
3160
2946
  }
3161
2947
  getDotVerticalDisplacement(staff, diatonicId, stemDir) {
@@ -3181,9 +2967,9 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
3181
2967
  };
3182
2968
 
3183
2969
  // src/score/engine/obj-rhythm-column.ts
3184
- 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";
3185
2971
  var noteHeadDataCompareFunc = (a, b) => {
3186
- let cmp = Note6.compareFunc(a.note, b.note);
2972
+ let cmp = Note5.compareFunc(a.note, b.note);
3187
2973
  if (cmp === 0) {
3188
2974
  cmp = a.noteGroup.stemDir === b.noteGroup.stemDir ? 0 : a.noteGroup.stemDir === 1 /* Up */ ? 1 : -1;
3189
2975
  }
@@ -3224,7 +3010,7 @@ var ObjRhythmColumn = class extends MusicObject {
3224
3010
  if (colId >= 0 && colId < this.measure.getColumnCount()) {
3225
3011
  return this.measure.getColumn(colId + 1);
3226
3012
  } else {
3227
- 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.");
3228
3014
  }
3229
3015
  }
3230
3016
  /**
@@ -3251,6 +3037,22 @@ var ObjRhythmColumn = class extends MusicObject {
3251
3037
  this.getRect();
3252
3038
  return this.shapeRects;
3253
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
+ }
3254
3056
  get doc() {
3255
3057
  return this.measure.doc;
3256
3058
  }
@@ -3301,6 +3103,7 @@ var ObjRhythmColumn = class extends MusicObject {
3301
3103
  this.setupNoteHeadDisplacements();
3302
3104
  }
3303
3105
  this.requestLayout();
3106
+ this.requestRectUpdate();
3304
3107
  }
3305
3108
  getVoiceSymbol(voiceId) {
3306
3109
  return this.voiceSymbol[voiceId];
@@ -3355,7 +3158,7 @@ var ObjRhythmColumn = class extends MusicObject {
3355
3158
  }
3356
3159
  }
3357
3160
  getNoteHeadDisplacement(noteGroup, note) {
3358
- 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));
3359
3162
  if ((data == null ? void 0 : data.displacement) !== void 0) {
3360
3163
  return data.displacement;
3361
3164
  } else {
@@ -3399,7 +3202,7 @@ var ObjRhythmColumn = class extends MusicObject {
3399
3202
  });
3400
3203
  }
3401
3204
  });
3402
- playerNotes.sort((a, b) => Note6.compareFunc(a.note, b.note));
3205
+ playerNotes.sort((a, b) => Note5.compareFunc(a.note, b.note));
3403
3206
  if (this.hasArpeggio() && this.getArpeggioDir() === 1 /* Down */) {
3404
3207
  playerNotes.reverse();
3405
3208
  }
@@ -3415,6 +3218,7 @@ var ObjRhythmColumn = class extends MusicObject {
3415
3218
  if (!this.needLayout) {
3416
3219
  return;
3417
3220
  }
3221
+ this.requestRectUpdate();
3418
3222
  this.rect = new DivRect();
3419
3223
  let { row } = this;
3420
3224
  let { unitSize } = renderer;
@@ -3452,7 +3256,6 @@ var ObjRhythmColumn = class extends MusicObject {
3452
3256
  this.rect.left = -leftw;
3453
3257
  this.rect.centerX = 0;
3454
3258
  this.rect.right = rightw;
3455
- this.requestRectUpdate();
3456
3259
  this.row.getStaves().forEach((staff) => {
3457
3260
  let minDiatonicId = void 0;
3458
3261
  let maxDiatonicId = void 0;
@@ -3647,7 +3450,7 @@ function isTempoText(text) {
3647
3450
  }
3648
3451
 
3649
3452
  // src/score/engine/extension.ts
3650
- 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";
3651
3454
  function getTextAnchorY(linePos) {
3652
3455
  switch (linePos) {
3653
3456
  case "bottom":
@@ -3683,7 +3486,7 @@ var Extension = class extends MusicObjectLink {
3683
3486
  if (head instanceof ObjText) {
3684
3487
  head.updateAnchorY(getTextAnchorY(linePos));
3685
3488
  } else {
3686
- 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.");
3687
3490
  }
3688
3491
  }
3689
3492
  isVisible() {
@@ -3819,7 +3622,7 @@ var PlayerColumnProps = class {
3819
3622
  return this.speed;
3820
3623
  }
3821
3624
  getTempo() {
3822
- let speed = Utils6.Math.clamp(this.getSpeed(), 0.1, 10);
3625
+ let speed = Utils5.Math.clamp(this.getSpeed(), 0.1, 10);
3823
3626
  return alterTempoSpeed(this.measure.getTempo(), speed);
3824
3627
  }
3825
3628
  setVolume(volume) {
@@ -3844,7 +3647,7 @@ var PlayerColumnProps = class {
3844
3647
  if (symbolsTicks.length === 0) {
3845
3648
  return 0;
3846
3649
  } else {
3847
- return Utils6.Math.sum(symbolsTicks) / symbolsTicks.length;
3650
+ return Utils5.Math.sum(symbolsTicks) / symbolsTicks.length;
3848
3651
  }
3849
3652
  }
3850
3653
  }
@@ -3992,7 +3795,7 @@ var Player = class _Player {
3992
3795
  } else if (layoutObj.musicObj.getLink() instanceof Extension) {
3993
3796
  let extension = layoutObj.musicObj.getLink();
3994
3797
  let { columnRange, extensionBreakText } = extension.getExtensionRangeInfo();
3995
- let totalTicks = Utils6.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
3798
+ let totalTicks = Utils5.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
3996
3799
  switch (text) {
3997
3800
  case "accel." /* accel */: {
3998
3801
  let startSpeed = curSpeed;
@@ -4046,11 +3849,11 @@ var Player = class _Player {
4046
3849
  });
4047
3850
  let speedArr = (_a = speedMap.get(col)) != null ? _a : [];
4048
3851
  if (speedArr.length > 0) {
4049
- curSpeed = Utils6.Math.sum(speedArr) / speedArr.length;
3852
+ curSpeed = Utils5.Math.sum(speedArr) / speedArr.length;
4050
3853
  }
4051
3854
  let volumeArr = (_b = volumeMap.get(col)) != null ? _b : [];
4052
3855
  if (volumeArr.length > 0) {
4053
- curVolume = Utils6.Math.sum(volumeArr) / volumeArr.length;
3856
+ curVolume = Utils5.Math.sum(volumeArr) / volumeArr.length;
4054
3857
  }
4055
3858
  col.getPlayerProps().setSpeed(curSpeed);
4056
3859
  col.getPlayerProps().setVolume(curVolume);
@@ -4242,14 +4045,12 @@ var ObjBarLine = class extends MusicObject {
4242
4045
  if (line instanceof ObjStaff) {
4243
4046
  lineCenterY = line.getMiddleLineY();
4244
4047
  lineDotOff = line.getDiatonicSpacing();
4245
- top = line.getTopLineY();
4246
- bottom = line.getBottomLineY();
4247
4048
  } else {
4248
- lineCenterY = (line.getBottom() + line.getTop()) / 2;
4249
- lineDotOff = (line.getBottom() - line.getTop()) / 6;
4250
- top = line.getTopStringY();
4251
- bottom = line.getBottomStringY();
4049
+ lineCenterY = (line.getBottomLineY() + line.getTopLineY()) / 2;
4050
+ lineDotOff = (line.getBottomLineY() - line.getTopLineY()) / 6;
4252
4051
  }
4052
+ top = line.getTopLineY();
4053
+ bottom = line.getBottomLineY();
4253
4054
  switch (barLineType) {
4254
4055
  case 0 /* None */:
4255
4056
  obj.setRect(new DivRect(0, 0, 0, top, 0, bottom));
@@ -4381,8 +4182,8 @@ var ObjBarLineRight = class extends ObjBarLine {
4381
4182
  };
4382
4183
 
4383
4184
  // src/score/engine/obj-ending.ts
4384
- import { Utils as Utils7 } from "@tspro/ts-utils-lib";
4385
- 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";
4386
4187
  var ObjEnding = class extends MusicObject {
4387
4188
  constructor(measure, passages) {
4388
4189
  super(measure);
@@ -4392,10 +4193,10 @@ var ObjEnding = class extends MusicObject {
4392
4193
  __publicField(this, "shapeRects", []);
4393
4194
  __publicField(this, "mi");
4394
4195
  this.mi = new MEnding(this);
4395
- if (!Utils7.Is.isIntegerGte(passages.length, 1)) {
4396
- throw new MusicError11(MusicErrorType11.Score, "Passages is empty.");
4397
- } else if (!this.passages.every((p) => Utils7.Is.isIntegerGte(p, 1))) {
4398
- 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);
4399
4200
  }
4400
4201
  this.passages.sort((a, b) => a - b);
4401
4202
  let text = this.passages.map((p) => p + ".").join("");
@@ -4484,9 +4285,9 @@ var ObjFermata = class extends MusicObject {
4484
4285
  let { measure } = anchor;
4485
4286
  let { row } = measure;
4486
4287
  if (row.getTopStaff() !== row.getBottomStaff()) {
4487
- return [0 /* AboveStaff */, 1 /* BelowStaff */];
4288
+ return [0 /* Above */, 1 /* Below */];
4488
4289
  } else {
4489
- return [0 /* AboveStaff */];
4290
+ return [0 /* Above */];
4490
4291
  }
4491
4292
  }
4492
4293
  pick(x, y) {
@@ -4507,7 +4308,7 @@ var ObjFermata = class extends MusicObject {
4507
4308
  return;
4508
4309
  }
4509
4310
  let { lineWidth, unitSize } = renderer;
4510
- let upsideDown = this.pos === 1 /* BelowStaff */;
4311
+ let upsideDown = this.pos === 1 /* Below */;
4511
4312
  let dy = (upsideDown ? unitSize : -unitSize) * 0.7;
4512
4313
  let left = this.rect.left;
4513
4314
  let right = this.rect.right;
@@ -4602,14 +4403,14 @@ var ObjExtensionLine = class extends MusicObject {
4602
4403
  };
4603
4404
 
4604
4405
  // src/score/engine/obj-measure.ts
4605
- 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";
4606
4407
 
4607
4408
  // src/score/engine/connective-props.ts
4608
- import { Note as Note7 } from "@tspro/web-music-score/theory";
4409
+ import { Note as Note6 } from "@tspro/web-music-score/theory";
4609
4410
 
4610
4411
  // src/score/engine/obj-connective.ts
4611
- import { Utils as Utils8 } from "@tspro/ts-utils-lib";
4612
- 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";
4613
4414
  var ObjConnective = class extends MusicObject {
4614
4415
  constructor(connectiveProps, line, measure, leftNoteGroup, leftNoteId, ...args) {
4615
4416
  super(measure);
@@ -4637,7 +4438,7 @@ var ObjConnective = class extends MusicObject {
4637
4438
  this.rightNoteGroup = args[0];
4638
4439
  this.rightNoteId = args[1];
4639
4440
  this.tieType = void 0;
4640
- } else if (Utils8.Is.isEnumValue(args[0], TieType)) {
4441
+ } else if (Utils7.Is.isEnumValue(args[0], TieType)) {
4641
4442
  this.rightNoteGroup = void 0;
4642
4443
  this.rightNoteId = void 0;
4643
4444
  this.tieType = args[0];
@@ -4698,7 +4499,7 @@ var ObjConnective = class extends MusicObject {
4698
4499
  rx = contentRect.right;
4699
4500
  ry = leftPos.y + (rightPos.y - leftPos.y) * tLeft / (tLeft + tRight);
4700
4501
  } else {
4701
- 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.");
4702
4503
  }
4703
4504
  let spanDy = arcDir === "up" ? -1 : 1;
4704
4505
  let arcHeight = spanDy * unitSize * Math.log2(rx - lx) / 3;
@@ -4707,7 +4508,7 @@ var ObjConnective = class extends MusicObject {
4707
4508
  this.rx = rx;
4708
4509
  this.ry = ry;
4709
4510
  this.arcHeight = this.connectiveProps.connective === 2 /* Slide */ ? 0 : arcHeight;
4710
- let { nx, ny } = Utils8.Math.calcNormal(lx, ly, rx, ry);
4511
+ let { nx, ny } = Utils7.Math.calcNormal(lx, ly, rx, ry);
4711
4512
  this.cp1x = lx * 0.7 + rx * 0.3 + nx * this.arcHeight;
4712
4513
  this.cp1y = ly * 0.7 + ry * 0.3 + ny * this.arcHeight;
4713
4514
  this.cp2x = lx * 0.3 + rx * 0.7 + nx * this.arcHeight;
@@ -4767,7 +4568,7 @@ var ObjConnective = class extends MusicObject {
4767
4568
  };
4768
4569
 
4769
4570
  // src/score/engine/connective-props.ts
4770
- 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";
4771
4572
  var ConnectiveProps = class {
4772
4573
  constructor(connective, span, noteAnchor, startNoteGroup) {
4773
4574
  this.connective = connective;
@@ -4847,7 +4648,7 @@ var ConnectiveProps = class {
4847
4648
  let leftNoteGroup = this.noteGroups[i];
4848
4649
  let rightNoteGroup = this.noteGroups[i + 1];
4849
4650
  leftNoteGroup.notes.forEach((leftNote, leftNoteId) => {
4850
- let rightNoteId = rightNoteGroup.notes.findIndex((rightNote) => Note7.equals(rightNote, leftNote));
4651
+ let rightNoteId = rightNoteGroup.notes.findIndex((rightNote) => Note6.equals(rightNote, leftNote));
4851
4652
  if (rightNoteId >= 0) {
4852
4653
  this.createObjConnective(leftNoteGroup, leftNoteId, rightNoteGroup, rightNoteId);
4853
4654
  }
@@ -4902,7 +4703,7 @@ var ConnectiveProps = class {
4902
4703
  addConnective(leftNoteGroup.measure, leftNoteGroup, leftNoteId, rightNoteGroup, rightNoteId);
4903
4704
  addConnective(rightNoteGroup.measure, leftNoteGroup, leftNoteId, rightNoteGroup, rightNoteId);
4904
4705
  } else {
4905
- 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.");
4906
4707
  }
4907
4708
  }
4908
4709
  };
@@ -4910,7 +4711,7 @@ var ConnectiveProps = class {
4910
4711
  // src/score/engine/obj-measure.ts
4911
4712
  function validateVoiceId(voiceId) {
4912
4713
  if (getVoiceIds().indexOf(voiceId) < 0) {
4913
- throw new MusicError14(MusicErrorType14.Score, "Invalid voiceId: " + voiceId);
4714
+ throw new MusicError13(MusicErrorType13.Score, "Invalid voiceId: " + voiceId);
4914
4715
  } else {
4915
4716
  return voiceId;
4916
4717
  }
@@ -4946,7 +4747,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
4946
4747
  __publicField(this, "voiceSymbols", []);
4947
4748
  __publicField(this, "lastAddedRhythmColumn");
4948
4749
  __publicField(this, "lastAddedRhythmSymbol");
4949
- __publicField(this, "addExtensionToMusicObject");
4750
+ __publicField(this, "addExtensionToMusicObjects", []);
4950
4751
  __publicField(this, "layoutObjects", []);
4951
4752
  __publicField(this, "postMeasureBreakWidth", 0);
4952
4753
  __publicField(this, "passCount", 0);
@@ -4958,6 +4759,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
4958
4759
  __publicField(this, "endRepeatPlayCount", 2);
4959
4760
  // play twice.
4960
4761
  __publicField(this, "endRepeatPlayCountText");
4762
+ __publicField(this, "staticObjectsCache", /* @__PURE__ */ new Map());
4961
4763
  __publicField(this, "mi");
4962
4764
  this.mi = new MMeasure(this);
4963
4765
  this.prevMeasure = row.doc.getLastMeasure();
@@ -5006,10 +4808,10 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5006
4808
  if (this.row.hasStaff) {
5007
4809
  diatonicId = this.row.getTopStaff().middleLineDiatonicId;
5008
4810
  } else {
5009
- diatonicId = Note8.getNote("C4").diatonicId;
4811
+ diatonicId = Note7.getNote("C4").diatonicId;
5010
4812
  }
5011
4813
  }
5012
- return this.useDiatonicId[voiceId] = Note8.validateDiatonicId(diatonicId);
4814
+ return this.useDiatonicId[voiceId] = Note7.validateDiatonicId(diatonicId);
5013
4815
  }
5014
4816
  updateOwnStemDir(symbol, setStemDir) {
5015
4817
  var _a, _b;
@@ -5146,7 +4948,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5146
4948
  let scaleType = validateScaleType("" + args[1]);
5147
4949
  this.alterKeySignature = getScale(tonic, scaleType);
5148
4950
  } catch (e) {
5149
- 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);
5150
4952
  }
5151
4953
  }
5152
4954
  this.updateKeySignature();
@@ -5220,25 +5022,65 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5220
5022
  getPostMeasureBreakWidth() {
5221
5023
  return this.postMeasureBreakWidth;
5222
5024
  }
5223
- addLayoutObject(musicObj, layoutGroupId, verticalPos) {
5224
- let w = new LayoutObjectWrapper(musicObj, layoutGroupId, verticalPos);
5225
- this.layoutObjects.push(w);
5025
+ addLayoutObject(musicObj, line, layoutGroupId, verticalPos) {
5026
+ this.layoutObjects.push(new LayoutObjectWrapper(musicObj, line, layoutGroupId, verticalPos));
5226
5027
  this.requestLayout();
5028
+ this.requestRectUpdate();
5029
+ }
5030
+ forEachStaffGroup(staffTabOrGroups, defaultVerticalPos, addFn) {
5031
+ const lines = this.row.getNotationLines();
5032
+ const addToStaffTabOrGroup = (staffTabOrGroup, vpos, prevGroups = []) => {
5033
+ if (typeof staffTabOrGroup === "number") {
5034
+ if (lines[staffTabOrGroup]) {
5035
+ addFn(lines[staffTabOrGroup], vpos);
5036
+ }
5037
+ } else if (typeof staffTabOrGroup === "string" && staffTabOrGroup.length > 0) {
5038
+ let stavesAndTabs = lines.filter((l) => l.name === staffTabOrGroup);
5039
+ stavesAndTabs.forEach((line) => addFn(line, vpos));
5040
+ if (stavesAndTabs.length === 0) {
5041
+ let grp = this.doc.getStaffGroup(staffTabOrGroup);
5042
+ if (grp && !prevGroups.includes(staffTabOrGroup)) {
5043
+ let curGroups = [...prevGroups, staffTabOrGroup];
5044
+ (Utils8.Is.isArray(grp.staffsTabsAndGroups) ? grp.staffsTabsAndGroups : [grp.staffsTabsAndGroups]).forEach((staffTabOrGroup2) => {
5045
+ switch (grp.verticalPosition) {
5046
+ case 0 /* Above */:
5047
+ addToStaffTabOrGroup(staffTabOrGroup2, 0 /* Above */, curGroups);
5048
+ break;
5049
+ case 1 /* Below */:
5050
+ addToStaffTabOrGroup(staffTabOrGroup2, 1 /* Below */, curGroups);
5051
+ break;
5052
+ case 2 /* Both */:
5053
+ addToStaffTabOrGroup(staffTabOrGroup2, 0 /* Above */, curGroups);
5054
+ addToStaffTabOrGroup(staffTabOrGroup2, 1 /* Below */, curGroups);
5055
+ break;
5056
+ case 3 /* Auto */:
5057
+ addToStaffTabOrGroup(staffTabOrGroup2, defaultVerticalPos, curGroups);
5058
+ break;
5059
+ }
5060
+ });
5061
+ }
5062
+ }
5063
+ }
5064
+ };
5065
+ if (staffTabOrGroups === void 0) {
5066
+ 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()) {
5067
+ addToStaffTabOrGroup(defaultVerticalPos === 1 /* Below */ ? 1 : 0, defaultVerticalPos);
5068
+ } else {
5069
+ addToStaffTabOrGroup(0, defaultVerticalPos);
5070
+ }
5071
+ } else if (Utils8.Is.isArray(staffTabOrGroups)) {
5072
+ staffTabOrGroups.forEach((staffTabOrGroup) => addToStaffTabOrGroup(staffTabOrGroup, defaultVerticalPos));
5073
+ } else {
5074
+ addToStaffTabOrGroup(staffTabOrGroups, defaultVerticalPos);
5075
+ }
5227
5076
  }
5228
- addFermata(fermata) {
5077
+ addFermata(staffTabOrGroups, fermata) {
5229
5078
  let anchor = fermata === 1 /* AtMeasureEnd */ ? this.barLineRight : this.lastAddedRhythmColumn;
5230
5079
  if (!anchor) {
5231
- throw new MusicError14(MusicErrorType14.Score, "Cannot add Fermata because anchor is undefined.");
5080
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add Fermata because anchor is undefined.");
5232
5081
  }
5233
- let fermataObjArr = anchor.getAnchoredLayoutObjects().map((layoutObj) => layoutObj.musicObj).filter((musicObj) => musicObj instanceof ObjFermata);
5234
- let hasAbove = fermataObjArr.some((obj) => obj.pos === 0 /* AboveStaff */);
5235
- let hasBelow = fermataObjArr.some((obj) => obj.pos === 1 /* BelowStaff */);
5236
- ObjFermata.getFermataPositions(anchor).forEach((fermataPos) => {
5237
- if (fermataPos === 0 /* AboveStaff */ && !hasAbove) {
5238
- this.addLayoutObject(new ObjFermata(anchor, fermataPos), 0 /* Fermata */, fermataPos);
5239
- } else if (fermataPos === 1 /* BelowStaff */ && !hasBelow) {
5240
- this.addLayoutObject(new ObjFermata(anchor, fermataPos), 0 /* Fermata */, fermataPos);
5241
- }
5082
+ this.forEachStaffGroup(staffTabOrGroups, 0 /* Above */, (line, vpos) => {
5083
+ this.addLayoutObject(new ObjFermata(anchor, vpos), line, 0 /* Fermata */, vpos);
5242
5084
  });
5243
5085
  this.disableExtension();
5244
5086
  this.requestLayout();
@@ -5246,15 +5088,20 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5246
5088
  hasFermata(anchor) {
5247
5089
  return this.layoutObjects.some((layoutObj) => layoutObj.musicObj instanceof ObjFermata && layoutObj.anchor === anchor);
5248
5090
  }
5249
- addNavigation(navigation, ...args) {
5091
+ addNavigation(staffTabOrGroups, navigation, ...args) {
5092
+ let addLayoutObjectProps = void 0;
5250
5093
  switch (navigation) {
5251
5094
  case 10 /* Ending */:
5252
5095
  if (this.navigationSet.has(navigation)) {
5253
- throw new MusicError14(MusicErrorType14.Score, "Cannot add ending beasure measure already has one.");
5096
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add ending beasure measure already has one.");
5254
5097
  }
5255
5098
  let anchor = this;
5256
5099
  let passages = args;
5257
- this.addLayoutObject(new ObjEnding(anchor, passages), 3 /* Ending */, 0 /* AboveStaff */);
5100
+ addLayoutObjectProps = {
5101
+ createObj: () => new ObjEnding(anchor, passages),
5102
+ layoutGroupId: 3 /* Ending */,
5103
+ defaultVerticalPos: 0 /* Above */
5104
+ };
5258
5105
  break;
5259
5106
  case 1 /* DC_al_Coda */:
5260
5107
  case 0 /* DC_al_Fine */:
@@ -5262,37 +5109,53 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5262
5109
  case 2 /* DS_al_Fine */: {
5263
5110
  let anchor2 = this.barLineRight;
5264
5111
  let text = getNavigationString(navigation);
5265
- this.addLayoutObject(new ObjText(anchor2, text, 1, 1), 2 /* Navigation */, 0 /* AboveStaff */);
5266
- this.addNavigation(9 /* EndRepeat */);
5112
+ addLayoutObjectProps = {
5113
+ createObj: () => new ObjText(anchor2, text, 1, 1),
5114
+ layoutGroupId: 2 /* Navigation */,
5115
+ defaultVerticalPos: 0 /* Above */
5116
+ };
5117
+ this.addNavigation(staffTabOrGroups, 9 /* EndRepeat */);
5267
5118
  this.endSong();
5268
5119
  break;
5269
5120
  }
5270
5121
  case 7 /* Fine */: {
5271
5122
  let anchor2 = this.barLineRight;
5272
5123
  let text = getNavigationString(navigation);
5273
- this.addLayoutObject(new ObjText(anchor2, text, 1, 1), 2 /* Navigation */, 0 /* AboveStaff */);
5124
+ addLayoutObjectProps = {
5125
+ createObj: () => new ObjText(anchor2, text, 1, 1),
5126
+ layoutGroupId: 2 /* Navigation */,
5127
+ defaultVerticalPos: 0 /* Above */
5128
+ };
5274
5129
  break;
5275
5130
  }
5276
5131
  case 6 /* Segno */:
5277
5132
  case 4 /* Coda */: {
5278
5133
  let anchor2 = this.barLineLeft;
5279
5134
  let text = getNavigationString(navigation);
5280
- this.addLayoutObject(new ObjSpecialText(anchor2, text), 2 /* Navigation */, 0 /* AboveStaff */);
5135
+ addLayoutObjectProps = {
5136
+ createObj: () => new ObjSpecialText(anchor2, text),
5137
+ layoutGroupId: 2 /* Navigation */,
5138
+ defaultVerticalPos: 0 /* Above */
5139
+ };
5281
5140
  break;
5282
5141
  }
5283
5142
  case 5 /* toCoda */: {
5284
5143
  let anchor2 = this.barLineRight;
5285
5144
  let text = getNavigationString(navigation);
5286
- this.addLayoutObject(new ObjSpecialText(anchor2, text), 2 /* Navigation */, 0 /* AboveStaff */);
5145
+ addLayoutObjectProps = {
5146
+ createObj: () => new ObjSpecialText(anchor2, text),
5147
+ layoutGroupId: 2 /* Navigation */,
5148
+ defaultVerticalPos: 0 /* Above */
5149
+ };
5287
5150
  break;
5288
5151
  }
5289
5152
  case 9 /* EndRepeat */:
5290
5153
  if (args.length === 0) {
5291
5154
  this.endRepeatPlayCount = 2;
5292
- } else if (Utils9.Is.isIntegerGte(args[0], 2)) {
5155
+ } else if (Utils8.Is.isIntegerGte(args[0], 2)) {
5293
5156
  this.endRepeatPlayCount = args[0];
5294
5157
  } else {
5295
- throw new MusicError14(MusicErrorType14.Score, "Invalid end repeat play count (should be 2 or greater integer): " + args[0]);
5158
+ throw new MusicError13(MusicErrorType13.Score, "Invalid end repeat play count (should be 2 or greater integer): " + args[0]);
5296
5159
  }
5297
5160
  if (this.endRepeatPlayCount !== 2) {
5298
5161
  let textProps = {
@@ -5303,85 +5166,118 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5303
5166
  }
5304
5167
  break;
5305
5168
  }
5169
+ if (addLayoutObjectProps) {
5170
+ this.forEachStaffGroup(staffTabOrGroups, addLayoutObjectProps.defaultVerticalPos, (line, vpos) => {
5171
+ this.addLayoutObject(addLayoutObjectProps.createObj(), line, addLayoutObjectProps.layoutGroupId, vpos);
5172
+ });
5173
+ }
5306
5174
  this.navigationSet.add(navigation);
5307
5175
  this.disableExtension();
5308
5176
  }
5309
5177
  hasNavigation(n) {
5310
5178
  return this.navigationSet.has(n);
5311
5179
  }
5312
- getEnding() {
5313
- return this.layoutObjects.map((layoutObj) => layoutObj.musicObj).find((musicObj) => musicObj instanceof ObjEnding);
5314
- }
5315
- getEndRepeatPlayCount() {
5316
- return this.endRepeatPlayCount;
5317
- }
5318
- addConnective(connective, ...args) {
5319
- let anchor = this.lastAddedRhythmSymbol;
5320
- if (!(anchor instanceof ObjNoteGroup)) {
5321
- throw new MusicError14(MusicErrorType14.Score, "Connective can be added to note group only.");
5180
+ addAnnotation(staffTabOrGroups, annotation, text) {
5181
+ let anchor = this.lastAddedRhythmColumn;
5182
+ if (!anchor) {
5183
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add annotation because anchor is undefined.");
5184
+ } else if (text.length === 0) {
5185
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add annotation because annotation text is empty.");
5322
5186
  }
5323
- if (connective === 0 /* Tie */) {
5324
- let tieSpan = Utils9.Is.isInteger(args[0]) || Utils9.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
5325
- let noteAnchor = Utils9.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5326
- anchor.startConnective(new ConnectiveProps(0 /* Tie */, tieSpan, noteAnchor, anchor));
5327
- } else if (connective === 1 /* Slur */) {
5328
- let slurSpan = Utils9.Is.isInteger(args[0]) ? args[0] : 2;
5329
- let noteAnchor = Utils9.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5330
- anchor.startConnective(new ConnectiveProps(1 /* Slur */, slurSpan, noteAnchor, anchor));
5331
- } else if (connective === 2 /* Slide */) {
5332
- let noteAnchor = Utils9.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : 0 /* Auto */;
5333
- anchor.startConnective(new ConnectiveProps(2 /* Slide */, 2, noteAnchor, anchor));
5187
+ let textProps = { text };
5188
+ let layoutGroupId;
5189
+ let defaultVerticalPos;
5190
+ switch (annotation) {
5191
+ case 0 /* Dynamics */:
5192
+ layoutGroupId = 5 /* DynamicsAnnotation */;
5193
+ defaultVerticalPos = 0 /* Above */;
5194
+ textProps.italic = true;
5195
+ break;
5196
+ case 1 /* Tempo */:
5197
+ layoutGroupId = 4 /* TempoAnnotation */;
5198
+ defaultVerticalPos = 0 /* Above */;
5199
+ textProps.italic = true;
5200
+ break;
5334
5201
  }
5202
+ this.forEachStaffGroup(staffTabOrGroups, defaultVerticalPos, (line, vpos) => {
5203
+ let textObj = new ObjText(anchor, textProps, 0.5, 1);
5204
+ this.addLayoutObject(textObj, line, layoutGroupId, vpos);
5205
+ this.enableExtension(textObj);
5206
+ });
5335
5207
  }
5336
- addLabel(label, text) {
5208
+ addLabel(staffTabOrGroups, label, text) {
5337
5209
  let anchor = this.lastAddedRhythmColumn;
5338
5210
  if (!anchor) {
5339
- 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.");
5340
5212
  } else if (text.length === 0) {
5341
- 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.");
5342
5214
  }
5343
5215
  let textProps = { text };
5344
5216
  let layoutGroupId;
5345
- let verticalPos;
5217
+ let defaultVerticalPos;
5346
5218
  switch (label) {
5347
5219
  case 0 /* Note */:
5348
5220
  layoutGroupId = 1 /* NoteLabel */;
5349
- verticalPos = 1 /* BelowStaff */;
5221
+ defaultVerticalPos = 1 /* Below */;
5350
5222
  break;
5351
5223
  case 1 /* Chord */:
5352
5224
  layoutGroupId = 6 /* ChordLabel */;
5353
- verticalPos = 0 /* AboveStaff */;
5225
+ defaultVerticalPos = 0 /* Above */;
5354
5226
  break;
5355
5227
  }
5356
- let textObj = new ObjText(anchor, textProps, 0.5, 1);
5357
- this.addLayoutObject(textObj, layoutGroupId, verticalPos);
5358
- this.enableExtension(textObj);
5228
+ this.forEachStaffGroup(staffTabOrGroups, 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
+ });
5359
5233
  }
5360
- addAnnotation(annotation, text) {
5361
- let anchor = this.lastAddedRhythmColumn;
5362
- if (!anchor) {
5363
- throw new MusicError14(MusicErrorType14.Score, "Cannot add annotation because anchor is undefined.");
5364
- } else if (text.length === 0) {
5365
- throw new MusicError14(MusicErrorType14.Score, "Cannot add annotation because annotation text is empty.");
5234
+ addConnective(connective, ...args) {
5235
+ let anchor = this.lastAddedRhythmSymbol;
5236
+ if (!(anchor instanceof ObjNoteGroup)) {
5237
+ throw new MusicError13(MusicErrorType13.Score, "Connective can be added to note group only.");
5366
5238
  }
5367
- let textProps = { text };
5368
- let layoutGroupId;
5369
- let verticalPos;
5370
- switch (annotation) {
5371
- case 0 /* Dynamics */:
5372
- layoutGroupId = 5 /* DynamicsAnnotation */;
5373
- verticalPos = 0 /* AboveStaff */;
5374
- textProps.italic = true;
5375
- break;
5376
- case 1 /* Tempo */:
5377
- layoutGroupId = 4 /* TempoAnnotation */;
5378
- verticalPos = 0 /* AboveStaff */;
5379
- textProps.italic = true;
5380
- break;
5239
+ if (connective === 0 /* Tie */) {
5240
+ let tieSpan = Utils8.Is.isInteger(args[0]) || Utils8.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
5241
+ let noteAnchor = Utils8.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5242
+ anchor.startConnective(new ConnectiveProps(0 /* Tie */, tieSpan, noteAnchor, anchor));
5243
+ } else if (connective === 1 /* Slur */) {
5244
+ let slurSpan = Utils8.Is.isInteger(args[0]) ? args[0] : 2;
5245
+ let noteAnchor = Utils8.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : 0 /* Auto */;
5246
+ anchor.startConnective(new ConnectiveProps(1 /* Slur */, slurSpan, noteAnchor, anchor));
5247
+ } else if (connective === 2 /* Slide */) {
5248
+ let noteAnchor = Utils8.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : 0 /* Auto */;
5249
+ anchor.startConnective(new ConnectiveProps(2 /* Slide */, 2, noteAnchor, anchor));
5250
+ }
5251
+ }
5252
+ addExtension(extensionLength, extensionVisible) {
5253
+ this.addExtensionToMusicObjects.forEach((musicObj) => {
5254
+ let anchor = musicObj.getParent();
5255
+ if (musicObj instanceof ObjText && anchor instanceof ObjRhythmColumn) {
5256
+ let lineStyle = "dashed";
5257
+ let linePos = "bottom";
5258
+ let extension = new Extension(musicObj, anchor, extensionLength, extensionVisible, lineStyle, linePos);
5259
+ musicObj.setLink(extension);
5260
+ } else {
5261
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add extension becaue no compatible music object to attach it to.");
5262
+ }
5263
+ });
5264
+ if (this.addExtensionToMusicObjects.length === 0) {
5265
+ throw new MusicError13(MusicErrorType13.Score, "Cannot add extension because music object to attach it to is undefined.");
5381
5266
  }
5382
- let textObj = new ObjText(anchor, textProps, 0.5, 1);
5383
- this.addLayoutObject(textObj, layoutGroupId, verticalPos);
5384
- this.enableExtension(textObj);
5267
+ this.disableExtension();
5268
+ this.requestLayout();
5269
+ }
5270
+ enableExtension(musicObject) {
5271
+ this.addExtensionToMusicObjects.push(musicObject);
5272
+ }
5273
+ disableExtension() {
5274
+ this.addExtensionToMusicObjects = [];
5275
+ }
5276
+ getEnding() {
5277
+ return this.layoutObjects.map((layoutObj) => layoutObj.musicObj).find((musicObj) => musicObj instanceof ObjEnding);
5278
+ }
5279
+ getEndRepeatPlayCount() {
5280
+ return this.endRepeatPlayCount;
5385
5281
  }
5386
5282
  endSong() {
5387
5283
  this.isEndSong = true;
@@ -5403,28 +5299,6 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5403
5299
  this.doc.requestNewRow();
5404
5300
  this.disableExtension();
5405
5301
  }
5406
- enableExtension(musicObj) {
5407
- this.addExtensionToMusicObject = musicObj;
5408
- }
5409
- disableExtension() {
5410
- this.addExtensionToMusicObject = void 0;
5411
- }
5412
- addExtension(extensionLength, extensionVisible) {
5413
- let musicObj = this.addExtensionToMusicObject;
5414
- let anchor = musicObj == null ? void 0 : musicObj.getParent();
5415
- if (musicObj instanceof ObjText && anchor instanceof ObjRhythmColumn) {
5416
- let lineStyle = "dashed";
5417
- let linePos = "bottom";
5418
- let extension = new Extension(musicObj, anchor, extensionLength, extensionVisible, lineStyle, linePos);
5419
- musicObj.setLink(extension);
5420
- this.disableExtension();
5421
- this.requestLayout();
5422
- } else if (musicObj === void 0) {
5423
- throw new MusicError14(MusicErrorType14.Score, "Cannot add extension because music object to attach it to is undefined.");
5424
- } else {
5425
- throw new MusicError14(MusicErrorType14.Score, "Cannot add extension becaue no compatible music object to attach it to.");
5426
- }
5427
- }
5428
5302
  addRhythmSymbol(voiceId, symbol) {
5429
5303
  let { col } = symbol;
5430
5304
  col.setVoiceSymbol(voiceId, symbol);
@@ -5435,7 +5309,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5435
5309
  this.lastAddedRhythmSymbol = symbol;
5436
5310
  }
5437
5311
  addNoteGroup(voiceId, notes, noteLength, options) {
5438
- let notes2 = notes.map((note) => typeof note === "string" ? Note8.getNote(note) : note);
5312
+ let notes2 = notes.map((note) => typeof note === "string" ? Note7.getNote(note) : note);
5439
5313
  let col = this.getRhythmColumn(voiceId);
5440
5314
  this.addRhythmSymbol(voiceId, new ObjNoteGroup(col, voiceId, notes2, noteLength, options));
5441
5315
  }
@@ -5467,7 +5341,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5467
5341
  return col2;
5468
5342
  }
5469
5343
  }
5470
- throw new MusicError14(MusicErrorType14.Score, "Error in rhythm column. Should never get here.");
5344
+ throw new MusicError13(MusicErrorType13.Score, "Error in rhythm column. Should never get here.");
5471
5345
  }
5472
5346
  getMeasureTicks() {
5473
5347
  return this.getTimeSignature().measureTicks;
@@ -5519,11 +5393,15 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5519
5393
  getStaffLineRight() {
5520
5394
  return this.barLineRight.getRect().centerX;
5521
5395
  }
5522
- getStaticObjects() {
5523
- return [
5524
- ...this.getColumns(),
5525
- ...this.layoutObjects.filter((layoutObj) => layoutObj.isPositionResolved()).map((layoutObj) => layoutObj.musicObj)
5526
- ];
5396
+ getStaticObjects(line) {
5397
+ let staticObjects = this.staticObjectsCache.get(line);
5398
+ if (!staticObjects) {
5399
+ staticObjects = [];
5400
+ this.getColumns().forEach((col) => col.getStaticObjects(line).forEach((obj) => staticObjects == null ? void 0 : staticObjects.push(obj)));
5401
+ this.staticObjectsCache.set(line, staticObjects);
5402
+ }
5403
+ let layoutObjects = this.layoutObjects.filter((layoutObj) => layoutObj.line === line && layoutObj.isPositionResolved()).map((layoutObj) => layoutObj.musicObj);
5404
+ return layoutObjects.length > 0 ? [...staticObjects, ...layoutObjects] : staticObjects;
5527
5405
  }
5528
5406
  removeLayoutObjects(musicObj) {
5529
5407
  this.layoutObjects = this.layoutObjects.filter((layoutObj) => {
@@ -5551,16 +5429,22 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5551
5429
  }
5552
5430
  createExtensions() {
5553
5431
  this.layoutObjects.forEach((layoutObj) => {
5554
- if (layoutObj.musicObj.getLink() instanceof Extension) {
5555
- let extension = layoutObj.musicObj.getLink();
5556
- if (extension.getHead() === layoutObj.musicObj) {
5557
- extension.getTails().forEach((musicObj) => layoutObj.measure.removeLayoutObjects(musicObj));
5432
+ var _a;
5433
+ let { musicObj, measure, layoutGroupId, verticalPos, line } = layoutObj;
5434
+ if (musicObj.getLink() instanceof Extension) {
5435
+ let extension = musicObj.getLink();
5436
+ if (extension.getHead() === musicObj) {
5437
+ extension.getTails().forEach((musicObj2) => measure.removeLayoutObjects(musicObj2));
5558
5438
  let { startColumn, endColumn } = extension.getExtensionRangeInfo();
5559
5439
  if (extension.isVisible() && startColumn !== endColumn) {
5560
5440
  for (let m = startColumn.measure; m !== void 0; m = m === endColumn.measure ? void 0 : m.getNextMeasure()) {
5561
5441
  let leftObj = m === startColumn.measure ? extension.getHead() : m.getBarLineLeft();
5562
5442
  let rightObj = m === endColumn.measure ? endColumn : m.getBarLineRight();
5563
- m.addLayoutObject(new ObjExtensionLine(m, extension, leftObj, rightObj), layoutObj.layoutGroupId, layoutObj.verticalPos);
5443
+ const lines = m.row.getNotationLines();
5444
+ let line2 = (_a = lines.find((l) => l.name !== "" && l.name === line.name)) != null ? _a : lines[line.id];
5445
+ if (line2) {
5446
+ m.addLayoutObject(new ObjExtensionLine(m, extension, leftObj, rightObj), line2, layoutGroupId, verticalPos);
5447
+ }
5564
5448
  }
5565
5449
  }
5566
5450
  }
@@ -5667,7 +5551,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5667
5551
  let consumedTicks = this.getConsumedTicks(voiceId);
5668
5552
  let remainingTicks = measureTicks - consumedTicks;
5669
5553
  let rests = [];
5670
- let noteLengthValues = Utils9.Enum.getEnumValues(NoteLength6);
5554
+ let noteLengthValues = Utils8.Enum.getEnumValues(NoteLength6);
5671
5555
  while (remainingTicks > 0) {
5672
5556
  noteLengthValues.forEach((restLength) => {
5673
5557
  let restValue = new RhythmProps4(restLength, false);
@@ -5697,6 +5581,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5697
5581
  if (!this.needLayout) {
5698
5582
  return;
5699
5583
  }
5584
+ this.staticObjectsCache.clear();
5700
5585
  this.requestRectUpdate();
5701
5586
  let { unitSize } = renderer;
5702
5587
  this.postMeasureBreakWidth = this.hasPostMeasureBreak() ? DocumentSettings.PostMeasureBreakWidth * unitSize : 0;
@@ -5744,6 +5629,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5744
5629
  if (this.endRepeatPlayCountText) {
5745
5630
  this.endRepeatPlayCountText.layout(renderer);
5746
5631
  }
5632
+ this.layoutObjects.forEach((layoutObj) => layoutObj.layout(renderer));
5747
5633
  let padding = renderer.unitSize;
5748
5634
  this.leftSolidAreaWidth = this.tabStringNotesWidth + Math.max(0, ...this.signatures.map((signature) => signature.getRect().width)) + this.barLineLeft.getRect().width + padding;
5749
5635
  this.rightSolidAreaWidth = padding + this.barLineRight.getRect().width;
@@ -5775,7 +5661,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5775
5661
  let columnsAreaLeft = this.rect.left + this.leftSolidAreaWidth;
5776
5662
  let columnsAreaRight = this.rect.right - this.rightSolidAreaWidth;
5777
5663
  let columnsAreaWidth = columnsAreaRight - columnsAreaLeft;
5778
- let columnsWidth = Utils9.Math.sum(this.columns.map((col) => col.getRect().width));
5664
+ let columnsWidth = Utils8.Math.sum(this.columns.map((col) => col.getRect().width));
5779
5665
  let columnScale = columnsAreaWidth / columnsWidth;
5780
5666
  let columnLeft = columnsAreaLeft;
5781
5667
  this.columns.forEach((col) => {
@@ -5820,7 +5706,8 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5820
5706
  ...this.columns.filter((col) => !col.isEmpty()).map((col) => col.getRect().top),
5821
5707
  this.barLineRight.getRect().top,
5822
5708
  ...this.connectives.map((c) => c.getRect().top),
5823
- ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().top)
5709
+ ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().top),
5710
+ ...this.layoutObjects.filter((o) => o.isPositionResolved()).map((o) => o.musicObj.getRect().top)
5824
5711
  );
5825
5712
  this.rect.bottom = Math.max(
5826
5713
  ...this.signatures.map((s) => s.getRect().bottom),
@@ -5829,12 +5716,20 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5829
5716
  ...this.columns.filter((col) => !col.isEmpty()).map((col) => col.getRect().bottom),
5830
5717
  this.barLineRight.getRect().bottom,
5831
5718
  ...this.connectives.map((c) => c.getRect().bottom),
5832
- ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().bottom)
5719
+ ...this.beamGroups.filter((b) => !b.isEmpty()).map((b) => b.getRect().bottom),
5720
+ ...this.layoutObjects.filter((o) => o.isPositionResolved()).map((o) => o.musicObj.getRect().bottom)
5833
5721
  );
5722
+ if (this === this.row.getLastMeasure()) {
5723
+ this.rect.right = Math.max(
5724
+ this.rect.right,
5725
+ ...this.layoutObjects.filter((o) => o.isPositionResolved() && o.musicObj instanceof ObjFermata).map((o) => o.musicObj.getRect().right)
5726
+ );
5727
+ }
5834
5728
  this.row.getNotationLines().forEach((line) => {
5835
5729
  this.rect.top = Math.min(this.rect.top, line.calcTop());
5836
5730
  this.rect.bottom = Math.max(this.rect.bottom, line.calcBottom());
5837
5731
  });
5732
+ this.row.requestRectUpdate();
5838
5733
  }
5839
5734
  offset(dx, dy) {
5840
5735
  this.signatures.forEach((signature) => signature.offset(dx, 0));
@@ -5847,7 +5742,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5847
5742
  }
5848
5743
  this.connectives.forEach((connective) => connective.offset(dx, 0));
5849
5744
  this.beamGroups.forEach((beam) => beam.offset(dx, dy));
5850
- this.layoutObjects.forEach((layoutObj) => layoutObj.musicObj.offset(dx, dy));
5745
+ this.layoutObjects.forEach((layoutObj) => layoutObj.offset(dx, 0));
5851
5746
  this.rect.offsetInPlace(dx, dy);
5852
5747
  this.requestRectUpdate();
5853
5748
  }
@@ -5862,7 +5757,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5862
5757
  for (let p = line.bottomLineDiatonicId; p <= line.topLineDiatonicId; p += 2) {
5863
5758
  drawLine(line.getDiatonicIdY(p));
5864
5759
  }
5865
- } else {
5760
+ } else if (line instanceof ObjTab) {
5866
5761
  for (let stringId = 0; stringId < 6; stringId++) {
5867
5762
  drawLine(line.getStringY(stringId));
5868
5763
  }
@@ -5885,7 +5780,7 @@ __publicField(_ObjMeasure, "MinFlexContentWidth", 10);
5885
5780
  var ObjMeasure2 = _ObjMeasure;
5886
5781
 
5887
5782
  // src/score/engine/layout-object.ts
5888
- import { MusicError as MusicError15, MusicErrorType as MusicErrorType15 } from "@tspro/web-music-score/core";
5783
+ import { MusicError as MusicError14, MusicErrorType as MusicErrorType14 } from "@tspro/web-music-score/core";
5889
5784
  var WidenColumnList = [1 /* NoteLabel */, 6 /* ChordLabel */];
5890
5785
  var RowAlignList = [2 /* Navigation */, 3 /* Ending */, 4 /* TempoAnnotation */, 5 /* DynamicsAnnotation */, 6 /* ChordLabel */];
5891
5786
  function requireParentMeasure(p) {
@@ -5895,11 +5790,19 @@ function requireParentMeasure(p) {
5895
5790
  }
5896
5791
  p = p.getParent();
5897
5792
  }
5898
- throw new MusicError15(MusicErrorType15.Score, "Parent measure is required but not found!");
5793
+ throw new MusicError14(MusicErrorType14.Score, "Parent measure is required but not found!");
5899
5794
  }
5795
+ var StaffGroup = class {
5796
+ constructor(groupName, staffsTabsAndGroups, verticalPosition) {
5797
+ this.groupName = groupName;
5798
+ this.staffsTabsAndGroups = staffsTabsAndGroups;
5799
+ this.verticalPosition = verticalPosition;
5800
+ }
5801
+ };
5900
5802
  var LayoutObjectWrapper = class {
5901
- constructor(musicObj, layoutGroupId, verticalPos) {
5803
+ constructor(musicObj, line, layoutGroupId, verticalPos) {
5902
5804
  this.musicObj = musicObj;
5805
+ this.line = line;
5903
5806
  this.layoutGroupId = layoutGroupId;
5904
5807
  this.verticalPos = verticalPos;
5905
5808
  __publicField(this, "anchor");
@@ -5907,15 +5810,15 @@ var LayoutObjectWrapper = class {
5907
5810
  __publicField(this, "row");
5908
5811
  __publicField(this, "layoutGroup");
5909
5812
  __publicField(this, "positionResolved", true);
5910
- this.measure = requireParentMeasure(musicObj);
5813
+ this.measure = requireParentMeasure(this.musicObj);
5911
5814
  this.row = this.measure.row;
5912
5815
  let anchor = this.musicObj.getParent();
5913
5816
  if (!anchor) {
5914
- throw new MusicError15(MusicErrorType15.Score, "Parent music object is required as an anchor.");
5817
+ throw new MusicError14(MusicErrorType14.Score, "Parent music object is required as an anchor.");
5915
5818
  }
5916
5819
  this.anchor = anchor;
5917
5820
  this.anchor.addAnchoredLayoutObject(this);
5918
- this.layoutGroup = this.measure.doc.getLayoutGroup(layoutGroupId);
5821
+ this.layoutGroup = this.line.getLayoutGroup(layoutGroupId);
5919
5822
  this.layoutGroup.add(this);
5920
5823
  }
5921
5824
  clearPositionResolved() {
@@ -5928,20 +5831,19 @@ var LayoutObjectWrapper = class {
5928
5831
  return this.positionResolved;
5929
5832
  }
5930
5833
  resolveClosestToStaffY(renderer) {
5931
- let { musicObj, measure, verticalPos } = this;
5932
- let { row } = measure;
5933
- let staffTop = row.hasStaff ? row.getTopStaff().getTopLineY() : row.getRect().centerY;
5934
- let staffBottom = row.hasStaff ? row.getBottomStaff().getBottomLineY() : row.getRect().centerY;
5935
- let staffPadding = renderer.unitSize * 2;
5936
- let y = verticalPos === 1 /* BelowStaff */ ? staffBottom + staffPadding + musicObj.getRect().toph : staffTop - staffPadding - musicObj.getRect().bottomh;
5937
- let staticObjects = measure.getStaticObjects();
5834
+ let { musicObj, measure, verticalPos, line } = this;
5835
+ let lineTop = line.getTopLineY();
5836
+ let lineBottom = line.getBottomLineY();
5837
+ let linePadding = renderer.unitSize * 2;
5838
+ let y = verticalPos === 1 /* Below */ ? lineBottom + linePadding + musicObj.getRect().toph : lineTop - linePadding - musicObj.getRect().bottomh;
5839
+ let staticObjects = measure.getStaticObjects(line);
5938
5840
  let objShapeRects = musicObj.getShapeRects();
5939
5841
  staticObjects.forEach((staticObj) => {
5940
5842
  let staticShapeRects = staticObj.getShapeRects();
5941
5843
  objShapeRects.forEach((objR) => {
5942
5844
  staticShapeRects.forEach((staticR) => {
5943
5845
  if (DivRect.overlapX(objR, staticR)) {
5944
- y = verticalPos === 1 /* BelowStaff */ ? Math.max(y, staticR.bottom + objR.toph + objR.centerY) : Math.min(y, staticR.top - objR.bottomh - objR.centerY);
5846
+ y = verticalPos === 1 /* Below */ ? Math.max(y, staticR.bottom + objR.toph + objR.centerY) : Math.min(y, staticR.top - objR.bottomh - objR.centerY);
5945
5847
  }
5946
5848
  });
5947
5849
  });
@@ -5955,6 +5857,15 @@ var LayoutObjectWrapper = class {
5955
5857
  return void 0;
5956
5858
  }
5957
5859
  }
5860
+ layout(renderer) {
5861
+ this.line.addObject(this);
5862
+ }
5863
+ offset(dx, dy) {
5864
+ this.musicObj.offset(dx, dy);
5865
+ }
5866
+ getRect() {
5867
+ return this.musicObj.getRect();
5868
+ }
5958
5869
  };
5959
5870
  var LayoutGroup = class {
5960
5871
  constructor(layoutGroupId) {
@@ -5962,8 +5873,8 @@ var LayoutGroup = class {
5962
5873
  __publicField(this, "layoutObjectTable", []);
5963
5874
  __publicField(this, "rowAlign");
5964
5875
  __publicField(this, "widensColumn");
5965
- this.layoutObjectTable[0 /* AboveStaff */] = [];
5966
- this.layoutObjectTable[1 /* BelowStaff */] = [];
5876
+ this.layoutObjectTable[0 /* Above */] = [];
5877
+ this.layoutObjectTable[1 /* Below */] = [];
5967
5878
  this.rowAlign = RowAlignList.indexOf(layoutGroupId) >= 0;
5968
5879
  this.widensColumn = WidenColumnList.indexOf(layoutGroupId) >= 0;
5969
5880
  }
@@ -5991,94 +5902,427 @@ var LayoutGroup = class {
5991
5902
  }
5992
5903
  };
5993
5904
 
5994
- // src/score/engine/obj-score-row.ts
5995
- import { MusicError as MusicError16, MusicErrorType as MusicErrorType16 } from "@tspro/web-music-score/core";
5996
- var ObjScoreRow = class extends MusicObject {
5997
- constructor(doc, prevRow, scoreConfig) {
5998
- super(doc);
5999
- this.doc = doc;
6000
- this.prevRow = prevRow;
6001
- this.scoreConfig = scoreConfig;
6002
- __publicField(this, "nextRow");
6003
- __publicField(this, "minWidth", 0);
6004
- __publicField(this, "notationLines");
6005
- __publicField(this, "staves");
6006
- __publicField(this, "tabs");
6007
- __publicField(this, "measures", []);
6008
- __publicField(this, "needLayout", true);
6009
- __publicField(this, "mi");
6010
- this.notationLines = this.createNotationLines();
6011
- this.staves = this.notationLines.filter((line) => line instanceof ObjStaff);
6012
- this.tabs = this.notationLines.filter((line) => line instanceof ObjTab);
6013
- if (this.prevRow) {
6014
- this.prevRow.nextRow = this;
6015
- }
6016
- this.mi = new MScoreRow(this);
6017
- }
6018
- getMusicInterface() {
6019
- return this.mi;
6020
- }
6021
- createNotationLines() {
6022
- let notationLines = this.scoreConfig.map((cfg) => cfg.type === "staff" ? new ObjStaff(this, cfg) : new ObjTab(this, cfg));
6023
- for (let i = 0; i < notationLines.length - 1; i++) {
6024
- let treble = notationLines[i];
6025
- let bass = notationLines[i + 1];
6026
- if (treble instanceof ObjStaff && treble.isGrand() && treble.staffConfig.clef === "G" /* G */ && bass instanceof ObjStaff && bass.isGrand() && bass.staffConfig.clef === "F" /* F */) {
6027
- treble.joinGrandStaff(bass);
6028
- bass.joinGrandStaff(treble);
6029
- }
6030
- }
6031
- return notationLines;
6032
- }
6033
- getNotationLines() {
6034
- return this.notationLines;
6035
- }
6036
- getStaves() {
6037
- return this.staves;
6038
- }
6039
- getTabs() {
6040
- return this.tabs;
5905
+ // src/score/engine/obj-staff-and-tab.ts
5906
+ var ObjNotationLine4 = class extends MusicObject {
5907
+ constructor(parent) {
5908
+ super(parent);
5909
+ __publicField(this, "objects", []);
5910
+ __publicField(this, "layoutGroups", []);
6041
5911
  }
6042
- get hasStaff() {
6043
- return this.staves.length > 0;
5912
+ addObject(o) {
5913
+ this.objects.push(o);
6044
5914
  }
6045
- get hasTab() {
6046
- return this.tabs.length > 0;
5915
+ removeObjects() {
5916
+ this.objects.length = 0;
6047
5917
  }
6048
- getTopStaff() {
6049
- let topStaff = this.staves[0];
6050
- if (topStaff) {
6051
- return topStaff;
6052
- } else {
6053
- throw new MusicError16(MusicErrorType16.Score, "Top staff is required!");
5918
+ getLayoutGroup(lauoutGroupId) {
5919
+ let layoutGroup = this.layoutGroups[lauoutGroupId];
5920
+ if (!layoutGroup) {
5921
+ layoutGroup = this.layoutGroups[lauoutGroupId] = new LayoutGroup(lauoutGroupId);
6054
5922
  }
5923
+ return layoutGroup;
6055
5924
  }
6056
- getBottomStaff() {
6057
- let bottomStaff = this.staves[this.staves.length - 1];
6058
- if (bottomStaff) {
6059
- return bottomStaff;
6060
- } else {
6061
- throw new MusicError16(MusicErrorType16.Score, "Bottom staff is required!");
6062
- }
5925
+ resetLayoutGroups(renderer) {
5926
+ this.layoutGroups.forEach((layoutGroup) => {
5927
+ if (layoutGroup) {
5928
+ layoutGroup.clearPositionAndLayout(renderer);
5929
+ }
5930
+ });
6063
5931
  }
6064
- getStaff(diatonicId) {
6065
- Note9.validateDiatonicId(diatonicId);
6066
- for (let i = 0; i < this.notationLines.length; i++) {
6067
- let line = this.notationLines[i];
6068
- if (line instanceof ObjStaff && line.containsDiatonicId(diatonicId)) {
6069
- return line;
5932
+ layoutLayoutGroups(renderer) {
5933
+ this.layoutGroups.forEach((layoutGroup) => {
5934
+ if (layoutGroup) {
5935
+ this.layoutLayoutGroup(renderer, layoutGroup, 0 /* Above */);
5936
+ this.layoutLayoutGroup(renderer, layoutGroup, 1 /* Below */);
6070
5937
  }
6071
- }
6072
- return void 0;
5938
+ });
6073
5939
  }
6074
- pick(x, y) {
6075
- if (!this.getRect().contains(x, y)) {
6076
- return [];
5940
+ setObjectY(layoutObj, y) {
5941
+ if (y === void 0) {
5942
+ return;
6077
5943
  }
6078
- for (let i = 0; i < this.measures.length; i++) {
6079
- let arr = this.measures[i].pick(x, y);
6080
- if (arr.length > 0) {
6081
- return [this, ...arr];
5944
+ layoutObj.offset(0, y - layoutObj.getRect().centerY);
5945
+ layoutObj.setPositionResolved();
5946
+ }
5947
+ alignObjectsY(renderer, layoutObjArr) {
5948
+ layoutObjArr = layoutObjArr.filter((layoutObj) => !layoutObj.isPositionResolved());
5949
+ let rowY;
5950
+ layoutObjArr.forEach((layoutObj) => {
5951
+ let y = layoutObj.resolveClosestToStaffY(renderer);
5952
+ rowY = layoutObj.verticalPos === 1 /* Below */ ? Math.max(y, rowY != null ? rowY : y) : Math.min(y, rowY != null ? rowY : y);
5953
+ });
5954
+ layoutObjArr.forEach((layoutObj) => this.setObjectY(layoutObj, rowY));
5955
+ }
5956
+ layoutLayoutGroup(renderer, layoutGroup, verticalPos) {
5957
+ let rowLayoutObjs = layoutGroup.getLayoutObjects(verticalPos).filter((layoutObj) => !layoutObj.isPositionResolved());
5958
+ rowLayoutObjs.forEach((layoutObj) => {
5959
+ let { musicObj, anchor } = layoutObj;
5960
+ if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine) {
5961
+ musicObj.layoutFitToMeasure(renderer);
5962
+ } else {
5963
+ musicObj.offset(anchor.getRect().centerX - musicObj.getRect().centerX, 0);
5964
+ }
5965
+ });
5966
+ if (layoutGroup.rowAlign) {
5967
+ this.alignObjectsY(renderer, rowLayoutObjs);
5968
+ } else {
5969
+ rowLayoutObjs.forEach((layoutObj) => {
5970
+ let link = layoutObj.musicObj.getLink();
5971
+ if (link && link.getHead() === layoutObj.musicObj) {
5972
+ let objectParts = [link.getHead(), ...link.getTails()];
5973
+ let layoutObjs = rowLayoutObjs.filter((layoutObj2) => objectParts.some((o) => o === layoutObj2.musicObj));
5974
+ this.alignObjectsY(renderer, layoutObjs);
5975
+ } else {
5976
+ this.alignObjectsY(renderer, [layoutObj]);
5977
+ }
5978
+ });
5979
+ }
5980
+ }
5981
+ };
5982
+ var ObjStaff = class extends ObjNotationLine4 {
5983
+ constructor(row, staffConfig, id) {
5984
+ super(row);
5985
+ this.row = row;
5986
+ this.staffConfig = staffConfig;
5987
+ this.id = id;
5988
+ __publicField(this, "clefImageAsset");
5989
+ __publicField(this, "clefLineDiatonicId");
5990
+ __publicField(this, "topLineDiatonicId");
5991
+ __publicField(this, "middleLineDiatonicId");
5992
+ __publicField(this, "bottomLineDiatonicId");
5993
+ __publicField(this, "minDiatonicId");
5994
+ __publicField(this, "maxDiatonicId");
5995
+ __publicField(this, "joinedGrandStaff");
5996
+ __publicField(this, "topLineY", 0);
5997
+ __publicField(this, "bottomLineY", 0);
5998
+ __publicField(this, "mi");
5999
+ const getDiatonicId = (noteName, isOctaveDown) => Note8.getNote(noteName).diatonicId - (isOctaveDown ? 7 : 0);
6000
+ if (staffConfig.clef === "G" /* G */) {
6001
+ this.clefImageAsset = 0 /* TrebleClefPng */;
6002
+ this.clefLineDiatonicId = getDiatonicId("G4", staffConfig.isOctaveDown === true);
6003
+ this.middleLineDiatonicId = this.clefLineDiatonicId + 2;
6004
+ } else {
6005
+ this.clefImageAsset = 1 /* BassClefPng */;
6006
+ this.clefLineDiatonicId = getDiatonicId("F3", staffConfig.isOctaveDown === true);
6007
+ this.middleLineDiatonicId = this.clefLineDiatonicId - 2;
6008
+ }
6009
+ this.topLineDiatonicId = this.middleLineDiatonicId + 4;
6010
+ this.bottomLineDiatonicId = this.middleLineDiatonicId - 4;
6011
+ this.minDiatonicId = staffConfig.minNote !== void 0 ? Math.min(getDiatonicId(staffConfig.minNote, false), this.bottomLineDiatonicId) : void 0;
6012
+ this.maxDiatonicId = staffConfig.maxNote !== void 0 ? Math.max(getDiatonicId(staffConfig.maxNote, false), this.topLineDiatonicId) : void 0;
6013
+ this.mi = new MStaff(this);
6014
+ }
6015
+ getMusicInterface() {
6016
+ return this.mi;
6017
+ }
6018
+ get isOctaveDown() {
6019
+ return this.staffConfig.isOctaveDown === true;
6020
+ }
6021
+ get name() {
6022
+ var _a;
6023
+ return (_a = this.staffConfig.name) != null ? _a : "";
6024
+ }
6025
+ getTopLineY() {
6026
+ return this.topLineY;
6027
+ }
6028
+ getMiddleLineY() {
6029
+ return (this.topLineY + this.bottomLineY) / 2;
6030
+ }
6031
+ getBottomLineY() {
6032
+ return this.bottomLineY;
6033
+ }
6034
+ joinGrandStaff(staff) {
6035
+ if (staff !== this) {
6036
+ this.joinedGrandStaff = staff;
6037
+ }
6038
+ }
6039
+ getLineSpacing() {
6040
+ return (this.bottomLineY - this.topLineY) / 4;
6041
+ }
6042
+ getDiatonicSpacing() {
6043
+ return this.getLineSpacing() / 2;
6044
+ }
6045
+ containsDiatonicId(diatonicId) {
6046
+ Note8.validateDiatonicId(diatonicId);
6047
+ return (this.minDiatonicId === void 0 || diatonicId >= this.minDiatonicId) && (this.maxDiatonicId === void 0 || diatonicId <= this.maxDiatonicId);
6048
+ }
6049
+ getDiatonicIdY(diatonicId) {
6050
+ if (this.containsDiatonicId(diatonicId)) {
6051
+ return this.bottomLineY + (this.bottomLineDiatonicId - diatonicId) * this.getDiatonicSpacing();
6052
+ } else if (this.joinedGrandStaff && this.joinedGrandStaff.containsDiatonicId(diatonicId)) {
6053
+ return this.joinedGrandStaff.getDiatonicIdY(diatonicId);
6054
+ } else {
6055
+ throw new MusicError15(MusicErrorType15.Score, "Staff does not contain diatonicId " + diatonicId);
6056
+ }
6057
+ }
6058
+ getActualStaff(diatonicId) {
6059
+ if (this.containsDiatonicId(diatonicId)) {
6060
+ return this;
6061
+ } else if (this.joinedGrandStaff && this.joinedGrandStaff.containsDiatonicId(diatonicId)) {
6062
+ return this.joinedGrandStaff;
6063
+ } else {
6064
+ throw new MusicError15(MusicErrorType15.Score, "Staff does not contain diatonicId " + diatonicId);
6065
+ }
6066
+ }
6067
+ getDiatonicIdAt(y) {
6068
+ let diatonicId = Math.round(this.bottomLineDiatonicId - (y - this.bottomLineY) / this.getDiatonicSpacing());
6069
+ return this.containsDiatonicId(diatonicId) ? diatonicId : void 0;
6070
+ }
6071
+ isLine(diatonicId) {
6072
+ return diatonicId % 2 === this.middleLineDiatonicId % 2;
6073
+ }
6074
+ isSpace(diatonicId) {
6075
+ return diatonicId % 2 !== this.middleLineDiatonicId % 2;
6076
+ }
6077
+ containsVoiceId(voiceId) {
6078
+ return !this.staffConfig.voiceIds || this.staffConfig.voiceIds.includes(voiceId);
6079
+ }
6080
+ isGrand() {
6081
+ return this.staffConfig.isGrand === true;
6082
+ }
6083
+ calcTop() {
6084
+ let top = this.topLineY;
6085
+ this.objects.forEach((o) => top = Math.min(top, o.getRect().top));
6086
+ if (this.maxDiatonicId !== void 0) {
6087
+ let y = this.getDiatonicIdY(this.maxDiatonicId);
6088
+ let y2 = this.getDiatonicIdY(this.maxDiatonicId - 1);
6089
+ top = Math.min(top, y - Math.abs(y2 - y) + 1);
6090
+ }
6091
+ return top;
6092
+ }
6093
+ calcBottom() {
6094
+ let bottom = this.bottomLineY;
6095
+ this.objects.forEach((o) => bottom = Math.max(bottom, o.getRect().bottom));
6096
+ if (this.minDiatonicId !== void 0) {
6097
+ let y = this.getDiatonicIdY(this.minDiatonicId);
6098
+ let y2 = this.getDiatonicIdY(this.minDiatonicId + 1);
6099
+ bottom = Math.max(bottom, y + Math.abs(y2 - y) - 1);
6100
+ }
6101
+ return bottom;
6102
+ }
6103
+ pick(x, y) {
6104
+ return [this];
6105
+ }
6106
+ layoutHeight(renderer) {
6107
+ let { unitSize } = renderer;
6108
+ let h = unitSize * DocumentSettings.StaffHeight;
6109
+ this.topLineY = -h / 2;
6110
+ this.bottomLineY = h / 2;
6111
+ this.rect = new DivRect(0, 0, this.topLineY, this.bottomLineY);
6112
+ }
6113
+ layoutWidth(renderer) {
6114
+ this.rect.left = this.row.getRect().left;
6115
+ this.rect.right = this.row.getRect().right;
6116
+ }
6117
+ offset(dx, dy) {
6118
+ this.topLineY += dy;
6119
+ this.bottomLineY += dy;
6120
+ this.objects.forEach((o) => {
6121
+ if (o.offsetInPlace) {
6122
+ o.offsetInPlace(0, dy);
6123
+ } else if (o.offset) {
6124
+ o.offset(0, dy);
6125
+ }
6126
+ });
6127
+ this.rect.offsetInPlace(dx, dy);
6128
+ }
6129
+ draw(renderer) {
6130
+ }
6131
+ };
6132
+ var ObjTab = class extends ObjNotationLine4 {
6133
+ constructor(row, tabConfig, id) {
6134
+ super(row);
6135
+ this.row = row;
6136
+ this.tabConfig = tabConfig;
6137
+ this.id = id;
6138
+ __publicField(this, "top", 0);
6139
+ __publicField(this, "bottom", 0);
6140
+ __publicField(this, "tuningName");
6141
+ __publicField(this, "tuningStrings");
6142
+ __publicField(this, "mi");
6143
+ if (Utils9.Is.isArray(tabConfig.tuning)) {
6144
+ this.tuningName = void 0;
6145
+ this.tuningStrings = tabConfig.tuning.map((noteName) => Note8.getNote(noteName)).reverse();
6146
+ } else if (typeof tabConfig.tuning === "string") {
6147
+ this.tuningName = validateTuningName(tabConfig.tuning);
6148
+ this.tuningStrings = getTuningStrings(this.tuningName);
6149
+ } else {
6150
+ this.tuningName = "Standard";
6151
+ this.tuningStrings = getTuningStrings(this.tuningName);
6152
+ }
6153
+ this.mi = new MTab(this);
6154
+ }
6155
+ getMusicInterface() {
6156
+ return this.mi;
6157
+ }
6158
+ get name() {
6159
+ var _a;
6160
+ return (_a = this.tabConfig.name) != null ? _a : "";
6161
+ }
6162
+ getTuningName() {
6163
+ return this.tuningName;
6164
+ }
6165
+ getTuningStrings() {
6166
+ return this.tuningStrings;
6167
+ }
6168
+ /** Return Y coordinate of string. */
6169
+ getStringY(stringId) {
6170
+ return this.top + (this.bottom - this.top) / 6 * (stringId + 0.5);
6171
+ }
6172
+ getTopStringY() {
6173
+ return this.getStringY(0);
6174
+ }
6175
+ getBottomStringY() {
6176
+ return this.getStringY(5);
6177
+ }
6178
+ getTopLineY() {
6179
+ return this.getTopStringY();
6180
+ }
6181
+ getBottomLineY() {
6182
+ return this.getBottomStringY();
6183
+ }
6184
+ getTop() {
6185
+ return this.top;
6186
+ }
6187
+ getBottom() {
6188
+ return this.bottom;
6189
+ }
6190
+ containsVoiceId(voiceId) {
6191
+ return !this.tabConfig.voiceIds || this.tabConfig.voiceIds.includes(voiceId);
6192
+ }
6193
+ containsDiatonicId(diatonicId) {
6194
+ return true;
6195
+ }
6196
+ calcTop() {
6197
+ return this.top;
6198
+ }
6199
+ calcBottom() {
6200
+ return this.bottom;
6201
+ }
6202
+ pick(x, y) {
6203
+ return [this];
6204
+ }
6205
+ layoutHeight(renderer) {
6206
+ let { unitSize } = renderer;
6207
+ let h = unitSize * DocumentSettings.TabHeight;
6208
+ this.top = -h / 2;
6209
+ this.bottom = h / 2;
6210
+ this.rect = new DivRect(0, 0, this.top, this.bottom);
6211
+ }
6212
+ layoutWidth(renderer) {
6213
+ this.rect.left = this.row.getRect().left;
6214
+ this.rect.right = this.row.getRect().right;
6215
+ }
6216
+ offset(dx, dy) {
6217
+ this.top += dy;
6218
+ this.bottom += dy;
6219
+ this.objects.forEach((o) => {
6220
+ if (o.offsetInPlace) {
6221
+ o.offsetInPlace(0, dy);
6222
+ } else if (o.offset) {
6223
+ o.offset(0, dy);
6224
+ }
6225
+ });
6226
+ this.rect.offsetInPlace(dx, dy);
6227
+ }
6228
+ draw(renderer) {
6229
+ }
6230
+ };
6231
+
6232
+ // src/score/engine/obj-score-row.ts
6233
+ import { MusicError as MusicError16, MusicErrorType as MusicErrorType16 } from "@tspro/web-music-score/core";
6234
+ var ObjScoreRow = class extends MusicObject {
6235
+ constructor(doc, prevRow, scoreConfig) {
6236
+ super(doc);
6237
+ this.doc = doc;
6238
+ this.prevRow = prevRow;
6239
+ this.scoreConfig = scoreConfig;
6240
+ __publicField(this, "nextRow");
6241
+ __publicField(this, "minWidth", 0);
6242
+ __publicField(this, "notationLines");
6243
+ __publicField(this, "staves");
6244
+ __publicField(this, "tabs");
6245
+ __publicField(this, "measures", []);
6246
+ __publicField(this, "needLayout", true);
6247
+ __publicField(this, "mi");
6248
+ this.notationLines = this.createNotationLines();
6249
+ this.staves = this.notationLines.filter((line) => line instanceof ObjStaff);
6250
+ this.tabs = this.notationLines.filter((line) => line instanceof ObjTab);
6251
+ if (this.prevRow) {
6252
+ this.prevRow.nextRow = this;
6253
+ }
6254
+ this.mi = new MScoreRow(this);
6255
+ }
6256
+ getMusicInterface() {
6257
+ return this.mi;
6258
+ }
6259
+ createNotationLines() {
6260
+ let notationLines = this.scoreConfig.map((cfg, index) => cfg.type === "staff" ? new ObjStaff(this, cfg, index) : new ObjTab(this, cfg, index));
6261
+ for (let i = 0; i < notationLines.length - 1; i++) {
6262
+ let treble = notationLines[i];
6263
+ let bass = notationLines[i + 1];
6264
+ if (treble instanceof ObjStaff && treble.isGrand() && treble.staffConfig.clef === "G" /* G */ && bass instanceof ObjStaff && bass.isGrand() && bass.staffConfig.clef === "F" /* F */) {
6265
+ treble.joinGrandStaff(bass);
6266
+ bass.joinGrandStaff(treble);
6267
+ }
6268
+ }
6269
+ return notationLines;
6270
+ }
6271
+ getNotationLines() {
6272
+ return this.notationLines;
6273
+ }
6274
+ getStaves() {
6275
+ return this.staves;
6276
+ }
6277
+ getTabs() {
6278
+ return this.tabs;
6279
+ }
6280
+ get hasStaff() {
6281
+ return this.staves.length > 0;
6282
+ }
6283
+ get hasTab() {
6284
+ return this.tabs.length > 0;
6285
+ }
6286
+ getTopStaff() {
6287
+ let topStaff = this.staves[0];
6288
+ if (topStaff) {
6289
+ return topStaff;
6290
+ } else {
6291
+ throw new MusicError16(MusicErrorType16.Score, "Top staff is required!");
6292
+ }
6293
+ }
6294
+ getBottomStaff() {
6295
+ let bottomStaff = this.staves[this.staves.length - 1];
6296
+ if (bottomStaff) {
6297
+ return bottomStaff;
6298
+ } else {
6299
+ throw new MusicError16(MusicErrorType16.Score, "Bottom staff is required!");
6300
+ }
6301
+ }
6302
+ getStaff(diatonicId) {
6303
+ Note9.validateDiatonicId(diatonicId);
6304
+ for (let i = 0; i < this.notationLines.length; i++) {
6305
+ let line = this.notationLines[i];
6306
+ if (line instanceof ObjStaff && line.containsDiatonicId(diatonicId)) {
6307
+ return line;
6308
+ }
6309
+ }
6310
+ return void 0;
6311
+ }
6312
+ resetLayoutGroups(renderer) {
6313
+ this.notationLines.forEach((line) => line.resetLayoutGroups(renderer));
6314
+ }
6315
+ layoutLayoutGroups(renderer) {
6316
+ this.notationLines.forEach((line) => line.layoutLayoutGroups(renderer));
6317
+ }
6318
+ pick(x, y) {
6319
+ if (!this.getRect().contains(x, y)) {
6320
+ return [];
6321
+ }
6322
+ for (let i = 0; i < this.measures.length; i++) {
6323
+ let arr = this.measures[i].pick(x, y);
6324
+ if (arr.length > 0) {
6325
+ return [this, ...arr];
6082
6326
  }
6083
6327
  }
6084
6328
  for (let i = 0; i < this.notationLines.length; i++) {
@@ -6151,7 +6395,6 @@ var ObjScoreRow = class extends MusicObject {
6151
6395
  this.minWidth = 0;
6152
6396
  this.measures.forEach((m) => {
6153
6397
  m.layout(renderer);
6154
- this.rect.expandInPlace(new DivRect(0, 0, m.getRect().top, m.getRect().bottom));
6155
6398
  this.minWidth += m.getMinWidth();
6156
6399
  this.minWidth += m.getPostMeasureBreakWidth();
6157
6400
  });
@@ -6185,6 +6428,13 @@ var ObjScoreRow = class extends MusicObject {
6185
6428
  m.layoutBeams(renderer);
6186
6429
  });
6187
6430
  }
6431
+ updateRect() {
6432
+ let left = this.measures.length > 0 ? this.measures[0].getRect().left : 0;
6433
+ let right = this.measures.length > 0 ? this.measures[this.measures.length - 1].getRect().right : 0;
6434
+ let top = Math.min(0, ...this.measures.map((m) => m.getRect().top));
6435
+ let bottom = Math.max(0, ...this.measures.map((m) => m.getRect().bottom));
6436
+ this.rect = new DivRect(left, right, top, bottom);
6437
+ }
6188
6438
  alignStemsToBeams() {
6189
6439
  this.measures.forEach((m) => m.alignStemsToBeams());
6190
6440
  }
@@ -6201,7 +6451,6 @@ var ObjScoreRow = class extends MusicObject {
6201
6451
  cur.offset(0, prev.calcBottom() - cur.calcTop() + sep);
6202
6452
  }
6203
6453
  }
6204
- this.requestRectUpdate();
6205
6454
  this.measures.forEach((m) => {
6206
6455
  m.requestRectUpdate();
6207
6456
  m.getBarLineLeft().requestRectUpdate();
@@ -6214,59 +6463,12 @@ var ObjScoreRow = class extends MusicObject {
6214
6463
  });
6215
6464
  });
6216
6465
  });
6217
- let lines = this.getNotationLines();
6218
- this.rect.top = lines[0].calcTop();
6219
- this.rect.bottom = lines[lines.length - 1].calcBottom();
6220
6466
  this.alignStemsToBeams();
6221
- }
6222
- updateRect() {
6223
- }
6224
- setObjectY(layoutObj, y) {
6225
- if (y === void 0) {
6226
- return;
6227
- }
6228
- let { measure, musicObj } = layoutObj;
6229
- musicObj.offset(0, y - musicObj.getRect().centerY);
6230
- layoutObj.setPositionResolved();
6231
- measure.getRect().expandInPlace(musicObj.getRect());
6232
- this.rect.expandInPlace(measure.getRect());
6233
- }
6234
- alignObjectsY(renderer, layoutObjArr) {
6235
- layoutObjArr = layoutObjArr.filter((layoutObj) => !layoutObj.isPositionResolved());
6236
- let rowY;
6237
- layoutObjArr.forEach((layoutObj) => {
6238
- let y = layoutObj.resolveClosestToStaffY(renderer);
6239
- rowY = layoutObj.verticalPos === 1 /* BelowStaff */ ? Math.max(y, rowY != null ? rowY : y) : Math.min(y, rowY != null ? rowY : y);
6240
- });
6241
- layoutObjArr.forEach((layoutObj) => this.setObjectY(layoutObj, rowY));
6242
- }
6243
- layoutLayoutGroup(renderer, layoutGroup, verticalPos) {
6244
- let rowLayoutObjs = layoutGroup.getLayoutObjects(verticalPos).filter((layoutObj) => layoutObj.row === this && !layoutObj.isPositionResolved());
6245
- rowLayoutObjs.forEach((layoutObj) => {
6246
- let { musicObj, anchor } = layoutObj;
6247
- if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine) {
6248
- musicObj.layoutFitToMeasure(renderer);
6249
- } else {
6250
- musicObj.offset(anchor.getRect().centerX - musicObj.getRect().centerX, 0);
6251
- }
6252
- });
6253
- if (layoutGroup.rowAlign) {
6254
- this.alignObjectsY(renderer, rowLayoutObjs);
6255
- } else {
6256
- rowLayoutObjs.forEach((layoutObj) => {
6257
- let link = layoutObj.musicObj.getLink();
6258
- if (link && link.getHead() === layoutObj.musicObj) {
6259
- let objectParts = [link.getHead(), ...link.getTails()];
6260
- let layoutObjs = rowLayoutObjs.filter((layoutObj2) => objectParts.some((o) => o === layoutObj2.musicObj));
6261
- this.alignObjectsY(renderer, layoutObjs);
6262
- } else {
6263
- this.alignObjectsY(renderer, [layoutObj]);
6264
- }
6265
- });
6266
- }
6467
+ this.requestRectUpdate();
6267
6468
  }
6268
6469
  layoutPadding(renderer) {
6269
6470
  let p = renderer.unitSize / 2;
6471
+ this.getRect();
6270
6472
  this.rect.left -= p;
6271
6473
  this.rect.right += p;
6272
6474
  this.rect.top -= p;
@@ -6290,21 +6492,10 @@ var ObjScoreRow = class extends MusicObject {
6290
6492
  ctx.save();
6291
6493
  ctx.rect(this.getRect().left, this.getRect().top, this.getRect().width, this.getRect().height);
6292
6494
  ctx.clip();
6293
- if (this.getFirstMeasure() && this.notationLines.length > 1 || this.notationLines.length === 1 && this.notationLines[0] instanceof ObjTab) {
6495
+ if (this.getFirstMeasure() && (this.notationLines.length > 1 || this.notationLines[0] instanceof ObjTab)) {
6294
6496
  let left = this.getFirstMeasure().getStaffLineLeft();
6295
- let tops = [];
6296
- let bottoms = [];
6297
- this.notationLines.forEach((line) => {
6298
- if (line instanceof ObjStaff) {
6299
- tops.push(line.getTopLineY());
6300
- bottoms.push(line.getBottomLineY());
6301
- } else {
6302
- tops.push(line.getTopStringY());
6303
- bottoms.push(line.getBottomStringY());
6304
- }
6305
- });
6306
- let top = Math.min(...tops);
6307
- let bottom = Math.max(...bottoms);
6497
+ let top = Math.min(...this.notationLines.map((line) => line.getTopLineY()));
6498
+ let bottom = Math.max(...this.notationLines.map((line) => line.getBottomLineY()));
6308
6499
  renderer.drawLine(left, top, left, bottom);
6309
6500
  }
6310
6501
  this.measures.forEach((m) => m.draw(renderer));
@@ -6415,9 +6606,9 @@ var ObjDocument = class extends MusicObject {
6415
6606
  __publicField(this, "measuresPerRow", Infinity);
6416
6607
  __publicField(this, "curScoreConfig", [{ type: "staff", clef: "G" /* G */ }]);
6417
6608
  __publicField(this, "header");
6418
- __publicField(this, "layoutGroups", []);
6419
6609
  __publicField(this, "newRowRequested", false);
6420
6610
  __publicField(this, "allConnectiveProps", []);
6611
+ __publicField(this, "staffGroups", /* @__PURE__ */ new Map());
6421
6612
  __publicField(this, "mi");
6422
6613
  this.mi = new MDocument2(this);
6423
6614
  }
@@ -6483,13 +6674,6 @@ var ObjDocument = class extends MusicObject {
6483
6674
  addConnectiveProps(connectiveProps) {
6484
6675
  this.allConnectiveProps.push(connectiveProps);
6485
6676
  }
6486
- getLayoutGroup(lauoutGroupId) {
6487
- let layoutGroup = this.layoutGroups[lauoutGroupId];
6488
- if (!layoutGroup) {
6489
- layoutGroup = this.layoutGroups[lauoutGroupId] = new LayoutGroup(lauoutGroupId);
6490
- }
6491
- return layoutGroup;
6492
- }
6493
6677
  setRenderer(renderer) {
6494
6678
  if (this.renderer === renderer) {
6495
6679
  return;
@@ -6555,6 +6739,12 @@ var ObjDocument = class extends MusicObject {
6555
6739
  this.requestLayout();
6556
6740
  return measure;
6557
6741
  }
6742
+ addStaffGroup(groupName, layoutElements, verticalPosition) {
6743
+ this.staffGroups.set(groupName, new StaffGroup(groupName, layoutElements, verticalPosition));
6744
+ }
6745
+ getStaffGroup(groupName) {
6746
+ return this.staffGroups.get(groupName);
6747
+ }
6558
6748
  getVoiceSymbols(voiceId) {
6559
6749
  let voiceSymbols = [];
6560
6750
  this.forEachMeasure((m) => voiceSymbols = voiceSymbols.concat(m.getVoiceSymbols(voiceId)));
@@ -6602,21 +6792,15 @@ var ObjDocument = class extends MusicObject {
6602
6792
  this.forEachMeasure((m) => m.createExtensions());
6603
6793
  this.allConnectiveProps.forEach((props) => props.removeConnectives());
6604
6794
  this.allConnectiveProps.forEach((props) => props.createConnectives());
6605
- let layoutGroups = this.layoutGroups.filter((layoutGroup) => !!layoutGroup);
6606
- layoutGroups.forEach((layoutGroup) => layoutGroup.clearPositionAndLayout(renderer));
6795
+ this.rows.forEach((row) => row.resetLayoutGroups(renderer));
6607
6796
  this.rows.forEach((row) => row.layout(renderer));
6608
6797
  let rowWidth = Math.max(
6609
6798
  DocumentSettings.DocumentMinWidth * unitSize,
6610
6799
  ...this.rows.map((row) => 1.4 * row.getMinWidth())
6611
6800
  );
6612
6801
  this.rows.forEach((row) => row.layoutWidth(renderer, rowWidth));
6802
+ this.rows.forEach((row) => row.layoutLayoutGroups(renderer));
6613
6803
  this.rows.forEach((row) => row.layoutPositionLines(renderer));
6614
- layoutGroups.forEach((layoutGroup) => {
6615
- this.rows.forEach((row) => {
6616
- row.layoutLayoutGroup(renderer, layoutGroup, 0 /* AboveStaff */);
6617
- row.layoutLayoutGroup(renderer, layoutGroup, 1 /* BelowStaff */);
6618
- });
6619
- });
6620
6804
  this.rows.forEach((row) => row.layoutPadding(renderer));
6621
6805
  this.rect = new DivRect();
6622
6806
  if (this.header) {
@@ -6740,6 +6924,15 @@ function assertRestOptions(options) {
6740
6924
  assertArg(Utils11.Is.isBooleanOrUndefined(options.hide), "restOptions.hide", options.hide);
6741
6925
  assertArg(Utils11.Is.isBooleanOrUndefined(options.triplet), "restOptions.triplet", options.triplet);
6742
6926
  }
6927
+ function assertStaffTabOrGRoups(staffTabOrGroups) {
6928
+ assertArg(
6929
+ Utils11.Is.isStringOrUndefined(staffTabOrGroups) || Utils11.Is.isIntegerGte(staffTabOrGroups, 0) || Utils11.Is.isArray(staffTabOrGroups) && staffTabOrGroups.every(
6930
+ (staffTabOrGroup) => Utils11.Is.isString(staffTabOrGroup) || Utils11.Is.isIntegerGte(staffTabOrGroup, 0)
6931
+ ),
6932
+ "staffTabOrGroup",
6933
+ staffTabOrGroups
6934
+ );
6935
+ }
6743
6936
  var DocumentBuilder = class {
6744
6937
  constructor() {
6745
6938
  __publicField(this, "doc");
@@ -6841,21 +7034,64 @@ var DocumentBuilder = class {
6841
7034
  this.getMeasure().addRest(voiceId, restLength, options);
6842
7035
  return this;
6843
7036
  }
6844
- addFermata(fermata) {
6845
- assertArg(Utils11.Is.isEnumValueOrUndefined(fermata, Fermata), "fermata", fermata);
6846
- this.getMeasure().addFermata(fermata != null ? fermata : 0 /* AtNote */);
7037
+ addFermataInternal(staffTabOrGroups, fermata) {
7038
+ assertStaffTabOrGRoups(staffTabOrGroups);
7039
+ assertArg(Utils11.Is.isEnumValue(fermata, Fermata), "fermata", fermata);
7040
+ this.getMeasure().addFermata(staffTabOrGroups, fermata);
6847
7041
  return this;
6848
7042
  }
6849
- addNavigation(navigation, ...args) {
7043
+ addFermata(fermata = 0 /* AtNote */) {
7044
+ return this.addFermataInternal(void 0, fermata);
7045
+ }
7046
+ /** @param staffTabOrGroups - staff/tab index (0=top), staff/tab name, or staff group name. */
7047
+ addFermataTo(staffTabOrGroups, fermata = 0 /* AtNote */) {
7048
+ return this.addFermataInternal(staffTabOrGroups, fermata);
7049
+ }
7050
+ addNavigationInternal(staffTabOrGroups, navigation, ...args) {
7051
+ assertStaffTabOrGRoups(staffTabOrGroups);
6850
7052
  assertArg(Utils11.Is.isEnumValue(navigation, Navigation), "navigation", navigation);
6851
7053
  if (navigation === 9 /* EndRepeat */ && args.length > 0) {
6852
7054
  assertArg(Utils11.Is.isIntegerGte(args[0], 1), "playCount", args[0]);
6853
7055
  } else if (navigation === 10 /* Ending */ && args.length > 0) {
6854
7056
  assertArg(args.every((passage) => Utils11.Is.isIntegerGte(passage, 1)), "passages", args);
6855
7057
  }
6856
- this.getMeasure().addNavigation(navigation, ...args);
7058
+ this.getMeasure().addNavigation(staffTabOrGroups, navigation, ...args);
7059
+ return this;
7060
+ }
7061
+ addNavigation(navigation, ...args) {
7062
+ return this.addNavigationInternal(void 0, navigation, ...args);
7063
+ }
7064
+ addNavigationTo(staffTabOrGroups, navigation, ...args) {
7065
+ return this.addNavigationInternal(staffTabOrGroups, navigation, ...args);
7066
+ }
7067
+ addLabelInternal(staffTabOrGroups, label, text) {
7068
+ assertStaffTabOrGRoups(staffTabOrGroups);
7069
+ assertArg(Utils11.Is.isEnumValue(label, Label), "label", label);
7070
+ assertArg(Utils11.Is.isString(text), "text", text);
7071
+ this.getMeasure().addLabel(staffTabOrGroups, label, text);
7072
+ return this;
7073
+ }
7074
+ addLabel(label, text) {
7075
+ return this.addLabelInternal(void 0, label, text);
7076
+ }
7077
+ /** @param staffTabOrGroups - staff/tab index (0=top), staff/tab name, or staff group name. */
7078
+ addLabelTo(staffTabOrGroups, label, text) {
7079
+ return this.addLabelInternal(staffTabOrGroups, label, text);
7080
+ }
7081
+ addAnnotationInternal(staffTabOrGroups, annotation, text) {
7082
+ assertStaffTabOrGRoups(staffTabOrGroups);
7083
+ assertArg(Utils11.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
7084
+ assertArg(Utils11.Is.isString(text), "text", text);
7085
+ this.getMeasure().addAnnotation(staffTabOrGroups, annotation, text);
6857
7086
  return this;
6858
7087
  }
7088
+ addAnnotation(annotation, text) {
7089
+ return this.addAnnotationInternal(void 0, annotation, text);
7090
+ }
7091
+ /** @param staffTabOrGroups - staff/tab index (0=top), staff/tab name, or staff group name. */
7092
+ addAnnotationTo(staffTabOrGroups, annotation, text) {
7093
+ return this.addAnnotationInternal(staffTabOrGroups, annotation, text);
7094
+ }
6859
7095
  addConnective(connective, ...args) {
6860
7096
  assertArg(Utils11.Is.isEnumValue(connective, Connective), "connective", connective);
6861
7097
  if (connective === 0 /* Tie */) {
@@ -6877,24 +7113,30 @@ var DocumentBuilder = class {
6877
7113
  }
6878
7114
  return this;
6879
7115
  }
6880
- addLabel(label, text) {
6881
- assertArg(Utils11.Is.isEnumValue(label, Label), "label", label);
6882
- assertArg(Utils11.Is.isString(text), "text", text);
6883
- this.getMeasure().addLabel(label, text);
6884
- return this;
6885
- }
6886
- addAnnotation(annotation, text) {
6887
- assertArg(Utils11.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
6888
- assertArg(Utils11.Is.isString(text), "text", text);
6889
- this.getMeasure().addAnnotation(annotation, text);
6890
- return this;
6891
- }
6892
7116
  addExtension(extensionLength, extensionVisible) {
6893
7117
  assertArg(Utils11.Is.isIntegerGte(extensionLength, 0) || extensionLength === Infinity || Utils11.Is.isEnumValue(extensionLength, NoteLength7), "extendionLength", extensionLength);
6894
7118
  assertArg(Utils11.Is.isBooleanOrUndefined(extensionVisible), "extensionVisible", extensionVisible);
6895
7119
  this.getMeasure().addExtension(extensionLength, extensionVisible != null ? extensionVisible : true);
6896
7120
  return this;
6897
7121
  }
7122
+ /**
7123
+ *
7124
+ * @param groupName - Name of staff group.
7125
+ * @param staffsTabsAndGroups - staff/tab index (0=top), staff/tab name, or staff group name. Single value or array.
7126
+ * @param verticalPosition - Vertical position, are elements added above, below or both.
7127
+ * @returns
7128
+ */
7129
+ addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition = 3 /* Auto */) {
7130
+ assertArg(Utils11.Is.isString(groupName) && groupName.length > 0, "groupName", groupName);
7131
+ assertArg(
7132
+ 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)),
7133
+ "staffsTabsAndGroups",
7134
+ staffsTabsAndGroups
7135
+ );
7136
+ assertArg(Utils11.Is.isEnumValue(verticalPosition, VerticalPosition), "verticalPosition", verticalPosition);
7137
+ this.doc.addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition);
7138
+ return this;
7139
+ }
6898
7140
  endSong() {
6899
7141
  this.getMeasure().endSong();
6900
7142
  return this;
@@ -7665,6 +7907,7 @@ export {
7665
7907
  StaffPreset,
7666
7908
  Stem,
7667
7909
  TieType,
7910
+ VerticalPosition,
7668
7911
  getStringNumbers,
7669
7912
  getVoiceIds
7670
7913
  };