@tspro/web-music-score 4.2.1 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +63 -26
  3. package/dist/audio/index.d.mts +23 -27
  4. package/dist/audio/index.d.ts +23 -27
  5. package/dist/audio/index.js +63 -85
  6. package/dist/audio/index.mjs +53 -73
  7. package/dist/audio-cg/index.d.mts +18 -3
  8. package/dist/audio-cg/index.d.ts +18 -3
  9. package/dist/audio-cg/index.js +54 -51
  10. package/dist/audio-cg/index.mjs +49 -52
  11. package/dist/audio-synth/index.d.mts +15 -0
  12. package/dist/audio-synth/index.d.ts +15 -0
  13. package/dist/audio-synth/index.js +95 -0
  14. package/dist/audio-synth/index.mjs +58 -0
  15. package/dist/{chunk-64N22LCV.mjs → chunk-2EQHSQWO.mjs} +2 -2
  16. package/dist/{chunk-RQFFLRWF.mjs → chunk-QVYFIK3L.mjs} +5 -6
  17. package/dist/chunk-ROPTZBKD.mjs +11 -0
  18. package/dist/core/index.d.mts +2 -1
  19. package/dist/core/index.d.ts +2 -1
  20. package/dist/core/index.js +3 -2
  21. package/dist/core/index.mjs +4 -3
  22. package/dist/iife/audio-cg.global.js +220 -0
  23. package/dist/iife/index.global.js +11 -11
  24. package/dist/instrument-DYboobMW.d.mts +44 -0
  25. package/dist/instrument-DYboobMW.d.ts +44 -0
  26. package/dist/{music-objects-CI7IjsjE.d.ts → music-objects-CMdYZeC6.d.ts} +118 -36
  27. package/dist/{music-objects-3Hxlkxy6.d.mts → music-objects-DTDFSro0.d.mts} +118 -36
  28. package/dist/pieces/index.d.mts +1 -1
  29. package/dist/pieces/index.d.ts +1 -1
  30. package/dist/pieces/index.js +1 -1
  31. package/dist/pieces/index.mjs +2 -2
  32. package/dist/react-ui/index.d.mts +52 -33
  33. package/dist/react-ui/index.d.ts +52 -33
  34. package/dist/react-ui/index.js +41 -32
  35. package/dist/react-ui/index.mjs +42 -33
  36. package/dist/score/index.d.mts +8 -8
  37. package/dist/score/index.d.ts +8 -8
  38. package/dist/score/index.js +1998 -1626
  39. package/dist/score/index.mjs +1584 -1211
  40. package/dist/theory/index.js +3 -4
  41. package/dist/theory/index.mjs +3 -3
  42. package/package.json +13 -3
@@ -1,10 +1,12 @@
1
- /* WebMusicScore v4.2.1 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
1
+ /* WebMusicScore v5.1.0 | (c) 2023 PahkaSoft | MIT License | Includes: Tone.js (MIT License) */
2
2
  import {
3
- RhythmProps
4
- } from "../chunk-RQFFLRWF.mjs";
3
+ NoteLengthProps,
4
+ RhythmProps,
5
+ validateNoteLength
6
+ } from "../chunk-QVYFIK3L.mjs";
5
7
  import {
6
8
  __publicField
7
- } from "../chunk-64N22LCV.mjs";
9
+ } from "../chunk-2EQHSQWO.mjs";
8
10
 
9
11
  // src/score/pub/div-rect.ts
10
12
  import { Utils } from "@tspro/ts-utils-lib";
@@ -286,7 +288,7 @@ var DivRect = class _DivRect {
286
288
  };
287
289
 
288
290
  // src/score/pub/document-builder.ts
289
- import { Utils as Utils14 } from "@tspro/ts-utils-lib";
291
+ import { Utils as Utils15 } from "@tspro/ts-utils-lib";
290
292
 
291
293
  // src/score/pub/types.ts
