@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,4 +1,4 @@
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
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -65,15 +65,17 @@ __export(score_exports, {
65
65
  MRest: () => MRest,
66
66
  MRhythmColumn: () => MRhythmColumn,
67
67
  MScoreRow: () => MScoreRow,
68
- MSignature: () => MSignature,
69
68
  MSpecialText: () => MSpecialText,
70
69
  MStaff: () => MStaff,
71
70
  MStaffBeamGroup: () => MStaffBeamGroup,
72
71
  MStaffNoteGroup: () => MStaffNoteGroup,
73
72
  MStaffRest: () => MStaffRest,
73
+ MStaffSignature: () => MStaffSignature,
74
74
  MStaffTabBarLine: () => MStaffTabBarLine,
75
75
  MTab: () => MTab,
76
76
  MTabNoteGroup: () => MTabNoteGroup,
77
+ MTabRhythm: () => MTabRhythm,
78
+ MTabSignature: () => MTabSignature,
77
79
  MText: () => MText,
78
80
  MusicInterface: () => MusicInterface6,
79
81
  Navigation: () => Navigation,
@@ -373,7 +375,7 @@ var DivRect = class _DivRect {
373
375
  };
374
376
 
375
377
  // src/score/pub/document-builder.ts
376
- var import_ts_utils_lib15 = require("@tspro/ts-utils-lib");
378
+ var import_ts_utils_lib16 = require("@tspro/ts-utils-lib");
377
379
 
378
380
  // src/score/pub/types.ts
379
381
  var StaffPreset = /* @__PURE__ */ ((StaffPreset3) => {
@@ -385,10 +387,10 @@ var StaffPreset = /* @__PURE__ */ ((StaffPreset3) => {
385
387
  StaffPreset3["GuitarCombined"] = "guitarCombined";
386
388
  return StaffPreset3;
387
389
  })(StaffPreset || {});
388
- var Clef = /* @__PURE__ */ ((Clef2) => {
389
- Clef2["G"] = "G";
390
- Clef2["F"] = "F";
391
- return Clef2;
390
+ var Clef = /* @__PURE__ */ ((Clef4) => {
391
+ Clef4["G"] = "G";
392
+ Clef4["F"] = "F";
393
+ return Clef4;
392
394
  })(Clef || {});
393
395
  function getVoiceIds() {
394
396
  return [0, 1, 2, 3];
@@ -585,7 +587,7 @@ var import_theory12 = require("@tspro/web-music-score/theory");
585
587
  var import_theory11 = require("@tspro/web-music-score/theory");
586
588
 
587
589
  // src/score/engine/renderer.ts
588
- var import_ts_utils_lib2 = require("@tspro/ts-utils-lib");
590
+ var import_ts_utils_lib3 = require("@tspro/ts-utils-lib");
589
591
 
590
592
  // src/score/engine/settings.ts
591
593
  var DebugSettings = {
@@ -617,7 +619,7 @@ var DocumentSettings = {
617
619
  };
618
620
 
619
621
  // src/score/engine/renderer.ts
620
- var import_core2 = require("@tspro/web-music-score/core");
622
+ var import_core3 = require("@tspro/web-music-score/core");
621
623
 
622
624
  // src/score/engine/assets/treble-clef.png
623
625
  var treble_clef_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAACWCAYAAACCe+v6AAADHXpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHja7ZZRcu0mDIbfWUWXgCSExHIwmJnu4C6/Pxg7J2kyTdv7GJhjsJCF0CfZJ5y//hzhDzRK5iGpeS45R7RUUuGKicerHetKMa3ratL2Gr2Xh5L3AkMkU/O6LbzlJ+SY074vexO69W9D94QqZvq2UOuWH+/lxzbI/tHQ9kDo2jn2/cA2JLw9Std92x7l4vbuaH2fGYqXyN9+SYyzZrKEa+JolgvmzjEZ4tmno6NxWYb0CugjuO9vVYZPfApJxFUkXV7K/IlUjBlXrAYokhhuFMK5UFbgI1DCBXha9kY1PsF8jc1bjL5o3zlWxCbjnMov1J7xQ97k/HnePLOdBg81z3tB3mON+Rk/lZPehu4Fefbh1529PTu/k4vE9BqK8Ip7jO5jHRqnqCkjFnkf6j7KmkHvmFFcT2V0izkgax2T2Qu6xxobcqrHhko7MC/EoDsoUadKg841NmpwMfHJhpG5BZYldEAq3GQmQ5qdBpsU6eLImHblkPDjC61ty9qukcceYieoMsEY4ZH/3MN3FceYtUQU/YoT0gJ+8axOeBEJ+OcANTCgsYOqK8B3/9gm18lMV5gdB6zxCJeJQ+ktuWSBFigqxgsyWd8GECJsrXCGBARiJlHK8MiYjQiBdACqcJ0l8QECpModTnISyYCD6sDeeMZoqbLyJcZbVVJAsWYUrYNQBayUFPljyZFDVUWTqmY1dS1as+RZeTlbnq/namLJ1LIZ3tlWrLp4cvXs5u7Fa+EieH1rQZ0WL6XUik0rLFc8XaFQ68GHHOnQIx92+FHCURvSp6WmLTdr3kqrnbt0FHjP3br30utJJ1LpTKee+bTTz3LWgVQbMtLQkYeF4aOM+lCjXbYf+7+gRpsaL1JT0R5qkJrdJmi+TnQyAzFOBOAGaiCGxJ7MolNKPMlNZvgeoSqU4aROOJ0mMRBMJ7EOethtcoHr7+EWzBc3/r/kwkT3TXJ/5/YZtT6/Em0Ru8pwBjUKqg/rp1f2Oj+vX47hnxS+O/4Y+jH0Y+jrcYwROv51hb8AKbCqdGIdCl0AAAGFaUNDUElDQyBwcm9maWxlAAB4nH2RPUjDQBzFX1O1UqoOdhBxyFCd7OAH0rFUsQgWSluhVQeTS7+gSUOS4uIouBYc/FisOrg46+rgKgiCHyCuLk6KLlLi/5JCi1gPjvvx7t7j7h0gNCpMNXuigKpZRioeE7O5VdH3ij74MYgpRCRm6on0YgZdx9c9PHy9C/Os7uf+HANK3mSARySOMt2wiDeI5zYtnfM+cZCVJIX4nHjSoAsSP3JddvmNc9FhgWcGjUxqnjhILBY7WO5gVjJU4lnikKJqlC9kXVY4b3FWKzXWuid/YSCvraS5TnMMcSwhgSREyKihjAoshGnVSDGRov1YF/+o40+SSyZXGYwcC6hCheT4wf/gd7dmYWbaTQrEgN4X2/4YB3y7QLNu29/Htt08AbzPwJXW9lcbQOST9HpbCx0BQ9vAxXVbk/eAyx1g5EmXDMmRvDSFQgF4P6NvygHDt4B/ze2ttY/TByBDXS3fAAeHwESRste7vLu/s7d/z7T6+wEMNXLkxtwRywAADzRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+Cjx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDQuNC4wLUV4aXYyIj4KIDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+CiAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIKICAgIHhtbG5zOkdJTVA9Imh0dHA6Ly93d3cuZ2ltcC5vcmcveG1wLyIKICAgIHhtbG5zOnRpZmY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vdGlmZi8xLjAvIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICB4bXBNTTpEb2N1bWVudElEPSJnaW1wOmRvY2lkOmdpbXA6NDA3ODVjMzYtNDAxZC00YTZlLTkxODctMDQ1NTI4MmM0ZGY2IgogICB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjhiZTJkYzc1LTVlYjQtNDk0Yy1iNWRlLWQ2MzZkNzZhNjI2YiIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOmU3YWE0MWNhLTNiYjMtNGU5Yi05NDQxLTllNTNmZTJiZjM5ZiIKICAgZGM6Rm9ybWF0PSJpbWFnZS9wbmciCiAgIEdJTVA6QVBJPSIyLjAiCiAgIEdJTVA6UGxhdGZvcm09IldpbmRvd3MiCiAgIEdJTVA6VGltZVN0YW1wPSIxNjg2NDA4NjA5MzE2NDM4IgogICBHSU1QOlZlcnNpb249IjIuMTAuMzQiCiAgIHRpZmY6T3JpZW50YXRpb249IjEiCiAgIHhtcDpDcmVhdG9yVG9vbD0iR0lNUCAyLjEwIgogICB4bXA6TWV0YWRhdGFEYXRlPSIyMDIzOjA2OjEwVDE3OjUwOjA5KzAzOjAwIgogICB4bXA6TW9kaWZ5RGF0ZT0iMjAyMzowNjoxMFQxNzo1MDowOSswMzowMCI+CiAgIDx4bXBNTTpIaXN0b3J5PgogICAgPHJkZjpTZXE+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjI3MzY2YmY0LWVkZDMtNDE5OC05NjJhLWU5ZTM5MTBlNThiZSIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iR2ltcCAyLjEwIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyMi0wOC0yMlQwMjo1NTozNiIvPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDo5NjVlMTM3OS0wZDlmLTQ5ODItYWQ3MC05MzhjOWMzOWE0ZjMiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkdpbXAgMi4xMCAoV2luZG93cykiCiAgICAgIHN0RXZ0OndoZW49IjIwMjItMDktMTFUMTY6MzU6MDAiLz4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MTBmYmEwYTMtOTI5Yi00NTRlLThjNGMtOGVkOGM4YWJhZGRjIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKFdpbmRvd3MpIgogICAgICBzdEV2dDp3aGVuPSIyMDIzLTA2LTEwVDE3OjUwOjA5Ii8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/Ppn4NIQAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfnBgoOMgm5WlWBAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAACHtJREFUeNrtnXuQVmMcxz+77cauTWUpbGSVu2w3BpnUEBq3chkmBjGayG1GBuNWLtUgw5SJkBkjl4QKg1wyQyarK0lRSlstU20bWam9+OM8O3P6vc8553nOe97tnO18Z84f57zP7XvOc/ndnueFfQx5e6neUmAI0B3oDPwD/AJ8Dvzcml5we+Al4D+gyeOaB1S0BrLHAut9iLqvf4ERSSZbBmwwJOu+RieV8JwQZJuARjXWE4WBIck2X38AByaJ8MwsCTcBTyWFbCFQFwHhv4DiKBqUn2PCPYEin9+bgI3AUuBPn3TtgMuT8IWv8vlq7wLdRPrTgPke6d9JAuFbPBo/3UfKK1TCh8yzIQmEb/cYjx0C8pUDuzV5D477GN6mefY+UBuQby0wV/O8U9wJr9E8W2iY92vNs45xJ6zTfKoN827UPNsdd8K1SlJyo8Awb7XhEIkVYYAVmjXVBPtr1uyqJBBeLu5LDPMdppkPdiaRcHvDfKeJ+++SIFoCLBP3R1toWW58lhQFogiodwkPlYZf1y1w/AcclCQVcYWQtILwqiA8M2lGgDcFgSN90nbXiJUXRdWQ/BYiLMdxH5+0k8VavRb4JGmEl4j7vh7pRgDni2fj1RyQKBwiuqjui/Un015dBbQloXCbaTdrZuUajTp4IwnGbEHmKPX8QmCHhuwC9p4rKBI8IghdB0zCsT1Lsg0+4zwxuEiQqqcVmGWDlAETk+zSJE9Ublyjuqof2TrgxKQT7anMNSZfd1iSiZYCUwy+avP1dJLJXglsxdyV8hHQJolEDwBewc5v9J3Klzj0xYnTsCG7W4mdicMdwC7CeQaPTBLRAjUxZeMKvSwpZPcDPghBUGpE45JAthjH92NLdiUwSDz7NO5k24YkuwTHGZYvtKMtcSabD7wVguy37OkilU7v8rgSfjoE2c816+wkkebKOJK9NgTZ2Wpykxgu0k2IG9lTcMIBbchOx9tTWKHpBbFBoZpwbMi+iL9FtEC8wG1xIvyQJdlJhuVWinzd4kD2cJxYZlOyky3KfkHkvSoOhF+2IPu8Zdk3x82O1QV96JDumhJSu5KB4XsVEwzJziCcy2Z/8UK3K5G1PZnhDi2iBW02IDvPY501xY8BuvJ6JcY+AQzAPCDGGucZkF2GefiCxFk4AWoN2K0AG4HHiSBATWJqQMXr1Qxui3Jlv8o2nHiHIl4UFeF1+G/ACOMGuZVoYqfd12qgX7ZkuwZUMjyEoWBaxETd1y5gVDaEr/YpfGqIyW9ODsm6r7FhCY/z6T625tTpLUS2+bo3DOHZHoVdYFnOqBYmG3rbz1JNQbZ2p2MsZfAor604G8OMsUVTyEBLwjMsv4r7vkapl28AH+PEWNqu1++ZNjRPk3mFJdnjDBu4HBipVoUGsewVaGb6fjgRPSsMSQ8wNb/KjA9bEp5osIzcLUitEml6BNQxxGPoWVtROmoynmFJ+CefRvytxFaJt0W6GwwtqE8GkA56cZSSGVxiI74FhTUM9ch3f0irCerleNU3wbZL2xrJzwhp+hks0s6PaBitMsnsXk7WWlY8xKPi7fjvOZI94x/sHOQFPobGw+U4kHBvrrDVRrw2RE4L6C3V7Ln3sBg43qLeeuAxj996BxHeJCYxm2i4Gh8RMwjL/BpqgA/VpKgTgnwJuzdXtbWUWpZpntUCiwwlPDf6WBLeBSzWPO8URFjuHOthUWm1ptJFaizZErb9wvJjNaMkiLDck2CrYD8n7k13hUrCvUIYB3Vdui6I8FI1qzbjUstKXwe+EV3aBKtE40pwjsKwwQEeuoEv4d3ALNf9ycCpFpU24ngRVrvkYNN8y7Ps1rqlb3MQYXCc3m7YytOb1FCYa2lhzHbiqjAoU4s2GoG+D+Fg85VGijq/ssh7qEboqLGZB6QDvBLHdZpLnK6R0EzlgNs0hGfZVJ6v1lV3ARNzTLhYo0sfY5h3sYWy4ole7Blh16ismrnEStFok/ou05BdR8iA1QfJDN2/PoeEZZTQkwZL0RoN4bvCNiCPzONlGpVJNBe7Tu4TdX1h2bbmmLCCbMfWAvTew6iDQy/QzLReZJ/RtKk+pFiagXZqmdCdyzGG8J5Eic6aOuSe4yK8A+RGRfn2/SqqwdmbVBZBPX/gHbh2MfAbEbtbTAQEr7itehyX6DDCn6zyCZlhUHcoTc7Ltj2WHKNcLexBRvaFaqxdr0Q/k2OixmNudN9uo+BEMcsOAB4AzrXIU6vUxlrVU3YqJaMEOELZoUzW0PeBezz04JyjN07o0mZy7zD7EjiTmKAQOAfHJlyJ/xmWtsHlo1UPCI28FnoBJym9urtaYspwdrOUKkmprerC/6pl7lel/HdxlTORBB/7aIJnLSQuK40orlisUWRaNXpoxnHX1ky4DZlhTkNbc5duwAlNjLRb58f8Ky/e1wgv2dcmrr6aiSur3agFOWxsL6XM91a6crUSCWfi+H9NoDtEsIKY7YI52sNQ4D5uZpBFeTKMamScyJqeFL4L8yOjfhB5x8Rp0ppoaPEoBF4j86A/HerEfUlcCB8GXGGRvqPSZYPQIeAF7DXC/bE3fJsY2eWsvCEuhMtC9oouAROgPPxveVwIN4TM53f08tnifgfmh/nmnPC6kPk2+fx2k7ifpWb4WKAT9mG+foFvMqqvkRj+pYntFp0HPMrZj8wg1VieEd8Tc6NdFXr3TCFOgLc77TZifE7AaAOyv+MY9iS64pxBK7vyJXHWcLy8eu4T0dybo9vhBMBMJvMwwEbgzqSodnfhvxOtDieQzOv3ncRkE7UNytV4tJ295+LsnUgsugKPAt/jvQm7DmcX2+Bcj7eWRjFwAo4rtYOa1avUMrSTFClSpEiRIkWKFClSpEiRIkWKFClSpEiRIkWKFClSpEiRIgL8D6ed2EKeJMaTAAAAAElFTkSuQmCC";
@@ -625,6 +627,255 @@ var treble_clef_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAC
625
627
  // src/score/engine/assets/bass-clef.png
626
628
  var bass_clef_default = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAABGCAYAAACQRffVAAADInpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHja7VdbktwgDPznFDkCkgCJ4/AwVblBjp8GY+/OZFPZPD7yMVADWIiWUEt2jTu+fR3uCxplTi5EtZRT8mghh8wFC/Nnq2skH9a4mrS9R49yF9LeYIhkap6Pmbf8gBxr2s95G6FL/wK6FlSwim8bpWx5fZTXDcj2DLQ3hE7Lvu8DG0h4exTO57Y9Stn04Wp93xmKp8jefkGUU0ykAWNgr5oy1sY+KOLZp6PcznP31S7B9XypMnziQ0g8RpFweinzJ1IwJ4wk4qA4hUXiGlmWGTiUEG4Fbj6BR/F3MN/H5i1GP2mfuZaHkXFM5XdXu+envOn147y5VzsN3JU3lvaGPNLq0z1/KKd4AV0bctvh95at3ZYf5ENWdt3Nvad7jG5jXRq3KCEhFmlf6rrKWkGvziiuUwldfXLANSxmz+jmi2/Iqe4bKq1inYnB/aBAnQoNOtbcqMHFwAcrZubmWJbQQFLmhlQgCbPTYJUsXQwp0c4cEr59oWU2L3ONzHfnO0GVCWCEI3/c3WcVx5i1ROTtjBM8g188qxNeeAL9c4IaGKGxgxpXgK/+3CavAgbjCrPhgsVXd0LUSG/JJYvoSW/EfFY9ad8ACBFMRzhDAgZ8IomU4JEyKxECaSCowHWWwBUMUIzc4SQHkQRyUB2wjTNKS5Ujn2K8VSU4FGsSBTdZCsgKISJ/NBhyqESJIcaYokaLOZYkaVZeSprm67moaNCoSVXNadZiYsGiJVMzy1YyZ8HrO2bUabaccykwWoBccLpAoZTKVWqosaaq1Wp2tTSkTwstttS0WcutdO7SUeA9de3Wcy8HHUilIxzxSIceduSjDKTakBFGHGmoGzbyKDdrtMv2uf8Ga7RZ48XUVNSbNUhVLwiar5M4OQNjHAiEK1gDY0jsyZk3CoEnc5MzfI9QFZHhZJzkdJqMgcFwEMdBN3ebOcfl3/Dm1BZv/LfMuUndJ5n7kbePWOvzK9EWY2cZzqB6QfVh/7DCVubn9aez+5XCZ+cX0AvoBfQCegG9gP57oIEPJ/4Bue+bLIaQwqExNwAAAYVpQ0NQSUNDIHByb2ZpbGUAAHicfZE9SMNAHMVfU7UiFQeLijhkqE4WREUcSxWLYKG0FVp1MLn0Q2jSkKS4OAquBQc/FqsOLs66OrgKguAHiKuLk6KLlPi/pNAixoPjfry797h7Bwj1MlPNjiigapaRisfEbG5FDLyiC0EMYgIDEjP1RHohA8/xdQ8fX+8iPMv73J+jV8mbDPCJxFGmGxbxOvHMpqVz3icOsZKkEJ8Tjxt0QeJHrssuv3EuOizwzJCRSc0Rh4jFYhvLbcxKhko8TRxWVI3yhazLCuctzmq5ypr35C8M5rXlNNdpjiCORSSQhAgZVWygDAsRWjVSTKRoP+bhH3b8SXLJ5NoAI8c8KlAhOX7wP/jdrVmYmnSTgjGg88W2P0aBwC7QqNn297FtN04A/zNwpbX8lTow+0l6raWFj4C+beDiuqXJe8DlDjD0pEuG5Eh+mkKhALyf0TflgP5boGfV7a25j9MHIENdLd0AB4fAWJGy1zze3d3e279nmv39ANCccsygwwDVAAAQE2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNC40LjAtRXhpdjIiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6R0lNUD0iaHR0cDovL3d3dy5naW1wLm9yZy94bXAvIgogICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iCiAgIHhtcE1NOkRvY3VtZW50SUQ9ImdpbXA6ZG9jaWQ6Z2ltcDo0MDc4NWMzNi00MDFkLTRhNmUtOTE4Ny0wNDU1MjgyYzRkZjYiCiAgIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6Nzg3YjYxN2YtMjg1MS00YzhlLTg2MTYtZWM3NGMwYzYwMWVlIgogICB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6ZTdhYTQxY2EtM2JiMy00ZTliLTk0NDEtOWU1M2ZlMmJmMzlmIgogICBkYzpGb3JtYXQ9ImltYWdlL3BuZyIKICAgR0lNUDpBUEk9IjIuMCIKICAgR0lNUDpQbGF0Zm9ybT0iV2luZG93cyIKICAgR0lNUDpUaW1lU3RhbXA9IjE2ODY2MTM5NDcxOTU2ODAiCiAgIEdJTVA6VmVyc2lvbj0iMi4xMC4zNCIKICAgdGlmZjpPcmllbnRhdGlvbj0iMSIKICAgeG1wOkNyZWF0b3JUb29sPSJHSU1QIDIuMTAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMjM6MDY6MTNUMDI6NTI6MjUrMDM6MDAiCiAgIHhtcDpNb2RpZnlEYXRlPSIyMDIzOjA2OjEzVDAyOjUyOjI1KzAzOjAwIj4KICAgPHhtcE1NOkhpc3Rvcnk+CiAgICA8cmRmOlNlcT4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MjczNjZiZjQtZWRkMy00MTk4LTk2MmEtZTllMzkxMGU1OGJlIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKFdpbmRvd3MpIgogICAgICBzdEV2dDp3aGVuPSIyMDIyLTA4LTIyVDAyOjU1OjM2Ii8+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249InNhdmVkIgogICAgICBzdEV2dDpjaGFuZ2VkPSIvIgogICAgICBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjk2NWUxMzc5LTBkOWYtNDk4Mi1hZDcwLTkzOGM5YzM5YTRmMyIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iR2ltcCAyLjEwIChXaW5kb3dzKSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyMi0wOS0xMVQxNjozNTowMCIvPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJzYXZlZCIKICAgICAgc3RFdnQ6Y2hhbmdlZD0iLyIKICAgICAgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDoxMGZiYTBhMy05MjliLTQ1NGUtOGM0Yy04ZWQ4YzhhYmFkZGMiCiAgICAgIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkdpbXAgMi4xMCAoV2luZG93cykiCiAgICAgIHN0RXZ0OndoZW49IjIwMjMtMDYtMTBUMTc6NTA6MDkiLz4KICAgICA8cmRmOmxpCiAgICAgIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiCiAgICAgIHN0RXZ0OmNoYW5nZWQ9Ii8iCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6MDBmYjM4YTMtZjZiMi00NjQ1LTliMTYtMjlhNWE0ODZlMjhhIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJHaW1wIDIuMTAgKFdpbmRvd3MpIgogICAgICBzdEV2dDp3aGVuPSIyMDIzLTA2LTEzVDAyOjUyOjI3Ii8+CiAgICA8L3JkZjpTZXE+CiAgIDwveG1wTU06SGlzdG9yeT4KICA8L3JkZjpEZXNjcmlwdGlvbj4KIDwvcmRmOlJERj4KPC94OnhtcG1ldGE+CiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICAgICAKPD94cGFja2V0IGVuZD0idyI/PsIRrtIAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAALiMAAC4jAXilP3YAAAAHdElNRQfnBgwXNBsqJURsAAAAGXRFWHRDb21tZW50AENyZWF0ZWQgd2l0aCBHSU1QV4EOFwAABF9JREFUeNrtmluIF1Ucxz9/E8P1VnnJ9dJWC4Frmq2JJmqolGEILoQvK2gZeXlRCSm1Fx9UEsJQERWsXhRftECs0Gq70EK9ZHlbFyHbds3VVXFX91+7664P81tYhpnfmft//st84TzMzDm/8/vOnPO7nYEMGTJkyJAhQ4YMGSJBLkJZw4FyYAIwDHgU+A9oAxqBv4C7xfyySoBlwKfAFaAb6DG0euAzoAoYXCxEnwH2A60eCGrtFrALGJNWokNEwY6QRO2tFXgPGJAmss8DlyImam/fASPTQHaeGJueBFod8FQhrfSLwM+ynDX8L1/oV+BP4LZY58eBUUAlMB94ycPSvQTMERmJ4jGgwYPh2Qg84VFmGbAP6DTI/aoQS/lzg1JfA2MDyn4ZuGaQvyZJspUGv3oKGBhyjmeBJmWOmxLMJIITiiIXIgwaZgFdylxbDeNHANXAZmAVUBpEiScNe2xRxC/3Y2WuRmUlLRHD1rd/HljvV4F3FAVqYlhNo4B7Pl/wdPEMbmOq/ShwRBH0Vkxb6LAy536fW64HuOpn8vOKoLKYCC9Q5rzs0L/JQxDjyYPkgHYXAW0xGslByrLuFuPUFw0eCI92mmiAQ4LgZoEbYyTcAZxVPsJk271ag7x6cWueCLvhfsyu8LzybKLtersUF9ywxe2BnXBnAZOUJuXZeNv1OSki3LLdzwPrgONuguw+7g7wAHjEoW+vEagAXgeelr1yUSZoCUn4hvJsqMO9byRaWyLGtFkiwOtBJnYzBKcVg/ZuSMIrlHl3RrWMnFK1OqX/q8oXOAisDqFLVxL7xonw9yHk7Q5RoxpuyLdjI3wmhLzBwMqAY0ck4SGcCNeKIQqKOTF84RtxEu4BPgohc2QM467HSRjgqBL5mBDUPU1Rnl1JwqBNUuJqrW0M+OLdYuk8Cdas38Rf4b3FR0HP/nLdZNYaioKbxSVuA6ZGQfoNvNWlO6VvEKxW5O5yGbNc4ml7ZrUtCtLjgGMSdjop9Q+wMIT8GoXwKw79ZxrKUG9r+a8flMoyr5AA4ybwo1QgggYHpZJ6Ou3Ta5IpddvufwEsVWQ2xFisCI1Nypf6RMmsIql4JI0S8bFuSs9UvmCgikeh8b6i8C/KuKOYD+VShzGSwLsprRnByYYYoSqNhE8qCv/kYfxrYjT7jmuPIC+PBWsVsl1YRzBeE45qqWGtwjo1SR0WoZ8a7KAfYa5h7/2OVaPuF1gqtS83srclpi565IAP0c+b7wOz+wPZckOc3Jt0LC52oiXABx7y6VasGnfRYgiwwRAu9raGqPLXQmAGcADvvyN+m9bgXnP4i4E9wN8+KiJ5WQG5QilumnioJP9lwHPANKw/fF7A+fxJw2ms/y9SFdiPBf4Vn9hJNL8T/iFxbyoxgej+m6zBOtnLpXlvhiXcDOyVJV8UCEL4KnBI/OnAtBP0q+ADMTq/SfshrdUFr4TzwJdY9d57WIdYzRIk1GMdeXSQIUOGDBmSwUMtd8u2ArdcUAAAAABJRU5ErkJggg==";
627
629
 
630
+ // src/theory/rhythm.ts
631
+ var import_ts_utils_lib2 = require("@tspro/ts-utils-lib");
632
+ var import_core2 = require("@tspro/web-music-score/core");
633
+ var MaxTupletRatioValue = 12;
634
+ var TicksMultiplier = 12 * 11 * 9 * 7 * 5;
635
+ var NoteLength = /* @__PURE__ */ ((NoteLength10) => {
636
+ NoteLength10["Whole"] = "1n";
637
+ NoteLength10["WholeTriplet"] = "1t";
638
+ NoteLength10["WholeDot"] = "1.";
639
+ NoteLength10["Whole2Dots"] = "1..";
640
+ NoteLength10["Whole12Dots"] = "1..";
641
+ NoteLength10["Whole3Dots"] = "1...";
642
+ NoteLength10["Whole4Dots"] = "1....";
643
+ NoteLength10["Whole5Dots"] = "1.....";
644
+ NoteLength10["Whole6Dots"] = "1......";
645
+ NoteLength10["Half"] = "2n";
646
+ NoteLength10["HalfTriplet"] = "2t";
647
+ NoteLength10["HalfDot"] = "2.";
648
+ NoteLength10["Half2Dots"] = "2..";
649
+ NoteLength10["Half3Dots"] = "2...";
650
+ NoteLength10["Half4Dots"] = "2....";
651
+ NoteLength10["Half5Dots"] = "2.....";
652
+ NoteLength10["Quarter"] = "4n";
653
+ NoteLength10["QuarterTriplet"] = "4t";
654
+ NoteLength10["QuarterDot"] = "4.";
655
+ NoteLength10["Quarter2Dots"] = "4..";
656
+ NoteLength10["Quarter3Dots"] = "4...";
657
+ NoteLength10["Quarter4Dots"] = "4....";
658
+ NoteLength10["Eighth"] = "8n";
659
+ NoteLength10["EighthTriplet"] = "8t";
660
+ NoteLength10["EighthDot"] = "8.";
661
+ NoteLength10["Eighth2Dots"] = "8..";
662
+ NoteLength10["Eighth3Dots"] = "8...";
663
+ NoteLength10["Sixteenth"] = "16n";
664
+ NoteLength10["SixteenthTriplet"] = "16t";
665
+ NoteLength10["SixteenthDot"] = "16.";
666
+ NoteLength10["Sixteenth2Dots"] = "16..";
667
+ NoteLength10["ThirtySecond"] = "32n";
668
+ NoteLength10["ThirtySecondTriplet"] = "32t";
669
+ NoteLength10["ThirtySecondDot"] = "32.";
670
+ NoteLength10["SixtyFourth"] = "64n";
671
+ NoteLength10["SixtyFourthTriplet"] = "64t";
672
+ return NoteLength10;
673
+ })(NoteLength || {});
674
+ function validateNoteLength(noteLength) {
675
+ if (import_ts_utils_lib2.Utils.Is.isEnumValue(noteLength, NoteLength)) {
676
+ return noteLength;
677
+ } else {
678
+ throw new import_core2.MusicError(import_core2.MusicErrorType.InvalidArg, `Invalid noteLength: ${noteLength}`);
679
+ }
680
+ }
681
+ var _NoteLengthProps = class _NoteLengthProps {
682
+ constructor(noteLength) {
683
+ /** Note length. */
684
+ __publicField(this, "noteLength");
685
+ /** Note size (whole=1, half=2, quarter=4, ...). */
686
+ __publicField(this, "noteSize");
687
+ /** Number of ticks (not altered by isTriplet). */
688
+ __publicField(this, "ticks");
689
+ /** Flag count. */
690
+ __publicField(this, "flagCount");
691
+ /** Dot count. */
692
+ __publicField(this, "dotCount");
693
+ /** Max dot count. */
694
+ __publicField(this, "maxDotCount");
695
+ /** Is triplet? */
696
+ __publicField(this, "isTriplet");
697
+ /** Has note stem. */
698
+ __publicField(this, "hasStem");
699
+ /** Is note head solid (black)? */
700
+ __publicField(this, "isSolid");
701
+ this.noteLength = validateNoteLength(noteLength);
702
+ this.noteSize = parseInt(noteLength);
703
+ this.isTriplet = noteLength.endsWith("t");
704
+ this.maxDotCount = this.isTriplet ? 0 : Math.floor(Math.log2(_NoteLengthProps.ShortestNoteSize / this.noteSize));
705
+ this.dotCount = import_ts_utils_lib2.Utils.Str.charCount(noteLength, ".");
706
+ this.flagCount = this.noteSize > 4 ? Math.floor(Math.log2(this.noteSize / 4)) : 0;
707
+ this.ticks = TicksMultiplier * _NoteLengthProps.ShortestNoteSize / this.noteSize;
708
+ this.hasStem = this.noteSize > 1;
709
+ this.isSolid = this.noteSize > 2;
710
+ if (this.dotCount > this.maxDotCount) {
711
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `dotCount ${this.dotCount} > maxDotCount ${this.maxDotCount}, for noteLength "${this.noteLength}".`);
712
+ } else if (this.isTriplet && this.dotCount > 0) {
713
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `noteLength "${this.noteLength}" is both triplet and dotted!`);
714
+ }
715
+ }
716
+ /**
717
+ * Get note length props.
718
+ * @param noteLength - Note length.
719
+ * @returns - Note length props.
720
+ */
721
+ static get(noteLength) {
722
+ let p = this.cache.get(noteLength);
723
+ if (!p) {
724
+ this.cache.set(noteLength, p = new _NoteLengthProps(noteLength));
725
+ }
726
+ return p;
727
+ }
728
+ /**
729
+ * Create note length props.
730
+ * @param noteLength - Note length or note size.
731
+ * @param dotCount - Dot count.
732
+ * @returns - Note length props.
733
+ */
734
+ static create(noteLength, dotCount = 0) {
735
+ let noteSize = typeof noteLength === "number" ? noteLength : this.get(noteLength).noteSize;
736
+ return this.get(noteSize + (import_ts_utils_lib2.Utils.Is.isIntegerGte(dotCount, 1) ? ".".repeat(dotCount) : "n"));
737
+ }
738
+ /**
739
+ * Compare note lengths/sizes. Whole (1) > half (2) > quarter (4), etc.
740
+ * Ignores possible triplet property of note length.
741
+ * @param a - NoteLengthProps, NoteLength/Str or noteSize
742
+ * @param b - NoteLengthProps, NoteLength/Str or noteSize
743
+ * @returns - -1: a < b, 0: a === b, +1: a > b (note length/size comparisons)
744
+ */
745
+ static cmp(a, b) {
746
+ let aNoteSize = a instanceof _NoteLengthProps ? a.noteSize : typeof a === "number" ? a : _NoteLengthProps.get(a).noteSize;
747
+ let bNoteSize = b instanceof _NoteLengthProps ? b.noteSize : typeof b === "number" ? b : _NoteLengthProps.get(b).noteSize;
748
+ return import_ts_utils_lib2.Utils.Math.cmp(bNoteSize, aNoteSize);
749
+ }
750
+ /**
751
+ * Compare note lengths/sizes for equality.
752
+ * Ignores possible triplet property of note length.
753
+ * @param a - NoteLengthProps, NoteLength/Str or noteSize
754
+ * @param b - NoteLengthProps, NoteLength/Str or noteSize
755
+ * @returns - true: a === b, false: a !== b (note length/size comparisons)
756
+ */
757
+ static equals(a, b) {
758
+ let aNoteSize = a instanceof _NoteLengthProps ? a.noteSize : typeof a === "number" ? a : _NoteLengthProps.get(a).noteSize;
759
+ let bNoteSize = b instanceof _NoteLengthProps ? b.noteSize : typeof b === "number" ? b : _NoteLengthProps.get(b).noteSize;
760
+ return aNoteSize === bNoteSize;
761
+ }
762
+ };
763
+ /** Longest note size (e.g. 1 = whole note). */
764
+ __publicField(_NoteLengthProps, "LongestNoteSize", Math.min(...import_ts_utils_lib2.Utils.Enum.getEnumValues(NoteLength).map((noteLength) => parseInt(noteLength))));
765
+ /** Shortest note size (e.g. 64 = sixtyfourth note). */
766
+ __publicField(_NoteLengthProps, "ShortestNoteSize", Math.max(...import_ts_utils_lib2.Utils.Enum.getEnumValues(NoteLength).map((noteLength) => parseInt(noteLength))));
767
+ __publicField(_NoteLengthProps, "cache", /* @__PURE__ */ new Map());
768
+ var NoteLengthProps = _NoteLengthProps;
769
+ function validateTupletRatio(tupletRatio) {
770
+ if (import_ts_utils_lib2.Utils.Is.isObject(tupletRatio) && import_ts_utils_lib2.Utils.Is.isIntegerBetween(tupletRatio.parts, 2, MaxTupletRatioValue) && import_ts_utils_lib2.Utils.Is.isIntegerBetween(tupletRatio.inTimeOf, 2, MaxTupletRatioValue)) {
771
+ return tupletRatio;
772
+ } else {
773
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Invalid tupletRatio ${JSON.stringify(tupletRatio)}`);
774
+ }
775
+ }
776
+ var Tuplet = {
777
+ /** Duplet: 2 in the time of 3 */
778
+ Duplet: { parts: 2, inTimeOf: 3 },
779
+ /** Triplet: 3 in the time of 2 */
780
+ Triplet: { parts: 3, inTimeOf: 2 },
781
+ /** Quadruplet: 4 in the time of 3 */
782
+ Quadruplet: { parts: 4, inTimeOf: 3 }
783
+ };
784
+ var _RhythmProps = class _RhythmProps {
785
+ constructor(noteLength, dotCount, tupletRatio) {
786
+ /** Note length. */
787
+ __publicField(this, "noteLength");
788
+ /** Note size (whole=1, half=2, quarter=4, ...). */
789
+ __publicField(this, "noteSize");
790
+ /** Dot count. */
791
+ __publicField(this, "dotCount");
792
+ /** Tuplet ratio. */
793
+ __publicField(this, "tupletRatio");
794
+ /** Number of ticks. */
795
+ __publicField(this, "ticks");
796
+ /** Flag count. */
797
+ __publicField(this, "flagCount");
798
+ /** Has note stem. */
799
+ __publicField(this, "hasStem");
800
+ /** Is note head solid (black)? */
801
+ __publicField(this, "isSolidNoteHead");
802
+ this.noteLength = validateNoteLength(noteLength);
803
+ let p = NoteLengthProps.get(noteLength);
804
+ this.noteSize = p.noteSize;
805
+ this.ticks = p.ticks;
806
+ this.flagCount = p.flagCount;
807
+ this.dotCount = dotCount != null ? dotCount : p.dotCount;
808
+ this.hasStem = p.hasStem;
809
+ this.isSolidNoteHead = p.isSolid;
810
+ if (import_ts_utils_lib2.Utils.Is.isObject(tupletRatio)) {
811
+ this.tupletRatio = validateTupletRatio(tupletRatio);
812
+ } else if (p.isTriplet) {
813
+ this.tupletRatio = Tuplet.Triplet;
814
+ } else {
815
+ this.tupletRatio = void 0;
816
+ }
817
+ if (this.dotCount > 0 && this.tupletRatio !== void 0) {
818
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Note cannot be both dotted and tuplet!`);
819
+ } else if (this.dotCount > p.maxDotCount) {
820
+ throw new import_core2.MusicError(import_core2.MusicErrorType.Note, `Too big dot count ${this.dotCount} for note length ${this.noteLength}.`);
821
+ }
822
+ for (let add = this.ticks / 2, i = 1; i <= this.dotCount; i++, add /= 2) {
823
+ this.ticks += add;
824
+ }
825
+ if (this.tupletRatio) {
826
+ this.ticks *= this.tupletRatio.inTimeOf / this.tupletRatio.parts;
827
+ }
828
+ }
829
+ /**
830
+ * Get string presentation of rhythm props.
831
+ * @returns - String presentation.
832
+ */
833
+ toString() {
834
+ let sym = _RhythmProps.NoteSymbolMap.get(this.noteSize);
835
+ let dots = ".".repeat(this.dotCount);
836
+ return sym ? sym + dots : "" + this.noteSize + (dots.length > 0 ? dots : "n");
837
+ }
838
+ /**
839
+ * Get rhythm props with given arguments.
840
+ * @param noteLength - Note length.
841
+ * @param dotCount - Dot count.
842
+ * @param tupletRatio - Tuplet ratio.
843
+ * @returns - Rhythm props.
844
+ */
845
+ static get(noteLength, dotCount, tupletRatio) {
846
+ if (dotCount !== void 0 || tupletRatio !== void 0) {
847
+ return new _RhythmProps(noteLength, dotCount, tupletRatio);
848
+ } else {
849
+ let rhythmProps = this.cache.get(noteLength);
850
+ if (!rhythmProps) {
851
+ this.cache.set(noteLength, rhythmProps = new _RhythmProps(noteLength));
852
+ }
853
+ return rhythmProps;
854
+ }
855
+ }
856
+ /**
857
+ * Compare duration of rhythm props.
858
+ * @param a - RhythmProps
859
+ * @param b - RhythmProps
860
+ * @returns - -1: a < b, 0: a === b, +1: a > b (duration comparisons)
861
+ */
862
+ static cmp(a, b) {
863
+ return import_ts_utils_lib2.Utils.Math.cmp(a.ticks, b.ticks);
864
+ }
865
+ /**
866
+ * Compare duration equality of rhythm props.
867
+ * @param a - RhythmProps
868
+ * @param b - RhythmProps
869
+ * @returns - true: a === b, false: a !== b (duration comparisons)
870
+ */
871
+ static equals(a, b) {
872
+ return a.ticks === b.ticks;
873
+ }
874
+ };
875
+ __publicField(_RhythmProps, "NoteSymbolMap", /* @__PURE__ */ new Map([[1, "\u{1D15D}"], [2, "\u{1D15E}"], [4, "\u{1D15F}"], [8, "\u{1D160}"], [16, "\u{1D161}"], [32, "\u{1D162}"], [64, "\u{1D163}"], [128, "\u{1D164}"]]));
876
+ __publicField(_RhythmProps, "cache", /* @__PURE__ */ new Map());
877
+ var RhythmProps = _RhythmProps;
878
+
628
879
  // src/score/engine/renderer.ts
629
880
  var HilightStaffPosRectColor = "#55cc55";
630
881
  var HilightObjectRectColor = "#55cc55";
@@ -668,7 +919,7 @@ var Renderer = class {
668
919
  __publicField(this, "onMouseLeaveFn");
669
920
  __publicField(this, "onTouchEndFn");
670
921
  this.devicePixelRatio = window.devicePixelRatio;
671
- this.fontSize = import_ts_utils_lib2.Device.FontSize * DocumentSettings.DocumentScale * this.devicePixelRatio;
922
+ this.fontSize = import_ts_utils_lib3.Device.FontSize * DocumentSettings.DocumentScale * this.devicePixelRatio;
672
923
  this.unitSize = this.fontSize * 0.3;
673
924
  this.lineWidth = this.unitSize * 0.2;
674
925
  this.beamThickness = this.unitSize * 0.8;
@@ -682,7 +933,7 @@ var Renderer = class {
682
933
  };
683
934
  img.onerror = () => {
684
935
  this.finishImageAsset(asset);
685
- throw new import_core2.MusicError(import_core2.MusicErrorType.Score, "Failed to load image: " + asset.src);
936
+ throw new import_core3.MusicError(import_core3.MusicErrorType.Score, "Failed to load image: " + asset.src);
686
937
  };
687
938
  }
688
939
  });
@@ -748,7 +999,7 @@ var Renderer = class {
748
999
  return this.scoreEventListener !== void 0;
749
1000
  }
750
1001
  getMousePos(e) {
751
- return new import_ts_utils_lib2.Vec2(e.offsetX, e.offsetY);
1002
+ return new import_ts_utils_lib3.Vec2(e.offsetX, e.offsetY);
752
1003
  }
753
1004
  updateCurStaffPos(staffPos, click) {
754
1005
  let changed = !staffPosEquals(staffPos, this.curStaffPos);
@@ -925,7 +1176,7 @@ var Renderer = class {
925
1176
  ctx.font = savedFont;
926
1177
  return metrics.width;
927
1178
  } else {
928
- return import_ts_utils_lib2.Utils.Dom.getCanvasTextWidth(text, font);
1179
+ return import_ts_utils_lib3.Utils.Dom.getCanvasTextWidth(text, font);
929
1180
  }
930
1181
  }
931
1182
  drawDebugRect(r) {
@@ -997,29 +1248,154 @@ var Renderer = class {
997
1248
  }
998
1249
  }
999
1250
  }
1000
- };
1001
-
1002
- // src/score/engine/obj-staff-and-tab.ts
1003
- var import_core16 = require("@tspro/web-music-score/core");
1004
- var import_ts_utils_lib13 = require("@tspro/ts-utils-lib");
1005
-
1006
- // src/score/engine/obj-measure.ts
1007
- var import_ts_utils_lib12 = require("@tspro/ts-utils-lib");
1008
- var import_theory9 = require("@tspro/web-music-score/theory");
1009
- var import_theory10 = require("@tspro/web-music-score/theory");
1010
-
1011
- // src/score/engine/acc-state.ts
1012
- var import_theory = require("@tspro/web-music-score/theory");
1013
- var AccidentalState = class {
1014
- constructor(measure) {
1015
- this.measure = measure;
1016
- __publicField(this, "accidentalByDiatonicId", []);
1017
- }
1018
- getAccidentalFromKeySignature(diatonicId) {
1019
- let ks = this.measure.getKeySignature();
1020
- let accNote = ks.getOrderedAccidentalNotes().find((accNote2) => accNote2.diatonicClass === import_theory.Note.getDiatonicClass(diatonicId));
1021
- return accNote ? accNote.accidental : void 0;
1022
- }
1251
+ getRestRect(restSize) {
1252
+ let { unitSize } = this;
1253
+ let { flagCount } = NoteLengthProps.get(validateNoteLength(restSize + "n"));
1254
+ let leftw = 0;
1255
+ let rightw = 0;
1256
+ let toph = 0;
1257
+ let bottomh = 0;
1258
+ if (NoteLengthProps.equals(restSize, "1n" /* Whole */)) {
1259
+ leftw = unitSize;
1260
+ rightw = unitSize;
1261
+ toph = 0;
1262
+ bottomh = unitSize;
1263
+ } else if (NoteLengthProps.equals(restSize, "2n" /* Half */)) {
1264
+ leftw = unitSize;
1265
+ rightw = unitSize;
1266
+ toph = unitSize;
1267
+ bottomh = 0;
1268
+ } else if (NoteLengthProps.equals(restSize, "4n" /* Quarter */)) {
1269
+ leftw = unitSize * 1;
1270
+ rightw = unitSize * 1;
1271
+ toph = unitSize * 3.2;
1272
+ bottomh = unitSize * 3;
1273
+ } else {
1274
+ let adj = 1 - flagCount % 2;
1275
+ leftw = unitSize * (1 + flagCount * 0.25);
1276
+ rightw = unitSize * (1 + flagCount * 0.125);
1277
+ toph = unitSize * (0.5 + flagCount - adj);
1278
+ bottomh = unitSize * (1 + flagCount + adj);
1279
+ }
1280
+ return new DivRect(-leftw, 0, rightw, -toph, 0, bottomh);
1281
+ }
1282
+ drawRest(restSize, x, y, color) {
1283
+ let ctx = this.getCanvasContext();
1284
+ if (!ctx) {
1285
+ return;
1286
+ }
1287
+ let { unitSize, lineWidth } = this;
1288
+ let { flagCount } = NoteLengthProps.get(validateNoteLength(restSize + "n"));
1289
+ ctx.strokeStyle = ctx.fillStyle = color;
1290
+ ctx.lineWidth = lineWidth;
1291
+ if (NoteLengthProps.equals(restSize, "1n" /* Whole */)) {
1292
+ ctx.fillRect(x - unitSize, y, unitSize * 2, unitSize);
1293
+ } else if (NoteLengthProps.equals(restSize, "2n" /* Half */)) {
1294
+ ctx.fillRect(x - unitSize, y - unitSize, unitSize * 2, unitSize);
1295
+ } else if (NoteLengthProps.equals(restSize, "4n" /* Quarter */)) {
1296
+ ctx.beginPath();
1297
+ ctx.moveTo(x - unitSize * 0.6, y - unitSize * 3.2);
1298
+ ctx.lineTo(x + unitSize * 0.7, y - unitSize * 1.5);
1299
+ ctx.quadraticCurveTo(
1300
+ x - unitSize * 0.8,
1301
+ y - unitSize * 0.5,
1302
+ x + unitSize * 1,
1303
+ y + unitSize * 1.5
1304
+ );
1305
+ ctx.lineTo(x - unitSize * 1, y - unitSize * 0.75);
1306
+ ctx.quadraticCurveTo(
1307
+ x + unitSize * 0.2,
1308
+ y - unitSize * 1.5,
1309
+ x - unitSize * 0.6,
1310
+ y - unitSize * 3.2
1311
+ );
1312
+ ctx.moveTo(x + unitSize * 1, y + unitSize * 1.5);
1313
+ ctx.quadraticCurveTo(
1314
+ x - unitSize * 0.8,
1315
+ y + unitSize * 1,
1316
+ x - unitSize * 0.2,
1317
+ y + unitSize * 2.8
1318
+ );
1319
+ ctx.bezierCurveTo(
1320
+ x - unitSize * 1.8,
1321
+ y + unitSize * 1.5,
1322
+ x - unitSize * 0.6,
1323
+ y - unitSize * 0.2,
1324
+ x + unitSize * 0.9,
1325
+ y + unitSize * 1.5
1326
+ );
1327
+ ctx.fill();
1328
+ ctx.stroke();
1329
+ } else if (flagCount > 0) {
1330
+ let adj = 1 - flagCount % 2;
1331
+ let fx = (p) => x + (-p * 0.25 + 0.5) * unitSize;
1332
+ let fy = (p) => y + (p + adj) * unitSize;
1333
+ ctx.beginPath();
1334
+ ctx.moveTo(fx(1 + flagCount), fy(1 + flagCount));
1335
+ ctx.lineTo(fx(-0.5 - flagCount), fy(-0.5 - flagCount));
1336
+ ctx.stroke();
1337
+ for (let i = 0; i < flagCount; i++) {
1338
+ let t = flagCount - i * 2;
1339
+ ctx.beginPath();
1340
+ ctx.moveTo(fx(t - 2.5), fy(t - 2.5));
1341
+ ctx.quadraticCurveTo(
1342
+ fx(t - 0.5) + unitSize * 0.25,
1343
+ fy(t - 1.5),
1344
+ fx(t - 1.5) - unitSize * 1.5,
1345
+ fy(t - 1.5)
1346
+ );
1347
+ ctx.stroke();
1348
+ ctx.beginPath();
1349
+ ctx.arc(fx(t - 2) - unitSize * 1.5, fy(t - 2), unitSize * 0.5, 0, Math.PI * 2);
1350
+ ctx.fill();
1351
+ }
1352
+ }
1353
+ }
1354
+ drawFlag(rect, dir) {
1355
+ let ctx = this.getCanvasContext();
1356
+ if (!ctx) {
1357
+ return;
1358
+ }
1359
+ let left = rect.left;
1360
+ let right = rect.right;
1361
+ let width = right - left;
1362
+ let top = dir === "up" ? rect.top : rect.bottom;
1363
+ let bottom = dir === "up" ? rect.bottom : rect.top;
1364
+ ctx.beginPath();
1365
+ ctx.moveTo(left, top);
1366
+ ctx.bezierCurveTo(
1367
+ left,
1368
+ top * 0.75 + bottom * 0.25,
1369
+ left + width * 1.5,
1370
+ top * 0.5 + bottom * 0.5,
1371
+ left + width * 0.5,
1372
+ bottom
1373
+ );
1374
+ ctx.stroke();
1375
+ }
1376
+ };
1377
+
1378
+ // src/score/engine/obj-staff-and-tab.ts
1379
+ var import_core16 = require("@tspro/web-music-score/core");
1380
+ var import_ts_utils_lib14 = require("@tspro/ts-utils-lib");
1381
+
1382
+ // src/score/engine/obj-measure.ts
1383
+ var import_ts_utils_lib13 = require("@tspro/ts-utils-lib");
1384
+ var import_theory9 = require("@tspro/web-music-score/theory");
1385
+ var import_theory10 = require("@tspro/web-music-score/theory");
1386
+
1387
+ // src/score/engine/acc-state.ts
1388
+ var import_theory = require("@tspro/web-music-score/theory");
1389
+ var AccidentalState = class {
1390
+ constructor(measure) {
1391
+ this.measure = measure;
1392
+ __publicField(this, "accidentalByDiatonicId", []);
1393
+ }
1394
+ getAccidentalFromKeySignature(diatonicId) {
1395
+ let ks = this.measure.getKeySignature();
1396
+ let accNote = ks.getOrderedAccidentalNotes().find((accNote2) => accNote2.diatonicClass === import_theory.Note.getDiatonicClass(diatonicId));
1397
+ return accNote ? accNote.accidental : void 0;
1398
+ }
1023
1399
  setAccidental(note) {
1024
1400
  this.accidentalByDiatonicId[note.diatonicId] = note.accidental;
1025
1401
  }
@@ -1079,7 +1455,7 @@ var ObjImage = class extends MusicObject {
1079
1455
  };
1080
1456
 
1081
1457
  // src/score/engine/obj-accidental.ts
1082
- var import_core3 = require("@tspro/web-music-score/core");
1458
+ var import_core4 = require("@tspro/web-music-score/core");
1083
1459
  var ObjAccidental = class extends MusicObject {
1084
1460
  constructor(parent, diatonicId, accidental, color = "black") {
1085
1461
  super(parent);
@@ -1114,7 +1490,7 @@ var ObjAccidental = class extends MusicObject {
1114
1490
  this.rect = DivRect.createSections(unitSize * 1, unitSize * 1, unitSize * 1, unitSize * 1);
1115
1491
  break;
1116
1492
  default:
1117
- throw new import_core3.MusicError(import_core3.MusicErrorType.Score, "Invalid accidental value: " + this.accidental);
1493
+ throw new import_core4.MusicError(import_core4.MusicErrorType.Score, "Invalid accidental value: " + this.accidental);
1118
1494
  }
1119
1495
  }
1120
1496
  offset(dx, dy) {
@@ -1327,8 +1703,8 @@ var ObjText = class extends MusicObject {
1327
1703
  };
1328
1704
 
1329
1705
  // src/score/engine/obj-signature.ts
1330
- var import_core4 = require("@tspro/web-music-score/core");
1331
- var ObjSignature = class extends MusicObject {
1706
+ var import_core5 = require("@tspro/web-music-score/core");
1707
+ var ObjStaffSignature = class extends MusicObject {
1332
1708
  constructor(measure, staff) {
1333
1709
  super(measure);
1334
1710
  this.measure = measure;
@@ -1342,7 +1718,7 @@ var ObjSignature = class extends MusicObject {
1342
1718
  __publicField(this, "beatSizeText");
1343
1719
  __publicField(this, "tempoText");
1344
1720
  __publicField(this, "mi");
1345
- this.mi = new MSignature(this);
1721
+ this.mi = new MStaffSignature(this);
1346
1722
  }
1347
1723
  getMusicInterface() {
1348
1724
  return this.mi;
@@ -1423,7 +1799,7 @@ var ObjSignature = class extends MusicObject {
1423
1799
  if (bottomAccidentalDiatonicId !== void 0) {
1424
1800
  return import_theory2.Note.findNextDiatonicIdAbove(accNote.diatonicId, bottomAccidentalDiatonicId, false);
1425
1801
  } else {
1426
- throw new import_core4.MusicError(import_core4.MusicErrorType.Score, "Cannot get accidental diatonicId because note has no accidental.");
1802
+ throw new import_core5.MusicError(import_core5.MusicErrorType.Score, "Cannot get accidental diatonicId because note has no accidental.");
1427
1803
  }
1428
1804
  }
1429
1805
  pick(x, y) {
@@ -1541,66 +1917,169 @@ var ObjSignature = class extends MusicObject {
1541
1917
  }
1542
1918
  x = right;
1543
1919
  if (this.tempoText) {
1920
+ let tempoBottom = Math.min(
1921
+ this.clefImage ? this.clefImage.getRect().top : staff.getTopLineY(),
1922
+ ...this.ksNeutralizeAccidentals.map((o) => o.getRect().top),
1923
+ ...this.ksNewAccidentals.map((o) => o.getRect().top)
1924
+ );
1544
1925
  this.tempoText.layout(renderer);
1545
- this.tempoText.offset(x, Math.min(this.rect.top, staff.getTopLineY()));
1926
+ this.tempoText.offset(x, tempoBottom);
1546
1927
  this.rect.expandInPlace(this.tempoText.getRect());
1547
1928
  }
1548
1929
  this.rect.right += paddingX;
1549
1930
  }
1550
1931
  offset(dx, dy) {
1551
- if (this.clefImage) {
1552
- this.clefImage.offset(dx, dy);
1932
+ var _a, _b, _c, _d, _e, _f;
1933
+ (_a = this.clefImage) == null ? void 0 : _a.offset(dx, dy);
1934
+ (_b = this.eightBelowClef) == null ? void 0 : _b.offset(dx, dy);
1935
+ (_c = this.measureNumber) == null ? void 0 : _c.offset(dx, dy);
1936
+ this.ksNeutralizeAccidentals.forEach((acc) => acc.offset(dx, dy));
1937
+ this.ksNewAccidentals.forEach((acc) => acc.offset(dx, dy));
1938
+ (_d = this.beatCountText) == null ? void 0 : _d.offset(dx, dy);
1939
+ (_e = this.beatSizeText) == null ? void 0 : _e.offset(dx, dy);
1940
+ (_f = this.tempoText) == null ? void 0 : _f.offset(dx, dy);
1941
+ this.rect.offsetInPlace(dx, dy);
1942
+ }
1943
+ draw(renderer) {
1944
+ var _a, _b, _c, _d, _e, _f;
1945
+ (_a = this.clefImage) == null ? void 0 : _a.draw(renderer);
1946
+ (_b = this.eightBelowClef) == null ? void 0 : _b.draw(renderer);
1947
+ (_c = this.measureNumber) == null ? void 0 : _c.draw(renderer);
1948
+ this.ksNeutralizeAccidentals.forEach((acc) => acc.draw(renderer));
1949
+ this.ksNewAccidentals.forEach((acc) => acc.draw(renderer));
1950
+ (_d = this.beatCountText) == null ? void 0 : _d.draw(renderer);
1951
+ (_e = this.beatSizeText) == null ? void 0 : _e.draw(renderer);
1952
+ (_f = this.tempoText) == null ? void 0 : _f.draw(renderer);
1953
+ }
1954
+ };
1955
+ var ObjTabSignature = class extends MusicObject {
1956
+ constructor(measure, tab) {
1957
+ super(measure);
1958
+ this.measure = measure;
1959
+ this.tab = tab;
1960
+ __publicField(this, "measureNumber");
1961
+ __publicField(this, "beatCountText");
1962
+ __publicField(this, "beatSizeText");
1963
+ __publicField(this, "tempoText");
1964
+ __publicField(this, "mi");
1965
+ this.mi = new MTabSignature(this);
1966
+ }
1967
+ getMusicInterface() {
1968
+ return this.mi;
1969
+ }
1970
+ updateMeasureNumber(showMeasureNumber) {
1971
+ if (showMeasureNumber) {
1972
+ let text = this.measure.getMeasureNumber().toString();
1973
+ this.measureNumber = new ObjText(this, text, 0, 1);
1974
+ } else {
1975
+ this.measureNumber = void 0;
1553
1976
  }
1554
- if (this.eightBelowClef) {
1555
- this.eightBelowClef.offset(dx, dy);
1977
+ }
1978
+ updateTimeSignature(showTimeSignature) {
1979
+ if (showTimeSignature) {
1980
+ let timeSignature = this.measure.getTimeSignature();
1981
+ let beatCount = timeSignature.beatCount.toString();
1982
+ this.beatCountText = new ObjText(this, { text: beatCount, scale: 1.4 }, 0.5, 0.5);
1983
+ let beatSize = timeSignature.beatSize.toString();
1984
+ this.beatSizeText = new ObjText(this, { text: beatSize, scale: 1.4 }, 0.5, 0.5);
1985
+ } else {
1986
+ this.beatCountText = this.beatSizeText = void 0;
1556
1987
  }
1557
- if (this.measureNumber) {
1558
- this.measureNumber.offset(dx, dy);
1988
+ }
1989
+ updateTempo(showTempo) {
1990
+ if (showTempo) {
1991
+ let tempoStr = (0, import_theory2.getTempoString)(this.measure.getTempo());
1992
+ this.tempoText = new ObjText(this, tempoStr, 0, 1);
1993
+ } else {
1994
+ this.tempoText = void 0;
1995
+ }
1996
+ }
1997
+ pick(x, y) {
1998
+ if (!this.rect.contains(x, y)) {
1999
+ return [];
1559
2000
  }
1560
- this.ksNeutralizeAccidentals.forEach((acc) => acc.offset(dx, dy));
1561
- this.ksNewAccidentals.forEach((acc) => acc.offset(dx, dy));
1562
2001
  if (this.beatCountText) {
1563
- this.beatCountText.offset(dx, dy);
2002
+ let arr = this.beatCountText.pick(x, y);
2003
+ if (arr.length > 0) {
2004
+ return [this, ...arr];
2005
+ }
1564
2006
  }
1565
2007
  if (this.beatSizeText) {
1566
- this.beatSizeText.offset(dx, dy);
2008
+ let arr = this.beatSizeText.pick(x, y);
2009
+ if (arr.length > 0) {
2010
+ return [this, ...arr];
2011
+ }
1567
2012
  }
1568
2013
  if (this.tempoText) {
1569
- this.tempoText.offset(dx, dy);
1570
- }
1571
- this.rect.offsetInPlace(dx, dy);
1572
- }
1573
- draw(renderer) {
1574
- if (this.clefImage) {
1575
- this.clefImage.draw(renderer);
2014
+ let arr = this.tempoText.pick(x, y);
2015
+ if (arr.length > 0) {
2016
+ return [this, ...arr];
2017
+ }
1576
2018
  }
1577
- if (this.eightBelowClef) {
1578
- this.eightBelowClef.draw(renderer);
2019
+ if (this.measureNumber) {
2020
+ let arr = this.measureNumber.pick(x, y);
2021
+ if (arr.length > 0) {
2022
+ return [this, ...arr];
2023
+ }
1579
2024
  }
2025
+ return [this];
2026
+ }
2027
+ layout(renderer) {
2028
+ var _a, _b, _c, _d, _e, _f;
2029
+ let { unitSize } = renderer;
2030
+ let { tab } = this;
2031
+ let paddingX = unitSize;
2032
+ let x = 0;
2033
+ let topLineY = tab.getTopLineY();
2034
+ this.rect = new DivRect();
1580
2035
  if (this.measureNumber) {
1581
- this.measureNumber.draw(renderer);
2036
+ this.measureNumber.layout(renderer);
2037
+ this.measureNumber.offset(0, topLineY);
2038
+ this.rect.expandInPlace(this.measureNumber.getRect());
2039
+ x = Math.max(x, this.rect.right);
1582
2040
  }
1583
- this.ksNeutralizeAccidentals.forEach((acc) => acc.draw(renderer));
1584
- this.ksNewAccidentals.forEach((acc) => acc.draw(renderer));
2041
+ (_a = this.beatCountText) == null ? void 0 : _a.layout(renderer);
2042
+ (_b = this.beatSizeText) == null ? void 0 : _b.layout(renderer);
2043
+ 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);
1585
2044
  if (this.beatCountText) {
1586
- this.beatCountText.draw(renderer);
2045
+ this.beatCountText.offset(0 + tsWidth / 2 + paddingX, tab.getRect().centerY - this.beatCountText.getRect().bottomh);
2046
+ this.rect.expandInPlace(this.beatCountText.getRect());
1587
2047
  }
1588
2048
  if (this.beatSizeText) {
1589
- this.beatSizeText.draw(renderer);
2049
+ this.beatSizeText.offset(0 + tsWidth / 2 + paddingX, tab.getRect().centerY + this.beatSizeText.getRect().toph);
2050
+ this.rect.expandInPlace(this.beatSizeText.getRect());
1590
2051
  }
1591
2052
  if (this.tempoText) {
1592
- this.tempoText.draw(renderer);
2053
+ this.tempoText.layout(renderer);
2054
+ this.tempoText.offset(x + unitSize * 2, topLineY);
2055
+ this.rect.expandInPlace(this.tempoText.getRect());
1593
2056
  }
2057
+ this.rect.right += paddingX;
2058
+ }
2059
+ offset(dx, dy) {
2060
+ var _a, _b, _c, _d;
2061
+ (_a = this.measureNumber) == null ? void 0 : _a.offset(dx, dy);
2062
+ (_b = this.beatCountText) == null ? void 0 : _b.offset(dx, dy);
2063
+ (_c = this.beatSizeText) == null ? void 0 : _c.offset(dx, dy);
2064
+ (_d = this.tempoText) == null ? void 0 : _d.offset(dx, dy);
2065
+ this.rect.offsetInPlace(dx, dy);
2066
+ }
2067
+ draw(renderer) {
2068
+ var _a, _b, _c, _d;
2069
+ (_a = this.measureNumber) == null ? void 0 : _a.draw(renderer);
2070
+ (_b = this.beatCountText) == null ? void 0 : _b.draw(renderer);
2071
+ (_c = this.beatSizeText) == null ? void 0 : _c.draw(renderer);
2072
+ (_d = this.tempoText) == null ? void 0 : _d.draw(renderer);
1594
2073
  }
1595
2074
  };
1596
2075
 
1597
2076
  // src/score/engine/player.ts
1598
- var import_ts_utils_lib8 = require("@tspro/ts-utils-lib");
1599
- var import_theory7 = require("@tspro/web-music-score/theory");
2077
+ var import_ts_utils_lib7 = require("@tspro/ts-utils-lib");
2078
+ var import_theory6 = require("@tspro/web-music-score/theory");
1600
2079
  var Audio = __toESM(require("@tspro/web-music-score/audio"));
1601
2080
 
1602
2081
  // src/score/engine/obj-rhythm-column.ts
1603
- var import_theory6 = require("@tspro/web-music-score/theory");
2082
+ var import_theory5 = require("@tspro/web-music-score/theory");
1604
2083
 
1605
2084
  // src/score/engine/obj-arpeggio.ts
1606
2085
  var ObjArpeggio = class extends MusicObject {
@@ -1674,7 +2153,7 @@ var ObjArpeggio = class extends MusicObject {
1674
2153
 
1675
2154
  // src/score/engine/obj-rest.ts
1676
2155
  var import_theory3 = require("@tspro/web-music-score/theory");
1677
- var import_core5 = require("@tspro/web-music-score/core");
2156
+ var import_core6 = require("@tspro/web-music-score/core");
1678
2157
  function getDiatonicIdFromStaffPos(staffPos) {
1679
2158
  if (typeof staffPos === "number") {
1680
2159
  return import_theory3.Note.getChromaticNote(staffPos).diatonicId;
@@ -1734,7 +2213,7 @@ var ObjRest = class extends MusicObject {
1734
2213
  let hasStaff = this.row.hasStaff;
1735
2214
  let staff2 = this.row.getStaff(diatonicId);
1736
2215
  if (hasStaff && !staff2) {
1737
- throw new import_core5.MusicError(import_core5.MusicErrorType.Score, "Rest staffPos is out of staff boundaries!");
2216
+ throw new import_core6.MusicError(import_core6.MusicErrorType.Score, "Rest staffPos is out of staff boundaries!");
1738
2217
  }
1739
2218
  }
1740
2219
  this.ownDiatonicId = this.measure.updateOwnDiatonicId(voiceId, diatonicId);
@@ -1810,6 +2289,9 @@ var ObjRest = class extends MusicObject {
1810
2289
  return { staff, x, y, stemHeight };
1811
2290
  });
1812
2291
  }
2292
+ hasTuplet() {
2293
+ return this.rhythmProps.tupletRatio !== void 0;
2294
+ }
1813
2295
  isEmpty() {
1814
2296
  return this.staffObjects.length === 0;
1815
2297
  }
@@ -1833,7 +2315,7 @@ var ObjRest = class extends MusicObject {
1833
2315
  case 64:
1834
2316
  return -3;
1835
2317
  default:
1836
- throw new import_core5.MusicError(import_core5.MusicErrorType.Score, `Get rest dot vertical displacement: Invalid note size: ${noteSize}`);
2318
+ throw new import_core6.MusicError(import_core6.MusicErrorType.Score, `Get rest dot vertical displacement: Invalid note size: ${noteSize}`);
1837
2319
  }
1838
2320
  }
1839
2321
  updateAccidentalState(accState) {
@@ -1846,42 +2328,16 @@ var ObjRest = class extends MusicObject {
1846
2328
  }
1847
2329
  let { unitSize } = renderer;
1848
2330
  let { ownDiatonicId } = this;
1849
- let { noteSize, dotCount, flagCount } = this.rhythmProps;
1850
- let leftw = 0;
1851
- let rightw = 0;
1852
- let toph = 0;
1853
- let bottomh = 0;
1854
- if (import_theory3.NoteLengthProps.equals(noteSize, import_theory3.NoteLength.Whole)) {
1855
- leftw = unitSize;
1856
- rightw = unitSize;
1857
- toph = 0;
1858
- bottomh = unitSize;
1859
- } else if (import_theory3.NoteLengthProps.equals(noteSize, import_theory3.NoteLength.Half)) {
1860
- leftw = unitSize;
1861
- rightw = unitSize;
1862
- toph = unitSize;
1863
- bottomh = 0;
1864
- } else if (import_theory3.NoteLengthProps.equals(noteSize, import_theory3.NoteLength.Quarter)) {
1865
- leftw = unitSize * 1;
1866
- rightw = unitSize * 1;
1867
- toph = unitSize * 3.2;
1868
- bottomh = unitSize * 3;
1869
- } else {
1870
- let adj = 1 - flagCount % 2;
1871
- leftw = unitSize * (1 + flagCount * 0.25);
1872
- rightw = unitSize * (1 + flagCount * 0.125);
1873
- toph = unitSize * (0.5 + flagCount - adj);
1874
- bottomh = unitSize * (1 + flagCount + adj);
1875
- }
2331
+ let { noteSize, dotCount } = this.rhythmProps;
1876
2332
  this.row.getStaves().forEach((staff) => {
1877
2333
  if (!staff.containsDiatonicId(ownDiatonicId) || !staff.containsVoiceId(this.voiceId)) {
1878
2334
  return;
1879
2335
  }
1880
2336
  let obj = new ObjStaffRest(staff, this);
1881
- obj.restRect = new DivRect(-leftw, 0, rightw, -toph, 0, bottomh);
2337
+ obj.restRect = renderer.getRestRect(noteSize);
1882
2338
  for (let i = 0; i < dotCount; i++) {
1883
2339
  let dotWidth = DocumentSettings.DotSize * unitSize;
1884
- let dotX = rightw + (DocumentSettings.RestDotSpace + DocumentSettings.DotSize * unitSize) + i * DocumentSettings.DotSize * unitSize * 1.5;
2340
+ let dotX = obj.restRect.rightw + (DocumentSettings.RestDotSpace + DocumentSettings.DotSize * unitSize) + i * DocumentSettings.DotSize * unitSize * 1.5;
1885
2341
  let dotY = this.getRestDotVerticalDisplacement(noteSize) * unitSize;
1886
2342
  obj.dotRects.push(DivRect.createCentered(dotX, dotY, dotWidth, dotWidth));
1887
2343
  }
@@ -1911,77 +2367,16 @@ var ObjRest = class extends MusicObject {
1911
2367
  return;
1912
2368
  }
1913
2369
  renderer.drawDebugRect(this.getRect());
1914
- let { unitSize, lineWidth } = renderer;
2370
+ let { lineWidth } = renderer;
1915
2371
  let { color } = this;
1916
- let { noteSize, flagCount } = this.rhythmProps;
2372
+ let { noteSize } = this.rhythmProps;
1917
2373
  ctx.strokeStyle = ctx.fillStyle = color;
1918
2374
  ctx.lineWidth = lineWidth;
1919
2375
  this.staffObjects.forEach((obj) => {
1920
2376
  let { dotRects, restRect } = obj;
1921
2377
  let x = restRect.centerX;
1922
2378
  let y = restRect.centerY;
1923
- if (import_theory3.NoteLengthProps.equals(noteSize, import_theory3.NoteLength.Whole)) {
1924
- ctx.fillRect(x - unitSize, y, unitSize * 2, unitSize);
1925
- } else if (import_theory3.NoteLengthProps.equals(noteSize, import_theory3.NoteLength.Half)) {
1926
- ctx.fillRect(x - unitSize, y - unitSize, unitSize * 2, unitSize);
1927
- } else if (import_theory3.NoteLengthProps.equals(noteSize, import_theory3.NoteLength.Quarter)) {
1928
- ctx.beginPath();
1929
- ctx.moveTo(x - unitSize * 0.6, y - unitSize * 3.2);
1930
- ctx.lineTo(x + unitSize * 0.7, y - unitSize * 1.5);
1931
- ctx.quadraticCurveTo(
1932
- x - unitSize * 0.8,
1933
- y - unitSize * 0.5,
1934
- x + unitSize * 1,
1935
- y + unitSize * 1.5
1936
- );
1937
- ctx.lineTo(x - unitSize * 1, y - unitSize * 0.75);
1938
- ctx.quadraticCurveTo(
1939
- x + unitSize * 0.2,
1940
- y - unitSize * 1.5,
1941
- x - unitSize * 0.6,
1942
- y - unitSize * 3.2
1943
- );
1944
- ctx.moveTo(x + unitSize * 1, y + unitSize * 1.5);
1945
- ctx.quadraticCurveTo(
1946
- x - unitSize * 0.8,
1947
- y + unitSize * 1,
1948
- x - unitSize * 0.2,
1949
- y + unitSize * 2.8
1950
- );
1951
- ctx.bezierCurveTo(
1952
- x - unitSize * 1.8,
1953
- y + unitSize * 1.5,
1954
- x - unitSize * 0.6,
1955
- y - unitSize * 0.2,
1956
- x + unitSize * 0.9,
1957
- y + unitSize * 1.5
1958
- );
1959
- ctx.fill();
1960
- ctx.stroke();
1961
- } else if (flagCount > 0) {
1962
- let adj = 1 - flagCount % 2;
1963
- let fx = (p) => x + (-p * 0.25 + 0.5) * unitSize;
1964
- let fy = (p) => y + (p + adj) * unitSize;
1965
- ctx.beginPath();
1966
- ctx.moveTo(fx(1 + flagCount), fy(1 + flagCount));
1967
- ctx.lineTo(fx(-0.5 - flagCount), fy(-0.5 - flagCount));
1968
- ctx.stroke();
1969
- for (let i = 0; i < flagCount; i++) {
1970
- let t = flagCount - i * 2;
1971
- ctx.beginPath();
1972
- ctx.moveTo(fx(t - 2.5), fy(t - 2.5));
1973
- ctx.quadraticCurveTo(
1974
- fx(t - 0.5) + unitSize * 0.25,
1975
- fy(t - 1.5),
1976
- fx(t - 1.5) - unitSize * 1.5,
1977
- fy(t - 1.5)
1978
- );
1979
- ctx.stroke();
1980
- ctx.beginPath();
1981
- ctx.arc(fx(t - 2) - unitSize * 1.5, fy(t - 2), unitSize * 0.5, 0, Math.PI * 2);
1982
- ctx.fill();
1983
- }
1984
- }
2379
+ renderer.drawRest(noteSize, x, y, color);
1985
2380
  dotRects.forEach((r) => {
1986
2381
  renderer.fillCircle(r.centerX, r.centerY, r.width / 2);
1987
2382
  });
@@ -1991,53 +2386,96 @@ var ObjRest = class extends MusicObject {
1991
2386
 
1992
2387
  // src/score/engine/obj-note-group.ts
1993
2388
  var import_ts_utils_lib4 = require("@tspro/ts-utils-lib");
1994
- var import_theory5 = require("@tspro/web-music-score/theory");
1995
-
1996
- // src/score/engine/obj-beam-group.ts
1997
- var import_ts_utils_lib3 = require("@tspro/ts-utils-lib");
1998
2389
  var import_theory4 = require("@tspro/web-music-score/theory");
1999
- var import_core6 = require("@tspro/web-music-score/core");
2000
- var adjustBeamAngle = (dx, dy) => {
2001
- let T = DocumentSettings.BeamAngleFactor;
2002
- if (!Number.isFinite(T) || T === 0) {
2003
- return dy;
2004
- } else {
2005
- let k = dx / dy / T;
2006
- k = Math.sign(k) * Math.sqrt(Math.abs(k));
2007
- return dx / k * T;
2008
- }
2009
- };
2010
- var BeamPoint = class {
2011
- constructor(staff, beamGroup, symbol, x, y) {
2390
+ var import_core7 = require("@tspro/web-music-score/core");
2391
+ function getStem(stem) {
2392
+ return import_ts_utils_lib4.Utils.Is.isEnumValue(stem, Stem) ? stem : void 0;
2393
+ }
2394
+ function getArpeggio(a) {
2395
+ return import_ts_utils_lib4.Utils.Is.isEnumValue(a, Arpeggio) ? a : a === true ? "up" /* Up */ : void 0;
2396
+ }
2397
+ function sortNoteStringData(notes, strings) {
2398
+ let stringArr = import_ts_utils_lib4.Utils.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2399
+ let noteStringData = notes.map((note, i) => {
2400
+ return { note, string: stringArr[i] };
2401
+ });
2402
+ noteStringData = import_ts_utils_lib4.Utils.Arr.removeDuplicatesCmp(noteStringData, (a, b) => import_theory4.Note.equals(a.note, b.note)).sort((a, b) => import_theory4.Note.compareFunc(a.note, b.note));
2403
+ return {
2404
+ notes: noteStringData.map((e) => e.note),
2405
+ strings: noteStringData.every((e) => e.string === void 0) ? void 0 : noteStringData.map((e) => e.string)
2406
+ };
2407
+ }
2408
+ var ObjStaffNoteGroup = class extends MusicObject {
2409
+ constructor(staff, noteGroup) {
2410
+ super(staff);
2012
2411
  this.staff = staff;
2013
- this.beamGroup = beamGroup;
2014
- this.symbol = symbol;
2015
- this.x = x;
2016
- this.y = y;
2017
- __publicField(this, "topBeamsHeight", 0);
2018
- __publicField(this, "bottomBeamsHeight", 0);
2019
- staff.addObject(this);
2412
+ this.noteGroup = noteGroup;
2413
+ __publicField(this, "noteHeadRects", []);
2414
+ __publicField(this, "dotRects", []);
2415
+ __publicField(this, "accidentals", []);
2416
+ __publicField(this, "stemTip");
2417
+ __publicField(this, "stemBase");
2418
+ __publicField(this, "flagRects", []);
2419
+ __publicField(this, "prevTopNoteY", 0);
2420
+ __publicField(this, "prevBottomNoteY", 0);
2421
+ __publicField(this, "mi");
2422
+ this.mi = new MStaffNoteGroup(this);
2020
2423
  }
2021
- offset(dx, dy) {
2022
- this.x += dx;
2023
- this.y += dy;
2024
- this.beamGroup.requestRectUpdate();
2424
+ getMusicInterface() {
2425
+ return this.mi;
2426
+ }
2427
+ pick(x, y) {
2428
+ if (!this.getRect().contains(x, y)) {
2429
+ return [];
2430
+ }
2431
+ for (let i = 0; i < this.accidentals.length; i++) {
2432
+ let arr = this.accidentals[i].pick(x, y);
2433
+ if (arr.length > 0) {
2434
+ return [this, ...arr];
2435
+ }
2436
+ }
2437
+ return [this];
2438
+ }
2439
+ updateRect() {
2440
+ this.rect = this.noteHeadRects[0].copy();
2441
+ this.noteHeadRects.forEach((r) => this.rect.expandInPlace(r));
2442
+ if (this.stemTip) this.rect.expandInPlace(this.stemTip);
2443
+ if (this.stemBase) this.rect.expandInPlace(this.stemBase);
2444
+ this.dotRects.forEach((r) => this.rect.expandInPlace(r));
2445
+ this.flagRects.forEach((r) => this.rect.expandInPlace(r));
2446
+ this.accidentals.forEach((a) => this.rect.expandInPlace(a.getRect()));
2025
2447
  }
2026
2448
  getRect() {
2027
- return new DivRect(this.x, this.x, this.x, this.y - this.topBeamsHeight, this.y, this.y + this.bottomBeamsHeight);
2449
+ let bottomNoteRect = this.noteHeadRects[0];
2450
+ let topNoteRect = this.noteHeadRects[this.noteHeadRects.length - 1];
2451
+ if (this.prevTopNoteY !== topNoteRect.centerY || this.prevBottomNoteY !== bottomNoteRect.centerY) {
2452
+ this.prevTopNoteY = topNoteRect.centerY;
2453
+ this.prevBottomNoteY = bottomNoteRect.centerY;
2454
+ this.requestRectUpdate();
2455
+ }
2456
+ return super.getRect();
2457
+ }
2458
+ offset(dx, dy) {
2459
+ var _a, _b;
2460
+ this.noteHeadRects.forEach((n) => n.offsetInPlace(dx, dy));
2461
+ this.dotRects.forEach((n) => n.offsetInPlace(dx, dy));
2462
+ this.accidentals.forEach((n) => n.offset(dx, dy));
2463
+ (_a = this.stemTip) == null ? void 0 : _a.offsetInPlace(dx, dy);
2464
+ (_b = this.stemBase) == null ? void 0 : _b.offsetInPlace(dx, dy);
2465
+ this.flagRects.forEach((n) => n.offsetInPlace(dx, dy));
2466
+ this.requestRectUpdate();
2467
+ this.noteGroup.requestRectUpdate();
2028
2468
  }
2029
2469
  };
2030
- var ObjStaffBeamGroup = class extends MusicObject {
2031
- constructor(staff, beamGroup) {
2032
- super(staff);
2033
- this.staff = staff;
2034
- this.beamGroup = beamGroup;
2035
- __publicField(this, "tupletNumber");
2036
- __publicField(this, "tupletNumberOffsetY", 0);
2037
- __publicField(this, "points", []);
2470
+ var ObjTabNoteGroup = class extends MusicObject {
2471
+ constructor(tab, noteGroup) {
2472
+ super(tab);
2473
+ this.tab = tab;
2474
+ this.noteGroup = noteGroup;
2475
+ __publicField(this, "fretNumbers", []);
2038
2476
  __publicField(this, "mi");
2039
- staff.addObject(this);
2040
- this.mi = new MStaffBeamGroup(this);
2477
+ tab.addObject(this);
2478
+ this.mi = new MTabNoteGroup(this);
2041
2479
  }
2042
2480
  getMusicInterface() {
2043
2481
  return this.mi;
@@ -2045,95 +2483,102 @@ var ObjStaffBeamGroup = class extends MusicObject {
2045
2483
  pick(x, y) {
2046
2484
  return this.getRect().contains(x, y) ? [this] : [];
2047
2485
  }
2486
+ updateRect() {
2487
+ this.rect = this.fretNumbers[0].getRect().copy();
2488
+ this.fretNumbers.forEach((fn) => this.rect.expandInPlace(fn.getRect()));
2489
+ }
2048
2490
  offset(dx, dy) {
2049
- var _a;
2050
- this.points.forEach((p) => p.offset(dx, 0));
2051
- (_a = this.tupletNumber) == null ? void 0 : _a.offset(dx, dy);
2491
+ this.fretNumbers.forEach((f) => f.offset(dx, dy));
2052
2492
  this.requestRectUpdate();
2053
- this.beamGroup.requestRectUpdate();
2054
- }
2055
- updateRect() {
2056
- if (this.points.length > 0) {
2057
- this.rect = this.points[0].getRect().copy();
2058
- } else if (this.tupletNumber) {
2059
- this.rect = this.tupletNumber.getRect().copy();
2060
- }
2061
- this.points.forEach((pt) => this.rect.expandInPlace(pt.getRect()));
2062
- if (this.tupletNumber) {
2063
- this.rect.expandInPlace(this.tupletNumber.getRect());
2064
- }
2493
+ this.noteGroup.requestRectUpdate();
2065
2494
  }
2066
2495
  };
2067
- var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2068
- constructor(symbols, tupletRatio) {
2069
- super(symbols[0].measure);
2070
- this.symbols = symbols;
2071
- this.tupletRatio = tupletRatio;
2072
- __publicField(this, "mi");
2073
- __publicField(this, "type");
2496
+ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2497
+ constructor(col, voiceId, notes, noteLength, options, tupletRatio) {
2498
+ var _a, _b, _c;
2499
+ super(col);
2500
+ this.col = col;
2501
+ this.voiceId = voiceId;
2502
+ this.notes = notes;
2503
+ __publicField(this, "minDiatonicId");
2504
+ __publicField(this, "maxDiatonicId");
2505
+ __publicField(this, "ownDiatonicId");
2506
+ // Average diatonicId of notes.
2507
+ __publicField(this, "ownStemDir");
2508
+ __publicField(this, "ownString");
2509
+ __publicField(this, "color");
2510
+ __publicField(this, "staccato");
2511
+ __publicField(this, "diamond");
2512
+ __publicField(this, "arpeggio");
2513
+ __publicField(this, "oldStyleTriplet");
2514
+ __publicField(this, "rhythmProps");
2515
+ __publicField(this, "startConnnectives", []);
2516
+ __publicField(this, "runningConnectives", []);
2517
+ __publicField(this, "leftBeamCount", 0);
2518
+ __publicField(this, "rightBeamCount", 0);
2519
+ __publicField(this, "beamGroup");
2074
2520
  __publicField(this, "staffObjects", []);
2075
- this.mi = new MBeamGroup(this);
2076
- let beamGroupName = tupletRatio ? "Tuplet" : "BeamGroup";
2077
- if (!symbols.every((s) => s.measure === symbols[0].measure)) {
2078
- throw new import_core6.MusicError(import_core6.MusicErrorType.Score, `All ${beamGroupName} symbols are not in same measure.`);
2079
- } else if (symbols.length < 2) {
2080
- throw new import_core6.MusicError(import_core6.MusicErrorType.Score, `${beamGroupName} needs minimum 2 symbols, but ${symbols.length} given.`);
2081
- }
2082
- if (tupletRatio !== void 0) {
2083
- let isGroup = symbols.length < 3 || symbols.some((s) => !(s instanceof ObjNoteGroup)) || symbols.some((s) => s.rhythmProps.flagCount !== symbols[0].rhythmProps.flagCount);
2084
- if (symbols.length >= 3 && symbols[0] instanceof ObjNoteGroup && symbols[symbols.length - 1] instanceof ObjNoteGroup && symbols[0].rhythmProps.flagCount === symbols[symbols.length - 1].rhythmProps.flagCount) {
2085
- isGroup = false;
2086
- }
2087
- if (symbols.some((s) => import_theory4.NoteLengthProps.cmp(s.rhythmProps.noteLength, import_theory4.NoteLength.Quarter) >= 0)) {
2088
- isGroup = true;
2089
- }
2090
- this.type = isGroup ? 2 /* TupletGroup */ : 1 /* TupletBeam */;
2091
- ObjNoteGroup.setTupletBeamCounts(this);
2092
- } else {
2093
- this.type = 0 /* RegularBeam */;
2094
- }
2095
- if (symbols.every((s) => s.getBeamGroup() === void 0)) {
2096
- symbols.forEach((s) => s.setBeamGroup(this));
2097
- symbols[0].measure.addBeamGroup(this);
2098
- } else {
2099
- throw new import_core6.MusicError(import_core6.MusicErrorType.Score, `Cannot add ${beamGroupName} because some symbol already has one.`);
2521
+ __publicField(this, "tabObjects", []);
2522
+ __publicField(this, "mi");
2523
+ if (!import_ts_utils_lib4.Utils.Is.isIntegerGte(notes.length, 1)) {
2524
+ throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Cannot create note group object because notes array is empty.");
2100
2525
  }
2526
+ let noteStringData = sortNoteStringData(notes, options == null ? void 0 : options.string);
2527
+ this.notes = noteStringData.notes;
2528
+ this.minDiatonicId = this.notes[0].diatonicId;
2529
+ this.maxDiatonicId = this.notes[this.notes.length - 1].diatonicId;
2530
+ this.ownDiatonicId = this.measure.updateOwnDiatonicId(voiceId, Math.round((this.minDiatonicId + this.maxDiatonicId) / 2));
2531
+ this.ownStemDir = this.measure.updateOwnStemDir(this, getStem(options == null ? void 0 : options.stem));
2532
+ this.ownString = this.measure.updateOwnString(this, noteStringData.strings);
2533
+ this.color = (_a = options == null ? void 0 : options.color) != null ? _a : "black";
2534
+ this.staccato = (_b = options == null ? void 0 : options.staccato) != null ? _b : false;
2535
+ this.diamond = (_c = options == null ? void 0 : options.diamond) != null ? _c : false;
2536
+ this.arpeggio = getArpeggio(options == null ? void 0 : options.arpeggio);
2537
+ this.oldStyleTriplet = tupletRatio === void 0 && ((options == null ? void 0 : options.triplet) === true || import_theory4.NoteLengthProps.get(noteLength).isTriplet);
2538
+ 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;
2539
+ this.rhythmProps = import_theory4.RhythmProps.get(noteLength, dotCount, (tupletRatio != null ? tupletRatio : this.oldStyleTriplet) ? import_theory4.Tuplet.Triplet : void 0);
2540
+ this.mi = new MNoteGroup(this);
2101
2541
  }
2102
- get showTupletRatio() {
2103
- var _a;
2104
- return ((_a = this.tupletRatio) == null ? void 0 : _a.showRatio) === true;
2542
+ getMusicInterface() {
2543
+ return this.mi;
2105
2544
  }
2106
- static createBeam(noteGroups) {
2107
- if (noteGroups.length > 1) {
2108
- new _ObjBeamGroup(noteGroups, void 0);
2109
- }
2545
+ get doc() {
2546
+ return this.col.doc;
2110
2547
  }
2111
- static createOldStyleTriplet(symbols) {
2112
- let s2 = symbols.slice(0, 2);
2113
- let n2 = s2.map((s) => s.rhythmProps.noteSize);
2114
- if (s2.length === 2 && s2.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && (n2[0] * 2 === n2[1] || n2[1] * 2 === n2[0])) {
2115
- new _ObjBeamGroup(s2, import_theory4.Tuplet.Triplet);
2116
- return 2;
2117
- }
2118
- let s3 = symbols.slice(0, 3);
2119
- let n3 = s3.map((s) => s.rhythmProps.noteSize);
2120
- if (s3.length === 3 && s3.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && n3.every((n) => n === n3[0])) {
2121
- new _ObjBeamGroup(s3, import_theory4.Tuplet.Triplet);
2122
- return 3;
2123
- }
2124
- return 0;
2548
+ get measure() {
2549
+ return this.col.measure;
2125
2550
  }
2126
- static createTuplet(symbols, tupletRatio) {
2127
- new _ObjBeamGroup(symbols, tupletRatio);
2551
+ get row() {
2552
+ return this.col.row;
2128
2553
  }
2129
- getMusicInterface() {
2130
- return this.mi;
2554
+ get stemDir() {
2555
+ return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
2131
2556
  }
2132
- detach() {
2133
- this.getSymbols().forEach((s) => s.resetBeamGroup());
2557
+ enableConnective(line) {
2558
+ return line.containsVoiceId(this.voiceId) && (line instanceof ObjTab || line.containsDiatonicId(this.ownDiatonicId));
2134
2559
  }
2135
- isEmpty() {
2136
- return this.staffObjects.length === 0;
2560
+ startConnective(connectiveProps) {
2561
+ if (!this.row.hasStaff && connectiveProps.connective === "tie" /* Tie */) {
2562
+ throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Ties not implemented for guitar tabs alone, staff is required!");
2563
+ } else if (!this.row.hasStaff && connectiveProps.connective === "slur" /* Slur */) {
2564
+ throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Slurs not implemented for guitar tabs alone, staff is required!");
2565
+ }
2566
+ this.startConnnectives.push(connectiveProps);
2567
+ this.doc.addConnectiveProps(connectiveProps);
2568
+ }
2569
+ getStaticObjects(line) {
2570
+ let staticObjects = [];
2571
+ this.staffObjects.forEach((obj) => {
2572
+ if (obj.staff === line) {
2573
+ staticObjects.push(obj);
2574
+ }
2575
+ });
2576
+ this.tabObjects.forEach((obj) => {
2577
+ if (obj.tab === line) {
2578
+ staticObjects.push(obj);
2579
+ }
2580
+ });
2581
+ return staticObjects;
2137
2582
  }
2138
2583
  pick(x, y) {
2139
2584
  if (!this.getRect().contains(x, y)) {
@@ -2145,632 +2590,201 @@ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
2145
2590
  return [this, ...arr];
2146
2591
  }
2147
2592
  }
2148
- return [this];
2149
- }
2150
- getType() {
2151
- return this.type;
2152
- }
2153
- isTuplet() {
2154
- return this.type === 1 /* TupletBeam */ || this.type === 2 /* TupletGroup */;
2155
- }
2156
- getSymbols() {
2157
- return this.symbols;
2158
- }
2159
- getFirstSymbol() {
2160
- return this.symbols[0];
2593
+ for (let i = 0; i < this.tabObjects.length; i++) {
2594
+ let arr = this.tabObjects[i].pick(x, y);
2595
+ if (arr.length > 0) {
2596
+ return [this, ...arr];
2597
+ }
2598
+ }
2599
+ return [];
2161
2600
  }
2162
- getLastSymbol() {
2163
- return this.symbols[this.symbols.length - 1];
2601
+ getTopNote() {
2602
+ return this.notes[this.notes.length - 1];
2164
2603
  }
2165
- get stemDir() {
2166
- return this.symbols[0].ownStemDir;
2604
+ getBottomNote() {
2605
+ return this.notes[0];
2167
2606
  }
2168
- layout(renderer) {
2169
- this.requestRectUpdate();
2170
- this.staffObjects.length = 0;
2171
- let symbols = this.getSymbols();
2172
- if (symbols.length === 0) {
2173
- return;
2174
- }
2175
- let voiceId = symbols[0].voiceId;
2176
- if (symbols.some((symbol) => symbol.voiceId !== voiceId)) {
2177
- return;
2178
- }
2179
- let { unitSize } = renderer;
2180
- let { stemDir } = this;
2181
- let symbolsBeamCoords = symbols.map((s) => s.getBeamCoords());
2182
- symbolsBeamCoords[0].map((s) => s == null ? void 0 : s.staff).forEach((mainStaff, index) => {
2183
- var _a, _b;
2184
- if (!mainStaff) {
2185
- return;
2607
+ getConnectiveAnchorPoint(connectiveProps, line, noteIndex, noteAnchor, side) {
2608
+ if (line instanceof ObjStaff) {
2609
+ let staff = line;
2610
+ if (noteIndex < 0 || noteIndex >= this.notes.length) {
2611
+ throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Invalid noteIndex: " + noteIndex);
2186
2612
  }
2187
- let symbolX = symbolsBeamCoords.map((s) => {
2188
- var _a2;
2189
- return (_a2 = s[index]) == null ? void 0 : _a2.x;
2190
- });
2191
- let symbolY = symbolsBeamCoords.map((s) => {
2192
- var _a2;
2193
- return (_a2 = s[index]) == null ? void 0 : _a2.y;
2194
- });
2195
- let symbolStaff = symbolsBeamCoords.map((s) => {
2196
- var _a2;
2197
- return (_a2 = s[index]) == null ? void 0 : _a2.staff;
2198
- });
2199
- let symbolStemHeight = symbolsBeamCoords.map((s) => {
2200
- var _a2;
2201
- return (_a2 = s[index]) == null ? void 0 : _a2.stemHeight;
2202
- });
2203
- let leftSymbol = symbols[0];
2204
- let leftX = symbolX[0];
2205
- let leftY = symbolY[0];
2206
- let leftStaff = symbolStaff[0];
2207
- let rightSymbol = symbols[symbols.length - 1];
2208
- let rightX = symbolX[symbolX.length - 1];
2209
- let rightY = symbolY[symbolY.length - 1];
2210
- let rightStaff = symbolStaff[symbolY.length - 1];
2211
- if (leftX === void 0 || leftY === void 0 || leftStaff === void 0 || rightX === void 0 || rightY === void 0 || rightStaff === void 0) {
2212
- return;
2613
+ let obj = this.staffObjects.find((obj2) => obj2.staff === staff);
2614
+ if (!obj || noteIndex < 0 || noteIndex >= obj.noteHeadRects.length) {
2615
+ let r = this.getRect();
2616
+ return { x: r.centerX, y: r.bottom };
2213
2617
  }
2214
- let leftStemHeight = (_a = symbolStemHeight[0]) != null ? _a : 0;
2215
- let rightStemHeight = (_b = symbolStemHeight[symbolStemHeight.length - 1]) != null ? _b : 0;
2216
- if (this.type !== 2 /* TupletGroup */) {
2217
- let leftDy = leftStemHeight < rightStemHeight ? Math.sqrt(rightStemHeight - leftStemHeight) : 0;
2218
- let rightDy = rightStemHeight < leftStemHeight ? Math.sqrt(leftStemHeight - rightStemHeight) : 0;
2219
- if (stemDir === "up" /* Up */) {
2220
- leftDy *= -1;
2221
- rightDy *= -1;
2222
- }
2223
- if (leftDy !== 0) {
2224
- leftY += leftDy;
2225
- symbolY[0] += leftDy;
2226
- }
2227
- if (rightDy !== 0) {
2228
- rightY += rightDy;
2229
- symbolY[symbolY.length - 1] += rightDy;
2230
- }
2618
+ let noteHeadRect = obj.noteHeadRects[noteIndex];
2619
+ let stemTip = obj.stemTip;
2620
+ let stemDir = this.stemDir;
2621
+ let hasStem = stemTip !== void 0;
2622
+ let stemSide = !hasStem ? void 0 : stemDir === "up" /* Up */ ? "right" : "left";
2623
+ let padding = noteHeadRect.height / 2;
2624
+ let centerX = noteHeadRect.centerX;
2625
+ let centerY = noteHeadRect.centerY;
2626
+ let leftX = noteHeadRect.left - padding;
2627
+ let rightX = noteHeadRect.right + padding;
2628
+ let aboveY = noteHeadRect.top - padding;
2629
+ let belowY = noteHeadRect.bottom + padding;
2630
+ if (noteAnchor === "auto" /* Auto */) {
2631
+ noteAnchor = "below" /* Below */;
2632
+ } else if (noteAnchor === "stemTip" /* StemTip */ && !hasStem) {
2633
+ noteAnchor = stemDir === "up" /* Up */ ? "above" /* Above */ : "below" /* Below */;
2231
2634
  }
2232
- let groupLineDy = unitSize * 2 * (stemDir === "up" /* Up */ ? -1 : 1);
2233
- let centerY = (rightY + leftY) / 2;
2234
- let halfDy = adjustBeamAngle(rightX - leftX, rightY - leftY) / 2;
2235
- leftY = centerY - halfDy;
2236
- rightY = centerY + halfDy;
2237
- let raiseBeamY = 0;
2238
- symbolY.forEach((symY, i) => {
2239
- let symX = symbolX[i];
2240
- if (symX !== void 0 && symY !== void 0) {
2241
- let beamY = import_ts_utils_lib3.Utils.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
2242
- let raiseY = symY - beamY;
2243
- if (stemDir === "up" /* Up */ && raiseY < 0) {
2244
- raiseBeamY = Math.min(raiseBeamY, raiseY);
2245
- } else if (stemDir === "down" /* Down */ && raiseY > 0) {
2246
- raiseBeamY = Math.max(raiseBeamY, raiseY);
2247
- }
2248
- }
2249
- });
2250
- leftY += raiseBeamY;
2251
- rightY += raiseBeamY;
2252
- symbolY = symbolY.map((y) => y === void 0 ? void 0 : y + raiseBeamY);
2253
- let obj = new ObjStaffBeamGroup(mainStaff, this);
2254
- if (this.type === 2 /* TupletGroup */) {
2255
- let ef = unitSize / (rightX - leftX);
2256
- let l = import_ts_utils_lib3.Utils.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, -ef);
2257
- let r = import_ts_utils_lib3.Utils.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, 1 + ef);
2258
- obj.points.push(new BeamPoint(leftStaff, this, leftSymbol, l.x, l.y));
2259
- obj.points.push(new BeamPoint(rightStaff, this, rightSymbol, r.x, r.y));
2260
- obj.tupletNumberOffsetY = 0;
2261
- } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
2262
- raiseBeamY *= 0.5;
2263
- let { beamThickness } = renderer;
2264
- const beamHeight = (i) => {
2265
- let sym = symbols[i];
2266
- if (sym instanceof ObjNoteGroup) {
2267
- let beamCount = sym instanceof ObjNoteGroup ? Math.max(sym.getLeftBeamCount(), sym.getRightBeamCount()) : 0;
2268
- return DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? beamCount - 1 : 0);
2635
+ switch (noteAnchor) {
2636
+ case "center" /* Center */:
2637
+ return side === "left" ? { x: rightX, y: centerY } : { x: leftX, y: centerY };
2638
+ case "above" /* Above */:
2639
+ if (!hasStem || stemDir === "down" /* Down */) {
2640
+ return { x: centerX, y: aboveY };
2269
2641
  } else {
2270
- return 0;
2642
+ return {
2643
+ x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
2644
+ y: aboveY
2645
+ };
2271
2646
  }
2272
- };
2273
- symbols.forEach((sym, i) => {
2274
- let symStaff = symbolStaff[i];
2275
- let symX = symbolX[i];
2276
- let symY = symbolY[i];
2277
- if (symStaff && symX !== void 0 && symY !== void 0) {
2278
- let pt = new BeamPoint(symStaff, this, sym, symX, symY);
2279
- pt.topBeamsHeight = beamThickness / 2 + (stemDir === "down" /* Down */ ? beamHeight(i) : 0);
2280
- pt.bottomBeamsHeight = beamThickness / 2 + (stemDir === "up" /* Up */ ? beamHeight(i) : 0);
2281
- obj.points.push(pt);
2647
+ case "below" /* Below */:
2648
+ if (!hasStem || stemDir === "up" /* Up */) {
2649
+ return { x: centerX, y: belowY };
2650
+ } else {
2651
+ return {
2652
+ x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
2653
+ y: belowY
2654
+ };
2282
2655
  }
2283
- });
2284
- obj.tupletNumberOffsetY = groupLineDy;
2285
- }
2286
- if (this.isTuplet() && this.tupletRatio) {
2287
- let txt = this.showTupletRatio ? String(this.tupletRatio.parts) + ":" + String(this.tupletRatio.inTimeOf) : String(this.tupletRatio.parts);
2288
- obj.tupletNumber = new ObjText(this, txt, 0.5, 0.5);
2289
- obj.tupletNumber.layout(renderer);
2290
- obj.tupletNumber.offset((leftX + rightX) / 2, (leftY + rightY) / 2 + obj.tupletNumberOffsetY);
2291
- }
2292
- if (obj.points.length >= 2) {
2293
- this.staffObjects.push(obj);
2656
+ case "stemTip" /* StemTip */:
2657
+ return { x: centerX, y: stemTip.centerY + (stemDir === "up" /* Up */ ? -padding : padding) };
2658
+ default:
2659
+ throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Invalid noteAnchor: " + noteAnchor);
2294
2660
  }
2295
- });
2296
- }
2297
- updateRect() {
2298
- if (this.staffObjects.length === 0) {
2299
- this.rect = new DivRect();
2300
2661
  } else {
2301
- this.staffObjects.forEach((obj) => obj.updateRect());
2302
- this.rect = this.staffObjects[0].getRect().copy();
2303
- for (let i = 1; i < this.staffObjects.length; i++) {
2304
- this.rect.expandInPlace(this.staffObjects[i].getRect());
2662
+ let tab = line;
2663
+ let obj = this.tabObjects.find((obj2) => obj2.tab === tab);
2664
+ let fretNumber = obj == null ? void 0 : obj.fretNumbers[noteIndex];
2665
+ if (!obj || !fretNumber) {
2666
+ return { x: 0, y: 0 };
2667
+ }
2668
+ let r = fretNumber.getRect();
2669
+ let x = side === "right" ? r.left : r.right;
2670
+ let y;
2671
+ let s = 0.9;
2672
+ if (connectiveProps.connective === "slide" /* Slide */) {
2673
+ let leftFretNumber = connectiveProps.noteGroups[0].getFretNumber(obj, 0);
2674
+ let rightFretNumber = connectiveProps.noteGroups[1].getFretNumber(obj, 0);
2675
+ let slideUp = leftFretNumber === void 0 || rightFretNumber === void 0 || leftFretNumber <= rightFretNumber;
2676
+ if (side === "left") {
2677
+ y = slideUp ? r.centerY + r.bottomh * s : r.centerY - r.toph * s;
2678
+ } else {
2679
+ y = slideUp ? r.centerY - r.toph * s : r.centerY + r.bottomh * s;
2680
+ }
2681
+ } else {
2682
+ y = r.centerY + r.bottomh * s;
2305
2683
  }
2684
+ return { x, y };
2306
2685
  }
2307
2686
  }
2308
- updateStemTips() {
2309
- this.staffObjects.forEach((obj) => {
2310
- let left = obj.points[0];
2311
- let right = obj.points[obj.points.length - 1];
2312
- if (this.type !== 2 /* TupletGroup */) {
2313
- obj.points.forEach((pt) => {
2314
- if (pt.symbol instanceof ObjNoteGroup) {
2315
- if (pt !== left && pt !== right) {
2316
- pt.y = import_ts_utils_lib3.Utils.Math.interpolateY(left.x, left.y, right.x, right.y, pt.x);
2317
- }
2318
- pt.symbol.setStemTipY(pt.staff, pt.y);
2319
- }
2320
- });
2321
- }
2322
- if (obj.tupletNumber) {
2323
- let y = (left.y + right.y) / 2 + obj.tupletNumberOffsetY;
2324
- obj.tupletNumber.offset(0, -obj.tupletNumber.getRect().centerY + y);
2325
- }
2326
- });
2687
+ getFretNumberString(noteIndex) {
2688
+ return this.ownString[noteIndex];
2327
2689
  }
2328
- offset(dx, dy) {
2329
- this.staffObjects.forEach((obj) => obj.offset(dx, 0));
2330
- this.requestRectUpdate();
2690
+ getFretNumber(tabObj, noteIndex) {
2691
+ let fretNumber = tabObj.fretNumbers[noteIndex];
2692
+ return fretNumber === void 0 ? void 0 : +fretNumber.getText();
2331
2693
  }
2332
- draw(renderer) {
2333
- let { unitSize, beamThickness, lineWidth } = renderer;
2334
- let color = "black";
2335
- this.staffObjects.forEach((obj) => {
2336
- if (this.type === 2 /* TupletGroup */) {
2337
- let l = obj.points[0];
2338
- let r = obj.points[obj.points.length - 1];
2339
- if (l && r) {
2340
- let tf = obj.tupletNumber ? obj.tupletNumber.getRect().width / (r.x - l.x) * 1.2 : 0;
2341
- let lc = import_ts_utils_lib3.Utils.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 - tf / 2);
2342
- let rc = import_ts_utils_lib3.Utils.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 + tf / 2);
2343
- let tipH = this.stemDir === "up" /* Up */ ? unitSize : -unitSize;
2344
- renderer.drawLine(l.x, l.y, lc.x, lc.y, color, lineWidth);
2345
- renderer.drawLine(rc.x, rc.y, r.x, r.y, color, lineWidth);
2346
- renderer.drawLine(l.x, l.y, l.x, l.y + tipH, color, lineWidth);
2347
- renderer.drawLine(r.x, r.y, r.x, r.y + tipH, color, lineWidth);
2348
- }
2349
- } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
2350
- let beamSeparation = DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? 1 : -1);
2351
- let noteGroupPoints = obj.points.filter((p) => p.symbol instanceof ObjNoteGroup);
2352
- for (let i = 0; i < noteGroupPoints.length - 1; i++) {
2353
- let left = noteGroupPoints[i];
2354
- let right = noteGroupPoints[i + 1];
2355
- if (!(left.symbol instanceof ObjNoteGroup && right.symbol instanceof ObjNoteGroup)) {
2356
- continue;
2357
- }
2358
- let leftBeamCount = left.symbol.getRightBeamCount();
2359
- let rightBeamCount = right.symbol.getLeftBeamCount();
2360
- let lx = left.x;
2361
- let ly = left.y;
2362
- let rx = right.x;
2363
- let ry = right.y;
2364
- for (let beamId = 0; beamId < Math.max(leftBeamCount, rightBeamCount); beamId++) {
2365
- if (beamId < leftBeamCount && beamId < rightBeamCount) {
2366
- renderer.drawLine(lx, ly, rx, ry, color, beamThickness);
2367
- } else if (leftBeamCount > rightBeamCount) {
2368
- renderer.drawPartialLine(lx, ly, rx, ry, 0, 0.25, color, beamThickness);
2369
- } else if (rightBeamCount > leftBeamCount) {
2370
- renderer.drawPartialLine(lx, ly, rx, ry, 0.75, 1, color, beamThickness);
2371
- }
2372
- ly += beamSeparation;
2373
- ry += beamSeparation;
2374
- }
2375
- }
2376
- }
2377
- if (obj.tupletNumber) {
2378
- obj.tupletNumber.draw(renderer);
2379
- }
2380
- });
2381
- }
2382
- };
2383
-
2384
- // src/score/engine/obj-note-group.ts
2385
- var import_core7 = require("@tspro/web-music-score/core");
2386
- function getStem(stem) {
2387
- return import_ts_utils_lib4.Utils.Is.isEnumValue(stem, Stem) ? stem : void 0;
2388
- }
2389
- function getArpeggio(a) {
2390
- return import_ts_utils_lib4.Utils.Is.isEnumValue(a, Arpeggio) ? a : a === true ? "up" /* Up */ : void 0;
2391
- }
2392
- function sortNoteStringData(notes, strings) {
2393
- let stringArr = import_ts_utils_lib4.Utils.Arr.isArray(strings) ? strings : strings !== void 0 ? [strings] : [];
2394
- let noteStringData = notes.map((note, i) => {
2395
- return { note, string: stringArr[i] };
2396
- });
2397
- noteStringData = import_ts_utils_lib4.Utils.Arr.removeDuplicatesCmp(noteStringData, (a, b) => import_theory5.Note.equals(a.note, b.note)).sort((a, b) => import_theory5.Note.compareFunc(a.note, b.note));
2398
- return {
2399
- notes: noteStringData.map((e) => e.note),
2400
- strings: noteStringData.every((e) => e.string === void 0) ? void 0 : noteStringData.map((e) => e.string)
2401
- };
2402
- }
2403
- var ObjStaffNoteGroup = class extends MusicObject {
2404
- constructor(staff, noteGroup) {
2405
- super(staff);
2406
- this.staff = staff;
2407
- this.noteGroup = noteGroup;
2408
- __publicField(this, "noteHeadRects", []);
2409
- __publicField(this, "dotRects", []);
2410
- __publicField(this, "accidentals", []);
2411
- __publicField(this, "stemTip");
2412
- __publicField(this, "stemBase");
2413
- __publicField(this, "flagRects", []);
2414
- __publicField(this, "prevTopNoteY", 0);
2415
- __publicField(this, "prevBottomNoteY", 0);
2416
- __publicField(this, "mi");
2417
- this.mi = new MStaffNoteGroup(this);
2418
- }
2419
- getMusicInterface() {
2420
- return this.mi;
2421
- }
2422
- pick(x, y) {
2423
- if (!this.getRect().contains(x, y)) {
2424
- return [];
2694
+ getNextNoteGroup() {
2695
+ let voiceNoteGroups = this.measure.getVoiceSymbols(this.voiceId).filter((s) => s instanceof _ObjNoteGroup);
2696
+ let i = voiceNoteGroups.indexOf(this);
2697
+ if (i < 0) {
2698
+ return void 0;
2699
+ } else if (i < voiceNoteGroups.length - 1) {
2700
+ return voiceNoteGroups[i + 1];
2425
2701
  }
2426
- for (let i = 0; i < this.accidentals.length; i++) {
2427
- let arr = this.accidentals[i].pick(x, y);
2428
- if (arr.length > 0) {
2429
- return [this, ...arr];
2702
+ let m = this.measure.getNextMeasure();
2703
+ while (m) {
2704
+ let voiceNoteGroups2 = m.getVoiceSymbols(this.voiceId).filter((s) => s instanceof _ObjNoteGroup);
2705
+ if (voiceNoteGroups2.length > 0) {
2706
+ return voiceNoteGroups2[0];
2430
2707
  }
2708
+ m = m.getNextMeasure();
2431
2709
  }
2432
- return [this];
2710
+ return void 0;
2433
2711
  }
2434
- updateRect() {
2435
- this.rect = this.noteHeadRects[0].copy();
2436
- this.noteHeadRects.forEach((r) => this.rect.expandInPlace(r));
2437
- if (this.stemTip) this.rect.expandInPlace(this.stemTip);
2438
- if (this.stemBase) this.rect.expandInPlace(this.stemBase);
2439
- this.dotRects.forEach((r) => this.rect.expandInPlace(r));
2440
- this.flagRects.forEach((r) => this.rect.expandInPlace(r));
2441
- this.accidentals.forEach((a) => this.rect.expandInPlace(a.getRect()));
2712
+ collectConnectiveProps() {
2713
+ this.startConnnectives.forEach((connective) => {
2714
+ this.runningConnectives.push(connective);
2715
+ let next = this.getNextNoteGroup();
2716
+ while (next && connective.addNoteGroup(next)) {
2717
+ next.runningConnectives.push(connective);
2718
+ next = next.getNextNoteGroup();
2719
+ }
2720
+ });
2442
2721
  }
2443
- getRect() {
2444
- let bottomNoteRect = this.noteHeadRects[0];
2445
- let topNoteRect = this.noteHeadRects[this.noteHeadRects.length - 1];
2446
- if (this.prevTopNoteY !== topNoteRect.centerY || this.prevBottomNoteY !== bottomNoteRect.centerY) {
2447
- this.prevTopNoteY = topNoteRect.centerY;
2448
- this.prevBottomNoteY = bottomNoteRect.centerY;
2449
- this.requestRectUpdate();
2722
+ removeConnectiveProps() {
2723
+ this.runningConnectives = [];
2724
+ }
2725
+ getPlaySlur() {
2726
+ let slurs = this.runningConnectives.filter((c) => c.connective === "slur" /* Slur */).map((c) => c.startsWith(this) ? "first" : "slurred");
2727
+ if (slurs.indexOf("first") >= 0) {
2728
+ return "first";
2729
+ } else if (slurs.indexOf("slurred") >= 0) {
2730
+ return "slurred";
2731
+ } else {
2732
+ return void 0;
2450
2733
  }
2451
- return super.getRect();
2452
2734
  }
2453
- offset(dx, dy) {
2454
- var _a, _b;
2455
- this.noteHeadRects.forEach((n) => n.offsetInPlace(dx, dy));
2456
- this.dotRects.forEach((n) => n.offsetInPlace(dx, dy));
2457
- this.accidentals.forEach((n) => n.offset(dx, dy));
2458
- (_a = this.stemTip) == null ? void 0 : _a.offsetInPlace(dx, dy);
2459
- (_b = this.stemBase) == null ? void 0 : _b.offsetInPlace(dx, dy);
2460
- this.flagRects.forEach((n) => n.offsetInPlace(dx, dy));
2461
- this.requestRectUpdate();
2462
- this.noteGroup.requestRectUpdate();
2735
+ getBeamGroup() {
2736
+ return this.beamGroup;
2463
2737
  }
2464
- };
2465
- var ObjTabNoteGroup = class extends MusicObject {
2466
- constructor(tab, noteGroup) {
2467
- super(tab);
2468
- this.tab = tab;
2469
- this.noteGroup = noteGroup;
2470
- __publicField(this, "fretNumbers", []);
2471
- __publicField(this, "mi");
2472
- tab.addObject(this);
2473
- this.mi = new MTabNoteGroup(this);
2738
+ setBeamGroup(beamGroup) {
2739
+ this.beamGroup = beamGroup;
2474
2740
  }
2475
- getMusicInterface() {
2476
- return this.mi;
2741
+ resetBeamGroup() {
2742
+ this.leftBeamCount = this.rightBeamCount = 0;
2743
+ this.beamGroup = void 0;
2477
2744
  }
2478
- pick(x, y) {
2479
- return this.getRect().contains(x, y) ? [this] : [];
2745
+ getBeamCoords() {
2746
+ return this.staffObjects.map((obj) => {
2747
+ var _a, _b, _c, _d;
2748
+ let staff = obj.staff;
2749
+ let x = (_b = (_a = obj.stemTip) == null ? void 0 : _a.centerX) != null ? _b : obj.noteHeadRects[0].centerX;
2750
+ let y = (_d = (_c = obj.stemTip) == null ? void 0 : _c.centerY) != null ? _d : this.stemDir === "up" /* Up */ ? obj.getRect().top : obj.getRect().bottom;
2751
+ let stemHeight = this.stemDir === "up" /* Up */ ? Math.abs(obj.noteHeadRects[0].centerY - y) : Math.abs(obj.noteHeadRects[obj.noteHeadRects.length - 1].centerY - y);
2752
+ return { staff, x, y, stemHeight };
2753
+ });
2480
2754
  }
2481
- updateRect() {
2482
- this.rect = this.fretNumbers[0].getRect().copy();
2483
- this.fretNumbers.forEach((fn) => this.rect.expandInPlace(fn.getRect()));
2755
+ getStemHeight(renderer) {
2756
+ let { unitSize } = renderer;
2757
+ let { flagCount, hasStem } = this.rhythmProps;
2758
+ if (hasStem) {
2759
+ let addY = this.hasBeamCount() ? DocumentSettings.BeamSeparation : DocumentSettings.FlagSeparation;
2760
+ return (DocumentSettings.StemHeight + Math.max(0, flagCount - 1) * addY) * unitSize;
2761
+ } else {
2762
+ return 0;
2763
+ }
2484
2764
  }
2485
- offset(dx, dy) {
2486
- this.fretNumbers.forEach((f) => f.offset(dx, dy));
2487
- this.requestRectUpdate();
2488
- this.noteGroup.requestRectUpdate();
2765
+ hasBeamCount() {
2766
+ return this.leftBeamCount > 0 || this.rightBeamCount > 0;
2489
2767
  }
2490
- };
2491
- var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2492
- constructor(col, voiceId, notes, noteLength, options, tupletRatio) {
2493
- var _a, _b, _c;
2494
- super(col);
2495
- this.col = col;
2496
- this.voiceId = voiceId;
2497
- this.notes = notes;
2498
- __publicField(this, "minDiatonicId");
2499
- __publicField(this, "maxDiatonicId");
2500
- __publicField(this, "ownDiatonicId");
2501
- // Average diatonicId of notes.
2502
- __publicField(this, "ownStemDir");
2503
- __publicField(this, "ownString");
2504
- __publicField(this, "color");
2505
- __publicField(this, "staccato");
2506
- __publicField(this, "diamond");
2507
- __publicField(this, "arpeggio");
2508
- __publicField(this, "oldStyleTriplet");
2509
- __publicField(this, "rhythmProps");
2510
- __publicField(this, "startConnnectives", []);
2511
- __publicField(this, "runningConnectives", []);
2512
- __publicField(this, "leftBeamCount", 0);
2513
- __publicField(this, "rightBeamCount", 0);
2514
- __publicField(this, "beamGroup");
2515
- __publicField(this, "staffObjects", []);
2516
- __publicField(this, "tabObjects", []);
2517
- __publicField(this, "mi");
2518
- if (!import_ts_utils_lib4.Utils.Is.isIntegerGte(notes.length, 1)) {
2519
- throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Cannot create note group object because notes array is empty.");
2520
- }
2521
- let noteStringData = sortNoteStringData(notes, options == null ? void 0 : options.string);
2522
- this.notes = noteStringData.notes;
2523
- this.minDiatonicId = this.notes[0].diatonicId;
2524
- this.maxDiatonicId = this.notes[this.notes.length - 1].diatonicId;
2525
- this.ownDiatonicId = this.measure.updateOwnDiatonicId(voiceId, Math.round((this.minDiatonicId + this.maxDiatonicId) / 2));
2526
- this.ownStemDir = this.measure.updateOwnStemDir(this, getStem(options == null ? void 0 : options.stem));
2527
- this.ownString = this.measure.updateOwnString(this, noteStringData.strings);
2528
- this.color = (_a = options == null ? void 0 : options.color) != null ? _a : "black";
2529
- this.staccato = (_b = options == null ? void 0 : options.staccato) != null ? _b : false;
2530
- this.diamond = (_c = options == null ? void 0 : options.diamond) != null ? _c : false;
2531
- this.arpeggio = getArpeggio(options == null ? void 0 : options.arpeggio);
2532
- this.oldStyleTriplet = tupletRatio === void 0 && ((options == null ? void 0 : options.triplet) === true || import_theory5.NoteLengthProps.get(noteLength).isTriplet);
2533
- 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;
2534
- this.rhythmProps = import_theory5.RhythmProps.get(noteLength, dotCount, (tupletRatio != null ? tupletRatio : this.oldStyleTriplet) ? import_theory5.Tuplet.Triplet : void 0);
2535
- this.mi = new MNoteGroup(this);
2768
+ getLeftBeamCount() {
2769
+ return this.leftBeamCount;
2536
2770
  }
2537
- getMusicInterface() {
2538
- return this.mi;
2771
+ getRightBeamCount() {
2772
+ return this.rightBeamCount;
2539
2773
  }
2540
- get doc() {
2541
- return this.col.doc;
2774
+ setLeftBeamCount(count) {
2775
+ this.leftBeamCount = count;
2542
2776
  }
2543
- get measure() {
2544
- return this.col.measure;
2777
+ setRightBeamCount(count) {
2778
+ this.rightBeamCount = count;
2545
2779
  }
2546
- get row() {
2547
- return this.col.row;
2780
+ hasTuplet() {
2781
+ return this.rhythmProps.tupletRatio !== void 0;
2548
2782
  }
2549
- get stemDir() {
2550
- return this.beamGroup ? this.beamGroup.stemDir : this.ownStemDir;
2783
+ isEmpty() {
2784
+ return this.staffObjects.length === 0 && this.tabObjects.length === 0;
2551
2785
  }
2552
- enableConnective(line) {
2553
- return line.containsVoiceId(this.voiceId) && (line instanceof ObjTab || line.containsDiatonicId(this.ownDiatonicId));
2554
- }
2555
- startConnective(connectiveProps) {
2556
- if (!this.row.hasStaff && connectiveProps.connective === "tie" /* Tie */) {
2557
- throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Ties not implemented for guitar tabs alone, staff is required!");
2558
- } else if (!this.row.hasStaff && connectiveProps.connective === "slur" /* Slur */) {
2559
- throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Slurs not implemented for guitar tabs alone, staff is required!");
2560
- }
2561
- this.startConnnectives.push(connectiveProps);
2562
- this.doc.addConnectiveProps(connectiveProps);
2563
- }
2564
- getStaticObjects(line) {
2565
- let staticObjects = [];
2566
- this.staffObjects.forEach((obj) => {
2567
- if (obj.staff === line) {
2568
- staticObjects.push(obj);
2569
- }
2570
- });
2571
- this.tabObjects.forEach((obj) => {
2572
- if (obj.tab === line) {
2573
- staticObjects.push(obj);
2574
- }
2575
- });
2576
- return staticObjects;
2577
- }
2578
- pick(x, y) {
2579
- if (!this.getRect().contains(x, y)) {
2580
- return [];
2581
- }
2582
- for (let i = 0; i < this.staffObjects.length; i++) {
2583
- let arr = this.staffObjects[i].pick(x, y);
2584
- if (arr.length > 0) {
2585
- return [this, ...arr];
2586
- }
2587
- }
2588
- for (let i = 0; i < this.tabObjects.length; i++) {
2589
- let arr = this.tabObjects[i].pick(x, y);
2590
- if (arr.length > 0) {
2591
- return [this, ...arr];
2592
- }
2593
- }
2594
- return [];
2595
- }
2596
- getTopNote() {
2597
- return this.notes[this.notes.length - 1];
2598
- }
2599
- getBottomNote() {
2600
- return this.notes[0];
2601
- }
2602
- getConnectiveAnchorPoint(connectiveProps, line, noteIndex, noteAnchor, side) {
2603
- if (line instanceof ObjStaff) {
2604
- let staff = line;
2605
- if (noteIndex < 0 || noteIndex >= this.notes.length) {
2606
- throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Invalid noteIndex: " + noteIndex);
2607
- }
2608
- let obj = this.staffObjects.find((obj2) => obj2.staff === staff);
2609
- if (!obj || noteIndex < 0 || noteIndex >= obj.noteHeadRects.length) {
2610
- let r = this.getRect();
2611
- return { x: r.centerX, y: r.bottom };
2612
- }
2613
- let noteHeadRect = obj.noteHeadRects[noteIndex];
2614
- let stemTip = obj.stemTip;
2615
- let stemDir = this.stemDir;
2616
- let hasStem = stemTip !== void 0;
2617
- let stemSide = !hasStem ? void 0 : stemDir === "up" /* Up */ ? "right" : "left";
2618
- let padding = noteHeadRect.height / 2;
2619
- let centerX = noteHeadRect.centerX;
2620
- let centerY = noteHeadRect.centerY;
2621
- let leftX = noteHeadRect.left - padding;
2622
- let rightX = noteHeadRect.right + padding;
2623
- let aboveY = noteHeadRect.top - padding;
2624
- let belowY = noteHeadRect.bottom + padding;
2625
- if (noteAnchor === "auto" /* Auto */) {
2626
- noteAnchor = "below" /* Below */;
2627
- } else if (noteAnchor === "stemTip" /* StemTip */ && !hasStem) {
2628
- noteAnchor = stemDir === "up" /* Up */ ? "above" /* Above */ : "below" /* Below */;
2629
- }
2630
- switch (noteAnchor) {
2631
- case "center" /* Center */:
2632
- return side === "left" ? { x: rightX, y: centerY } : { x: leftX, y: centerY };
2633
- case "above" /* Above */:
2634
- if (!hasStem || stemDir === "down" /* Down */) {
2635
- return { x: centerX, y: aboveY };
2636
- } else {
2637
- return {
2638
- x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
2639
- y: aboveY
2640
- };
2641
- }
2642
- case "below" /* Below */:
2643
- if (!hasStem || stemDir === "up" /* Up */) {
2644
- return { x: centerX, y: belowY };
2645
- } else {
2646
- return {
2647
- x: side === "left" && stemSide === "right" ? rightX : side === "right" && stemSide === "left" ? leftX : centerX,
2648
- y: belowY
2649
- };
2650
- }
2651
- case "stemTip" /* StemTip */:
2652
- return { x: centerX, y: stemTip.centerY + (stemDir === "up" /* Up */ ? -padding : padding) };
2653
- default:
2654
- throw new import_core7.MusicError(import_core7.MusicErrorType.Score, "Invalid noteAnchor: " + noteAnchor);
2655
- }
2656
- } else {
2657
- let tab = line;
2658
- let obj = this.tabObjects.find((obj2) => obj2.tab === tab);
2659
- let fretNumber = obj == null ? void 0 : obj.fretNumbers[noteIndex];
2660
- if (!obj || !fretNumber) {
2661
- return { x: 0, y: 0 };
2662
- }
2663
- let r = fretNumber.getRect();
2664
- let x = side === "right" ? r.left : r.right;
2665
- let y;
2666
- let s = 0.9;
2667
- if (connectiveProps.connective === "slide" /* Slide */) {
2668
- let leftFretNumber = connectiveProps.noteGroups[0].getFretNumber(obj, 0);
2669
- let rightFretNumber = connectiveProps.noteGroups[1].getFretNumber(obj, 0);
2670
- let slideUp = leftFretNumber === void 0 || rightFretNumber === void 0 || leftFretNumber <= rightFretNumber;
2671
- if (side === "left") {
2672
- y = slideUp ? r.centerY + r.bottomh * s : r.centerY - r.toph * s;
2673
- } else {
2674
- y = slideUp ? r.centerY - r.toph * s : r.centerY + r.bottomh * s;
2675
- }
2676
- } else {
2677
- y = r.centerY + r.bottomh * s;
2678
- }
2679
- return { x, y };
2680
- }
2681
- }
2682
- getFretNumberString(noteIndex) {
2683
- return this.ownString[noteIndex];
2684
- }
2685
- getFretNumber(tabObj, noteIndex) {
2686
- let fretNumber = tabObj.fretNumbers[noteIndex];
2687
- return fretNumber === void 0 ? void 0 : +fretNumber.getText();
2688
- }
2689
- getNextNoteGroup() {
2690
- let voiceNoteGroups = this.measure.getVoiceSymbols(this.voiceId).filter((s) => s instanceof _ObjNoteGroup);
2691
- let i = voiceNoteGroups.indexOf(this);
2692
- if (i < 0) {
2693
- return void 0;
2694
- } else if (i < voiceNoteGroups.length - 1) {
2695
- return voiceNoteGroups[i + 1];
2696
- }
2697
- let m = this.measure.getNextMeasure();
2698
- while (m) {
2699
- let voiceNoteGroups2 = m.getVoiceSymbols(this.voiceId).filter((s) => s instanceof _ObjNoteGroup);
2700
- if (voiceNoteGroups2.length > 0) {
2701
- return voiceNoteGroups2[0];
2702
- }
2703
- m = m.getNextMeasure();
2704
- }
2705
- return void 0;
2706
- }
2707
- collectConnectiveProps() {
2708
- this.startConnnectives.forEach((connective) => {
2709
- this.runningConnectives.push(connective);
2710
- let next = this.getNextNoteGroup();
2711
- while (next && connective.addNoteGroup(next)) {
2712
- next.runningConnectives.push(connective);
2713
- next = next.getNextNoteGroup();
2714
- }
2715
- });
2716
- }
2717
- removeConnectiveProps() {
2718
- this.runningConnectives = [];
2719
- }
2720
- getPlaySlur() {
2721
- let slurs = this.runningConnectives.filter((c) => c.connective === "slur" /* Slur */).map((c) => c.startsWith(this) ? "first" : "slurred");
2722
- if (slurs.indexOf("first") >= 0) {
2723
- return "first";
2724
- } else if (slurs.indexOf("slurred") >= 0) {
2725
- return "slurred";
2726
- } else {
2727
- return void 0;
2728
- }
2729
- }
2730
- getBeamGroup() {
2731
- return this.beamGroup;
2732
- }
2733
- setBeamGroup(beamGroup) {
2734
- this.beamGroup = beamGroup;
2735
- }
2736
- resetBeamGroup() {
2737
- this.leftBeamCount = this.rightBeamCount = 0;
2738
- this.beamGroup = void 0;
2739
- }
2740
- getBeamCoords() {
2741
- return this.staffObjects.map((obj) => {
2742
- var _a, _b, _c, _d;
2743
- let staff = obj.staff;
2744
- let x = (_b = (_a = obj.stemTip) == null ? void 0 : _a.centerX) != null ? _b : obj.noteHeadRects[0].centerX;
2745
- let y = (_d = (_c = obj.stemTip) == null ? void 0 : _c.centerY) != null ? _d : this.stemDir === "up" /* Up */ ? obj.getRect().top : obj.getRect().bottom;
2746
- let stemHeight = this.stemDir === "up" /* Up */ ? Math.abs(obj.noteHeadRects[0].centerY - y) : Math.abs(obj.noteHeadRects[obj.noteHeadRects.length - 1].centerY - y);
2747
- return { staff, x, y, stemHeight };
2748
- });
2749
- }
2750
- getStemHeight(renderer) {
2751
- let { unitSize } = renderer;
2752
- let { flagCount, hasStem } = this.rhythmProps;
2753
- if (hasStem) {
2754
- let addY = this.hasBeamCount() ? DocumentSettings.BeamSeparation : DocumentSettings.FlagSeparation;
2755
- return (DocumentSettings.StemHeight + Math.max(0, flagCount - 1) * addY) * unitSize;
2756
- } else {
2757
- return 0;
2758
- }
2759
- }
2760
- hasBeamCount() {
2761
- return this.leftBeamCount > 0 || this.rightBeamCount > 0;
2762
- }
2763
- getLeftBeamCount() {
2764
- return this.leftBeamCount;
2765
- }
2766
- getRightBeamCount() {
2767
- return this.rightBeamCount;
2768
- }
2769
- isEmpty() {
2770
- return this.staffObjects.length === 0 && this.tabObjects.length === 0;
2771
- }
2772
- visibleInStaff(staff) {
2773
- return staff.containsVoiceId(this.voiceId) && this.staffObjects.some((obj) => obj instanceof ObjStaffNoteGroup && obj.staff === staff);
2786
+ visibleInStaff(staff) {
2787
+ return staff.containsVoiceId(this.voiceId) && this.staffObjects.some((obj) => obj instanceof ObjStaffNoteGroup && obj.staff === staff);
2774
2788
  }
2775
2789
  getPlayTicks(note) {
2776
2790
  let tiedTicks = this.runningConnectives.filter((c) => c.connective === "tie" /* Tie */).map((tie) => {
@@ -2783,11 +2797,11 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2783
2797
  return Math.max(this.rhythmProps.ticks, this.measure.getMeasureTicks() - this.col.positionTicks);
2784
2798
  }
2785
2799
  let prev = tieNoteGroups[j - 1];
2786
- if (prev && prev.notes.some((n) => import_theory5.Note.equals(n, note))) {
2800
+ if (prev && prev.notes.some((n) => import_theory4.Note.equals(n, note))) {
2787
2801
  return 0;
2788
2802
  }
2789
2803
  tieNoteGroups = tieNoteGroups.slice(j);
2790
- j = tieNoteGroups.findIndex((ng) => ng.notes.every((n) => !import_theory5.Note.equals(n, note)));
2804
+ j = tieNoteGroups.findIndex((ng) => ng.notes.every((n) => !import_theory4.Note.equals(n, note)));
2791
2805
  if (j >= 0) {
2792
2806
  tieNoteGroups = tieNoteGroups.slice(0, j);
2793
2807
  }
@@ -2990,95 +3004,10 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
2990
3004
  ctx.lineTo(obj.stemTip.centerX, obj.stemTip.centerY);
2991
3005
  ctx.stroke();
2992
3006
  }
2993
- obj.flagRects.forEach((rect) => {
2994
- let left = rect.left;
2995
- let right = rect.right;
2996
- let width = right - left;
2997
- let top = stemDir === "up" /* Up */ ? rect.top : rect.bottom;
2998
- let bottom = stemDir === "up" /* Up */ ? rect.bottom : rect.top;
2999
- ctx.beginPath();
3000
- ctx.moveTo(left, top);
3001
- ctx.bezierCurveTo(
3002
- left,
3003
- top * 0.75 + bottom * 0.25,
3004
- left + width * 1.5,
3005
- top * 0.5 + bottom * 0.5,
3006
- left + width * 0.5,
3007
- bottom
3008
- );
3009
- ctx.stroke();
3010
- });
3007
+ obj.flagRects.forEach((rect) => renderer.drawFlag(rect, stemDir === "up" /* Up */ ? "up" : "down"));
3011
3008
  });
3012
3009
  this.tabObjects.forEach((obj) => obj.fretNumbers.forEach((fn) => fn.draw(renderer)));
3013
3010
  }
3014
- static setBeamCounts(groupNotes) {
3015
- const isADottedBHalf = (a, b) => {
3016
- let { flagCount: aFlagCount, noteSize: aNoteSize, dotCount: aDotCount } = a.rhythmProps;
3017
- let { flagCount: bFlagCount, noteSize: bNoteSize, dotCount: bDotCount } = b.rhythmProps;
3018
- return aFlagCount > 0 && bFlagCount > 0 && aDotCount > 0 && bDotCount === 0 && aNoteSize * Math.pow(2, aDotCount) === bNoteSize;
3019
- };
3020
- for (let i = 0; i < groupNotes.length; i++) {
3021
- let center = groupNotes[i];
3022
- let left = groupNotes[i - 1];
3023
- let right = groupNotes[i + 1];
3024
- if (center) {
3025
- center.leftBeamCount = 0;
3026
- center.rightBeamCount = 0;
3027
- if (left) {
3028
- if (left.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(left, center) || isADottedBHalf(center, left)) {
3029
- center.leftBeamCount = center.rhythmProps.flagCount;
3030
- } else {
3031
- center.leftBeamCount = Math.min(left.rhythmProps.flagCount, center.rhythmProps.flagCount);
3032
- }
3033
- }
3034
- if (right) {
3035
- if (right.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(right, center) || isADottedBHalf(center, right)) {
3036
- center.rightBeamCount = center.rhythmProps.flagCount;
3037
- } else {
3038
- center.rightBeamCount = Math.min(right.rhythmProps.flagCount, center.rhythmProps.flagCount);
3039
- }
3040
- }
3041
- }
3042
- }
3043
- let fixAgain;
3044
- do {
3045
- fixAgain = false;
3046
- for (let i = 0; i < groupNotes.length; i++) {
3047
- let center = groupNotes[i];
3048
- let left = groupNotes[i - 1];
3049
- let right = groupNotes[i + 1];
3050
- if (center && center.leftBeamCount !== center.rhythmProps.flagCount && center.rightBeamCount !== center.rhythmProps.flagCount) {
3051
- center.leftBeamCount = center.rightBeamCount = 0;
3052
- if (left && left.rightBeamCount > 0) {
3053
- left.rightBeamCount = 0;
3054
- fixAgain = true;
3055
- }
3056
- if (right && right.leftBeamCount > 0) {
3057
- right.leftBeamCount = 0;
3058
- fixAgain = true;
3059
- }
3060
- }
3061
- }
3062
- } while (fixAgain);
3063
- }
3064
- static setTupletBeamCounts(tuplet) {
3065
- let type = tuplet.getType();
3066
- let symbols = tuplet.getSymbols();
3067
- if (type === 1 /* TupletBeam */) {
3068
- symbols.forEach((s, i) => {
3069
- if (s instanceof _ObjNoteGroup) {
3070
- s.leftBeamCount = i === 0 ? 0 : s.rhythmProps.flagCount;
3071
- s.rightBeamCount = i === symbols.length - 1 ? 0 : s.rhythmProps.flagCount;
3072
- }
3073
- });
3074
- } else if (type === 2 /* TupletGroup */) {
3075
- symbols.forEach((s) => {
3076
- if (s instanceof _ObjNoteGroup) {
3077
- s.leftBeamCount = s.rightBeamCount = 0;
3078
- }
3079
- });
3080
- }
3081
- }
3082
3011
  getDotVerticalDisplacement(staff, diatonicId, stemDir) {
3083
3012
  if (staff.isLine(diatonicId)) {
3084
3013
  return stemDir === "up" /* Up */ ? -1 : 1;
@@ -3089,279 +3018,29 @@ var ObjNoteGroup = class _ObjNoteGroup extends MusicObject {
3089
3018
  static hasSameNotes(ng1, ng2) {
3090
3019
  if (ng1.notes.length !== ng2.notes.length) {
3091
3020
  return false;
3092
- }
3093
- for (let i = 0; i < ng1.notes.length; i++) {
3094
- let note1 = ng1.notes[i];
3095
- let note2 = ng2.notes[i];
3096
- if (note1.diatonicId !== note2.diatonicId || note1.accidental !== note2.accidental) {
3097
- return false;
3098
- }
3099
- }
3100
- return true;
3101
- }
3102
- };
3103
-
3104
- // src/score/engine/obj-rhythm-column.ts
3105
- var import_core9 = require("@tspro/web-music-score/core");
3106
-
3107
- // src/theory/rhythm.ts
3108
- var import_ts_utils_lib5 = require("@tspro/ts-utils-lib");
3109
- var import_core8 = require("@tspro/web-music-score/core");
3110
- var cmp = (a, b) => a === b ? 0 : a < b ? -1 : 1;
3111
- var MaxTupletRatioValue = 12;
3112
- var TicksMultiplier = 12 * 11 * 9 * 7 * 5;
3113
- var NoteLength4 = /* @__PURE__ */ ((NoteLength10) => {
3114
- NoteLength10["Whole"] = "1n";
3115
- NoteLength10["WholeTriplet"] = "1t";
3116
- NoteLength10["WholeDot"] = "1.";
3117
- NoteLength10["Whole2Dots"] = "1..";
3118
- NoteLength10["Whole12Dots"] = "1..";
3119
- NoteLength10["Whole3Dots"] = "1...";
3120
- NoteLength10["Whole4Dots"] = "1....";
3121
- NoteLength10["Whole5Dots"] = "1.....";
3122
- NoteLength10["Whole6Dots"] = "1......";
3123
- NoteLength10["Half"] = "2n";
3124
- NoteLength10["HalfTriplet"] = "2t";
3125
- NoteLength10["HalfDot"] = "2.";
3126
- NoteLength10["Half2Dots"] = "2..";
3127
- NoteLength10["Half3Dots"] = "2...";
3128
- NoteLength10["Half4Dots"] = "2....";
3129
- NoteLength10["Half5Dots"] = "2.....";
3130
- NoteLength10["Quarter"] = "4n";
3131
- NoteLength10["QuarterTriplet"] = "4t";
3132
- NoteLength10["QuarterDot"] = "4.";
3133
- NoteLength10["Quarter2Dots"] = "4..";
3134
- NoteLength10["Quarter3Dots"] = "4...";
3135
- NoteLength10["Quarter4Dots"] = "4....";
3136
- NoteLength10["Eighth"] = "8n";
3137
- NoteLength10["EighthTriplet"] = "8t";
3138
- NoteLength10["EighthDot"] = "8.";
3139
- NoteLength10["Eighth2Dots"] = "8..";
3140
- NoteLength10["Eighth3Dots"] = "8...";
3141
- NoteLength10["Sixteenth"] = "16n";
3142
- NoteLength10["SixteenthTriplet"] = "16t";
3143
- NoteLength10["SixteenthDot"] = "16.";
3144
- NoteLength10["Sixteenth2Dots"] = "16..";
3145
- NoteLength10["ThirtySecond"] = "32n";
3146
- NoteLength10["ThirtySecondTriplet"] = "32t";
3147
- NoteLength10["ThirtySecondDot"] = "32.";
3148
- NoteLength10["SixtyFourth"] = "64n";
3149
- NoteLength10["SixtyFourthTriplet"] = "64t";
3150
- return NoteLength10;
3151
- })(NoteLength4 || {});
3152
- function validateNoteLength(noteLength) {
3153
- if (import_ts_utils_lib5.Utils.Is.isEnumValue(noteLength, NoteLength4)) {
3154
- return noteLength;
3155
- } else {
3156
- throw new import_core8.MusicError(import_core8.MusicErrorType.InvalidArg, `Invalid noteLength: ${noteLength}`);
3157
- }
3158
- }
3159
- var _NoteLengthProps = class _NoteLengthProps {
3160
- constructor(noteLength) {
3161
- /** Note length. */
3162
- __publicField(this, "noteLength");
3163
- /** Note size (whole=1, half=2, quarter=4, ...). */
3164
- __publicField(this, "noteSize");
3165
- /** Number of ticks (not altered by isTriplet). */
3166
- __publicField(this, "ticks");
3167
- /** Flag count. */
3168
- __publicField(this, "flagCount");
3169
- /** Dot count. */
3170
- __publicField(this, "dotCount");
3171
- /** Max dot count. */
3172
- __publicField(this, "maxDotCount");
3173
- /** Is triplet? */
3174
- __publicField(this, "isTriplet");
3175
- /** Has note stem. */
3176
- __publicField(this, "hasStem");
3177
- /** Is note head solid (black)? */
3178
- __publicField(this, "isSolid");
3179
- this.noteLength = validateNoteLength(noteLength);
3180
- this.noteSize = parseInt(noteLength);
3181
- this.isTriplet = noteLength.endsWith("t");
3182
- this.maxDotCount = this.isTriplet ? 0 : Math.floor(Math.log2(_NoteLengthProps.ShortestNoteSize / this.noteSize));
3183
- this.dotCount = import_ts_utils_lib5.Utils.Str.charCount(noteLength, ".");
3184
- this.flagCount = this.noteSize > 4 ? Math.floor(Math.log2(this.noteSize / 4)) : 0;
3185
- this.ticks = TicksMultiplier * _NoteLengthProps.ShortestNoteSize / this.noteSize;
3186
- this.hasStem = this.noteSize > 1;
3187
- this.isSolid = this.noteSize > 2;
3188
- if (this.dotCount > this.maxDotCount) {
3189
- throw new import_core8.MusicError(import_core8.MusicErrorType.Note, `dotCount ${this.dotCount} > maxDotCount ${this.maxDotCount}, for noteLength "${this.noteLength}".`);
3190
- } else if (this.isTriplet && this.dotCount > 0) {
3191
- throw new import_core8.MusicError(import_core8.MusicErrorType.Note, `noteLength "${this.noteLength}" is both triplet and dotted!`);
3192
- }
3193
- }
3194
- /**
3195
- * Get note length props.
3196
- * @param noteLength - Note length.
3197
- * @returns - Note length props.
3198
- */
3199
- static get(noteLength) {
3200
- let p = this.cache.get(noteLength);
3201
- if (!p) {
3202
- this.cache.set(noteLength, p = new _NoteLengthProps(noteLength));
3203
- }
3204
- return p;
3205
- }
3206
- /**
3207
- * Create note length props.
3208
- * @param noteLength - Note length or note size.
3209
- * @param dotCount - Dot count.
3210
- * @returns - Note length props.
3211
- */
3212
- static create(noteLength, dotCount = 0) {
3213
- let noteSize = typeof noteLength === "number" ? noteLength : this.get(noteLength).noteSize;
3214
- return this.get(noteSize + (import_ts_utils_lib5.Utils.Is.isIntegerGte(dotCount, 1) ? ".".repeat(dotCount) : "n"));
3215
- }
3216
- /**
3217
- * Compare note lengths/sizes. Whole (1) > half (2) > quarter (4), etc.
3218
- * Ignores possible triplet property of note length.
3219
- * @param a - NoteLengthProps, NoteLength/Str or noteSize
3220
- * @param b - NoteLengthProps, NoteLength/Str or noteSize
3221
- * @returns - -1: a < b, 0: a === b, +1: a > b (note length/size comparisons)
3222
- */
3223
- static cmp(a, b) {
3224
- let aNoteSize = a instanceof _NoteLengthProps ? a.noteSize : typeof a === "number" ? a : _NoteLengthProps.get(a).noteSize;
3225
- let bNoteSize = b instanceof _NoteLengthProps ? b.noteSize : typeof b === "number" ? b : _NoteLengthProps.get(b).noteSize;
3226
- return cmp(bNoteSize, aNoteSize);
3227
- }
3228
- /**
3229
- * Compare note lengths/sizes for equality.
3230
- * Ignores possible triplet property of note length.
3231
- * @param a - NoteLengthProps, NoteLength/Str or noteSize
3232
- * @param b - NoteLengthProps, NoteLength/Str or noteSize
3233
- * @returns - true: a === b, false: a !== b (note length/size comparisons)
3234
- */
3235
- static equals(a, b) {
3236
- let aNoteSize = a instanceof _NoteLengthProps ? a.noteSize : typeof a === "number" ? a : _NoteLengthProps.get(a).noteSize;
3237
- let bNoteSize = b instanceof _NoteLengthProps ? b.noteSize : typeof b === "number" ? b : _NoteLengthProps.get(b).noteSize;
3238
- return aNoteSize === bNoteSize;
3239
- }
3240
- };
3241
- /** Longest note size (e.g. 1 = whole note). */
3242
- __publicField(_NoteLengthProps, "LongestNoteSize", Math.min(...import_ts_utils_lib5.Utils.Enum.getEnumValues(NoteLength4).map((noteLength) => parseInt(noteLength))));
3243
- /** Shortest note size (e.g. 64 = sixtyfourth note). */
3244
- __publicField(_NoteLengthProps, "ShortestNoteSize", Math.max(...import_ts_utils_lib5.Utils.Enum.getEnumValues(NoteLength4).map((noteLength) => parseInt(noteLength))));
3245
- __publicField(_NoteLengthProps, "cache", /* @__PURE__ */ new Map());
3246
- var NoteLengthProps4 = _NoteLengthProps;
3247
- function validateTupletRatio(tupletRatio) {
3248
- if (import_ts_utils_lib5.Utils.Is.isObject(tupletRatio) && import_ts_utils_lib5.Utils.Is.isIntegerBetween(tupletRatio.parts, 2, MaxTupletRatioValue) && import_ts_utils_lib5.Utils.Is.isIntegerBetween(tupletRatio.inTimeOf, 2, MaxTupletRatioValue)) {
3249
- return tupletRatio;
3250
- } else {
3251
- throw new import_core8.MusicError(import_core8.MusicErrorType.Note, `Invalid tupletRatio ${JSON.stringify(tupletRatio)}`);
3252
- }
3253
- }
3254
- var Tuplet4 = {
3255
- /** Duplet: 2 in the time of 3 */
3256
- Duplet: { parts: 2, inTimeOf: 3 },
3257
- /** Triplet: 3 in the time of 2 */
3258
- Triplet: { parts: 3, inTimeOf: 2 },
3259
- /** Quadruplet: 4 in the time of 3 */
3260
- Quadruplet: { parts: 4, inTimeOf: 3 }
3261
- };
3262
- var _RhythmProps = class _RhythmProps {
3263
- constructor(noteLength, dotCount, tupletRatio) {
3264
- /** Note length. */
3265
- __publicField(this, "noteLength");
3266
- /** Note size (whole=1, half=2, quarter=4, ...). */
3267
- __publicField(this, "noteSize");
3268
- /** Dot count. */
3269
- __publicField(this, "dotCount");
3270
- /** Tuplet ratio. */
3271
- __publicField(this, "tupletRatio");
3272
- /** Number of ticks. */
3273
- __publicField(this, "ticks");
3274
- /** Flag count. */
3275
- __publicField(this, "flagCount");
3276
- /** Has note stem. */
3277
- __publicField(this, "hasStem");
3278
- /** Is note head solid (black)? */
3279
- __publicField(this, "isSolidNoteHead");
3280
- this.noteLength = validateNoteLength(noteLength);
3281
- let p = NoteLengthProps4.get(noteLength);
3282
- this.noteSize = p.noteSize;
3283
- this.ticks = p.ticks;
3284
- this.flagCount = p.flagCount;
3285
- this.dotCount = dotCount != null ? dotCount : p.dotCount;
3286
- this.hasStem = p.hasStem;
3287
- this.isSolidNoteHead = p.isSolid;
3288
- if (import_ts_utils_lib5.Utils.Is.isObject(tupletRatio)) {
3289
- this.tupletRatio = validateTupletRatio(tupletRatio);
3290
- } else if (p.isTriplet) {
3291
- this.tupletRatio = Tuplet4.Triplet;
3292
- } else {
3293
- this.tupletRatio = void 0;
3294
- }
3295
- if (this.dotCount > 0 && this.tupletRatio !== void 0) {
3296
- throw new import_core8.MusicError(import_core8.MusicErrorType.Note, `Note cannot be both dotted and tuplet!`);
3297
- } else if (this.dotCount > p.maxDotCount) {
3298
- throw new import_core8.MusicError(import_core8.MusicErrorType.Note, `Too big dot count ${this.dotCount} for note length ${this.noteLength}.`);
3299
- }
3300
- for (let add = this.ticks / 2, i = 1; i <= this.dotCount; i++, add /= 2) {
3301
- this.ticks += add;
3302
- }
3303
- if (this.tupletRatio) {
3304
- this.ticks *= this.tupletRatio.inTimeOf / this.tupletRatio.parts;
3305
- }
3306
- }
3307
- /**
3308
- * Get string presentation of rhythm props.
3309
- * @returns - String presentation.
3310
- */
3311
- toString() {
3312
- let sym = _RhythmProps.NoteSymbolMap.get(this.noteSize);
3313
- let dots = ".".repeat(this.dotCount);
3314
- return sym ? sym + dots : "" + this.noteSize + (dots.length > 0 ? dots : "n");
3315
- }
3316
- /**
3317
- * Get rhythm props with given arguments.
3318
- * @param noteLength - Note length.
3319
- * @param dotCount - Dot count.
3320
- * @param tupletRatio - Tuplet ratio.
3321
- * @returns - Rhythm props.
3322
- */
3323
- static get(noteLength, dotCount, tupletRatio) {
3324
- if (dotCount !== void 0 || tupletRatio !== void 0) {
3325
- return new _RhythmProps(noteLength, dotCount, tupletRatio);
3326
- } else {
3327
- let rhythmProps = this.cache.get(noteLength);
3328
- if (!rhythmProps) {
3329
- this.cache.set(noteLength, rhythmProps = new _RhythmProps(noteLength));
3330
- }
3331
- return rhythmProps;
3332
- }
3333
- }
3334
- /**
3335
- * Compare duration of rhythm props.
3336
- * @param a - RhythmProps
3337
- * @param b - RhythmProps
3338
- * @returns - -1: a < b, 0: a === b, +1: a > b (duration comparisons)
3339
- */
3340
- static cmp(a, b) {
3341
- return cmp(a.ticks, b.ticks);
3342
- }
3343
- /**
3344
- * Compare duration equality of rhythm props.
3345
- * @param a - RhythmProps
3346
- * @param b - RhythmProps
3347
- * @returns - true: a === b, false: a !== b (duration comparisons)
3348
- */
3349
- static equals(a, b) {
3350
- return a.ticks === b.ticks;
3021
+ }
3022
+ for (let i = 0; i < ng1.notes.length; i++) {
3023
+ let note1 = ng1.notes[i];
3024
+ let note2 = ng2.notes[i];
3025
+ if (note1.diatonicId !== note2.diatonicId || note1.accidental !== note2.accidental) {
3026
+ return false;
3027
+ }
3028
+ }
3029
+ return true;
3351
3030
  }
3352
3031
  };
3353
- __publicField(_RhythmProps, "NoteSymbolMap", /* @__PURE__ */ new Map([[1, "\u{1D15D}"], [2, "\u{1D15E}"], [4, "\u{1D15F}"], [8, "\u{1D160}"], [16, "\u{1D161}"], [32, "\u{1D162}"], [64, "\u{1D163}"], [128, "\u{1D164}"]]));
3354
- __publicField(_RhythmProps, "cache", /* @__PURE__ */ new Map());
3355
- var RhythmProps3 = _RhythmProps;
3032
+
3033
+ // src/score/engine/obj-rhythm-column.ts
3034
+ var import_core8 = require("@tspro/web-music-score/core");
3356
3035
 
3357
3036
  // src/score/engine/obj-lyrics.ts
3358
- var import_ts_utils_lib6 = require("@tspro/ts-utils-lib");
3037
+ var import_ts_utils_lib5 = require("@tspro/ts-utils-lib");
3359
3038
  var LyricsContainer = class {
3360
3039
  constructor(col, lyricsLength) {
3361
3040
  this.col = col;
3362
3041
  __publicField(this, "lyricsObjects", []);
3363
3042
  __publicField(this, "rhythmProps");
3364
- this.rhythmProps = RhythmProps3.get(lyricsLength);
3043
+ this.rhythmProps = RhythmProps.get(lyricsLength);
3365
3044
  }
3366
3045
  addLyricsObject(lyricsObj) {
3367
3046
  var _a;
@@ -3382,7 +3061,7 @@ var ObjLyrics = class extends MusicObject {
3382
3061
  __publicField(this, "text");
3383
3062
  __publicField(this, "mi");
3384
3063
  let halign = (lyricsOptions == null ? void 0 : lyricsOptions.align) === "left" /* Left */ ? 0 : (lyricsOptions == null ? void 0 : lyricsOptions.align) === "right" /* Right */ ? 1 : 0.5;
3385
- this.hyphen = import_ts_utils_lib6.Utils.Is.isEnumValue(lyricsOptions == null ? void 0 : lyricsOptions.hyphen, LyricsHyphen) ? lyricsOptions == null ? void 0 : lyricsOptions.hyphen : void 0;
3064
+ this.hyphen = import_ts_utils_lib5.Utils.Is.isEnumValue(lyricsOptions == null ? void 0 : lyricsOptions.hyphen, LyricsHyphen) ? lyricsOptions == null ? void 0 : lyricsOptions.hyphen : void 0;
3386
3065
  this.text = new ObjText(this, { text: lyricsText, color: this.color, scale: 0.8 }, halign, 0);
3387
3066
  this.rect = new DivRect();
3388
3067
  this.mi = new MLyrics(this);
@@ -3435,11 +3114,11 @@ var ObjLyrics = class extends MusicObject {
3435
3114
 
3436
3115
  // src/score/engine/obj-rhythm-column.ts
3437
3116
  var noteHeadDataCompareFunc = (a, b) => {
3438
- let cmp3 = import_theory6.Note.compareFunc(a.note, b.note);
3439
- if (cmp3 === 0) {
3440
- cmp3 = a.noteGroup.stemDir === b.noteGroup.stemDir ? 0 : a.noteGroup.stemDir === "up" /* Up */ ? 1 : -1;
3117
+ let cmp = import_theory5.Note.compareFunc(a.note, b.note);
3118
+ if (cmp === 0) {
3119
+ cmp = a.noteGroup.stemDir === b.noteGroup.stemDir ? 0 : a.noteGroup.stemDir === "up" /* Up */ ? 1 : -1;
3441
3120
  }
3442
- return cmp3;
3121
+ return cmp;
3443
3122
  };
3444
3123
  var ObjRhythmColumn = class extends MusicObject {
3445
3124
  constructor(measure, positionTicks) {
@@ -3477,7 +3156,7 @@ var ObjRhythmColumn = class extends MusicObject {
3477
3156
  if (colId >= 0 && colId < this.measure.getColumnCount()) {
3478
3157
  return this.measure.getColumn(colId + 1);
3479
3158
  } else {
3480
- throw new import_core9.MusicError(import_core9.MusicErrorType.Score, "Cannot get next column in measure because current column's id in mesure is invalid.");
3159
+ throw new import_core8.MusicError(import_core8.MusicErrorType.Score, "Cannot get next column in measure because current column's id in mesure is invalid.");
3481
3160
  }
3482
3161
  }
3483
3162
  /**
@@ -3579,7 +3258,7 @@ var ObjRhythmColumn = class extends MusicObject {
3579
3258
  getLyricsContainer(verse, line, vpos, lyricsLength) {
3580
3259
  let data = this.lyricsContainers.find((data2) => data2.verse === verse && data2.line === line && data2.vpos === vpos);
3581
3260
  if (data === void 0 && lyricsLength !== void 0) {
3582
- data = { lyricsContainer: new LyricsContainer(this, (0, import_theory6.validateNoteLength)(lyricsLength)), verse, line, vpos };
3261
+ data = { lyricsContainer: new LyricsContainer(this, (0, import_theory5.validateNoteLength)(lyricsLength)), verse, line, vpos };
3583
3262
  this.lyricsContainers.push(data);
3584
3263
  this.requestLayout();
3585
3264
  this.requestRectUpdate();
@@ -3639,7 +3318,7 @@ var ObjRhythmColumn = class extends MusicObject {
3639
3318
  }
3640
3319
  }
3641
3320
  getNoteHeadDisplacement(noteGroup, note) {
3642
- let data = this.noteHeadDisplacements.find((d) => d.noteGroup === noteGroup && import_theory6.Note.equals(d.note, note));
3321
+ let data = this.noteHeadDisplacements.find((d) => d.noteGroup === noteGroup && import_theory5.Note.equals(d.note, note));
3643
3322
  if ((data == null ? void 0 : data.displacement) !== void 0) {
3644
3323
  return data.displacement;
3645
3324
  } else {
@@ -3683,7 +3362,7 @@ var ObjRhythmColumn = class extends MusicObject {
3683
3362
  });
3684
3363
  }
3685
3364
  });
3686
- playerNotes.sort((a, b) => import_theory6.Note.compareFunc(a.note, b.note));
3365
+ playerNotes.sort((a, b) => import_theory5.Note.compareFunc(a.note, b.note));
3687
3366
  if (this.hasArpeggio() && this.getArpeggioDir() === "down" /* Down */) {
3688
3367
  playerNotes.reverse();
3689
3368
  }
@@ -3802,10 +3481,10 @@ var ObjRhythmColumn = class extends MusicObject {
3802
3481
  };
3803
3482
 
3804
3483
  // src/score/engine/extension.ts
3805
- var import_core10 = require("@tspro/web-music-score/core");
3484
+ var import_core9 = require("@tspro/web-music-score/core");
3806
3485
 
3807
3486
  // src/score/engine/element-data.ts
3808
- var import_ts_utils_lib7 = require("@tspro/ts-utils-lib");
3487
+ var import_ts_utils_lib6 = require("@tspro/ts-utils-lib");
3809
3488
 
3810
3489
  // src/score/engine/obj-special-text.ts
3811
3490
  var _ObjSpecialText = class _ObjSpecialText extends MusicObject {
@@ -3927,23 +3606,23 @@ function getNavigationString(navigation) {
3927
3606
  }
3928
3607
  }
3929
3608
  function isDynamicsText(text) {
3930
- return import_ts_utils_lib7.Utils.Is.isEnumValue(text, DynamicsAnnotation);
3609
+ return import_ts_utils_lib6.Utils.Is.isEnumValue(text, DynamicsAnnotation);
3931
3610
  }
3932
3611
  function getDynamicsVolume(text) {
3933
3612
  if (/^(p+|f+|m|mp|mf)$/.test(text)) {
3934
- let volume = 0.5 - import_ts_utils_lib7.Utils.Str.charCount(text, "p") * 0.1 + import_ts_utils_lib7.Utils.Str.charCount(text, "f") * 0.1;
3935
- return import_ts_utils_lib7.Utils.Math.clamp(volume, 0, 1);
3613
+ let volume = 0.5 - import_ts_utils_lib6.Utils.Str.charCount(text, "p") * 0.1 + import_ts_utils_lib6.Utils.Str.charCount(text, "f") * 0.1;
3614
+ return import_ts_utils_lib6.Utils.Math.clamp(volume, 0, 1);
3936
3615
  } else {
3937
3616
  return void 0;
3938
3617
  }
3939
3618
  }
3940
3619
  function isTempoText(text) {
3941
- return import_ts_utils_lib7.Utils.Is.isEnumValue(text, TempoAnnotation);
3620
+ return import_ts_utils_lib6.Utils.Is.isEnumValue(text, TempoAnnotation);
3942
3621
  }
3943
3622
  function getAnnotation(text) {
3944
- if (import_ts_utils_lib7.Utils.Is.isEnumValue(text, DynamicsAnnotation)) {
3623
+ if (import_ts_utils_lib6.Utils.Is.isEnumValue(text, DynamicsAnnotation)) {
3945
3624
  return "dynamics" /* Dynamics */;
3946
- } else if (import_ts_utils_lib7.Utils.Is.isEnumValue(text, TempoAnnotation)) {
3625
+ } else if (import_ts_utils_lib6.Utils.Is.isEnumValue(text, TempoAnnotation)) {
3947
3626
  return "tempo" /* Tempo */;
3948
3627
  } else {
3949
3628
  return void 0;
@@ -3986,7 +3665,7 @@ var Extension = class extends MusicObjectLink {
3986
3665
  if (head instanceof ObjText) {
3987
3666
  head.updateAnchorY(getTextAnchorY(linePos));
3988
3667
  } else {
3989
- throw new import_core10.MusicError(import_core10.MusicErrorType.Score, "Update anchor's y-coordinate is only implemented for text objects.");
3668
+ throw new import_core9.MusicError(import_core9.MusicErrorType.Score, "Update anchor's y-coordinate is only implemented for text objects.");
3990
3669
  }
3991
3670
  }
3992
3671
  isVisible() {
@@ -4066,7 +3745,7 @@ var RitardandoSpeedDiv = 2;
4066
3745
  var CrescendoVolumeAdd = 0.5;
4067
3746
  var DiminuendoVolumeSub = 0.5;
4068
3747
  function calcTicksDuration(ticks, tempo) {
4069
- let beatTicks = import_theory7.RhythmProps.get(tempo.options.beatLength, tempo.options.dotCount).ticks;
3748
+ let beatTicks = import_theory6.RhythmProps.get(tempo.options.beatLength, tempo.options.dotCount).ticks;
4070
3749
  let ticksPerMinute = tempo.beatsPerMinute * beatTicks;
4071
3750
  return 60 * ticks / ticksPerMinute;
4072
3751
  }
@@ -4099,8 +3778,8 @@ var PlayerColumnProps = class {
4099
3778
  return this.speed;
4100
3779
  }
4101
3780
  getTempo() {
4102
- let speed = import_ts_utils_lib8.Utils.Math.clamp(this.getSpeed(), 0.1, 10);
4103
- return (0, import_theory7.alterTempoSpeed)(this.measure.getTempo(), speed);
3781
+ let speed = import_ts_utils_lib7.Utils.Math.clamp(this.getSpeed(), 0.1, 10);
3782
+ return (0, import_theory6.alterTempoSpeed)(this.measure.getTempo(), speed);
4104
3783
  }
4105
3784
  setVolume(volume) {
4106
3785
  this.volume = volume;
@@ -4124,7 +3803,7 @@ var PlayerColumnProps = class {
4124
3803
  if (symbolsTicks.length === 0) {
4125
3804
  return 0;
4126
3805
  } else {
4127
- return import_ts_utils_lib8.Utils.Math.sum(symbolsTicks) / symbolsTicks.length;
3806
+ return import_ts_utils_lib7.Utils.Math.sum(symbolsTicks) / symbolsTicks.length;
4128
3807
  }
4129
3808
  }
4130
3809
  }
@@ -4273,7 +3952,7 @@ var Player = class _Player {
4273
3952
  } else if (layoutObj.musicObj.getLink() instanceof Extension) {
4274
3953
  let extension = layoutObj.musicObj.getLink();
4275
3954
  let { columnRange, extensionBreakText } = extension.getExtensionRangeInfo();
4276
- let totalTicks = import_ts_utils_lib8.Utils.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
3955
+ let totalTicks = import_ts_utils_lib7.Utils.Math.sum(columnRange.map((c) => c.getTicksToNextColumn()));
4277
3956
  switch (text) {
4278
3957
  case "accel." /* accel */: {
4279
3958
  let startSpeed = curSpeed;
@@ -4327,11 +4006,11 @@ var Player = class _Player {
4327
4006
  });
4328
4007
  let speedArr = (_a = speedMap.get(col)) != null ? _a : [];
4329
4008
  if (speedArr.length > 0) {
4330
- curSpeed = import_ts_utils_lib8.Utils.Math.sum(speedArr) / speedArr.length;
4009
+ curSpeed = import_ts_utils_lib7.Utils.Math.sum(speedArr) / speedArr.length;
4331
4010
  }
4332
4011
  let volumeArr = (_b = volumeMap.get(col)) != null ? _b : [];
4333
4012
  if (volumeArr.length > 0) {
4334
- curVolume = import_ts_utils_lib8.Utils.Math.sum(volumeArr) / volumeArr.length;
4013
+ curVolume = import_ts_utils_lib7.Utils.Math.sum(volumeArr) / volumeArr.length;
4335
4014
  }
4336
4015
  col.getPlayerProps().setSpeed(curSpeed);
4337
4016
  col.getPlayerProps().setVolume(curVolume);
@@ -4369,11 +4048,11 @@ var Player = class _Player {
4369
4048
  } else {
4370
4049
  let playerNotes = col.getPlayerNotes();
4371
4050
  playerNotes.forEach((note, i) => {
4372
- let arpeggioDelayTicks = col.hasArpeggio() ? import_theory7.RhythmProps.get(import_theory7.NoteLength.ThirtySecond).ticks * i : 0;
4051
+ let arpeggioDelayTicks = col.hasArpeggio() ? import_theory6.RhythmProps.get(import_theory6.NoteLength.ThirtySecond).ticks * i : 0;
4373
4052
  let noteSeconds = getDuration(note.ticks + fermataHoldTicks - arpeggioDelayTicks, tempo);
4374
4053
  if (noteSeconds > 0) {
4375
4054
  if (note.staccato) {
4376
- noteSeconds = Math.min(getDuration(import_theory7.RhythmProps.get(import_theory7.NoteLength.Eighth).ticks, tempo) / 2, noteSeconds / 2);
4055
+ noteSeconds = Math.min(getDuration(import_theory6.RhythmProps.get(import_theory6.NoteLength.Eighth).ticks, tempo) / 2, noteSeconds / 2);
4377
4056
  }
4378
4057
  let volume = adjustVolume(col.getPlayerProps().getVolume());
4379
4058
  if (note.slur === "slurred") {
@@ -4633,118 +4312,591 @@ var ObjBarLineRight = class extends ObjBarLine {
4633
4312
  getMusicInterface() {
4634
4313
  return this.mi;
4635
4314
  }
4636
- getPlayerProps() {
4637
- return this.playerProps;
4315
+ getPlayerProps() {
4316
+ return this.playerProps;
4317
+ }
4318
+ solveBarLineType() {
4319
+ let m = this.measure;
4320
+ let next = m.getNextMeasure();
4321
+ if (m.hasNavigation("endRepeat" /* EndRepeat */)) {
4322
+ if (next && next.row === m.row && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4323
+ return 6 /* EndStartRepeat */;
4324
+ } else {
4325
+ return 5 /* EndRepeat */;
4326
+ }
4327
+ } else if (!m.doc.hasSingleMeasure() && (m.hasEndSong() || !m.getNextMeasure())) {
4328
+ return 3 /* EndSong */;
4329
+ } else if (m.hasEndSection()) {
4330
+ return 2 /* Double */;
4331
+ }
4332
+ if (m === m.row.getLastMeasure() && next && next.row === m.row.getNextRow() && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4333
+ return 2 /* Double */;
4334
+ }
4335
+ if (next && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4336
+ return 0 /* None */;
4337
+ }
4338
+ return 1 /* Single */;
4339
+ }
4340
+ };
4341
+
4342
+ // src/score/engine/obj-ending.ts
4343
+ var import_ts_utils_lib8 = require("@tspro/ts-utils-lib");
4344
+ var import_core10 = require("@tspro/web-music-score/core");
4345
+ var ObjEnding = class extends MusicObject {
4346
+ constructor(measure, passages) {
4347
+ super(measure);
4348
+ this.measure = measure;
4349
+ this.passages = passages;
4350
+ __publicField(this, "endingText");
4351
+ __publicField(this, "shapeRects", []);
4352
+ __publicField(this, "mi");
4353
+ this.mi = new MEnding(this);
4354
+ if (!import_ts_utils_lib8.Utils.Is.isIntegerGte(passages.length, 1)) {
4355
+ throw new import_core10.MusicError(import_core10.MusicErrorType.Score, "Passages is empty.");
4356
+ } else if (!this.passages.every((p) => import_ts_utils_lib8.Utils.Is.isIntegerGte(p, 1))) {
4357
+ throw new import_core10.MusicError(import_core10.MusicErrorType.Score, "Invalid passages: " + this.passages);
4358
+ }
4359
+ this.passages.sort((a, b) => a - b);
4360
+ let text = this.passages.map((p) => p + ".").join("");
4361
+ this.endingText = new ObjText(this, text, 0, 1);
4362
+ }
4363
+ getMusicInterface() {
4364
+ return this.mi;
4365
+ }
4366
+ getShapeRects() {
4367
+ return this.shapeRects;
4368
+ }
4369
+ isSingleMeasureEnding() {
4370
+ let { measure } = this;
4371
+ let next = measure.getNextMeasure();
4372
+ return (next == null ? void 0 : next.hasNavigation("ending" /* Ending */)) === true || measure.hasNavigation("endRepeat" /* EndRepeat */) || measure.isLastMeasure();
4373
+ }
4374
+ hasPassage(pass) {
4375
+ return this.passages.some((p) => p === pass);
4376
+ }
4377
+ getHighestPassage() {
4378
+ return Math.max(0, ...this.passages);
4379
+ }
4380
+ pick(x, y) {
4381
+ return this.rect.contains(x, y) ? [this] : [];
4382
+ }
4383
+ layout(renderer) {
4384
+ this.rect = new DivRect();
4385
+ this.shapeRects = [this.rect.copy()];
4386
+ }
4387
+ layoutFitToMeasure(renderer) {
4388
+ let { unitSize } = renderer;
4389
+ let { measure } = this;
4390
+ this.endingText.layout(renderer);
4391
+ let textRect = this.endingText.getRect();
4392
+ let measureContent = measure.getColumnsContentRect();
4393
+ let endingHeight = textRect.height;
4394
+ this.rect = new DivRect(measureContent.left + unitSize, measureContent.right - unitSize, -endingHeight, 0);
4395
+ this.endingText.offset(this.rect.left + unitSize / 2, this.rect.bottom);
4396
+ this.shapeRects = [
4397
+ new DivRect(this.rect.left, this.rect.left + 1, this.rect.top, this.rect.bottom),
4398
+ new DivRect(this.rect.left, this.rect.right, this.rect.top, this.rect.top + 1),
4399
+ new DivRect(this.rect.right - 1, this.rect.right, this.rect.top, this.rect.bottom),
4400
+ this.endingText.getRect().copy()
4401
+ ];
4402
+ }
4403
+ offset(dx, dy) {
4404
+ this.endingText.offset(dx, dy);
4405
+ this.shapeRects.forEach((r) => r.offsetInPlace(dx, dy));
4406
+ this.rect.offsetInPlace(dx, dy);
4407
+ }
4408
+ draw(renderer) {
4409
+ let ctx = renderer.getCanvasContext();
4410
+ if (!ctx) {
4411
+ return;
4412
+ }
4413
+ let { lineWidth } = renderer;
4414
+ let { rect } = this;
4415
+ renderer.drawDebugRect(this.rect);
4416
+ ctx.strokeStyle = ctx.fillStyle = "black";
4417
+ ctx.lineWidth = lineWidth;
4418
+ ctx.beginPath();
4419
+ ctx.moveTo(rect.left, rect.bottom);
4420
+ ctx.lineTo(rect.left, rect.top);
4421
+ ctx.lineTo(rect.right, rect.top);
4422
+ if (this.isSingleMeasureEnding()) {
4423
+ ctx.lineTo(rect.right, rect.bottom);
4424
+ }
4425
+ ctx.stroke();
4426
+ this.endingText.draw(renderer);
4427
+ }
4428
+ };
4429
+
4430
+ // src/score/engine/obj-beam-group.ts
4431
+ var import_ts_utils_lib9 = require("@tspro/ts-utils-lib");
4432
+ var import_theory7 = require("@tspro/web-music-score/theory");
4433
+ var import_core11 = require("@tspro/web-music-score/core");
4434
+ var adjustBeamAngle = (dx, dy) => {
4435
+ let T = DocumentSettings.BeamAngleFactor;
4436
+ if (!Number.isFinite(T) || T === 0) {
4437
+ return dy;
4438
+ } else {
4439
+ let k = dx / dy / T;
4440
+ k = Math.sign(k) * Math.sqrt(Math.abs(k));
4441
+ return dx / k * T;
4442
+ }
4443
+ };
4444
+ var BeamPoint = class {
4445
+ constructor(staff, beamGroup, symbol, x, y) {
4446
+ this.staff = staff;
4447
+ this.beamGroup = beamGroup;
4448
+ this.symbol = symbol;
4449
+ this.x = x;
4450
+ this.y = y;
4451
+ __publicField(this, "topBeamsHeight", 0);
4452
+ __publicField(this, "bottomBeamsHeight", 0);
4453
+ staff.addObject(this);
4454
+ }
4455
+ offset(dx, dy) {
4456
+ this.x += dx;
4457
+ this.y += dy;
4458
+ this.beamGroup.requestRectUpdate();
4459
+ }
4460
+ getRect() {
4461
+ return new DivRect(this.x, this.x, this.x, this.y - this.topBeamsHeight, this.y, this.y + this.bottomBeamsHeight);
4462
+ }
4463
+ };
4464
+ var ObjStaffBeamGroup = class extends MusicObject {
4465
+ constructor(staff, beamGroup) {
4466
+ super(staff);
4467
+ this.staff = staff;
4468
+ this.beamGroup = beamGroup;
4469
+ __publicField(this, "tupletNumber");
4470
+ __publicField(this, "tupletNumberOffsetY", 0);
4471
+ __publicField(this, "points", []);
4472
+ __publicField(this, "mi");
4473
+ staff.addObject(this);
4474
+ this.mi = new MStaffBeamGroup(this);
4475
+ }
4476
+ getMusicInterface() {
4477
+ return this.mi;
4478
+ }
4479
+ pick(x, y) {
4480
+ return this.getRect().contains(x, y) ? [this] : [];
4481
+ }
4482
+ offset(dx, dy) {
4483
+ var _a;
4484
+ this.points.forEach((p) => p.offset(dx, 0));
4485
+ (_a = this.tupletNumber) == null ? void 0 : _a.offset(dx, dy);
4486
+ this.requestRectUpdate();
4487
+ this.beamGroup.requestRectUpdate();
4488
+ }
4489
+ updateRect() {
4490
+ if (this.points.length > 0) {
4491
+ this.rect = this.points[0].getRect().copy();
4492
+ } else if (this.tupletNumber) {
4493
+ this.rect = this.tupletNumber.getRect().copy();
4494
+ }
4495
+ this.points.forEach((pt) => this.rect.expandInPlace(pt.getRect()));
4496
+ if (this.tupletNumber) {
4497
+ this.rect.expandInPlace(this.tupletNumber.getRect());
4498
+ }
4499
+ }
4500
+ };
4501
+ var ObjBeamGroup = class _ObjBeamGroup extends MusicObject {
4502
+ constructor(symbols, tupletRatio) {
4503
+ super(symbols[0].measure);
4504
+ this.symbols = symbols;
4505
+ this.tupletRatio = tupletRatio;
4506
+ __publicField(this, "mi");
4507
+ __publicField(this, "type");
4508
+ __publicField(this, "staffObjects", []);
4509
+ this.mi = new MBeamGroup(this);
4510
+ let beamGroupName = tupletRatio ? "Tuplet" : "BeamGroup";
4511
+ if (!symbols.every((s) => s.measure === symbols[0].measure)) {
4512
+ throw new import_core11.MusicError(import_core11.MusicErrorType.Score, `All ${beamGroupName} symbols are not in same measure.`);
4513
+ } else if (symbols.length < 2) {
4514
+ throw new import_core11.MusicError(import_core11.MusicErrorType.Score, `${beamGroupName} needs minimum 2 symbols, but ${symbols.length} given.`);
4515
+ }
4516
+ if (tupletRatio !== void 0) {
4517
+ let isGroup = symbols.length < 3 || symbols.some((s) => !(s instanceof ObjNoteGroup)) || symbols.some((s) => s.rhythmProps.flagCount !== symbols[0].rhythmProps.flagCount);
4518
+ if (symbols.length >= 3 && symbols[0] instanceof ObjNoteGroup && symbols[symbols.length - 1] instanceof ObjNoteGroup && symbols[0].rhythmProps.flagCount === symbols[symbols.length - 1].rhythmProps.flagCount) {
4519
+ isGroup = false;
4520
+ }
4521
+ if (symbols.some((s) => import_theory7.NoteLengthProps.cmp(s.rhythmProps.noteLength, import_theory7.NoteLength.Quarter) >= 0)) {
4522
+ isGroup = true;
4523
+ }
4524
+ this.type = isGroup ? 2 /* TupletGroup */ : 1 /* TupletBeam */;
4525
+ this.setTupletBeamCounts();
4526
+ } else {
4527
+ this.type = 0 /* RegularBeam */;
4528
+ this.setBeamCounts();
4529
+ }
4530
+ if (symbols.every((s) => s.getBeamGroup() === void 0)) {
4531
+ symbols.forEach((s) => s.setBeamGroup(this));
4532
+ symbols[0].measure.addBeamGroup(this);
4533
+ } else {
4534
+ throw new import_core11.MusicError(import_core11.MusicErrorType.Score, `Cannot add ${beamGroupName} because some symbol already has one.`);
4535
+ }
4536
+ if (this.type === 0 /* RegularBeam */) {
4537
+ this.symbols.filter((sym) => sym instanceof ObjNoteGroup).some((sym, i) => {
4538
+ let first = i === 0;
4539
+ let last = i === this.symbols.length - 1;
4540
+ if (first && sym.getRightBeamCount() === 0 || last && sym.getLeftBeamCount() === 0 || !first && !last && (sym.getLeftBeamCount() === 0 || sym.getRightBeamCount() === 0)) {
4541
+ this.detach();
4542
+ }
4543
+ });
4544
+ }
4545
+ }
4546
+ get showTupletRatio() {
4547
+ var _a;
4548
+ return ((_a = this.tupletRatio) == null ? void 0 : _a.showRatio) === true;
4549
+ }
4550
+ static createBeam(noteGroups) {
4551
+ if (noteGroups.length > 1 && noteGroups.every((ng) => !ng.hasTuplet())) {
4552
+ new _ObjBeamGroup(noteGroups, void 0);
4553
+ }
4554
+ }
4555
+ static createOldStyleTriplet(symbols) {
4556
+ let s2 = symbols.slice(0, 2);
4557
+ let n2 = s2.map((s) => s.rhythmProps.noteSize);
4558
+ if (s2.length === 2 && s2.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && (n2[0] * 2 === n2[1] || n2[1] * 2 === n2[0])) {
4559
+ new _ObjBeamGroup(s2, import_theory7.Tuplet.Triplet);
4560
+ return 2;
4561
+ }
4562
+ let s3 = symbols.slice(0, 3);
4563
+ let n3 = s3.map((s) => s.rhythmProps.noteSize);
4564
+ if (s3.length === 3 && s3.every((s) => s.oldStyleTriplet && s.getBeamGroup() === void 0) && n3.every((n) => n === n3[0])) {
4565
+ new _ObjBeamGroup(s3, import_theory7.Tuplet.Triplet);
4566
+ return 3;
4567
+ }
4568
+ return 0;
4569
+ }
4570
+ static createTuplet(symbols, tupletRatio) {
4571
+ new _ObjBeamGroup(symbols, tupletRatio);
4572
+ }
4573
+ getMusicInterface() {
4574
+ return this.mi;
4575
+ }
4576
+ detach() {
4577
+ this.getSymbols().forEach((s) => s.resetBeamGroup());
4638
4578
  }
4639
- solveBarLineType() {
4640
- let m = this.measure;
4641
- let next = m.getNextMeasure();
4642
- if (m.hasNavigation("endRepeat" /* EndRepeat */)) {
4643
- if (next && next.row === m.row && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4644
- return 6 /* EndStartRepeat */;
4645
- } else {
4646
- return 5 /* EndRepeat */;
4647
- }
4648
- } else if (!m.doc.hasSingleMeasure() && (m.hasEndSong() || !m.getNextMeasure())) {
4649
- return 3 /* EndSong */;
4650
- } else if (m.hasEndSection()) {
4651
- return 2 /* Double */;
4652
- }
4653
- if (m === m.row.getLastMeasure() && next && next.row === m.row.getNextRow() && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4654
- return 2 /* Double */;
4579
+ isEmpty() {
4580
+ return this.staffObjects.length === 0;
4581
+ }
4582
+ pick(x, y) {
4583
+ if (!this.getRect().contains(x, y)) {
4584
+ return [];
4655
4585
  }
4656
- if (next && next.hasNavigation("startRepeat" /* StartRepeat */)) {
4657
- return 0 /* None */;
4586
+ for (let i = 0; i < this.staffObjects.length; i++) {
4587
+ let arr = this.staffObjects[i].pick(x, y);
4588
+ if (arr.length > 0) {
4589
+ return [this, ...arr];
4590
+ }
4658
4591
  }
4659
- return 1 /* Single */;
4592
+ return [this];
4660
4593
  }
4661
- };
4662
-
4663
- // src/score/engine/obj-ending.ts
4664
- var import_ts_utils_lib9 = require("@tspro/ts-utils-lib");
4665
- var import_core11 = require("@tspro/web-music-score/core");
4666
- var ObjEnding = class extends MusicObject {
4667
- constructor(measure, passages) {
4668
- super(measure);
4669
- this.measure = measure;
4670
- this.passages = passages;
4671
- __publicField(this, "endingText");
4672
- __publicField(this, "shapeRects", []);
4673
- __publicField(this, "mi");
4674
- this.mi = new MEnding(this);
4675
- if (!import_ts_utils_lib9.Utils.Is.isIntegerGte(passages.length, 1)) {
4676
- throw new import_core11.MusicError(import_core11.MusicErrorType.Score, "Passages is empty.");
4677
- } else if (!this.passages.every((p) => import_ts_utils_lib9.Utils.Is.isIntegerGte(p, 1))) {
4678
- throw new import_core11.MusicError(import_core11.MusicErrorType.Score, "Invalid passages: " + this.passages);
4679
- }
4680
- this.passages.sort((a, b) => a - b);
4681
- let text = this.passages.map((p) => p + ".").join("");
4682
- this.endingText = new ObjText(this, text, 0, 1);
4594
+ getType() {
4595
+ return this.type;
4683
4596
  }
4684
- getMusicInterface() {
4685
- return this.mi;
4597
+ isTuplet() {
4598
+ return this.type === 1 /* TupletBeam */ || this.type === 2 /* TupletGroup */;
4686
4599
  }
4687
- getShapeRects() {
4688
- return this.shapeRects;
4600
+ getTupletRatioText() {
4601
+ var _a, _b, _c;
4602
+ 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);
4689
4603
  }
4690
- isSingleMeasureEnding() {
4691
- let { measure } = this;
4692
- let next = measure.getNextMeasure();
4693
- return (next == null ? void 0 : next.hasNavigation("ending" /* Ending */)) === true || measure.hasNavigation("endRepeat" /* EndRepeat */) || measure.isLastMeasure();
4604
+ getSymbols() {
4605
+ return this.symbols;
4694
4606
  }
4695
- hasPassage(pass) {
4696
- return this.passages.some((p) => p === pass);
4607
+ getFirstSymbol() {
4608
+ return this.symbols[0];
4697
4609
  }
4698
- getHighestPassage() {
4699
- return Math.max(0, ...this.passages);
4610
+ getLastSymbol() {
4611
+ return this.symbols[this.symbols.length - 1];
4700
4612
  }
4701
- pick(x, y) {
4702
- return this.rect.contains(x, y) ? [this] : [];
4613
+ get stemDir() {
4614
+ return this.symbols[0].ownStemDir;
4703
4615
  }
4704
4616
  layout(renderer) {
4705
- this.rect = new DivRect();
4706
- this.shapeRects = [this.rect.copy()];
4707
- }
4708
- layoutFitToMeasure(renderer) {
4617
+ this.requestRectUpdate();
4618
+ this.staffObjects.length = 0;
4619
+ let symbols = this.getSymbols();
4620
+ if (symbols.length === 0) {
4621
+ return;
4622
+ }
4623
+ let voiceId = symbols[0].voiceId;
4624
+ if (symbols.some((symbol) => symbol.voiceId !== voiceId)) {
4625
+ return;
4626
+ }
4709
4627
  let { unitSize } = renderer;
4710
- let { measure } = this;
4711
- this.endingText.layout(renderer);
4712
- let textRect = this.endingText.getRect();
4713
- let measureContent = measure.getColumnsContentRect();
4714
- let endingHeight = textRect.height;
4715
- this.rect = new DivRect(measureContent.left + unitSize, measureContent.right - unitSize, -endingHeight, 0);
4716
- this.endingText.offset(this.rect.left + unitSize / 2, this.rect.bottom);
4717
- this.shapeRects = [
4718
- new DivRect(this.rect.left, this.rect.left + 1, this.rect.top, this.rect.bottom),
4719
- new DivRect(this.rect.left, this.rect.right, this.rect.top, this.rect.top + 1),
4720
- new DivRect(this.rect.right - 1, this.rect.right, this.rect.top, this.rect.bottom),
4721
- this.endingText.getRect().copy()
4722
- ];
4628
+ let { stemDir } = this;
4629
+ let symbolsBeamCoords = symbols.map((s) => s.getBeamCoords());
4630
+ symbolsBeamCoords[0].map((s) => s == null ? void 0 : s.staff).forEach((mainStaff, index) => {
4631
+ var _a, _b;
4632
+ if (!mainStaff) {
4633
+ return;
4634
+ }
4635
+ let symbolX = symbolsBeamCoords.map((s) => {
4636
+ var _a2;
4637
+ return (_a2 = s[index]) == null ? void 0 : _a2.x;
4638
+ });
4639
+ let symbolY = symbolsBeamCoords.map((s) => {
4640
+ var _a2;
4641
+ return (_a2 = s[index]) == null ? void 0 : _a2.y;
4642
+ });
4643
+ let symbolStaff = symbolsBeamCoords.map((s) => {
4644
+ var _a2;
4645
+ return (_a2 = s[index]) == null ? void 0 : _a2.staff;
4646
+ });
4647
+ let symbolStemHeight = symbolsBeamCoords.map((s) => {
4648
+ var _a2;
4649
+ return (_a2 = s[index]) == null ? void 0 : _a2.stemHeight;
4650
+ });
4651
+ let leftSymbol = symbols[0];
4652
+ let leftX = symbolX[0];
4653
+ let leftY = symbolY[0];
4654
+ let leftStaff = symbolStaff[0];
4655
+ let rightSymbol = symbols[symbols.length - 1];
4656
+ let rightX = symbolX[symbolX.length - 1];
4657
+ let rightY = symbolY[symbolY.length - 1];
4658
+ let rightStaff = symbolStaff[symbolY.length - 1];
4659
+ if (leftX === void 0 || leftY === void 0 || leftStaff === void 0 || rightX === void 0 || rightY === void 0 || rightStaff === void 0) {
4660
+ return;
4661
+ }
4662
+ let leftStemHeight = (_a = symbolStemHeight[0]) != null ? _a : 0;
4663
+ let rightStemHeight = (_b = symbolStemHeight[symbolStemHeight.length - 1]) != null ? _b : 0;
4664
+ if (this.type !== 2 /* TupletGroup */) {
4665
+ let leftDy = leftStemHeight < rightStemHeight ? Math.sqrt(rightStemHeight - leftStemHeight) : 0;
4666
+ let rightDy = rightStemHeight < leftStemHeight ? Math.sqrt(leftStemHeight - rightStemHeight) : 0;
4667
+ if (stemDir === "up" /* Up */) {
4668
+ leftDy *= -1;
4669
+ rightDy *= -1;
4670
+ }
4671
+ if (leftDy !== 0) {
4672
+ leftY += leftDy;
4673
+ symbolY[0] += leftDy;
4674
+ }
4675
+ if (rightDy !== 0) {
4676
+ rightY += rightDy;
4677
+ symbolY[symbolY.length - 1] += rightDy;
4678
+ }
4679
+ }
4680
+ let groupLineDy = unitSize * 2 * (stemDir === "up" /* Up */ ? -1 : 1);
4681
+ let centerY = (rightY + leftY) / 2;
4682
+ let halfDy = adjustBeamAngle(rightX - leftX, rightY - leftY) / 2;
4683
+ leftY = centerY - halfDy;
4684
+ rightY = centerY + halfDy;
4685
+ let raiseBeamY = 0;
4686
+ symbolY.forEach((symY, i) => {
4687
+ let symX = symbolX[i];
4688
+ if (symX !== void 0 && symY !== void 0) {
4689
+ let beamY = import_ts_utils_lib9.Utils.Math.interpolateY(leftX, leftY, rightX, rightY, symX);
4690
+ let raiseY = symY - beamY;
4691
+ if (stemDir === "up" /* Up */ && raiseY < 0) {
4692
+ raiseBeamY = Math.min(raiseBeamY, raiseY);
4693
+ } else if (stemDir === "down" /* Down */ && raiseY > 0) {
4694
+ raiseBeamY = Math.max(raiseBeamY, raiseY);
4695
+ }
4696
+ }
4697
+ });
4698
+ leftY += raiseBeamY;
4699
+ rightY += raiseBeamY;
4700
+ symbolY = symbolY.map((y) => y === void 0 ? void 0 : y + raiseBeamY);
4701
+ let obj = new ObjStaffBeamGroup(mainStaff, this);
4702
+ if (this.type === 2 /* TupletGroup */) {
4703
+ let ef = unitSize / (rightX - leftX);
4704
+ let l = import_ts_utils_lib9.Utils.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, -ef);
4705
+ let r = import_ts_utils_lib9.Utils.Math.interpolateCoord(leftX, leftY + groupLineDy, rightX, rightY + groupLineDy, 1 + ef);
4706
+ obj.points.push(new BeamPoint(leftStaff, this, leftSymbol, l.x, l.y));
4707
+ obj.points.push(new BeamPoint(rightStaff, this, rightSymbol, r.x, r.y));
4708
+ obj.tupletNumberOffsetY = 0;
4709
+ } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
4710
+ raiseBeamY *= 0.5;
4711
+ let { beamThickness } = renderer;
4712
+ const beamHeight = (i) => {
4713
+ let sym = symbols[i];
4714
+ if (sym instanceof ObjNoteGroup) {
4715
+ let beamCount = sym instanceof ObjNoteGroup ? Math.max(sym.getLeftBeamCount(), sym.getRightBeamCount()) : 0;
4716
+ return DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? beamCount - 1 : 0);
4717
+ } else {
4718
+ return 0;
4719
+ }
4720
+ };
4721
+ symbols.forEach((sym, i) => {
4722
+ let symStaff = symbolStaff[i];
4723
+ let symX = symbolX[i];
4724
+ let symY = symbolY[i];
4725
+ if (symStaff && symX !== void 0 && symY !== void 0) {
4726
+ let pt = new BeamPoint(symStaff, this, sym, symX, symY);
4727
+ pt.topBeamsHeight = beamThickness / 2 + (stemDir === "down" /* Down */ ? beamHeight(i) : 0);
4728
+ pt.bottomBeamsHeight = beamThickness / 2 + (stemDir === "up" /* Up */ ? beamHeight(i) : 0);
4729
+ obj.points.push(pt);
4730
+ }
4731
+ });
4732
+ obj.tupletNumberOffsetY = groupLineDy;
4733
+ }
4734
+ if (this.isTuplet()) {
4735
+ obj.tupletNumber = new ObjText(this, this.getTupletRatioText(), 0.5, 0.5);
4736
+ obj.tupletNumber.layout(renderer);
4737
+ obj.tupletNumber.offset((leftX + rightX) / 2, (leftY + rightY) / 2 + obj.tupletNumberOffsetY);
4738
+ }
4739
+ if (obj.points.length >= 2) {
4740
+ this.staffObjects.push(obj);
4741
+ }
4742
+ });
4723
4743
  }
4724
- offset(dx, dy) {
4725
- this.endingText.offset(dx, dy);
4726
- this.shapeRects.forEach((r) => r.offsetInPlace(dx, dy));
4727
- this.rect.offsetInPlace(dx, dy);
4744
+ updateRect() {
4745
+ if (this.staffObjects.length === 0) {
4746
+ this.rect = new DivRect();
4747
+ } else {
4748
+ this.staffObjects.forEach((obj) => obj.updateRect());
4749
+ this.rect = this.staffObjects[0].getRect().copy();
4750
+ for (let i = 1; i < this.staffObjects.length; i++) {
4751
+ this.rect.expandInPlace(this.staffObjects[i].getRect());
4752
+ }
4753
+ }
4754
+ }
4755
+ updateStemTips() {
4756
+ this.staffObjects.forEach((obj) => {
4757
+ let left = obj.points[0];
4758
+ let right = obj.points[obj.points.length - 1];
4759
+ if (this.type !== 2 /* TupletGroup */) {
4760
+ obj.points.forEach((pt) => {
4761
+ if (pt.symbol instanceof ObjNoteGroup) {
4762
+ if (pt !== left && pt !== right) {
4763
+ pt.y = import_ts_utils_lib9.Utils.Math.interpolateY(left.x, left.y, right.x, right.y, pt.x);
4764
+ }
4765
+ pt.symbol.setStemTipY(pt.staff, pt.y);
4766
+ }
4767
+ });
4768
+ }
4769
+ if (obj.tupletNumber) {
4770
+ let y = (left.y + right.y) / 2 + obj.tupletNumberOffsetY;
4771
+ obj.tupletNumber.offset(0, -obj.tupletNumber.getRect().centerY + y);
4772
+ }
4773
+ });
4774
+ }
4775
+ offset(dx, dy) {
4776
+ this.staffObjects.forEach((obj) => obj.offset(dx, 0));
4777
+ this.requestRectUpdate();
4728
4778
  }
4729
4779
  draw(renderer) {
4730
- let ctx = renderer.getCanvasContext();
4731
- if (!ctx) {
4732
- return;
4780
+ let { unitSize, beamThickness, lineWidth } = renderer;
4781
+ let color = "black";
4782
+ this.staffObjects.forEach((obj) => {
4783
+ if (this.type === 2 /* TupletGroup */) {
4784
+ let l = obj.points[0];
4785
+ let r = obj.points[obj.points.length - 1];
4786
+ if (l && r) {
4787
+ let tf = obj.tupletNumber ? obj.tupletNumber.getRect().width / (r.x - l.x) * 1.2 : 0;
4788
+ let lc = import_ts_utils_lib9.Utils.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 - tf / 2);
4789
+ let rc = import_ts_utils_lib9.Utils.Math.interpolateCoord(l.x, l.y, r.x, r.y, 0.5 + tf / 2);
4790
+ let tipH = this.stemDir === "up" /* Up */ ? unitSize : -unitSize;
4791
+ renderer.drawLine(l.x, l.y, lc.x, lc.y, color, lineWidth);
4792
+ renderer.drawLine(rc.x, rc.y, r.x, r.y, color, lineWidth);
4793
+ renderer.drawLine(l.x, l.y, l.x, l.y + tipH, color, lineWidth);
4794
+ renderer.drawLine(r.x, r.y, r.x, r.y + tipH, color, lineWidth);
4795
+ }
4796
+ } else if (this.type === 0 /* RegularBeam */ || this.type === 1 /* TupletBeam */) {
4797
+ let beamSeparation = DocumentSettings.BeamSeparation * unitSize * (this.stemDir === "up" /* Up */ ? 1 : -1);
4798
+ let noteGroupPoints = obj.points.filter((p) => p.symbol instanceof ObjNoteGroup);
4799
+ for (let i = 0; i < noteGroupPoints.length - 1; i++) {
4800
+ let left = noteGroupPoints[i];
4801
+ let right = noteGroupPoints[i + 1];
4802
+ if (!(left.symbol instanceof ObjNoteGroup && right.symbol instanceof ObjNoteGroup)) {
4803
+ continue;
4804
+ }
4805
+ let leftBeamCount = left.symbol.getRightBeamCount();
4806
+ let rightBeamCount = right.symbol.getLeftBeamCount();
4807
+ let lx = left.x;
4808
+ let ly = left.y;
4809
+ let rx = right.x;
4810
+ let ry = right.y;
4811
+ let dy = beamSeparation * (1 + 0.5 * Math.abs(Math.atan2(ry - ly, rx - lx)));
4812
+ for (let beamId = 0; beamId < Math.max(leftBeamCount, rightBeamCount); beamId++) {
4813
+ if (beamId < leftBeamCount && beamId < rightBeamCount) {
4814
+ renderer.drawLine(lx, ly, rx, ry, color, beamThickness);
4815
+ } else if (leftBeamCount > rightBeamCount) {
4816
+ renderer.drawPartialLine(lx, ly, rx, ry, 0, 0.25, color, beamThickness);
4817
+ } else if (rightBeamCount > leftBeamCount) {
4818
+ renderer.drawPartialLine(lx, ly, rx, ry, 0.75, 1, color, beamThickness);
4819
+ }
4820
+ ly += dy;
4821
+ ry += dy;
4822
+ }
4823
+ }
4824
+ }
4825
+ if (obj.tupletNumber) {
4826
+ obj.tupletNumber.draw(renderer);
4827
+ }
4828
+ });
4829
+ }
4830
+ setBeamCounts() {
4831
+ const isADottedBHalf = (a, b) => {
4832
+ let { flagCount: aFlagCount, noteSize: aNoteSize, dotCount: aDotCount } = a.rhythmProps;
4833
+ let { flagCount: bFlagCount, noteSize: bNoteSize, dotCount: bDotCount } = b.rhythmProps;
4834
+ return aFlagCount > 0 && bFlagCount > 0 && aDotCount > 0 && bDotCount === 0 && aNoteSize * Math.pow(2, aDotCount) === bNoteSize;
4835
+ };
4836
+ let groupNotes = this.symbols.filter((s) => s instanceof ObjNoteGroup);
4837
+ for (let i = 0; i < groupNotes.length; i++) {
4838
+ let center = groupNotes[i];
4839
+ let left = groupNotes[i - 1];
4840
+ let right = groupNotes[i + 1];
4841
+ if (center) {
4842
+ center.setLeftBeamCount(0);
4843
+ center.setRightBeamCount(0);
4844
+ if (left) {
4845
+ if (left.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(left, center) || isADottedBHalf(center, left)) {
4846
+ center.setLeftBeamCount(center.rhythmProps.flagCount);
4847
+ } else {
4848
+ center.setLeftBeamCount(Math.min(left.rhythmProps.flagCount, center.rhythmProps.flagCount));
4849
+ }
4850
+ }
4851
+ if (right) {
4852
+ if (right.rhythmProps.flagCount === center.rhythmProps.flagCount || isADottedBHalf(right, center) || isADottedBHalf(center, right)) {
4853
+ center.setRightBeamCount(center.rhythmProps.flagCount);
4854
+ } else {
4855
+ center.setRightBeamCount(Math.min(right.rhythmProps.flagCount, center.rhythmProps.flagCount));
4856
+ }
4857
+ }
4858
+ }
4733
4859
  }
4734
- let { lineWidth } = renderer;
4735
- let { rect } = this;
4736
- renderer.drawDebugRect(this.rect);
4737
- ctx.strokeStyle = ctx.fillStyle = "black";
4738
- ctx.lineWidth = lineWidth;
4739
- ctx.beginPath();
4740
- ctx.moveTo(rect.left, rect.bottom);
4741
- ctx.lineTo(rect.left, rect.top);
4742
- ctx.lineTo(rect.right, rect.top);
4743
- if (this.isSingleMeasureEnding()) {
4744
- ctx.lineTo(rect.right, rect.bottom);
4860
+ let fixAgain;
4861
+ do {
4862
+ fixAgain = false;
4863
+ for (let i = 0; i < groupNotes.length; i++) {
4864
+ let center = groupNotes[i];
4865
+ let left = groupNotes[i - 1];
4866
+ let right = groupNotes[i + 1];
4867
+ if (center && center.getLeftBeamCount() !== center.rhythmProps.flagCount && center.getRightBeamCount() !== center.rhythmProps.flagCount) {
4868
+ center.setLeftBeamCount(0);
4869
+ center.setRightBeamCount(0);
4870
+ if (left && left.getRightBeamCount() > 0) {
4871
+ left.setRightBeamCount(0);
4872
+ fixAgain = true;
4873
+ }
4874
+ if (right && right.getLeftBeamCount() > 0) {
4875
+ right.setLeftBeamCount(0);
4876
+ fixAgain = true;
4877
+ }
4878
+ }
4879
+ }
4880
+ } while (fixAgain);
4881
+ }
4882
+ setTupletBeamCounts() {
4883
+ let type = this.getType();
4884
+ let symbols = this.getSymbols();
4885
+ if (type === 1 /* TupletBeam */) {
4886
+ symbols.forEach((s, i) => {
4887
+ if (s instanceof ObjNoteGroup) {
4888
+ s.setLeftBeamCount(i === 0 ? 0 : s.rhythmProps.flagCount);
4889
+ s.setRightBeamCount(i === symbols.length - 1 ? 0 : s.rhythmProps.flagCount);
4890
+ }
4891
+ });
4892
+ } else if (type === 2 /* TupletGroup */) {
4893
+ symbols.forEach((s) => {
4894
+ if (s instanceof ObjNoteGroup) {
4895
+ s.setLeftBeamCount(0);
4896
+ s.setRightBeamCount(0);
4897
+ }
4898
+ });
4745
4899
  }
4746
- ctx.stroke();
4747
- this.endingText.draw(renderer);
4748
4900
  }
4749
4901
  };
4750
4902
 
@@ -5189,8 +5341,147 @@ var ConnectiveProps = class {
5189
5341
  }
5190
5342
  };
5191
5343
 
5344
+ // src/score/engine/obj-tab-rhythm.ts
5345
+ var import_ts_utils_lib12 = require("@tspro/ts-utils-lib");
5346
+ var ObjTabRhythm = class extends MusicObject {
5347
+ constructor(measure, tab) {
5348
+ super(measure);
5349
+ this.measure = measure;
5350
+ this.tab = tab;
5351
+ __publicField(this, "voiceIds");
5352
+ __publicField(this, "mi");
5353
+ // Keep non-static
5354
+ __publicField(this, "tupletPartsTextObjMap", /* @__PURE__ */ new Map());
5355
+ this.voiceIds = getVoiceIds().filter((voiceId) => tab.containsVoiceId(voiceId));
5356
+ this.rect = new DivRect();
5357
+ this.mi = new MTabRhythm(this);
5358
+ }
5359
+ getMusicInterface() {
5360
+ return this.mi;
5361
+ }
5362
+ pick(x, y) {
5363
+ return this.rect.contains(x, y) ? [this] : [];
5364
+ }
5365
+ layout(renderer) {
5366
+ let columns = this.measure.getColumns();
5367
+ let numColsInVoiceId = getVoiceIds().map((voiceId) => import_ts_utils_lib12.Utils.Math.sum(columns.map((col) => col.getVoiceSymbol(voiceId) ? 1 : 0)));
5368
+ this.voiceIds.sort((a, b) => import_ts_utils_lib12.Utils.Math.cmp(numColsInVoiceId[a], numColsInVoiceId[b]));
5369
+ this.rect = new DivRect();
5370
+ }
5371
+ hasTuplets() {
5372
+ return this.measure.getBeamGroups().some((beamGroup) => beamGroup.isTuplet());
5373
+ }
5374
+ layoutFitToMeasure(renderer) {
5375
+ let { unitSize, fontSize } = renderer;
5376
+ let { measure } = this;
5377
+ let { left, right } = measure.getColumnsContentRect();
5378
+ let stemHeight = unitSize * 5;
5379
+ this.rect.left = left;
5380
+ this.rect.centerX = (left + right) / 2;
5381
+ this.rect.right = right;
5382
+ this.rect.top = this.hasTuplets() ? -fontSize : 0;
5383
+ this.rect.centerY = 0;
5384
+ this.rect.bottom = stemHeight;
5385
+ }
5386
+ offset(dx, dy) {
5387
+ this.rect.offsetInPlace(dx, dy);
5388
+ }
5389
+ draw(renderer) {
5390
+ const ctx = renderer.getCanvasContext();
5391
+ if (!ctx) {
5392
+ return;
5393
+ }
5394
+ renderer.drawDebugRect(this.rect);
5395
+ let { unitSize, lineWidth, fontSize } = renderer;
5396
+ let flagSize = unitSize;
5397
+ let dotSpace = unitSize;
5398
+ let dotWidth = unitSize * 0.25;
5399
+ let { bottom, centerY } = this.getRect();
5400
+ let stemTop = centerY;
5401
+ let stemBottom = bottom;
5402
+ let columns = this.measure.getColumns();
5403
+ for (let colId = 0; colId < columns.length; colId++) {
5404
+ let cur = columns[colId];
5405
+ let curVoiceSymbol = this.voiceIds.map((voiceId) => cur.getVoiceSymbol(voiceId)).find((sym) => sym !== void 0);
5406
+ if (!curVoiceSymbol) {
5407
+ continue;
5408
+ }
5409
+ let beamGroup = curVoiceSymbol.getBeamGroup();
5410
+ let symbols = beamGroup ? beamGroup.getSymbols() : [curVoiceSymbol];
5411
+ for (let j = 0; j < symbols.length; j++) {
5412
+ let sym = symbols[j];
5413
+ let nextSym = symbols[j + 1];
5414
+ let colX = sym.col.getRect().centerX;
5415
+ if (sym instanceof ObjNoteGroup) {
5416
+ if (sym.rhythmProps.noteSize >= 2) {
5417
+ let stemThickness = sym.rhythmProps.noteSize === 4 ? lineWidth * 2 : lineWidth;
5418
+ renderer.drawLine(colX, stemBottom, colX, stemTop, "black", stemThickness);
5419
+ }
5420
+ if (symbols.length === 1) {
5421
+ for (let i = 0; i < sym.rhythmProps.flagCount; i++) {
5422
+ renderer.drawFlag(new DivRect(colX, colX + flagSize, stemTop + i * flagSize, stemTop + (i + 2) * flagSize), "up");
5423
+ }
5424
+ }
5425
+ for (let i = 0; i < sym.rhythmProps.dotCount; i++) {
5426
+ renderer.fillCircle(colX + dotSpace * (i + 1), stemBottom - dotWidth, dotWidth);
5427
+ }
5428
+ } else if (sym instanceof ObjRest) {
5429
+ let cx = colX;
5430
+ let cy = (stemTop + stemBottom) / 2;
5431
+ let scale = 0.65;
5432
+ ctx.save();
5433
+ ctx.scale(scale, scale);
5434
+ renderer.drawRest(sym.rhythmProps.noteSize, cx / scale, cy / scale, "black");
5435
+ ctx.restore();
5436
+ for (let i = 0; i < sym.rhythmProps.dotCount; i++) {
5437
+ cx += dotSpace * 1.5;
5438
+ renderer.fillCircle(cx, cy + dotSpace, dotWidth);
5439
+ }
5440
+ }
5441
+ if (nextSym) {
5442
+ let left = sym;
5443
+ let right = nextSym;
5444
+ let leftX = left.col.getRect().centerX;
5445
+ let rightX = right.col.getRect().centerX;
5446
+ let leftBeamCount = left.hasTuplet() ? 1 : left instanceof ObjNoteGroup ? left.getRightBeamCount() : 1;
5447
+ let rightBeamCount = right.hasTuplet() ? 1 : right instanceof ObjNoteGroup ? right.getLeftBeamCount() : 1;
5448
+ let maxBeamCount = Math.max(leftBeamCount, rightBeamCount);
5449
+ for (let i = 0; i < maxBeamCount; i++) {
5450
+ let leftT = rightBeamCount > leftBeamCount && i >= leftBeamCount ? 0.75 : 0;
5451
+ let rightT = leftBeamCount > rightBeamCount && i >= rightBeamCount ? 0.25 : 1;
5452
+ renderer.drawPartialLine(leftX, stemTop + i * flagSize, rightX, stemTop + i * flagSize, leftT, rightT, "black", lineWidth * 2);
5453
+ }
5454
+ for (let i = 0; i < left.rhythmProps.dotCount; i++) {
5455
+ renderer.fillCircle(leftX + dotSpace * (i + 1), stemBottom - dotWidth, dotWidth);
5456
+ }
5457
+ for (let i = 0; i < right.rhythmProps.dotCount; i++) {
5458
+ renderer.fillCircle(rightX + dotSpace * (i + 1), stemBottom - dotWidth, dotWidth);
5459
+ }
5460
+ }
5461
+ if (beamGroup && beamGroup.isTuplet()) {
5462
+ let cx = (symbols[0].col.getRect().centerX + symbols[symbols.length - 1].col.getRect().centerX) / 2;
5463
+ let text = beamGroup.getTupletRatioText();
5464
+ let textObj = this.tupletPartsTextObjMap.get(text);
5465
+ if (!textObj) {
5466
+ this.tupletPartsTextObjMap.set(text, textObj = new ObjText(this, { text, scale: 0.75 }, 0.5, 0.5));
5467
+ textObj.layout(renderer);
5468
+ }
5469
+ textObj.offset(-textObj.getRect().centerX, -textObj.getRect().centerY);
5470
+ textObj.offset(cx, stemTop - fontSize / 2);
5471
+ textObj.draw(renderer);
5472
+ }
5473
+ if (symbols.length > 1) {
5474
+ colId = columns.indexOf(symbols[symbols.length - 1].col);
5475
+ if (colId < 0) {
5476
+ colId = columns.length;
5477
+ }
5478
+ }
5479
+ }
5480
+ }
5481
+ }
5482
+ };
5483
+
5192
5484
  // src/score/engine/obj-measure.ts
5193
- var cmp2 = (a, b) => a === b ? 0 : a < b ? -1 : 1;
5194
5485
  function validateVoiceId(voiceId) {
5195
5486
  if (typeof voiceId === "number" && getVoiceIds().indexOf(voiceId) < 0) {
5196
5487
  throw new import_core14.MusicError(import_core14.MusicErrorType.Score, "Invalid voiceId: " + voiceId);
@@ -5202,7 +5493,7 @@ function getExtensionTicks(extensionLength) {
5202
5493
  if (typeof extensionLength === "string") {
5203
5494
  extensionLength = [extensionLength];
5204
5495
  }
5205
- if (import_ts_utils_lib12.Utils.Is.isArray(extensionLength)) {
5496
+ if (import_ts_utils_lib13.Utils.Is.isArray(extensionLength)) {
5206
5497
  let totalTicks = 0;
5207
5498
  for (let i = 0; i < extensionLength.length; ) {
5208
5499
  let str = extensionLength[i];
@@ -5227,11 +5518,11 @@ function getExtensionTicks(extensionLength) {
5227
5518
  function getVerseLayoutGroupId(verse) {
5228
5519
  switch (verse) {
5229
5520
  case 1:
5230
- return 7 /* LyricsVerse1 */;
5521
+ return 8 /* LyricsVerse1 */;
5231
5522
  case 2:
5232
- return 8 /* LyricsVerse2 */;
5523
+ return 9 /* LyricsVerse2 */;
5233
5524
  case 3:
5234
- return 9 /* LyricsVerse3 */;
5525
+ return 10 /* LyricsVerse3 */;
5235
5526
  default:
5236
5527
  throw new import_core14.MusicError(import_core14.MusicErrorType.Unknown, "VerseNumber is not 1, 2 or 3.");
5237
5528
  }
@@ -5293,6 +5584,9 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5293
5584
  this.updateKeySignature();
5294
5585
  this.updateTimeSignature();
5295
5586
  this.updateTempo();
5587
+ this.row.getTabs().forEach((tab) => {
5588
+ this.addLayoutObject(new ObjTabRhythm(this, tab), tab, 0 /* TabRhythm */, 0 /* Above */);
5589
+ });
5296
5590
  }
5297
5591
  getMusicInterface() {
5298
5592
  return this.mi;
@@ -5464,7 +5758,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5464
5758
  this.alterKeySignature = args[0];
5465
5759
  } else if (args[0] instanceof import_theory9.Scale) {
5466
5760
  this.alterKeySignature = args[0];
5467
- } else if (import_ts_utils_lib12.Utils.Is.isNonEmptyString(args[0])) {
5761
+ } else if (import_ts_utils_lib13.Utils.Is.isNonEmptyString(args[0])) {
5468
5762
  if (args.length === 1) {
5469
5763
  this.alterKeySignature = (0, import_theory9.getScale)(args[0]);
5470
5764
  } else if (args.length === 2) {
@@ -5575,7 +5869,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5575
5869
  let grp = this.doc.getStaffGroup(staffTabOrGroup);
5576
5870
  if (grp && !prevGroups.includes(staffTabOrGroup)) {
5577
5871
  let curGroups = [...prevGroups, staffTabOrGroup];
5578
- (import_ts_utils_lib12.Utils.Is.isArray(grp.staffsTabsAndGroups) ? grp.staffsTabsAndGroups : [grp.staffsTabsAndGroups]).forEach((staffTabOrGroup2) => {
5872
+ (import_ts_utils_lib13.Utils.Is.isArray(grp.staffsTabsAndGroups) ? grp.staffsTabsAndGroups : [grp.staffsTabsAndGroups]).forEach((staffTabOrGroup2) => {
5579
5873
  switch (grp.verticalPosition) {
5580
5874
  case "above" /* Above */:
5581
5875
  addToStaffTabOrGroup(staffTabOrGroup2, 0 /* Above */, curGroups);
@@ -5597,12 +5891,12 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5597
5891
  }
5598
5892
  };
5599
5893
  if (staffTabOrGroups === void 0) {
5600
- 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()) {
5894
+ 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) {
5601
5895
  addToStaffTabOrGroup(defaultVerticalPos === 1 /* Below */ ? 1 : 0, defaultVerticalPos);
5602
5896
  } else {
5603
5897
  addToStaffTabOrGroup(0, defaultVerticalPos);
5604
5898
  }
5605
- } else if (import_ts_utils_lib12.Utils.Is.isArray(staffTabOrGroups)) {
5899
+ } else if (import_ts_utils_lib13.Utils.Is.isArray(staffTabOrGroups)) {
5606
5900
  staffTabOrGroups.forEach((staffTabOrGroup) => addToStaffTabOrGroup(staffTabOrGroup, defaultVerticalPos));
5607
5901
  } else {
5608
5902
  addToStaffTabOrGroup(staffTabOrGroups, defaultVerticalPos);
@@ -5614,7 +5908,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5614
5908
  throw new import_core14.MusicError(import_core14.MusicErrorType.Score, "Cannot add Fermata because anchor is undefined.");
5615
5909
  }
5616
5910
  this.forEachStaffGroup(staffTabOrGroups, 0 /* Above */, (line, vpos) => {
5617
- this.addLayoutObject(new ObjFermata(anchor, vpos), line, 0 /* Fermata */, vpos);
5911
+ this.addLayoutObject(new ObjFermata(anchor, vpos), line, 1 /* Fermata */, vpos);
5618
5912
  });
5619
5913
  this.disableExtension();
5620
5914
  this.requestLayout();
@@ -5633,7 +5927,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5633
5927
  let passages = args;
5634
5928
  addLayoutObjectProps = {
5635
5929
  createObj: () => new ObjEnding(anchor, passages),
5636
- layoutGroupId: 3 /* Ending */,
5930
+ layoutGroupId: 4 /* Ending */,
5637
5931
  defaultVerticalPos: 0 /* Above */
5638
5932
  };
5639
5933
  break;
@@ -5645,7 +5939,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5645
5939
  let text = getNavigationString(navigation);
5646
5940
  addLayoutObjectProps = {
5647
5941
  createObj: () => new ObjText(anchor2, text, 1, 1),
5648
- layoutGroupId: 2 /* Navigation */,
5942
+ layoutGroupId: 3 /* Navigation */,
5649
5943
  defaultVerticalPos: 0 /* Above */
5650
5944
  };
5651
5945
  this.addNavigation(staffTabOrGroups, "endRepeat" /* EndRepeat */);
@@ -5657,7 +5951,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5657
5951
  let text = getNavigationString(navigation);
5658
5952
  addLayoutObjectProps = {
5659
5953
  createObj: () => new ObjText(anchor2, text, 1, 1),
5660
- layoutGroupId: 2 /* Navigation */,
5954
+ layoutGroupId: 3 /* Navigation */,
5661
5955
  defaultVerticalPos: 0 /* Above */
5662
5956
  };
5663
5957
  break;
@@ -5668,7 +5962,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5668
5962
  let text = getNavigationString(navigation);
5669
5963
  addLayoutObjectProps = {
5670
5964
  createObj: () => new ObjSpecialText(anchor2, text),
5671
- layoutGroupId: 2 /* Navigation */,
5965
+ layoutGroupId: 3 /* Navigation */,
5672
5966
  defaultVerticalPos: 0 /* Above */
5673
5967
  };
5674
5968
  break;
@@ -5678,7 +5972,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5678
5972
  let text = getNavigationString(navigation);
5679
5973
  addLayoutObjectProps = {
5680
5974
  createObj: () => new ObjSpecialText(anchor2, text),
5681
- layoutGroupId: 2 /* Navigation */,
5975
+ layoutGroupId: 3 /* Navigation */,
5682
5976
  defaultVerticalPos: 0 /* Above */
5683
5977
  };
5684
5978
  break;
@@ -5686,7 +5980,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5686
5980
  case "endRepeat" /* EndRepeat */:
5687
5981
  if (args.length === 0) {
5688
5982
  this.endRepeatPlayCount = 2;
5689
- } else if (import_ts_utils_lib12.Utils.Is.isIntegerGte(args[0], 2)) {
5983
+ } else if (import_ts_utils_lib13.Utils.Is.isIntegerGte(args[0], 2)) {
5690
5984
  this.endRepeatPlayCount = args[0];
5691
5985
  } else {
5692
5986
  throw new import_core14.MusicError(import_core14.MusicErrorType.Score, "Invalid end repeat play count (should be 2 or greater integer): " + args[0]);
@@ -5723,12 +6017,12 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5723
6017
  let defaultVerticalPos;
5724
6018
  switch (annotation) {
5725
6019
  case "dynamics" /* Dynamics */:
5726
- layoutGroupId = 5 /* DynamicsAnnotation */;
6020
+ layoutGroupId = 6 /* DynamicsAnnotation */;
5727
6021
  defaultVerticalPos = 0 /* Above */;
5728
6022
  textProps.italic = true;
5729
6023
  break;
5730
6024
  case "tempo" /* Tempo */:
5731
- layoutGroupId = 4 /* TempoAnnotation */;
6025
+ layoutGroupId = 5 /* TempoAnnotation */;
5732
6026
  defaultVerticalPos = 0 /* Above */;
5733
6027
  textProps.italic = true;
5734
6028
  break;
@@ -5752,11 +6046,11 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5752
6046
  let defaultVerticalPos;
5753
6047
  switch (label) {
5754
6048
  case "note" /* Note */:
5755
- layoutGroupId = 1 /* NoteLabel */;
6049
+ layoutGroupId = 2 /* NoteLabel */;
5756
6050
  defaultVerticalPos = 1 /* Below */;
5757
6051
  break;
5758
6052
  case "chord" /* Chord */:
5759
- layoutGroupId = 6 /* ChordLabel */;
6053
+ layoutGroupId = 7 /* ChordLabel */;
5760
6054
  defaultVerticalPos = 0 /* Above */;
5761
6055
  break;
5762
6056
  }
@@ -5773,15 +6067,15 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5773
6067
  throw new import_core14.MusicError(import_core14.MusicErrorType.Score, "Connective can be added to note group only.");
5774
6068
  }
5775
6069
  if (connective === "tie" /* Tie */) {
5776
- let tieSpan = import_ts_utils_lib12.Utils.Is.isInteger(args[0]) || import_ts_utils_lib12.Utils.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
5777
- let noteAnchor = import_ts_utils_lib12.Utils.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
6070
+ let tieSpan = import_ts_utils_lib13.Utils.Is.isInteger(args[0]) || import_ts_utils_lib13.Utils.Is.isEnumValue(args[0], TieType) ? args[0] : 2;
6071
+ let noteAnchor = import_ts_utils_lib13.Utils.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
5778
6072
  anchor.startConnective(new ConnectiveProps("tie" /* Tie */, tieSpan, noteAnchor, anchor));
5779
6073
  } else if (connective === "slur" /* Slur */) {
5780
- let slurSpan = import_ts_utils_lib12.Utils.Is.isInteger(args[0]) ? args[0] : 2;
5781
- let noteAnchor = import_ts_utils_lib12.Utils.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
6074
+ let slurSpan = import_ts_utils_lib13.Utils.Is.isInteger(args[0]) ? args[0] : 2;
6075
+ let noteAnchor = import_ts_utils_lib13.Utils.Is.isEnumValue(args[1], NoteAnchor) ? args[1] : "auto" /* Auto */;
5782
6076
  anchor.startConnective(new ConnectiveProps("slur" /* Slur */, slurSpan, noteAnchor, anchor));
5783
6077
  } else if (connective === "slide" /* Slide */) {
5784
- let noteAnchor = import_ts_utils_lib12.Utils.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : "auto" /* Auto */;
6078
+ let noteAnchor = import_ts_utils_lib13.Utils.Is.isEnumValue(args[0], NoteAnchor) ? args[0] : "auto" /* Auto */;
5785
6079
  anchor.startConnective(new ConnectiveProps("slide" /* Slide */, 2, noteAnchor, anchor));
5786
6080
  }
5787
6081
  }
@@ -5869,7 +6163,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
5869
6163
  let lyricsObj = new ObjLyrics(col, verse, line, vpos, lyricsText, lyricsOptions);
5870
6164
  let lyricsArr = this.getLyricsObjects(lyricsObj.line, lyricsObj.vpos, lyricsObj.verse);
5871
6165
  lyricsArr.push(lyricsObj);
5872
- lyricsArr.sort((a, b) => cmp2(a.col.positionTicks, b.col.positionTicks));
6166
+ lyricsArr.sort((a, b) => import_ts_utils_lib13.Utils.Math.cmp(a.col.positionTicks, b.col.positionTicks));
5873
6167
  lyricsContainer.addLyricsObject(lyricsObj);
5874
6168
  this.addLayoutObject(lyricsObj, line, getVerseLayoutGroupId(verse), vpos);
5875
6169
  }
@@ -6061,6 +6355,9 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
6061
6355
  }
6062
6356
  this.requestLayout();
6063
6357
  }
6358
+ getBeamGroups() {
6359
+ return this.beamGroups;
6360
+ }
6064
6361
  createBeams() {
6065
6362
  if (!this.needBeamsUpdate) {
6066
6363
  return;
@@ -6079,72 +6376,42 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
6079
6376
  }
6080
6377
  getVoiceIds().forEach((voiceId) => {
6081
6378
  let symbols = this.getVoiceSymbols(voiceId).slice();
6082
- if (symbols.length >= 2) {
6083
- let symbolsStartTicks = this.isUpBeat() ? Math.max(0, this.getMeasureTicks() - this.getConsumedTicks()) : 0;
6084
- let groupStartTicks = 0;
6085
- for (let groupId = 0; groupId < ts.beamGroupSizes.length; groupId++) {
6086
- let beamGroupSize = ts.beamGroupSizes[groupId];
6087
- let groupSizeSum = 0;
6088
- beamGroupSize.forEach((s) => groupSizeSum += s);
6089
- let groupLength = groupSizeSum * import_theory9.NoteLengthProps.get("8n").ticks;
6090
- let groupSymbols = [];
6091
- let groupSymbolsLength = 0;
6092
- while (symbols.length > 0 && groupSymbolsLength < groupLength) {
6093
- let symbol = symbols[0];
6094
- if (symbol.col.positionTicks >= groupStartTicks) {
6095
- groupSymbols.push(symbol);
6096
- groupSymbolsLength += symbol.rhythmProps.ticks;
6097
- symbols.shift();
6098
- } else {
6099
- break;
6379
+ if (symbols.length < 2) {
6380
+ return;
6381
+ }
6382
+ let upBeatStartTicks = this.isUpBeat() ? Math.max(0, this.getMeasureTicks() - this.getConsumedTicks()) : 0;
6383
+ let groupStartTicks = 0;
6384
+ for (let groupId = 0; groupId < ts.beamGroupSizes.length; groupId++) {
6385
+ let beamGroupSize = ts.beamGroupSizes[groupId];
6386
+ let beamGroupSizeList = [beamGroupSize];
6387
+ if (beamGroupSize.length > 1) {
6388
+ beamGroupSizeList.unshift([import_ts_utils_lib13.Utils.Math.sum(beamGroupSize)]);
6389
+ }
6390
+ let beamsCreated = false;
6391
+ let groupStartTicksSave = groupStartTicks;
6392
+ while (beamGroupSizeList.length > 0 && !beamsCreated) {
6393
+ let beamGroupSize2 = beamGroupSizeList.shift();
6394
+ groupStartTicks = groupStartTicksSave;
6395
+ beamGroupSize2.forEach((beamGroupSize3) => {
6396
+ let beamGroupTicks = beamGroupSize3 * import_theory9.NoteLengthProps.get("8n").ticks;
6397
+ let groupSymbols = symbols.filter((symbol) => {
6398
+ let symbolStartTicks = upBeatStartTicks + symbol.col.positionTicks;
6399
+ let symbolTicks = symbol.rhythmProps.ticks;
6400
+ return symbolStartTicks >= groupStartTicks && symbolStartTicks + symbolTicks <= groupStartTicks + beamGroupTicks;
6401
+ });
6402
+ let groupNotesTicks = import_ts_utils_lib13.Utils.Math.sum(groupSymbols.map((sym) => sym.rhythmProps.ticks));
6403
+ if (groupNotesTicks === beamGroupTicks && groupSymbols.every((n) => n instanceof ObjNoteGroup) && (groupSymbols.every((n) => n.rhythmProps.flagCount === 1) || beamGroupSizeList.length === 0)) {
6404
+ ObjBeamGroup.createBeam(groupSymbols);
6405
+ beamsCreated = true;
6100
6406
  }
6101
- }
6102
- _ObjMeasure.setupBeamGroup(groupSymbols, beamGroupSize);
6103
- symbolsStartTicks += groupSymbolsLength;
6104
- groupStartTicks += groupLength;
6407
+ groupStartTicks += beamGroupTicks;
6408
+ });
6105
6409
  }
6106
6410
  }
6107
6411
  });
6108
6412
  this.needBeamsUpdate = false;
6109
6413
  this.requestLayout();
6110
6414
  }
6111
- static setupBeamGroup(groupSymbols, mainBeamGroupSizeArr) {
6112
- if (mainBeamGroupSizeArr.length === 0) {
6113
- return false;
6114
- }
6115
- let groupNotes = groupSymbols.map((s) => {
6116
- var _a;
6117
- return s instanceof ObjNoteGroup && ((_a = s.getBeamGroup()) == null ? void 0 : _a.isTuplet()) !== true ? s : void 0;
6118
- });
6119
- ObjNoteGroup.setBeamCounts(groupNotes);
6120
- let beamGroupSizeArrList = [mainBeamGroupSizeArr];
6121
- if (mainBeamGroupSizeArr.length > 1) {
6122
- let sum = 0;
6123
- mainBeamGroupSizeArr.forEach((s) => sum += s);
6124
- beamGroupSizeArrList.unshift([sum]);
6125
- }
6126
- let beamsCreated = false;
6127
- while (beamGroupSizeArrList.length > 0 && !beamsCreated) {
6128
- let beamGroupSizeArr = beamGroupSizeArrList.shift();
6129
- let groupSymbolsCopy = groupSymbols.slice();
6130
- beamGroupSizeArr.forEach((beamGroupSize) => {
6131
- var _a;
6132
- let beamGroupLength = beamGroupSize * import_theory9.NoteLengthProps.get("8n").ticks;
6133
- let beamNotesLength = 0;
6134
- let beamNotes = [];
6135
- while (beamNotesLength < beamGroupLength && groupSymbolsCopy.length > 0) {
6136
- let symbol = groupSymbolsCopy.shift();
6137
- beamNotesLength += symbol.rhythmProps.ticks;
6138
- beamNotes.push(symbol instanceof ObjNoteGroup && ((_a = symbol.getBeamGroup()) == null ? void 0 : _a.isTuplet()) !== true ? symbol : void 0);
6139
- }
6140
- if (beamNotesLength === beamGroupLength && beamNotes.every((n) => n !== void 0) && (beamNotes.every((n) => n.rhythmProps.flagCount === 1) || beamGroupSizeArrList.length === 0)) {
6141
- ObjBeamGroup.createBeam(beamNotes);
6142
- beamsCreated = true;
6143
- }
6144
- });
6145
- }
6146
- return beamsCreated;
6147
- }
6148
6415
  getBarLineLeft() {
6149
6416
  return this.barLineLeft;
6150
6417
  }
@@ -6165,7 +6432,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
6165
6432
  this.completeRests(getVoiceIds().filter((id) => this.getConsumedTicks(id) > 0));
6166
6433
  }
6167
6434
  return;
6168
- } else if (import_ts_utils_lib12.Utils.Is.isArray(voiceId)) {
6435
+ } else if (import_ts_utils_lib13.Utils.Is.isArray(voiceId)) {
6169
6436
  voiceId.forEach((id) => this.completeRests(id));
6170
6437
  return;
6171
6438
  } else {
@@ -6212,22 +6479,30 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
6212
6479
  let showKeySignature = isFirstMeasureInRow || isAfterMeasureBreak || !!this.alterKeySignature;
6213
6480
  let showTimeSignature = !!this.alterTimeSignature;
6214
6481
  let showTempo = !!this.alterTempo;
6215
- if (showClef || showMeasureNumber || showKeySignature || showTimeSignature || showTempo) {
6216
- this.signatures = this.row.getStaves().map((staff, staffId) => {
6217
- let oldSignature = this.signatures.find((s) => s.staff === staff);
6218
- let signature = oldSignature != null ? oldSignature : new ObjSignature(this, staff);
6482
+ this.signatures = [];
6483
+ this.row.getNotationLines().forEach((line, lineId) => {
6484
+ if (line instanceof ObjStaff && (showClef || showMeasureNumber || showKeySignature || showTimeSignature || showTempo)) {
6485
+ let oldSignature = this.signatures.filter((s) => s instanceof ObjStaffSignature).find((s) => s.staff === line);
6486
+ let signature = oldSignature != null ? oldSignature : new ObjStaffSignature(this, line);
6219
6487
  signature.staff.addObject(signature);
6220
6488
  signature.updateClefImage(renderer, showClef);
6221
- signature.updateMeasureNumber(showMeasureNumber && staffId === 0);
6489
+ signature.updateMeasureNumber(showMeasureNumber && lineId === 0);
6222
6490
  signature.updateKeySignature(showKeySignature);
6223
6491
  signature.updateTimeSignature(showTimeSignature);
6224
- signature.updateTempo(showTempo && staffId === 0);
6225
- return signature;
6226
- });
6227
- } else {
6228
- this.signatures = [];
6229
- }
6230
- this.signatures.forEach((signature) => signature.layout(renderer));
6492
+ signature.updateTempo(showTempo && lineId === 0);
6493
+ signature.layout(renderer);
6494
+ this.signatures.push(signature);
6495
+ } else if (line instanceof ObjTab && (showMeasureNumber || showTimeSignature || showTempo)) {
6496
+ let oldSignature = this.signatures.filter((s) => s instanceof ObjTabSignature).find((s) => s.tab === line);
6497
+ let signature = oldSignature != null ? oldSignature : new ObjTabSignature(this, line);
6498
+ signature.tab.addObject(signature);
6499
+ signature.updateMeasureNumber(showMeasureNumber && lineId === 0);
6500
+ signature.updateTimeSignature(showTimeSignature);
6501
+ signature.updateTempo(showTempo && lineId === 0);
6502
+ signature.layout(renderer);
6503
+ this.signatures.push(signature);
6504
+ }
6505
+ });
6231
6506
  this.tabStringNotes.length = 0;
6232
6507
  if (this === this.row.getFirstMeasure()) {
6233
6508
  this.row.getTabs().forEach((tab) => {
@@ -6280,7 +6555,7 @@ var _ObjMeasure = class _ObjMeasure extends MusicObject {
6280
6555
  let columnsAreaLeft = this.rect.left + this.leftSolidAreaWidth;
6281
6556
  let columnsAreaRight = this.rect.right - this.rightSolidAreaWidth;
6282
6557
  let columnsAreaWidth = columnsAreaRight - columnsAreaLeft;
6283
- let columnsWidth = import_ts_utils_lib12.Utils.Math.sum(this.columns.map((col) => col.getRect().width));
6558
+ let columnsWidth = import_ts_utils_lib13.Utils.Math.sum(this.columns.map((col) => col.getRect().width));
6284
6559
  let columnScale = columnsAreaWidth / columnsWidth;
6285
6560
  let columnLeft = columnsAreaLeft;
6286
6561
  this.columns.forEach((col) => {
@@ -6401,18 +6676,19 @@ var ObjMeasure2 = _ObjMeasure;
6401
6676
  // src/score/engine/layout-object.ts
6402
6677
  var import_core15 = require("@tspro/web-music-score/core");
6403
6678
  var WidenColumnList = [
6404
- 1 /* NoteLabel */,
6405
- 6 /* ChordLabel */
6679
+ 2 /* NoteLabel */,
6680
+ 7 /* ChordLabel */
6406
6681
  ];
6407
6682
  var RowAlignList = [
6408
- 2 /* Navigation */,
6409
- 3 /* Ending */,
6410
- 4 /* TempoAnnotation */,
6411
- 5 /* DynamicsAnnotation */,
6412
- 6 /* ChordLabel */,
6413
- 7 /* LyricsVerse1 */,
6414
- 8 /* LyricsVerse2 */,
6415
- 9 /* LyricsVerse3 */
6683
+ 0 /* TabRhythm */,
6684
+ 3 /* Navigation */,
6685
+ 4 /* Ending */,
6686
+ 5 /* TempoAnnotation */,
6687
+ 6 /* DynamicsAnnotation */,
6688
+ 7 /* ChordLabel */,
6689
+ 8 /* LyricsVerse1 */,
6690
+ 9 /* LyricsVerse2 */,
6691
+ 10 /* LyricsVerse3 */
6416
6692
  ];
6417
6693
  function requireParentMeasure(p) {
6418
6694
  while (p) {
@@ -6588,7 +6864,7 @@ var ObjNotationLine4 = class extends MusicObject {
6588
6864
  let rowLayoutObjs = layoutGroup.getLayoutObjects(verticalPos).filter((layoutObj) => !layoutObj.isPositionResolved());
6589
6865
  rowLayoutObjs.forEach((layoutObj) => {
6590
6866
  let { musicObj, anchor } = layoutObj;
6591
- if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine) {
6867
+ if (musicObj instanceof ObjEnding || musicObj instanceof ObjExtensionLine || musicObj instanceof ObjTabRhythm) {
6592
6868
  musicObj.layoutFitToMeasure(renderer);
6593
6869
  } else {
6594
6870
  musicObj.offset(anchor.getRect().centerX - musicObj.getRect().centerX, 0);
@@ -6710,9 +6986,6 @@ var ObjStaff = class extends ObjNotationLine4 {
6710
6986
  containsVoiceId(voiceId) {
6711
6987
  return !this.staffConfig.voiceIds || this.staffConfig.voiceIds.includes(voiceId);
6712
6988
  }
6713
- isGrand() {
6714
- return this.staffConfig.isGrand === true;
6715
- }
6716
6989
  calcTop() {
6717
6990
  let top = this.topLineY;
6718
6991
  this.objects.forEach((o) => top = Math.min(top, o.getRect().top));
@@ -6773,7 +7046,7 @@ var ObjTab = class extends ObjNotationLine4 {
6773
7046
  __publicField(this, "tuningName");
6774
7047
  __publicField(this, "tuningStrings");
6775
7048
  __publicField(this, "mi");
6776
- if (import_ts_utils_lib13.Utils.Is.isArray(tabConfig.tuning)) {
7049
+ if (import_ts_utils_lib14.Utils.Is.isArray(tabConfig.tuning)) {
6777
7050
  this.tuningName = void 0;
6778
7051
  this.tuningStrings = tabConfig.tuning.map((noteName) => import_theory11.Note.getNote(noteName)).reverse();
6779
7052
  } else if (typeof tabConfig.tuning === "string") {
@@ -6827,10 +7100,14 @@ var ObjTab = class extends ObjNotationLine4 {
6827
7100
  return true;
6828
7101
  }
6829
7102
  calcTop() {
6830
- return this.top;
7103
+ let { top } = this;
7104
+ this.objects.forEach((o) => top = Math.min(top, o.getRect().top));
7105
+ return top;
6831
7106
  }
6832
7107
  calcBottom() {
6833
- return this.bottom;
7108
+ let { bottom } = this;
7109
+ this.objects.forEach((o) => bottom = Math.max(bottom, o.getRect().bottom));
7110
+ return bottom;
6834
7111
  }
6835
7112
  pick(x, y) {
6836
7113
  return [this];
@@ -6894,7 +7171,7 @@ var ObjScoreRow = class extends MusicObject {
6894
7171
  for (let i = 0; i < notationLines.length - 1; i++) {
6895
7172
  let treble = notationLines[i];
6896
7173
  let bass = notationLines[i + 1];
6897
- if (treble instanceof ObjStaff && treble.isGrand() && treble.staffConfig.clef === "G" /* G */ && bass instanceof ObjStaff && bass.isGrand() && bass.staffConfig.clef === "F" /* F */) {
7174
+ if (treble instanceof ObjStaff && bass instanceof ObjStaff && treble.staffConfig.grandId !== void 0 && treble.staffConfig.grandId === bass.staffConfig.grandId) {
6898
7175
  treble.joinGrandStaff(bass);
6899
7176
  bass.joinGrandStaff(treble);
6900
7177
  }
@@ -7071,17 +7348,17 @@ var ObjScoreRow = class extends MusicObject {
7071
7348
  alignStemsToBeams() {
7072
7349
  this.measures.forEach((m) => m.alignStemsToBeams());
7073
7350
  }
7074
- layoutPositionLines(renderer) {
7351
+ layoutSetNotationLines(renderer) {
7075
7352
  let { unitSize } = renderer;
7076
7353
  for (let i = 1; i < this.notationLines.length; i++) {
7077
7354
  let prev = this.notationLines[i - 1];
7078
7355
  let cur = this.notationLines[i];
7079
- if (prev instanceof ObjStaff && prev.isGrand() && prev.staffConfig.clef === "G" /* G */ && cur instanceof ObjStaff && cur.isGrand() && cur.staffConfig.clef === "F" /* F */) {
7080
- let sep = unitSize * 6;
7081
- cur.offset(0, prev.getBottomLineY() - cur.getTopLineY() + sep);
7356
+ if (prev instanceof ObjStaff && cur instanceof ObjStaff && prev.staffConfig.grandId !== void 0 && prev.staffConfig.grandId === cur.staffConfig.grandId) {
7357
+ let dy = prev.getBottomLineY() - cur.getTopLineY() + unitSize * 6;
7358
+ cur.offset(0, dy);
7082
7359
  } else {
7083
- let sep = unitSize * 3;
7084
- cur.offset(0, prev.calcBottom() - cur.calcTop() + sep);
7360
+ let dy = prev.calcBottom() - cur.calcTop() + unitSize * 3;
7361
+ cur.offset(0, dy);
7085
7362
  }
7086
7363
  }
7087
7364
  this.measures.forEach((m) => {
@@ -7228,7 +7505,8 @@ var ObjHeader = class extends MusicObject {
7228
7505
  };
7229
7506
 
7230
7507
  // src/score/engine/obj-document.ts
7231
- var import_ts_utils_lib14 = require("@tspro/ts-utils-lib");
7508
+ var import_ts_utils_lib15 = require("@tspro/ts-utils-lib");
7509
+ var import_core18 = require("@tspro/web-music-score/core");
7232
7510
  var ObjDocument = class extends MusicObject {
7233
7511
  constructor() {
7234
7512
  super(void 0);
@@ -7249,7 +7527,7 @@ var ObjDocument = class extends MusicObject {
7249
7527
  return this.mi;
7250
7528
  }
7251
7529
  setScoreConfiguration(config) {
7252
- if (import_ts_utils_lib14.Utils.Is.isEnumValue(config, StaffPreset)) {
7530
+ if (import_ts_utils_lib15.Utils.Is.isEnumValue(config, StaffPreset)) {
7253
7531
  switch (config) {
7254
7532
  default:
7255
7533
  case "treble" /* Treble */:
@@ -7260,8 +7538,8 @@ var ObjDocument = class extends MusicObject {
7260
7538
  break;
7261
7539
  case "grand" /* Grand */:
7262
7540
  this.curScoreConfig = [
7263
- { type: "staff", clef: "G" /* G */, isGrand: true },
7264
- { type: "staff", clef: "F" /* F */, isGrand: true }
7541
+ { type: "staff", clef: "G" /* G */, grandId: "grand1" },
7542
+ { type: "staff", clef: "F" /* F */, grandId: "grand1" }
7265
7543
  ];
7266
7544
  break;
7267
7545
  case "guitarTreble" /* GuitarTreble */:
@@ -7277,26 +7555,57 @@ var ObjDocument = class extends MusicObject {
7277
7555
  ];
7278
7556
  break;
7279
7557
  }
7280
- } else if (import_ts_utils_lib14.Utils.Is.isArray(config)) {
7558
+ } else if (import_ts_utils_lib15.Utils.Is.isArray(config)) {
7281
7559
  this.curScoreConfig = config;
7282
7560
  } else {
7283
7561
  this.curScoreConfig = [config];
7284
7562
  }
7285
- for (let i = 0; i < this.curScoreConfig.length - 1; i++) {
7286
- let treble = this.curScoreConfig[i];
7287
- let bass = this.curScoreConfig[i + 1];
7288
- if (treble.type === "staff" && bass.type === "staff") {
7289
- if (treble.clef === "G" /* G */ && treble.isGrand && bass.clef === "F" /* F */ && bass.isGrand) {
7290
- treble.minNote = "C4";
7291
- bass.maxNote = "B3";
7292
- treble.isOctaveDown = bass.isOctaveDown = false;
7563
+ for (let cfgId = 0, grandId = "grand"; cfgId < this.curScoreConfig.length; ) {
7564
+ let treble = this.curScoreConfig[cfgId];
7565
+ let bass = this.curScoreConfig[cfgId + 1];
7566
+ while (this.curScoreConfig.filter((cfg) => cfg.type === "staff").findIndex((cfg) => cfg.grandId === grandId) >= 0) {
7567
+ grandId += "A";
7568
+ }
7569
+ if (treble && treble.type === "staff" && treble.isGrand) {
7570
+ if (treble.grandId !== void 0) {
7571
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: mixing isGrand and grandId!`);
7572
+ } else if (bass && bass.type === "staff" && bass.isGrand) {
7573
+ if (bass.grandId !== void 0) {
7574
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: mixing isGrand and grandId!`);
7575
+ } else {
7576
+ treble.grandId = grandId;
7577
+ bass.grandId = grandId;
7578
+ treble.isGrand = bass.isGrand = false;
7579
+ cfgId += 2;
7580
+ }
7293
7581
  } else {
7294
- treble.isGrand = bass.isGrand = false;
7582
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: invalid use of isGrand!`);
7583
+ }
7584
+ } else {
7585
+ cfgId++;
7586
+ }
7587
+ }
7588
+ for (let cfgId = 0, usedGrandIdes = []; cfgId < this.curScoreConfig.length; ) {
7589
+ let treble = this.curScoreConfig[cfgId];
7590
+ let bass = this.curScoreConfig[cfgId + 1];
7591
+ if (treble && bass && treble.type === "staff" && bass.type === "staff" && treble.grandId !== void 0 && treble.grandId === bass.grandId) {
7592
+ if (usedGrandIdes.includes(treble.grandId)) {
7593
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: grandId "${treble.grandId}" already used!`);
7594
+ } else if (treble.clef !== "G" /* G */) {
7595
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: Invalid treble clef "${treble.clef}"!`);
7596
+ } else if (bass.clef !== "F" /* F */) {
7597
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: Invalid treble clef "${treble.clef}"!`);
7598
+ } else if (treble.isOctaveDown || bass.isOctaveDown) {
7599
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: cannot use isOctaveDown option!`);
7295
7600
  }
7296
- } else if (treble.type === "staff") {
7297
- treble.isGrand = false;
7298
- } else if (bass.type === "staff") {
7299
- bass.isGrand = false;
7601
+ usedGrandIdes.push(treble.grandId);
7602
+ treble.minNote = "C4";
7603
+ bass.maxNote = "B3";
7604
+ cfgId += 2;
7605
+ } else if (treble && treble.type === "staff" && treble.grandId !== void 0) {
7606
+ throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Grand staff error: invalid use of grandId "${treble.grandId}"!`);
7607
+ } else {
7608
+ cfgId++;
7300
7609
  }
7301
7610
  }
7302
7611
  this.requestNewRow();
@@ -7439,7 +7748,7 @@ var ObjDocument = class extends MusicObject {
7439
7748
  );
7440
7749
  this.rows.forEach((row) => row.layoutWidth(renderer, rowWidth));
7441
7750
  this.rows.forEach((row) => row.layoutLayoutGroups(renderer));
7442
- this.rows.forEach((row) => row.layoutPositionLines(renderer));
7751
+ this.rows.forEach((row) => row.layoutSetNotationLines(renderer));
7443
7752
  this.rows.forEach((row) => row.layoutPadding(renderer));
7444
7753
  this.rect = new DivRect();
7445
7754
  if (this.header) {
@@ -7504,10 +7813,10 @@ var ObjDocument = class extends MusicObject {
7504
7813
 
7505
7814
  // src/score/pub/document-builder.ts
7506
7815
  var import_theory13 = require("@tspro/web-music-score/theory");
7507
- var import_core18 = require("@tspro/web-music-score/core");
7816
+ var import_core19 = require("@tspro/web-music-score/core");
7508
7817
  function assertArg(condition, argName, argValue) {
7509
7818
  if (!condition) {
7510
- throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Invalid arg: ${argName} = ${argValue}`);
7819
+ throw new import_core19.MusicError(import_core19.MusicErrorType.Score, `Invalid arg: ${argName} = ${argValue}`);
7511
7820
  }
7512
7821
  }
7513
7822
  function isNote(note) {
@@ -7519,64 +7828,70 @@ function isNote(note) {
7519
7828
  }
7520
7829
  }
7521
7830
  function isVoiceId(value) {
7522
- return import_ts_utils_lib15.Utils.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
7831
+ return import_ts_utils_lib16.Utils.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
7523
7832
  }
7524
7833
  function isStringNumber(value) {
7525
- return import_ts_utils_lib15.Utils.Is.isNumber(value) && getStringNumbers().indexOf(value) >= 0;
7834
+ return import_ts_utils_lib16.Utils.Is.isNumber(value) && getStringNumbers().indexOf(value) >= 0;
7526
7835
  }
7527
7836
  function isVerseNumber(value) {
7528
- return import_ts_utils_lib15.Utils.Is.isNumber(value) && getVerseNumbers().indexOf(value) >= 0;
7837
+ return import_ts_utils_lib16.Utils.Is.isNumber(value) && getVerseNumbers().indexOf(value) >= 0;
7838
+ }
7839
+ function assertBaseConfig(baseConfig) {
7840
+ assertArg(import_ts_utils_lib16.Utils.Is.isObject(baseConfig), "baseConfig", baseConfig);
7841
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(baseConfig.name), "baseConfig.name", baseConfig.name);
7842
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(baseConfig.voiceIds) || import_ts_utils_lib16.Utils.Is.isArray(baseConfig.voiceIds) && baseConfig.voiceIds.every((voiceId) => import_ts_utils_lib16.Utils.Is.isNumber(voiceId)), "baseConfig.voiceIds", baseConfig.voiceIds);
7529
7843
  }
7530
7844
  function assertStaffConfig(staffConfig) {
7531
- assertArg(import_ts_utils_lib15.Utils.Is.isObject(staffConfig), "staffConfig", staffConfig);
7845
+ assertBaseConfig(staffConfig);
7846
+ assertArg(import_ts_utils_lib16.Utils.Is.isObject(staffConfig), "staffConfig", staffConfig);
7532
7847
  assertArg(staffConfig.type === "staff", "staffConfig.type", staffConfig.type);
7533
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(staffConfig.clef, Clef), "staffConfig.clef", staffConfig.clef);
7534
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(staffConfig.isOctaveDown), "staffConfig.isOctaveDown", staffConfig.isOctaveDown);
7535
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(staffConfig.minNote) || isNote(staffConfig.minNote), "staffConfig.minNote", staffConfig.minNote);
7536
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(staffConfig.maxNote) || isNote(staffConfig.maxNote), "staffConfig.maxNote", staffConfig.maxNote);
7537
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(staffConfig.voiceIds) || import_ts_utils_lib15.Utils.Is.isArray(staffConfig.voiceIds) && staffConfig.voiceIds.every((voiceId) => import_ts_utils_lib15.Utils.Is.isNumber(voiceId)), "staffConfig.voiceIds", staffConfig.voiceIds);
7538
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(staffConfig.isGrand), "staffConfig.isGrand", staffConfig.isGrand);
7848
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(staffConfig.clef, Clef), "staffConfig.clef", staffConfig.clef);
7849
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(staffConfig.isOctaveDown), "staffConfig.isOctaveDown", staffConfig.isOctaveDown);
7850
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(staffConfig.minNote) || isNote(staffConfig.minNote), "staffConfig.minNote", staffConfig.minNote);
7851
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(staffConfig.maxNote) || isNote(staffConfig.maxNote), "staffConfig.maxNote", staffConfig.maxNote);
7852
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(staffConfig.grandId), "staffConfig.grandId", staffConfig.grandId);
7853
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(staffConfig.isGrand), "staffConfig.isGrand", staffConfig.isGrand);
7539
7854
  }
7540
7855
  function assertTabConfig(tabConfig) {
7541
- assertArg(import_ts_utils_lib15.Utils.Is.isObject(tabConfig), "tabConfig", tabConfig);
7856
+ assertBaseConfig(tabConfig);
7857
+ assertArg(import_ts_utils_lib16.Utils.Is.isObject(tabConfig), "tabConfig", tabConfig);
7542
7858
  assertArg(tabConfig.type === "tab", "tabConfig.type", tabConfig.type);
7543
- if (typeof tabConfig.tuning === "string") {
7859
+ if (import_ts_utils_lib16.Utils.Is.isString(tabConfig.tuning)) {
7544
7860
  assertArg(import_theory13.TuningNameList.includes(tabConfig.tuning), "tabConfig.tuning", tabConfig.tuning);
7545
- } else if (import_ts_utils_lib15.Utils.Is.isArray(tabConfig.tuning)) {
7861
+ } else if (import_ts_utils_lib16.Utils.Is.isArray(tabConfig.tuning)) {
7546
7862
  assertArg(tabConfig.tuning.length === getStringNumbers().length && tabConfig.tuning.every((s) => isNote(s)), "tabConfig.tuning", tabConfig.tuning);
7547
7863
  }
7548
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(tabConfig.voiceIds) || import_ts_utils_lib15.Utils.Is.isArray(tabConfig.voiceIds) && tabConfig.voiceIds.every((voiceId) => import_ts_utils_lib15.Utils.Is.isNumber(voiceId)), "tabConfig.voiceIds", tabConfig.voiceIds);
7549
7864
  }
7550
7865
  function assertNoteOptions(noteOptions) {
7551
- assertArg(import_ts_utils_lib15.Utils.Is.isObject(noteOptions), "noteOptions", noteOptions);
7552
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(noteOptions.dotted) || import_ts_utils_lib15.Utils.Is.isIntegerGte(noteOptions.dotted, 0), "noteOptions.dotted", noteOptions.dotted);
7553
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(noteOptions.stem, Stem), "noteOptions.stem", noteOptions.stem);
7554
- assertArg(import_ts_utils_lib15.Utils.Is.isStringOrUndefined(noteOptions.color), "noteOptions.color", noteOptions.color);
7555
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(noteOptions.arpeggio) || import_ts_utils_lib15.Utils.Is.isEnumValue(noteOptions.arpeggio, Arpeggio), "noteOptions.arpeggio", noteOptions.arpeggio);
7556
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(noteOptions.staccato), "noteOptions.staccato", noteOptions.staccato);
7557
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(noteOptions.diamond), "noteOptions.diamond", noteOptions.diamond);
7558
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(noteOptions.triplet), "noteOptions.triplet", noteOptions.triplet);
7559
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(noteOptions.string) || isStringNumber(noteOptions.string) || import_ts_utils_lib15.Utils.Is.isNonEmptyArray(noteOptions.string) && noteOptions.string.every((string) => isStringNumber(string)), "noteOptions.string", noteOptions.string);
7560
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(noteOptions.tieSpan), 'NoteOptions.tieSpan was removed. Use addConnective("tie", tieSpan)', "");
7561
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(noteOptions.slurSpan), 'NoteOptions.slurSpan was removed. Use addConnective("slur", slurSpan)', "");
7866
+ assertArg(import_ts_utils_lib16.Utils.Is.isObject(noteOptions), "noteOptions", noteOptions);
7867
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(noteOptions.dotted) || import_ts_utils_lib16.Utils.Is.isIntegerGte(noteOptions.dotted, 0), "noteOptions.dotted", noteOptions.dotted);
7868
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(noteOptions.stem, Stem), "noteOptions.stem", noteOptions.stem);
7869
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(noteOptions.color), "noteOptions.color", noteOptions.color);
7870
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(noteOptions.arpeggio) || import_ts_utils_lib16.Utils.Is.isEnumValue(noteOptions.arpeggio, Arpeggio), "noteOptions.arpeggio", noteOptions.arpeggio);
7871
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(noteOptions.staccato), "noteOptions.staccato", noteOptions.staccato);
7872
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(noteOptions.diamond), "noteOptions.diamond", noteOptions.diamond);
7873
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(noteOptions.triplet), "noteOptions.triplet", noteOptions.triplet);
7874
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(noteOptions.string) || isStringNumber(noteOptions.string) || import_ts_utils_lib16.Utils.Is.isNonEmptyArray(noteOptions.string) && noteOptions.string.every((string) => isStringNumber(string)), "noteOptions.string", noteOptions.string);
7875
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(noteOptions.tieSpan), 'NoteOptions.tieSpan was removed. Use addConnective("tie", tieSpan)', "");
7876
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(noteOptions.slurSpan), 'NoteOptions.slurSpan was removed. Use addConnective("slur", slurSpan)', "");
7562
7877
  }
7563
7878
  function assertRestOptions(restOptions) {
7564
- assertArg(import_ts_utils_lib15.Utils.Is.isObject(restOptions), "restOptions", restOptions);
7565
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(restOptions.dotted) || import_ts_utils_lib15.Utils.Is.isIntegerGte(restOptions.dotted, 0), "restOptions.dotted", restOptions.dotted);
7566
- assertArg(import_ts_utils_lib15.Utils.Is.isStringOrUndefined(restOptions.staffPos) || import_ts_utils_lib15.Utils.Is.isInteger(restOptions.staffPos) || restOptions.staffPos instanceof import_theory13.Note, "restOptions.staffPos", restOptions.staffPos);
7567
- assertArg(import_ts_utils_lib15.Utils.Is.isStringOrUndefined(restOptions.color), "restOptions.color", restOptions.color);
7568
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(restOptions.hide), "restOptions.hide", restOptions.hide);
7569
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(restOptions.triplet), "restOptions.triplet", restOptions.triplet);
7879
+ assertArg(import_ts_utils_lib16.Utils.Is.isObject(restOptions), "restOptions", restOptions);
7880
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(restOptions.dotted) || import_ts_utils_lib16.Utils.Is.isIntegerGte(restOptions.dotted, 0), "restOptions.dotted", restOptions.dotted);
7881
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(restOptions.staffPos) || import_ts_utils_lib16.Utils.Is.isInteger(restOptions.staffPos) || restOptions.staffPos instanceof import_theory13.Note, "restOptions.staffPos", restOptions.staffPos);
7882
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(restOptions.color), "restOptions.color", restOptions.color);
7883
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(restOptions.hide), "restOptions.hide", restOptions.hide);
7884
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(restOptions.triplet), "restOptions.triplet", restOptions.triplet);
7570
7885
  }
7571
7886
  function assertLyricsOptions(lyricsOptions) {
7572
- assertArg(import_ts_utils_lib15.Utils.Is.isObject(lyricsOptions), "lyricsOptions", lyricsOptions);
7573
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(lyricsOptions.align, LyricsAlign), "lyricsOptions.align", lyricsOptions.align);
7574
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(lyricsOptions.hyphen, LyricsHyphen), "lyricsOptions.hyphen", lyricsOptions.hyphen);
7887
+ assertArg(import_ts_utils_lib16.Utils.Is.isObject(lyricsOptions), "lyricsOptions", lyricsOptions);
7888
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(lyricsOptions.align, LyricsAlign), "lyricsOptions.align", lyricsOptions.align);
7889
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(lyricsOptions.hyphen, LyricsHyphen), "lyricsOptions.hyphen", lyricsOptions.hyphen);
7575
7890
  }
7576
7891
  function assertStaffTabOrGRoups(staffTabOrGroups) {
7577
7892
  assertArg(
7578
- import_ts_utils_lib15.Utils.Is.isStringOrUndefined(staffTabOrGroups) || import_ts_utils_lib15.Utils.Is.isIntegerGte(staffTabOrGroups, 0) || import_ts_utils_lib15.Utils.Is.isNonEmptyArray(staffTabOrGroups) && staffTabOrGroups.every(
7579
- (staffTabOrGroup) => import_ts_utils_lib15.Utils.Is.isString(staffTabOrGroup) || import_ts_utils_lib15.Utils.Is.isIntegerGte(staffTabOrGroup, 0)
7893
+ import_ts_utils_lib16.Utils.Is.isStringOrUndefined(staffTabOrGroups) || import_ts_utils_lib16.Utils.Is.isIntegerGte(staffTabOrGroups, 0) || import_ts_utils_lib16.Utils.Is.isNonEmptyArray(staffTabOrGroups) && staffTabOrGroups.every(
7894
+ (staffTabOrGroup) => import_ts_utils_lib16.Utils.Is.isString(staffTabOrGroup) || import_ts_utils_lib16.Utils.Is.isIntegerGte(staffTabOrGroup, 0)
7580
7895
  ),
7581
7896
  "staffTabOrGroup",
7582
7897
  staffTabOrGroups
@@ -7608,19 +7923,19 @@ var DocumentBuilder = class {
7608
7923
  this.doc = new ObjDocument();
7609
7924
  }
7610
7925
  setScoreConfiguration(config) {
7611
- if (import_ts_utils_lib15.Utils.Is.isEnumValue(config, StaffPreset)) {
7926
+ if (import_ts_utils_lib16.Utils.Is.isEnumValue(config, StaffPreset)) {
7612
7927
  this.doc.setScoreConfiguration(config);
7613
- } else if (import_ts_utils_lib15.Utils.Is.isObject(config) && config.type === "staff") {
7928
+ } else if (import_ts_utils_lib16.Utils.Is.isObject(config) && config.type === "staff") {
7614
7929
  assertStaffConfig(config);
7615
7930
  this.doc.setScoreConfiguration(config);
7616
- } else if (import_ts_utils_lib15.Utils.Is.isObject(config) && config.type === "tab") {
7931
+ } else if (import_ts_utils_lib16.Utils.Is.isObject(config) && config.type === "tab") {
7617
7932
  assertTabConfig(config);
7618
7933
  this.doc.setScoreConfiguration(config);
7619
- } else if (import_ts_utils_lib15.Utils.Is.isNonEmptyArray(config)) {
7934
+ } else if (import_ts_utils_lib16.Utils.Is.isNonEmptyArray(config)) {
7620
7935
  config.forEach((c) => {
7621
- if (import_ts_utils_lib15.Utils.Is.isObject(c) && c.type === "staff") {
7936
+ if (import_ts_utils_lib16.Utils.Is.isObject(c) && c.type === "staff") {
7622
7937
  assertStaffConfig(c);
7623
- } else if (import_ts_utils_lib15.Utils.Is.isObject(c) && c.type === "tab") {
7938
+ } else if (import_ts_utils_lib16.Utils.Is.isObject(c) && c.type === "tab") {
7624
7939
  assertTabConfig(c);
7625
7940
  } else {
7626
7941
  assertArg(false, "config", config);
@@ -7651,9 +7966,9 @@ var DocumentBuilder = class {
7651
7966
  * @returns - This document builder instance.
7652
7967
  */
7653
7968
  setHeader(title, composer, arranger) {
7654
- assertArg(import_ts_utils_lib15.Utils.Is.isStringOrUndefined(title), "title", title);
7655
- assertArg(import_ts_utils_lib15.Utils.Is.isStringOrUndefined(composer), "composer", composer);
7656
- assertArg(import_ts_utils_lib15.Utils.Is.isStringOrUndefined(arranger), "arranger", arranger);
7969
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(title), "title", title);
7970
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(composer), "composer", composer);
7971
+ assertArg(import_ts_utils_lib16.Utils.Is.isStringOrUndefined(arranger), "arranger", arranger);
7657
7972
  this.doc.setHeader(title, composer, arranger);
7658
7973
  return this;
7659
7974
  }
@@ -7663,7 +7978,7 @@ var DocumentBuilder = class {
7663
7978
  * @returns - This document builder instance.
7664
7979
  */
7665
7980
  setMeasuresPerRow(measuresPerRow) {
7666
- assertArg(import_ts_utils_lib15.Utils.Is.isIntegerGte(measuresPerRow, 1) || import_ts_utils_lib15.Utils.Is.isPosInfinity(measuresPerRow), "measuresPerRow", measuresPerRow);
7981
+ assertArg(import_ts_utils_lib16.Utils.Is.isIntegerGte(measuresPerRow, 1) || import_ts_utils_lib16.Utils.Is.isPosInfinity(measuresPerRow), "measuresPerRow", measuresPerRow);
7667
7982
  this.doc.setMeasuresPerRow(measuresPerRow);
7668
7983
  return this;
7669
7984
  }
@@ -7676,16 +7991,16 @@ var DocumentBuilder = class {
7676
7991
  return this;
7677
7992
  }
7678
7993
  setKeySignature(...args) {
7679
- assertArg(args[0] instanceof import_theory13.Scale || args[0] instanceof import_theory13.KeySignature || import_ts_utils_lib15.Utils.Is.isNonEmptyString(args[0]) && (args.length === 1 || import_ts_utils_lib15.Utils.Is.isEnumValue(args[1], import_theory13.ScaleType)), "keySignature", args);
7994
+ assertArg(args[0] instanceof import_theory13.Scale || args[0] instanceof import_theory13.KeySignature || import_ts_utils_lib16.Utils.Is.isNonEmptyString(args[0]) && (args.length === 1 || import_ts_utils_lib16.Utils.Is.isEnumValue(args[1], import_theory13.ScaleType)), "keySignature", args);
7680
7995
  this.getMeasure().setKeySignature(...args);
7681
7996
  return this;
7682
7997
  }
7683
7998
  setTimeSignature(...args) {
7684
7999
  if (args[0] instanceof import_theory13.TimeSignature) {
7685
8000
  this.getMeasure().setTimeSignature(args[0]);
7686
- } else if (import_ts_utils_lib15.Utils.Is.isEnumValue(args[0], import_theory13.TimeSignatures) && import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(args[1], import_theory13.BeamGrouping)) {
8001
+ } else if (import_ts_utils_lib16.Utils.Is.isEnumValue(args[0], import_theory13.TimeSignatures) && import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(args[1], import_theory13.BeamGrouping)) {
7687
8002
  this.getMeasure().setTimeSignature(new import_theory13.TimeSignature(args[0], args[1]));
7688
- } else if (import_ts_utils_lib15.Utils.Is.isIntegerGte(args[0], 1) && import_ts_utils_lib15.Utils.Is.isIntegerGte(args[1], 1) && import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(args[2], import_theory13.BeamGrouping)) {
8003
+ } else if (import_ts_utils_lib16.Utils.Is.isIntegerGte(args[0], 1) && import_ts_utils_lib16.Utils.Is.isIntegerGte(args[1], 1) && import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(args[2], import_theory13.BeamGrouping)) {
7689
8004
  this.getMeasure().setTimeSignature(new import_theory13.TimeSignature(args[0], args[1], args[2]));
7690
8005
  } else {
7691
8006
  assertArg(false, "timeSignature args", args);
@@ -7693,12 +8008,12 @@ var DocumentBuilder = class {
7693
8008
  return this;
7694
8009
  }
7695
8010
  setTempo(beatsPerMinute, beatLength, dotted) {
7696
- assertArg(import_ts_utils_lib15.Utils.Is.isIntegerGte(beatsPerMinute, 1), "beatsPerMinute", beatsPerMinute);
8011
+ assertArg(import_ts_utils_lib16.Utils.Is.isIntegerGte(beatsPerMinute, 1), "beatsPerMinute", beatsPerMinute);
7697
8012
  if (beatLength === void 0) {
7698
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(dotted), "dotted", dotted);
8013
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(dotted), "dotted", dotted);
7699
8014
  } else {
7700
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(beatLength, import_theory13.NoteLength) || isNoteLength(beatLength), "beatLength", beatLength);
7701
- assertArg(import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(dotted) || import_ts_utils_lib15.Utils.Is.isIntegerGte(dotted, 0), "dotted", dotted);
8015
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(beatLength, import_theory13.NoteLength) || isNoteLength(beatLength), "beatLength", beatLength);
8016
+ assertArg(import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(dotted) || import_ts_utils_lib16.Utils.Is.isIntegerGte(dotted, 0), "dotted", dotted);
7702
8017
  }
7703
8018
  this.getMeasure().setTempo(beatsPerMinute, beatLength, dotted);
7704
8019
  return this;
@@ -7714,15 +8029,19 @@ var DocumentBuilder = class {
7714
8029
  addNote(voiceId, note, noteLength, noteOptions) {
7715
8030
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7716
8031
  assertArg(
7717
- note instanceof import_theory13.Note || import_ts_utils_lib15.Utils.Is.isNonEmptyString(note) || import_ts_utils_lib15.Utils.Is.isArray(note) && note.every((note2) => note2 instanceof import_theory13.Note || import_ts_utils_lib15.Utils.Is.isNonEmptyString(note2)),
8032
+ note instanceof import_theory13.Note || import_ts_utils_lib16.Utils.Is.isNonEmptyString(note) || import_ts_utils_lib16.Utils.Is.isArray(note) && note.every((note2) => note2 instanceof import_theory13.Note || import_ts_utils_lib16.Utils.Is.isNonEmptyString(note2)),
7718
8033
  "note",
7719
8034
  note
7720
8035
  );
7721
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
8036
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
7722
8037
  noteOptions != null ? noteOptions : noteOptions = {};
7723
8038
  assertNoteOptions(noteOptions);
7724
- if (import_ts_utils_lib15.Utils.Is.isArray(note)) {
7725
- note.forEach((note2) => this.getMeasure().addNoteGroup(voiceId, [note2], noteLength, noteOptions));
8039
+ if (import_ts_utils_lib16.Utils.Is.isArray(note)) {
8040
+ let string = noteOptions.string;
8041
+ note.forEach((note2, noteId) => {
8042
+ noteOptions.string = import_ts_utils_lib16.Utils.Is.isArray(string) ? string[noteId] : string;
8043
+ this.getMeasure().addNoteGroup(voiceId, [note2], noteLength, noteOptions);
8044
+ });
7726
8045
  } else {
7727
8046
  this.getMeasure().addNoteGroup(voiceId, [note], noteLength, noteOptions);
7728
8047
  }
@@ -7738,8 +8057,8 @@ var DocumentBuilder = class {
7738
8057
  */
7739
8058
  addChord(voiceId, notes, noteLength, noteOptions) {
7740
8059
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7741
- assertArg(import_ts_utils_lib15.Utils.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof import_theory13.Note || import_ts_utils_lib15.Utils.Is.isNonEmptyString(note)), "notes", notes);
7742
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
8060
+ assertArg(import_ts_utils_lib16.Utils.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof import_theory13.Note || import_ts_utils_lib16.Utils.Is.isNonEmptyString(note)), "notes", notes);
8061
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
7743
8062
  noteOptions != null ? noteOptions : noteOptions = {};
7744
8063
  assertNoteOptions(noteOptions);
7745
8064
  this.getMeasure().addNoteGroup(voiceId, notes, noteLength, noteOptions);
@@ -7754,7 +8073,7 @@ var DocumentBuilder = class {
7754
8073
  */
7755
8074
  addRest(voiceId, restLength, restOptions) {
7756
8075
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7757
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(restLength, import_theory13.NoteLength) || isNoteLength(restLength), "restLength", restLength);
8076
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(restLength, import_theory13.NoteLength) || isNoteLength(restLength), "restLength", restLength);
7758
8077
  restOptions != null ? restOptions : restOptions = {};
7759
8078
  assertRestOptions(restOptions);
7760
8079
  this.getMeasure().addRest(voiceId, restLength, restOptions);
@@ -7762,13 +8081,13 @@ var DocumentBuilder = class {
7762
8081
  }
7763
8082
  /**
7764
8083
  * Usage:
7765
- * <pre>
8084
+ * ```ts
7766
8085
  * addTuplet(0, Theory.Tuplet.Triplet, notes => {
7767
8086
  * notes.addNote("G3", Theory.NoteLength.Eighth);
7768
8087
  * notes.addNote("B3", Theory.NoteLength.Eighth);
7769
8088
  * notes.addNote("D4", Theory.NoteLength.Eighth);
7770
8089
  * });
7771
- * </pre>
8090
+ * ```
7772
8091
  *
7773
8092
  * @param voiceId - Voice id to add tuplet to.
7774
8093
  * @param tupletRatio - You can also use Theory.Tuplet presets (e.g. Theory.Tuplet.Triplet).
@@ -7777,22 +8096,24 @@ var DocumentBuilder = class {
7777
8096
  */
7778
8097
  addTuplet(voiceId, tupletRatio, tupletBuilder) {
7779
8098
  assertArg(isVoiceId(voiceId), "voiceId", voiceId);
7780
- assertArg(import_ts_utils_lib15.Utils.Is.isFunction(tupletBuilder), "tupletBuilder", tupletBuilder);
7781
- assertArg(isTupletRatio(tupletRatio) && import_ts_utils_lib15.Utils.Is.isBooleanOrUndefined(tupletRatio.showRatio), "tupletRatio", tupletRatio);
8099
+ assertArg(import_ts_utils_lib16.Utils.Is.isFunction(tupletBuilder), "tupletBuilder", tupletBuilder);
8100
+ assertArg(isTupletRatio(tupletRatio) && import_ts_utils_lib16.Utils.Is.isBooleanOrUndefined(tupletRatio.showRatio), "tupletRatio", tupletRatio);
7782
8101
  let tupletSymbols = [];
7783
8102
  const helper = {
7784
8103
  addNote: (note, noteLength, noteOptions) => {
7785
8104
  assertArg(
7786
- note instanceof import_theory13.Note || import_ts_utils_lib15.Utils.Is.isNonEmptyString(note) || import_ts_utils_lib15.Utils.Is.isArray(note) && note.every((note2) => note2 instanceof import_theory13.Note || import_ts_utils_lib15.Utils.Is.isNonEmptyString(note2)),
8105
+ note instanceof import_theory13.Note || import_ts_utils_lib16.Utils.Is.isNonEmptyString(note) || import_ts_utils_lib16.Utils.Is.isArray(note) && note.every((note2) => note2 instanceof import_theory13.Note || import_ts_utils_lib16.Utils.Is.isNonEmptyString(note2)),
7787
8106
  "note",
7788
8107
  note
7789
8108
  );
7790
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
8109
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
7791
8110
  noteOptions != null ? noteOptions : noteOptions = {};
7792
8111
  delete noteOptions.triplet;
7793
8112
  assertNoteOptions(noteOptions);
7794
- if (import_ts_utils_lib15.Utils.Is.isArray(note)) {
7795
- note.forEach((note2) => {
8113
+ if (import_ts_utils_lib16.Utils.Is.isArray(note)) {
8114
+ let string = noteOptions.string;
8115
+ note.forEach((note2, noteId) => {
8116
+ noteOptions.string = import_ts_utils_lib16.Utils.Is.isArray(string) ? string[noteId] : string;
7796
8117
  let s = this.getMeasure().addNoteGroup(voiceId, [note2], noteLength, noteOptions, tupletRatio);
7797
8118
  tupletSymbols.push(s);
7798
8119
  });
@@ -7803,8 +8124,8 @@ var DocumentBuilder = class {
7803
8124
  return helper;
7804
8125
  },
7805
8126
  addChord: (notes, noteLength, noteOptions) => {
7806
- assertArg(import_ts_utils_lib15.Utils.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof import_theory13.Note || import_ts_utils_lib15.Utils.Is.isNonEmptyString(note)), "notes", notes);
7807
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
8127
+ assertArg(import_ts_utils_lib16.Utils.Is.isNonEmptyArray(notes) && notes.every((note) => note instanceof import_theory13.Note || import_ts_utils_lib16.Utils.Is.isNonEmptyString(note)), "notes", notes);
8128
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
7808
8129
  noteOptions != null ? noteOptions : noteOptions = {};
7809
8130
  delete noteOptions.triplet;
7810
8131
  assertNoteOptions(noteOptions);
@@ -7813,7 +8134,7 @@ var DocumentBuilder = class {
7813
8134
  return helper;
7814
8135
  },
7815
8136
  addRest: (restLength, restOptions) => {
7816
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(restLength, import_theory13.NoteLength) || isNoteLength(restLength), "restLength", restLength);
8137
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(restLength, import_theory13.NoteLength) || isNoteLength(restLength), "restLength", restLength);
7817
8138
  restOptions != null ? restOptions : restOptions = {};
7818
8139
  delete restOptions.triplet;
7819
8140
  assertRestOptions(restOptions);
@@ -7830,8 +8151,8 @@ var DocumentBuilder = class {
7830
8151
  var _a;
7831
8152
  assertStaffTabOrGRoups(staffTabOrGroups);
7832
8153
  assertArg(isVerseNumber(verse), "verse", verse);
7833
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(lyricsLength, import_theory13.NoteLength), "lyricsLength", lyricsLength);
7834
- assertArg(import_ts_utils_lib15.Utils.Is.isString(lyricsText) || import_ts_utils_lib15.Utils.Is.isArray(lyricsText) && lyricsText.every((text) => import_ts_utils_lib15.Utils.Is.isString(text)), "lyricsText", lyricsText);
8154
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(lyricsLength, import_theory13.NoteLength), "lyricsLength", lyricsLength);
8155
+ assertArg(import_ts_utils_lib16.Utils.Is.isString(lyricsText) || import_ts_utils_lib16.Utils.Is.isArray(lyricsText) && lyricsText.every((text) => import_ts_utils_lib16.Utils.Is.isString(text)), "lyricsText", lyricsText);
7835
8156
  lyricsOptions != null ? lyricsOptions : lyricsOptions = {};
7836
8157
  assertLyricsOptions(lyricsOptions);
7837
8158
  if (lyricsOptions.align !== void 0) {
@@ -7839,7 +8160,7 @@ var DocumentBuilder = class {
7839
8160
  } else {
7840
8161
  (_a = lyricsOptions.align) != null ? _a : lyricsOptions.align = this.currentLyricsAlign;
7841
8162
  }
7842
- if (import_ts_utils_lib15.Utils.Is.isArray(lyricsText)) {
8163
+ if (import_ts_utils_lib16.Utils.Is.isArray(lyricsText)) {
7843
8164
  lyricsText.forEach((text) => this.getMeasure().addLyrics(staffTabOrGroups, verse, lyricsLength, text, lyricsOptions));
7844
8165
  } else {
7845
8166
  this.getMeasure().addLyrics(staffTabOrGroups, verse, lyricsLength, lyricsText, lyricsOptions);
@@ -7871,7 +8192,7 @@ var DocumentBuilder = class {
7871
8192
  }
7872
8193
  addFermataInternal(staffTabOrGroups, fermata) {
7873
8194
  assertStaffTabOrGRoups(staffTabOrGroups);
7874
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(fermata, Fermata), "fermata", fermata);
8195
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(fermata, Fermata), "fermata", fermata);
7875
8196
  this.getMeasure().addFermata(staffTabOrGroups, fermata);
7876
8197
  return this;
7877
8198
  }
@@ -7894,11 +8215,11 @@ var DocumentBuilder = class {
7894
8215
  }
7895
8216
  addNavigationInternal(staffTabOrGroups, navigation, ...args) {
7896
8217
  assertStaffTabOrGRoups(staffTabOrGroups);
7897
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(navigation, Navigation), "navigation", navigation);
8218
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(navigation, Navigation), "navigation", navigation);
7898
8219
  if (navigation === "endRepeat" /* EndRepeat */ && args.length > 0) {
7899
- assertArg(import_ts_utils_lib15.Utils.Is.isIntegerGte(args[0], 1), "playCount", args[0]);
8220
+ assertArg(import_ts_utils_lib16.Utils.Is.isIntegerGte(args[0], 1), "playCount", args[0]);
7900
8221
  } else if (navigation === "ending" /* Ending */ && args.length > 0) {
7901
- assertArg(args.every((passage) => import_ts_utils_lib15.Utils.Is.isIntegerGte(passage, 1)), "passages", args);
8222
+ assertArg(args.every((passage) => import_ts_utils_lib16.Utils.Is.isIntegerGte(passage, 1)), "passages", args);
7902
8223
  }
7903
8224
  this.getMeasure().addNavigation(staffTabOrGroups, navigation, ...args);
7904
8225
  return this;
@@ -7912,11 +8233,11 @@ var DocumentBuilder = class {
7912
8233
  addAnnotationInternal(staffTabOrGroups, annotation, text) {
7913
8234
  annotation != null ? annotation : annotation = getAnnotation(text);
7914
8235
  if (annotation === void 0) {
7915
- throw new import_core18.MusicError(import_core18.MusicErrorType.Score, `Annotation text "${text}" is not known annotation.`);
8236
+ throw new import_core19.MusicError(import_core19.MusicErrorType.Score, `Annotation text "${text}" is not known annotation.`);
7916
8237
  }
7917
8238
  assertStaffTabOrGRoups(staffTabOrGroups);
7918
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
7919
- assertArg(import_ts_utils_lib15.Utils.Is.isNonEmptyString(text), "text", text);
8239
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(annotation, Annotation), "annotation", annotation);
8240
+ assertArg(import_ts_utils_lib16.Utils.Is.isNonEmptyString(text), "text", text);
7920
8241
  this.getMeasure().addAnnotation(staffTabOrGroups, annotation, text);
7921
8242
  return this;
7922
8243
  }
@@ -7936,8 +8257,8 @@ var DocumentBuilder = class {
7936
8257
  }
7937
8258
  addLabelInternal(staffTabOrGroups, label, text) {
7938
8259
  assertStaffTabOrGRoups(staffTabOrGroups);
7939
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(label, Label), "label", label);
7940
- assertArg(import_ts_utils_lib15.Utils.Is.isNonEmptyString(text), "text", text);
8260
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(label, Label), "label", label);
8261
+ assertArg(import_ts_utils_lib16.Utils.Is.isNonEmptyString(text), "text", text);
7941
8262
  this.getMeasure().addLabel(staffTabOrGroups, label, text);
7942
8263
  return this;
7943
8264
  }
@@ -7961,21 +8282,21 @@ var DocumentBuilder = class {
7961
8282
  return this.addLabelInternal(staffTabOrGroups, label, text);
7962
8283
  }
7963
8284
  addConnective(connective, ...args) {
7964
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(connective, Connective), "connective", connective);
8285
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(connective, Connective), "connective", connective);
7965
8286
  if (connective === "tie" /* Tie */) {
7966
- assertArg(import_ts_utils_lib15.Utils.Is.isIntegerOrUndefined(args[0]) || import_ts_utils_lib15.Utils.Is.isEnumValue(args[0], TieType), "tieSpan", args[0]);
7967
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
8287
+ assertArg(import_ts_utils_lib16.Utils.Is.isIntegerOrUndefined(args[0]) || import_ts_utils_lib16.Utils.Is.isEnumValue(args[0], TieType), "tieSpan", args[0]);
8288
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
7968
8289
  let tieSpan = args[0];
7969
8290
  let noteAnchor = args[1];
7970
8291
  this.getMeasure().addConnective(connective, tieSpan, noteAnchor);
7971
8292
  } else if (connective === "slur" /* Slur */) {
7972
- assertArg(import_ts_utils_lib15.Utils.Is.isIntegerOrUndefined(args[0]), "slurSpan", args[0]);
7973
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
8293
+ assertArg(import_ts_utils_lib16.Utils.Is.isIntegerOrUndefined(args[0]), "slurSpan", args[0]);
8294
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(args[1], NoteAnchor), "noteAnchor", args[1]);
7974
8295
  let slurSpan = args[0];
7975
8296
  let noteAnchor = args[1];
7976
8297
  this.getMeasure().addConnective(connective, slurSpan, noteAnchor);
7977
8298
  } else if (connective === "slide" /* Slide */) {
7978
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValueOrUndefined(args[0], NoteAnchor), "noteAnchor", args[0]);
8299
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValueOrUndefined(args[0], NoteAnchor), "noteAnchor", args[0]);
7979
8300
  let noteAnchor = args[0];
7980
8301
  this.getMeasure().addConnective(connective, noteAnchor);
7981
8302
  }
@@ -7983,29 +8304,29 @@ var DocumentBuilder = class {
7983
8304
  }
7984
8305
  /**
7985
8306
  * Add extension line to previously added annotation or label element.
7986
- * <pre>
8307
+ * ```ts
7987
8308
  * // Example
7988
8309
  * addExtension(ext => ext.notes("1n", 2)) // length is 2 whole notes
7989
8310
  * addExtension(ext => ext.measures(3).hide()) // length is 3 measures, hidden
7990
8311
  * addExtension(ext => ext.measures(1).notes("8n")) // length is 1 measure + 1 eigth note
7991
8312
  * addExtension(ext => ext.infinity()) // length is as long as possible
7992
- * </pre>
8313
+ * ```
7993
8314
  * @param extensionBuilder - Extension builder function used to build exstension.
7994
8315
  * @returns - This document builder instance.
7995
8316
  */
7996
8317
  addExtension(extensionBuilder) {
7997
- assertArg(import_ts_utils_lib15.Utils.Is.isFunctionOrUndefined(extensionBuilder), "addExtension() has new usage, for e.g. addExtension(ext => ext.measures(2)). Please refer to README or API Reference.", extensionBuilder);
8318
+ assertArg(import_ts_utils_lib16.Utils.Is.isFunctionOrUndefined(extensionBuilder), "addExtension() has new usage, for e.g. addExtension(ext => ext.measures(2)). Please refer to README or API Reference.", extensionBuilder);
7998
8319
  let ticks = 0;
7999
8320
  let visible = true;
8000
8321
  const helper = {
8001
8322
  notes: (noteLength, noteCount) => {
8002
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
8003
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(noteCount) || import_ts_utils_lib15.Utils.Is.isNumber(noteCount) && noteCount >= 0, "noteCount", noteCount);
8323
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(noteLength, import_theory13.NoteLength) || isNoteLength(noteLength), "noteLength", noteLength);
8324
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(noteCount) || import_ts_utils_lib16.Utils.Is.isNumber(noteCount) && noteCount >= 0, "noteCount", noteCount);
8004
8325
  ticks += import_theory13.RhythmProps.get(noteLength).ticks * (noteCount != null ? noteCount : 1);
8005
8326
  return helper;
8006
8327
  },
8007
8328
  measures: (measureCount) => {
8008
- assertArg(import_ts_utils_lib15.Utils.Is.isNumber(measureCount) && measureCount >= 1, "measureCount", measureCount);
8329
+ assertArg(import_ts_utils_lib16.Utils.Is.isNumber(measureCount) && measureCount >= 1, "measureCount", measureCount);
8009
8330
  ticks += this.getMeasure().getMeasureTicks() * measureCount;
8010
8331
  return helper;
8011
8332
  },
@@ -8034,13 +8355,13 @@ var DocumentBuilder = class {
8034
8355
  * @returns - This document builder instance.
8035
8356
  */
8036
8357
  addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition = "auto" /* Auto */) {
8037
- assertArg(import_ts_utils_lib15.Utils.Is.isNonEmptyString(groupName), "groupName", groupName);
8358
+ assertArg(import_ts_utils_lib16.Utils.Is.isNonEmptyString(groupName), "groupName", groupName);
8038
8359
  assertArg(
8039
- import_ts_utils_lib15.Utils.Is.isNonEmptyString(staffsTabsAndGroups) || import_ts_utils_lib15.Utils.Is.isIntegerGte(staffsTabsAndGroups, 0) || import_ts_utils_lib15.Utils.Is.isNonEmptyArray(staffsTabsAndGroups) && staffsTabsAndGroups.every((line) => import_ts_utils_lib15.Utils.Is.isNonEmptyString(line) || import_ts_utils_lib15.Utils.Is.isIntegerGte(line, 0)),
8360
+ import_ts_utils_lib16.Utils.Is.isNonEmptyString(staffsTabsAndGroups) || import_ts_utils_lib16.Utils.Is.isIntegerGte(staffsTabsAndGroups, 0) || import_ts_utils_lib16.Utils.Is.isNonEmptyArray(staffsTabsAndGroups) && staffsTabsAndGroups.every((line) => import_ts_utils_lib16.Utils.Is.isNonEmptyString(line) || import_ts_utils_lib16.Utils.Is.isIntegerGte(line, 0)),
8040
8361
  "staffsTabsAndGroups",
8041
8362
  staffsTabsAndGroups
8042
8363
  );
8043
- assertArg(import_ts_utils_lib15.Utils.Is.isEnumValue(verticalPosition, VerticalPosition), "verticalPosition", verticalPosition);
8364
+ assertArg(import_ts_utils_lib16.Utils.Is.isEnumValue(verticalPosition, VerticalPosition), "verticalPosition", verticalPosition);
8044
8365
  this.doc.addStaffGroup(groupName, staffsTabsAndGroups, verticalPosition);
8045
8366
  return this;
8046
8367
  }
@@ -8075,7 +8396,7 @@ var DocumentBuilder = class {
8075
8396
  * @returns - This document builder instance.
8076
8397
  */
8077
8398
  completeRests(voiceId) {
8078
- assertArg(import_ts_utils_lib15.Utils.Is.isUndefined(voiceId) || isVoiceId(voiceId) || import_ts_utils_lib15.Utils.Is.isArray(voiceId) && voiceId.every((id) => isVoiceId(id)), "voiceId", voiceId);
8399
+ assertArg(import_ts_utils_lib16.Utils.Is.isUndefined(voiceId) || isVoiceId(voiceId) || import_ts_utils_lib16.Utils.Is.isArray(voiceId) && voiceId.every((id) => isVoiceId(id)), "voiceId", voiceId);
8079
8400
  this.getMeasure().completeRests(voiceId);
8080
8401
  return this;
8081
8402
  }
@@ -8087,8 +8408,8 @@ var DocumentBuilder = class {
8087
8408
  * @returns - This document builder instance.
8088
8409
  */
8089
8410
  addScaleArpeggio(scale, bottomNote, numOctaves) {
8090
- assertArg(import_ts_utils_lib15.Utils.Is.isNonEmptyString(bottomNote), "bottomNote", bottomNote);
8091
- assertArg(import_ts_utils_lib15.Utils.Is.isIntegerGte(numOctaves, 1), "numOctaves", numOctaves);
8411
+ assertArg(import_ts_utils_lib16.Utils.Is.isNonEmptyString(bottomNote), "bottomNote", bottomNote);
8412
+ assertArg(import_ts_utils_lib16.Utils.Is.isIntegerGte(numOctaves, 1), "numOctaves", numOctaves);
8092
8413
  let ts = this.getMeasure().getTimeSignature();
8093
8414
  let notes = scale.getScaleNotes(bottomNote, numOctaves);
8094
8415
  for (let i = 0; i < notes.length; i++) {
@@ -8104,7 +8425,7 @@ var DocumentBuilder = class {
8104
8425
  };
8105
8426
 
8106
8427
  // src/score/pub/event.ts
8107
- var import_core19 = require("@tspro/web-music-score/core");
8428
+ var import_core20 = require("@tspro/web-music-score/core");
8108
8429
  var ScoreEvent = class {
8109
8430
  /**
8110
8431
  * Create new score event instance.
@@ -8141,7 +8462,7 @@ var ScoreObjectEvent = class extends ScoreEvent {
8141
8462
  this.renderer = renderer;
8142
8463
  this.objects = objects;
8143
8464
  if (arguments.length === 0) {
8144
- throw new import_core19.MusicError(import_core19.MusicErrorType.Score, "Empty array in score object event!");
8465
+ throw new import_core20.MusicError(import_core20.MusicErrorType.Score, "Empty array in score object event!");
8145
8466
  }
8146
8467
  }
8147
8468
  /** Top object getter. */
@@ -8160,24 +8481,24 @@ var ScoreObjectEvent = class extends ScoreEvent {
8160
8481
 
8161
8482
  // src/score/pub/music-interface.ts
8162
8483
  var Audio2 = __toESM(require("@tspro/web-music-score/audio"));
8163
- var import_ts_utils_lib17 = require("@tspro/ts-utils-lib");
8484
+ var import_ts_utils_lib18 = require("@tspro/ts-utils-lib");
8164
8485
 
8165
8486
  // src/score/pub/music-objects.ts
8166
- var import_ts_utils_lib16 = require("@tspro/ts-utils-lib");
8167
- var import_core20 = require("@tspro/web-music-score/core");
8487
+ var import_ts_utils_lib17 = require("@tspro/ts-utils-lib");
8488
+ var import_core21 = require("@tspro/web-music-score/core");
8168
8489
  function assertArg2(condition, argName, argValue) {
8169
8490
  if (!condition) {
8170
- throw new import_core20.MusicError(import_core20.MusicErrorType.Score, `Invalid arg: ${argName} = ${argValue}`);
8491
+ throw new import_core21.MusicError(import_core21.MusicErrorType.Score, `Invalid arg: ${argName} = ${argValue}`);
8171
8492
  }
8172
8493
  }
8173
8494
  function isVoiceId2(value) {
8174
- return import_ts_utils_lib16.Utils.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
8495
+ return import_ts_utils_lib17.Utils.Is.isNumber(value) && getVoiceIds().indexOf(value) >= 0;
8175
8496
  }
8176
8497
  function getNotationLine(line) {
8177
8498
  if (line instanceof ObjStaff || line instanceof ObjTab) {
8178
8499
  return line.getMusicInterface();
8179
8500
  } else {
8180
- throw new import_core20.MusicError(import_core20.MusicErrorType.Score, `Notation line not staff nor tab.`);
8501
+ throw new import_core21.MusicError(import_core21.MusicErrorType.Score, `Notation line not staff nor tab.`);
8181
8502
  }
8182
8503
  }
8183
8504
  var MusicInterface6 = class {
@@ -8347,7 +8668,7 @@ var _MDocument = class _MDocument extends MusicInterface6 {
8347
8668
  * @returns - Player instance.
8348
8669
  */
8349
8670
  play(playStateChangeListener) {
8350
- assertArg2(import_ts_utils_lib16.Utils.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
8671
+ assertArg2(import_ts_utils_lib17.Utils.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
8351
8672
  return new MPlayer(this, playStateChangeListener).play();
8352
8673
  }
8353
8674
  };
@@ -8377,7 +8698,7 @@ var _MEnding = class _MEnding extends MusicInterface6 {
8377
8698
  * @returns - Boolean whether this ending has asked passage number.
8378
8699
  */
8379
8700
  hasPassage(passage) {
8380
- assertArg2(import_ts_utils_lib16.Utils.Is.isIntegerGte(passage, 1), "passage", passage);
8701
+ assertArg2(import_ts_utils_lib17.Utils.Is.isIntegerGte(passage, 1), "passage", passage);
8381
8702
  return this.obj.hasPassage(passage);
8382
8703
  }
8383
8704
  };
@@ -8529,7 +8850,7 @@ var _MStaffTabBarLine = class _MStaffTabBarLine extends MusicInterface6 {
8529
8850
  if (barLine instanceof ObjBarLineLeft || barLine instanceof ObjBarLineRight) {
8530
8851
  return barLine.getMusicInterface();
8531
8852
  } else {
8532
- throw new import_core20.MusicError(import_core20.MusicErrorType.Score, `Bar line not let nor right.`);
8853
+ throw new import_core21.MusicError(import_core21.MusicErrorType.Score, `Bar line not let nor right.`);
8533
8854
  }
8534
8855
  }
8535
8856
  /**
@@ -8893,10 +9214,10 @@ var _MTab = class _MTab extends MusicInterface6 {
8893
9214
  /** Object name. */
8894
9215
  __publicField(_MTab, "Name", "Tab");
8895
9216
  var MTab = _MTab;
8896
- var _MSignature = class _MSignature extends MusicInterface6 {
9217
+ var _MStaffSignature = class _MStaffSignature extends MusicInterface6 {
8897
9218
  /** @internal */
8898
9219
  constructor(obj) {
8899
- super(_MSignature.Name);
9220
+ super(_MStaffSignature.Name);
8900
9221
  this.obj = obj;
8901
9222
  }
8902
9223
  /** @internal */
@@ -8912,8 +9233,57 @@ var _MSignature = class _MSignature extends MusicInterface6 {
8912
9233
  }
8913
9234
  };
8914
9235
  /** Object name. */
8915
- __publicField(_MSignature, "Name", "Signature");
8916
- var MSignature = _MSignature;
9236
+ __publicField(_MStaffSignature, "Name", "StaffSignature");
9237
+ var MStaffSignature = _MStaffSignature;
9238
+ var _MTabSignature = class _MTabSignature extends MusicInterface6 {
9239
+ /** @internal */
9240
+ constructor(obj) {
9241
+ super(_MTabSignature.Name);
9242
+ this.obj = obj;
9243
+ }
9244
+ /** @internal */
9245
+ getMusicObject() {
9246
+ return this.obj;
9247
+ }
9248
+ /**
9249
+ * Get tab notation line this signature is in.
9250
+ * @returns - Tab object.
9251
+ */
9252
+ getTab() {
9253
+ return this.obj.tab.getMusicInterface();
9254
+ }
9255
+ };
9256
+ /** Object name. */
9257
+ __publicField(_MTabSignature, "Name", "TabSignature");
9258
+ var MTabSignature = _MTabSignature;
9259
+ var _MTabRhythm = class _MTabRhythm extends MusicInterface6 {
9260
+ /** @internal */
9261
+ constructor(obj) {
9262
+ super(_MTabRhythm.Name);
9263
+ this.obj = obj;
9264
+ }
9265
+ /** @internal */
9266
+ getMusicObject() {
9267
+ return this.obj;
9268
+ }
9269
+ /**
9270
+ * Get measure.
9271
+ * @returns - Measure.
9272
+ */
9273
+ getMeasure() {
9274
+ return this.obj.measure.getMusicInterface();
9275
+ }
9276
+ /**
9277
+ * Get tab.
9278
+ * @returns - Tab.
9279
+ */
9280
+ getTab() {
9281
+ return this.obj.tab.getMusicInterface();
9282
+ }
9283
+ };
9284
+ /** Object name. */
9285
+ __publicField(_MTabRhythm, "Name", "TabRhythm");
9286
+ var MTabRhythm = _MTabRhythm;
8917
9287
  var _MSpecialText = class _MSpecialText extends MusicInterface6 {
8918
9288
  /** @internal */
8919
9289
  constructor(obj) {
@@ -8993,10 +9363,10 @@ __publicField(_MExtensionLine, "Name", "ExtensionLine");
8993
9363
  var MExtensionLine = _MExtensionLine;
8994
9364
 
8995
9365
  // src/score/pub/music-interface.ts
8996
- var import_core21 = require("@tspro/web-music-score/core");
9366
+ var import_core22 = require("@tspro/web-music-score/core");
8997
9367
  function assertArg3(condition, argName, argValue) {
8998
9368
  if (!condition) {
8999
- throw new import_core21.MusicError(import_core21.MusicErrorType.Score, `Invalid arg: ${argName} = ${argValue}`);
9369
+ throw new import_core22.MusicError(import_core22.MusicErrorType.Score, `Invalid arg: ${argName} = ${argValue}`);
9000
9370
  }
9001
9371
  }
9002
9372
  function require_t(t, message) {
@@ -9015,7 +9385,7 @@ var _MPlayer = class _MPlayer {
9015
9385
  constructor(doc, playStateChangeListener) {
9016
9386
  __publicField(this, "player");
9017
9387
  assertArg3(doc instanceof MDocument2, "doc", doc);
9018
- assertArg3(import_ts_utils_lib17.Utils.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
9388
+ assertArg3(import_ts_utils_lib18.Utils.Is.isFunctionOrUndefined(playStateChangeListener), "playStateChangeListener", playStateChangeListener);
9019
9389
  this.player = new Player();
9020
9390
  this.player.setDocument(doc.getMusicObject());
9021
9391
  this.player.setCursorPositionChangeListener((cursorRect) => doc.getMusicObject().updateCursorRect(cursorRect));
@@ -9073,7 +9443,7 @@ var MRenderer2 = class {
9073
9443
  * @returns - This renderer instance.
9074
9444
  */
9075
9445
  setDocument(doc) {
9076
- assertArg3(import_ts_utils_lib17.Utils.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
9446
+ assertArg3(import_ts_utils_lib18.Utils.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
9077
9447
  this.renderer.setDocument(doc);
9078
9448
  return this;
9079
9449
  }
@@ -9083,7 +9453,7 @@ var MRenderer2 = class {
9083
9453
  * @returns - This renderer instance.
9084
9454
  */
9085
9455
  setCanvas(canvas) {
9086
- canvas = require_t(import_ts_utils_lib17.Utils.Dom.getCanvas(canvas), typeof canvas === "string" ? "Cannot set renderer canvas because invalid canvas id: " + canvas : "Cannot set renderer canvas because given canvas is undefined.");
9456
+ canvas = require_t(import_ts_utils_lib18.Utils.Dom.getCanvas(canvas), typeof canvas === "string" ? "Cannot set renderer canvas because invalid canvas id: " + canvas : "Cannot set renderer canvas because given canvas is undefined.");
9087
9457
  this.renderer.setCanvas(canvas);
9088
9458
  return this;
9089
9459
  }
@@ -9092,7 +9462,7 @@ var MRenderer2 = class {
9092
9462
  * @param scoreEventListener - Score event listener.
9093
9463
  */
9094
9464
  setScoreEventListener(scoreEventListener) {
9095
- assertArg3(import_ts_utils_lib17.Utils.Is.isFunctionOrUndefined(scoreEventListener), "scoreEventListener", scoreEventListener);
9465
+ assertArg3(import_ts_utils_lib18.Utils.Is.isFunctionOrUndefined(scoreEventListener), "scoreEventListener", scoreEventListener);
9096
9466
  this.renderer.setScoreEventListener(scoreEventListener);
9097
9467
  }
9098
9468
  /**
@@ -9166,7 +9536,7 @@ var _MPlaybackButtons = class _MPlaybackButtons {
9166
9536
  * @returns
9167
9537
  */
9168
9538
  setDocument(doc) {
9169
- assertArg3(import_ts_utils_lib17.Utils.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
9539
+ assertArg3(import_ts_utils_lib18.Utils.Is.isUndefined(doc) || doc instanceof MDocument2, "doc", doc);
9170
9540
  this.onStop();
9171
9541
  if (doc) {
9172
9542
  this.player = new MPlayer(doc, (playState) => {
@@ -9210,9 +9580,9 @@ var _MPlaybackButtons = class _MPlaybackButtons {
9210
9580
  * @returns - This playback buttons class instance.
9211
9581
  */
9212
9582
  setPlayButton(btn, btnLabel) {
9213
- assertArg3(import_ts_utils_lib17.Utils.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9583
+ assertArg3(import_ts_utils_lib18.Utils.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9214
9584
  _MPlaybackButtons.removeOnClickListeners(this.playButton, this.onPlay);
9215
- this.playButton = require_t(import_ts_utils_lib17.Utils.Dom.getButton(btn), "Play button required!");
9585
+ this.playButton = require_t(import_ts_utils_lib18.Utils.Dom.getButton(btn), "Play button required!");
9216
9586
  this.playLabel = btnLabel != null ? btnLabel : "Play";
9217
9587
  _MPlaybackButtons.removeOnClickListeners(this.playButton, "all");
9218
9588
  _MPlaybackButtons.addOnClickListener(this.playButton, this.onPlay);
@@ -9226,9 +9596,9 @@ var _MPlaybackButtons = class _MPlaybackButtons {
9226
9596
  * @returns - This playback buttons class instance.
9227
9597
  */
9228
9598
  setStopButton(btn, btnLabel) {
9229
- assertArg3(import_ts_utils_lib17.Utils.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9599
+ assertArg3(import_ts_utils_lib18.Utils.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9230
9600
  _MPlaybackButtons.removeOnClickListeners(this.stopButton, this.onStop);
9231
- this.stopButton = require_t(import_ts_utils_lib17.Utils.Dom.getButton(btn), "Stop button required!");
9601
+ this.stopButton = require_t(import_ts_utils_lib18.Utils.Dom.getButton(btn), "Stop button required!");
9232
9602
  this.stopLabel = btnLabel != null ? btnLabel : "Stop";
9233
9603
  _MPlaybackButtons.removeOnClickListeners(this.stopButton, "all");
9234
9604
  _MPlaybackButtons.addOnClickListener(this.stopButton, this.onStop);
@@ -9243,10 +9613,10 @@ var _MPlaybackButtons = class _MPlaybackButtons {
9243
9613
  * @returns - This playback buttons class instance.
9244
9614
  */
9245
9615
  setPlayStopButton(btn, playLabel, stopLabel) {
9246
- assertArg3(import_ts_utils_lib17.Utils.Is.isStringOrUndefined(playLabel), "playLabel", playLabel);
9247
- assertArg3(import_ts_utils_lib17.Utils.Is.isStringOrUndefined(stopLabel), "stopLabel", stopLabel);
9616
+ assertArg3(import_ts_utils_lib18.Utils.Is.isStringOrUndefined(playLabel), "playLabel", playLabel);
9617
+ assertArg3(import_ts_utils_lib18.Utils.Is.isStringOrUndefined(stopLabel), "stopLabel", stopLabel);
9248
9618
  _MPlaybackButtons.removeOnClickListeners(this.playStopButton, this.onPlayStop);
9249
- this.playStopButton = require_t(import_ts_utils_lib17.Utils.Dom.getButton(btn), "Play/stop button required!");
9619
+ this.playStopButton = require_t(import_ts_utils_lib18.Utils.Dom.getButton(btn), "Play/stop button required!");
9250
9620
  this.playLabel = playLabel != null ? playLabel : "Play";
9251
9621
  this.stopLabel = stopLabel != null ? stopLabel : "Stop";
9252
9622
  _MPlaybackButtons.removeOnClickListeners(this.playStopButton, "all");
@@ -9261,9 +9631,9 @@ var _MPlaybackButtons = class _MPlaybackButtons {
9261
9631
  * @returns - This playback buttons class instance.
9262
9632
  */
9263
9633
  setPauseButton(btn, btnLabel) {
9264
- assertArg3(import_ts_utils_lib17.Utils.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9634
+ assertArg3(import_ts_utils_lib18.Utils.Is.isStringOrUndefined(btnLabel), "btnLabel", btnLabel);
9265
9635
  _MPlaybackButtons.removeOnClickListeners(this.pauseButton, this.onPause);
9266
- this.pauseButton = require_t(import_ts_utils_lib17.Utils.Dom.getButton(btn), "Pause button required!");
9636
+ this.pauseButton = require_t(import_ts_utils_lib18.Utils.Dom.getButton(btn), "Pause button required!");
9267
9637
  this.pauseLabel = btnLabel != null ? btnLabel : "Pause";
9268
9638
  _MPlaybackButtons.removeOnClickListeners(this.pauseButton, "all");
9269
9639
  _MPlaybackButtons.addOnClickListener(this.pauseButton, this.onPause);
@@ -9285,7 +9655,7 @@ var _MPlaybackButtons = class _MPlaybackButtons {
9285
9655
  }
9286
9656
  }
9287
9657
  static addOnClickListener(btn, onClick) {
9288
- assertArg3(import_ts_utils_lib17.Utils.Is.isFunction(onClick), "onClick", onClick);
9658
+ assertArg3(import_ts_utils_lib18.Utils.Is.isFunction(onClick), "onClick", onClick);
9289
9659
  btn.addEventListener("click", onClick);
9290
9660
  let clickListeners = this.savedOnClickListeners.get(btn) || [];
9291
9661
  this.savedOnClickListeners.set(btn, [...clickListeners, onClick]);
@@ -9295,8 +9665,8 @@ __publicField(_MPlaybackButtons, "savedOnClickListeners", /* @__PURE__ */ new Ma
9295
9665
  var MPlaybackButtons = _MPlaybackButtons;
9296
9666
 
9297
9667
  // src/score/index.ts
9298
- var import_core22 = require("@tspro/web-music-score/core");
9299
- (0, import_core22.init)();
9668
+ var import_core23 = require("@tspro/web-music-score/core");
9669
+ (0, import_core23.init)();
9300
9670
  // Annotate the CommonJS export names for ESM import in node:
9301
9671
  0 && (module.exports = {
9302
9672
  Annotation,
@@ -9331,15 +9701,17 @@ var import_core22 = require("@tspro/web-music-score/core");
9331
9701
  MRest,
9332
9702
  MRhythmColumn,
9333
9703
  MScoreRow,
9334
- MSignature,
9335
9704
  MSpecialText,
9336
9705
  MStaff,
9337
9706
  MStaffBeamGroup,
9338
9707
  MStaffNoteGroup,
9339
9708
  MStaffRest,
9709
+ MStaffSignature,
9340
9710
  MStaffTabBarLine,
9341
9711
  MTab,
9342
9712
  MTabNoteGroup,
9713
+ MTabRhythm,
9714
+ MTabSignature,
9343
9715
  MText,
9344
9716
  MusicInterface,
9345
9717
  Navigation,