292
294
  var StaffPreset = /* @__PURE__ */ ((StaffPreset3) => {
@@ -298,10 +300,10 @@ var StaffPreset = /* @__PURE__ */ ((StaffPreset3) => {
298
300
  StaffPreset3["GuitarCombined"] = "guitarCombined";
299
301
  return StaffPreset3;
300
302
  })(StaffPreset || {});
301
- var Clef = /* @__PURE__ */ ((Clef2) => {
302
- Clef2["G"] = "G";
303
- Clef2["F"] = "F";
304
- return Clef2;
303
+ var Clef = /* @__PURE__ */ ((Clef4) => {
304
+ Clef4["G"] = "G";
305
+ Clef4["F"] = "F";
306
+ return Clef4;
305
307
  })(Clef || {});
306
308
  function getVoiceIds() {
307
309
  return [0, 1, 2, 3];
@@ -910,15 +912,140 @@ var Renderer = class {
910
912
  }
911
913
  }
912
914
  }
915
+ getRestRect(restSize) {
916
+ let { unitSize } = this;
917
+ let { flagCount } = NoteLengthProps.get(validateNoteLength(restSize + "n"));
918
+ let leftw = 0;
919
+ let rightw = 0;
920
+ let toph = 0;
921
+ let bottomh = 0;
922
+ if (NoteLengthProps.equals(restSize, "1n" /* Whole */)) {
923
+ leftw = unitSize;
924
+ rightw = unitSize;
925
+ toph = 0;
926
+ bottomh = unitSize;
927
+ } else if (NoteLengthProps.equals(restSize, "2n" /* Half */)) {
928
+ leftw = unitSize;
929
+ rightw = unitSize;
930
+ toph = unitSize;
931
+ bottomh = 0;
932
+ } else if (NoteLengthProps.equals(restSize, "4n" /* Quarter */)) {
933
+ leftw = unitSize * 1;
934
+ rightw = unitSize * 1;
935
+ toph = unitSize * 3.2;
936
+ bottomh = unitSize * 3;
937
+ } else {
938
+ let adj = 1 - flagCount % 2;
939
+ leftw = unitSize * (1 + flagCount * 0.25);
940
+ rightw = unitSize * (1 + flagCount * 0.125);
941
+ toph = unitSize * (0.5 + flagCount - adj);
942
+ bottomh = unitSize * (1 + flagCount + adj);
943
+ }
944
+ return new DivRect(-leftw, 0, rightw, -toph, 0, bottomh);
945
+ }
946
+ drawRest(restSize, x, y, color) {
947
+ let ctx = this.getCanvasContext();
948
+ if (!ctx) {
949
+ return;
950
+ }
951
+ let { unitSize, lineWidth } = this;
952
+ let { flagCount } = NoteLengthProps.get(validateNoteLength(restSize + "n"));
953
+ ctx.strokeStyle = ctx.fillStyle = color;
954
+ ctx.lineWidth = lineWidth;
955
+ if (NoteLengthProps.equals(restSize, "1n" /* Whole */)) {
956
+ ctx.fillRect(x - unitSize, y, unitSize * 2, unitSize);
957
+ } else if (NoteLengthProps.equals(restSize, "2n" /* Half */)) {
958
+ ctx.fillRect(x - unitSize, y - unitSize, unitSize * 2, unitSize);
959
+ } else if (NoteLengthProps.equals(restSize, "4n" /* Quarter */)) {
960
+ ctx.beginPath();
961
+ ctx.moveTo(x - unitSize * 0.6, y - unitSize * 3.2);
962
+ ctx.lineTo(x + unitSize * 0.7, y - unitSize * 1.5);
963
+ ctx.quadraticCurveTo(
964
+ x - unitSize * 0.8,
965
+ y - unitSize * 0.5,
966
+ x + unitSize * 1,
967
+ y + unitSize * 1.5
968
+ );
969
+ ctx.lineTo(x - unitSize * 1, y - unitSize * 0.75);
970
+ ctx.quadraticCurveTo(
971
+ x + unitSize * 0.2,
972
+ y - unitSize * 1.5,
973
+ x - unitSize * 0.6,
974
+ y - unitSize * 3.2
975
+ );
976
+ ctx.moveTo(x + unitSize * 1, y + unitSize * 1.5);
977
+ ctx.quadraticCurveTo(
978
+ x - unitSize * 0.8,
979
+ y + unitSize * 1,
980
+ x - unitSize * 0.2,
981
+ y + unitSize * 2.8
982
+ );
983
+ ctx.bezierCurveTo(
984
+ x - unitSize * 1.8,
985
+ y + unitSize * 1.5,
986
+ x - unitSize * 0.6,
987
+ y - unitSize * 0.2,
988
+ x + unitSize * 0.9,
989
+ y + unitSize * 1.5
990
+ );
991
+ ctx.fill();
992
+ ctx.stroke();
993
+ } else if (flagCount > 0) {
994
+ let adj = 1 - flagCount % 2;
995
+ let fx = (p) => x + (-p * 0.25 + 0.5) * unitSize;
996
+ let fy = (p) => y + (p + adj) * unitSize;
997
+ ctx.beginPath();
998
+ ctx.moveTo(fx(1 + flagCount), fy(1 + flagCount));
999
+ ctx.lineTo(fx(-0.5 - flagCount), fy(-0.5 - flagCount));
1000
+ ctx.stroke();
1001
+ for (let i = 0; i < flagCount; i++) {
1002
+ let t = flagCount - i * 2;
1003
+ ctx.beginPath();
1004
+ ctx.moveTo(fx(t - 2.5), fy(t - 2.5));
1005
+ ctx.quadraticCurveTo(
1006
+ fx(t - 0.5) + unitSize * 0.25,
1007
+ fy(t - 1.5),
1008
+ fx(t - 1.5) - unitSize * 1.5,
1009
+ fy(t - 1.5)
1010
+ );
1011
+ ctx.stroke();
1012
+ ctx.beginPath();
1013
+ ctx.arc(fx(t - 2) - unitSize * 1.5, fy(t - 2), unitSize * 0.5, 0, Math.PI * 2);
1014
+ ctx.fill();
1015
+ }
1016
+ }
1017
+ }
1018
+ drawFlag(rect, dir) {
1019
+ let ctx = this.getCanvasContext();
1020
+ if (!ctx) {
1021
+ return;
1022
+ }
1023
+ let left = rect.left;
1024
+ let right = rect.right;
1025
+ let width = right - left;
1026
+ let top = dir === "up" ? rect.top : rect.bottom;
1027
+ let bottom = dir === "up" ? rect.bottom : rect.top;
1028
+ ctx.beginPath();
1029
+ ctx.moveTo(left, top);
1030
+ ctx.bezierCurveTo(
1031
+ left,
1032
+ top * 0.75 + bottom * 0.25,
1033
+ left + width * 1.5,
1034
+ top * 0.5 + bottom * 0.5,
1035
+ left + width * 0.5,
1036
+ bottom
1037
+ );
1038
+ ctx.stroke();
1039
+ }
913
1040
  };
914
1041
 
915
1042
  // src/score/engine/obj-staff-and-tab.ts
916
1043
  import { MusicError as MusicError15, MusicErrorType as MusicErrorType15 } from "@tspro/web-music-score/core";
917
- import { Utils as Utils12 } from "@tspro/ts-utils-lib";
1044
+ import { Utils as Utils13 } from "@tspro/ts-utils-lib";
918
1045
 
919
1046
  // src/score/engine/obj-measure.ts
920
- import { Utils as Utils11 } from "@tspro/ts-utils-lib";
921
- import { getScale, Scale, validateScaleType, Note as Note7, RhythmProps as RhythmProps5, KeySignature as KeySignature2, getDefaultKeySignature, PitchNotation, SymbolSet, validateNoteLength as validateNoteLength2, NoteLengthProps as NoteLengthProps4 } from "@tspro/web-music-score/theory";
1047
+ import { Utils as Utils12 } from "@tspro/ts-utils-lib";
1048
+ import { getScale, Scale, validateScaleType, Note as Note7, RhythmProps as RhythmProps5, KeySignature as KeySignature2, getDefaultKeySignature, PitchNotation, SymbolSet, validateNoteLength as validateNoteLength3, NoteLengthProps as NoteLengthProps5 } from "@tspro/web-music-score/theory";
922
1049
  import { getDefaultTempo, getDefaultTimeSignature } from "@tspro/web-music-score/theory";
923
1050
 
924
1051
  // src/score/engine/acc-state.ts
@@ -1241,7 +1368,7 @@ var ObjText = class extends MusicObject {
1241
1368
 
1242
1369
  // src/score/engine/obj-signature.ts
1243
1370
  import { MusicError as MusicError4, MusicErrorType as MusicErrorType4 } from "@tspro/web-music-score/core";
1244
- var ObjSignature = class extends MusicObject {
1371
+ var ObjStaffSignature = class extends MusicObject {
1245
1372
  constructor(measure, staff) {
1246
1373
  super(measure);
1247
1374
  this.measure = measure;
@@ -1255,7 +1382,7 @@ var ObjSignature = class extends MusicObject {
1255
1382
  __publicField(this, "beatSizeText");
1256
1383
  __publicField(this, "tempoText");
1257
1384
  __publicField(this, "mi");
1258
- this.mi = new MSignature(this);
1385
+ this.mi = new MStaffSignature(this);
1259
1386
  }
1260
1387
  getMusicInterface() {
1261
1388
  return this.mi;
@@ -1454,66 +1581,169 @@ var ObjSignature = class extends MusicObject {
1454
1581
  }
1455
1582
  x = right;
1456
1583
  if (this.tempoText) {
1584
+ let tempoBottom = Math.min(
1585
+ this.clefImage ? this.clefImage.getRect().top : staff.getTopLineY(),
1586
+ ...this.ksNeutralizeAccidentals.map((o) => o.getRect().top),
1587
+ ...this.ksNewAccidentals.map((o) => o.getRect().top)
1588
+ );
1457
1589
  this.tempoText.layout(renderer);
1458
- this.tempoText.offset(x, Math.min(this.rect.top, staff.getTopLineY()));
1590
+ this.tempoText.offset(x, tempoBottom);
1459
1591
  this.rect.expandInPlace(this.tempoText.getRect());
1460
1592
  }
1461
1593
  this.rect.right += paddingX;
1462
1594
  }
1463
1595
  offset(dx, dy) {
1464
- if (this.clefImage) {
1465
- this.clefImage.offset(dx, dy);
1596
+ var _a, _b, _c, _d, _e, _f;
1597
+ (_a = this.clefImage) == null ? void 0 : _a.offset(dx, dy);
1598
+ (_b = this.eightBelowClef) == null ? void 0 : _b.offset(dx, dy);
1599
+ (_c = this.measureNumber) == null ? void 0 : _c.offset(dx, dy);
1600
+ this.ksNeutralizeAccidentals.forEach((acc) => acc.offset(dx, dy));
1601
+ this.ksNewAccidentals.forEach((acc) => acc.offset(dx, dy));
1602
+ (_d = this.beatCountText) == null ? void 0 : _d.offset(dx, dy);
1603
+ (_e = this.beatSizeText) == null ? void 0 : _e.offset(dx, dy);
1604
+ (_f = this.tempoText) == null ? void 0 : _f.offset(dx, dy);
1605
+ this.rect.offsetInPlace(dx, dy);
1606
+ }
1607
+ draw(renderer) {
1608
+ var _a, _b, _c, _d, _e, _f;
1609
+ (_a = this.clefImage) == null ? void 0 : _a.draw(renderer);
1610
+ (_b = this.eightBelowClef) == null ? void 0 : _b.draw(renderer);
1611
+ (_c = this.measureNumber) == null ? void 0 : _c.draw(renderer);
1612
+ this.ksNeutralizeAccidentals.forEach((acc) => acc.draw(renderer));
1613
+ this.ksNewAccidentals.forEach((acc) => acc.draw(renderer));
1614
+ (_d = this.beatCountText) == null ? void 0 : _d.draw(renderer);
1615
+ (_e = this.beatSizeText) == null ? void 0 : _e.draw(renderer);
1616
+ (_f = this.tempoText) == null ? void 0 : _f.draw(renderer);
1617
+ }
1618
+ };
1619
+ var ObjTabSignature = class extends MusicObject {
1620
+ constructor(measure, tab) {
1621
+ super(measure);
1622
+ this.measure = measure;
1623
+ this.tab = tab;
1624
+ __publicField(this, "measureNumber");
1625
+ __publicField(this, "beatCountText");
1626
+ __publicField(this, "beatSizeText");
1627
+ __publicField(this, "tempoText");
1628
+ __publicField(this, "mi");
1629
+ this.mi = new MTabSignature(this);
1630
+ }
1631
+ getMusicInterface() {
1632
+ return this.mi;
1633
+ }
1634
+ updateMeasureNumber(showMeasureNumber) {
1635
+ if (showMeasureNumber) {
1636
+ let text = this.measure.getMeasureNumber().toString();
1637
+ this.measureNumber = new ObjText(this, text, 0, 1);
1638
+ } else {
1639
+ this.measureNumber = void 0;
1466
1640
  }
1467
- if (this.eightBelowClef) {
1468
- this.eightBelowClef.offset(dx, dy);
1641
+ }
1642
+ updateTimeSignature(showTimeSignature) {
1643
+ if (showTimeSignature) {
1644
+ let timeSignature = this.measure.getTimeSignature();
1645
+ let beatCount = timeSignature.beatCount.toString();
1646
+ this.beatCountText = new ObjText(this, { text: beatCount, scale: 1.4 }, 0.5, 0.5);
1647
+ let beatSize = timeSignature.beatSize.toString();
1648
+ this.beatSizeText = new ObjText(this, { text: beatSize, scale: 1.4 }, 0.5, 0.5);
1649
+ } else {
1650
+ this.beatCountText = this.beatSizeText = void 0;
1469
1651
  }
1470
- if (this.measureNumber) {
1471
- this.measureNumber.offset(dx, dy);
1652
+ }
1653
+ updateTempo(showTempo) {
1654
+ if (showTempo) {
1655
+ let tempoStr = getTempoString(this.measure.getTempo());
1656
+ this.tempoText = new ObjText(this, tempoStr, 0, 1);
1657
+ } else {
1658
+ this.tempoText = void 0;
1659
+ }
1660
+ }
1661
+ pick(x, y) {
1662
+ if (!this.rect.contains(x, y)) {
1663
+ return [];
1472
1664
  }
1473
- this.ksNeutralizeAccidentals.forEach((acc) => acc.offset(dx, dy));
1474
- this.ksNewAccidentals.forEach((acc) => acc.offset(dx, dy));
1475
1665
  if (this.beatCountText) {
1476
- this.beatCountText.offset(dx, dy);
1666
+ let arr = this.beatCountText.pick(x, y);
1667
+ if (arr.length > 0) {
1668
+ return [this, ...arr];
1669
+ }
1477
1670
  }
1478
1671
  if (this.beatSizeText) {
1479
- this.beatSizeText.offset(dx, dy);
1672
+ let arr = this.beatSizeText.pick(x, y);
1673
+ if (arr.length > 0) {
1674
+ return [this, ...arr];
1675
+ }
1480
1676
  }
1481
1677
  if (this.tempoText) {
1482
- this.tempoText.offset(dx, dy);
1483
- }
1484
- this.rect.offsetInPlace(dx, dy);
1485
- }
1486
- draw(renderer) {
1487
- if (this.clefImage) {
1488
- this.clefImage.draw(renderer);
1678
+ let arr = this.tempoText.pick(x, y);
1679
+ if (arr.length > 0) {
1680
+ return [this, ...arr];
1681
+ }
1489
1682
  }
1490
- if (this.eightBelowClef) {
1491
- this.eightBelowClef.draw(renderer);
1683
+ if (this.measureNumber) {
1684
+ let arr = this.measureNumber.pick(x, y);
1685
+ if (arr.length > 0) {
1686
+ return [this, ...arr];
1687
+ }
1492
1688
  }
1689
+ return [this];
1690
+ }
1691
+ layout(renderer) {
1692
+ var _a, _b, _c, _d, _e, _f;
1693
+ let { unitSize } = renderer;
1694
+ let { tab } = this;
1695
+ let paddingX = unitSize;
1696
+ let x = 0;
1697
+ let topLineY = tab.getTopLineY();
1698
+ this.rect = new DivRect();
1493
1699
  if (this.measureNumber) {
1494
- this.measureNumber.draw(renderer);
1700
+ this.measureNumber.layout(renderer);
1701
+ this.measureNumber.offset(0, topLineY);
1702
+ this.rect.expandInPlace(this.measureNumber.getRect());
1703
+ x = Math.max(x, this.rect.right);
1495
1704
  }
1496
- this.ksNeutralizeAccidentals.forEach((acc) => acc.draw(renderer));
1497
- this.ksNewAccidentals.forEach((acc) => acc.draw(renderer));
1705
+ (_a = this.beatCountText) == null ? void 0 : _a.layout(renderer);
1706
+ (_b = this.beatSizeText) == null ? void 0 : _b.layout(renderer);
1707
+ let tsWidth = Math.max((_d = (_c = this.beatCountText) == null ? void 0 : _c.getRect().width) != null ? _d : 0, (_f = (_e = this.beatSizeText) == null ? void 0 : _e.getRect().width) != null ? _f : 0);
1498
1708
  if (this.beatCountText) {
1499
- this.beatCountText.draw(renderer);
1709
+ this.beatCountText.offset(0 + tsWidth / 2 + paddingX, tab.getRect().centerY - this.beatCountText.getRect().bottomh);
1710
+ this.rect.expandInPlace(this.beatCountText.getRect());
1500
1711
  }
1501
1712
  if (this.beatSizeText) {
1502
- this.beatSizeText.draw(renderer);
1713
+ this.beatSizeText.offset(0 + tsWidth / 2 + paddingX, tab.getRect().centerY + this.beatSizeText.getRect().toph);
1714
+ this.rect.expandInPlace(this.beatSizeText.getRect());
1503
1715
  }
1504
1716
  if (this.tempoText) {
1505
- this.tempoText.draw(renderer);
1717
+ this.tempoText.layout(renderer);
1718
+ this.tempoText.offset(x + unitSize * 2, topLineY);
1719
+ this.rect.expandInPlace(this.tempoText.getRect());
1506
1720
  }
1721
+ this.rect.right += paddingX;
1722
+ }
1723
+ offset(dx, dy) {
1724
+ var _a, _b, _c, _d;
1725
+ (_a = this.measureNumber) == null ? void 0 : _a.offset(dx, dy);
1726
+ (_b = this.beatCountText) == null ? void 0 : _b.offset(dx, dy);
1727
+ (_c = this.beatSizeText) == null ? void 0 : _c.offset(dx, dy);
1728
+ (_d = this.tempoText) == null ? void 0 : _d.offset(dx, dy);
1729
+ this.rect.offsetInPlace(dx, dy);
1730
+ }
1731
+ draw(renderer) {
1732
+ var _a, _b, _c, _d;
1733
+ (_a = this.measureNumber) == null ? void 0 : _a.draw(renderer);
1734
+ (_b = this.beatCountText) == null ? void 0 : _b.draw(renderer);
1735
+ (_c = this.beatSizeText) == null ? void 0 : _c.draw(renderer);
1736
+ (_d = this.tempoText) == null ? void 0 : _d.draw(renderer);
1507
1737
  }
1508
1738
  };
1509
1739
 
1510
1740
  // src/score/engine/player.ts
1511
- import { Utils as Utils7 } from "@tspro/ts-utils-lib";
1741
+ import { Utils as Utils6 } from "@tspro/ts-utils-lib";
1512
1742
  import { NoteLength as NoteLength6, RhythmProps as RhythmProps4, alterTempoSpeed } from "@tspro/web-music-score/theory";
1513
1743
  import * as Audio from "@tspro/web-music-score/audio";
1514
1744
 
1515
1745
  // src/score/engine/obj-rhythm-column.ts
1516
- import { Note as Note5, validateNoteLength } from "@tspro/web-music-score/theory";
1746
+ import { Note as Note5, validateNoteLength as validateNoteLength2 } from "@tspro/web-music-score/theory";
1517
1747
 
1518
1748
  // src/score/engine/obj-arpeggio.ts
1519
1749
  var ObjArpeggio = class extends MusicObject {
@@ -1586,7 +1816,7 @@ var ObjArpeggio = class extends MusicObject {
1586
1816
  };
1587
1817
 
1588
1818
  // src/score/engine/obj-rest.ts
1589
- import { Note as Note3, NoteLength, NoteLengthProps, RhythmProps as RhythmProps2, Tuplet } from "@tspro/web-music-score/theory";
1819
+ import { Note as Note3, NoteLengthProps as NoteLengthProps2, RhythmProps as RhythmProps2, Tuplet } from "@tspro/web-music-score/theory";
1590
1820
  import { MusicError as MusicError5, MusicErrorType as MusicErrorType5 } from "@tspro/web-music-score/core";
1591
1821
  function getDiatonicIdFromStaffPos(staffPos) {
1592
1822
  if (typeof staffPos === "number") {
@@ -1661,7 +1891,7 @@ var ObjRest = class extends MusicObject {
1661
1891
  }
1662
1892
  this.color = (_a = options == null ? void 0 : options.color) != null ? _a : "black";
1663
1893
  this.hide = (_b = options == null ? void 0 : options.hide) != null ? _b : false;
1664
- this.oldStyleTriplet = tupletRatio === void 0 && ((options == null ? void 0 : options.triplet) === true || NoteLengthProps.get(noteLength).isTriplet);
1894
+ this.oldStyleTriplet = tupletRatio === void 0 && ((options == null ? void 0 : options.triplet) === true || NoteLengthProps2.get(noteLength).isTriplet);
1665
1895
  let dotCount = typeof (options == null ? void 0 : options.dotted) === "number" ? options.dotted > 0 ? options.dotted : void 0 : (options == null ? void 0 : options.dotted) === true ? 1 : void 0;
1666
1896
  this.rhythmProps = RhythmProps2.get(noteLength, dotCount, (tupletRatio != null ? tupletRatio : this.oldStyleTriplet) ? Tuplet.Triplet : void 0);
1667
1897
  this.mi = new MRest(this);
@@ -1723,6 +1953,9 @@ var ObjRest = class extends MusicObject {
1723
1953
  return { staff, x, y, stemHeight };
1724
1954
  });
1725
1955
  }
1956
+ hasTuplet() {
1957
+ return this.rhythmProps.tupletRatio !== void 0;
1958
+ }
1726
1959
  isEmpty() {
1727
1960
  return this.staffObjects.length === 0;
1728
1961
  }
@@ -1759,42 +1992,16 @@ var ObjRest = class extends MusicObject {
1759
1992
  }
1760
1993
  let { unitSize } = renderer;
1761
1994
  let { ownDiatonicId } = this;
1762
- let { noteSize, dotCount, flagCount } = this.rhythmProps;
1763
- let leftw = 0;
1764
- let rightw = 0;
1765
- let toph = 0;
1766
- let bottomh = 0;
1767
- if (NoteLengthProps.equals(noteSize, NoteLength.Whole)) {
1768
- leftw = unitSize;
1769
- rightw = unitSize;
1770
- toph = 0;
1771
- bottomh = unitSize;
1772
- } else if (NoteLengthProps.equals(noteSize, NoteLength.Half)) {
1773
- leftw = unitSize;
1774
- rightw = unitSize;
1775
- toph = unitSize;
1776
- bottomh = 0;
1777
- } else if (NoteLengthProps.equals(noteSize, NoteLength.Quarter)) {
1778
- leftw = unitSize * 1;
1779
- rightw = unitSize * 1;
1780
- toph = unitSize * 3.2;
1781
- bottomh = unitSize * 3;
1782
- } else {
1783
- let adj = 1 - flagCount % 2;
1784
- leftw = unitSize * (1 + flagCount * 0.25);
1785
- rightw = unitSize * (1 + flagCount * 0.125);
1786
- toph = unitSize * (0.5 + flagCount - adj);
1787
- bottomh = unitSize * (1 + flagCount + adj);
1788
- }
1995
+ let { noteSize, dotCount } = this.rhythmProps;
1789
1996
  this.row.getStaves().forEach((staff) => {
1790
1997
  if (!staff.containsDiatonicId(ownDiatonicId) || !staff.containsVoiceId(this.voiceId)) {
1791
1998
  return;
1792
1999
  }
1793
2000
  let obj = new ObjStaffRest(staff, this);
1794
- obj.restRect = new DivRect(-leftw, 0, rightw, -toph, 0, bottomh);
2001
+ obj.restRect = renderer.getRestRect(noteSize);
1795
2002
  for (let i = 0; i < dotCount; i++) {
1796
2003
  let dotWidth = DocumentSettings.DotSize * unitSize;
1797
- let dotX = rightw + (DocumentSettings.RestDotSpace + DocumentSettings.DotSize * unitSize) + i * DocumentSettings.DotSize * unitSize * 1.5;
2004
+ let dotX = obj.restRect.rightw + (DocumentSettings.RestDotSpace + DocumentSettings.DotSize * unitSize) + i * DocumentSettings.DotSize * unitSize * 1.5;
1798
2005
  let dotY = this.getRestDotVerticalDisplacement(noteSize) * unitSize;
1799
2006
  obj.dotRects.push(DivRect.createCentered(dotX, dotY, dotWidth, dotWidth));
1800
2007
  }
@@ -1824,77 +2031,16 @@ var ObjRest = class extends MusicObject {
1824
2031
  return;
1825
2032
  }
1826
2033
  renderer.drawDebugRect(this.getRect());
1827
- let { unitSize, lineWidth } = renderer;
2034
+ let { lineWidth } = renderer;
1828
2035
  let { color } = this;
1829
- let { noteSize, flagCount } = this.rhythmProps;
2036
+ let { noteSize } = this.rhythmProps;
1830
2037
  ctx.strokeStyle = ctx.fillStyle = color;
1831
2038
  ctx.lineWidth = lineWidth;
1832
2039
  this.staffObjects.forEach((obj) => {
1833
2040
  let { dotRects, restRect } = obj;
1834
2041
  let x = restRect.centerX;
1835
2042
  let y = restRect.centerY;
1836
- if (NoteLengthProps.equals(noteSize, NoteLength.Whole)) {
1837
- ctx.fillRect(x - unitSize, y, unitSize * 2, unitSize);
1838
- } else if (NoteLengthProps.equals(noteSize, NoteLength.Half)) {
1839
- ctx.fillRect(x - unitSize, y - unitSize, unitSize * 2, unitSize);
1840
- } else if (NoteLengthProps.equals(noteSize, NoteLength.Quarter)) {
1841
- ctx.beginPath();
1842
- ctx.moveTo(x - unitSize * 0.6, y - unitSize * 3.2);
1843
- ctx.lineTo(x + unitSize * 0.7, y - unitSize * 1.5);
1844
- ctx.quadraticCurveTo(
1845
- x - unitSize * 0.8,
1846
- y - unitSize * 0.5,
1847
- x + unitSize * 1,
1848
- y + unitSize * 1.5
1849
- );
1850
- ctx.lineTo(x - unitSize * 1, y - unitSize * 0.75);
1851
- ctx.quadraticCurveTo(
1852
- x + unitSize * 0.2,
1853
- y - unitSize * 1.5,
1854
- x - unitSize * 0.6,
1855
- y - unitSize * 3.2
1856
- );
1857
- ctx.moveTo(x + unitSize * 1, y + unitSize * 1.5);
1858
- ctx.quadraticCurveTo(
1859
- x - unitSize * 0.8,
1860
- y + unitSize * 1,
1861
- x - unitSize * 0.2,
1862
- y + unitSize * 2.8
1863
- );
1864
- ctx.bezierCurveTo(
1865
- x - unitSize * 1.8,
1866
- y + unitSize * 1.5,
1867
- x - unitSize * 0.6,
1868
- y - unitSize * 0.2,
1869
- x + unitSize * 0.9,
1870
- y + unitSize * 1.5
1871
- );
1872
- ctx.fill();
1873
- ctx.stroke();
1874
- } else if (flagCount > 0) {
1875
- let adj = 1 - flagCount % 2;
1876
- let fx = (p) => x + (-p * 0.25 + 0.5) * unitSize;
1877
- let fy = (p) => y + (p + adj) * unitSize;
1878
- ctx.beginPath();
1879
- ctx.moveTo(fx(1 + flagCount), fy(1 + flagCount));
1880
- ctx.lineTo(fx(-0.5 - flagCount), fy(-0.5 - flagCount));
1881
- ctx.stroke();
1882
- for (let i = 0; i < flagCount; i++) {
1883
- let t = flagCount - i * 2;
1884
- ctx.beginPath();
1885
- ctx.moveTo(fx(t - 2.5), fy(t - 2.5));
1886
- ctx.quadraticCurveTo(
1887
- fx(t - 0.5) + unitSize * 0.25,
1888
- fy(t - 1.5),
1889
- fx(t - 1.5) - unitSize * 1.5,
1890
- fy(t - 1.5)
1891
- );
1892
- ctx.stroke();
1893
- ctx.beginPath();
1894
- ctx.arc(fx(t - 2) - unitSize * 1.5, fy(t - 2), unitSize * 0.5, 0, Math.PI * 2);
1895
- ctx.fill();
1896
- }
1897
- }
2043
+ renderer.drawRest(noteSize, x, y, color);
1898
2044
  dotRects.forEach((r) => {
1899
2045
  renderer.fillCircle(r.centerX, r.centerY, r.width / 2);
1900
2046
  });
@@ -1903,54 +2049,97 @@ var ObjRest = class extends MusicObject {
1903
2049
  };
1904
2050
 
1905
2051
  // src/score/engine/obj-note-group.ts
1906
- import { Utils as Utils4 } from "@tspro/ts-utils-lib";
1907
- import { Note as Note4, NoteLengthProps as NoteLengthProps3, RhythmProps as RhythmProps3, Tuplet as Tuplet3 } from "@tspro/web-music-score/theory";
1908
-
1909
- // src/score/engine/obj-beam-group.ts
1910
2052
  import { Utils as Utils3 } from "@tspro/ts-utils-lib";
1911
- import { NoteLength as NoteLength2, Tuplet as Tuplet2, NoteLengthProps as NoteLengthProps2 } from "@tspro/web-music-score/theory";
2053
+ import { Note as Note4, NoteLengthProps as NoteLengthProps3, RhythmProps as RhythmProps3, Tuplet as Tuplet2 } from "@tspro/web-music-score/theory";
1912
2054
  import { MusicError as MusicError6, MusicErrorType as MusicErrorType6 } from "@tspro/web-music-score/core";
1913
- var adjustBeamAngle = (dx, dy) => {
1914
- let T = DocumentSettings.BeamAngleFactor;
1915
- if (!Number.isFinite(T) || T === 0) {
1916
- return dy;
1917
- } else {
1918
- let k = dx / dy / T;
1919
- k = Math.sign(k) * Math.sqrt(Math.abs(k));
1920
- return dx / k * T;
1921
- }
1922
- };
1923
- var BeamPoint = class {
1924
- constructor(staff, beamGroup, symbol, x, y) {
2055
+ function getStem(stem) {
2056
+ return Utils3.Is.isEnumValue(stem, Stem) ? stem : void 0;
2057
+ }
2058
+ function getArpeggio(a) {
2059
+ return Utils3.Is.isEnumValue(a, Arpeggio) ? a : a === true ? "up" /* Up */ : void 0;
2060
+ }
2061
+ function sortNoteStringData(notes, strings) {
2062
+ let stringArr = Utils3.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2063
+ let noteStringData = notes.map((note, i) => {
2064
+ return { note, string: stringArr[i] };
2065
+ });
2066
+ noteStringData = Utils3.Arr.removeDuplicatesCmp(noteStringData, (a, b) => Note4.equals(a.note, b.note)).sort((a, b) => Note4.compareFunc(a.note, b.note));
2067
+ return {
2068
+ notes: noteStringData.map((e) => e.note),
2069
+ strings: noteStringData.every((e) => e.string === void 0) ? void 0 : noteStringData.map((e) => e.string)
2070
+ };
2071
+ }
2072
+ var ObjStaffNoteGroup = class extends MusicObject {
2073
+ constructor(staff, noteGroup) {
2074
+ super(staff);
1925
2075
  this.staff = staff;
1926
- this.beamGroup = beamGroup;
1927
- this.symbol = symbol;
1928
- this.x = x;
1929
- this.y = y;
1930
- __publicField(this, "topBeamsHeight", 0);
1931
- __publicField(this, "bottomBeamsHeight", 0);
1932
- staff.addObject(this);
1933
- }
1934
- offset(dx, dy) {
1935
- this.x += dx;
1936
- this.y += dy;
1937
- this.beamGroup.requestRectUpdate();
2076
+ this.noteGroup = noteGroup;
2077
+ __publicField(this, "noteHeadRects", []);
2078
+ __publicField(this, "dotRects", []);
2079
+ __publicField(this, "accidentals", []);
2080
+ __publicField(this, "stemTip");
2081
+ __publicField(this, "stemBase");
2082
+ __publicField(this, "flagRects", []);
2083
+ __publicField(this, "prevTopNoteY", 0);
2084
+ __publicField(this, "prevBottomNoteY", 0);
2085
+ __publicField(this, "mi");
2086
+ this.mi = new MStaffNoteGroup(this);
2087
+ }
2088
+ getMusicInterface() {
2089
+ return this.mi;
2090
+ }
2091
+ pick(x, y) {
2092
+ if (!this.getRect().contains(x, y)) {
2093
+ return [];
2094
+ }
2095
+ for (let i = 0; i < this.accidentals.length; i++) {
2096
+ let arr = this.accidentals[i].pick(x, y);
2097
+ if (arr.length > 0) {
2098
+ return [this, ...arr];
2099
+ }
2100
+ }
2101
+ return [this];
2102
+ }
2103
+ updateRect() {
2104
+ this.rect = this.noteHeadRects[0].copy();
2105
+ this.noteHeadRects.forEach((r) => this.rect.expandInPlace(r));
2106
+ if (this.stemTip) this.rect.expandInPlace(this.stemTip);
2107
+ if (this.stemBase) this.rect.expandInPlace(this.stemBase);
2108
+ this.dotRects.forEach((r) => this.rect.expandInPlace(r));
2109
+ this.flagRects.forEach((r) => this.rect.expandInPlace(r));
2110
+ this.accidentals.forEach((a) => this.rect.expandInPlace(a.getRect()));
1938
2111
  }
1939
2112
  getRect() {
1940
- return new DivRect(this.x, this.x, this.x, this.y - this.topBeamsHeight, this.y, this.y + this.bottomBeamsHeight);
2113
+ let bottomNoteRect = this.noteHeadRects[0];
2114
+ let topNoteRect = this.noteHeadRects[this.noteHeadRects.length - 1];
2115
+ if (this.prevTopNoteY !== topNoteRect.centerY || this.prevBottomNoteY !== bottomNoteRect.centerY) {
2116
+ this.prevTopNoteY = topNoteRect.centerY;
2117
+ this.prevBottomNoteY = bottomNoteRect.centerY;
2118
+ this.requestRectUpdate();
2119
+ }
2120
+ return super.getRect();
2121
+ }
2122
+ offset(dx, dy) {
2123
+ var _a, _b;
2124
+ this.noteHeadRects.forEach((n) => n.offsetInPlace(dx, dy));
2125
+ this.dotRects.forEach((n) => n.offsetInPlace(dx, dy));
2126
+ this.accidentals.forEach((n) => n.offset(dx, dy));
2127
+ (_a = this.stemTip) == null ? void 0 : _a.offsetInPlace(dx, dy);
2128
+ (_b = this.stemBase) == null ? void 0 : _b.offsetInPlace(dx, dy);
2129
+ this.flagRects.forEach((n) => n.offsetInPlace(dx, dy));
2130
+ this.requestRectUpdate();
2131
+ this.noteGroup.requestRectUpdate();
1941
2132
  }
1942
2133
  };
1943
- var ObjStaffBeamGroup = class extends MusicObject {
1944
- constructor(staff, beamGroup) {
1945
- super(staff);
1946
- this.staff = staff;
1947
- this.beamGroup = beamGroup;
1948
- __publicField(this, "tupletNumber");
1949
- __publicField(this, "tupletNumberOffsetY", 0);
1950
- __publicField(this, "points", []);
2134
+ var ObjTabNoteGroup = class extends MusicObject {
2135
+ constructor(tab, noteGroup) {
2136
+ super(tab);
2137
+ this.tab = tab;
2138
+ this.noteGroup = noteGroup;
2139
+ __publicField(this, "fretNumbers", []);
1951
2140
  __publicField(this, "mi");
1952
- staff.addObject(this);
1953
- this.mi = new MStaffBeamGroup(this);
2141
+ tab.addObject(this);
2142
+ this.mi = new MTabNoteGroup(this);
1954
2143
  }
1955
2144
  getMusicInterface() {
1956
2145
  return this.mi;
@@ -1958,95 +2147,102 @@ var ObjStaffBeamGroup = class extends MusicObject {
1958
2147
  pick(x, y) {
1959
2148
  return this.getRect().contains(x, y) ? [this] : [];
1960
2149
  }
2150
+ updateRect() {
2151
+ this.rect = this.fretNumbers[0].getRect().copy();
2152
+ this.fretNumbers.forEach((fn) => this.rect.expandInPlace(fn.getRect()));
2153
+ }
1961
2154
  offset(dx, dy) {
1962
- var _a;
1963
- this.points.forEach((p) => p.offset(dx, 0));
1964
- (_a = this.tupletNumber) == null ? void 0 : _a.offset(dx, dy);
2155
+ this.fretNumbers.forEach((f) => f.offset(dx, dy));
1965
2156
  this.requestRectUpdate();
1966
- this.beamGroup.requestRectUpdate();
1967
- }
1968
- updateRect() {
1969
- if (this.points.length > 0) {
1970
- this.rect = this.points[0].getRect().copy();
1971
- } else if (this.tupletNumber) {
1972
- this.rect = this.tupletNumber.getRect().copy();
1973
- }
1974
- this.points.forEach((pt) => this.rect.expandInPlace(pt.getRect()));
1975
- if (this.tupletNumber) {
1976
- this.rect.expandInPlace(this.tupletNumber.getRect());
1977
- }
2157
+ this.noteGroup.requestRectUpdate();
1978
2158
  }
1979
2159
  };
1980
- var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
1981
- constructor(symbols, tupletRatio) {
1982
- super(symbols[0].measure);
1983
- this.symbols = symbols;
1984
- this.tupletRatio = tupletRatio;
1985
- __publicField(this, "mi");
1986
- __publicField(this, "type");
2160
+ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2161
+ constructor(col, voiceId, notes, noteLength, options, tupletRatio) {
2162
+ var _a, _b, _c;
2163
+ super(col);
2164
+ this.col = col;
2165
+ this.voiceId = voiceId;
2166
+ this.notes = notes;
2167
+ __publicField(this, "minDiatonicId");
2168
+ __publicField(this, "maxDiatonicId");
2169
+ __publicField(this, "ownDiatonicId");
2170
+ // Average diatonicId of notes.
2171
+ __publicField(this, "ownStemDir");
2172
+ __publicField(this, "ownString");
2173
+ __publicField(this, "color");
2174
+ __publicField(this, "staccato");
2175
+ __publicField(this, "diamond");
2176
+ __publicField(this, "arpeggio");
2177
+ __publicField(this, "oldStyleTriplet");
2178
+ __publicField(this, "rhythmProps");
2179
+ __publicField(this, "startConnnectives", []);
2180
+ __publicField(this, "runningConnectives", []);
2181
+ __publicField(this, "leftBeamCount", 0);
2182
+ __publicField(this, "rightBeamCount", 0);
2183
+ __publicField(this, "beamGroup");
1987
2184
  __publicField(this, "staffObjects", []);
1988
- this.mi = new MBeamGroup(this);
1989
- let beamGroupName = tupletRatio ? "Tuplet" : "BeamGroup";
1990
- if (!symbols.every((s) => s.measure === symbols[0].measure)) {
1991
- throw new MusicError6(MusicErrorType6.Score, `All ${beamGroupName} symbols are not in same measure.`);
1992
- } else if (symbols.length < 2) {
1993
- throw new MusicError6(MusicErrorType6.Score, `${beamGroupName} needs minimum 2 symbols, but ${symbols.length} given.`);
1994
- }
1995
- if (tupletRatio !== void 0) {
1996
- let isGroup = symbols.length < 3 || symbols.some((s) => !(s instanceof ObjNoteGroup)) || symbols.some((s) => s.rhythmProps.flagCount !== symbols[0].rhythmProps.flagCount);
1997
- if (symbols.length >= 3 && symbols[0] instanceof ObjNoteGroup && symbols[symbols.length - 1] instanceof ObjNoteGroup && symbols[0].rhythmProps.flagCount === symbols[symbols.length - 1].rhythmProps.flagCount) {
1998
- isGroup = false;
1999
- }
2000
- if (symbols.some((s) => NoteLengthProps2.cmp(s.rhythmProps.noteLength, NoteLength2.Quarter) >= 0)) {
2001
- isGroup = true;
2002
- }
2003
- this.type = isGroup ? 2 /* TupletGroup */ : 1 /* TupletBeam */;
2004
- ObjNoteGroup.setTupletBeamCounts(this);
2005
- } else {
2006
- this.type = 0 /* RegularBeam */;
2007
- }
2008
- if (symbols.every((s) => s.getBeamGroup() === void 0)) {
2009
- symbols.forEach((s) => s.setBeamGroup(this));
2010
- symbols[0].measure.addBeamGroup(this);
2011
- } else {
2012
- throw new MusicError6(MusicErrorType6.Score, `Cannot add ${beamGroupName} because some symbol already has one.`);
2185
+ __publicField(this, "tabObjects", []);
2186
+ __publicField(this, "mi");
2187
+ if (!Utils3.Is.isIntegerGte(notes.length, 1)) {
2188
+ throw new MusicError6(MusicErrorType6.Score, "Cannot create note group object because notes array is empty.");
2013
2189
  }
2190
+ let noteStringData = sortNoteStringData(notes, options == null ? void 0 : options.string);
2191
+ this.notes = noteStringData.notes;
2192
+ this.minDiatonicId = this.notes[0].diatonicId;
2193
+ this.maxDiatonicId = this.notes[this.notes.length - 1].diatonicId;
2194
+ this.ownDiatonicId = this.measure.updateOwnDiatonicId(voiceId, Math.round((this.minDiatonicId + this.maxDiatonicId) / 2));
2195
+ this.ownStemDir = this.measure.updateOwnStemDir(this, getStem(options == null ? void 0 : options.stem));
2196
+ this.ownString = this.measure.updateOwnString(this, noteStringData.strings);
2197
+ this.color = (_a = options == null ? void 0 : options.color) != null ? _a : "black";
2198
+ this.staccato = (_b = options == null ? void 0 : options.staccato) != null ? _b : false;
2199
+ this.diamond = (_c = options == null ? void 0 : options.diamond) != null ? _c : false;
2200
+ this.arpeggio = getArpeggio(options == null ? void 0 : options.arpeggio);
2201
+ this.oldStyleTriplet = tupletRatio === void 0 && ((options == null ? void 0 : options.triplet) === true || NoteLengthProps3.get(noteLength).isTriplet);
2202
+ let dotCount = typeof (options == null ? void 0 : options.dotted) === "number" ? options.dotted > 0 ? options.dotted : void 0 : (options == null ? void 0 : options.dotted) === true ? 1 : void 0;
2203
+ this.rhythmProps = RhythmProps3.get(noteLength, dotCount, (tupletRatio != null ? tupletRatio : this.oldStyleTriplet) ? Tuplet2.Triplet : void 0);
2204
+ this.mi = new MNoteGroup(this);
2014
2205
  }
2015
- get showTupletRatio() {
2016
- var _a;
2017
- return ((_a = this.tupletRatio) == null ? void 0 : _a.showRatio) === true;
2206
+ getMusicInterface() {
2207
+ return this.mi;
2018
2208
  }
2019
- static createBeam(noteGroups) {
2020
- if (noteGroups.length > 1) {
2021
- new _ObjBeamGroup(noteGroups, void 0);
2022
- }
2209
+ get doc() {
2210
+ return this.col.doc;
2023
2211
  }
2024
- static createOldStyleTriplet(symbols) {
2025
- let s2 = symbols.slice(0, 2);
2026
- let n2 = s2.map((s) => s.rhythmProps.noteSize);
2027
- if (s2.length === 2 && s2.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && (n2[0] * 2 === n2[1] || n2[1] * 2 === n2[0])) {
2028
- new _ObjBeamGroup(s2, Tuplet2.Triplet);
2029
- return 2;
2030
- }
2031
- let s3 = symbols.slice(0, 3);
2032
- let n3 = s3.map((s) => s.rhythmProps.noteSize);
2033
- if (s3.length === 3 && s3.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && n3.every((n) => n === n3[0])) {
2034
- new _ObjBeamGroup(s3, Tuplet2.Triplet);
2035
- return 3;
2036
- }
2037
- return 0;
2212
+ get measure() {
2213
+ return this.col.measure;
2038
2214
  }
2039
- static createTuplet(symbols, tupletRatio) {
2040
- new _ObjBeamGroup(symbols, tupletRatio);
2215
+ get row() {
2216
+ return this.col.row;
2041
2217
  }
2042
- getMusicInterface() {
2043
- return this.mi;
2218
+ get stemDir() {
2219
+ return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
2044
2220
  }
2045
- detach() {
2046
- this.getSymbols().forEach((s) => s.resetBeamGroup());
2221
+ enableConnective(line) {
2222
+ return line.containsVoiceId(this.voiceId) && (line instanceof ObjTab || line.containsDiatonicId(this.ownDiatonicId));
2047
2223
  }
2048
- isEmpty() {
2049
- return this.staffObjects.length === 0;
2224
+ startConnective(connectiveProps) {
2225
+ if (!this.row.hasStaff && connectiveProps.connective === "tie" /* Tie */) {
2226
+ throw new MusicError6(MusicErrorType6.Score, "Ties not implemented for guitar tabs alone, staff is required!");
2227
+ } else if (!this.row.hasStaff && connectiveProps.connective === "slur" /* Slur */) {
2228
+ throw new MusicError6(MusicErrorType6.Score, "Slurs not implemented for guitar tabs alone, staff is required!");
2229
+ }
2230
+ this.startConnnectives.push(connectiveProps);
2231
+ this.doc.addConnectiveProps(connectiveProps);
2232
+ }
2233
+ getStaticObjects(line) {
2234
+ let staticObjects = [];
2235
+ this.staffObjects.forEach((obj) => {
2236
+ if (obj.staff === line) {
2237
+ staticObjects.push(obj);
2238
+ }
2239
+ });
2240
+ this.tabObjects.forEach((obj) => {
2241
+ if (obj.tab === line) {
2242
+ staticObjects.push(obj);
2243
+ }
2244
+ });
2245
+ return staticObjects;
2050
2246
  }
2051
2247
  pick(x, y) {
2052
2248
  if (!this.getRect().contains(x, y)) {
@@ -2058,465 +2254,25 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2058
2254
  return [this, ...arr];
2059
2255
  }
2060
2256
  }
2061
- return [this];
2062
- }
2063
- getType() {
2064
- return this.type;
2065
- }
2066
- isTuplet() {
2067
- return this.type === 1 /* TupletBeam */ || this.type === 2 /* TupletGroup */;
2068
- }
2069
- getSymbols() {
2070
- return this.symbols;
2071
- }
2072
- getFirstSymbol() {
2073
- return this.symbols[0];
2257
+ for (let i = 0; i < this.tabObjects.length; i++) {
2258
+ let arr = this.tabObjects[i].pick(x, y);
2259
+ if (arr.length > 0) {
2260
+ return [this, ...arr];
2261
+ }
2262
+ }
2263
+ return [];
2074
2264
  }
2075
- getLastSymbol() {
2076
- return this.symbols[this.symbols.length - 1];
2265
+ getTopNote() {
2266
+ return this.notes[this.notes.length - 1];
2077
2267
  }
2078
- get stemDir() {
2079
- return this.symbols[0].ownStemDir;
2080
- }
2081
- layout(renderer) {
2082
- this.requestRectUpdate();
2083
- this.staffObjects.length = 0;
2084
- let symbols = this.getSymbols();
2085
- if (symbols.length === 0) {
2086
- return;
2087
- }
2088
- let voiceId = symbols[0].voiceId;
2089
- if (symbols.some((symbol) => symbol.voiceId !== voiceId)) {
2090
- return;
2091
- }
2092
- let { unitSize } = renderer;
2093
- let { stemDir } = this;
2094
- let symbolsBeamCoords = symbols.map((s) => s.getBeamCoords());
2095
- symbolsBeamCoords[0].map((s) => s == null ? void 0 : s.staff).forEach((mainStaff, index) => {
2096
- var _a, _b;
2097
- if (!mainStaff) {
2098
- return;
2099
- }
2100
- let symbolX = symbolsBeamCoords.map((s) => {
2101
- var _a2;
2102
- return (_a2 = s[index]) == null ? void 0 : _a2.x;
2103
- });
2104
- let symbolY = symbolsBeamCoords.map((s) => {
2105
- var _a2;
2106
- return (_a2 = s[index]) == null ? void 0 : _a2.y;
2107
- });
2108
- let symbolStaff = symbolsBeamCoords.map((s) => {
2109
- var _a2;
2110
- return (_a2 = s[index]) == null ? void 0 : _a2.staff;
2111
- });
2112
- let symbolStemHeight = symbolsBeamCoords.map((s) => {
2113
- var _a2;
2114
- return (_a2 = s[index]) == null ? void 0 : _a2.stemHeight;
2115
- });
2116
- let leftSymbol = symbols[0];
2117
- let leftX = symbolX[0];
2118
- let leftY = symbolY[0];
2119
- let leftStaff = symbolStaff[0];
2120
- let rightSymbol = symbols[symbols.length - 1];
2121
- let rightX = symbolX[symbolX.length - 1];
2122
- let rightY = symbolY[symbolY.length - 1];
2123
- let rightStaff = symbolStaff[symbolY.length - 1];
2124
- if (leftX === void 0 || leftY === void 0 || leftStaff === void 0 || rightX === void 0 || rightY === void 0 || rightStaff === void 0) {
2125
- return;
2126
- }
2127
- let leftStemHeight = (_a = symbolStemHeight[0]) != null ? _a : 0;
2128
- let rightStemHeight = (_b = symbolStemHeight[symbolStemHeight.length - 1]) != null ? _b : 0;
2129
- if (this.type !== 2 /* TupletGroup */) {
2130
- let leftDy = leftStemHeight < rightStemHeight ? Math.sqrt(rightStemHeight - leftStemHeight) : 0;
2131
- let rightDy = rightStemHeight < leftStemHeight ? Math.sqrt(leftStemHeight - rightStemHeight) : 0;
2132
- if (stemDir === "up" /* Up */) {
2133
- leftDy *= -1;
2134
- rightDy *= -1;
2135
- }
2136
- if (leftDy !== 0) {
2137
- leftY += leftDy;
2138
- symbolY[0] += leftDy;
2139
- }
2140
- if (rightDy !== 0) {
2141
- rightY += rightDy;
2142
- symbolY[symbolY.length - 1] += rightDy;
2143
- }
2144
- }
2145
- let groupLineDy = unitSize * 2 * (stemDir === "up" /* Up */ ? -1 : 1);
2146
- let centerY = (rightY + leftY) / 2;
2147
- let halfDy = adjustBeamAngle(rightX - leftX, rightY - leftY) / 2;
2148
- leftY = centerY - halfDy;
2149
- rightY = centerY + halfDy;
2150
- let raiseBeamY = 0;
2151
- symbolY.forEach((symY, i) => {
2152
- let symX = symbolX[i];
2153
- if (symX !== void 0 && symY !== void 0) {
2154
- let beamY = Utils3.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
2155
- let raiseY = symY - beamY;
2156
- if (stemDir === "up" /* Up */ && raiseY < 0) {
2157
- raiseBeamY = Math.min(raiseBeamY, raiseY);
2158
- } else if (stemDir === "down" /* Down */ && raiseY > 0) {
2159
- raiseBeamY = Math.max(raiseBeamY, raiseY);
2160
- }
2161
- }
2162
- });
2163
- leftY += raiseBeamY;
2164
- rightY += raiseBeamY;
2165
- symbolY = symbolY.map((y) => y === void 0 ? void 0 : y + raiseBeamY);
2166
- let obj = new ObjStaffBeamGroup(mainStaff, this);
2167
- if (this.type === 2 /* TupletGroup */) {
2168
- let ef = unitSize / (rightX - leftX);
2169
- let l = Utils3.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, -ef);
2170
- let r = Utils3.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, 1 + ef);
2171
- obj.points.push(new BeamPoint(leftStaff, this, leftSymbol, l.x, l.y));
2172
- obj.points.push(new BeamPoint(rightStaff, this, rightSymbol, r.x, r.y));
2173
- obj.tupletNumberOffsetY = 0;
2174
- } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
2175
- raiseBeamY *= 0.5;
2176
- let { beamThickness } = renderer;
2177
- const beamHeight = (i) => {
2178
- let sym = symbols[i];
2179
- if (sym instanceof ObjNoteGroup) {
2180
- let beamCount = sym instanceof ObjNoteGroup ? Math.max(sym.getLeftBeamCount(), sym.getRightBeamCount()) : 0;
2181
- return DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? beamCount - 1 : 0);
2182
- } else {
2183
- return 0;
2184
- }
2185
- };
2186
- symbols.forEach((sym, i) => {
2187
- let symStaff = symbolStaff[i];
2188
- let symX = symbolX[i];
2189
- let symY = symbolY[i];
2190
- if (symStaff && symX !== void 0 && symY !== void 0) {
2191
- let pt = new BeamPoint(symStaff, this, sym, symX, symY);
2192
- pt.topBeamsHeight = beamThickness / 2 + (stemDir === "down" /* Down */ ? beamHeight(i) : 0);
2193
- pt.bottomBeamsHeight = beamThickness / 2 + (stemDir === "up" /* Up */ ? beamHeight(i) : 0);
2194
- obj.points.push(pt);
2195
- }
2196
- });
2197
- obj.tupletNumberOffsetY = groupLineDy;
2198
- }
2199
- if (this.isTuplet() && this.tupletRatio) {
2200
- let txt = this.showTupletRatio ? String(this.tupletRatio.parts) + ":" + String(this.tupletRatio.inTimeOf) : String(this.tupletRatio.parts);
2201
- obj.tupletNumber = new ObjText(this, txt, 0.5, 0.5);
2202
- obj.tupletNumber.layout(renderer);
2203
- obj.tupletNumber.offset((leftX + rightX) / 2, (leftY + rightY) / 2 + obj.tupletNumberOffsetY);
2204
- }
2205
- if (obj.points.length >= 2) {
2206
- this.staffObjects.push(obj);
2207
- }
2208
- });
2209
- }
2210
- updateRect() {
2211
- if (this.staffObjects.length === 0) {
2212
- this.rect = new DivRect();
2213
- } else {
2214
- this.staffObjects.forEach((obj) => obj.updateRect());
2215
- this.rect = this.staffObjects[0].getRect().copy();
2216
- for (let i = 1; i < this.staffObjects.length; i++) {
2217
- this.rect.expandInPlace(this.staffObjects[i].getRect());
2218
- }
2219
- }
2220
- }
2221
- updateStemTips() {
2222
- this.staffObjects.forEach((obj) => {
2223
- let left = obj.points[0];
2224
- let right = obj.points[obj.points.length - 1];
2225
- if (this.type !== 2 /* TupletGroup */) {
2226
- obj.points.forEach((pt) => {
2227
- if (pt.symbol instanceof ObjNoteGroup) {
2228
- if (pt !== left && pt !== right) {
2229
- pt.y = Utils3.Math.interpolateY(left.x, left.y, right.x, right.y, pt.x);
2230
- }
2231
- pt.symbol.setStemTipY(pt.staff, pt.y);
2232
- }
2233
- });
2234
- }
2235
- if (obj.tupletNumber) {
2236
- let y = (left.y + right.y) / 2 + obj.tupletNumberOffsetY;
2237
- obj.tupletNumber.offset(0, -obj.tupletNumber.getRect().centerY + y);
2238
- }
2239
- });
2240
- }
2241
- offset(dx, dy) {
2242
- this.staffObjects.forEach((obj) => obj.offset(dx, 0));
2243
- this.requestRectUpdate();
2244
- }
2245
- draw(renderer) {
2246
- let { unitSize, beamThickness, lineWidth } = renderer;
2247
- let color = "black";
2248
- this.staffObjects.forEach((obj) => {
2249
- if (this.type === 2 /* TupletGroup */) {
2250
- let l = obj.points[0];
2251
- let r = obj.points[obj.points.length - 1];
2252
- if (l && r) {
2253
- let tf = obj.tupletNumber ? obj.tupletNumber.getRect().width / (r.x - l.x) * 1.2 : 0;
2254
- let lc = Utils3.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 - tf / 2);
2255
- let rc = Utils3.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 + tf / 2);
2256
- let tipH = this.stemDir === "up" /* Up */ ? unitSize : -unitSize;
2257
- renderer.drawLine(l.x, l.y, lc.x, lc.y, color, lineWidth);
2258
- renderer.drawLine(rc.x, rc.y, r.x, r.y, color, lineWidth);
2259
- renderer.drawLine(l.x, l.y, l.x, l.y + tipH, color, lineWidth);
2260
- renderer.drawLine(r.x, r.y, r.x, r.y + tipH, color, lineWidth);
2261
- }
2262
- } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
2263
- let beamSeparation = DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? 1 : -1);
2264
- let noteGroupPoints = obj.points.filter((p) => p.symbol instanceof ObjNoteGroup);
2265
- for (let i = 0; i < noteGroupPoints.length - 1; i++) {
2266
- let left = noteGroupPoints[i];
2267
- let right = noteGroupPoints[i + 1];
2268
- if (!(left.symbol instanceof ObjNoteGroup && right.symbol instanceof ObjNoteGroup)) {
2269
- continue;
2270
- }
2271
- let leftBeamCount = left.symbol.getRightBeamCount();
2272
- let rightBeamCount = right.symbol.getLeftBeamCount();
2273
- let lx = left.x;
2274
- let ly = left.y;
2275
- let rx = right.x;
2276
- let ry = right.y;
2277
- for (let beamId = 0; beamId < Math.max(leftBeamCount, rightBeamCount); beamId++) {
2278
- if (beamId < leftBeamCount && beamId < rightBeamCount) {
2279
- renderer.drawLine(lx, ly, rx, ry, color, beamThickness);
2280
- } else if (leftBeamCount > rightBeamCount) {
2281
- renderer.drawPartialLine(lx, ly, rx, ry, 0, 0.25, color, beamThickness);
2282
- } else if (rightBeamCount > leftBeamCount) {
2283
- renderer.drawPartialLine(lx, ly, rx, ry, 0.75, 1, color, beamThickness);
2284
- }
2285
- ly += beamSeparation;
2286
- ry += beamSeparation;
2287
- }
2288
- }
2289
- }
2290
- if (obj.tupletNumber) {
2291
- obj.tupletNumber.draw(renderer);
2292
- }
2293
- });
2294
- }
2295
- };
2296
-
2297
- // src/score/engine/obj-note-group.ts
2298
- import { MusicError as MusicError7, MusicErrorType as MusicErrorType7 } from "@tspro/web-music-score/core";
2299
- function getStem(stem) {
2300
- return Utils4.Is.isEnumValue(stem, Stem) ? stem : void 0;
2301
- }
2302
- function getArpeggio(a) {
2303
- return Utils4.Is.isEnumValue(a, Arpeggio) ? a : a === true ? "up" /* Up */ : void 0;
2304
- }
2305
- function sortNoteStringData(notes, strings) {
2306
- let stringArr = Utils4.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2307
- let noteStringData = notes.map((note, i) => {
2308
- return { note, string: stringArr[i] };
2309
- });
2310
- noteStringData = Utils4.Arr.removeDuplicatesCmp(noteStringData, (a, b) => Note4.equals(a.note, b.note)).sort((a, b) => Note4.compareFunc(a.note, b.note));
2311
- return {
2312
- notes: noteStringData.map((e) => e.note),
2313
- strings: noteStringData.every((e) => e.string === void 0) ? void 0 : noteStringData.map((e) => e.string)
2314
- };
2315
- }
2316
- var ObjStaffNoteGroup = class extends MusicObject {
2317
- constructor(staff, noteGroup) {
2318
- super(staff);
2319
- this.staff = staff;
2320
- this.noteGroup = noteGroup;
2321
- __publicField(this, "noteHeadRects", []);
2322
- __publicField(this, "dotRects", []);
2323
- __publicField(this, "accidentals", []);
2324
- __publicField(this, "stemTip");
2325
- __publicField(this, "stemBase");
2326
- __publicField(this, "flagRects", []);
2327
- __publicField(this, "prevTopNoteY", 0);
2328
- __publicField(this, "prevBottomNoteY", 0);
2329
- __publicField(this, "mi");
2330
- this.mi = new MStaffNoteGroup(this);
2331
- }
2332
- getMusicInterface() {
2333
- return this.mi;
2334
- }
2335
- pick(x, y) {
2336
- if (!this.getRect().contains(x, y)) {
2337
- return [];
2338
- }
2339
- for (let i = 0; i < this.accidentals.length; i++) {
2340
- let arr = this.accidentals[i].pick(x, y);
2341
- if (arr.length > 0) {
2342
- return [this, ...arr];
2343
- }
2344
- }
2345
- return [this];
2346
- }
2347
- updateRect() {
2348
- this.rect = this.noteHeadRects[0].copy();
2349
- this.noteHeadRects.forEach((r) => this.rect.expandInPlace(r));
2350
- if (this.stemTip) this.rect.expandInPlace(this.stemTip);
2351
- if (this.stemBase) this.rect.expandInPlace(this.stemBase);
2352
- this.dotRects.forEach((r) => this.rect.expandInPlace(r));
2353
- this.flagRects.forEach((r) => this.rect.expandInPlace(r));
2354
- this.accidentals.forEach((a) => this.rect.expandInPlace(a.getRect()));
2355
- }
2356
- getRect() {
2357
- let bottomNoteRect = this.noteHeadRects[0];
2358
- let topNoteRect = this.noteHeadRects[this.noteHeadRects.length - 1];
2359
- if (this.prevTopNoteY !== topNoteRect.centerY || this.prevBottomNoteY !== bottomNoteRect.centerY) {
2360
- this.prevTopNoteY = topNoteRect.centerY;
2361
- this.prevBottomNoteY = bottomNoteRect.centerY;
2362
- this.requestRectUpdate();
2363
- }
2364
- return super.getRect();
2365
- }
2366
- offset(dx, dy) {
2367
- var _a, _b;
2368
- this.noteHeadRects.forEach((n) => n.offsetInPlace(dx, dy));
2369
- this.dotRects.forEach((n) => n.offsetInPlace(dx, dy));
2370
- this.accidentals.forEach((n) => n.offset(dx, dy));
2371
- (_a = this.stemTip) == null ? void 0 : _a.offsetInPlace(dx, dy);
2372
- (_b = this.stemBase) == null ? void 0 : _b.offsetInPlace(dx, dy);
2373
- this.flagRects.forEach((n) => n.offsetInPlace(dx, dy));
2374
- this.requestRectUpdate();
2375
- this.noteGroup.requestRectUpdate();
2376
- }
2377
- };
2378
- var ObjTabNoteGroup = class extends MusicObject {
2379
- constructor(tab, noteGroup) {
2380
- super(tab);
2381
- this.tab = tab;
2382
- this.noteGroup = noteGroup;
2383
- __publicField(this, "fretNumbers", []);
2384
- __publicField(this, "mi");
2385
- tab.addObject(this);
2386
- this.mi = new MTabNoteGroup(this);
2387
- }
2388
- getMusicInterface() {
2389
- return this.mi;
2390
- }
2391
- pick(x, y) {
2392
- return this.getRect().contains(x, y) ? [this] : [];
2393
- }
2394
- updateRect() {
2395
- this.rect = this.fretNumbers[0].getRect().copy();
2396
- this.fretNumbers.forEach((fn) => this.rect.expandInPlace(fn.getRect()));
2397
- }
2398
- offset(dx, dy) {
2399
- this.fretNumbers.forEach((f) => f.offset(dx, dy));
2400
- this.requestRectUpdate();
2401
- this.noteGroup.requestRectUpdate();
2402
- }
2403
- };
2404
- var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2405
- constructor(col, voiceId, notes, noteLength, options, tupletRatio) {
2406
- var _a, _b, _c;
2407
- super(col);
2408
- this.col = col;
2409
- this.voiceId = voiceId;
2410
- this.notes = notes;
2411
- __publicField(this, "minDiatonicId");
2412
- __publicField(this, "maxDiatonicId");
2413
- __publicField(this, "ownDiatonicId");
2414
- // Average diatonicId of notes.
2415
- __publicField(this, "ownStemDir");
2416
- __publicField(this, "ownString");
2417
- __publicField(this, "color");
2418
- __publicField(this, "staccato");
2419
- __publicField(this, "diamond");
2420
- __publicField(this, "arpeggio");
2421
- __publicField(this, "oldStyleTriplet");
2422
- __publicField(this, "rhythmProps");
2423
- __publicField(this, "startConnnectives", []);
2424
- __publicField(this, "runningConnectives", []);
2425
- __publicField(this, "leftBeamCount", 0);
2426
- __publicField(this, "rightBeamCount", 0);
2427
- __publicField(this, "beamGroup");
2428
- __publicField(this, "staffObjects", []);
2429
- __publicField(this, "tabObjects", []);
2430
- __publicField(this, "mi");
2431
- if (!Utils4.Is.isIntegerGte(notes.length, 1)) {
2432
- throw new MusicError7(MusicErrorType7.Score, "Cannot create note group object because notes array is empty.");
2433
- }
2434
- let noteStringData = sortNoteStringData(notes, options == null ? void 0 : options.string);
2435
- this.notes = noteStringData.notes;
2436
- this.minDiatonicId = this.notes[0].diatonicId;
2437
- this.maxDiatonicId = this.notes[this.notes.length - 1].diatonicId;
2438
- this.ownDiatonicId = this.measure.updateOwnDiatonicId(voiceId, Math.round((this.minDiatonicId + this.maxDiatonicId) / 2));
2439
- this.ownStemDir = this.measure.updateOwnStemDir(this, getStem(options == null ? void 0 : options.stem));
2440
- this.ownString = this.measure.updateOwnString(this, noteStringData.strings);
2441
- this.color = (_a = options == null ? void 0 : options.color) != null ? _a : "black";
2442
- this.staccato = (_b = options == null ? void 0 : options.staccato) != null ? _b : false;
2443
- this.diamond = (_c = options == null ? void 0 : options.diamond) != null ? _c : false;
2444
- this.arpeggio = getArpeggio(options == null ? void 0 : options.arpeggio);
2445
- this.oldStyleTriplet = tupletRatio === void 0 && ((options == null ? void 0 : options.triplet) === true || NoteLengthProps3.get(noteLength).isTriplet);
2446
- let dotCount = typeof (options == null ? void 0 : options.dotted) === "number" ? options.dotted > 0 ? options.dotted : void 0 : (options == null ? void 0 : options.dotted) === true ? 1 : void 0;
2447
- this.rhythmProps = RhythmProps3.get(noteLength, dotCount, (tupletRatio != null ? tupletRatio : this.oldStyleTriplet) ? Tuplet3.Triplet : void 0);
2448
- this.mi = new MNoteGroup(this);
2449
- }
2450
- getMusicInterface() {
2451
- return this.mi;
2452
- }
2453
- get doc() {
2454
- return this.col.doc;
2455
- }
2456
- get measure() {
2457
- return this.col.measure;
2458
- }
2459
- get row() {
2460
- return this.col.row;
2461
- }
2462
- get stemDir() {
2463
- return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
2464
- }
2465
- enableConnective(line) {
2466
- return line.containsVoiceId(this.voiceId) && (line instanceof ObjTab || line.containsDiatonicId(this.ownDiatonicId));
2467
- }
2468
- startConnective(connectiveProps) {
2469
- if (!this.row.hasStaff && connectiveProps.connective === "tie" /* Tie */) {
2470
- throw new MusicError7(MusicErrorType7.Score, "Ties not implemented for guitar tabs alone, staff is required!");
2471
- } else if (!this.row.hasStaff && connectiveProps.connective === "slur" /* Slur */) {
2472
- throw new MusicError7(MusicErrorType7.Score, "Slurs not implemented for guitar tabs alone, staff is required!");
2473
- }
2474
- this.startConnnectives.push(connectiveProps);
2475
- this.doc.addConnectiveProps(connectiveProps);
2476
- }
2477
- getStaticObjects(line) {
2478
- let staticObjects = [];
2479
- this.staffObjects.forEach((obj) => {
2480
- if (obj.staff === line) {
2481
- staticObjects.push(obj);
2482
- }
2483
- });
2484
- this.tabObjects.forEach((obj) => {
2485
- if (obj.tab === line) {
2486
- staticObjects.push(obj);
2487
- }
2488
- });
2489
- return staticObjects;
2490
- }
2491
- pick(x, y) {
2492
- if (!this.getRect().contains(x, y)) {
2493
- return [];
2494
- }
2495
- for (let i = 0; i < this.staffObjects.length; i++) {
2496
- let arr = this.staffObjects[i].pick(x, y);
2497
- if (arr.length > 0) {
2498
- return [this, ...arr];
2499
- }
2500
- }
2501
- for (let i = 0; i < this.tabObjects.length; i++) {
2502
- let arr = this.tabObjects[i].pick(x, y);
2503
- if (arr.length > 0) {
2504
- return [this, ...arr];
2505
- }
2506
- }
2507
- return [];
2508
- }
2509
- getTopNote() {
2510
- return this.notes[this.notes.length - 1];
2511
- }
2512
- getBottomNote() {
2513
- return this.notes[0];
2268
+ getBottomNote() {
2269
+ return this.notes[0];
2514
2270
  }
2515
2271
  getConnectiveAnchorPoint(connectiveProps, line, noteIndex, noteAnchor, side) {
2516
2272
  if (line instanceof ObjStaff) {
2517
2273
  let staff = line;
2518
2274
  if (noteIndex < 0 || noteIndex >= this.notes.length) {
2519
- throw new MusicError7(MusicErrorType7.Score, "Invalid noteIndex: " + noteIndex);
2275
+ throw new MusicError6(MusicErrorType6.Score, "Invalid noteIndex: " + noteIndex);
2520
2276
  }
2521
2277
  let obj = this.staffObjects.find((obj2) => obj2.staff === staff);
2522
2278
  if (!obj || noteIndex < 0 || noteIndex >= obj.noteHeadRects.length) {
@@ -2564,7 +2320,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2564
2320
  case "stemTip" /* StemTip */:
2565
2321
  return { x: centerX, y: stemTip.centerY + (stemDir === "up" /* Up */ ? -padding : padding) };
2566
2322
  default:
2567
- throw new MusicError7(MusicErrorType7.Score, "Invalid noteAnchor: " + noteAnchor);
2323
+ throw new MusicError6(MusicErrorType6.Score, "Invalid noteAnchor: " + noteAnchor);
2568
2324
  }
2569
2325
  } else {
2570
2326
  let tab = line;
@@ -2679,6 +2435,15 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2679
2435
  getRightBeamCount() {
2680
2436
  return this.rightBeamCount;
2681
2437
  }
2438
+ setLeftBeamCount(count) {
2439
+ this.leftBeamCount = count;
2440
+ }
2441
+ setRightBeamCount(count) {
2442
+ this.rightBeamCount = count;
2443
+ }
2444
+ hasTuplet() {
2445
+ return this.rhythmProps.tupletRatio !== void 0;
2446
+ }
2682
2447
  isEmpty() {
2683
2448
  return this.staffObjects.length === 0 && this.tabObjects.length === 0;
2684
2449
  }
@@ -2704,7 +2469,7 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2704
2469
  if (j >= 0) {
2705
2470
  tieNoteGroups = tieNoteGroups.slice(0, j);
2706
2471
  }
2707
- return Utils4.Math.sum(tieNoteGroups.map((ng) => ng.rhythmProps.ticks));
2472
+ return Utils3.Math.sum(tieNoteGroups.map((ng) => ng.rhythmProps.ticks));
2708
2473
  });
2709
2474
  return tiedTicks.length === 0 ? this.rhythmProps.ticks : Math.max(...tiedTicks);
2710
2475
  }
@@ -2887,110 +2652,25 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2887
2652
  ctx.stroke();
2888
2653
  }
2889
2654
  } else {
2890
- ctx.beginPath();
2891
- ctx.ellipse(r.centerX, r.centerY, r.leftw, r.toph, -0.3, 0, Math.PI * 2);
2892
- if (isSolidNoteHead) {
2893
- ctx.fill();
2894
- } else {
2895
- ctx.stroke();
2896
- }
2897
- }
2898
- });
2899
- obj.dotRects.forEach((r) => renderer.fillCircle(r.centerX, r.centerY, r.width / 2));
2900
- if (obj.stemTip && obj.stemBase) {
2901
- ctx.beginPath();
2902
- ctx.moveTo(obj.stemBase.centerX, obj.stemBase.centerY);
2903
- ctx.lineTo(obj.stemTip.centerX, obj.stemTip.centerY);
2904
- ctx.stroke();
2905
- }
2906
- obj.flagRects.forEach((rect) => {
2907
- let left = rect.left;
2908
- let right = rect.right;
2909
- let width = right - left;
2910
- let top = stemDir === "up" /* Up */ ? rect.top : rect.bottom;
2911
- let bottom = stemDir === "up" /* Up */ ? rect.bottom : rect.top;
2912
- ctx.beginPath();
2913
- ctx.moveTo(left, top);
2914
- ctx.bezierCurveTo(
2915
- left,
2916
- top * 0.75 + bottom * 0.25,
2917
- left + width * 1.5,
2918
- top * 0.5 + bottom * 0.5,
2919
- left + width * 0.5,
2920
- bottom
2921
- );
2922
- ctx.stroke();
2923
- });
2924
- });
2925
- this.tabObjects.forEach((obj) => obj.fretNumbers.forEach((fn) => fn.draw(renderer)));
2926
- }
2927
- static setBeamCounts(groupNotes) {
2928
- const isADottedBHalf = (a, b) => {
2929
- let { flagCount: aFlagCount, noteSize: aNoteSize, dotCount: aDotCount } = a.rhythmProps;
2930
- let { flagCount: bFlagCount, noteSize: bNoteSize, dotCount: bDotCount } = b.rhythmProps;
2931
- return aFlagCount > 0 && bFlagCount > 0 && aDotCount > 0 && bDotCount === 0 && aNoteSize * Math.pow(2, aDotCount) === bNoteSize;
2932
- };
2933
- for (let i = 0; i < groupNotes.length; i++) {
2934
- let center = groupNotes[i];
2935
- let left = groupNotes[i - 1];
2936
- let right = groupNotes[i + 1];
2937
- if (center) {
2938
- center.leftBeamCount = 0;
2939
- center.rightBeamCount = 0;
2940
- if (left) {
2941
- if (left.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(left, center) || isADottedBHalf(center, left)) {
2942
- center.leftBeamCount = center.rhythmProps.flagCount;
2943
- } else {
2944
- center.leftBeamCount = Math.min(left.rhythmProps.flagCount, center.rhythmProps.flagCount);
2945
- }
2946
- }
2947
- if (right) {
2948
- if (right.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(right, center) || isADottedBHalf(center, right)) {
2949
- center.rightBeamCount = center.rhythmProps.flagCount;
2950
- } else {
2951
- center.rightBeamCount = Math.min(right.rhythmProps.flagCount, center.rhythmProps.flagCount);
2952
- }
2953
- }
2954
- }
2955
- }
2956
- let fixAgain;
2957
- do {
2958
- fixAgain = false;
2959
- for (let i = 0; i < groupNotes.length; i++) {
2960
- let center = groupNotes[i];
2961
- let left = groupNotes[i - 1];
2962
- let right = groupNotes[i + 1];
2963
- if (center && center.leftBeamCount !== center.rhythmProps.flagCount && center.rightBeamCount !== center.rhythmProps.flagCount) {
2964
- center.leftBeamCount = center.rightBeamCount = 0;
2965
- if (left && left.rightBeamCount > 0) {
2966
- left.rightBeamCount = 0;
2967
- fixAgain = true;
2968
- }
2969
- if (right && right.leftBeamCount > 0) {
2970
- right.leftBeamCount = 0;
2971
- fixAgain = true;
2972
- }
2973
- }
2974
- }
2975
- } while (fixAgain);
2976
- }
2977
- static setTupletBeamCounts(tuplet) {
2978
- let type = tuplet.getType();
2979
- let symbols = tuplet.getSymbols();
2980
- if (type === 1 /* TupletBeam */) {
2981
- symbols.forEach((s, i) => {
2982
- if (s instanceof _ObjNoteGroup) {
2983
- s.leftBeamCount = i === 0 ? 0 : s.rhythmProps.flagCount;
2984
- s.rightBeamCount = i === symbols.length - 1 ? 0 : s.rhythmProps.flagCount;
2985
- }
2986
- });
2987
- } else if (type === 2 /* TupletGroup */) {
2988
- symbols.forEach((s) => {
2989
- if (s instanceof _ObjNoteGroup) {
2990
- s.leftBeamCount = s.rightBeamCount = 0;
2655
+ ctx.beginPath();
2656
+ ctx.ellipse(r.centerX, r.centerY, r.leftw, r.toph, -0.3, 0, Math.PI * 2);
2657
+ if (isSolidNoteHead) {
2658
+ ctx.fill();
2659
+ } else {
2660
+ ctx.stroke();
2661
+ }
2991
2662
  }
2992
2663
  });
2993
- }
2664
+ obj.dotRects.forEach((r) => renderer.fillCircle(r.centerX, r.centerY, r.width / 2));
2665
+ if (obj.stemTip && obj.stemBase) {
2666
+ ctx.beginPath();
2667
+ ctx.moveTo(obj.stemBase.centerX, obj.stemBase.centerY);
2668
+ ctx.lineTo(obj.stemTip.centerX, obj.stemTip.centerY);
2669
+ ctx.stroke();
2670
+ }
2671
+ obj.flagRects.forEach((rect) => renderer.drawFlag(rect, stemDir === "up" /* Up */ ? "up" : "down"));
2672
+ });
2673
+ this.tabObjects.forEach((obj) => obj.fretNumbers.forEach((fn) => fn.draw(renderer)));
2994
2674
  }
2995
2675
  getDotVerticalDisplacement(staff, diatonicId, stemDir) {
2996
2676
  if (staff.isLine(diatonicId)) {
@@ -3015,10 +2695,10 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
3015
2695
  };
3016
2696
 
3017
2697
  // src/score/engine/obj-rhythm-column.ts
3018
- import { MusicError as MusicError8, MusicErrorType as MusicErrorType8 } from "@tspro/web-music-score/core";
2698
+ import { MusicError as MusicError7, MusicErrorType as MusicErrorType7 } from "@tspro/web-music-score/core";
3019
2699
 
3020
2700
  // src/score/engine/obj-lyrics.ts
3021
- import { Utils as Utils5 } from "@tspro/ts-utils-lib";
2701
+ import { Utils as Utils4 } from "@tspro/ts-utils-lib";
3022
2702
  var LyricsContainer = class {
3023
2703
  constructor(col, lyricsLength) {
3024
2704
  this.col = col;
@@ -3045,7 +2725,7 @@ var ObjLyrics = class extends MusicObject {
3045
2725
  __publicField(this, "text");
3046
2726
  __publicField(this, "mi");
3047
2727
  let halign = (lyricsOptions == null ? void 0 : lyricsOptions.align) === "left" /* Left */ ? 0 : (lyricsOptions == null ? void 0 : lyricsOptions.align) === "right" /* Right */ ? 1 : 0.5;
3048
- this.hyphen = Utils5.Is.isEnumValue(lyricsOptions == null ? void 0 : lyricsOptions.hyphen, LyricsHyphen) ? lyricsOptions == null ? void 0 : lyricsOptions.hyphen : void 0;
2728
+ this.hyphen = Utils4.Is.isEnumValue(lyricsOptions == null ? void 0 : lyricsOptions.hyphen, LyricsHyphen) ? lyricsOptions == null ? void 0 : lyricsOptions.hyphen : void 0;
3049
2729
  this.text = new ObjText(this, { text: lyricsText, color: this.color, scale: 0.8 }, halign, 0);
3050
2730
  this.rect = new DivRect();
3051
2731
  this.mi = new MLyrics(this);
@@ -3098,11 +2778,11 @@ var ObjLyrics = class extends MusicObject {
3098
2778
 
3099
2779
  // src/score/engine/obj-rhythm-column.ts
3100
2780
  var noteHeadDataCompareFunc = (a, b) => {
3101
- let cmp2 = Note5.compareFunc(a.note, b.note);
3102
- if (cmp2 === 0) {
3103
- cmp2 = a.noteGroup.stemDir === b.noteGroup.stemDir ? 0 : a.noteGroup.stemDir === "up" /* Up */ ? 1 : -1;
2781
+ let cmp = Note5.compareFunc(a.note, b.note);
2782
+ if (cmp === 0) {
2783
+ cmp = a.noteGroup.stemDir === b.noteGroup.stemDir ? 0 : a.noteGroup.stemDir === "up" /* Up */ ? 1 : -1;
3104
2784
  }
3105
- return cmp2;
2785
+ return cmp;
3106
2786
  };
3107
2787
  var ObjRhythmColumn = class extends MusicObject {
3108
2788
  constructor(measure, positionTicks) {
@@ -3140,7 +2820,7 @@ var ObjRhythmColumn = class extends MusicObject {
3140
2820
  if (colId >= 0 && colId < this.measure.getColumnCount()) {
3141
2821
  return this.measure.getColumn(colId + 1);
3142
2822
  } else {
3143
- throw new MusicError8(MusicErrorType8.Score, "Cannot get next column in measure because current column's id in mesure is invalid.");
2823
+ throw new MusicError7(MusicErrorType7.Score, "Cannot get next column in measure because current column's id in mesure is invalid.");
3144
2824
  }
3145
2825
  }
3146
2826
  /**
@@ -3242,7 +2922,7 @@ var ObjRhythmColumn = class extends MusicObject {
3242
2922
  getLyricsContainer(verse, line, vpos, lyricsLength) {
3243
2923
  let data = this.lyricsContainers.find((data2) => data2.verse === verse && data2.line === line && data2.vpos === vpos);
3244
2924
  if (data === void 0 && lyricsLength !== void 0) {
3245
- data = { lyricsContainer: new LyricsContainer(this, validateNoteLength(lyricsLength)), verse, line, vpos };
2925
+ data = { lyricsContainer: new LyricsContainer(this, validateNoteLength2(lyricsLength)), verse, line, vpos };
3246
2926
  this.lyricsContainers.push(data);
3247
2927
  this.requestLayout();
3248
2928
  this.requestRectUpdate();
@@ -3465,10 +3145,10 @@ var ObjRhythmColumn = class extends MusicObject {
3465
3145
  };
3466
3146
 
3467
3147
  // src/score/engine/extension.ts
3468
- import { MusicError as MusicError9, MusicErrorType as MusicErrorType9 } from "@tspro/web-music-score/core";
3148
+ import { MusicError as MusicError8, MusicErrorType as MusicErrorType8 } from "@tspro/web-music-score/core";
3469
3149
 
3470
3150
  // src/score/engine/element-data.ts
3471
- import { Utils as Utils6 } from "@tspro/ts-utils-lib";
3151
+ import { Utils as Utils5 } from "@tspro/ts-utils-lib";
3472
3152
 
3473
3153
  // src/score/engine/obj-special-text.ts
3474
3154
  var _ObjSpecialText = class _ObjSpecialText extends MusicObject {
@@ -3590,23 +3270,23 @@ function getNavigationString(navigation) {
3590
3270
  }
3591
3271
  }
3592
3272
  function isDynamicsText(text) {
3593
- return Utils6.Is.isEnumValue(text, DynamicsAnnotation);
3273
+ return Utils5.Is.isEnumValue(text, DynamicsAnnotation);
3594
3274
  }
3595
3275
  function getDynamicsVolume(text) {
3596
3276
  if (/^(p+|f+|m|mp|mf)$/.test(text)) {
3597
- let volume = 0.5 - Utils6.Str.charCount(text, "p") * 0.1 + Utils6.Str.charCount(text, "f") * 0.1;
3598
- return Utils6.Math.clamp(volume, 0, 1);
3277
+ let volume = 0.5 - Utils5.Str.charCount(text, "p") * 0.1 + Utils5.Str.charCount(text, "f") * 0.1;
3278
+ return Utils5.Math.clamp(volume, 0, 1);
3599
3279
  } else {
3600
3280
  return void 0;
3601
3281
  }
3602
3282
  }
3603
3283
  function isTempoText(text) {
3604
- return Utils6.Is.isEnumValue(text, TempoAnnotation);
3284
+ return Utils5.Is.isEnumValue(text, TempoAnnotation);
3605
3285
  }
3606
3286
  function getAnnotation(text) {
3607
- if (Utils6.Is.isEnumValue(text, DynamicsAnnotation)) {
3287
+ if (Utils5.Is.isEnumValue(text, DynamicsAnnotation)) {
3608
3288
  return "dynamics" /* Dynamics */;
3609
- } else if (Utils6.Is.isEnumValue(text, TempoAnnotation)) {
3289
+ } else if (Utils5.Is.isEnumValue(text, TempoAnnotation)) {
3610
3290
  return "tempo" /* Tempo */;
3611
3291
  } else {
3612
3292
  return void 0;
@@ -3649,7 +3329,7 @@ var Extension = class extends MusicObjectLink {
3649
3329
  if (head instanceof ObjText) {
3650
3330
  head.updateAnchorY(getTextAnchorY(linePos));
3651
3331
  } else {
3652
- throw new MusicError9(MusicErrorType9.Score, "Update anchor's y-coordinate is only implemented for text objects.");
3332
+ throw new MusicError8(MusicErrorType8.Score, "Update anchor's y-coordinate is only implemented for text objects.");
3653
3333
  }
3654
3334
  }
3655
3335
  isVisible() {
@@ -3762,7 +3442,7 @@ var PlayerColumnProps = class {
3762
3442
  return this.speed;
3763
3443
  }
3764
3444
  getTempo() {
3765
- let speed = Utils7.Math.clamp(this.getSpeed(), 0.1, 10);
3445
+ let speed = Utils6.Math.clamp(this.getSpeed(), 0.1, 10);
3766
3446
  return alterTempoSpeed(this.measure.getTempo(), speed);
3767
3447
  }
3768
3448
  setVolume(volume) {
@@ -3787,7 +3467,7 @@ var PlayerColumnProps = class {
3787
3467
  if (symbolsTicks.length === 0) {
3788
3468
  return 0;
3789
3469
  } else {
3790
- return Utils7.Math.sum(symbolsTicks) / symbolsTicks.length;
3470
+ return Utils6.Math.sum(symbolsTicks) / symbolsTicks.length;
3791
3471
  }
3792
3472
  }
3793
3473
  }
@@ -3936,7 +3616,7 @@ var Player = class _Player {
3936
3616
  } else if (layoutObj.musicObj.getLink() instanceof Extension) {
3937
3617
  let extension = layoutObj.musicObj.getLink();
3938
3618
  let { columnRange, extensionBreakText } = extension.getExtensionRangeInfo();
3939
- let totalTicks = Utils7.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
3619
+ let totalTicks = Utils6.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
3940
3620
  switch (text) {
3941
3621
  case "accel." /* accel */: {
3942
3622
  let startSpeed = curSpeed;
@@ -3990,11 +3670,11 @@ var Player = class _Player {
3990
3670
  });
3991
3671
  let speedArr = (_a = speedMap.get(col)) != null ? _a : [];
3992
3672
  if (speedArr.length > 0) {
3993
- curSpeed = Utils7.Math.sum(speedArr) / speedArr.length;
3673
+ curSpeed = Utils6.Math.sum(speedArr) / speedArr.length;
3994
3674
  }
3995
3675
  let volumeArr = (_b = volumeMap.get(col)) != null ? _b : [];
3996
3676
  if (volumeArr.length > 0) {
3997
- curVolume = Utils7.Math.sum(volumeArr) / volumeArr.length;
3677
+ curVolume = Utils6.Math.sum(volumeArr) / volumeArr.length;
3998
3678
  }
3999
3679
  col.getPlayerProps().setSpeed(curSpeed);
4000
3680
  col.getPlayerProps().setVolume(curVolume);
@@ -4296,118 +3976,591 @@ var ObjBarLineRight = class extends ObjBarLine {
4296
3976
  getMusicInterface() {
4297
3977
  return this.mi;
4298
3978
  }
4299
- getPlayerProps() {
4300
- return this.playerProps;
3979
+ getPlayerProps() {
3980
+ return this.playerProps;
3981
+ }
3982
+ solveBarLineType() {
3983
+ let m = this.measure;
3984
+ let next = m.getNextMeasure();
3985
+ if (m.hasNavigation("endRepeat" /* EndRepeat */)) {
3986
+ if (next && next.row === m.row && next.hasNavigation("startRepeat" /* StartRepeat */)) {
3987
+ return 6 /* EndStartRepeat */;
3988
+ } else {
3989
+ return 5 /* EndRepeat */;
3990
+ }
3991
+ } else if (!m.doc.hasSingleMeasure() && (m.hasEndSong() || !m.getNextMeasure())) {
3992
+ return 3 /* EndSong */;
3993
+ } else if (m.hasEndSection()) {
3994
+ return 2 /* Double */;
3995
+ }
3996
+ if (m === m.row.getLastMeasure() && next && next.row === m.row.getNextRow() && next.hasNavigation("startRepeat" /* StartRepeat */)) {
3997
+ return 2 /* Double */;
3998
+ }
3999
+ if (next && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4000
+ return 0 /* None */;
4001
+ }
4002
+ return 1 /* Single */;
4003
+ }
4004
+ };
4005
+
4006
+ // src/score/engine/obj-ending.ts
4007
+ import { Utils as Utils7 } from "@tspro/ts-utils-lib";
4008
+ import { MusicError as MusicError9, MusicErrorType as MusicErrorType9 } from "@tspro/web-music-score/core";
4009
+ var ObjEnding = class extends MusicObject {
4010
+ constructor(measure, passages) {
4011
+ super(measure);
4012
+ this.measure = measure;
4013
+ this.passages = passages;
4014
+ __publicField(this, "endingText");
4015
+ __publicField(this, "shapeRects", []);
4016
+ __publicField(this, "mi");
4017
+ this.mi = new MEnding(this);
4018
+ if (!Utils7.Is.isIntegerGte(passages.length, 1)) {
4019
+ throw new MusicError9(MusicErrorType9.Score, "Passages is empty.");
4020
+ } else if (!this.passages.every((p) => Utils7.Is.isIntegerGte(p, 1))) {
4021
+ throw new MusicError9(MusicErrorType9.Score, "Invalid passages: " + this.passages);
4022
+ }
4023
+ this.passages.sort((a, b) => a - b);
4024
+ let text = this.passages.map((p) => p + ".").join("");
4025
+ this.endingText = new ObjText(this, text, 0, 1);
4026
+ }
4027
+ getMusicInterface() {
4028
+ return this.mi;
4029
+ }
4030
+ getShapeRects() {
4031
+ return this.shapeRects;
4032
+ }
4033
+ isSingleMeasureEnding() {
4034
+ let { measure } = this;
4035
+ let next = measure.getNextMeasure();
4036
+ return (next == null ? void 0 : next.hasNavigation("ending" /* Ending */)) === true || measure.hasNavigation("endRepeat" /* EndRepeat */) || measure.isLastMeasure();
4037
+ }
4038
+ hasPassage(pass) {
4039
+ return this.passages.some((p) => p === pass);
4040
+ }
4041
+ getHighestPassage() {
4042
+ return Math.max(0, ...this.passages);
4043
+ }
4044
+ pick(x, y) {
4045
+ return this.rect.contains(x, y) ? [this] : [];
4046
+ }
4047
+ layout(renderer) {
4048
+ this.rect = new DivRect();
4049
+ this.shapeRects = [this.rect.copy()];
4050
+ }
4051
+ layoutFitToMeasure(renderer) {
4052
+ let { unitSize } = renderer;
4053
+ let { measure } = this;
4054
+ this.endingText.layout(renderer);
4055
+ let textRect = this.endingText.getRect();
4056
+ let measureContent = measure.getColumnsContentRect();
4057
+ let endingHeight = textRect.height;
4058
+ this.rect = new DivRect(measureContent.left + unitSize, measureContent.right - unitSize, -endingHeight, 0);
4059
+ this.endingText.offset(this.rect.left + unitSize / 2, this.rect.bottom);
4060
+ this.shapeRects = [
4061
+ new DivRect(this.rect.left, this.rect.left + 1, this.rect.top, this.rect.bottom),
4062
+ new DivRect(this.rect.left, this.rect.right, this.rect.top, this.rect.top + 1),
4063
+ new DivRect(this.rect.right - 1, this.rect.right, this.rect.top, this.rect.bottom),
4064
+ this.endingText.getRect().copy()
4065
+ ];
4066
+ }
4067
+ offset(dx, dy) {
4068
+ this.endingText.offset(dx, dy);
4069
+ this.shapeRects.forEach((r) => r.offsetInPlace(dx, dy));
4070
+ this.rect.offsetInPlace(dx, dy);
4071
+ }
4072
+ draw(renderer) {
4073
+ let ctx = renderer.getCanvasContext();
4074
+ if (!ctx) {
4075
+ return;
4076
+ }
4077
+ let { lineWidth } = renderer;
4078
+ let { rect } = this;
4079
+ renderer.drawDebugRect(this.rect);
4080
+ ctx.strokeStyle = ctx.fillStyle = "black";
4081
+ ctx.lineWidth = lineWidth;
4082
+ ctx.beginPath();
4083
+ ctx.moveTo(rect.left, rect.bottom);
4084
+ ctx.lineTo(rect.left, rect.top);
4085
+ ctx.lineTo(rect.right, rect.top);
4086
+ if (this.isSingleMeasureEnding()) {
4087
+ ctx.lineTo(rect.right, rect.bottom);
4088
+ }
4089
+ ctx.stroke();
4090
+ this.endingText.draw(renderer);
4091
+ }
4092
+ };
4093
+
4094
+ // src/score/engine/obj-beam-group.ts
4095
+ import { Utils as Utils8 } from "@tspro/ts-utils-lib";
4096
+ import { NoteLength as NoteLength7, Tuplet as Tuplet3, NoteLengthProps as NoteLengthProps4 } from "@tspro/web-music-score/theory";
4097
+ import { MusicError as MusicError10, MusicErrorType as MusicErrorType10 } from "@tspro/web-music-score/core";
4098
+ var adjustBeamAngle = (dx, dy) => {
4099
+ let T = DocumentSettings.BeamAngleFactor;
4100
+ if (!Number.isFinite(T) || T === 0) {
4101
+ return dy;
4102
+ } else {
4103
+ let k = dx / dy / T;
4104
+ k = Math.sign(k) * Math.sqrt(Math.abs(k));
4105
+ return dx / k * T;
4106
+ }
4107
+ };
4108
+ var BeamPoint = class {
4109
+ constructor(staff, beamGroup, symbol, x, y) {
4110
+ this.staff = staff;
4111
+ this.beamGroup = beamGroup;
4112
+ this.symbol = symbol;
4113
+ this.x = x;
4114
+ this.y = y;
4115
+ __publicField(this, "topBeamsHeight", 0);
4116
+ __publicField(this, "bottomBeamsHeight", 0);
4117
+ staff.addObject(this);
4118
+ }
4119
+ offset(dx, dy) {
4120
+ this.x += dx;
4121
+ this.y += dy;
4122
+ this.beamGroup.requestRectUpdate();
4123
+ }
4124
+ getRect() {
4125
+ return new DivRect(this.x, this.x, this.x, this.y - this.topBeamsHeight, this.y, this.y + this.bottomBeamsHeight);
4126
+ }
4127
+ };
4128
+ var ObjStaffBeamGroup = class extends MusicObject {
4129
+ constructor(staff, beamGroup) {
4130
+ super(staff);
4131
+ this.staff = staff;
4132
+ this.beamGroup = beamGroup;
4133
+ __publicField(this, "tupletNumber");
4134
+ __publicField(this, "tupletNumberOffsetY", 0);
4135
+ __publicField(this, "points", []);
4136
+ __publicField(this, "mi");
4137
+ staff.addObject(this);
4138
+ this.mi = new MStaffBeamGroup(this);
4139
+ }
4140
+ getMusicInterface() {
4141
+ return this.mi;
4142
+ }
4143
+ pick(x, y) {
4144
+ return this.getRect().contains(x, y) ? [this] : [];
4145
+ }
4146
+ offset(dx, dy) {
4147
+ var _a;
4148
+ this.points.forEach((p) => p.offset(dx, 0));
4149
+ (_a = this.tupletNumber) == null ? void 0 : _a.offset(dx, dy);
4150
+ this.requestRectUpdate();
4151
+ this.beamGroup.requestRectUpdate();
4152
+ }
4153
+ updateRect() {
4154
+ if (this.points.length > 0) {
4155
+ this.rect = this.points[0].getRect().copy();
4156
+ } else if (this.tupletNumber) {
4157
+ this.rect = this.tupletNumber.getRect().copy();
4158
+ }
4159
+ this.points.forEach((pt) => this.rect.expandInPlace(pt.getRect()));
4160
+ if (this.tupletNumber) {
4161
+ this.rect.expandInPlace(this.tupletNumber.getRect());
4162
+ }
4163
+ }
4164
+ };
4165
+ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
4166
+ constructor(symbols, tupletRatio) {
4167
+ super(symbols[0].measure);
4168
+ this.symbols = symbols;
4169
+ this.tupletRatio = tupletRatio;
4170
+ __publicField(this, "mi");
4171
+ __publicField(this, "type");
4172
+ __publicField(this, "staffObjects", []);
4173
+ this.mi = new MBeamGroup(this);
4174
+ let beamGroupName = tupletRatio ? "Tuplet" : "BeamGroup";
4175
+ if (!symbols.every((s) => s.measure === symbols[0].measure)) {
4176
+ throw new MusicError10(MusicErrorType10.Score, `All ${beamGroupName} symbols are not in same measure.`);
4177
+ } else if (symbols.length < 2) {
4178
+ throw new MusicError10(MusicErrorType10.Score, `${beamGroupName} needs minimum 2 symbols, but ${symbols.length} given.`);
4179
+ }
4180
+ if (tupletRatio !== void 0) {
4181
+ let isGroup = symbols.length < 3 || symbols.some((s) => !(s instanceof ObjNoteGroup)) || symbols.some((s) => s.rhythmProps.flagCount !== symbols[0].rhythmProps.flagCount);
4182
+ if (symbols.length >= 3 && symbols[0] instanceof ObjNoteGroup && symbols[symbols.length - 1] instanceof ObjNoteGroup && symbols[0].rhythmProps.flagCount === symbols[symbols.length - 1].rhythmProps.flagCount) {
4183
+ isGroup = false;
4184
+ }
4185
+ if (symbols.some((s) => NoteLengthProps4.cmp(s.rhythmProps.noteLength, NoteLength7.Quarter) >= 0)) {
4186
+ isGroup = true;
4187
+ }
4188
+ this.type = isGroup ? 2 /* TupletGroup */ : 1 /* TupletBeam */;
4189
+ this.setTupletBeamCounts();
4190
+ } else {
4191
+ this.type = 0 /* RegularBeam */;
4192
+ this.setBeamCounts();
4193
+ }
4194
+ if (symbols.every((s) => s.getBeamGroup() === void 0)) {
4195
+ symbols.forEach((s) => s.setBeamGroup(this));
4196
+ symbols[0].measure.addBeamGroup(this);
4197
+ } else {
4198
+ throw new MusicError10(MusicErrorType10.Score, `Cannot add ${beamGroupName} because some symbol already has one.`);
4199
+ }
4200
+ if (this.type === 0 /* RegularBeam */) {
4201
+ this.symbols.filter((sym) => sym instanceof ObjNoteGroup).some((sym, i) => {
4202
+ let first = i === 0;
4203
+ let last = i === this.symbols.length - 1;
4204
+ if (first && sym.getRightBeamCount() === 0 || last && sym.getLeftBeamCount() === 0 || !first && !last && (sym.getLeftBeamCount() === 0 || sym.getRightBeamCount() === 0)) {
4205
+ this.detach();
4206
+ }
4207
+ });
4208
+ }
4209
+ }
4210
+ get showTupletRatio() {
4211
+ var _a;
4212
+ return ((_a = this.tupletRatio) == null ? void 0 : _a.showRatio) === true;
4213
+ }
4214
+ static createBeam(noteGroups) {
4215
+ if (noteGroups.length > 1 && noteGroups.every((ng) => !ng.hasTuplet())) {
4216
+ new _ObjBeamGroup(noteGroups, void 0);
4217
+ }
4218
+ }
4219
+ static createOldStyleTriplet(symbols) {
4220
+ let s2 = symbols.slice(0, 2);
4221
+ let n2 = s2.map((s) => s.rhythmProps.noteSize);
4222
+ if (s2.length === 2 && s2.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && (n2[0] * 2 === n2[1] || n2[1] * 2 === n2[0])) {
4223
+ new _ObjBeamGroup(s2, Tuplet3.Triplet);
4224
+ return 2;
4225
+ }
4226
+ let s3 = symbols.slice(0, 3);
4227
+ let n3 = s3.map((s) => s.rhythmProps.noteSize);
4228
+ if (s3.length === 3 && s3.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && n3.every((n) => n === n3[0])) {
4229
+ new _ObjBeamGroup(s3, Tuplet3.Triplet);
4230
+ return 3;
4231
+ }
4232
+ return 0;
4233
+ }
4234
+ static createTuplet(symbols, tupletRatio) {
4235
+ new _ObjBeamGroup(symbols, tupletRatio);
4236
+ }
4237
+ getMusicInterface() {
4238
+ return this.mi;
4239
+ }
4240
+ detach() {
4241
+ this.getSymbols().forEach((s) => s.resetBeamGroup());
4301
4242
  }
4302
- solveBarLineType() {
4303
- let m = this.measure;
4304
- let next = m.getNextMeasure();
4305
- if (m.hasNavigation("endRepeat" /* EndRepeat */)) {
4306
- if (next && next.row === m.row && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4307
- return 6 /* EndStartRepeat */;
4308
- } else {
4309
- return 5 /* EndRepeat */;
4310
- }
4311
- } else if (!m.doc.hasSingleMeasure() && (m.hasEndSong() || !m.getNextMeasure())) {
4312
- return 3 /* EndSong */;
4313
- } else if (m.hasEndSection()) {
4314
- return 2 /* Double */;
4315
- }
4316
- if (m === m.row.getLastMeasure() && next && next.row === m.row.getNextRow() && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4317
- return 2 /* Double */;
4243
+ isEmpty() {
4244
+ return this.staffObjects.length === 0;
4245
+ }
4246
+ pick(x, y) {
4247
+ if (!this.getRect().contains(x, y)) {
4248
+ return [];
4318
4249
  }
4319
- if (next && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4320
- return 0 /* None */;
4250
+ for (let i = 0; i < this.staffObjects.length; i++) {
4251
+ let arr = this.staffObjects[i].pick(x, y);
4252
+ if (arr.length > 0) {
4253
+ return [this, ...arr];
4254
+ }
4321
4255
  }
4322
- return 1 /* Single */;
4256
+ return [this];
4323
4257
  }
4324
- };
4325
-
4326
- // src/score/engine/obj-ending.ts
4327
- import { Utils as Utils8 } from "@tspro/ts-utils-lib";
4328
- import { MusicError as MusicError10, MusicErrorType as MusicErrorType10 } from "@tspro/web-music-score/core";
4329
- var ObjEnding = class extends MusicObject {
4330
- constructor(measure, passages) {
4331
- super(measure);
4332
- this.measure = measure;
4333
- this.passages = passages;
4334
- __publicField(this, "endingText");
4335
- __publicField(this, "shapeRects", []);
4336
- __publicField(this, "mi");
4337
- this.mi = new MEnding(this);
4338
- if (!Utils8.Is.isIntegerGte(passages.length, 1)) {
4339
- throw new MusicError10(MusicErrorType10.Score, "Passages is empty.");
4340
- } else if (!this.passages.every((p) => Utils8.Is.isIntegerGte(p, 1))) {
4341
- throw new MusicError10(MusicErrorType10.Score, "Invalid passages: " + this.passages);
4342
- }
4343
- this.passages.sort((a, b) => a - b);
4344
- let text = this.passages.map((p) => p + ".").join("");
4345
- this.endingText = new ObjText(this, text, 0, 1);
4258
+ getType() {
4259
+ return this.type;
4346
4260
  }
4347
- getMusicInterface() {
4348
- return this.mi;
4261
+ isTuplet() {
4262
+ return this.type === 1 /* TupletBeam */ || this.type === 2 /* TupletGroup */;
4349
4263
  }
4350
- getShapeRects() {
4351
- return this.shapeRects;
4264
+ getTupletRatioText() {
4265
+ var _a, _b, _c;
4266
+ return this.showTupletRatio ? String((_a = this.tupletRatio) == null ? void 0 : _a.parts) + ":" + String((_b = this.tupletRatio) == null ? void 0 : _b.inTimeOf) : String((_c = this.tupletRatio) == null ? void 0 : _c.parts);
4352
4267
  }
4353
- isSingleMeasureEnding() {
4354
- let { measure } = this;
4355
- let next = measure.getNextMeasure();
4356
- return (next == null ? void 0 : next.hasNavigation("ending" /* Ending */)) === true || measure.hasNavigation("endRepeat" /* EndRepeat */) || measure.isLastMeasure();
4268
+ getSymbols() {
4269
+ return this.symbols;
4357
4270
  }
4358
- hasPassage(pass) {
4359
- return this.passages.some((p) => p === pass);
4271
+ getFirstSymbol() {
4272
+ return this.symbols[0];
4360
4273
  }
4361
- getHighestPassage() {
4362
- return Math.max(0, ...this.passages);
4274
+ getLastSymbol() {
4275
+ return this.symbols[this.symbols.length - 1];
4363
4276
  }
4364
- pick(x, y) {
4365
- return this.rect.contains(x, y) ? [this] : [];
4277
+ get stemDir() {
4278
+ return this.symbols[0].ownStemDir;
4366
4279
  }
4367
4280
  layout(renderer) {
4368
- this.rect = new DivRect();
4369
- this.shapeRects = [this.rect.copy()];
4370
- }
4371
- layoutFitToMeasure(renderer) {
4281
+ this.requestRectUpdate();
4282
+ this.staffObjects.length = 0;
4283
+ let symbols = this.getSymbols();
4284
+ if (symbols.length === 0) {
4285
+ return;
4286
+ }
4287
+ let voiceId = symbols[0].voiceId;
4288
+ if (symbols.some((symbol) => symbol.voiceId !== voiceId)) {
4289
+ return;
4290
+ }
4372
4291
  let { unitSize } = renderer;
4373
- let { measure } = this;
4374
- this.endingText.layout(renderer);
4375
- let textRect = this.endingText.getRect();
4376
- let measureContent = measure.getColumnsContentRect();
4377
- let endingHeight = textRect.height;
4378
- this.rect = new DivRect(measureContent.left + unitSize, measureContent.right - unitSize, -endingHeight, 0);
4379
- this.endingText.offset(this.rect.left + unitSize / 2, this.rect.bottom);
4380
- this.shapeRects = [
4381
- new DivRect(this.rect.left, this.rect.left + 1, this.rect.top, this.rect.bottom),
4382
- new DivRect(this.rect.left, this.rect.right, this.rect.top, this.rect.top + 1),
4383
- new DivRect(this.rect.right - 1, this.rect.right, this.rect.top, this.rect.bottom),
4384
- this.endingText.getRect().copy()
4385
- ];
4292
+ let { stemDir } = this;
4293
+ let symbolsBeamCoords = symbols.map((s) => s.getBeamCoords());
4294
+ symbolsBeamCoords[0].map((s) => s == null ? void 0 : s.staff).forEach((mainStaff, index) => {
4295
+ var _a, _b;
4296
+ if (!mainStaff) {
4297
+ return;
4298
+ }
4299
+ let symbolX = symbolsBeamCoords.map((s) => {
4300
+ var _a2;
4301
+ return (_a2 = s[index]) == null ? void 0 : _a2.x;
4302
+ });
4303
+ let symbolY = symbolsBeamCoords.map((s) => {
4304
+ var _a2;
4305
+ return (_a2 = s[index]) == null ? void 0 : _a2.y;
4306
+ });
4307
+ let symbolStaff = symbolsBeamCoords.map((s) => {
4308
+ var _a2;
4309
+ return (_a2 = s[index]) == null ? void 0 : _a2.staff;
4310
+ });
4311
+ let symbolStemHeight = symbolsBeamCoords.map((s) => {
4312
+ var _a2;
4313
+ return (_a2 = s[index]) == null ? void 0 : _a2.stemHeight;
4314
+ });
4315
+ let leftSymbol = symbols[0];
4316
+ let leftX = symbolX[0];
4317
+ let leftY = symbolY[0];
4318
+ let leftStaff = symbolStaff[0];
4319
+ let rightSymbol = symbols[symbols.length - 1];
4320
+ let rightX = symbolX[symbolX.length - 1];
4321
+ let rightY = symbolY[symbolY.length - 1];
4322
+ let rightStaff = symbolStaff[symbolY.length - 1];
4323
+ if (leftX === void 0 || leftY === void 0 || leftStaff === void 0 || rightX === void 0 || rightY === void 0 || rightStaff === void 0) {
4324
+ return;
4325
+ }
4326
+ let leftStemHeight = (_a = symbolStemHeight[0]) != null ? _a : 0;
4327
+ let rightStemHeight = (_b = symbolStemHeight[symbolStemHeight.length - 1]) != null ? _b : 0;
4328
+ if (this.type !== 2 /* TupletGroup */) {
4329
+ let leftDy = leftStemHeight < rightStemHeight ? Math.sqrt(rightStemHeight - leftStemHeight) : 0;
4330
+ let rightDy = rightStemHeight < leftStemHeight ? Math.sqrt(leftStemHeight - rightStemHeight) : 0;
4331
+ if (stemDir === "up" /* Up */) {
4332
+ leftDy *= -1;
4333
+ rightDy *= -1;
4334
+ }
4335
+ if (leftDy !== 0) {
4336
+ leftY += leftDy;
4337
+ symbolY[0] += leftDy;
4338
+ }
4339
+ if (rightDy !== 0) {
4340
+ rightY += rightDy;
4341
+ symbolY[symbolY.length - 1] += rightDy;
4342
+ }
4343
+ }
4344
+ let groupLineDy = unitSize * 2 * (stemDir === "up" /* Up */ ? -1 : 1);
4345
+ let centerY = (rightY + leftY) / 2;
4346
+ let halfDy = adjustBeamAngle(rightX - leftX, rightY - leftY) / 2;
4347
+ leftY = centerY - halfDy;
4348
+ rightY = centerY + halfDy;
4349
+ let raiseBeamY = 0;
4350
+ symbolY.forEach((symY, i) => {
4351
+ let symX = symbolX[i];
4352
+ if (symX !== void 0 && symY !== void 0) {
4353
+ let beamY = Utils8.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
4354
+ let raiseY = symY - beamY;
4355
+ if (stemDir === "up" /* Up */ && raiseY < 0) {
4356
+ raiseBeamY = Math.min(raiseBeamY, raiseY);
4357
+ } else if (stemDir === "down" /* Down */ && raiseY > 0) {
4358
+ raiseBeamY = Math.max(raiseBeamY, raiseY);
4359
+ }
4360
+ }
4361
+ });
4362
+ leftY += raiseBeamY;
4363
+ rightY += raiseBeamY;
4364
+ symbolY = symbolY.map((y) => y === void 0 ? void 0 : y + raiseBeamY);
4365
+ let obj = new ObjStaffBeamGroup(mainStaff, this);
4366
+ if (this.type === 2 /* TupletGroup */) {
4367
+ let ef = unitSize / (rightX - leftX);
4368
+ let l = Utils8.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, -ef);
4369
+ let r = Utils8.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, 1 + ef);
4370
+ obj.points.push(new BeamPoint(leftStaff, this, leftSymbol, l.x, l.y));
4371
+ obj.points.push(new BeamPoint(rightStaff, this, rightSymbol, r.x, r.y));
4372
+ obj.tupletNumberOffsetY = 0;
4373
+ } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
4374
+ raiseBeamY *= 0.5;
4375
+ let { beamThickness } = renderer;
4376
+ const beamHeight = (i) => {
4377
+ let sym = symbols[i];
4378
+ if (sym instanceof ObjNoteGroup) {
4379
+ let beamCount = sym instanceof ObjNoteGroup ? Math.max(sym.getLeftBeamCount(), sym.getRightBeamCount()) : 0;
4380
+ return DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? beamCount - 1 : 0);
4381
+ } else {
4382
+ return 0;
4383
+ }
4384
+ };
4385
+ symbols.forEach((sym, i) => {
4386
+ let symStaff = symbolStaff[i];
4387
+ let symX = symbolX[i];
4388
+ let symY = symbolY[i];
4389
+ if (symStaff && symX !== void 0 && symY !== void 0) {
4390
+ let pt = new BeamPoint(symStaff, this, sym, symX, symY);
4391
+ pt.topBeamsHeight = beamThickness / 2 + (stemDir === "down" /* Down */ ? beamHeight(i) : 0);
4392
+ pt.bottomBeamsHeight = beamThickness / 2 + (stemDir === "up" /* Up */ ? beamHeight(i) : 0);
4393
+ obj.points.push(pt);
4394
+ }
4395
+ });
4396
+ obj.tupletNumberOffsetY = groupLineDy;
4397
+ }
4398
+ if (this.isTuplet()) {
4399
+ obj.tupletNumber = new ObjText(this, this.getTupletRatioText(), 0.5, 0.5);
4400
+ obj.tupletNumber.layout(renderer);
4401
+ obj.tupletNumber.offset((leftX + rightX) / 2, (leftY + rightY) / 2 + obj.tupletNumberOffsetY);
4402
+ }
4403
+ if (obj.points.length >= 2) {
4404
+ this.staffObjects.push(obj);
4405
+ }
4406
+ });
4407
+ }
4408
+ updateRect() {
4409
+ if (this.staffObjects.length === 0) {
4410
+ this.rect = new DivRect();
4411
+ } else {
4412
+ this.staffObjects.forEach((obj) => obj.updateRect());
4413
+ this.rect = this.staffObjects[0].getRect().copy();
4414
+ for (let i = 1; i < this.staffObjects.length; i++) {
4415
+ this.rect.expandInPlace(this.staffObjects[i].getRect());
4416
+ }
4417
+ }
4418
+ }
4419
+ updateStemTips() {
4420
+ this.staffObjects.forEach((obj) => {
4421
+ let left = obj.points[0];
4422
+ let right = obj.points[obj.points.length - 1];
4423
+ if (this.type !== 2 /* TupletGroup */) {
4424
+ obj.points.forEach((pt) => {
4425
+ if (pt.symbol instanceof ObjNoteGroup) {
4426
+ if (pt !== left && pt !== right) {
4427
+ pt.y = Utils8.Math.interpolateY(left.x, left.y, right.x, right.y, pt.x);
4428
+ }
4429
+ pt.symbol.setStemTipY(pt.staff, pt.y);
4430
+ }
4431
+ });
4432
+ }
4433
+ if (obj.tupletNumber) {
4434
+ let y = (left.y + right.y) / 2 + obj.tupletNumberOffsetY;
4435
+ obj.tupletNumber.offset(0, -obj.tupletNumber.getRect().centerY + y);
4436
+ }
4437
+ });
4386
4438
  }
4387
4439
  offset(dx, dy) {
4388
- this.endingText.offset(dx, dy);
4389
- this.shapeRects.forEach((r) => r.offsetInPlace(dx, dy));
4390
- this.rect.offsetInPlace(dx, dy);
4440
+ this.staffObjects.forEach((obj) => obj.offset(dx, 0));
4441
+ this.requestRectUpdate();
4391
4442
  }
4392
4443
  draw(renderer) {
4393
- let ctx = renderer.getCanvasContext();
4394
- if (!ctx) {
4395
- return;
4444
+ let { unitSize, beamThickness, lineWidth } = renderer;
4445
+ let color = "black";
4446
+ this.staffObjects.forEach((obj) => {
4447
+ if (this.type === 2 /* TupletGroup */) {
4448
+ let l = obj.points[0];
4449
+ let r = obj.points[obj.points.length - 1];
4450
+ if (l && r) {
4451
+ let tf = obj.tupletNumber ? obj.tupletNumber.getRect().width / (r.x - l.x) * 1.2 : 0;
4452
+ let lc = Utils8.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 - tf / 2);
4453
+ let rc = Utils8.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 + tf / 2);
4454
+ let tipH = this.stemDir === "up" /* Up */ ? unitSize : -unitSize;
4455
+ renderer.drawLine(l.x, l.y, lc.x, lc.y, color, lineWidth);
4456
+ renderer.drawLine(rc.x, rc.y, r.x, r.y, color, lineWidth);
4457
+ renderer.drawLine(l.x, l.y, l.x, l.y + tipH, color, lineWidth);
4458
+ renderer.drawLine(r.x, r.y, r.x, r.y + tipH, color, lineWidth);
4459
+ }
4460
+ } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
4461
+ let beamSeparation = DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? 1 : -1);
4462
+ let noteGroupPoints = obj.points.filter((p) => p.symbol instanceof ObjNoteGroup);
4463
+ for (let i = 0; i < noteGroupPoints.length - 1; i++) {
4464
+ let left = noteGroupPoints[i];
4465
+ let right = noteGroupPoints[i + 1];
4466
+ if (!(left.symbol instanceof ObjNoteGroup && right.symbol instanceof ObjNoteGroup)) {
4467
+ continue;
4468
+ }
4469
+ let leftBeamCount = left.symbol.getRightBeamCount();
4470
+ let rightBeamCount = right.symbol.getLeftBeamCount();
4471
+ let lx = left.x;
4472
+ let ly = left.y;
4473
+ let rx = right.x;
4474
+ let ry = right.y;
4475
+ let dy = beamSeparation * (1 + 0.5 * Math.abs(Math.atan2(ry - ly, rx - lx)));
4476
+ for (let beamId = 0; beamId < Math.max(leftBeamCount, rightBeamCount); beamId++) {
4477
+ if (beamId < leftBeamCount && beamId < rightBeamCount) {
4478
+ renderer.drawLine(lx, ly, rx, ry, color, beamThickness);
4479
+ } else if (leftBeamCount > rightBeamCount) {
4480
+ renderer.drawPartialLine(lx, ly, rx, ry, 0, 0.25, color, beamThickness);
4481
+ } else if (rightBeamCount > leftBeamCount) {
4482
+ renderer.drawPartialLine(lx, ly, rx, ry, 0.75, 1, color, beamThickness);
4483
+ }
4484
+ ly += dy;
4485
+ ry += dy;
4486
+ }
4487
+ }
4488
+ }
4489
+ if (obj.tupletNumber) {
4490
+ obj.tupletNumber.draw(renderer);
4491
+ }
4492
+ });
4493
+ }
4494
+ setBeamCounts() {
4495
+ const isADottedBHalf = (a, b) => {
4496
+ let { flagCount: aFlagCount, noteSize: aNoteSize, dotCount: aDotCount } = a.rhythmProps;
4497
+ let { flagCount: bFlagCount, noteSize: bNoteSize, dotCount: bDotCount } = b.rhythmProps;
4498
+ return aFlagCount > 0 && bFlagCount > 0 && aDotCount > 0 && bDotCount === 0 && aNoteSize * Math.pow(2, aDotCount) === bNoteSize;
4499
+ };
4500
+ let groupNotes = this.symbols.filter((s) => s instanceof ObjNoteGroup);
4501
+ for (let i = 0; i < groupNotes.length; i++) {
4502
+ let center = groupNotes[i];
4503
+ let left = groupNotes[i - 1];
4504
+ let right = groupNotes[i + 1];
4505
+ if (center) {
4506
+ center.setLeftBeamCount(0);
4507
+ center.setRightBeamCount(0);
4508
+ if (left) {
4509
+ if (left.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(left, center) || isADottedBHalf(center, left)) {
4510
+ center.setLeftBeamCount(center.rhythmProps.flagCount);
4511
+ } else {
4512
+ center.setLeftBeamCount(Math.min(left.rhythmProps.flagCount, center.rhythmProps.flagCount));
4513
+ }
4514
+ }
4515
+ if (right) {
4516
+ if (right.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(right, center) || isADottedBHalf(center, right)) {
4517
+ center.setRightBeamCount(center.rhythmProps.flagCount);
4518
+ } else {
4519
+ center.setRightBeamCount(Math.min(right.rhythmProps.flagCount, center.rhythmProps.flagCount));
4520
+ }
4521
+ }
4522
+ }
4396
4523
  }
4397
- let { lineWidth } = renderer;
4398
- let { rect } = this;
4399
- renderer.drawDebugRect(this.rect);
4400
- ctx.strokeStyle = ctx.fillStyle = "black";
4401
- ctx.lineWidth = lineWidth;
4402
- ctx.beginPath();
4403
- ctx.moveTo(rect.left, rect.bottom);
4404
- ctx.lineTo(rect.left, rect.top);
4405
- ctx.lineTo(rect.right, rect.top);
4406
- if (this.isSingleMeasureEnding()) {
4407
- ctx.lineTo(rect.right, rect.bottom);
4524
+ let fixAgain;
4525
+ do {
4526
+ fixAgain = false;
4527
+ for (let i = 0; i < groupNotes.length; i++) {
4528
+ let center = groupNotes[i];
4529
+ let left = groupNotes[i - 1];
4530
+ let right = groupNotes[i + 1];
4531
+ if (center && center.getLeftBeamCount() !== center.rhythmProps.flagCount && center.getRightBeamCount() !== center.rhythmProps.flagCount) {
4532
+ center.setLeftBeamCount(0);
4533
+ center.setRightBeamCount(0);
4534
+ if (left && left.getRightBeamCount() > 0) {
4535
+ left.setRightBeamCount(0);
4536
+ fixAgain = true;
4537
+ }
4538
+ if (right && right.getLeftBeamCount() > 0) {
4539
+ right.setLeftBeamCount(0);
4540
+ fixAgain = true;
4541
+ }
4542
+ }
4543
+ }
4544
+ } while (fixAgain);
4545
+ }
4546
+ setTupletBeamCounts() {
4547
+ let type = this.getType();
4548
+ let symbols = this.getSymbols();
4549
+ if (type === 1 /* TupletBeam */) {
4550
+ symbols.forEach((s, i) => {
4551
+ if (s instanceof ObjNoteGroup) {
4552
+ s.setLeftBeamCount(i === 0 ? 0 : s.rhythmProps.flagCount);
4553
+ s.setRightBeamCount(i === symbols.length - 1 ? 0 : s.rhythmProps.flagCount);
4554
+ }
4555
+ });
4556
+ } else if (type === 2 /* TupletGroup */) {
4557
+ symbols.forEach((s) => {
4558
+ if (s instanceof ObjNoteGroup) {
4559
+ s.setLeftBeamCount(0);
4560
+ s.setRightBeamCount(0);
4561
+ }
4562
+ });
4408
4563
  }
4409
- ctx.stroke();
4410
- this.endingText.draw(renderer);
4411
4564
  }
4412
4565
  };
4413
4566
 
@@ -4852,8 +5005,147 @@ var ConnectiveProps = class {
4852
5005
  }
4853
5006
  };
4854
5007
 
5008
+ // src/score/engine/obj-tab-rhythm.ts
5009
+ import { Utils as Utils11 } from "@tspro/ts-utils-lib";
5010
+ var ObjTabRhythm = class extends MusicObject {
5011
+ constructor(measure, tab) {
5012
+ super(measure);
5013
+ this.measure = measure;
5014
+ this.tab = tab;
5015
+ __publicField(this, "voiceIds");
5016
+ __publicField(this, "mi");
5017
+ // Keep non-static
5018
+ __publicField(this, "tupletPartsTextObjMap", /* @__PURE__ */ new Map());
5019
+ this.voiceIds = getVoiceIds().filter((voiceId) => tab.containsVoiceId(voiceId));
5020
+ this.rect = new DivRect();
5021
+ this.mi = new MTabRhythm(this);
5022
+ }
5023
+ getMusicInterface() {
5024
+ return this.mi;
5025
+ }
5026
+ pick(x, y) {
5027
+ return this.rect.contains(x, y) ? [this] : [];
5028
+ }
5029
+ layout(renderer) {
5030
+ let columns = this.measure.getColumns();
5031
+ let numColsInVoiceId = getVoiceIds().map((voiceId) => Utils11.Math.sum(columns.map((col) => col.getVoiceSymbol(voiceId) ? 1 : 0)));
5032
+ this.voiceIds.sort((a, b) => Utils11.Math.cmp(numColsInVoiceId[a], numColsInVoiceId[b]));
5033
+ this.rect = new DivRect();
5034
+ }
5035
+ hasTuplets() {
5036
+ return this.measure.getBeamGroups().some((beamGroup) => beamGroup.isTuplet());
5037
+ }
5038
+ layoutFitToMeasure(renderer) {
5039
+ let { unitSize, fontSize } = renderer;
5040
+ let { measure } = this;
5041
+ let { left, right } = measure.getColumnsContentRect();
5042
+ let stemHeight = unitSize * 5;
5043
+ this.rect.left = left;
5044
+ this.rect.centerX = (left + right) / 2;
5045
+ this.rect.right = right;
5046
+ this.rect.top = this.hasTuplets() ? -fontSize : 0;
5047
+ this.rect.centerY = 0;
5048
+ this.rect.bottom = stemHeight;
5049
+ }
5050
+ offset(dx, dy) {
5051
+ this.rect.offsetInPlace(dx, dy);
5052
+ }
5053
+ draw(renderer) {
5054
+ const ctx = renderer.getCanvasContext();
5055
+ if (!ctx) {
5056
+ return;
5057
+ }
5058
+ renderer.drawDebugRect(this.rect);
5059
+ let { unitSize, lineWidth, fontSize } = renderer;
5060
+ let flagSize = unitSize;
5061
+ let dotSpace = unitSize;
5062
+ let dotWidth = unitSize * 0.25;
5063
+ let { bottom, centerY } = this.getRect();
5064
+ let stemTop = centerY;
5065
+ let stemBottom = bottom;
5066
+ let columns = this.measure.getColumns();
5067
+ for (let colId = 0; colId < columns.length; colId++) {
5068
+ let cur = columns[colId];
5069
+ let curVoiceSymbol = this.voiceIds.map((voiceId) => cur.getVoiceSymbol(voiceId)).find((sym) => sym !== void 0);
5070
+ if (!curVoiceSymbol) {
5071
+ continue;
5072
+ }
5073
+ let beamGroup = curVoiceSymbol.getBeamGroup();
5074
+ let symbols = beamGroup ? beamGroup.getSymbols() : [curVoiceSymbol];
5075
+ for (let j = 0; j < symbols.length; j++) {
5076
+ let sym = symbols[j];
5077
+ let nextSym = symbols[j + 1];
5078
+ let colX = sym.col.getRect().centerX;
5079
+ if (sym instanceof ObjNoteGroup) {
5080
+ if (sym.rhythmProps.noteSize >= 2) {
5081
+ let stemThickness = sym.rhythmProps.noteSize === 4 ? lineWidth * 2 : lineWidth;
5082
+ renderer.drawLine(colX, stemBottom, colX, stemTop, "black", stemThickness);
5083
+ }
5084
+ if (symbols.length === 1) {
5085
+ for (let i = 0; i < sym.rhythmProps.flagCount; i++) {
5086
+ renderer.drawFlag(new DivRect(colX, colX + flagSize, stemTop + i * flagSize, stemTop + (i + 2) * flagSize), "up");
5087
+ }
5088
+ }
5089
+ for (let i = 0; i < sym.rhythmProps.dotCount; i++) {
5090
+ renderer.fillCircle(colX + dotSpace * (i + 1), stemBottom - dotWidth, dotWidth);
5091
+ }
5092
+ } else if (sym instanceof ObjRest) {
5093
+ let cx = colX;
5094
+ let cy = (stemTop + stemBottom) / 2;
5095
+ let scale = 0.65;
5096
+ ctx.save();
5097
+ ctx.scale(scale, scale);
5098
+ renderer.drawRest(sym.rhythmProps.noteSize, cx / scale, cy / scale, "black");
5099
+ ctx.restore();
5100
+ for (let i = 0; i < sym.rhythmProps.dotCount; i++) {
5101
+ cx += dotSpace * 1.5;
5102
+ renderer.fillCircle(cx, cy + dotSpace, dotWidth);
5103
+ }
5104
+ }
5105
+ if (nextSym) {
5106
+ let left = sym;
5107
+ let right = nextSym;
5108
+ let leftX = left.col.getRect().centerX;
5109
+ let rightX = right.col.getRect().centerX;
5110
+ let leftBeamCount = left.hasTuplet() ? 1 : left instanceof ObjNoteGroup ? left.getRightBeamCount() : 1;
5111
+ let rightBeamCount = right.hasTuplet() ? 1 : right instanceof ObjNoteGroup ? right.getLeftBeamCount() : 1;
5112
+ let maxBeamCount = Math.max(leftBeamCount, rightBeamCount);
5113
+ for (let i = 0; i < maxBeamCount; i++) {
5114
+ let leftT = rightBeamCount > leftBeamCount && i >= leftBeamCount ? 0.75 : 0;
5115
+ let rightT = leftBeamCount > rightBeamCount && i >= rightBeamCount ? 0.25 : 1;
5116
+ renderer.drawPartialLine(leftX, stemTop + i * flagSize, rightX, stemTop + i * flagSize, leftT, rightT, "black", lineWidth * 2);
5117
+ }
5118
+ for (let i = 0; i < left.rhythmProps.dotCount; i++) {
5119
+ renderer.fillCircle(leftX + dotSpace * (i + 1), stemBottom - dotWidth, dotWidth);
5120
+ }
5121
+ for (let i = 0; i < right.rhythmProps.dotCount; i++) {
5122
+ renderer.fillCircle(rightX + dotSpace * (i + 1), stemBottom - dotWidth, dotWidth);
5123
+ }
5124
+ }
5125
+ if (beamGroup && beamGroup.isTuplet()) {
5126
+ let cx = (symbols[0].col.getRect().centerX + symbols[symbols.length - 1].col.getRect().centerX) / 2;
5127
+ let text = beamGroup.getTupletRatioText();
5128
+ let textObj = this.tupletPartsTextObjMap.get(text);
5129
+ if (!textObj) {
5130
+ this.tupletPartsTextObjMap.set(text, textObj = new ObjText(this, { text, scale: 0.75 }, 0.5, 0.5));
5131
+ textObj.layout(renderer);
5132
+ }
5133
+ textObj.offset(-textObj.getRect().centerX, -textObj.getRect().centerY);
5134
+ textObj.offset(cx, stemTop - fontSize / 2);
5135
+ textObj.draw(renderer);
5136
+ }
5137
+ if (symbols.length > 1) {
5138
+ colId = columns.indexOf(symbols[symbols.length - 1].col);
5139
+ if (colId < 0) {
5140
+ colId = columns.length;
5141
+ }
5142
+ }
5143
+ }
5144
+ }
5145
+ }
5146
+ };
5147
+
4855
5148
  // src/score/engine/obj-measure.ts
4856
- var cmp = (a, b) => a === b ? 0 : a < b ? -1 : 1;
4857
5149
  function validateVoiceId(voiceId) {
4858
5150
  if (typeof voiceId === "number" && getVoiceIds().indexOf(voiceId) < 0) {
4859
5151
  throw new MusicError13(MusicErrorType13.Score, "Invalid voiceId: " + voiceId);
@@ -4865,7 +5157,7 @@ function getExtensionTicks(extensionLength) {
4865
5157
  if (typeof extensionLength === "string") {
4866
5158
  extensionLength = [extensionLength];
4867
5159
  }
4868
- if (Utils11.Is.isArray(extensionLength)) {
5160
+ if (Utils12.Is.isArray(extensionLength)) {
4869
5161
  let totalTicks = 0;
4870
5162
  for (let i = 0; i < extensionLength.length; ) {
4871
5163
  let str = extensionLength[i];
@@ -4890,11 +5182,11 @@ function getExtensionTicks(extensionLength) {
4890
5182
  function getVerseLayoutGroupId(verse) {
4891
5183
  switch (verse) {
4892
5184
  case 1:
4893
- return 7 /* LyricsVerse1 */;
5185
+ return 8 /* LyricsVerse1 */;
4894
5186
  case 2:
4895
- return 8 /* LyricsVerse2 */;
5187
+ return 9 /* LyricsVerse2 */;
4896
5188
  case 3:
4897
- return 9 /* LyricsVerse3 */;
5189
+ return 10 /* LyricsVerse3 */;
4898
5190
  default:
4899
5191
  throw new MusicError13(MusicErrorType13.Unknown, "VerseNumber is not 1, 2 or 3.");
4900
5192
  }
@@ -4956,6 +5248,9 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
4956
5248
  this.updateKeySignature();
4957
5249
  this.updateTimeSignature();
4958
5250
  this.updateTempo();
5251
+ this.row.getTabs().forEach((tab) => {
5252
+ this.addLayoutObject(new ObjTabRhythm(this, tab), tab, 0 /* TabRhythm */, 0 /* Above */);
5253
+ });
4959
5254
  }
4960
5255
  getMusicInterface() {
4961
5256
  return this.mi;
@@ -5127,7 +5422,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5127
5422
  this.alterKeySignature = args[0];
5128
5423
  } else if (args[0] instanceof Scale) {
5129
5424
  this.alterKeySignature = args[0];
5130
- } else if (Utils11.Is.isNonEmptyString(args[0])) {
5425
+ } else if (Utils12.Is.isNonEmptyString(args[0])) {
5131
5426
  if (args.length === 1) {
5132
5427
  this.alterKeySignature = getScale(args[0]);
5133
5428
  } else if (args.length === 2) {
@@ -5180,9 +5475,9 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5180
5475
  if (beatLength === void 0) {
5181
5476
  this.alterTempo = { beatsPerMinute };
5182
5477
  } else {
5183
- let dotCount = typeof dotted === "number" && dotted > 0 ? dotted : dotted === true ? 1 : NoteLengthProps4.get(beatLength).dotCount;
5478
+ let dotCount = typeof dotted === "number" && dotted > 0 ? dotted : dotted === true ? 1 : NoteLengthProps5.get(beatLength).dotCount;
5184
5479
  let options = {
5185
- beatLength: validateNoteLength2(beatLength),
5480
+ beatLength: validateNoteLength3(beatLength),
5186
5481
  dotCount: dotCount > 0 ? dotCount : void 0
5187
5482
  };
5188
5483
  this.alterTempo = { beatsPerMinute, options };
@@ -5238,7 +5533,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5238
5533
  let grp = this.doc.getStaffGroup(staffTabOrGroup);
5239
5534
  if (grp && !prevGroups.includes(staffTabOrGroup)) {
5240
5535
  let curGroups = [...prevGroups, staffTabOrGroup];
5241
- (Utils11.Is.isArray(grp.staffsTabsAndGroups) ? grp.staffsTabsAndGroups : [grp.staffsTabsAndGroups]).forEach((staffTabOrGroup2) => {
5536
+ (Utils12.Is.isArray(grp.staffsTabsAndGroups) ? grp.staffsTabsAndGroups : [grp.staffsTabsAndGroups]).forEach((staffTabOrGroup2) => {
5242
5537
  switch (grp.verticalPosition) {
5243
5538
  case "above" /* Above */:
5244
5539
  addToStaffTabOrGroup(staffTabOrGroup2, 0 /* Above */, curGroups);
@@ -5260,12 +5555,12 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5260
5555
  }
5261
5556
  };
5262
5557
  if (staffTabOrGroups === void 0) {
5263
- 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()) {
5558
+ if (lines.length >= 2 && lines[0] instanceof ObjStaff && lines[1] instanceof ObjStaff && lines[0].staffConfig.grandId !== void 0 && lines[0].staffConfig.grandId === lines[1].staffConfig.grandId) {
5264
5559
  addToStaffTabOrGroup(defaultVerticalPos === 1 /* Below */ ? 1 : 0, defaultVerticalPos);
5265
5560
  } else {
5266
5561
  addToStaffTabOrGroup(0, defaultVerticalPos);
5267
5562
  }
5268
- } else if (Utils11.Is.isArray(staffTabOrGroups)) {
5563
+ } else if (Utils12.Is.isArray(staffTabOrGroups)) {
5269
5564
  staffTabOrGroups.forEach((staffTabOrGroup) => addToStaffTabOrGroup(staffTabOrGroup, defaultVerticalPos));
5270
5565
  } else {
5271
5566
  addToStaffTabOrGroup(staffTabOrGroups, defaultVerticalPos);
@@ -5277,7 +5572,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5277
5572
  throw new MusicError13(MusicErrorType13.Score, "Cannot add Fermata because anchor is undefined.");
5278
5573
  }
5279
5574
  this.forEachStaffGroup(staffTabOrGroups, 0 /* Above */, (line, vpos) => {
5280
- this.addLayoutObject(new ObjFermata(anchor, vpos), line, 0 /* Fermata */, vpos);
5575
+ this.addLayoutObject(new ObjFermata(anchor, vpos), line, 1 /* Fermata */, vpos);
5281
5576
  });
5282
5577
  this.disableExtension();
5283
5578
  this.requestLayout();
@@ -5296,7 +5591,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5296
5591
  let passages = args;
5297
5592
  addLayoutObjectProps = {
5298
5593
  createObj: () => new ObjEnding(anchor, passages),
5299
- layoutGroupId: 3 /* Ending */,
5594
+ layoutGroupId: 4 /* Ending */,
5300
5595
  defaultVerticalPos: 0 /* Above */
5301
5596
  };
5302
5597
  break;
@@ -5308,7 +5603,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5308
5603
  let text = getNavigationString(navigation);
5309
5604
  addLayoutObjectProps = {
5310
5605
  createObj: () => new ObjText(anchor2, text, 1, 1),
5311
- layoutGroupId: 2 /* Navigation */,
5606
+ layoutGroupId: 3 /* Navigation */,
5312
5607
  defaultVerticalPos: 0 /* Above */
5313
5608
  };
5314
5609
  this.addNavigation(staffTabOrGroups, "endRepeat" /* EndRepeat */);
@@ -5320,7 +5615,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5320
5615
  let text = getNavigationString(navigation);
5321
5616
  addLayoutObjectProps = {
5322
5617
  createObj: () => new ObjText(anchor2, text, 1, 1),
5323
- layoutGroupId: 2 /* Navigation */,
5618
+ layoutGroupId: 3 /* Navigation */,
5324
5619
  defaultVerticalPos: 0 /* Above */
5325
5620
  };
5326
5621
  break;
@@ -5331,7 +5626,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5331
5626
  let text = getNavigationString(navigation);
5332
5627
  addLayoutObjectProps = {
5333
5628
  createObj: () => new ObjSpecialText(anchor2, text),
5334
- layoutGroupId: 2 /* Navigation */,
5629
+ layoutGroupId: 3 /* Navigation */,
5335
5630
  defaultVerticalPos: 0 /* Above */
5336
5631
  };
5337
5632
  break;
@@ -5341,7 +5636,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5341
5636
  let text = getNavigationString(navigation);
5342
5637
  addLayoutObjectProps = {
5343
5638
  createObj: () => new ObjSpecialText(anchor2, text),
5344
- layoutGroupId: 2 /* Navigation */,
5639
+ layoutGroupId: 3 /* Navigation */,
5345
5640
  defaultVerticalPos: 0 /* Above */
5346
5641
  };
5347
5642
  break;
@@ -5349,7 +5644,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5349
5644
  case "endRepeat" /* EndRepeat */:
5350
5645
  if (args.length === 0) {
5351
5646
  this.endRepeatPlayCount = 2;
5352
- } else if (Utils11.Is.isIntegerGte(args[0], 2)) {
5647
+ } else if (Utils12.Is.isIntegerGte(args[0], 2)) {
5353
5648
  this.endRepeatPlayCount = args[0];
5354
5649
  } else {
5355
5650
  throw new MusicError13(MusicErrorType13.Score, "Invalid end repeat play count (should be 2 or greater integer): " + args[0]);
@@ -5386,12 +5681,12 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5386
5681
  let defaultVerticalPos;
5387
5682
  switch (annotation) {
5388
5683
  case "dynamics" /* Dynamics */:
5389
- layoutGroupId = 5 /* DynamicsAnnotation */;
5684
+ layoutGroupId = 6 /* DynamicsAnnotation */;
5390
5685
  defaultVerticalPos = 0 /* Above */;
5391
5686
  textProps.italic = true;
5392
5687
  break;
5393
5688
  case "tempo" /* Tempo */:
5394
- layoutGroupId = 4 /* TempoAnnotation */;
5689
+ layoutGroupId = 5 /* TempoAnnotation */;
5395
5690
  defaultVerticalPos = 0 /* Above */;
5396
5691
  textProps.italic = true;
5397
5692
  break;
@@ -5415,11 +5710,11 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5415
5710
  let defaultVerticalPos;
5416
5711
  switch (label) {
5417
5712
  case "note" /* Note */:
5418
- layoutGroupId = 1 /* NoteLabel */;
5713
+ layoutGroupId = 2 /* NoteLabel */;
5419
5714
  defaultVerticalPos = 1 /* Below */;
5420
5715
  break;
5421
5716
  case "chord" /* Chord */:
5422
- layoutGroupId = 6 /* ChordLabel */;
5717
+ layoutGroupId = 7 /* ChordLabel */;
5423
5718
  defaultVerticalPos = 0 /* Above */;
5424
5719
  break;
5425
5720
  }
@@ -5436,15 +5731,15 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5436
5731
  throw new MusicError13(MusicErrorType13.Score, "Connective can be added to note group only.");
5437
5732
  }
5438
5733
  if (connective === "tie" /* Tie */) {
5439
- let tieSpan = Utils11.Is.isInteger(args[0]) || Utils11.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
5440
- let noteAnchor = Utils11.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
5734
+ let tieSpan = Utils12.Is.isInteger(args[0]) || Utils12.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
5735
+ let noteAnchor = Utils12.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
5441
5736
  anchor.startConnective(new ConnectiveProps("tie" /* Tie */, tieSpan, noteAnchor, anchor));
5442
5737
  } else if (connective === "slur" /* Slur */) {
5443
- let slurSpan = Utils11.Is.isInteger(args[0]) ? args[0] : 2;
5444
- let noteAnchor = Utils11.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
5738
+ let slurSpan = Utils12.Is.isInteger(args[0]) ? args[0] : 2;
5739
+ let noteAnchor = Utils12.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
5445
5740
  anchor.startConnective(new ConnectiveProps("slur" /* Slur */, slurSpan, noteAnchor, anchor));
5446
5741
  } else if (connective === "slide" /* Slide */) {
5447
- let noteAnchor = Utils11.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : "auto" /* Auto */;
5742
+ let noteAnchor = Utils12.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : "auto" /* Auto */;
5448
5743
  anchor.startConnective(new ConnectiveProps("slide" /* Slide */, 2, noteAnchor, anchor));
5449
5744
  }
5450
5745
  }
@@ -5527,12 +5822,12 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5527
5822
  addLyrics(staffTabOrGroups, verse, lyricsLength, lyricsText, lyricsOptions) {
5528
5823
  this.forEachStaffGroup(staffTabOrGroups, 1 /* Below */, (line, vpos) => {
5529
5824
  let col = this.getRhythmColumn({ verse, line, vpos });
5530
- let lyricsContainer = col.getLyricsContainer(verse, line, vpos, validateNoteLength2(lyricsLength));
5825
+ let lyricsContainer = col.getLyricsContainer(verse, line, vpos, validateNoteLength3(lyricsLength));
5531
5826
  if (lyricsContainer) {
5532
5827
  let lyricsObj = new ObjLyrics(col, verse, line, vpos, lyricsText, lyricsOptions);
5533
5828
  let lyricsArr = this.getLyricsObjects(lyricsObj.line, lyricsObj.vpos, lyricsObj.verse);
5534
5829
  lyricsArr.push(lyricsObj);
5535
- lyricsArr.sort((a, b) => cmp(a.col.positionTicks, b.col.positionTicks));
5830
+ lyricsArr.sort((a, b) => Utils12.Math.cmp(a.col.positionTicks, b.col.positionTicks));
5536
5831
  lyricsContainer.addLyricsObject(lyricsObj);
5537
5832
  this.addLayoutObject(lyricsObj, line, getVerseLayoutGroupId(verse), vpos);
5538
5833
  }
@@ -5724,6 +6019,9 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5724
6019
  }
5725
6020
  this.requestLayout();
5726
6021
  }
6022
+ getBeamGroups() {
6023
+ return this.beamGroups;
6024
+ }
5727
6025
  createBeams() {
5728
6026
  if (!this.needBeamsUpdate) {
5729
6027
  return;
@@ -5742,72 +6040,42 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5742
6040
  }
5743
6041
  getVoiceIds().forEach((voiceId) => {
5744
6042
  let symbols = this.getVoiceSymbols(voiceId).slice();
5745
- if (symbols.length >= 2) {
5746
- let symbolsStartTicks = this.isUpBeat() ? Math.max(0, this.getMeasureTicks() - this.getConsumedTicks()) : 0;
5747
- let groupStartTicks = 0;
5748
- for (let groupId = 0; groupId < ts.beamGroupSizes.length; groupId++) {
5749
- let beamGroupSize = ts.beamGroupSizes[groupId];
5750
- let groupSizeSum = 0;
5751
- beamGroupSize.forEach((s) => groupSizeSum += s);
5752
- let groupLength = groupSizeSum * NoteLengthProps4.get("8n").ticks;
5753
- let groupSymbols = [];
5754
- let groupSymbolsLength = 0;
5755
- while (symbols.length > 0 && groupSymbolsLength < groupLength) {
5756
- let symbol = symbols[0];
5757
- if (symbol.col.positionTicks >= groupStartTicks) {
5758
- groupSymbols.push(symbol);
5759
- groupSymbolsLength += symbol.rhythmProps.ticks;
5760
- symbols.shift();
5761
- } else {
5762
- break;
6043
+ if (symbols.length < 2) {
6044
+ return;
6045
+ }
6046
+ let upBeatStartTicks = this.isUpBeat() ? Math.max(0, this.getMeasureTicks() - this.getConsumedTicks()) : 0;
6047
+ let groupStartTicks = 0;
6048
+ for (let groupId = 0; groupId < ts.beamGroupSizes.length; groupId++) {
6049
+ let beamGroupSize = ts.beamGroupSizes[groupId];
6050
+ let beamGroupSizeList = [beamGroupSize];
6051
+ if (beamGroupSize.length > 1) {
6052
+ beamGroupSizeList.unshift([Utils12.Math.sum(beamGroupSize)]);
6053
+ }
6054
+ let beamsCreated = false;
6055
+ let groupStartTicksSave = groupStartTicks;
6056
+ while (beamGroupSizeList.length > 0 && !beamsCreated) {
6057
+ let beamGroupSize2 = beamGroupSizeList.shift();
6058
+ groupStartTicks = groupStartTicksSave;
6059
+ beamGroupSize2.forEach((beamGroupSize3) => {
6060
+ let beamGroupTicks = beamGroupSize3 * NoteLengthProps5.get("8n").ticks;
6061
+ let groupSymbols = symbols.filter((symbol) => {
6062
+ let symbolStartTicks = upBeatStartTicks + symbol.col.positionTicks;
6063
+ let symbolTicks = symbol.rhythmProps.ticks;
6064
+ return symbolStartTicks >= groupStartTicks && symbolStartTicks + symbolTicks <= groupStartTicks + beamGroupTicks;
6065
+ });
6066
+ let groupNotesTicks = Utils12.Math.sum(groupSymbols.map((sym) => sym.rhythmProps.ticks));
6067
+ if (groupNotesTicks === beamGroupTicks && groupSymbols.every((n) => n instanceof ObjNoteGroup) && (groupSymbols.every((n) => n.rhythmProps.flagCount === 1) || beamGroupSizeList.length === 0)) {
6068
+ ObjBeamGroup.createBeam(groupSymbols);
6069
+ beamsCreated = true;
5763
6070
  }
5764
- }
5765
- _ObjMeasure.setupBeamGroup(groupSymbols, beamGroupSize);
5766
- symbolsStartTicks += groupSymbolsLength;
5767
- groupStartTicks += groupLength;
6071
+ groupStartTicks += beamGroupTicks;
6072
+ });
5768
6073
  }
5769
6074
  }
5770
6075
  });
5771
6076
  this.needBeamsUpdate = false;
5772
6077
  this.requestLayout();
5773
6078
  }
5774
- static setupBeamGroup(groupSymbols, mainBeamGroupSizeArr) {
5775
- if (mainBeamGroupSizeArr.length === 0) {
5776
- return false;
5777
- }
5778
- let groupNotes = groupSymbols.map((s) => {
5779
- var _a;
5780
- return s instanceof ObjNoteGroup && ((_a = s.getBeamGroup()) == null ? void 0 : _a.isTuplet()) !== true ? s : void 0;
5781
- });
5782
- ObjNoteGroup.setBeamCounts(groupNotes);
5783
- let beamGroupSizeArrList = [mainBeamGroupSizeArr];
5784
- if (mainBeamGroupSizeArr.length > 1) {
5785
- let sum = 0;
5786
- mainBeamGroupSizeArr.forEach((s) => sum += s);
5787
- beamGroupSizeArrList.unshift([sum]);
5788
- }
5789
- let beamsCreated = false;
5790
- while (beamGroupSizeArrList.length > 0 && !beamsCreated) {
5791
- let beamGroupSizeArr = beamGroupSizeArrList.shift();
5792
- let groupSymbolsCopy = groupSymbols.slice();
5793
- beamGroupSizeArr.forEach((beamGroupSize) => {
5794
- var _a;
5795
- let beamGroupLength = beamGroupSize * NoteLengthProps4.get("8n").ticks;
5796
- let beamNotesLength = 0;
5797
- let beamNotes = [];
5798
- while (beamNotesLength < beamGroupLength && groupSymbolsCopy.length > 0) {
5799
- let symbol = groupSymbolsCopy.shift();
5800
- beamNotesLength += symbol.rhythmProps.ticks;
5801
- beamNotes.push(symbol instanceof ObjNoteGroup && ((_a = symbol.getBeamGroup()) == null ? void 0 : _a.isTuplet()) !== true ? symbol : void 0);
5802
- }
5803
- if (beamNotesLength === beamGroupLength && beamNotes.every((n) => n !== void 0) && (beamNotes.every((n) => n.rhythmProps.flagCount === 1) || beamGroupSizeArrList.length === 0)) {
5804
- ObjBeamGroup.createBeam(beamNotes);
5805
- beamsCreated = true;
5806
- }
5807
- });
5808
- }
5809
- return beamsCreated;
5810
- }
5811
6079
  getBarLineLeft() {
5812
6080
  return this.barLineLeft;
5813
6081
  }
@@ -5828,7 +6096,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5828
6096
  this.completeRests(getVoiceIds().filter((id) => this.getConsumedTicks(id) > 0));
5829
6097
  }
5830
6098
  return;
5831
- } else if (Utils11.Is.isArray(voiceId)) {
6099
+ } else if (Utils12.Is.isArray(voiceId)) {
5832
6100
  voiceId.forEach((id) => this.completeRests(id));
5833
6101
  return;
5834
6102
  } else {
@@ -5838,9 +6106,9 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5838
6106
  let remainingTicks = measureTicks - consumedTicks;
5839
6107
  let rests = [];
5840
6108
  while (remainingTicks > 0) {
5841
- for (let noteSize = NoteLengthProps4.LongestNoteSize; noteSize <= NoteLengthProps4.ShortestNoteSize; noteSize *= 2) {
5842
- let restLength = NoteLengthProps4.create(noteSize).noteLength;
5843
- for (let dotCount = NoteLengthProps4.get(restLength).maxDotCount; dotCount >= 0; dotCount--) {
6109
+ for (let noteSize = NoteLengthProps5.LongestNoteSize; noteSize <= NoteLengthProps5.ShortestNoteSize; noteSize *= 2) {
6110
+ let restLength = NoteLengthProps5.create(noteSize).noteLength;
6111
+ for (let dotCount = NoteLengthProps5.get(restLength).maxDotCount; dotCount >= 0; dotCount--) {
5844
6112
  let restProps = RhythmProps5.get(restLength, dotCount);
5845
6113
  while (restProps.ticks <= remainingTicks) {
5846
6114
  rests.push(restProps);
@@ -5875,22 +6143,30 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5875
6143
  let showKeySignature = isFirstMeasureInRow || isAfterMeasureBreak || !!this.alterKeySignature;
5876
6144
  let showTimeSignature = !!this.alterTimeSignature;
5877
6145
  let showTempo = !!this.alterTempo;
5878
- if (showClef || showMeasureNumber || showKeySignature || showTimeSignature || showTempo) {
5879
- this.signatures = this.row.getStaves().map((staff, staffId) => {
5880
- let oldSignature = this.signatures.find((s) => s.staff === staff);
5881
- let signature = oldSignature != null ? oldSignature : new ObjSignature(this, staff);
6146
+ this.signatures = [];
6147
+ this.row.getNotationLines().forEach((line, lineId) => {
6148
+ if (line instanceof ObjStaff && (showClef || showMeasureNumber || showKeySignature || showTimeSignature || showTempo)) {
6149
+ let oldSignature = this.signatures.filter((s) => s instanceof ObjStaffSignature).find((s) => s.staff === line);
6150
+ let signature = oldSignature != null ? oldSignature : new ObjStaffSignature(this, line);
5882
6151
  signature.staff.addObject(signature);
5883
6152
  signature.updateClefImage(renderer, showClef);
5884
- signature.updateMeasureNumber(showMeasureNumber && staffId === 0);
6153
+ signature.updateMeasureNumber(showMeasureNumber && lineId === 0);
5885
6154
  signature.updateKeySignature(showKeySignature);
5886
6155
  signature.updateTimeSignature(showTimeSignature);
5887
- signature.updateTempo(showTempo && staffId === 0);
5888
- return signature;
5889
- });
5890
- } else {
5891
- this.signatures = [];
5892
- }
5893
- this.signatures.forEach((signature) => signature.layout(renderer));
6156
+ signature.updateTempo(showTempo && lineId === 0);
6157
+ signature.layout(renderer);
6158
+ this.signatures.push(signature);
6159
+ } else if (line instanceof ObjTab && (showMeasureNumber || showTimeSignature || showTempo)) {
6160
+ let oldSignature = this.signatures.filter((s) => s instanceof ObjTabSignature).find((s) => s.tab === line);
6161
+ let signature = oldSignature != null ? oldSignature : new ObjTabSignature(this, line);
6162
+ signature.tab.addObject(signature);
6163
+ signature.updateMeasureNumber(showMeasureNumber && lineId === 0);
6164
+ signature.updateTimeSignature(showTimeSignature);
6165
+ signature.updateTempo(showTempo && lineId === 0);
6166
+ signature.layout(renderer);
6167
+ this.signatures.push(signature);
6168
+ }
6169
+ });
5894
6170
  this.tabStringNotes.length = 0;
5895
6171
  if (this === this.row.getFirstMeasure()) {
5896
6172
  this.row.getTabs().forEach((tab) => {
@@ -5943,7 +6219,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5943
6219
  let columnsAreaLeft = this.rect.left + this.leftSolidAreaWidth;
5944
6220
  let columnsAreaRight = this.rect.right - this.rightSolidAreaWidth;
5945
6221
  let columnsAreaWidth = columnsAreaRight - columnsAreaLeft;
5946
- let columnsWidth = Utils11.Math.sum(this.columns.map((col) => col.getRect().width));
6222
+ let columnsWidth = Utils12.Math.sum(this.columns.map((col) => col.getRect().width));
5947
6223
  let columnScale = columnsAreaWidth / columnsWidth;
5948
6224
  let columnLeft = columnsAreaLeft;
5949
6225
  this.columns.forEach((col) => {
@@ -6064,18 +6340,19 @@ var ObjMeasure2 = _ObjMeasure;
6064
6340
  // src/score/engine/layout-object.ts
6065
6341
  import { MusicError as MusicError14, MusicErrorType as MusicErrorType14 } from "@tspro/web-music-score/core";
6066
6342
  var WidenColumnList = [
6067
- 1 /* NoteLabel */,
6068
- 6 /* ChordLabel */
6343
+ 2 /* NoteLabel */,
6344
+ 7 /* ChordLabel */
6069
6345
  ];
6070
6346
  var RowAlignList = [
6071
- 2 /* Navigation */,
6072
- 3 /* Ending */,
6073
- 4 /* TempoAnnotation */,
6074
- 5 /* DynamicsAnnotation */,
6075
- 6 /* ChordLabel */,
6076
- 7 /* LyricsVerse1 */,
6077
- 8 /* LyricsVerse2 */,
6078
- 9 /* LyricsVerse3 */
6347
+ 0 /* TabRhythm */,
6348
+ 3 /* Navigation */,
6349
+ 4 /* Ending */,
6350
+ 5 /* TempoAnnotation */,
6351
+ 6 /* DynamicsAnnotation */,
6352
+ 7 /* ChordLabel */,
6353
+ 8 /* LyricsVerse1 */,
6354
+ 9 /* LyricsVerse2 */,
6355
+ 10 /* LyricsVerse3 */
6079
6356
  ];
6080
6357
  function requireParentMeasure(p) {
6081
6358
  while (p) {
@@ -6251,7 +6528,7 @@ var ObjNotationLine4 = class extends MusicObject {
6251
6528
  let rowLayoutObjs = layoutGroup.getLayoutObjects(verticalPos).filter((layoutObj) => !layoutObj.isPositionResolved());
6252
6529
  rowLayoutObjs.forEach((layoutObj) => {
6253
6530
  let { musicObj, anchor } = layoutObj;
6254
- if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine) {
6531
+ if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine || musicObj instanceof ObjTabRhythm) {
6255
6532
  musicObj.layoutFitToMeasure(renderer);
6256
6533
  } else {
6257
6534
  musicObj.offset(anchor.getRect().centerX - musicObj.getRect().centerX, 0);
@@ -6373,9 +6650,6 @@ var ObjStaff = class extends ObjNotationLine4 {
6373
6650
  containsVoiceId(voiceId) {
6374
6651
  return !this.staffConfig.voiceIds || this.staffConfig.voiceIds.includes(voiceId);
6375
6652
  }
6376
- isGrand() {
6377
- return this.staffConfig.isGrand === true;
6378
- }
6379
6653
  calcTop() {
6380
6654
  let top = this.topLineY;
6381
6655
  this.objects.forEach((o) => top = Math.min(top, o.getRect().top));
@@ -6436,7 +6710,7 @@ var ObjTab = class extends ObjNotationLine4 {
6436
6710
  __publicField(this, "tuningName");
6437
6711
  __publicField(this, "tuningStrings");
6438
6712
  __publicField(this, "mi");
6439
- if (Utils12.Is.isArray(tabConfig.tuning)) {
6713
+ if (Utils13.Is.isArray(tabConfig.tuning)) {
6440
6714
  this.tuningName = void 0;
6441
6715
  this.tuningStrings = tabConfig.tuning.map((noteName) => Note8.getNote(noteName)).reverse();
6442
6716
  } else if (typeof tabConfig.tuning === "string") {
@@ -6490,10 +6764,14 @@ var ObjTab = class extends ObjNotationLine4 {
6490
6764
  return true;
6491
6765
  }
6492
6766
  calcTop() {
6493
- return this.top;
6767
+ let { top } = this;
6768
+ this.objects.forEach((o) => top = Math.min(top, o.getRect().top));
6769
+ return top;
6494
6770
  }
6495
6771
  calcBottom() {
6496
- return this.bottom;
6772
+ let { bottom } = this;
6773
+ this.objects.forEach((o) => bottom = Math.max(bottom, o.getRect().bottom));
6774
+ return bottom;
6497
6775
  }
6498
6776
  pick(x, y) {
6499
6777
  return [this];
@@ -6557,7 +6835,7 @@ var ObjScoreRow = class extends MusicObject {
6557
6835
  for (let i = 0; i < notationLines.length - 1; i++) {
6558
6836
  let treble = notationLines[i];
6559
6837
  let bass = notationLines[i + 1];
6560
- if (treble instanceof ObjStaff && treble.isGrand() && treble.staffConfig.clef === "G" /* G */ && bass instanceof ObjStaff && bass.isGrand() && bass.staffConfig.clef === "F" /* F */) {
6838
+ if (treble instanceof ObjStaff && bass instanceof ObjStaff && treble.staffConfig.grandId !== void 0 && treble.staffConfig.grandId === bass.staffConfig.grandId) {
6561
6839
  treble.joinGrandStaff(bass);
6562
6840
  bass.joinGrandStaff(treble);
6563
6841
  }
@@ -6734,17 +7012,17 @@ var ObjScoreRow = class extends MusicObject {
6734
7012
  alignStemsToBeams() {
6735
7013
  this.measures.forEach((m) => m.alignStemsToBeams());
6736
7014
  }
6737
- layoutPositionLines(renderer) {
7015
+ layoutSetNotationLines(renderer) {
6738
7016
  let { unitSize } = renderer;
6739
7017
  for (let i = 1; i < this.notationLines.length; i++) {
6740
7018
  let prev = this.notationLines[i - 1];
6741
7019
  let cur = this.notationLines[i];
6742
- if (prev instanceof ObjStaff && prev.isGrand() && prev.staffConfig.clef === "G" /* G */ && cur instanceof ObjStaff && cur.isGrand() && cur.staffConfig.clef === "F" /* F */) {
6743
- let sep = unitSize * 6;
6744
- cur.offset(0, prev.getBottomLineY() - cur.getTopLineY() + sep);
7020
+ if (prev instanceof ObjStaff && cur instanceof ObjStaff && prev.staffConfig.grandId !== void 0 && prev.staffConfig.grandId === cur.staffConfig.grandId) {
7021
+ let dy = prev.getBottomLineY() - cur.getTopLineY() + unitSize * 6;
7022
+ cur.offset(0, dy);
6745
7023
  } else {
6746
- let sep = unitSize * 3;
6747
- cur.offset(0, prev.calcBottom() - cur.calcTop() + sep);
7024
+ let dy = prev.calcBottom() - cur.calcTop() + unitSize * 3;
7025
+ cur.offset(0, dy);
6748
7026
  }
6749
7027
  }
6750
7028
  this.measures.forEach((m) => {
@@ -6891,7 +7169,8 @@ var ObjHeader = class extends MusicObject {
6891
7169
  };
6892
7170
 
6893
7171
  // src/score/engine/obj-document.ts
6894
- import { Utils as Utils13 } from "@tspro/ts-utils-lib";
7172
+ import { Utils as Utils14 } from "@tspro/ts-utils-lib";
7173
+ import { MusicError as MusicError17, MusicErrorType as MusicErrorType17 } from "@tspro/web-music-score/core";
6895
7174
  var ObjDocument = class extends MusicObject {
6896
7175
  constructor() {
6897
7176
  super(void 0);
@@ -6912,7 +7191,7 @@ var ObjDocument = class extends MusicObject {
6912
7191
  return this.mi;
6913
7192
  }
6914
7193
  setScoreConfiguration(config) {
6915
- if (Utils13.Is.isEnumValue(config, StaffPreset)) {
7194
+ if (Utils14.Is.isEnumValue(config, StaffPreset)) {
6916
7195
  switch (config) {
6917
7196
  default:
6918
7197
  case "treble" /* Treble */:
@@ -6923,8 +7202,8 @@ var ObjDocument = class extends MusicObject {
6923
7202
  break;
6924
7203
  case "grand" /* Grand */:
6925
7204
  this.curScoreConfig = [
6926
- { type: "staff", clef: "G" /* G */, isGrand: true },
6927
- { type: "staff", clef: "F" /* F */, isGrand: true }
7205
+ { type: "staff", clef: "G" /* G */, grandId: "grand1" },
7206
+ { type: "staff", clef: "F" /* F */, grandId: "grand1" }
6928
7207
  ];
6929
7208
  break;
6930
7209
  case "guitarTreble" /* GuitarTreble */:
@@ -6940,26 +7219,57 @@ var ObjDocument = class extends MusicObject {
6940
7219
  ];
6941
7220
  break;
6942
7221
  }
6943
- } else if (Utils13.Is.isArray(config)) {
7222
+ } else if (Utils14.Is.isArray(config)) {
6944
7223
  this.curScoreConfig = config;
6945
7224
  } else {
6946
7225
  this.curScoreConfig = [config];
6947
7226
  }
6948
- for (let i = 0; i < this.curScoreConfig.length - 1; i++) {
6949
- let treble = this.curScoreConfig[i];
6950
- let bass = this.curScoreConfig[i + 1];
6951
- if (treble.type === "staff" && bass.type === "staff") {
6952
- if (treble.clef === "G" /* G */ && treble.isGrand && bass.clef === "F" /* F */ && bass.isGrand) {
6953
- treble.minNote = "C4";
6954
- bass.maxNote = "B3";
6955
- treble.isOctaveDown = bass.isOctaveDown = false;
7227
+ for (let cfgId = 0, grandId = "grand"; cfgId < this.curScoreConfig.length; ) {
7228
+ let treble = this.curScoreConfig[cfgId];
7229
+ let bass = this.curScoreConfig[cfgId + 1];
7230
+ while (this.curScoreConfig.filter((cfg) => cfg.type === "staff").findIndex((cfg) => cfg.grandId === grandId) >= 0) {
7231
+ grandId += "A";
7232
+ }
7233
+ if (treble && treble.type === "staff" && treble.isGrand) {
7234
+ if (treble.grandId !== void 0) {
7235
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: mixing isGrand and grandId!`);
7236
+ } else if (bass && bass.type === "staff" && bass.isGrand) {
7237
+ if (bass.grandId !== void 0) {
7238
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: mixing isGrand and grandId!`);
7239
+ } else {
7240
+ treble.grandId = grandId;
7241
+ bass.grandId = grandId;
7242
+ treble.isGrand = bass.isGrand = false;
7243
+ cfgId += 2;
7244
+ }
6956
7245
  } else {
6957
- treble.isGrand = bass.isGrand = false;
7246
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: invalid use of isGrand!`);
7247
+ }
7248
+ } else {
7249
+ cfgId++;
7250
+ }
7251
+ }
7252
+ for (let cfgId = 0, usedGrandIdes = []; cfgId < this.curScoreConfig.length; ) {
7253
+ let treble = this.curScoreConfig[cfgId];
7254
+ let bass = this.curScoreConfig[cfgId + 1];
7255
+ if (treble && bass && treble.type === "staff" && bass.type === "staff" && treble.grandId !== void 0 && treble.grandId === bass.grandId) {
7256
+ if (usedGrandIdes.includes(treble.grandId)) {
7257
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: grandId "${treble.grandId}" already used!`);
7258
+ } else if (treble.clef !== "G" /* G */) {
7259
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: Invalid treble clef "${treble.clef}"!`);
7260
+ } else if (bass.clef !== "F" /* F */) {
7261
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: Invalid treble clef "${treble.clef}"!`);
7262
+ } else if (treble.isOctaveDown || bass.isOctaveDown) {
7263
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: cannot use isOctaveDown option!`);
6958
7264
  }
6959
- } else if (treble.type === "staff") {
6960
- treble.isGrand = false;
6961
- } else if (bass.type === "staff") {
6962
- bass.isGrand = false;
7265
+ usedGrandIdes.push(treble.grandId);
7266
+ treble.minNote = "C4";
7267
+ bass.maxNote = "B3";
7268
+ cfgId += 2;
7269
+ } else if (treble && treble.type === "staff" && treble.grandId !== void 0) {
7270
+ throw new MusicError17(MusicErrorType17.Score, `Grand staff error: invalid use of grandId "${treble.grandId}"!`);
7271
+ } else {
7272
+ cfgId++;
6963
7273
  }
6964
7274
  }
6965
7275
  this.requestNewRow();
@@ -7102,7 +7412,7 @@ var ObjDocument = class extends MusicObject {
7102
7412
  );
7103
7413
  this.rows.forEach((row) => row.layoutWidth(renderer, rowWidth));
7104
7414
  this.rows.forEach((row) => row.layoutLayoutGroups(renderer));
7105
- this.rows.forEach((row) => row.layoutPositionLines(renderer));
7415
+ this.rows.forEach((row) => row.layoutSetNotationLines(renderer));
7106
7416
  this.rows.forEach((row) => row.layoutPadding(renderer));
7107
7417
  this.rect = new DivRect();
7108
7418
  if (this.header) {
@@ -7166,11 +7476,11 @@ var ObjDocument = class extends MusicObject {
7166
7476
  };
7167
7477
 
7168
7478
  // src/score/pub/document-builder.ts
7169
- import { BeamGrouping, KeySignature as KeySignature3, Note as Note10, NoteLength as NoteLength8, RhythmProps as RhythmProps6, Scale as Scale2, ScaleType, SymbolSet as SymbolSet2, TimeSignature as TimeSignature2, TimeSignatures, TuningNameList, validateNoteLength as validateNoteLength3, validateTupletRatio } from "@tspro/web-music-score/theory";
7170
- import { MusicError as MusicError17, MusicErrorType as MusicErrorType17 } from "@tspro/web-music-score/core";
7479
+ import { BeamGrouping, KeySignature as KeySignature3, Note as Note10, NoteLength as NoteLength9, RhythmProps as RhythmProps6, Scale as Scale2, ScaleType, SymbolSet as SymbolSet2, TimeSignature as TimeSignature2, TimeSignatures, TuningNameList, validateNoteLength as validateNoteLength4, validateTupletRatio } from "@tspro/web-music-score/theory";
7480
+ import { MusicError as MusicError18, MusicErrorType as MusicErrorType18 } from "@tspro/web-music-score/core";
7171
7481
  function assertArg(condition, argName, argValue) {
7172
7482
  if (!condition) {
7173
- throw new MusicError17(MusicErrorType17.Score, `Invalid arg: ${argName} = ${argValue}`);
7483
+ throw new MusicError18(MusicErrorType18.Score, `Invalid arg: ${argName} = ${argValue}`);
7174
7484
  }
7175
7485
  }
7176
7486
  function isNote(note) {
@@ -7182,64 +7492,70 @@ function isNote(note) {
7182
7492
  }
7183
7493
  }
7184
7494
  function isVoiceId(value) {
7185
- return Utils14.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
7495
+ return Utils15.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
7186
7496
  }
7187
7497
  function isStringNumber(value) {
7188
- return Utils14.Is.isNumber(value) && getStringNumbers().indexOf(value) >= 0;
7498
+ return Utils15.Is.isNumber(value) && getStringNumbers().indexOf(value) >= 0;
7189
7499
  }
7190
7500
  function isVerseNumber(value) {
7191
- return Utils14.Is.isNumber(value) && getVerseNumbers().indexOf(value) >= 0;
7501
+ return Utils15.Is.isNumber(value) && getVerseNumbers().indexOf(value) >= 0;
7502
+ }
7503
+ function assertBaseConfig(baseConfig) {
7504
+ assertArg(Utils15.Is.isObject(baseConfig), "baseConfig", baseConfig);
7505
+ assertArg(Utils15.Is.isStringOrUndefined(baseConfig.name), "baseConfig.name", baseConfig.name);
7506
+ assertArg(Utils15.Is.isUndefined(baseConfig.voiceIds) || Utils15.Is.isArray(baseConfig.voiceIds) && baseConfig.voiceIds.every((voiceId) => Utils15.Is.isNumber(voiceId)), "baseConfig.voiceIds", baseConfig.voiceIds);
7192
7507
  }
7193
7508
  function assertStaffConfig(staffConfig) {
7194
- assertArg(Utils14.Is.isObject(staffConfig), "staffConfig", staffConfig);
7509
+ assertBaseConfig(staffConfig);
7510
+ assertArg(Utils15.Is.isObject(staffConfig), "staffConfig", staffConfig);
7195
7511
  assertArg(staffConfig.type === "staff", "staffConfig.type", staffConfig.type);
7196
- assertArg(Utils14.Is.isEnumValue(staffConfig.clef, Clef), "staffConfig.clef", staffConfig.clef);
7197
- assertArg(Utils14.Is.isBooleanOrUndefined(staffConfig.isOctaveDown), "staffConfig.isOctaveDown", staffConfig.isOctaveDown);
7198
- assertArg(Utils14.Is.isUndefined(staffConfig.minNote) || isNote(staffConfig.minNote), "staffConfig.minNote", staffConfig.minNote);
7199
- assertArg(Utils14.Is.isUndefined(staffConfig.maxNote) || isNote(staffConfig.maxNote), "staffConfig.maxNote", staffConfig.maxNote);
7200
- assertArg(Utils14.Is.isUndefined(staffConfig.voiceIds) || Utils14.Is.isArray(staffConfig.voiceIds) && staffConfig.voiceIds.every((voiceId) => Utils14.Is.isNumber(voiceId)), "staffConfig.voiceIds", staffConfig.voiceIds);
7201
- assertArg(Utils14.Is.isBooleanOrUndefined(staffConfig.isGrand), "staffConfig.isGrand", staffConfig.isGrand);
7512
+ assertArg(Utils15.Is.isEnumValue(staffConfig.clef, Clef), "staffConfig.clef", staffConfig.clef);
7513
+ assertArg(Utils15.Is.isBooleanOrUndefined(staffConfig.isOctaveDown), "staffConfig.isOctaveDown", staffConfig.isOctaveDown);
7514
+ assertArg(Utils15.Is.isUndefined(staffConfig.minNote) || isNote(staffConfig.minNote), "staffConfig.minNote", staffConfig.minNote);
7515
+ assertArg(Utils15.Is.isUndefined(staffConfig.maxNote) || isNote(staffConfig.maxNote), "staffConfig.maxNote", staffConfig.maxNote);
7516
+ assertArg(Utils15.Is.isStringOrUndefined(staffConfig.grandId), "staffConfig.grandId", staffConfig.grandId);
7517
+ assertArg(Utils15.Is.isBooleanOrUndefined(staffConfig.isGrand), "staffConfig.isGrand", staffConfig.isGrand);
7202
7518
  }
7203
7519
  function assertTabConfig(tabConfig) {
7204
- assertArg(Utils14.Is.isObject(tabConfig), "tabConfig", tabConfig);
7520
+ assertBaseConfig(tabConfig);
7521
+ assertArg(Utils15.Is.isObject(tabConfig), "tabConfig", tabConfig);
7205
7522
  assertArg(tabConfig.type === "tab", "tabConfig.type", tabConfig.type);
7206
- if (typeof tabConfig.tuning === "string") {
7523
+ if (Utils15.Is.isString(tabConfig.tuning)) {
7207
7524
  assertArg(TuningNameList.includes(tabConfig.tuning), "tabConfig.tuning", tabConfig.tuning);
7208
- } else if (Utils14.Is.isArray(tabConfig.tuning)) {
7525
+ } else if (Utils15.Is.isArray(tabConfig.tuning)) {
7209
7526
  assertArg(tabConfig.tuning.length === getStringNumbers().length && tabConfig.tuning.every((s) => isNote(s)), "tabConfig.tuning", tabConfig.tuning);
7210
7527
  }
7211
- assertArg(Utils14.Is.isUndefined(tabConfig.voiceIds) || Utils14.Is.isArray(tabConfig.voiceIds) && tabConfig.voiceIds.every((voiceId) => Utils14.Is.isNumber(voiceId)), "tabConfig.voiceIds", tabConfig.voiceIds);
7212
7528
  }
7213
7529
  function assertNoteOptions(noteOptions) {
7214
- assertArg(Utils14.Is.isObject(noteOptions), "noteOptions", noteOptions);
7215
- assertArg(Utils14.Is.isBooleanOrUndefined(noteOptions.dotted) || Utils14.Is.isIntegerGte(noteOptions.dotted, 0), "noteOptions.dotted", noteOptions.dotted);
7216
- assertArg(Utils14.Is.isEnumValueOrUndefined(noteOptions.stem, Stem), "noteOptions.stem", noteOptions.stem);
7217
- assertArg(Utils14.Is.isStringOrUndefined(noteOptions.color), "noteOptions.color", noteOptions.color);
7218
- assertArg(Utils14.Is.isBooleanOrUndefined(noteOptions.arpeggio) || Utils14.Is.isEnumValue(noteOptions.arpeggio, Arpeggio), "noteOptions.arpeggio", noteOptions.arpeggio);
7219
- assertArg(Utils14.Is.isBooleanOrUndefined(noteOptions.staccato), "noteOptions.staccato", noteOptions.staccato);
7220
- assertArg(Utils14.Is.isBooleanOrUndefined(noteOptions.diamond), "noteOptions.diamond", noteOptions.diamond);
7221
- assertArg(Utils14.Is.isBooleanOrUndefined(noteOptions.triplet), "noteOptions.triplet", noteOptions.triplet);
7222
- assertArg(Utils14.Is.isUndefined(noteOptions.string) || isStringNumber(noteOptions.string) || Utils14.Is.isNonEmptyArray(noteOptions.string) && noteOptions.string.every((string) => isStringNumber(string)), "noteOptions.string", noteOptions.string);
7223
- assertArg(Utils14.Is.isUndefined(noteOptions.tieSpan), 'NoteOptions.tieSpan was removed. Use addConnective("tie", tieSpan)', "");
7224
- assertArg(Utils14.Is.isUndefined(noteOptions.slurSpan), 'NoteOptions.slurSpan was removed. Use addConnective("slur", slurSpan)', "");
7530
+ assertArg(Utils15.Is.isObject(noteOptions), "noteOptions", noteOptions);
7531
+ assertArg(Utils15.Is.isBooleanOrUndefined(noteOptions.dotted) || Utils15.Is.isIntegerGte(noteOptions.dotted, 0), "noteOptions.dotted", noteOptions.dotted);
7532
+ assertArg(Utils15.Is.isEnumValueOrUndefined(noteOptions.stem, Stem), "noteOptions.stem", noteOptions.stem);
7533
+ assertArg(Utils15.Is.isStringOrUndefined(noteOptions.color), "noteOptions.color", noteOptions.color);
7534
+ assertArg(Utils15.Is.isBooleanOrUndefined(noteOptions.arpeggio) || Utils15.Is.isEnumValue(noteOptions.arpeggio, Arpeggio), "noteOptions.arpeggio", noteOptions.arpeggio);
7535
+ assertArg(Utils15.Is.isBooleanOrUndefined(noteOptions.staccato), "noteOptions.staccato", noteOptions.staccato);
7536
+ assertArg(Utils15.Is.isBooleanOrUndefined(noteOptions.diamond), "noteOptions.diamond", noteOptions.diamond);
7537
+ assertArg(Utils15.Is.isBooleanOrUndefined(noteOptions.triplet), "noteOptions.triplet", noteOptions.triplet);
7538
+ assertArg(Utils15.Is.isUndefined(noteOptions.string) || isStringNumber(noteOptions.string) || Utils15.Is.isNonEmptyArray(noteOptions.string) && noteOptions.string.every((string) => isStringNumber(string)), "noteOptions.string", noteOptions.string);
7539
+ assertArg(Utils15.Is.isUndefined(noteOptions.tieSpan), 'NoteOptions.tieSpan was removed. Use addConnective("tie", tieSpan)', "");
7540
+ assertArg(Utils15.Is.isUndefined(noteOptions.slurSpan), 'NoteOptions.slurSpan was removed. Use addConnective("slur", slurSpan)', "");
7225
7541
  }
7226
7542
  function assertRestOptions(restOptions) {
7227
- assertArg(Utils14.Is.isObject(restOptions), "restOptions", restOptions);
7228
- assertArg(Utils14.Is.isBooleanOrUndefined(restOptions.dotted) || Utils14.Is.isIntegerGte(restOptions.dotted, 0), "restOptions.dotted", restOptions.dotted);
7229
- assertArg(Utils14.Is.isStringOrUndefined(restOptions.staffPos) || Utils14.Is.isInteger(restOptions.staffPos) || restOptions.staffPos instanceof Note10, "restOptions.staffPos", restOptions.staffPos);
7230
- assertArg(Utils14.Is.isStringOrUndefined(restOptions.color), "restOptions.color", restOptions.color);
7231
- assertArg(Utils14.Is.isBooleanOrUndefined(restOptions.hide), "restOptions.hide", restOptions.hide);
7232
- assertArg(Utils14.Is.isBooleanOrUndefined(restOptions.triplet), "restOptions.triplet", restOptions.triplet);
7543
+ assertArg(Utils15.Is.isObject(restOptions), "restOptions", restOptions);
7544
+ assertArg(Utils15.Is.isBooleanOrUndefined(restOptions.dotted) || Utils15.Is.isIntegerGte(restOptions.dotted, 0), "restOptions.dotted", restOptions.dotted);
7545
+ assertArg(Utils15.Is.isStringOrUndefined(restOptions.staffPos) || Utils15.Is.isInteger(restOptions.staffPos) || restOptions.staffPos instanceof Note10, "restOptions.staffPos", restOptions.staffPos);
7546
+ assertArg(Utils15.Is.isStringOrUndefined(restOptions.color), "restOptions.color", restOptions.color);
7547
+ assertArg(Utils15.Is.isBooleanOrUndefined(restOptions.hide), "restOptions.hide", restOptions.hide);
7548
+ assertArg(Utils15.Is.isBooleanOrUndefined(restOptions.triplet), "restOptions.triplet", restOptions.triplet);
7233
7549
  }
7234
7550
  function assertLyricsOptions(lyricsOptions) {
7235
- assertArg(Utils14.Is.isObject(lyricsOptions), "lyricsOptions", lyricsOptions);
7236
- assertArg(Utils14.Is.isEnumValueOrUndefined(lyricsOptions.align, LyricsAlign), "lyricsOptions.align", lyricsOptions.align);
7237
- assertArg(Utils14.Is.isEnumValueOrUndefined(lyricsOptions.hyphen, LyricsHyphen), "lyricsOptions.hyphen", lyricsOptions.hyphen);
7551
+ assertArg(Utils15.Is.isObject(lyricsOptions), "lyricsOptions", lyricsOptions);
7552
+ assertArg(Utils15.Is.isEnumValueOrUndefined(lyricsOptions.align, LyricsAlign), "lyricsOptions.align", lyricsOptions.align);
7553
+ assertArg(Utils15.Is.isEnumValueOrUndefined(lyricsOptions.hyphen, LyricsHyphen), "lyricsOptions.hyphen", lyricsOptions.hyphen);
7238
7554
  }
7239
7555
  function assertStaffTabOrGRoups(staffTabOrGroups) {
7240
7556
  assertArg(
7241
- Utils14.Is.isStringOrUndefined(staffTabOrGroups) || Utils14.Is.isIntegerGte(staffTabOrGroups, 0) || Utils14.Is.isNonEmptyArray(staffTabOrGroups) && staffTabOrGroups.every(
7242
- (staffTabOrGroup) => Utils14.Is.isString(staffTabOrGroup) || Utils14.Is.isIntegerGte(staffTabOrGroup, 0)
7557
+ Utils15.Is.isStringOrUndefined(staffTabOrGroups) || Utils15.Is.isIntegerGte(staffTabOrGroups, 0) || Utils15.Is.isNonEmptyArray(staffTabOrGroups) && staffTabOrGroups.every(
7558
+ (staffTabOrGroup) => Utils15.Is.isString(staffTabOrGroup) || Utils15.Is.isIntegerGte(staffTabOrGroup, 0)
7243
7559
  ),
7244
7560
  "staffTabOrGroup",
7245
7561
  staffTabOrGroups
@@ -7247,7 +7563,7 @@ function assertStaffTabOrGRoups(staffTabOrGroups) {
7247
7563
  }
7248
7564
  function isNoteLength(noteLen) {
7249
7565
  try {
7250
- validateNoteLength3(noteLen);
7566
+ validateNoteLength4(noteLen);
7251
7567
  return true;
7252
7568
  } catch (e) {
7253
7569
  return false;
@@ -7271,19 +7587,19 @@ var DocumentBuilder = class {
7271
7587
  this.doc = new ObjDocument();
7272
7588
  }
7273
7589
  setScoreConfiguration(config) {
7274
- if (Utils14.Is.isEnumValue(config, StaffPreset)) {
7590
+ if (Utils15.Is.isEnumValue(config, StaffPreset)) {
7275
7591
  this.doc.setScoreConfiguration(config);
7276
- } else if (Utils14.Is.isObject(config) && config.type === "staff") {
7592
+ } else if (Utils15.Is.isObject(config) && config.type === "staff") {
7277
7593
  assertStaffConfig(config);
7278
7594
  this.doc.setScoreConfiguration(config);
7279
- } else if (Utils14.Is.isObject(config) && config.type === "tab") {
7595
+ } else if (Utils15.Is.isObject(config) && config.type === "tab") {
7280
7596
  assertTabConfig(config);
7281
7597
  this.doc.setScoreConfiguration(config);
7282
- } else if (Utils14.Is.isNonEmptyArray(config)) {
7598
+ } else if (Utils15.Is.isNonEmptyArray(config)) {
7283
7599
  config.forEach((c) => {
7284
- if (Utils14.Is.isObject(c) && c.type === "staff") {
7600
+ if (Utils15.Is.isObject(c) && c.type === "staff") {
7285
7601
  assertStaffConfig(c);
7286
- } else if (Utils14.Is.isObject(c) && c.type === "tab") {
7602
+ } else if (Utils15.Is.isObject(c) && c.type === "tab") {
7287
7603
  assertTabConfig(c);
7288
7604
  } else {
7289
7605
  assertArg(false, "config", config);
@@ -7314,9 +7630,9 @@ var DocumentBuilder = class {
7314
7630
  * @returns - This document builder instance.
7315
7631
  */
7316
7632
  setHeader(title, composer, arranger) {
7317
- assertArg(Utils14.Is.isStringOrUndefined(title), "title", title);
7318
- assertArg(Utils14.Is.isStringOrUndefined(composer), "composer", composer);
7319
- assertArg(Utils14.Is.isStringOrUndefined(arranger), "arranger", arranger);
7633
+ assertArg(Utils15.Is.isStringOrUndefined(title), "title", title);
7634
+ assertArg(Utils15.Is.isStringOrUndefined(composer), "composer", composer);
7635
+ assertArg(Utils15.Is.isStringOrUndefined(arranger), "arranger", arranger);
7320
7636
  this.doc.setHeader(title, composer, arranger);
7321
7637
  return this;
7322
7638
  }
@@ -7326,7 +7642,7 @@ var DocumentBuilder = class {
7326
7642
  * @returns - This document builder instance.
7327
7643
  */
7328
7644
  setMeasuresPerRow(measuresPerRow) {
7329
- assertArg(Utils14.Is.isIntegerGte(measuresPerRow, 1) || Utils14.Is.isPosInfinity(measuresPerRow), "measuresPerRow", measuresPerRow);
7645
+ assertArg(Utils15.Is.isIntegerGte(measuresPerRow, 1) || Utils15.Is.isPosInfinity(measuresPerRow), "measuresPerRow", measuresPerRow);
7330
7646
  this.doc.setMeasuresPerRow(measuresPerRow);
7331
7647
  return this;
7332
7648
  }
@@ -7339,16 +7655,16 @@ var DocumentBuilder = class {
7339
7655
  return this;
7340
7656
  }
7341
7657
  setKeySignature(...args) {
7342
- assertArg(args[0] instanceof Scale2 || args[0] instanceof KeySignature3 || Utils14.Is.isNonEmptyString(args[0]) && (args.length === 1 || Utils14.Is.isEnumValue(args[1], ScaleType)), "keySignature", args);
7658
+ assertArg(args[0] instanceof Scale2 || args[0] instanceof KeySignature3 || Utils15.Is.isNonEmptyString(args[0]) && (args.length === 1 || Utils15.Is.isEnumValue(args[1], ScaleType)), "keySignature", args);
7343
7659
  this.getMeasure().setKeySignature(...args);
7344
7660
  return this;
7345
7661
  }
7346
7662
  setTimeSignature(...args) {
7347
7663
  if (args[0] instanceof TimeSignature2) {
7348
7664
  this.getMeasure().setTimeSignature(args[0]);
7349
- } else if (Utils14.Is.isEnumValue(args[0], TimeSignatures) && Utils14.Is.isEnumValueOrUndefined(args[1], BeamGrouping)) {
7665
+ } else if (Utils15.Is.isEnumValue(args[0], TimeSignatures) && Utils15.Is.isEnumValueOrUndefined(args[1], BeamGrouping)) {
7350
7666
  this.getMeasure().setTimeSignature(new TimeSignature2(args[0], args[1]));
7351
- } else if (Utils14.Is.isIntegerGte(args[0], 1) && Utils14.Is.isIntegerGte(args[1], 1) && Utils14.Is.isEnumValueOrUndefined(args[2], BeamGrouping)) {
7667
+ } else if (Utils15.Is.isIntegerGte(args[0], 1) && Utils15.Is.isIntegerGte(args[1], 1) && Utils15.Is.isEnumValueOrUndefined(args[2], BeamGrouping)) {
7352
7668
  this.getMeasure().setTimeSignature(new TimeSignature2(args[0], args[1], args[2]));
7353
7669
  } else {
7354
7670
  assertArg(false, "timeSignature args", args);
@@ -7356,12 +7672,12 @@ var DocumentBuilder = class {
7356
7672
  return this;
7357
7673
  }
7358
7674
  setTempo(beatsPerMinute, beatLength, dotted) {
7359
- assertArg(Utils14.Is.isIntegerGte(beatsPerMinute, 1), "beatsPerMinute", beatsPerMinute);
7675
+ assertArg(Utils15.Is.isIntegerGte(beatsPerMinute, 1), "beatsPerMinute", beatsPerMinute);
7360
7676
  if (beatLength === void 0) {
7361
- assertArg(Utils14.Is.isUndefined(dotted), "dotted", dotted);
7677
+ assertArg(Utils15.Is.isUndefined(dotted), "dotted", dotted);
7362
7678
  } else {
7363
- assertArg(Utils14.Is.isEnumValue(beatLength, NoteLength8) || isNoteLength(beatLength), "beatLength", beatLength);
7364
- assertArg(Utils14.Is.isBooleanOrUndefined(dotted) || Utils14.Is.isIntegerGte(dotted, 0), "dotted", dotted);
7679
+ assertArg(Utils15.Is.isEnumValue(beatLength, NoteLength9) || isNoteLength(beatLength), "beatLength", beatLength);
7680
+ assertArg(Utils15.Is.isBooleanOrUndefined(dotted) || Utils15.Is.isIntegerGte(dotted, 0), "dotted", dotted);
7365
7681
  }
7366
7682
  this.getMeasure().setTempo(beatsPerMinute, beatLength, dotted);
7367
7683
  return this;
@@ -7377,15 +7693,19 @@ var DocumentBuilder = class {
7377
7693
  addNote(voiceId, note, noteLength, noteOptions) {
7378
7694
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7379
7695
  assertArg(
7380
- note instanceof Note10 || Utils14.Is.isNonEmptyString(note) || Utils14.Is.isArray(note) && note.every((note2) => note2 instanceof Note10 || Utils14.Is.isNonEmptyString(note2)),
7696
+ note instanceof Note10 || Utils15.Is.isNonEmptyString(note) || Utils15.Is.isArray(note) && note.every((note2) => note2 instanceof Note10 || Utils15.Is.isNonEmptyString(note2)),
7381
7697
  "note",
7382
7698
  note
7383
7699
  );
7384
- assertArg(Utils14.Is.isEnumValue(noteLength, NoteLength8) || isNoteLength(noteLength), "noteLength", noteLength);
7700
+ assertArg(Utils15.Is.isEnumValue(noteLength, NoteLength9) || isNoteLength(noteLength), "noteLength", noteLength);
7385
7701
  noteOptions != null ? noteOptions : noteOptions = {};
7386
7702
  assertNoteOptions(noteOptions);
7387
- if (Utils14.Is.isArray(note)) {
7388
- note.forEach((note2) => this.getMeasure().addNoteGroup(voiceId, [note2], noteLength, noteOptions));
7703
+ if (Utils15.Is.isArray(note)) {
7704
+ let string = noteOptions.string;
7705
+ note.forEach((note2, noteId) => {
7706
+ noteOptions.string = Utils15.Is.isArray(string) ? string[noteId] : string;
7707
+ this.getMeasure().addNoteGroup(voiceId, [note2], noteLength, noteOptions);
7708
+ });
7389
7709
  } else {
7390
7710
  this.getMeasure().addNoteGroup(voiceId, [note], noteLength, noteOptions);
7391
7711
  }
@@ -7401,8 +7721,8 @@ var DocumentBuilder = class {
7401
7721
  */
7402
7722
  addChord(voiceId, notes, noteLength, noteOptions) {
7403
7723
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7404
- assertArg(Utils14.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof Note10 || Utils14.Is.isNonEmptyString(note)), "notes", notes);
7405
- assertArg(Utils14.Is.isEnumValue(noteLength, NoteLength8) || isNoteLength(noteLength), "noteLength", noteLength);
7724
+ assertArg(Utils15.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof Note10 || Utils15.Is.isNonEmptyString(note)), "notes", notes);
7725
+ assertArg(Utils15.Is.isEnumValue(noteLength, NoteLength9) || isNoteLength(noteLength), "noteLength", noteLength);
7406
7726
  noteOptions != null ? noteOptions : noteOptions = {};
7407
7727
  assertNoteOptions(noteOptions);
7408
7728
  this.getMeasure().addNoteGroup(voiceId, notes, noteLength, noteOptions);
@@ -7417,7 +7737,7 @@ var DocumentBuilder = class {
7417
7737
  */
7418
7738
  addRest(voiceId, restLength, restOptions) {
7419
7739
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7420
- assertArg(Utils14.Is.isEnumValue(restLength, NoteLength8) || isNoteLength(restLength), "restLength", restLength);
7740
+ assertArg(Utils15.Is.isEnumValue(restLength, NoteLength9) || isNoteLength(restLength), "restLength", restLength);
7421
7741
  restOptions != null ? restOptions : restOptions = {};
7422
7742
  assertRestOptions(restOptions);
7423
7743
  this.getMeasure().addRest(voiceId, restLength, restOptions);
@@ -7425,13 +7745,13 @@ var DocumentBuilder = class {
7425
7745
  }
7426
7746
  /**
7427
7747
  * Usage:
7428
- * <pre>
7748
+ * ```ts
7429
7749
  * addTuplet(0, Theory.Tuplet.Triplet, notes => {
7430
7750
  * notes.addNote("G3", Theory.NoteLength.Eighth);
7431
7751
  * notes.addNote("B3", Theory.NoteLength.Eighth);
7432
7752
  * notes.addNote("D4", Theory.NoteLength.Eighth);
7433
7753
  * });
7434
- * </pre>
7754
+ * ```
7435
7755
  *
7436
7756
  * @param voiceId - Voice id to add tuplet to.
7437
7757
  * @param tupletRatio - You can also use Theory.Tuplet presets (e.g. Theory.Tuplet.Triplet).
@@ -7440,22 +7760,24 @@ var DocumentBuilder = class {
7440
7760
  */
7441
7761
  addTuplet(voiceId, tupletRatio, tupletBuilder) {
7442
7762
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7443
- assertArg(Utils14.Is.isFunction(tupletBuilder), "tupletBuilder", tupletBuilder);
7444
- assertArg(isTupletRatio(tupletRatio) && Utils14.Is.isBooleanOrUndefined(tupletRatio.showRatio), "tupletRatio", tupletRatio);
7763
+ assertArg(Utils15.Is.isFunction(tupletBuilder), "tupletBuilder", tupletBuilder);
7764
+ assertArg(isTupletRatio(tupletRatio) && Utils15.Is.isBooleanOrUndefined(tupletRatio.showRatio), "tupletRatio", tupletRatio);
7445
7765
  let tupletSymbols = [];
7446
7766
  const helper = {
7447
7767
  addNote: (note, noteLength, noteOptions) => {
7448
7768
  assertArg(
7449
- note instanceof Note10 || Utils14.Is.isNonEmptyString(note) || Utils14.Is.isArray(note) && note.every((note2) => note2 instanceof Note10 || Utils14.Is.isNonEmptyString(note2)),
7769
+ note instanceof Note10 || Utils15.Is.isNonEmptyString(note) || Utils15.Is.isArray(note) && note.every((note2) => note2 instanceof Note10 || Utils15.Is.isNonEmptyString(note2)),
7450
7770
  "note",
7451
7771
  note
7452
7772
  );
7453
- assertArg(Utils14.Is.isEnumValue(noteLength, NoteLength8) || isNoteLength(noteLength), "noteLength", noteLength);
7773
+ assertArg(Utils15.Is.isEnumValue(noteLength, NoteLength9) || isNoteLength(noteLength), "noteLength", noteLength);
7454
7774
  noteOptions != null ? noteOptions : noteOptions = {};
7455
7775
  delete noteOptions.triplet;
7456
7776
  assertNoteOptions(noteOptions);
7457
- if (Utils14.Is.isArray(note)) {
7458
- note.forEach((note2) => {
7777
+ if (Utils15.Is.isArray(note)) {
7778
+ let string = noteOptions.string;
7779
+ note.forEach((note2, noteId) => {
7780
+ noteOptions.string = Utils15.Is.isArray(string) ? string[noteId] : string;
7459
7781
  let s = this.getMeasure().addNoteGroup(voiceId, [note2], noteLength, noteOptions, tupletRatio);
7460
7782
  tupletSymbols.push(s);
7461
7783
  });
@@ -7466,8 +7788,8 @@ var DocumentBuilder = class {
7466
7788
  return helper;
7467
7789
  },
7468
7790
  addChord: (notes, noteLength, noteOptions) => {
7469
- assertArg(Utils14.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof Note10 || Utils14.Is.isNonEmptyString(note)), "notes", notes);
7470
- assertArg(Utils14.Is.isEnumValue(noteLength, NoteLength8) || isNoteLength(noteLength), "noteLength", noteLength);
7791
+ assertArg(Utils15.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof Note10 || Utils15.Is.isNonEmptyString(note)), "notes", notes);
7792
+ assertArg(Utils15.Is.isEnumValue(noteLength, NoteLength9) || isNoteLength(noteLength), "noteLength", noteLength);
7471
7793
  noteOptions != null ? noteOptions : noteOptions = {};
7472
7794
  delete noteOptions.triplet;
7473
7795
  assertNoteOptions(noteOptions);
@@ -7476,7 +7798,7 @@ var DocumentBuilder = class {
7476
7798
  return helper;
7477
7799
  },
7478
7800
  addRest: (restLength, restOptions) => {
7479
- assertArg(Utils14.Is.isEnumValue(restLength, NoteLength8) || isNoteLength(restLength), "restLength", restLength);
7801
+ assertArg(Utils15.Is.isEnumValue(restLength, NoteLength9) || isNoteLength(restLength), "restLength", restLength);
7480
7802
  restOptions != null ? restOptions : restOptions = {};
7481
7803
  delete restOptions.triplet;
7482
7804
  assertRestOptions(restOptions);
@@ -7493,8 +7815,8 @@ var DocumentBuilder = class {
7493
7815
  var _a;
7494
7816
  assertStaffTabOrGRoups(staffTabOrGroups);
7495
7817
  assertArg(isVerseNumber(verse), "verse", verse);
7496
- assertArg(Utils14.Is.isEnumValue(lyricsLength, NoteLength8), "lyricsLength", lyricsLength);
7497
- assertArg(Utils14.Is.isString(lyricsText) || Utils14.Is.isArray(lyricsText) && lyricsText.every((text) => Utils14.Is.isString(text)), "lyricsText", lyricsText);
7818
+ assertArg(Utils15.Is.isEnumValue(lyricsLength, NoteLength9), "lyricsLength", lyricsLength);
7819
+ assertArg(Utils15.Is.isString(lyricsText) || Utils15.Is.isArray(lyricsText) && lyricsText.every((text) => Utils15.Is.isString(text)), "lyricsText", lyricsText);
7498
7820
  lyricsOptions != null ? lyricsOptions : lyricsOptions = {};
7499
7821
  assertLyricsOptions(lyricsOptions);
7500
7822
  if (lyricsOptions.align !== void 0) {
@@ -7502,7 +7824,7 @@ var DocumentBuilder = class {
7502
7824
  } else {
7503
7825
  (_a = lyricsOptions.align) != null ? _a : lyricsOptions.align = this.currentLyricsAlign;
7504
7826
  }
7505
- if (Utils14.Is.isArray(lyricsText)) {
7827
+ if (Utils15.Is.isArray(lyricsText)) {
7506
7828
  lyricsText.forEach((text) => this.getMeasure().addLyrics(staffTabOrGroups, verse, lyricsLength, text, lyricsOptions));
7507
7829
  } else {
7508
7830
  this.getMeasure().addLyrics(staffTabOrGroups, verse, lyricsLength, lyricsText, lyricsOptions);
@@ -7534,7 +7856,7 @@ var DocumentBuilder = class {
7534
7856
  }
7535
7857
  addFermataInternal(staffTabOrGroups, fermata) {
7536
7858
  assertStaffTabOrGRoups(staffTabOrGroups);
7537
- assertArg(Utils14.Is.isEnumValue(fermata, Fermata), "fermata", fermata);
7859
+ assertArg(Utils15.Is.isEnumValue(fermata, Fermata), "fermata", fermata);
7538
7860
  this.getMeasure().addFermata(staffTabOrGroups, fermata);
7539
7861
  return this;
7540
7862
  }
@@ -7557,11 +7879,11 @@ var DocumentBuilder = class {
7557
7879
  }
7558
7880
  addNavigationInternal(staffTabOrGroups, navigation, ...args) {
7559
7881
  assertStaffTabOrGRoups(staffTabOrGroups);
7560
- assertArg(Utils14.Is.isEnumValue(navigation, Navigation), "navigation", navigation);
7882
+ assertArg(Utils15.Is.isEnumValue(navigation, Navigation), "navigation", navigation);
7561
7883
  if (navigation === "endRepeat" /* EndRepeat */ && args.length > 0) {
7562
- assertArg(Utils14.Is.isIntegerGte(args[0], 1), "playCount", args[0]);
7884
+ assertArg(Utils15.Is.isIntegerGte(args[0], 1), "playCount", args[0]);
7563
7885
  } else if (navigation === "ending" /* Ending */ && args.length > 0) {
7564
- assertArg(args.every((passage) => Utils14.Is.isIntegerGte(passage, 1)), "passages", args);
7886
+ assertArg(args.every((passage) => Utils15.Is.isIntegerGte(passage, 1)), "passages", args);
7565
7887
  }
7566
7888
  this.getMeasure().addNavigation(staffTabOrGroups, navigation, ...args);
7567
7889
  return this;
@@ -7575,11 +7897,11 @@ var DocumentBuilder = class {
7575
7897
  addAnnotationInternal(staffTabOrGroups, annotation, text) {
7576
7898
  annotation != null ? annotation : annotation = getAnnotation(text);
7577
7899
  if (annotation === void 0) {
7578
- throw new MusicError17(MusicErrorType17.Score, `Annotation text "${text}" is not known annotation.`);
7900
+ throw new MusicError18(MusicErrorType18.Score, `Annotation text "${text}" is not known annotation.`);
7579
7901
  }
7580
7902
  assertStaffTabOrGRoups(staffTabOrGroups);
7581
- assertArg(Utils14.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
7582
- assertArg(Utils14.Is.isNonEmptyString(text), "text", text);
7903
+ assertArg(Utils15.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
7904
+ assertArg(Utils15.Is.isNonEmptyString(text), "text", text);
7583
7905
  this.getMeasure().addAnnotation(staffTabOrGroups, annotation, text);
7584
7906
  return this;
7585
7907
  }
@@ -7599,8 +7921,8 @@ var DocumentBuilder = class {
7599
7921
  }
7600
7922
  addLabelInternal(staffTabOrGroups, label, text) {
7601
7923
  assertStaffTabOrGRoups(staffTabOrGroups);
7602
- assertArg(Utils14.Is.isEnumValue(label, Label), "label", label);
7603
- assertArg(Utils14.Is.isNonEmptyString(text), "text", text);
7924
+ assertArg(Utils15.Is.isEnumValue(label, Label), "label", label);
7925
+ assertArg(Utils15.Is.isNonEmptyString(text), "text", text);
7604
7926
  this.getMeasure().addLabel(staffTabOrGroups, label, text);
7605
7927
  return this;
7606
7928
  }
@@ -7624,21 +7946,21 @@ var DocumentBuilder = class {
7624
7946
  return this.addLabelInternal(staffTabOrGroups, label, text);
7625
7947
  }
7626
7948
  addConnective(connective, ...args) {
7627
- assertArg(Utils14.Is.isEnumValue(connective, Connective), "connective", connective);
7949
+ assertArg(Utils15.Is.isEnumValue(connective, Connective), "connective", connective);
7628
7950
  if (connective === "tie" /* Tie */) {
7629
- assertArg(Utils14.Is.isIntegerOrUndefined(args[0]) || Utils14.Is.isEnumValue(args[0], TieType), "tieSpan", args[0]);
7630
- assertArg(Utils14.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
7951
+ assertArg(Utils15.Is.isIntegerOrUndefined(args[0]) || Utils15.Is.isEnumValue(args[0], TieType), "tieSpan", args[0]);
7952
+ assertArg(Utils15.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
7631
7953
  let tieSpan = args[0];
7632
7954
  let noteAnchor = args[1];
7633
7955
  this.getMeasure().addConnective(connective, tieSpan, noteAnchor);
7634
7956
  } else if (connective === "slur" /* Slur */) {
7635
- assertArg(Utils14.Is.isIntegerOrUndefined(args[0]), "slurSpan", args[0]);
7636
- assertArg(Utils14.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
7957
+ assertArg(Utils15.Is.isIntegerOrUndefined(args[0]), "slurSpan", args[0]);
7958
+ assertArg(Utils15.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
7637
7959
  let slurSpan = args[0];
7638
7960
  let noteAnchor = args[1];
7639
7961
  this.getMeasure().addConnective(connective, slurSpan, noteAnchor);
7640
7962
  } else if (connective === "slide" /* Slide */) {
7641
- assertArg(Utils14.Is.isEnumValueOrUndefined(args[0], NoteAnchor), "noteAnchor", args[0]);
7963
+ assertArg(Utils15.Is.isEnumValueOrUndefined(args[0], NoteAnchor), "noteAnchor", args[0]);
7642
7964
  let noteAnchor = args[0];
7643
7965
  this.getMeasure().addConnective(connective, noteAnchor);
7644
7966
  }
@@ -7646,29 +7968,29 @@ var DocumentBuilder = class {
7646
7968
  }
7647
7969
  /**
7648
7970
  * Add extension line to previously added annotation or label element.
7649
- * <pre>
7971
+ * ```ts
7650
7972
  * // Example
7651
7973
  * addExtension(ext => ext.notes("1n", 2)) // length is 2 whole notes
7652
7974
  * addExtension(ext => ext.measures(3).hide()) // length is 3 measures, hidden
7653
7975
  * addExtension(ext => ext.measures(1).notes("8n")) // length is 1 measure + 1 eigth note
7654
7976
  * addExtension(ext => ext.infinity()) // length is as long as possible
7655
- * </pre>
7977
+ * ```
7656
7978
  * @param extensionBuilder - Extension builder function used to build exstension.
7657
7979
  * @returns - This document builder instance.
7658
7980
  */
7659
7981
  addExtension(extensionBuilder) {
7660
- assertArg(Utils14.Is.isFunctionOrUndefined(extensionBuilder), "addExtension() has new usage, for e.g. addExtension(ext => ext.measures(2)). Please refer to README or API Reference.", extensionBuilder);
7982
+ assertArg(Utils15.Is.isFunctionOrUndefined(extensionBuilder), "addExtension() has new usage, for e.g. addExtension(ext => ext.measures(2)). Please refer to README or API Reference.", extensionBuilder);
7661
7983
  let ticks = 0;
7662
7984
  let visible = true;
7663
7985
  const helper = {
7664
7986
  notes: (noteLength, noteCount) => {
7665
- assertArg(Utils14.Is.isEnumValue(noteLength, NoteLength8) || isNoteLength(noteLength), "noteLength", noteLength);
7666
- assertArg(Utils14.Is.isUndefined(noteCount) || Utils14.Is.isNumber(noteCount) && noteCount >= 0, "noteCount", noteCount);
7987
+ assertArg(Utils15.Is.isEnumValue(noteLength, NoteLength9) || isNoteLength(noteLength), "noteLength", noteLength);
7988
+ assertArg(Utils15.Is.isUndefined(noteCount) || Utils15.Is.isNumber(noteCount) && noteCount >= 0, "noteCount", noteCount);
7667
7989
  ticks += RhythmProps6.get(noteLength).ticks * (noteCount != null ? noteCount : 1);
7668
7990
  return helper;
7669
7991
  },
7670
7992
  measures: (measureCount) => {
7671
- assertArg(Utils14.Is.isNumber(measureCount) && measureCount >= 1, "measureCount", measureCount);
7993
+ assertArg(Utils15.Is.isNumber(measureCount) && measureCount >= 1, "measureCount", measureCount);
7672
7994
  ticks += this.getMeasure().getMeasureTicks() * measureCount;
7673
7995
  return helper;
7674
7996
  },
@@ -7697,13 +8019,13 @@ var DocumentBuilder = class {
7697
8019
  * @returns - This document builder instance.
7698
8020
  */
7699
8021
  addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition = "auto" /* Auto */) {
7700
- assertArg(Utils14.Is.isNonEmptyString(groupName), "groupName", groupName);
8022
+ assertArg(Utils15.Is.isNonEmptyString(groupName), "groupName", groupName);
7701
8023
  assertArg(
7702
- Utils14.Is.isNonEmptyString(staffsTabsAndGroups) || Utils14.Is.isIntegerGte(staffsTabsAndGroups, 0) || Utils14.Is.isNonEmptyArray(staffsTabsAndGroups) && staffsTabsAndGroups.every((line) => Utils14.Is.isNonEmptyString(line) || Utils14.Is.isIntegerGte(line, 0)),
8024
+ Utils15.Is.isNonEmptyString(staffsTabsAndGroups) || Utils15.Is.isIntegerGte(staffsTabsAndGroups, 0) || Utils15.Is.isNonEmptyArray(staffsTabsAndGroups) && staffsTabsAndGroups.every((line) => Utils15.Is.isNonEmptyString(line) || Utils15.Is.isIntegerGte(line, 0)),
7703
8025
  "staffsTabsAndGroups",
7704
8026
  staffsTabsAndGroups
7705
8027
  );
7706
- assertArg(Utils14.Is.isEnumValue(verticalPosition, VerticalPosition), "verticalPosition", verticalPosition);
8028
+ assertArg(Utils15.Is.isEnumValue(verticalPosition, VerticalPosition), "verticalPosition", verticalPosition);
7707
8029
  this.doc.addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition);
7708
8030
  return this;
7709
8031
  }
@@ -7738,7 +8060,7 @@ var DocumentBuilder = class {
7738
8060
  * @returns - This document builder instance.
7739
8061
  */
7740
8062
  completeRests(voiceId) {
7741
- assertArg(Utils14.Is.isUndefined(voiceId) || isVoiceId(voiceId) || Utils14.Is.isArray(voiceId) && voiceId.every((id) => isVoiceId(id)), "voiceId", voiceId);
8063
+ assertArg(Utils15.Is.isUndefined(voiceId) || isVoiceId(voiceId) || Utils15.Is.isArray(voiceId) && voiceId.every((id) => isVoiceId(id)), "voiceId", voiceId);
7742
8064
  this.getMeasure().completeRests(voiceId);
7743
8065
  return this;
7744
8066
  }
@@ -7750,8 +8072,8 @@ var DocumentBuilder = class {
7750
8072
  * @returns - This document builder instance.
7751
8073
  */
7752
8074
  addScaleArpeggio(scale, bottomNote, numOctaves) {
7753
- assertArg(Utils14.Is.isNonEmptyString(bottomNote), "bottomNote", bottomNote);
7754
- assertArg(Utils14.Is.isIntegerGte(numOctaves, 1), "numOctaves", numOctaves);
8075
+ assertArg(Utils15.Is.isNonEmptyString(bottomNote), "bottomNote", bottomNote);
8076
+ assertArg(Utils15.Is.isIntegerGte(numOctaves, 1), "numOctaves", numOctaves);
7755
8077
  let ts = this.getMeasure().getTimeSignature();
7756
8078
  let notes = scale.getScaleNotes(bottomNote, numOctaves);
7757
8079
  for (let i = 0; i < notes.length; i++) {
@@ -7767,7 +8089,7 @@ var DocumentBuilder = class {
7767
8089
  };
7768
8090
 
7769
8091
  // src/score/pub/event.ts
7770
- import { MusicError as MusicError18, MusicErrorType as MusicErrorType18 } from "@tspro/web-music-score/core";
8092
+ import { MusicError as MusicError19, MusicErrorType as MusicErrorType19 } from "@tspro/web-music-score/core";
7771
8093
  var ScoreEvent = class {
7772
8094
  /**
7773
8095
  * Create new score event instance.
@@ -7804,7 +8126,7 @@ var ScoreObjectEvent = class extends ScoreEvent {
7804
8126
  this.renderer = renderer;
7805
8127
  this.objects = objects;
7806
8128
  if (arguments.length === 0) {
7807
- throw new MusicError18(MusicErrorType18.Score, "Empty array in score object event!");
8129
+ throw new MusicError19(MusicErrorType19.Score, "Empty array in score object event!");
7808
8130
  }
7809
8131
  }
7810
8132
  /** Top object getter. */
@@ -7823,24 +8145,24 @@ var ScoreObjectEvent = class extends ScoreEvent {
7823
8145
 
7824
8146
  // src/score/pub/music-interface.ts
7825
8147
  import * as Audio2 from "@tspro/web-music-score/audio";
7826
- import { Utils as Utils16 } from "@tspro/ts-utils-lib";
8148
+ import { Utils as Utils17 } from "@tspro/ts-utils-lib";
7827
8149
 
7828
8150
  // src/score/pub/music-objects.ts
7829
- import { Utils as Utils15 } from "@tspro/ts-utils-lib";
7830
- import { MusicError as MusicError19, MusicErrorType as MusicErrorType19 } from "@tspro/web-music-score/core";
8151
+ import { Utils as Utils16 } from "@tspro/ts-utils-lib";
8152
+ import { MusicError as MusicError20, MusicErrorType as MusicErrorType20 } from "@tspro/web-music-score/core";
7831
8153
  function assertArg2(condition, argName, argValue) {
7832
8154
  if (!condition) {
7833
- throw new MusicError19(MusicErrorType19.Score, `Invalid arg: ${argName} = ${argValue}`);
8155
+ throw new MusicError20(MusicErrorType20.Score, `Invalid arg: ${argName} = ${argValue}`);
7834
8156
  }
7835
8157
  }
7836
8158
  function isVoiceId2(value) {
7837
- return Utils15.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
8159
+ return Utils16.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
7838
8160
  }
7839
8161
  function getNotationLine(line) {
7840
8162
  if (line instanceof ObjStaff || line instanceof ObjTab) {
7841
8163
  return line.getMusicInterface();
7842
8164
  } else {
7843
- throw new MusicError19(MusicErrorType19.Score, `Notation line not staff nor tab.`);
8165
+ throw new MusicError20(MusicErrorType20.Score, `Notation line not staff nor tab.`);
7844
8166
  }
7845
8167
  }
7846
8168
  var MusicInterface6 = class {
@@ -8010,7 +8332,7 @@ var _MDocument = class _MDocument extends MusicInterface6 {
8010
8332
  * @returns - Player instance.
8011
8333
  */
8012
8334
  play(playStateChangeListener) {
8013
- assertArg2(Utils15.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
8335
+ assertArg2(Utils16.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
8014
8336
  return new MPlayer(this, playStateChangeListener).play();
8015
8337
  }
8016
8338
  };
@@ -8040,7 +8362,7 @@ var _MEnding = class _MEnding extends MusicInterface6 {
8040
8362
  * @returns - Boolean whether this ending has asked passage number.
8041
8363
  */
8042
8364
  hasPassage(passage) {
8043
- assertArg2(Utils15.Is.isIntegerGte(passage, 1), "passage", passage);
8365
+ assertArg2(Utils16.Is.isIntegerGte(passage, 1), "passage", passage);
8044
8366
  return this.obj.hasPassage(passage);
8045
8367
  }
8046
8368
  };
@@ -8192,7 +8514,7 @@ var _MStaffTabBarLine = class _MStaffTabBarLine extends MusicInterface6 {
8192
8514
  if (barLine instanceof ObjBarLineLeft || barLine instanceof ObjBarLineRight) {
8193
8515
  return barLine.getMusicInterface();
8194
8516
  } else {
8195
- throw new MusicError19(MusicErrorType19.Score, `Bar line not let nor right.`);
8517
+ throw new MusicError20(MusicErrorType20.Score, `Bar line not let nor right.`);
8196
8518
  }
8197
8519
  }
8198
8520
  /**
@@ -8556,10 +8878,10 @@ var _MTab = class _MTab extends MusicInterface6 {
8556
8878
  /** Object name. */
8557
8879
  __publicField(_MTab, "Name", "Tab");
8558
8880
  var MTab = _MTab;
8559
- var _MSignature = class _MSignature extends MusicInterface6 {
8881
+ var _MStaffSignature = class _MStaffSignature extends MusicInterface6 {
8560
8882
  /** @internal */
8561
8883
  constructor(obj) {
8562
- super(_MSignature.Name);
8884
+ super(_MStaffSignature.Name);
8563
8885
  this.obj = obj;
8564
8886
  }
8565
8887
  /** @internal */
@@ -8575,8 +8897,57 @@ var _MSignature = class _MSignature extends MusicInterface6 {
8575
8897
  }
8576
8898
  };
8577
8899
  /** Object name. */
8578
- __publicField(_MSignature, "Name", "Signature");
8579
- var MSignature = _MSignature;
8900
+ __publicField(_MStaffSignature, "Name", "StaffSignature");
8901
+ var MStaffSignature = _MStaffSignature;
8902
+ var _MTabSignature = class _MTabSignature extends MusicInterface6 {
8903
+ /** @internal */
8904
+ constructor(obj) {
8905
+ super(_MTabSignature.Name);
8906
+ this.obj = obj;
8907
+ }
8908
+ /** @internal */
8909
+ getMusicObject() {
8910
+ return this.obj;
8911
+ }
8912
+ /**
8913
+ * Get tab notation line this signature is in.
8914
+ * @returns - Tab object.
8915
+ */
8916
+ getTab() {
8917
+ return this.obj.tab.getMusicInterface();
8918
+ }
8919
+ };
8920
+ /** Object name. */
8921
+ __publicField(_MTabSignature, "Name", "TabSignature");
8922
+ var MTabSignature = _MTabSignature;
8923
+ var _MTabRhythm = class _MTabRhythm extends MusicInterface6 {
8924
+ /** @internal */
8925
+ constructor(obj) {
8926
+ super(_MTabRhythm.Name);
8927
+ this.obj = obj;
8928
+ }
8929
+ /** @internal */
8930
+ getMusicObject() {
8931
+ return this.obj;
8932
+ }
8933
+ /**
8934
+ * Get measure.
8935
+ * @returns - Measure.
8936
+ */
8937
+ getMeasure() {
8938
+ return this.obj.measure.getMusicInterface();
8939
+ }
8940
+ /**
8941
+ * Get tab.
8942
+ * @returns - Tab.
8943
+ */
8944
+ getTab() {
8945
+ return this.obj.tab.getMusicInterface();
8946
+ }
8947
+ };
8948
+ /** Object name. */
8949
+ __publicField(_MTabRhythm, "Name", "TabRhythm");
8950
+ var MTabRhythm = _MTabRhythm;
8580
8951
  var _MSpecialText = class _MSpecialText extends MusicInterface6 {
8581
8952
  /** @internal */
8582
8953
  constructor(obj) {
@@ -8656,10 +9027,10 @@ __publicField(_MExtensionLine, "Name", "ExtensionLine");
8656
9027
  var MExtensionLine = _MExtensionLine;
8657
9028
 
8658
9029
  // src/score/pub/music-interface.ts
8659
- import { MusicError as MusicError20, MusicErrorType as MusicErrorType20 } from "@tspro/web-music-score/core";
9030
+ import { MusicError as MusicError21, MusicErrorType as MusicErrorType21 } from "@tspro/web-music-score/core";
8660
9031
  function assertArg3(condition, argName, argValue) {
8661
9032
  if (!condition) {
8662
- throw new MusicError20(MusicErrorType20.Score, `Invalid arg: ${argName} = ${argValue}`);
9033
+ throw new MusicError21(MusicErrorType21.Score, `Invalid arg: ${argName} = ${argValue}`);
8663
9034
  }
8664
9035
  }
8665
9036
  function require_t(t, message) {
@@ -8678,7 +9049,7 @@ var _MPlayer = class _MPlayer {
8678
9049
  constructor(doc, playStateChangeListener) {
8679
9050
  __publicField(this, "player");
8680
9051
  assertArg3(doc instanceof MDocument2, "doc", doc);
8681
- assertArg3(Utils16.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
9052
+ assertArg3(Utils17.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
8682
9053
  this.player = new Player();
8683
9054
  this.player.setDocument(doc.getMusicObject());
8684
9055
  this.player.setCursorPositionChangeListener((cursorRect) => doc.getMusicObject().updateCursorRect(cursorRect));
@@ -8736,7 +9107,7 @@ var MRenderer2 = class {
8736
9107
  * @returns - This renderer instance.
8737
9108
  */
8738
9109
  setDocument(doc) {
8739
- assertArg3(Utils16.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
9110
+ assertArg3(Utils17.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
8740
9111
  this.renderer.setDocument(doc);
8741
9112
  return this;
8742
9113
  }
@@ -8746,7 +9117,7 @@ var MRenderer2 = class {
8746
9117
  * @returns - This renderer instance.
8747
9118
  */
8748
9119
  setCanvas(canvas) {
8749
- canvas = require_t(Utils16.Dom.getCanvas(canvas), typeof canvas === "string" ? "Cannot set renderer canvas because invalid canvas id: " + canvas : "Cannot set renderer canvas because given canvas is undefined.");
9120
+ canvas = require_t(Utils17.Dom.getCanvas(canvas), typeof canvas === "string" ? "Cannot set renderer canvas because invalid canvas id: " + canvas : "Cannot set renderer canvas because given canvas is undefined.");
8750
9121
  this.renderer.setCanvas(canvas);
8751
9122
  return this;
8752
9123
  }
@@ -8755,7 +9126,7 @@ var MRenderer2 = class {
8755
9126
  * @param scoreEventListener - Score event listener.
8756
9127
  */
8757
9128
  setScoreEventListener(scoreEventListener) {
8758
- assertArg3(Utils16.Is.isFunctionOrUndefined(scoreEventListener), "scoreEventListener", scoreEventListener);
9129
+ assertArg3(Utils17.Is.isFunctionOrUndefined(scoreEventListener), "scoreEventListener", scoreEventListener);
8759
9130
  this.renderer.setScoreEventListener(scoreEventListener);
8760
9131
  }
8761
9132
  /**
@@ -8829,7 +9200,7 @@ var _MPlaybackButtons = class _MPlaybackButtons {
8829
9200
  * @returns
8830
9201
  */
8831
9202
  setDocument(doc) {
8832
- assertArg3(Utils16.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
9203
+ assertArg3(Utils17.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
8833
9204
  this.onStop();
8834
9205
  if (doc) {
8835
9206
  this.player = new MPlayer(doc, (playState) => {
@@ -8873,9 +9244,9 @@ var _MPlaybackButtons = class _MPlaybackButtons {
8873
9244
  * @returns - This playback buttons class instance.
8874
9245
  */
8875
9246
  setPlayButton(btn, btnLabel) {
8876
- assertArg3(Utils16.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9247
+ assertArg3(Utils17.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
8877
9248
  _MPlaybackButtons.removeOnClickListeners(this.playButton, this.onPlay);
8878
- this.playButton = require_t(Utils16.Dom.getButton(btn), "Play button required!");
9249
+ this.playButton = require_t(Utils17.Dom.getButton(btn), "Play button required!");
8879
9250
  this.playLabel = btnLabel != null ? btnLabel : "Play";
8880
9251
  _MPlaybackButtons.removeOnClickListeners(this.playButton, "all");
8881
9252
  _MPlaybackButtons.addOnClickListener(this.playButton, this.onPlay);
@@ -8889,9 +9260,9 @@ var _MPlaybackButtons = class _MPlaybackButtons {
8889
9260
  * @returns - This playback buttons class instance.
8890
9261
  */
8891
9262
  setStopButton(btn, btnLabel) {
8892
- assertArg3(Utils16.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9263
+ assertArg3(Utils17.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
8893
9264
  _MPlaybackButtons.removeOnClickListeners(this.stopButton, this.onStop);
8894
- this.stopButton = require_t(Utils16.Dom.getButton(btn), "Stop button required!");
9265
+ this.stopButton = require_t(Utils17.Dom.getButton(btn), "Stop button required!");
8895
9266
  this.stopLabel = btnLabel != null ? btnLabel : "Stop";
8896
9267
  _MPlaybackButtons.removeOnClickListeners(this.stopButton, "all");
8897
9268
  _MPlaybackButtons.addOnClickListener(this.stopButton, this.onStop);
@@ -8906,10 +9277,10 @@ var _MPlaybackButtons = class _MPlaybackButtons {
8906
9277
  * @returns - This playback buttons class instance.
8907
9278
  */
8908
9279
  setPlayStopButton(btn, playLabel, stopLabel) {
8909
- assertArg3(Utils16.Is.isStringOrUndefined(playLabel), "playLabel", playLabel);
8910
- assertArg3(Utils16.Is.isStringOrUndefined(stopLabel), "stopLabel", stopLabel);
9280
+ assertArg3(Utils17.Is.isStringOrUndefined(playLabel), "playLabel", playLabel);
9281
+ assertArg3(Utils17.Is.isStringOrUndefined(stopLabel), "stopLabel", stopLabel);
8911
9282
  _MPlaybackButtons.removeOnClickListeners(this.playStopButton, this.onPlayStop);
8912
- this.playStopButton = require_t(Utils16.Dom.getButton(btn), "Play/stop button required!");
9283
+ this.playStopButton = require_t(Utils17.Dom.getButton(btn), "Play/stop button required!");
8913
9284
  this.playLabel = playLabel != null ? playLabel : "Play";
8914
9285
  this.stopLabel = stopLabel != null ? stopLabel : "Stop";
8915
9286
  _MPlaybackButtons.removeOnClickListeners(this.playStopButton, "all");
@@ -8924,9 +9295,9 @@ var _MPlaybackButtons = class _MPlaybackButtons {
8924
9295
  * @returns - This playback buttons class instance.
8925
9296
  */
8926
9297
  setPauseButton(btn, btnLabel) {
8927
- assertArg3(Utils16.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9298
+ assertArg3(Utils17.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
8928
9299
  _MPlaybackButtons.removeOnClickListeners(this.pauseButton, this.onPause);
8929
- this.pauseButton = require_t(Utils16.Dom.getButton(btn), "Pause button required!");
9300
+ this.pauseButton = require_t(Utils17.Dom.getButton(btn), "Pause button required!");
8930
9301
  this.pauseLabel = btnLabel != null ? btnLabel : "Pause";
8931
9302
  _MPlaybackButtons.removeOnClickListeners(this.pauseButton, "all");
8932
9303
  _MPlaybackButtons.addOnClickListener(this.pauseButton, this.onPause);
@@ -8948,7 +9319,7 @@ var _MPlaybackButtons = class _MPlaybackButtons {
8948
9319
  }
8949
9320
  }
8950
9321
  static addOnClickListener(btn, onClick) {
8951
- assertArg3(Utils16.Is.isFunction(onClick), "onClick", onClick);
9322
+ assertArg3(Utils17.Is.isFunction(onClick), "onClick", onClick);
8952
9323
  btn.addEventListener("click", onClick);
8953
9324
  let clickListeners = this.savedOnClickListeners.get(btn) || [];
8954
9325
  this.savedOnClickListeners.set(btn, [...clickListeners, onClick]);
@@ -8993,15 +9364,17 @@ export {
8993
9364
  MRest,
8994
9365
  MRhythmColumn,
8995
9366
  MScoreRow,
8996
- MSignature,
8997
9367
  MSpecialText,
8998
9368
  MStaff,
8999
9369
  MStaffBeamGroup,
9000
9370
  MStaffNoteGroup,
9001
9371
  MStaffRest,
9372
+ MStaffSignature,
9002
9373
  MStaffTabBarLine,
9003
9374
  MTab,
9004
9375
  MTabNoteGroup,
9376
+ MTabRhythm,
9377
+ MTabSignature,
9005
9378
  MText,
9006
9379
  MusicInterface6 as MusicInterface,
9007
9380
  Navigation,