vibe-editor 0.0.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 (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +51 -0
  3. package/package.json +56 -0
  4. package/src/fonts/bravura/FONTLOG.txt +243 -0
  5. package/src/fonts/bravura/OFL-FAQ.txt +369 -0
  6. package/src/fonts/bravura/OFL.txt +94 -0
  7. package/src/fonts/bravura/bravura-text.md +153 -0
  8. package/src/fonts/bravura/bravura_metadata.json +34718 -0
  9. package/src/fonts/bravura/eot/Bravura.eot +0 -0
  10. package/src/fonts/bravura/eot/BravuraText.eot +0 -0
  11. package/src/fonts/bravura/otf/Bravura.otf +0 -0
  12. package/src/fonts/bravura/otf/BravuraText.otf +0 -0
  13. package/src/fonts/bravura/svg/Bravura.svg +3517 -0
  14. package/src/fonts/bravura/svg/BravuraText.svg +18879 -0
  15. package/src/fonts/bravura/woff/Bravura.woff +0 -0
  16. package/src/fonts/bravura/woff/BravuraText.woff +0 -0
  17. package/src/fonts/colaborate/ColabBol-webfont.eot +0 -0
  18. package/src/fonts/colaborate/ColabBol-webfont.svg +976 -0
  19. package/src/fonts/colaborate/ColabBol-webfont.ttf +0 -0
  20. package/src/fonts/colaborate/ColabBol-webfont.woff +0 -0
  21. package/src/fonts/colaborate/ColabLig-webfont.eot +0 -0
  22. package/src/fonts/colaborate/ColabLig-webfont.svg +976 -0
  23. package/src/fonts/colaborate/ColabLig-webfont.ttf +0 -0
  24. package/src/fonts/colaborate/ColabLig-webfont.woff +0 -0
  25. package/src/fonts/colaborate/ColabMed-webfont.eot +0 -0
  26. package/src/fonts/colaborate/ColabMed-webfont.svg +976 -0
  27. package/src/fonts/colaborate/ColabMed-webfont.ttf +0 -0
  28. package/src/fonts/colaborate/ColabMed-webfont.woff +0 -0
  29. package/src/fonts/colaborate/ColabReg-webfont.eot +0 -0
  30. package/src/fonts/colaborate/ColabReg-webfont.svg +976 -0
  31. package/src/fonts/colaborate/ColabReg-webfont.ttf +0 -0
  32. package/src/fonts/colaborate/ColabReg-webfont.woff +0 -0
  33. package/src/fonts/colaborate/ColabThi-webfont.eot +0 -0
  34. package/src/fonts/colaborate/ColabThi-webfont.svg +970 -0
  35. package/src/fonts/colaborate/ColabThi-webfont.ttf +0 -0
  36. package/src/fonts/colaborate/ColabThi-webfont.woff +0 -0
  37. package/src/images/GUI/.DS_Store +0 -0
  38. package/src/images/GUI/backward-fast-solid.svg +1 -0
  39. package/src/images/GUI/bars-solid.svg +1 -0
  40. package/src/images/GUI/caret-left-solid.svg +1 -0
  41. package/src/images/GUI/caret-right-solid.svg +1 -0
  42. package/src/images/GUI/edit-solid.svg +1 -0
  43. package/src/images/GUI/pause-solid.svg +1 -0
  44. package/src/images/GUI/play-solid.svg +1 -0
  45. package/src/images/GUI/triplet.svg +21 -0
  46. package/src/images/GUI/zoomin.svg +1 -0
  47. package/src/images/GUI/zoomout.svg +1 -0
  48. package/src/images/bravura_notes/.DS_Store +0 -0
  49. package/src/images/bravura_notes/16th.svg +1 -0
  50. package/src/images/bravura_notes/32th.svg +1 -0
  51. package/src/images/bravura_notes/alterDDown.svg +1 -0
  52. package/src/images/bravura_notes/alterDUp.svg +1 -0
  53. package/src/images/bravura_notes/alterDown.svg +1 -0
  54. package/src/images/bravura_notes/alterNeutral.svg +1 -0
  55. package/src/images/bravura_notes/alterUp.svg +1 -0
  56. package/src/images/bravura_notes/beams.svg +1 -0
  57. package/src/images/bravura_notes/eigth.svg +1 -0
  58. package/src/images/bravura_notes/full.svg +1 -0
  59. package/src/images/bravura_notes/half.svg +1 -0
  60. package/src/images/bravura_notes/oneDot.svg +1 -0
  61. package/src/images/bravura_notes/pauseNote.svg +1 -0
  62. package/src/images/bravura_notes/quarter.svg +1 -0
  63. package/src/images/bravura_notes/tie.svg +1 -0
  64. package/src/images/bravura_notes/twoDot.svg +1 -0
  65. package/src/scripts/js/.DS_Store +0 -0
  66. package/src/scripts/js/Core.js +887 -0
  67. package/src/scripts/js/MusicPlayer.js +572 -0
  68. package/src/scripts/js/MusicProcessor.js +652 -0
  69. package/src/scripts/js/VerovioScoreEditor.js +183 -0
  70. package/src/scripts/js/assets/mei_template.js +161 -0
  71. package/src/scripts/js/constants.js +20 -0
  72. package/src/scripts/js/datastructures/MeasureMatrix.js +235 -0
  73. package/src/scripts/js/datastructures/ScoreGraph.js +432 -0
  74. package/src/scripts/js/datastructures/ScoreNode.js +78 -0
  75. package/src/scripts/js/entry.js +4 -0
  76. package/src/scripts/js/gui/Annotations.js +456 -0
  77. package/src/scripts/js/gui/Cursor.js +203 -0
  78. package/src/scripts/js/gui/CustomAnnotationDrawer.js +114 -0
  79. package/src/scripts/js/gui/CustomAnnotationShapeDrawer.js +114 -0
  80. package/src/scripts/js/gui/HarmonyLabel.js +104 -0
  81. package/src/scripts/js/gui/Label.js +2 -0
  82. package/src/scripts/js/gui/PhantomElement.js +132 -0
  83. package/src/scripts/js/gui/ScoreManipulator.js +156 -0
  84. package/src/scripts/js/gui/Tabbar.js +675 -0
  85. package/src/scripts/js/gui/TempoLabel.js +60 -0
  86. package/src/scripts/js/gui/Toolbar copy.js +614 -0
  87. package/src/scripts/js/gui/Toolbar.js +618 -0
  88. package/src/scripts/js/handlers/AnnotationChangeHandler.js +567 -0
  89. package/src/scripts/js/handlers/AnnotationDragHandler.js +113 -0
  90. package/src/scripts/js/handlers/AnnotationLineHandler.js +113 -0
  91. package/src/scripts/js/handlers/ArticulationHandler.js +20 -0
  92. package/src/scripts/js/handlers/ClickModeHandler.js +265 -0
  93. package/src/scripts/js/handlers/CustomAnnotationShapeDrawer.js +131 -0
  94. package/src/scripts/js/handlers/CustomToolbarHandler.js +297 -0
  95. package/src/scripts/js/handlers/DeleteHandler.js +102 -0
  96. package/src/scripts/js/handlers/GlobalKeyboardHandler.js +367 -0
  97. package/src/scripts/js/handlers/Handler.js +2 -0
  98. package/src/scripts/js/handlers/HarmonyHandler.js +282 -0
  99. package/src/scripts/js/handlers/InsertModeHandler copy.js +423 -0
  100. package/src/scripts/js/handlers/InsertModeHandler.js +380 -0
  101. package/src/scripts/js/handlers/InsertModeHandler_deprecated.js +424 -0
  102. package/src/scripts/js/handlers/KeyModeHandler copy.js +407 -0
  103. package/src/scripts/js/handlers/KeyModeHandler.js +456 -0
  104. package/src/scripts/js/handlers/KeyModeHandler_deprecated.js +411 -0
  105. package/src/scripts/js/handlers/LabelHandler.js +461 -0
  106. package/src/scripts/js/handlers/ModHandler.js +311 -0
  107. package/src/scripts/js/handlers/NoteDragHandler copy.js +148 -0
  108. package/src/scripts/js/handlers/NoteDragHandler.js +97 -0
  109. package/src/scripts/js/handlers/NoteDragHandler_deprecated.js +150 -0
  110. package/src/scripts/js/handlers/PhantomElementHandler.js +168 -0
  111. package/src/scripts/js/handlers/ScoreManipulatorHandler.js +135 -0
  112. package/src/scripts/js/handlers/SelectionHandler.js +218 -0
  113. package/src/scripts/js/handlers/SideBarHandler.js +499 -0
  114. package/src/scripts/js/handlers/TooltipHandler.js +132 -0
  115. package/src/scripts/js/handlers/WindowHandler.js +257 -0
  116. package/src/scripts/js/utils/DOMCreator.js +174 -0
  117. package/src/scripts/js/utils/MEIConverter.js +64 -0
  118. package/src/scripts/js/utils/MEIOperations.js +2112 -0
  119. package/src/scripts/js/utils/Mouse2MEI.js +735 -0
  120. package/src/scripts/js/utils/Mouse2SVG.js +737 -0
  121. package/src/scripts/js/utils/SVGEditor.js +352 -0
  122. package/src/scripts/js/utils/SVGFiller.js +245 -0
  123. package/src/scripts/js/utils/Types.js +2 -0
  124. package/src/scripts/js/utils/VerovioWrapper copy.js +156 -0
  125. package/src/scripts/js/utils/VerovioWrapper.js +165 -0
  126. package/src/scripts/js/utils/VerovioWrapperLocal.js +156 -0
  127. package/src/scripts/js/utils/convenienceQueries.js +37 -0
  128. package/src/scripts/js/utils/coordinates.js +54 -0
  129. package/src/scripts/js/utils/firefoxBBoxes.js +143 -0
  130. package/src/scripts/js/utils/mappings.js +332 -0
  131. package/src/scripts/js/utils/random.js +45 -0
  132. package/src/styles/VerovioScoreEditor.css +694 -0
@@ -0,0 +1,2112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setArticulation = exports.getTimestamp = exports.getElementTimestampById = exports.insertTempo = exports.insertMeter = exports.replaceMeterInScoreDef = exports.insertKey = exports.replaceKeyInScoreDef = exports.insertClef = exports.replaceClefinScoreDef = exports.paste = exports.createTuplet = exports.removeStaff = exports.addStaff = exports.removeMeasure = exports.addMeasure = exports.cleanUp = exports.elementIsOverfilling = exports.changeDur = exports.changeDurationsInLayer = exports.fillLayerWithRests = exports.fillWithRests = exports.disableFeatures = exports.changeMeter = exports.transposeByStep = exports.mergeArticToParent = exports.mergeSectionScoreDefToLayer = exports.adjustAccids = exports.extrapolateMeter = exports.getAbsoluteRatio = exports.connectNotes = exports.addToMEI = exports.getMeterRatioLocal = exports.removeFromMEI = void 0;
4
+ const meiConverter = require("./MEIConverter");
5
+ const random_1 = require("./random");
6
+ const constants_1 = require("../constants");
7
+ const mappings_1 = require("./mappings");
8
+ const mei_template_1 = require("../assets/mei_template");
9
+ const MeasureMatrix_1 = require("../datastructures/MeasureMatrix");
10
+ const countableNoteUnitSelector = ":scope > *[dur]:not([grace])";
11
+ const overfillMeasure = false;
12
+ const siblingNames = ["note", "chord", "clef", "beam"];
13
+ // ":scope > note:not([grace])," +
14
+ // ":scope > chord," +
15
+ // ":scope > beam > chord," +
16
+ // ":scope > beam > note:not([grace])," +
17
+ // ":scope > rest"
18
+ ////// DELETE //////
19
+ /**
20
+ * Remove Elements from MEI.
21
+ * Some Elements (such as accid...) could are not represeented as elements in the current MEI.
22
+ * These have to be found in the parent element which have these as an attribute.
23
+ * @param scoreElements Array of Elements which are marked in the SVG Representation (notes, chords, slur, tie, accid etc..)
24
+ * @param currentMEI
25
+ * @returns
26
+ */
27
+ function removeFromMEI(scoreElements, currentMEI) {
28
+ return new Promise((resolve) => {
29
+ scoreElements.forEach(se => {
30
+ var _a;
31
+ if (currentMEI.getElementById(se === null || se === void 0 ? void 0 : se.id) !== null) { // this only applies for <note> and <rest>
32
+ //do not remove completely, replace with rest
33
+ //currentMEI.getElementById(note.id).remove()
34
+ if (["note", "chord"].some(s => se.classList.contains(s))) {
35
+ replaceWithRest(se, currentMEI);
36
+ }
37
+ else {
38
+ currentMEI.getElementById(se.id).remove(); // possibility to remove rests entirely
39
+ }
40
+ // remove all tie/ harms etc when startid is no more a note or is deleted
41
+ //currentMEI.querySelectorAll("tie").forEach(t => {
42
+ currentMEI.querySelectorAll("[startid]").forEach(t => {
43
+ var _a;
44
+ if (t.getAttribute("startid").includes(se.id)) {
45
+ if (currentMEI.getElementById(se.id) === null) {
46
+ (_a = currentMEI.querySelector(t.getAttribute("endid"))) === null || _a === void 0 ? void 0 : _a.remove();
47
+ }
48
+ t.remove();
49
+ }
50
+ });
51
+ }
52
+ else {
53
+ //may be some of the following: accid
54
+ var closestNote = currentMEI.getElementById((_a = se === null || se === void 0 ? void 0 : se.closest(".note")) === null || _a === void 0 ? void 0 : _a.id);
55
+ if (closestNote !== null) {
56
+ //console.log("removing ", se)
57
+ var attrName = se.classList.item(0).toLowerCase();
58
+ closestNote.removeAttribute(attrName);
59
+ if (attrName === "accid") {
60
+ closestNote.removeAttribute("accid.ges");
61
+ }
62
+ }
63
+ else if (se.closest(".tuplet") !== null) {
64
+ var tuplet = currentMEI.querySelector("#" + se.closest(".tuplet").id);
65
+ if (tuplet !== null)
66
+ tuplet.outerHTML = tuplet.innerHTML; //the element could be gone in current mei, but se is still present
67
+ }
68
+ }
69
+ });
70
+ //removeEmptyElements(currentMEI)
71
+ // For now: No Shifts (22.07.2021)
72
+ // if($(".measure").length > 1){
73
+ // checkDeleteShifts(currentMEI);
74
+ // }
75
+ cleanUp(currentMEI);
76
+ //fillWithRests(currentMEI)
77
+ // Warum ist das ein Problem?
78
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
79
+ resolve(currentMEI);
80
+ });
81
+ }
82
+ exports.removeFromMEI = removeFromMEI;
83
+ function checkDeleteShifts(currentMEI) {
84
+ var meterRatio = getMeterRatioGlobal(currentMEI);
85
+ var shifters = new Array;
86
+ var elements = currentMEI.getElementsByTagName("layer");
87
+ Array.from(elements).forEach(layer => {
88
+ var actualMeterFill = getAbsoluteRatio(layer);
89
+ var layerLevel = layer.getAttribute("n");
90
+ var staffLevel = layer.closest("staff").getAttribute("n");
91
+ var nextSibling = layer.closest("measure").nextElementSibling;
92
+ if (actualMeterFill < meterRatio && nextSibling !== null) {
93
+ let hasStaff = nextSibling.querySelector("staff[n$='" + staffLevel + "'") !== null ? true : false;
94
+ let hasLayer = nextSibling.querySelector("layer[n$='" + layerLevel + "'") !== null ? true : false;
95
+ if (hasStaff && hasLayer) {
96
+ nextSibling = nextSibling.querySelector("staff[n$='" + staffLevel + "'").querySelector("layer[n$='" + layerLevel + "'");
97
+ Array.from(nextSibling.querySelectorAll(countableNoteUnitSelector)).forEach(node => {
98
+ if (actualMeterFill < meterRatio) {
99
+ shifters.push(node);
100
+ }
101
+ actualMeterFill += 1 / parseInt(node.getAttribute("dur"));
102
+ });
103
+ }
104
+ }
105
+ if (shifters.length > 0) {
106
+ doShiftLeft(shifters, meterRatio);
107
+ shifters.length = 0;
108
+ checkDeleteShifts(currentMEI);
109
+ }
110
+ });
111
+ }
112
+ function getMeterRatioGlobal(currentMEI) {
113
+ var staffDef = currentMEI.getElementsByTagName("staffDef").item(0);
114
+ var meterRatio = null;
115
+ //Do I know the meter?
116
+ if (staffDef.getAttribute(constants_1.constants._METERCOUNT_) !== null && staffDef.getAttribute(constants_1.constants._METERUNIT_) !== null) {
117
+ meterRatio = parseInt(staffDef.getAttribute(constants_1.constants._METERCOUNT_)) / parseInt(staffDef.getAttribute(constants_1.constants._METERUNIT_));
118
+ }
119
+ else {
120
+ meterRatio = extrapolateMeter(currentMEI);
121
+ }
122
+ return meterRatio;
123
+ }
124
+ /**
125
+ *
126
+ * @param currentMEI
127
+ * @param refElement Must be a staff-Element at most
128
+ */
129
+ function getMeterRatioLocal(currentMEI, refElement) {
130
+ var _a, _b;
131
+ var staffElement;
132
+ if (refElement.tagName !== "staff") {
133
+ if (refElement.closest("staff") === null) {
134
+ staffElement = ((_a = currentMEI.getElementById(refElement.id)) === null || _a === void 0 ? void 0 : _a.closest("staff")) || ((_b = currentMEI.getElementById(refElement.parentElement.id)) === null || _b === void 0 ? void 0 : _b.closest("staff"));
135
+ }
136
+ else {
137
+ staffElement = refElement.closest("staff");
138
+ }
139
+ }
140
+ else {
141
+ staffElement = refElement;
142
+ }
143
+ if (staffElement === null || staffElement == undefined) {
144
+ throw new Error("RefElement must be a staff-Element at most");
145
+ }
146
+ var mm = new MeasureMatrix_1.default();
147
+ mm.populateFromMEI(currentMEI);
148
+ var measureIdx = staffElement.closest("measure").getAttribute("n");
149
+ var staffIdx = staffElement.getAttribute("n");
150
+ var mmStaff = mm.get(measureIdx, staffIdx);
151
+ return parseInt(mmStaff.meterSig.count) / parseInt(mmStaff.meterSig.unit);
152
+ }
153
+ exports.getMeterRatioLocal = getMeterRatioLocal;
154
+ //////// INSERT //////////
155
+ /**
156
+ * Insert given sound event into MEI
157
+ * @param newSound NewNote or NewChord to be inserted
158
+ * @param currentMEI MEI as Document
159
+ * @param replace Switching to replaceMode (default: False)
160
+ * @param scoreGraph
161
+ * @returns mei
162
+ */
163
+ function addToMEI(newSound, currentMEI, replace = false, scoreGraph = null) {
164
+ var _a, _b;
165
+ //return new Promise<Document>((resolve): void => {
166
+ var currMeiClone = currentMEI.cloneNode(true);
167
+ var newElem;
168
+ var nearestNoteIsSameDurRest = false;
169
+ if (newSound.hasOwnProperty("pname")) {
170
+ var newNote = newSound;
171
+ if (newNote.rest) {
172
+ newElem = currentMEI.createElement("rest");
173
+ }
174
+ else {
175
+ newElem = currentMEI.createElement("note");
176
+ newElem.setAttribute("pname", newNote.pname);
177
+ newElem.setAttribute("oct", newNote.oct);
178
+ if (newNote.accid != undefined) {
179
+ newElem.setAttribute("accid.ges", newNote.accid);
180
+ }
181
+ }
182
+ newElem.setAttribute("dur", newNote.dur);
183
+ if (newNote.dots != undefined) {
184
+ newElem.setAttribute("dots", newNote.dots);
185
+ }
186
+ if (newNote.id != undefined && newNote.id !== null) {
187
+ newElem.setAttribute("id", newNote.id);
188
+ }
189
+ //break up an cache beams for easier processing
190
+ //later all the beams will be reastablished
191
+ var beams = new Array();
192
+ currentMEI.querySelector("#" + newNote.nearestNoteId).closest("layer").querySelectorAll("beam").forEach(b => {
193
+ beams.push(b.cloneNode(true));
194
+ Array.from(b.children).forEach(e => {
195
+ b.parentElement.insertBefore(e, b);
196
+ });
197
+ b.remove();
198
+ });
199
+ //Do sthm with chords
200
+ if (newNote.chordElement != undefined && !newNote.rest) {
201
+ var chord;
202
+ var meiChordEl = currentMEI.getElementById(newNote.chordElement.id);
203
+ if (newNote.chordElement.classList.contains("chord") || newNote.chordElement.tagName === "chord") {
204
+ chord = meiChordEl;
205
+ chord.appendChild(newElem);
206
+ }
207
+ else {
208
+ chord = document.createElement("chord");
209
+ chord.setAttribute("id", random_1.uuidv4());
210
+ chord.setAttribute("dur", meiChordEl.getAttribute("dur"));
211
+ if (meiChordEl.getAttribute("dots") !== null) {
212
+ chord.setAttribute("dots", meiChordEl.getAttribute("dots"));
213
+ }
214
+ chord.appendChild(newElem);
215
+ meiChordEl.parentElement.insertBefore(chord, meiChordEl);
216
+ chord.appendChild(meiChordEl);
217
+ }
218
+ chord.childNodes.forEach((n) => {
219
+ n.removeAttribute("dur");
220
+ n.removeAttribute("dots");
221
+ });
222
+ // check for existing ties within the chord and make one for the new element as well
223
+ currentMEI.querySelectorAll("tie").forEach(t => {
224
+ if (Array.from(chord.querySelectorAll("note")).some(n => t.getAttribute("startid") === "#" + n.id)) {
225
+ if (!currentMEI.querySelector("tie[startid='#" + newNote.id + "']")) { // just make the tie once (since this can be called twice in recursion)
226
+ var addToChord = Object.assign({}, newNote);
227
+ addToChord.id = random_1.uuidv4();
228
+ var tieEnd = currentMEI.querySelector(t.getAttribute("endid"));
229
+ tieEnd = tieEnd.closest("chord") || tieEnd;
230
+ addToChord.chordElement = tieEnd;
231
+ addToMEI(addToChord, currentMEI, replace);
232
+ connectNotes(currentMEI.querySelector("#" + newNote.id), currentMEI.querySelector("#" + addToChord.id), "tie");
233
+ }
234
+ }
235
+ });
236
+ }
237
+ else if (newNote.nearestNoteId !== null) {
238
+ var sibling = currentMEI.getElementById(newNote.nearestNoteId);
239
+ if (sibling === null)
240
+ return;
241
+ nearestNoteIsSameDurRest = sibling.tagName === "rest" && sibling.getAttribute("dur") === newElem.getAttribute("dur") && sibling.getAttribute("dots") === newElem.getAttribute("dots");
242
+ //special rule for first element in layer
243
+ if (sibling.tagName === "layer") {
244
+ if (scoreGraph !== null) {
245
+ sibling = (_a = currentMEI.getElementById(scoreGraph.getCurrentNode().getRight().getId())) === null || _a === void 0 ? void 0 : _a.parentElement;
246
+ }
247
+ var firstChild = sibling.firstChild;
248
+ sibling.insertBefore(newElem, firstChild);
249
+ if (replace) {
250
+ changeDurationsInLayer(currentMEI, [firstChild], newElem);
251
+ }
252
+ }
253
+ else {
254
+ var parentLayer = sibling.closest("layer");
255
+ var trueParent = sibling.parentElement;
256
+ var isTrueSibling = parentLayer == trueParent;
257
+ var trueSibling = sibling;
258
+ if (!isTrueSibling) {
259
+ var currParent = trueParent;
260
+ while (!isTrueSibling) {
261
+ trueSibling = currParent;
262
+ currParent = currParent === null || currParent === void 0 ? void 0 : currParent.parentElement;
263
+ isTrueSibling = currParent.tagName === "layer";
264
+ }
265
+ }
266
+ if (replace) {
267
+ let ms = Array.from(trueSibling.parentElement.querySelectorAll("note:not(chord note), chord, rest, mRest")); //querySelectorAll(":scope > *")
268
+ if (newNote.relPosX === "left") {
269
+ var measureSiblings = ms.filter((_, i) => i >= ms.indexOf(trueSibling));
270
+ trueSibling.parentElement.insertBefore(newElem, trueSibling);
271
+ changeDurationsInLayer(currentMEI, measureSiblings, newElem);
272
+ }
273
+ else {
274
+ if (["clef"].every(el => { var _a; return ((_a = trueSibling.nextElementSibling) === null || _a === void 0 ? void 0 : _a.tagName) !== el; }) && trueSibling.nextElementSibling !== null) {
275
+ var measureSiblings = ms.filter((_, i) => i >= ms.indexOf(trueSibling.nextElementSibling));
276
+ trueSibling.parentElement.insertBefore(newElem, trueSibling.nextElementSibling);
277
+ changeDurationsInLayer(currentMEI, measureSiblings, newElem);
278
+ }
279
+ else {
280
+ trueSibling.parentElement.insertBefore(newElem, trueSibling.nextElementSibling);
281
+ }
282
+ }
283
+ }
284
+ else {
285
+ if (newNote.relPosX === "left") {
286
+ trueSibling.parentElement.insertBefore(newElem, trueSibling);
287
+ }
288
+ else {
289
+ trueSibling.parentElement.insertBefore(newElem, trueSibling.nextElementSibling);
290
+ }
291
+ }
292
+ }
293
+ }
294
+ else {
295
+ currentMEI.getElementById(newNote.staffId).querySelector("layer").appendChild(newElem);
296
+ }
297
+ }
298
+ else { // is newChord
299
+ //TODO
300
+ var newChord = newSound;
301
+ newElem = convertToElement(newChord, currentMEI);
302
+ var nearestElem = currentMEI.getElementById(newChord.nearestNoteId);
303
+ if ((nearestElem === null || nearestElem === void 0 ? void 0 : nearestElem.tagName) === "layer") {
304
+ nearestElem.insertBefore(newElem, nearestElem.firstChild);
305
+ }
306
+ else if (newChord.relPosX === "left") {
307
+ nearestElem.parentElement.insertBefore(newElem, currentMEI.getElementById(newChord.nearestNoteId));
308
+ }
309
+ else {
310
+ nearestElem.parentElement.insertBefore(newElem, currentMEI.getElementById(newChord.nearestNoteId).nextSibling);
311
+ }
312
+ }
313
+ // if measure overfills tie note to next measure
314
+ var currentLayer = newElem.closest("layer");
315
+ if (!overfillMeasure) {
316
+ var newMeasureRatio = getAbsoluteRatio(newElem.closest("layer"));
317
+ var measureRatio = getMeterRatioLocal(currMeiClone, newElem);
318
+ if (newMeasureRatio > measureRatio) {
319
+ //currentMEI = currMeiClone as Document
320
+ // Decide if next measure should be created and what should be added
321
+ var lastElement = Array.from(currentLayer.querySelectorAll(":scope > :is(note, chord)")).reverse()[0];
322
+ var lastElementRatio = getAbsoluteRatio(lastElement);
323
+ var measureOverhead = newMeasureRatio - measureRatio;
324
+ var newRatio = lastElementRatio - measureOverhead;
325
+ if (newRatio > 0) {
326
+ changeDur(lastElement, newRatio);
327
+ // create new Element and if needed, new measure
328
+ var splittedElement = lastElement.tagName === "note" ? convertToNewNote(lastElement) : convertToNewChord(lastElement);
329
+ splittedElement.id = random_1.uuidv4();
330
+ var newDur = ratioToDur(measureOverhead);
331
+ splittedElement.dur = newDur[0].toString();
332
+ splittedElement.dots = newDur[1].toString();
333
+ if (currentLayer.closest("measure") === currentLayer.closest("section").lastElementChild) {
334
+ addMeasure(currentMEI);
335
+ }
336
+ var newLayer = currentMEI.querySelector("measure[n='" + (parseInt(currentLayer.closest("measure").getAttribute("n")) + 1).toString() + "'] layer[n='" + currentLayer.getAttribute("n") + "']");
337
+ splittedElement.nearestNoteId = newLayer.id;
338
+ splittedElement.staffId = newLayer.closest("staff").id;
339
+ splittedElement.relPosX = "left";
340
+ addToMEI(splittedElement, currentMEI, replace);
341
+ connectNotes(lastElement, currentMEI.querySelector("#" + splittedElement.id), "tie");
342
+ }
343
+ else if (newRatio == 0 && measureOverhead > 0) { // if the measure is perfectly fine and there should be no tie, modify the newsound (push it one position to the right) and compute again
344
+ currentMEI = currMeiClone;
345
+ if (currentLayer.closest("measure").nextElementSibling === null) { // add measure if there is none to extend into
346
+ addMeasure(currentMEI);
347
+ }
348
+ var cl = currentMEI.getElementById(currentLayer.id);
349
+ newSound.nearestNoteId = (_b = cl.closest("measure").nextElementSibling.querySelector("staff[n='" + cl.closest("staff").getAttribute("n") + "'] layer[n='" + cl.getAttribute("n") + "'] :is(chord, note, rest, mRest)")) === null || _b === void 0 ? void 0 : _b.id;
350
+ newSound.relPosX = "left";
351
+ if (newSound.nearestNoteId !== null) {
352
+ currentMEI = addToMEI(newSound, currentMEI, replace);
353
+ }
354
+ }
355
+ }
356
+ }
357
+ newElem = currentMEI.querySelector("#" + newElem.id);
358
+ fillLayerWithRests(currentLayer, currentMEI);
359
+ //reestablish beams
360
+ beams.forEach(b => {
361
+ var first;
362
+ var last;
363
+ Array.from(b.children).forEach(bc => {
364
+ var existingChild = currentMEI.querySelector("#" + bc.id);
365
+ if (existingChild !== null) {
366
+ if (first == undefined) {
367
+ first = bc;
368
+ }
369
+ else {
370
+ last = bc;
371
+ }
372
+ }
373
+ else if (first == undefined) {
374
+ first = newElem;
375
+ }
376
+ });
377
+ if (last == undefined) {
378
+ last = newElem;
379
+ }
380
+ if (first != undefined && last != undefined) {
381
+ var newBeam = currentMEI.createElement("beam");
382
+ newBeam.id = b.id;
383
+ var beamElements = currentMEI.querySelectorAll("#" + first.id + ", #" + first.id + "~ *:not(#" + last.id + "~ *)"); // all elements in between first and last
384
+ beamElements[0].insertAdjacentElement("beforebegin", newBeam);
385
+ beamElements.forEach(be => {
386
+ newBeam.append(be);
387
+ });
388
+ }
389
+ });
390
+ cleanUp(currentMEI);
391
+ adjustAccids(currentMEI);
392
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
393
+ return currentMEI;
394
+ }
395
+ exports.addToMEI = addToMEI;
396
+ /**
397
+ * Check if notes have to be shifted after insertion
398
+ * @param currentMEI
399
+ */
400
+ function checkInsertShifts(currentMEI) {
401
+ var staffDef = currentMEI.getElementsByTagName("staffDef").item(0);
402
+ var meterRatio = parseInt(staffDef.getAttribute(constants_1.constants._METERCOUNT_)) / parseInt(staffDef.getAttribute(constants_1.constants._METERUNIT_));
403
+ if (staffDef.getAttribute(constants_1.constants._METERCOUNT_) !== null && staffDef.getAttribute(constants_1.constants._METERUNIT_) !== null) {
404
+ meterRatio = parseInt(staffDef.getAttribute(constants_1.constants._METERCOUNT_)) / parseInt(staffDef.getAttribute(constants_1.constants._METERUNIT_));
405
+ }
406
+ else {
407
+ meterRatio = extrapolateMeter(currentMEI);
408
+ }
409
+ var shifters = new Array;
410
+ var elements = currentMEI.getElementsByTagName("layer");
411
+ Array.from(elements).forEach(layer => {
412
+ var i = 0;
413
+ var layerChildern = layer.querySelectorAll(countableNoteUnitSelector);
414
+ Array.from(layerChildern).forEach(node => {
415
+ i += getAbsoluteRatio(node); //1/parseInt(node.getAttribute("dur"))
416
+ if (i > meterRatio) {
417
+ shifters.push(node);
418
+ }
419
+ });
420
+ if (shifters.length > 0) {
421
+ doShiftRight(shifters, meterRatio, layer);
422
+ shifters.length = 0;
423
+ checkInsertShifts(currentMEI);
424
+ }
425
+ });
426
+ }
427
+ /**
428
+ * Shift all Elements to the right (according to measure borders)
429
+ * @param arr Array of Elements to be shifted
430
+ * @param meterRatio
431
+ * @param currentLayer
432
+ */
433
+ function doShiftRight(arr, meterRatio, currentLayer) {
434
+ arr.forEach((element, elementIdx) => {
435
+ var parentMeasure = element.closest("measure");
436
+ var parentMeasureSibling = null;
437
+ parentMeasureSibling = parentMeasure.nextElementSibling;
438
+ if (parentMeasureSibling === null) {
439
+ parentMeasureSibling = parentMeasure.parentElement.appendChild(createEmptyCopy(parentMeasure));
440
+ }
441
+ var layerLevel = element.closest("layer").getAttribute("n");
442
+ var staffLevel = element.closest("staff").getAttribute("n");
443
+ var targetStaff = parentMeasureSibling.querySelector("staff[n$='" + staffLevel + "'");
444
+ var targetLayer;
445
+ if (targetStaff.querySelector("layer[n$='" + layerLevel + "'") !== null) {
446
+ targetLayer = targetStaff.querySelector("layer[n$='" + layerLevel + "'");
447
+ }
448
+ else {
449
+ targetLayer = document.createElement("layer");
450
+ targetLayer.setAttribute("id", "layer-" + random_1.uuidv4());
451
+ targetLayer.setAttribute("n", layerLevel);
452
+ targetStaff.appendChild(targetLayer);
453
+ }
454
+ var absLayerRatio = getAbsoluteRatio(currentLayer);
455
+ var elementRatio = getAbsoluteRatio(element);
456
+ var chunkDurRight = absLayerRatio - meterRatio;
457
+ var chunkDurLeft = elementRatio - chunkDurRight;
458
+ if (chunkDurRight > elementRatio) {
459
+ chunkDurRight = elementRatio;
460
+ chunkDurLeft = 0;
461
+ }
462
+ //check if note must be split
463
+ if ((absLayerRatio + elementRatio) > meterRatio && chunkDurRight * chunkDurLeft !== 0) {
464
+ //check for dots
465
+ if (Number.isInteger(1 / chunkDurLeft) && Number.isInteger(1 / chunkDurRight)) {
466
+ element.removeAttribute("dots");
467
+ var splitRightElement = element.cloneNode(true);
468
+ splitRightElement.setAttribute("id", random_1.uuidv4());
469
+ splitRightElement.setAttribute("dur", (Math.abs(1 / chunkDurRight)).toString());
470
+ var beforeElement = elementIdx === 0 ? targetLayer.firstChild : targetLayer.children.item(elementIdx);
471
+ targetLayer.insertBefore(splitRightElement, beforeElement);
472
+ //change already existing element
473
+ element.setAttribute("dur", (Math.abs(1 / chunkDurLeft)).toString());
474
+ }
475
+ else {
476
+ var dottedElements = splitDottedNote(element, chunkDurLeft, chunkDurRight);
477
+ dottedElements.left.forEach(lel => currentLayer.appendChild(lel));
478
+ var beforeElement = elementIdx === 0 ? targetLayer.firstChild : targetLayer.children.item(elementIdx);
479
+ dottedElements.right.forEach(rel => {
480
+ rel.setAttribute("id", random_1.uuidv4());
481
+ if (rel.tagName === "chord") {
482
+ rel.querySelectorAll("note").forEach(rl => {
483
+ rl.setAttribute("id", random_1.uuidv4());
484
+ });
485
+ }
486
+ targetLayer.insertBefore(rel, beforeElement);
487
+ });
488
+ element.remove();
489
+ }
490
+ }
491
+ else {
492
+ var beforeElement = elementIdx === 0 ? targetLayer.firstChild : targetLayer.children.item(elementIdx);
493
+ targetLayer.insertBefore(element, beforeElement);
494
+ }
495
+ });
496
+ }
497
+ function createEmptyCopy(element) {
498
+ let copy = element.cloneNode(true);
499
+ let childrenToDelete = Array.from(copy.querySelectorAll("layer > *, measure > slur"));
500
+ childrenToDelete.forEach(child => {
501
+ child.parentNode.removeChild(child);
502
+ });
503
+ //set new ids for everything
504
+ copy.setAttribute("id", random_1.uuidv4());
505
+ copy.setAttribute("n", (parseInt(element.getAttribute("n")) + 1).toString());
506
+ let allElements = copy.querySelectorAll("*");
507
+ allElements.forEach(e => e.setAttribute("id", random_1.uuidv4()));
508
+ return copy;
509
+ }
510
+ function connectNotes(left, right, connectionShape) {
511
+ var leftpname = left.getAttribute("pname");
512
+ var leftoct = left.getAttribute("oct");
513
+ var leftAccid = left.getAttribute("accid") || left.getAttribute("accid.ges");
514
+ var rightpname = right.getAttribute("pname");
515
+ var rightoct = right.getAttribute("oct");
516
+ var rightAccid = right.getAttribute("accid") || right.getAttribute("accid.ges");
517
+ if (!(leftpname === rightpname && leftoct === rightoct && leftAccid === rightAccid)) {
518
+ connectionShape = "slur";
519
+ }
520
+ var currentMEI = left.getRootNode();
521
+ var connections = currentMEI.querySelectorAll("tie, slur");
522
+ var deleted = false;
523
+ connections.forEach(c => {
524
+ var sid = c.getAttribute("startid").replace("#", "");
525
+ var eid = c.getAttribute("endid").replace("#", "");
526
+ if (sid === left.id && eid === right.id) {
527
+ c.remove();
528
+ deleted = true;
529
+ }
530
+ });
531
+ if (!deleted) {
532
+ var tieElement = currentMEI.createElementNS(constants_1.constants._MEINS_, connectionShape);
533
+ tieElement.setAttribute("startid", "#" + left.id);
534
+ tieElement.setAttribute("endid", "#" + right.id);
535
+ tieElement.setAttribute("id", random_1.uuidv4());
536
+ currentMEI.getElementById(left.id).closest("measure").append(tieElement);
537
+ }
538
+ }
539
+ exports.connectNotes = connectNotes;
540
+ ///// GENERAL OPERATIONS /////
541
+ function getAbsoluteRatio(el) {
542
+ var i = 0;
543
+ var arr;
544
+ if (el === null) {
545
+ return 0;
546
+ }
547
+ if (el.tagName !== "layer") { //if single Element is given, eg. chord, note
548
+ arr = [el];
549
+ }
550
+ else {
551
+ arr = Array.from(el.querySelectorAll(countableNoteUnitSelector));
552
+ }
553
+ arr.forEach(node => {
554
+ i += 1 / parseInt(node.getAttribute("dur"));
555
+ let baseDur = parseInt(node.getAttribute("dur"));
556
+ if (node.getAttribute("dots") !== null) {
557
+ let dots = parseInt(node.getAttribute("dots"));
558
+ i += dots == 0 ? 0 : (dots * 2 - 1) / (baseDur * 2 * dots);
559
+ }
560
+ });
561
+ return i;
562
+ }
563
+ exports.getAbsoluteRatio = getAbsoluteRatio;
564
+ function ratioToDur(ratio) {
565
+ var dur;
566
+ var dots = 0;
567
+ //1. next smallest ratio of basedur
568
+ var basedur = 1;
569
+ while (basedur > ratio) {
570
+ basedur = basedur / 2;
571
+ }
572
+ dur = 1 / basedur;
573
+ ratio -= basedur;
574
+ if (ratio > 0) {
575
+ if (ratio > dur / 2) {
576
+ dots = 2;
577
+ }
578
+ else {
579
+ dots = 1;
580
+ }
581
+ }
582
+ return [dur, dots];
583
+ }
584
+ /**
585
+ * Shift Elements to left (according to measure borders)
586
+ * @param arr Array of Elements to shift
587
+ * @param meterRatio meterRatio of the piece
588
+ */
589
+ function doShiftLeft(arr, meterRatio) {
590
+ arr.forEach(element => {
591
+ var parentMeasure = element.closest("measure");
592
+ var parentMeasureSibling = parentMeasure.previousElementSibling;
593
+ var layerLevel = element.closest("layer").getAttribute("n");
594
+ var targetLayer = parentMeasureSibling.querySelector("layer[n$='" + layerLevel + "'"); // should be <layer>
595
+ var absLayerRatio = getAbsoluteRatio(targetLayer);
596
+ var elementRatio = getAbsoluteRatio(element);
597
+ //check if note must be split
598
+ if ((absLayerRatio + elementRatio) > meterRatio) {
599
+ var chunkDurLeft = meterRatio - absLayerRatio;
600
+ var chunkDurRight = elementRatio - chunkDurLeft;
601
+ //check for dots
602
+ if (Number.isInteger(1 / chunkDurLeft) && Number.isInteger(1 / chunkDurRight)) {
603
+ element.removeAttribute("dots");
604
+ var splitLeftElement = element.cloneNode(true);
605
+ splitLeftElement.setAttribute("id", random_1.uuidv4());
606
+ splitLeftElement.setAttribute("dur", (Math.abs(1 / chunkDurLeft)).toString());
607
+ targetLayer.appendChild(splitLeftElement);
608
+ //change already existing element
609
+ element.setAttribute("dur", (Math.abs(1 / chunkDurRight)).toString());
610
+ }
611
+ else {
612
+ var elements = splitDottedNote(element, chunkDurLeft, chunkDurRight);
613
+ elements.left.forEach(lel => {
614
+ lel.setAttribute("id", random_1.uuidv4());
615
+ if (lel.tagName === "chord") {
616
+ lel.querySelectorAll("note").forEach(ll => {
617
+ ll.setAttribute("id", random_1.uuidv4());
618
+ });
619
+ }
620
+ targetLayer.appendChild(lel);
621
+ });
622
+ elements.right.forEach(rel => element.parentElement.insertBefore(rel, element));
623
+ element.remove();
624
+ }
625
+ }
626
+ else {
627
+ targetLayer.appendChild(element);
628
+ //is current Layer empty and should be deleted? if split occured this should not be the case
629
+ var parentLayer = parentMeasure.querySelector("layer[n$='" + layerLevel + "'"); // should always be <layer>
630
+ // if(parentLayer.childNodes.length === 0){
631
+ // parentMeasure.remove();
632
+ // }
633
+ }
634
+ });
635
+ }
636
+ /**
637
+ * Operations to split dotted notes
638
+ * @param note reference note elements
639
+ * @param chunkLeftDur calculated ratio left
640
+ * @param chunkRightDur calculated ratio right
641
+ * @returns collection of right ans left elements
642
+ */
643
+ function splitDottedNote(note, chunkLeftDur, chunkRightDur) {
644
+ let gcdLeft = gcd(chunkLeftDur);
645
+ let gcdRight = gcd(chunkRightDur);
646
+ let countLeftSubNotes = findDotsRecursive(chunkLeftDur, gcdLeft); //return z.B.: [8, 16]
647
+ let countRightSubNotes = findDotsRecursive(chunkRightDur, gcdRight); //return z.B. [2, 8, 16]
648
+ let newLeftElement = createElementsFromSubNotes(note, countLeftSubNotes);
649
+ let newRightElement = createElementsFromSubNotes(note, countRightSubNotes);
650
+ return { left: newLeftElement, right: newRightElement };
651
+ }
652
+ /**
653
+ * Create actual XML Elements from sequence of dotted notes
654
+ * @param note
655
+ * @param subNoteDurs
656
+ * @returns
657
+ */
658
+ function createElementsFromSubNotes(note, subNoteDurs) {
659
+ let newElements = new Array();
660
+ //find sliceBoundaries in array
661
+ let arraySliceIdx = new Array();
662
+ for (var i = 0; i < subNoteDurs.length; i++) {
663
+ if (i > 0) {
664
+ if (subNoteDurs[i] !== subNoteDurs[i - 1] * 2) {
665
+ arraySliceIdx.push(i);
666
+ }
667
+ }
668
+ }
669
+ //find actual slices
670
+ let durSlices = new Array();
671
+ for (var i = 0; i < arraySliceIdx.length + 1; i++) {
672
+ if (i === 0) {
673
+ durSlices.push(subNoteDurs.slice(0, arraySliceIdx[i]));
674
+ }
675
+ else if (i === arraySliceIdx.length) {
676
+ durSlices.push(subNoteDurs.slice(arraySliceIdx[i - 1]));
677
+ }
678
+ else {
679
+ durSlices.push(subNoteDurs.slice(arraySliceIdx[i - 1], arraySliceIdx[i]));
680
+ }
681
+ }
682
+ //create notes
683
+ let createArr = durSlices.length > 0 ? durSlices : [subNoteDurs];
684
+ createArr.forEach(durs => {
685
+ let newElement = note.cloneNode(true);
686
+ newElement.removeAttribute("dots"); //eventual dots could be in original note value
687
+ newElement.setAttribute("dur", Math.abs(durs[0]).toString());
688
+ let dots = 0;
689
+ durs.forEach((dur, i) => {
690
+ if (i > 0) {
691
+ dots += 1;
692
+ }
693
+ });
694
+ if (dots > 0) {
695
+ newElement.setAttribute("dots", dots.toString());
696
+ }
697
+ newElements.push(newElement);
698
+ });
699
+ return newElements;
700
+ }
701
+ /**
702
+ * Compute greatest integer divisor
703
+ * @param chunkDur Duration of given Chunk
704
+ * @returns
705
+ */
706
+ function gcd(chunkDur) {
707
+ var largestModulo = null;
708
+ var baseValue = 1;
709
+ var mod = 0;
710
+ while (largestModulo === null) {
711
+ mod = chunkDur % baseValue;
712
+ if (mod === 0) {
713
+ largestModulo = baseValue;
714
+ }
715
+ baseValue = baseValue / 2;
716
+ }
717
+ return largestModulo;
718
+ }
719
+ /**
720
+ * Splits duration of given chunk into possible dotted sequences
721
+ * @param chunk
722
+ * @param smallestUnit = greatest integer divisor
723
+ * @returns
724
+ */
725
+ function findDotsRecursive(chunk, smallestUnit) {
726
+ var arr = new Array();
727
+ var sliceChunk = chunk / smallestUnit;
728
+ if (Math.floor(sliceChunk) > 1) {
729
+ arr = arr.concat(findDotsRecursive(chunk, smallestUnit * 2));
730
+ }
731
+ else if (Math.floor(sliceChunk) < 1) {
732
+ arr = arr.concat(findDotsRecursive(chunk, smallestUnit / 2));
733
+ }
734
+ else if (!Number.isInteger(sliceChunk)) {
735
+ arr.push(1 / 1 / smallestUnit);
736
+ arr = arr.concat(findDotsRecursive(chunk - smallestUnit, smallestUnit));
737
+ }
738
+ else {
739
+ arr.push(1 / 1 / smallestUnit);
740
+ }
741
+ return arr; //.sort((a,b) => a-b)
742
+ }
743
+ /**
744
+ * Extrapolates meter, if is not given in scoreDef. Iterates through each staff to get the mostly found ratio
745
+ * @param currentMEI
746
+ * @returns meter ratio
747
+ */
748
+ function extrapolateMeter(currentMEI) {
749
+ var ratioMap = new Map();
750
+ var xmlCopy = currentMEI.cloneNode(true);
751
+ var layers = Array.from(xmlCopy.querySelectorAll("layer"));
752
+ var mostlyUsedRatio = 0;
753
+ layers.forEach(layer => {
754
+ if (layer.childElementCount === 0) {
755
+ return;
756
+ }
757
+ //strip all unnecessary elements: garce notes, beams
758
+ //which do not contribute to count of measure duration
759
+ var beams = Array.from(layer.querySelectorAll("beam"));
760
+ beams.forEach(beam => {
761
+ Array.from(beam.children).forEach(c => {
762
+ beam.parentElement.append(c);
763
+ });
764
+ xmlCopy.getElementById(beam.id).remove();
765
+ });
766
+ var graceNotes = Array.from(layer.querySelectorAll("[grace]"));
767
+ graceNotes.forEach(g => {
768
+ xmlCopy.getElementById(g.id).remove();
769
+ });
770
+ var childElements = Array.from(layer.children);
771
+ var ratio = 0;
772
+ childElements.forEach(element => {
773
+ ratio += getAbsoluteRatio(element);
774
+ });
775
+ if (!ratioMap.has(ratio)) {
776
+ ratioMap.set(ratio, 1);
777
+ }
778
+ else {
779
+ ratioMap.set(ratio, ratioMap.get(ratio) + 1);
780
+ }
781
+ var prevItCount = 0;
782
+ for (const [key, value] of ratioMap.entries()) {
783
+ if (value > prevItCount) {
784
+ prevItCount = value;
785
+ mostlyUsedRatio = key;
786
+ }
787
+ }
788
+ });
789
+ return mostlyUsedRatio;
790
+ }
791
+ exports.extrapolateMeter = extrapolateMeter;
792
+ /**
793
+ * Adjust all accids according to key signature
794
+ * e.g. after changing global Key
795
+ * @param currentMEI
796
+ * @returns
797
+ */
798
+ function adjustAccids(currentMEI) {
799
+ var measureMatrix = new MeasureMatrix_1.default();
800
+ measureMatrix.populateFromMEI(currentMEI);
801
+ var prevAccidMap = new Map(); // key: pname+oct
802
+ var currentLayer = "1";
803
+ var currentStaff = "1";
804
+ var currentMeasure = "1";
805
+ currentMEI.querySelectorAll("note").forEach(note => {
806
+ var layerN = note.closest("layer").getAttribute("n");
807
+ var staffN = note.closest("staff").getAttribute("n");
808
+ var measureN = note.closest("measure").getAttribute("n");
809
+ if (layerN !== currentLayer || staffN !== currentStaff || measureN !== currentMeasure) {
810
+ prevAccidMap = new Map(); // key: pname+oct
811
+ currentLayer = layerN;
812
+ currentStaff = staffN;
813
+ currentMeasure = measureN;
814
+ }
815
+ var sig = measureMatrix.get(measureN, staffN).keysig;
816
+ var sigSymbol = sig.charAt(1);
817
+ var signedNotes = mappings_1.keysigToNotes.get(sig);
818
+ var accid = note.getAttribute("accid") || note.getAttribute("accid.ges");
819
+ accid = accid === "n" || accid === "" ? null : accid;
820
+ // remove all accids so I don't have to look it up several times
821
+ note.removeAttribute("accid");
822
+ note.removeAttribute("accid.ges");
823
+ var pname = note.getAttribute("pname");
824
+ var oct = note.getAttribute("oct");
825
+ var mapKey = pname + oct;
826
+ var noteInKey = signedNotes.some(sn => sn === pname);
827
+ if (accid === null) { // "I have no accid"
828
+ accid = "n";
829
+ if (prevAccidMap.has(mapKey)) { // "does someone before me has any accid?"
830
+ if (prevAccidMap.get(mapKey) === "n") {
831
+ prevAccidMap.delete(mapKey);
832
+ }
833
+ else {
834
+ note.setAttribute("accid", accid);
835
+ prevAccidMap.set(mapKey, accid);
836
+ }
837
+ }
838
+ else if (noteInKey) {
839
+ note.setAttribute("accid", accid);
840
+ prevAccidMap.set(mapKey, accid);
841
+ }
842
+ }
843
+ else { // "I have accid"
844
+ if (prevAccidMap.has(mapKey)) {
845
+ if (prevAccidMap.get(mapKey) === accid) {
846
+ note.setAttribute("accid.ges", accid);
847
+ prevAccidMap.set(mapKey, accid);
848
+ }
849
+ else {
850
+ note.setAttribute("accid", accid);
851
+ prevAccidMap.set(mapKey, accid);
852
+ }
853
+ }
854
+ else {
855
+ if (noteInKey) {
856
+ if (sigSymbol === accid) {
857
+ if (prevAccidMap.has(mapKey)) {
858
+ if (prevAccidMap.get(mapKey) === accid) {
859
+ note.setAttribute("accid.ges", accid);
860
+ prevAccidMap.set(mapKey, accid);
861
+ }
862
+ else {
863
+ note.setAttribute("accid", accid);
864
+ prevAccidMap.set(mapKey, accid);
865
+ }
866
+ }
867
+ else {
868
+ if (sigSymbol === accid) {
869
+ note.setAttribute("accid.ges", accid);
870
+ prevAccidMap.set(mapKey, accid);
871
+ }
872
+ else {
873
+ note.setAttribute("accid", accid);
874
+ prevAccidMap.set(mapKey, accid);
875
+ }
876
+ }
877
+ }
878
+ else {
879
+ note.setAttribute("accid", accid);
880
+ prevAccidMap.set(mapKey, accid);
881
+ }
882
+ }
883
+ else {
884
+ note.setAttribute("accid", accid);
885
+ prevAccidMap.set(mapKey, accid);
886
+ }
887
+ }
888
+ }
889
+ });
890
+ return currentMEI;
891
+ }
892
+ exports.adjustAccids = adjustAccids;
893
+ /**
894
+ * Merge all scoreDefs in sections in the respective layers, e.g. when importing a file.
895
+ * This is important since MeasureMartrix only handles signature elements (keySig, meterSig, clef) in layers
896
+ * @param currentMEI
897
+ */
898
+ function mergeSectionScoreDefToLayer(currentMEI) {
899
+ var mei;
900
+ if (typeof currentMEI === "string") {
901
+ mei = new DOMParser().parseFromString(currentMEI, "text/xml");
902
+ }
903
+ else {
904
+ mei = currentMEI;
905
+ }
906
+ mei.querySelectorAll("section").forEach(sec => {
907
+ var secChildren = sec.querySelectorAll(":scope > *");
908
+ secChildren.forEach((e, i) => {
909
+ if (e.tagName === "scoreDef") {
910
+ secChildren[i + 1].querySelectorAll("layer").forEach(layer => {
911
+ e.querySelectorAll(":scope > *").forEach(sig => {
912
+ var newElem = sig.cloneNode(true);
913
+ layer.prepend(newElem);
914
+ });
915
+ });
916
+ }
917
+ });
918
+ sec.querySelectorAll(":scope > scoreDef").forEach(sd => sd.remove());
919
+ });
920
+ return mei;
921
+ }
922
+ exports.mergeSectionScoreDefToLayer = mergeSectionScoreDefToLayer;
923
+ function mergeArticToParent(currentMEI) {
924
+ currentMEI.querySelectorAll("artic").forEach(a => {
925
+ a.parentElement.setAttribute("artic", a.getAttribute("artic"));
926
+ a.remove();
927
+ });
928
+ return currentMEI;
929
+ }
930
+ exports.mergeArticToParent = mergeArticToParent;
931
+ /**
932
+ * Transpose marked notes according to direcion (up or down)
933
+ * @param currentMEI
934
+ * @param direction
935
+ * @returns
936
+ */
937
+ function transposeByStep(currentMEI, direction) {
938
+ //document.querySelectorAll(".activeContainer #vrvSVG :is(.note.marked, .note.lastAdded)").forEach(nm => {
939
+ document.querySelectorAll(".activeContainer :is(.note.marked, .note.lastAdded)").forEach(nm => {
940
+ if (nm.id === null || nm.id == undefined || nm.id === "")
941
+ return; // make shure that only the id is taken from the verovio svg so that the element will only be effected once
942
+ var id = nm.id;
943
+ var noteMEI = currentMEI.getElementById(id);
944
+ var pname = noteMEI.getAttribute("pname");
945
+ var oct = parseInt(noteMEI.getAttribute("oct"));
946
+ var accid = noteMEI.getAttribute("accid") || noteMEI.getAttribute("accid.ges");
947
+ if (accid === null || typeof accid == "undefined" || accid === "n") {
948
+ accid = "";
949
+ }
950
+ var nextNote;
951
+ if (direction === "up") {
952
+ nextNote = mappings_1.nextStepUp.get(pname + accid);
953
+ }
954
+ else if (direction === "down") {
955
+ nextNote = mappings_1.nextStepDown.get(pname + accid);
956
+ }
957
+ noteMEI.setAttribute("pname", nextNote.charAt(0));
958
+ if (nextNote.charAt(1) !== "") {
959
+ noteMEI.setAttribute("accid", nextNote.charAt(1));
960
+ }
961
+ else {
962
+ noteMEI.removeAttribute("accid");
963
+ noteMEI.removeAttribute("accid.ges");
964
+ }
965
+ //Change Octave
966
+ if (["c", "cf"].includes(pname + accid) && direction === "down") {
967
+ noteMEI.setAttribute("oct", (oct - 1).toString());
968
+ }
969
+ if (["b", "bs"].includes(pname + accid) && direction === "up") {
970
+ noteMEI.setAttribute("oct", (oct + 1).toString());
971
+ }
972
+ });
973
+ return adjustAccids(currentMEI);
974
+ }
975
+ exports.transposeByStep = transposeByStep;
976
+ /**
977
+ * Change Meter according to #timeUnit and #timeCount in side bar option.
978
+ * @param currentMEI
979
+ * @returns changed mei; null, if input has no valid values
980
+ */
981
+ function changeMeter(currentMEI) {
982
+ var timeCount = document.querySelector(".activeElement #timeCount");
983
+ var timeUnit = document.querySelector(".activeElement #timeUnit");
984
+ //@ts-ignore
985
+ var timeCountValue = timeCount.value; //getAttribute("value")
986
+ //@ts-ignore
987
+ var timeUnitValue = timeUnit.value; //getAttribute("value")
988
+ if (timeCountValue !== null && timeUnitValue !== null) {
989
+ timeCountValue = timeCountValue.trim();
990
+ timeUnitValue = timeUnitValue.trim();
991
+ if (!isNaN(parseInt(timeCountValue)) && !isNaN(parseInt(timeUnitValue))) {
992
+ var oldMeterRatio = getMeterRatioGlobal(currentMEI);
993
+ currentMEI.querySelectorAll("staffDef").forEach(sd => {
994
+ sd.setAttribute("meter.count", timeCountValue);
995
+ sd.setAttribute("meter.unit", timeUnitValue);
996
+ });
997
+ // adjust noteposition
998
+ var newMeterRatio = getMeterRatioGlobal(currentMEI);
999
+ if (oldMeterRatio > newMeterRatio) {
1000
+ checkInsertShifts(currentMEI);
1001
+ }
1002
+ else if (oldMeterRatio < newMeterRatio) {
1003
+ checkDeleteShifts(currentMEI);
1004
+ }
1005
+ if (oldMeterRatio !== newMeterRatio) {
1006
+ return currentMEI;
1007
+ }
1008
+ }
1009
+ }
1010
+ return currentMEI; //null
1011
+ }
1012
+ exports.changeMeter = changeMeter;
1013
+ /**
1014
+ * disable features if necesseray (only supposed to be used for debugging)
1015
+ * @param features Array of TagNames and AttributeNames which have to be disabled (deleted)
1016
+ * @param currentMEI mei
1017
+ * @returns
1018
+ */
1019
+ function disableFeatures(features, currentMEI) {
1020
+ //console.log("Features disabled:", features)
1021
+ features.forEach(f => {
1022
+ var elements = Array.from(currentMEI.getElementsByTagName(f));
1023
+ elements.forEach(e => {
1024
+ let parent = e.parentElement;
1025
+ e.remove();
1026
+ if (parent.childElementCount === 0) {
1027
+ parent.remove();
1028
+ }
1029
+ });
1030
+ elements = Array.from(currentMEI.querySelectorAll("*[" + f + "]"));
1031
+ elements.forEach(e => {
1032
+ let parent = e.parentElement;
1033
+ e.remove();
1034
+ if (parent.childElementCount === 0) {
1035
+ parent.remove();
1036
+ }
1037
+ });
1038
+ });
1039
+ return currentMEI;
1040
+ }
1041
+ exports.disableFeatures = disableFeatures;
1042
+ /**
1043
+ * When a note is shortened, fill old remaining duration with rests
1044
+ * @param newElement
1045
+ * @param oldElement
1046
+ * @param currentMEI
1047
+ */
1048
+ function fillWithRests(newElement, oldElement, currentMEI) {
1049
+ var newRatio = getAbsoluteRatio(newElement);
1050
+ var oldRatio = getAbsoluteRatio(oldElement);
1051
+ if (newRatio < oldRatio) {
1052
+ var remainRatio = oldRatio - newRatio;
1053
+ var smallestUnit = gcd(remainRatio);
1054
+ var restDur = ratioToDur(smallestUnit)[0];
1055
+ var restCount = remainRatio / smallestUnit;
1056
+ newElement.classList.add("changed");
1057
+ for (var i = 0; i < restCount; i++) {
1058
+ var rest = createNewRestElement(restDur);
1059
+ currentMEI.getElementById(newElement.id).parentElement.insertBefore(rest, newElement.nextElementSibling);
1060
+ }
1061
+ }
1062
+ return currentMEI;
1063
+ }
1064
+ exports.fillWithRests = fillWithRests;
1065
+ function fillLayerWithRests(layer, currentMEI) {
1066
+ var targetDur = getMeterRatioLocal(currentMEI, layer);
1067
+ var currentDur = getAbsoluteRatio(layer);
1068
+ if (currentDur < targetDur) {
1069
+ var remainRatio = targetDur - currentDur;
1070
+ var smallestUnit = gcd(remainRatio);
1071
+ var restDur = ratioToDur(smallestUnit)[0];
1072
+ var restCount = remainRatio / smallestUnit;
1073
+ for (var i = 0; i < restCount; i++) {
1074
+ var rest = createNewRestElement(restDur);
1075
+ Array.from(layer.querySelectorAll("note, chord, rest")).reverse()[0].insertAdjacentElement("afterend", rest);
1076
+ }
1077
+ }
1078
+ }
1079
+ exports.fillLayerWithRests = fillLayerWithRests;
1080
+ /**
1081
+ * Fill Empty Space with rest
1082
+ * @deprecated
1083
+ * @param currentMEI
1084
+ */
1085
+ function _fillWithRests(currentMEI) {
1086
+ var staffDef = currentMEI.getElementsByTagName("staffDef").item(0);
1087
+ var meterCount;
1088
+ var meterUnit;
1089
+ var meterRatio;
1090
+ if (staffDef.getAttribute(constants_1.constants._METERCOUNT_) !== null && staffDef.getAttribute(constants_1.constants._METERUNIT_) !== null) {
1091
+ meterCount = staffDef.getAttribute(constants_1.constants._METERCOUNT_);
1092
+ meterUnit = staffDef.getAttribute(constants_1.constants._METERUNIT_);
1093
+ meterRatio = parseInt(meterCount) / parseInt(meterUnit);
1094
+ }
1095
+ else {
1096
+ var meterRatio = getMeterRatioGlobal(currentMEI);
1097
+ meterCount = (meterRatio * 4).toString();
1098
+ meterUnit = "4";
1099
+ }
1100
+ currentMEI.querySelectorAll("measure").forEach(m => {
1101
+ m.querySelectorAll("staff").forEach(s => {
1102
+ s.querySelectorAll("layer").forEach((l, idx) => {
1103
+ //mRest for empty Layer
1104
+ if (l.childElementCount === 0) {
1105
+ if (idx === 0) {
1106
+ var restEl = document.createElementNS(constants_1.constants._MEINS_, "mRest");
1107
+ l.appendChild(restEl);
1108
+ }
1109
+ else { // remove 1+ empty layer
1110
+ l.remove();
1111
+ }
1112
+ }
1113
+ else {
1114
+ var actualMeterFill = getAbsoluteRatio(l);
1115
+ var ratioDiff = Math.abs(actualMeterFill - meterRatio);
1116
+ var smallestValue = gcd(ratioDiff);
1117
+ //var restDurs = findDotsRecursive(ratioDiff, gcd(ratioDiff))
1118
+ if (Number.isInteger(ratioDiff / smallestValue) && ratioDiff > 0) {
1119
+ var leftRatio = ratioDiff;
1120
+ var durArr = new Array();
1121
+ while (!Number.isInteger(1 / leftRatio)) {
1122
+ var leftRatio = ratioDiff - smallestValue;
1123
+ durArr.push(1 / smallestValue);
1124
+ }
1125
+ durArr.push(1 / leftRatio);
1126
+ durArr = durArr.reverse();
1127
+ durArr.forEach(dur => {
1128
+ var newRest = currentMEI.createElementNS(constants_1.constants._MEINS_, "rest");
1129
+ newRest.setAttribute("dur", dur.toString());
1130
+ l.appendChild(newRest);
1131
+ });
1132
+ }
1133
+ //console.log(document.getElementById(l.id), ratioDiff, gcd(ratioDiff), durArr)
1134
+ }
1135
+ });
1136
+ });
1137
+ });
1138
+ }
1139
+ /**
1140
+ * Replace given id with rest
1141
+ * @param element element from svg
1142
+ * @param currentMEI
1143
+ */
1144
+ function replaceWithRest(element, currentMEI) {
1145
+ var elmei = currentMEI.getElementById(element.id);
1146
+ //var closestChord: Element = currentMEI .getElementById(element.id).closest("chord")
1147
+ //if(closestChord !== null){elmei = closestChord}
1148
+ var dur = elmei.getAttribute("dur");
1149
+ var dots = elmei.getAttribute("dots");
1150
+ var newRest = currentMEI.createElementNS(constants_1.constants._MEINS_, "rest");
1151
+ newRest.setAttribute("dur", dur);
1152
+ if (dots !== null) {
1153
+ newRest.setAttribute("dots", dots);
1154
+ }
1155
+ elmei.parentElement.insertBefore(newRest, elmei);
1156
+ elmei.remove();
1157
+ }
1158
+ /**
1159
+ * @deprecated
1160
+ * Change duration of the following sound events. Elements to change duration are determined by the class to be "marked".
1161
+ * @param currentMEI Current MEI as Document
1162
+ * @param additionalElements Elements to be considered to be changed.
1163
+ * @param refElement Reference Element after which all determined elements (.marked and additionElements) will be changed (e.g. replacing duration during a note insert).
1164
+ * If no refElement is given, filter the additionalElements to exclude the refElement
1165
+ * @param marked Consider marked elements
1166
+ * @returns
1167
+ */
1168
+ function _changeDuration(currentMEI, additionalElements = new Array(), refElement = null) {
1169
+ var currMeiClone = currentMEI.cloneNode(true);
1170
+ var changedFlag = "changed";
1171
+ var multiplier;
1172
+ var elmei;
1173
+ var i = refElement === null ? 1 : 0;
1174
+ for (i; i < additionalElements.length; i++) {
1175
+ elmei = currentMEI.getElementById(additionalElements[i].id);
1176
+ var elmeiRatio = getAbsoluteRatio(elmei);
1177
+ var chord = elmei.closest("chord");
1178
+ //Dur is attribute of chord and all notes will be changed accordingly
1179
+ if (chord !== null) {
1180
+ if (chord.classList.contains(changedFlag)) {
1181
+ return;
1182
+ }
1183
+ else {
1184
+ elmei = chord;
1185
+ elmei.classList.add(changedFlag);
1186
+ }
1187
+ }
1188
+ var dur = parseInt(elmei.getAttribute("dur"));
1189
+ var dots = parseInt(elmei.getAttribute("dots")); // is NaN if elmei has no dots
1190
+ if (dur > 0) {
1191
+ var layerRatio = getAbsoluteRatio(elmei.closest("layer")); // current ratio of layer with already inserted new sound event
1192
+ var localRatio = getMeterRatioLocal(currentMEI, elmei); //getMeterRatioGlobal(currentMEI )
1193
+ var danglingRatio = layerRatio - localRatio;
1194
+ if (danglingRatio > 0) {
1195
+ var nextElementRatio = getAbsoluteRatio(elmei);
1196
+ var neNewRatio = nextElementRatio - danglingRatio;
1197
+ if (neNewRatio > 0) {
1198
+ var durArr = ratioToDur(neNewRatio);
1199
+ elmei.setAttribute("dur", durArr[0].toString());
1200
+ if (durArr[1] > 0) {
1201
+ elmei.setAttribute("dots", durArr[1].toString());
1202
+ }
1203
+ else {
1204
+ elmei.removeAttribute("dots");
1205
+ }
1206
+ }
1207
+ else {
1208
+ elmei.remove();
1209
+ }
1210
+ }
1211
+ if ((layerRatio <= localRatio && refElement === null) || (layerRatio < localRatio && refElement !== null)) {
1212
+ var nextElementRatio = getAbsoluteRatio(elmei);
1213
+ var neNewRatio;
1214
+ if (refElement !== null) {
1215
+ neNewRatio = nextElementRatio - getAbsoluteRatio(refElement);
1216
+ }
1217
+ else {
1218
+ var addRatios = (function (elements) {
1219
+ var r = 0;
1220
+ elements.forEach((v, i) => {
1221
+ if (i > 0) {
1222
+ r += getAbsoluteRatio(v);
1223
+ }
1224
+ });
1225
+ return r;
1226
+ });
1227
+ neNewRatio = nextElementRatio - (layerRatio - addRatios(additionalElements) - getAbsoluteRatio(additionalElements[0]));
1228
+ }
1229
+ if (neNewRatio > 0) {
1230
+ var durArr = ratioToDur(neNewRatio);
1231
+ elmei.setAttribute("dur", durArr[0].toString());
1232
+ if (durArr[1] > 0) {
1233
+ elmei.setAttribute("dots", durArr[1].toString());
1234
+ }
1235
+ else {
1236
+ elmei.removeAttribute("dots");
1237
+ }
1238
+ }
1239
+ else {
1240
+ elmei.remove();
1241
+ }
1242
+ }
1243
+ }
1244
+ }
1245
+ if (!overfillMeasure && elmei != undefined && (elmei === null || elmei === void 0 ? void 0 : elmei.closest("layer")) !== null) {
1246
+ var newMeasureRatio = getAbsoluteRatio(elmei.closest("layer"));
1247
+ var localRatio = getMeterRatioLocal(currentMEI, elmei);
1248
+ if (newMeasureRatio > localRatio) { //getMeterRatioGlobal(currentMEI )){
1249
+ currentMEI = currMeiClone;
1250
+ }
1251
+ }
1252
+ //clean up after changing durations
1253
+ currentMEI.querySelectorAll(".changed").forEach(c => c.classList.remove(changedFlag));
1254
+ cleanUp(currentMEI);
1255
+ return currentMEI;
1256
+ }
1257
+ function addRatios(elements) {
1258
+ var r = 0;
1259
+ elements.forEach((v, i) => {
1260
+ //if(i > 0){
1261
+ r += getAbsoluteRatio(v);
1262
+ //}
1263
+ });
1264
+ return r;
1265
+ }
1266
+ /**
1267
+ *
1268
+ * @param currentMEI current used MEI to be changed
1269
+ * @param additionalElements elements which duration has to be changed which occur after the refElement in the same layer
1270
+ * @param refElement actual current Element which will be changed in duration
1271
+ * @param remainRatio remaining ratio of the current layer
1272
+ * @param meiToReset MEI which can be used to reset the whole process
1273
+ * @returns
1274
+ */
1275
+ function changeDurationsInLayer(currentMEI, additionalElements = new Array(), refElement = null, remainRatio = null, meiToReset = null) {
1276
+ var meiCopy = meiToReset || currentMEI.cloneNode(true);
1277
+ let ms = Array.from(refElement.parentElement.querySelectorAll("note:not(chord note), chord, rest")); // querySelectorAll("note:not(chord note), chord, beam, rest")
1278
+ var measureSiblings = ms.filter((_, i) => i <= ms.indexOf(refElement));
1279
+ var ratioUpTpRef = addRatios(measureSiblings);
1280
+ var refElementRatio = getAbsoluteRatio(refElement);
1281
+ var remainBarRatio = getMeterRatioLocal(currentMEI, refElement) - ratioUpTpRef;
1282
+ if (getAbsoluteRatio(refElement.parentElement) === getMeterRatioLocal(currentMEI, refElement)) { // bar has right size,
1283
+ return currentMEI;
1284
+ }
1285
+ if (additionalElements.length > 0) {
1286
+ var nextNote = additionalElements.shift();
1287
+ var nnRatio = getAbsoluteRatio(nextNote);
1288
+ remainRatio = remainRatio || refElementRatio;
1289
+ var currEl;
1290
+ var harm;
1291
+ if (remainRatio < nnRatio) {
1292
+ var diffRatio = nnRatio - remainRatio;
1293
+ var nextNoteMEI = currentMEI.getElementById(nextNote.id);
1294
+ //var dur = ratioToDur(diffRatio)
1295
+ // currentMEI.getElementById(nextNote.id).setAttribute("dur", dur.shift().toString())
1296
+ // if (dur.length > 0) {
1297
+ // currentMEI.getElementById(nextNote.id).setAttribute("dots", dur.shift().toString())
1298
+ // }
1299
+ changeDur(nextNoteMEI, diffRatio);
1300
+ harm = currentMEI.querySelector('harm[startid="' + nextNote.id + '"]');
1301
+ if (harm !== null) {
1302
+ harm.setAttribute("startid", refElement.id);
1303
+ }
1304
+ }
1305
+ else if (remainRatio === nnRatio) {
1306
+ currEl = currentMEI.getElementById(nextNote.id);
1307
+ harm = currentMEI.querySelector('harm[startid="' + nextNote.id + '"]');
1308
+ //if(currEl.tagName === "rest" && harm !== null){
1309
+ if (harm !== null) {
1310
+ harm.setAttribute("startid", refElement.id);
1311
+ }
1312
+ currEl.remove();
1313
+ }
1314
+ else {
1315
+ currEl = currentMEI.getElementById(nextNote.id);
1316
+ harm = currentMEI.querySelector('harm[startid="' + nextNote.id + '"]');
1317
+ //if(currEl.tagName === "rest" && harm !== null){
1318
+ if (harm !== null) {
1319
+ harm.setAttribute("startid", refElement.id);
1320
+ }
1321
+ remainRatio = remainRatio - nnRatio;
1322
+ currEl.remove();
1323
+ changeDurationsInLayer(currentMEI, additionalElements, refElement, remainRatio, meiCopy);
1324
+ }
1325
+ }
1326
+ cleanUp(currentMEI);
1327
+ return currentMEI;
1328
+ }
1329
+ exports.changeDurationsInLayer = changeDurationsInLayer;
1330
+ /**
1331
+ * Change duration attributes for given Element for the given ratio.
1332
+ * Will also change dot attribute if necessary
1333
+ * @param element
1334
+ * @param ratio
1335
+ */
1336
+ function changeDur(element, ratio) {
1337
+ var dur = ratioToDur(ratio);
1338
+ element.setAttribute("dur", dur.shift().toString());
1339
+ if (dur.length > 0) {
1340
+ element.setAttribute("dots", dur.shift().toString());
1341
+ }
1342
+ }
1343
+ exports.changeDur = changeDur;
1344
+ /**
1345
+ * Check if elment is overfilling the current layer element. Must provide previous MEI for reference.
1346
+ * Violate rule: true; follow rules: false
1347
+ * @param element
1348
+ * @param currMeiClone
1349
+ * @returns
1350
+ */
1351
+ function elementIsOverfilling(element, currMeiClone) {
1352
+ if (!overfillMeasure) {
1353
+ var newMeasureRatio = getAbsoluteRatio(element.closest("layer"));
1354
+ var localRatio = getMeterRatioLocal(currMeiClone, element);
1355
+ if (newMeasureRatio > localRatio) { //getMeterRatioGlobal(currMeiClone)){
1356
+ return true;
1357
+ }
1358
+ }
1359
+ return false;
1360
+ }
1361
+ exports.elementIsOverfilling = elementIsOverfilling;
1362
+ /**
1363
+ * Clean up mei after changing values
1364
+ * @param currentMEI
1365
+ */
1366
+ function cleanUp(currentMEI) {
1367
+ deleteDefSequences(currentMEI);
1368
+ reorganizeBeams(currentMEI);
1369
+ removeEmptyElements(currentMEI);
1370
+ adjustRests(currentMEI);
1371
+ redistributeHarms(currentMEI);
1372
+ }
1373
+ exports.cleanUp = cleanUp;
1374
+ /**
1375
+ * Delete all redundant definition sequences in staffDefs and layers
1376
+ * @param currentMEI
1377
+ */
1378
+ function deleteDefSequences(currentMEI) {
1379
+ var staffCount = currentMEI.querySelectorAll("staffDef").length;
1380
+ for (var i = 0; i < staffCount; i++) {
1381
+ var n = (i + 1).toString();
1382
+ var prevElement = null;
1383
+ var prevShape = null;
1384
+ var prevLine = null;
1385
+ currentMEI.querySelectorAll("staffDef[n=\"" + n + "\"] clef, staff[n=\"" + n + "\"] clef").forEach(clefElement => {
1386
+ var shape = clefElement.getAttribute("shape");
1387
+ var line = clefElement.getAttribute("line");
1388
+ if (prevElement != null) {
1389
+ prevShape = prevElement.getAttribute("shape");
1390
+ prevLine = prevElement.getAttribute("line");
1391
+ if (prevShape === shape && prevLine === line) {
1392
+ clefElement.remove();
1393
+ }
1394
+ else {
1395
+ prevElement = clefElement;
1396
+ }
1397
+ }
1398
+ else {
1399
+ prevElement = clefElement;
1400
+ }
1401
+ });
1402
+ prevElement = null;
1403
+ var prevSig = null;
1404
+ currentMEI.querySelectorAll("staffDef[n=\"" + n + "\"] keySig, staff[n=\"" + n + "\"] keySig").forEach(sigElement => {
1405
+ var sig = sigElement.getAttribute("sig");
1406
+ if (prevElement != null) {
1407
+ prevSig = prevElement.getAttribute("sig");
1408
+ if (prevSig === sig) {
1409
+ sigElement.remove();
1410
+ }
1411
+ else {
1412
+ prevElement = sigElement;
1413
+ }
1414
+ }
1415
+ else {
1416
+ prevElement = sigElement;
1417
+ }
1418
+ });
1419
+ prevElement = null;
1420
+ currentMEI.querySelectorAll("staffDef[n=\"" + n + "\"] meterSig, staff[n=\"" + n + "\"] meterSig").forEach(meterElement => {
1421
+ var count = meterElement.getAttribute("count");
1422
+ var unit = meterElement.getAttribute("unit");
1423
+ if (prevElement != null) {
1424
+ var lastCount = prevElement.getAttribute("count");
1425
+ var lastUnit = prevElement.getAttribute("unit");
1426
+ if (lastCount === count && lastUnit === unit) {
1427
+ meterElement.remove();
1428
+ }
1429
+ else {
1430
+ prevElement = meterElement;
1431
+ }
1432
+ }
1433
+ else {
1434
+ prevElement = meterElement;
1435
+ }
1436
+ });
1437
+ }
1438
+ }
1439
+ function reorganizeBeams(currentMEI) {
1440
+ // if beams have elements, which shouldn be there
1441
+ currentMEI.querySelectorAll("beam").forEach(b => {
1442
+ var beamNotes = Array.from(b.children);
1443
+ if (!beamNotes.every(c => parseInt(c.getAttribute("dur")) >= 8) && beamNotes.length > 0) {
1444
+ beamNotes.forEach(n => {
1445
+ if (parseInt(n.getAttribute("dur")) >= 8) {
1446
+ if (n.previousElementSibling !== null) {
1447
+ if (n.previousElementSibling.tagName === "beam") { // check for previous beams to merge with
1448
+ n.previousElementSibling.appendChild(n);
1449
+ }
1450
+ }
1451
+ else { // else make new beam
1452
+ var newBeam = currentMEI.createElementNS(constants_1.constants._MEINS_, "beam");
1453
+ newBeam.setAttribute("id", random_1.uuidv4());
1454
+ n.parentElement.insertBefore(newBeam, n);
1455
+ newBeam.append(n);
1456
+ }
1457
+ }
1458
+ });
1459
+ //set all inner elements outseide of old beam
1460
+ b.outerHTML = b.innerHTML;
1461
+ }
1462
+ });
1463
+ }
1464
+ /**
1465
+ * After manipulating elements in the score, some elements could be empty
1466
+ * @param currentMEI
1467
+ */
1468
+ function removeEmptyElements(currentMEI) {
1469
+ Array.from(currentMEI.querySelectorAll("beam")).forEach(b => {
1470
+ var _a;
1471
+ if (b.childElementCount === 0) {
1472
+ (_a = currentMEI.getElementById(b.id)) === null || _a === void 0 ? void 0 : _a.remove();
1473
+ }
1474
+ if (b.childElementCount === 1) {
1475
+ //b.parentElement.insertBefore(b, b.firstChild)
1476
+ //b.remove()
1477
+ b.outerHTML = b.innerHTML;
1478
+ }
1479
+ var bArr = Array.from(b.children);
1480
+ if (bArr.every(c => c.tagName === "rest") && bArr.length > 0) {
1481
+ // Array.from(b.children).forEach(c => {
1482
+ // b.parentElement.insertBefore(c, b)
1483
+ // })
1484
+ // b.remove()
1485
+ b.outerHTML = b.innerHTML;
1486
+ }
1487
+ // Avoids that unvalid rests will be displayed as double full notes
1488
+ Array.from(currentMEI.querySelectorAll("rest")).forEach(r => {
1489
+ if (r.getAttribute("dur") === "0" || r.getAttribute("dur") === null) {
1490
+ r.removeAttribute("dur");
1491
+ r.removeAttribute("dots");
1492
+ r.outerHTML = r.outerHTML.replace("rest>", "mRest>");
1493
+ }
1494
+ });
1495
+ Array.from(currentMEI.querySelectorAll("*[xmlns]")).forEach(x => {
1496
+ var attr = x.getAttribute("xmlns");
1497
+ if (attr === "" || attr === null || attr == undefined) {
1498
+ x.removeAttribute("xmlns");
1499
+ }
1500
+ });
1501
+ });
1502
+ // allow no empty and rest-note element chord elements
1503
+ Array.from(currentMEI.querySelectorAll("chord")).forEach(c => {
1504
+ if (c.childElementCount === 0) {
1505
+ currentMEI.getElementById(c.id).remove();
1506
+ }
1507
+ else if (c.childElementCount === 1) {
1508
+ c.outerHTML = c.innerHTML;
1509
+ }
1510
+ else if (c.childElementCount === 2 && c.querySelector("rest") !== null && c.querySelector("note") !== null) {
1511
+ c.querySelector("note").setAttribute("dur", c.getAttribute("dur"));
1512
+ c.querySelector("rest").remove();
1513
+ c.outerHTML = c.innerHTML;
1514
+ }
1515
+ });
1516
+ // Empty harms could be somewhere
1517
+ Array.from(currentMEI.querySelectorAll("harm")).forEach(h => {
1518
+ if (h.childElementCount > 0) {
1519
+ if (h.firstElementChild.childElementCount === 0)
1520
+ h.remove();
1521
+ }
1522
+ else if (h.textContent === "") {
1523
+ h.remove();
1524
+ }
1525
+ });
1526
+ // remove all xmlns since they are someties empty and also are not parsable sometimes
1527
+ Array.from(currentMEI.querySelectorAll("*")).forEach(el => {
1528
+ if (el.tagName.toLowerCase() === "xml")
1529
+ return;
1530
+ el.removeAttribute("xmlns");
1531
+ });
1532
+ // Array.from(currentMEI .querySelectorAll("measure")).forEach(m => {
1533
+ // if(m.querySelectorAll("note, chord").length === 0){
1534
+ // currentMEI .getElementById(m.id).remove()
1535
+ // }
1536
+ // })
1537
+ }
1538
+ /**
1539
+ * Apply some additional rules for rests, Elements where added
1540
+ * @param currentMEI
1541
+ */
1542
+ function adjustRests(currentMEI) {
1543
+ //mRest and any Element with dur attribute are not allowed in the same layer
1544
+ currentMEI.querySelectorAll("layer").forEach(l => {
1545
+ var hasAnyDurAttributes = l.querySelectorAll("*[dur]").length > 0;
1546
+ var hasTags = l.querySelectorAll("clef, keySig").length > 0;
1547
+ var hasMrest = l.querySelectorAll("mRest").length > 0;
1548
+ if (l.children.length === 0 || (hasTags && !hasAnyDurAttributes && !hasMrest)) {
1549
+ //no layer should be empty, has at least an mRest (therefore: mRests are virtually not deletable)
1550
+ var newMrest = new mei_template_1.default().createMRest();
1551
+ l.append(newMrest);
1552
+ }
1553
+ else {
1554
+ Array.from(l.children).forEach(cn => {
1555
+ if (cn.tagName === "mRest" && hasAnyDurAttributes) {
1556
+ cn.remove();
1557
+ }
1558
+ });
1559
+ }
1560
+ });
1561
+ }
1562
+ /**
1563
+ * Give harm new start id if related note was included in chord during process
1564
+ * @param currentMEI
1565
+ */
1566
+ function redistributeHarms(currentMEI) {
1567
+ currentMEI.querySelectorAll("harm").forEach(h => {
1568
+ var startid = h.getAttribute("startid");
1569
+ if (startid !== null) {
1570
+ var note = currentMEI.getElementById(startid);
1571
+ if ((note === null || note === void 0 ? void 0 : note.parentElement.tagName) === "chord")
1572
+ h.setAttribute("startid", note.parentElement.id);
1573
+ }
1574
+ });
1575
+ }
1576
+ /**
1577
+ * Remove tie from all layers if length of layer exceeds global Ratio
1578
+ * @param currentMEI
1579
+ */
1580
+ function removeTiesFromDoc(currentMEI) {
1581
+ var globalRatio = getMeterRatioGlobal(currentMEI);
1582
+ currentMEI.querySelectorAll("layer").forEach(l => {
1583
+ var layerRatio = getAbsoluteRatio(l);
1584
+ if (layerRatio > globalRatio) {
1585
+ var m = l.closest("measure");
1586
+ m.querySelectorAll("tie").forEach(t => {
1587
+ var _a;
1588
+ (_a = l.querySelector(t.getAttribute("endid"))) === null || _a === void 0 ? void 0 : _a.remove();
1589
+ t.remove();
1590
+ });
1591
+ }
1592
+ });
1593
+ }
1594
+ function addMeasure(currentMEI) {
1595
+ var lastMeasure = Array.from(currentMEI.querySelectorAll("measure")).reverse()[0];
1596
+ var staffCounts = Array.from(lastMeasure.querySelectorAll("staff")).map(s => { return parseInt(s.getAttribute("n")); });
1597
+ var staffCount = Math.max.apply(Math, staffCounts);
1598
+ var layerCounts = Array.from(lastMeasure.querySelectorAll("layer")).map(s => { return parseInt(s.getAttribute("n")); });
1599
+ var layerCount = Math.max.apply(Math, layerCounts);
1600
+ var newMeasure = new mei_template_1.default().createMeasure(1, staffCount, layerCount);
1601
+ lastMeasure.parentElement.append(newMeasure);
1602
+ var i = 1;
1603
+ currentMEI.querySelectorAll("measure").forEach(m => {
1604
+ m.setAttribute("n", i.toString());
1605
+ i++;
1606
+ });
1607
+ newMeasure.setAttribute("id", random_1.uuidv4());
1608
+ newMeasure.querySelectorAll("*").forEach(el => {
1609
+ if (el.id === null || el.id === "") {
1610
+ el.setAttribute("id", random_1.uuidv4());
1611
+ }
1612
+ });
1613
+ cleanUp(currentMEI);
1614
+ }
1615
+ exports.addMeasure = addMeasure;
1616
+ function removeMeasure(currentMEI) {
1617
+ var measures = Array.from(currentMEI.querySelectorAll("measure")).reverse();
1618
+ if (measures.length > 1) {
1619
+ measures[0].remove();
1620
+ }
1621
+ else {
1622
+ measures[0].querySelectorAll("layer").forEach(l => {
1623
+ l.innerHTML = "";
1624
+ l.appendChild(currentMEI.createElement("mRest"));
1625
+ });
1626
+ }
1627
+ cleanUp(currentMEI);
1628
+ }
1629
+ exports.removeMeasure = removeMeasure;
1630
+ function addStaff(currentMEI, referenceStaff, relPos) {
1631
+ var staffNum = referenceStaff.getAttribute("n");
1632
+ var refn;
1633
+ var refElement;
1634
+ currentMEI.querySelectorAll("staff[n=\"" + staffNum + "\"]").forEach(s => {
1635
+ var _a;
1636
+ var newStaff = new mei_template_1.default().createStaff(1, 1);
1637
+ switch (relPos) {
1638
+ case "above":
1639
+ refElement = s;
1640
+ break;
1641
+ case "below":
1642
+ refElement = s.nextElementSibling || s;
1643
+ break;
1644
+ default:
1645
+ console.error(relPos, " was never an option");
1646
+ }
1647
+ if (relPos === "below" && refElement === s) { // => new staff at the end
1648
+ s.parentElement.append(newStaff);
1649
+ }
1650
+ else {
1651
+ s.parentElement.insertBefore(newStaff, refElement);
1652
+ }
1653
+ //copy elements from the current Staff that have to appear in new staff
1654
+ var newLayer = newStaff.querySelector("layer");
1655
+ var copyMeter = (_a = s.querySelector("meterSig")) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
1656
+ if (copyMeter != undefined && copyMeter !== null) {
1657
+ newLayer.insertBefore(copyMeter, newLayer.firstChild);
1658
+ }
1659
+ refn = (refElement === null || refElement === void 0 ? void 0 : refElement.getAttribute("n")) || staffNum; // s.getAttribute("n")
1660
+ });
1661
+ //new StaffDef
1662
+ var refStaffDef = currentMEI.querySelector("staffDef[n=\"" + refn + "\"]");
1663
+ var refCopy = refStaffDef.cloneNode(true);
1664
+ refCopy.querySelectorAll("*[id]").forEach(i => {
1665
+ i.removeAttribute("id");
1666
+ });
1667
+ refStaffDef.parentElement.insertBefore(refCopy, refStaffDef);
1668
+ currentMEI.querySelectorAll("measure").forEach(m => {
1669
+ var i = 1;
1670
+ m.querySelectorAll("staff").forEach(s => {
1671
+ s.setAttribute("n", i.toString());
1672
+ i++;
1673
+ });
1674
+ });
1675
+ var i = 1;
1676
+ currentMEI.querySelectorAll("staffDef").forEach(sd => {
1677
+ sd.setAttribute("n", i.toString());
1678
+ i++;
1679
+ });
1680
+ cleanUp(currentMEI);
1681
+ }
1682
+ exports.addStaff = addStaff;
1683
+ function removeStaff(currentMEI, referenceStaff, relPos) {
1684
+ var staff = currentMEI.getElementById(referenceStaff.id);
1685
+ var staffNum = staff.getAttribute("n");
1686
+ var refn;
1687
+ currentMEI.querySelectorAll("staff[n=\"" + staffNum + "\"]").forEach(s => {
1688
+ switch (relPos) {
1689
+ case "above":
1690
+ refn = s.previousElementSibling.getAttribute("n");
1691
+ s.previousElementSibling.remove();
1692
+ break;
1693
+ case "below":
1694
+ refn = s.nextElementSibling.getAttribute("n");
1695
+ s.nextElementSibling.remove();
1696
+ break;
1697
+ default:
1698
+ console.error(relPos, " was never an option");
1699
+ }
1700
+ });
1701
+ currentMEI.querySelector("staffDef[n=\"" + refn + "\"]").remove();
1702
+ currentMEI.querySelectorAll("measure").forEach(m => {
1703
+ var i = 1;
1704
+ m.querySelectorAll("staff").forEach(s => {
1705
+ s.setAttribute("n", i.toString());
1706
+ i++;
1707
+ });
1708
+ });
1709
+ var i = 1;
1710
+ currentMEI.querySelectorAll("staffDef").forEach(sd => {
1711
+ sd.setAttribute("n", i.toString());
1712
+ i++;
1713
+ });
1714
+ cleanUp(currentMEI);
1715
+ }
1716
+ exports.removeStaff = removeStaff;
1717
+ /**
1718
+ * Create a tuplet out of given Elements.
1719
+ * Tuplet duration and kind will be derived from number and attributes of the given notes.
1720
+ * E.g.: Selecting 3 Notes will make a triplet, 4 Notes will make a quadruplet, etc. The after the tuplet the missing durations will be added as rests
1721
+ * @param meiElements
1722
+ */
1723
+ function createTuplet(meiElements, currentMEI) {
1724
+ meiElements = meiElements.filter(me => {
1725
+ if (me != undefined) {
1726
+ return me.getAttribute("dur") !== null;
1727
+ }
1728
+ return;
1729
+ });
1730
+ console.log("create tuplets:", meiElements);
1731
+ var arrCopy = [...meiElements];
1732
+ var minDurElement = arrCopy.sort((a, b) => parseFloat(b.getAttribute("dur")) - parseFloat(a.getAttribute("dur")))[0];
1733
+ var ratioTotal = 0;
1734
+ meiElements.forEach(me => ratioTotal += getAbsoluteRatio(me));
1735
+ var ratioMinElement = getAbsoluteRatio(minDurElement);
1736
+ var numMinNotes = (ratioTotal / ratioMinElement);
1737
+ var numTarget = numMinNotes - 1;
1738
+ var ratio = numTarget * getAbsoluteRatio(minDurElement);
1739
+ var [dur, dots] = ratioToDur(ratio);
1740
+ var tuplet = currentMEI.createElement("tuplet");
1741
+ tuplet.setAttribute("dur", dur.toString());
1742
+ if (dots > 0) {
1743
+ tuplet.setAttribute("dots.ges", dots.toString());
1744
+ }
1745
+ tuplet.setAttribute("num", numMinNotes.toString());
1746
+ tuplet.setAttribute("numbase", numTarget.toString());
1747
+ currentMEI.querySelector("#" + meiElements[0].id).insertAdjacentElement("beforebegin", tuplet);
1748
+ meiElements.forEach(me => tuplet.append(me));
1749
+ // fill missing values with rest
1750
+ var [durRest, dotsRest] = ratioToDur((numMinNotes * getAbsoluteRatio(minDurElement)) - ratio);
1751
+ if (ratio < 1) {
1752
+ if (durRest > 0) {
1753
+ var rest = currentMEI.createElement("rest");
1754
+ rest.setAttribute("id", random_1.uuidv4());
1755
+ rest.setAttribute("dur", durRest.toString());
1756
+ if (dotsRest > 0) {
1757
+ rest.setAttribute("dots", dotsRest.toString());
1758
+ }
1759
+ tuplet.insertAdjacentElement("afterend", rest);
1760
+ }
1761
+ }
1762
+ }
1763
+ exports.createTuplet = createTuplet;
1764
+ /**
1765
+ * Paste copied ids. First position to which the Elements are copied is the Element according to the refId (= RefElement).
1766
+ * If multiple staffs are copied, overhanging staffs will be pasted to the staffs below the staff of the RefElement, if definedstaffs exist.
1767
+ * Else these copiedId will be not pasted.
1768
+ * @param ids
1769
+ * @param refId
1770
+ */
1771
+ function paste(ids, refId, currentMEI) {
1772
+ var _a;
1773
+ //ordered by staff
1774
+ var meiElements = new Array();
1775
+ ids.forEach(id => {
1776
+ var el = currentMEI.getElementById(id);
1777
+ //order copiable elements by staff
1778
+ if (["CHORD", "NOTE", "REST"].includes(el === null || el === void 0 ? void 0 : el.tagName.toUpperCase())) {
1779
+ if (!(el.tagName.toUpperCase() === "NOTE" && el.closest("chord") !== null)) {
1780
+ var staff = el.closest("staff");
1781
+ var num = parseInt(staff.getAttribute("n")) - 1;
1782
+ if (meiElements[num] == undefined) {
1783
+ meiElements[num] = new Array();
1784
+ }
1785
+ var cel = el.cloneNode(true);
1786
+ cel.setAttribute("id", random_1.uuidv4());
1787
+ meiElements[num].push(cel);
1788
+ }
1789
+ }
1790
+ });
1791
+ var refElement = currentMEI.getElementById(refId);
1792
+ refElement = (refElement === null || refElement === void 0 ? void 0 : refElement.closest("chord")) || refElement;
1793
+ var refStaff = refElement === null || refElement === void 0 ? void 0 : refElement.closest("staff");
1794
+ var refLayer = refElement === null || refElement === void 0 ? void 0 : refElement.closest("layer");
1795
+ var refMeasure = refElement === null || refElement === void 0 ? void 0 : refElement.closest("measure");
1796
+ var currentMeasure;
1797
+ let anyNew;
1798
+ //console.log(...meiElements)
1799
+ meiElements.forEach((staff, staffIdx) => {
1800
+ var _a, _b, _c, _d, _e, _f, _g;
1801
+ if (refElement === null)
1802
+ return;
1803
+ currentMeasure = refElement.closest("measure");
1804
+ staff.forEach((element, elementIdx) => {
1805
+ var _a, _b;
1806
+ if (["NOTE", "REST"].includes(element.tagName.toUpperCase())) {
1807
+ var newNote = convertToNewNote(element);
1808
+ newNote.nearestNoteId = refElement.id;
1809
+ newNote.relPosX = "right";
1810
+ anyNew = newNote;
1811
+ }
1812
+ else if (element.tagName.toUpperCase() === "CHORD") {
1813
+ var newChord = convertToNewChord(element);
1814
+ newChord.nearestNoteId = refElement.id;
1815
+ newChord.relPosX = "right";
1816
+ anyNew = newChord;
1817
+ var elementArr = Array.from(element.querySelectorAll("note"));
1818
+ }
1819
+ var replace = ((_b = (_a = document.querySelector(".activeContainer")) === null || _a === void 0 ? void 0 : _a.querySelector("#insertToggle")) === null || _b === void 0 ? void 0 : _b.checked) || true;
1820
+ addToMEI(anyNew, currentMEI, replace);
1821
+ refElement = convertToElement(anyNew, currentMEI); //element
1822
+ });
1823
+ //when changing next staff, refElement musst be staff + 1
1824
+ var targetStaffN = (_c = (parseInt((_b = (_a = currentMEI.getElementById(refElement.id)) === null || _a === void 0 ? void 0 : _a.closest("staff")) === null || _b === void 0 ? void 0 : _b.getAttribute("n")) + 1)) === null || _c === void 0 ? void 0 : _c.toString();
1825
+ var refLayerN = (_e = (_d = currentMEI.getElementById(refElement.id)) === null || _d === void 0 ? void 0 : _d.closest("layer")) === null || _e === void 0 ? void 0 : _e.getAttribute("n");
1826
+ var refMeasureN = (_g = (_f = currentMEI.getElementById(refElement.id)) === null || _f === void 0 ? void 0 : _f.closest("measure")) === null || _g === void 0 ? void 0 : _g.getAttribute("n");
1827
+ refElement = currentMEI.querySelector("measure[n=\"" + refMeasureN + "\"] > staff[n=\"" + targetStaffN + "\"] > layer[n=\"" + refLayerN + "\"]");
1828
+ });
1829
+ //Element gets replaced in all other modes except keymode/textmode
1830
+ if (!document.querySelector(".activeContainer").classList.contains("textmode") && ((_a = currentMEI.getElementById(refId)) === null || _a === void 0 ? void 0 : _a.tagName) !== "LAYER") {
1831
+ removeFromMEI([currentMEI.getElementById(refId)], currentMEI);
1832
+ }
1833
+ return anyNew === null || anyNew === void 0 ? void 0 : anyNew.id;
1834
+ }
1835
+ exports.paste = paste;
1836
+ /**
1837
+ * Replace clef in main/ first score definition
1838
+ * @param targetid
1839
+ * @param newClef
1840
+ * @param currentMEI
1841
+ * @returns
1842
+ */
1843
+ function replaceClefinScoreDef(target, newClef, currentMEI) {
1844
+ var staffN = document.querySelector(".activeContainer #vrvSVG #" + target.id).closest(".staff").getAttribute("n");
1845
+ var staffDefClef = currentMEI.querySelector("staffDef[n=\"" + staffN + "\"] > clef");
1846
+ staffDefClef.setAttribute("shape", newClef.charAt(0));
1847
+ staffDefClef.setAttribute("line", mappings_1.clefToLine.get(newClef.charAt(0)));
1848
+ cleanUp(currentMEI);
1849
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1850
+ return currentMEI;
1851
+ }
1852
+ exports.replaceClefinScoreDef = replaceClefinScoreDef;
1853
+ /**
1854
+ * Layer to which a new clef object has to be inserted
1855
+ * @param targetid Usually a barline before which new clef should stand
1856
+ * @param newClef Name of new Clef to be inserted
1857
+ */
1858
+ function insertClef(target, newClef, currentMEI) {
1859
+ var _a, _b;
1860
+ var targetStaffId = ((_a = target.closest(".measure").querySelector(".staff[n=\"" + target.getAttribute("n") + "\"]")) === null || _a === void 0 ? void 0 : _a.id) || ((_b = target.closest(".staff")) === null || _b === void 0 ? void 0 : _b.id);
1861
+ var targetLayerId = currentMEI.getElementById(targetStaffId).querySelector("layer").id;
1862
+ currentMEI.getElementById(targetLayerId).querySelectorAll("clef").forEach(c => c.remove());
1863
+ var clefElement = currentMEI.createElement("clef");
1864
+ clefElement.setAttribute("id", random_1.uuidv4());
1865
+ clefElement.setAttribute("shape", newClef.charAt(0));
1866
+ clefElement.setAttribute("line", mappings_1.clefToLine.get(newClef.charAt(0)));
1867
+ currentMEI.getElementById(targetLayerId).append(clefElement);
1868
+ cleanUp(currentMEI);
1869
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1870
+ return currentMEI;
1871
+ }
1872
+ exports.insertClef = insertClef;
1873
+ function findAttributeRecursive(element, attributeName, currentValue = null) {
1874
+ var value = currentValue || element.getAttribute(attributeName);
1875
+ if (value === null) {
1876
+ Array.from(element.children).forEach(c => {
1877
+ if (value !== null)
1878
+ return;
1879
+ value = findAttributeRecursive(c, attributeName, value);
1880
+ });
1881
+ }
1882
+ console.log(element, value);
1883
+ return value;
1884
+ }
1885
+ /**
1886
+ * If Key is already defined in scoreDef, replace values
1887
+ * @param target
1888
+ * @param newSig
1889
+ * @param currentMEI
1890
+ * @returns
1891
+ */
1892
+ function replaceKeyInScoreDef(target, newSig, currentMEI) {
1893
+ var _a;
1894
+ var staffN = document.querySelector(".activeContainer #vrvSVG #" + target.id).closest(".staff").getAttribute("n");
1895
+ var staffDefSig = currentMEI.querySelector("staffDef[n=\"" + staffN + "\"] > keySig");
1896
+ if (staffDefSig !== null) {
1897
+ staffDefSig.setAttribute("sig", mappings_1.keyIdToSig.get(newSig));
1898
+ }
1899
+ else {
1900
+ var newSigElement = new mei_template_1.default().createKeySig("major", mappings_1.keyIdToSig.get(newSig));
1901
+ (_a = currentMEI.querySelector("staffDef[n=\"" + staffN + "\"]")) === null || _a === void 0 ? void 0 : _a.append(newSigElement);
1902
+ }
1903
+ adjustAccids(currentMEI);
1904
+ cleanUp(currentMEI);
1905
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1906
+ return currentMEI;
1907
+ }
1908
+ exports.replaceKeyInScoreDef = replaceKeyInScoreDef;
1909
+ /**
1910
+ * Create a whole new Sig Element and Insert to MEI at given target
1911
+ * @param target
1912
+ * @param newSig
1913
+ * @param currentMEI
1914
+ * @returns
1915
+ */
1916
+ function insertKey(target, newSig, currentMEI) {
1917
+ var _a, _b;
1918
+ console.log("insertKey", target, newSig);
1919
+ var targetStaff = target.closest(".measure").querySelector(".staff[n=\"" + target.getAttribute("n") + "\"]") || target.closest(".staff");
1920
+ var staffN = targetStaff.getAttribute("n");
1921
+ var parentMeasure = currentMEI.getElementById(targetStaff.id).closest("measure");
1922
+ var pmn = parseInt(parentMeasure.getAttribute("n")) + 1;
1923
+ var targetLayerId = (_a = parentMeasure.parentElement.querySelector("measure[n=\"" + pmn.toString() + "\"] > staff[n=\"" + staffN + "\"] > layer")) === null || _a === void 0 ? void 0 : _a.id;
1924
+ (_b = currentMEI.getElementById(targetLayerId).querySelectorAll("keySig")) === null || _b === void 0 ? void 0 : _b.forEach(c => c.remove());
1925
+ var newSigElement = new mei_template_1.default().createKeySig("major", mappings_1.keyIdToSig.get(newSig));
1926
+ currentMEI.getElementById(targetLayerId).insertBefore(newSigElement, currentMEI.getElementById(targetLayerId).firstElementChild);
1927
+ adjustAccids(currentMEI);
1928
+ cleanUp(currentMEI);
1929
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1930
+ return currentMEI;
1931
+ }
1932
+ exports.insertKey = insertKey;
1933
+ function replaceMeterInScoreDef(target, currentMEI) {
1934
+ var staffN = document.querySelector(".activeContainer #vrvSVG #" + target.id).closest(".staff").getAttribute("n");
1935
+ var staffDefMeter = currentMEI.querySelector("staffDef[n=\"" + staffN + "\"]");
1936
+ var count = document.querySelector(".activeContainer #timeCount").value;
1937
+ var unit = document.querySelector(".activeContainer #timeUnit").value;
1938
+ staffDefMeter.setAttribute("meter.count", count);
1939
+ staffDefMeter.setAttribute("meter.unit", unit);
1940
+ cleanUp(currentMEI);
1941
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1942
+ return currentMEI;
1943
+ }
1944
+ exports.replaceMeterInScoreDef = replaceMeterInScoreDef;
1945
+ function insertMeter(target, currentMEI) {
1946
+ var targetStaff = target.closest(".measure").querySelector(".staff[n=\"" + target.getAttribute("n") + "\"]") || target.closest(".staff");
1947
+ var parentMeasure = currentMEI.getElementById(targetStaff.id).closest("measure");
1948
+ var pmn = parseInt(parentMeasure.getAttribute("n")) + 1;
1949
+ var targetLayers = parentMeasure.parentElement.querySelectorAll("measure[n=\"" + pmn.toString() + "\"] layer");
1950
+ targetLayers.forEach(tl => {
1951
+ var _a;
1952
+ (_a = currentMEI.getElementById(tl.id).querySelectorAll("meterSig")) === null || _a === void 0 ? void 0 : _a.forEach(c => c.remove());
1953
+ });
1954
+ var count = document.querySelector(".activeContainer #selectTime #timeCount").value;
1955
+ var unit = document.querySelector(".activeContainer #selectTime #timeUnit").value;
1956
+ // change for all layers in given measure
1957
+ targetLayers.forEach(tl => {
1958
+ let newMeterElement = new mei_template_1.default().createMeterSig(count, unit); // must be in loop, otherwise same reference gets reassigned every time
1959
+ currentMEI.getElementById(tl.id).insertBefore(newMeterElement, currentMEI.getElementById(tl.id).firstElementChild);
1960
+ });
1961
+ cleanUp(currentMEI);
1962
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1963
+ return currentMEI;
1964
+ }
1965
+ exports.insertMeter = insertMeter;
1966
+ function insertTempo(target, currentMEI) {
1967
+ var measure = currentMEI.getElementById(target.id).closest("measure");
1968
+ var existingTempo = measure.querySelectorAll("tempo");
1969
+ var sameTempos = Array.from(existingTempo).filter(et => {
1970
+ var hasSameTimeStamp = parseFloat(et.getAttribute("timeStamp")) === getElementTimestampById(target.id, currentMEI);
1971
+ var hasSameStartId = et.getAttribute("startId") === target.id;
1972
+ return hasSameTimeStamp || hasSameStartId;
1973
+ });
1974
+ var mmUnit = document.querySelector(".activeContainer #selectTempo #timeCount").value;
1975
+ var mm = document.querySelector(".activeContainer #selectTempo #timeUnit").value;
1976
+ measure.appendChild(new mei_template_1.default().createTempo(mm, mmUnit, getElementTimestampById(target.id, currentMEI).toString(), target.id));
1977
+ sameTempos.forEach(st => st.remove());
1978
+ cleanUp(currentMEI);
1979
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1980
+ return currentMEI;
1981
+ }
1982
+ exports.insertTempo = insertTempo;
1983
+ /**
1984
+ * Gets timestamp of element. Computes it, if no such attribute is present for the element
1985
+ * @param id
1986
+ * @param currentMEI
1987
+ * @returns
1988
+ */
1989
+ function getElementTimestampById(id, currentMEI) {
1990
+ var element = currentMEI.getElementById(id);
1991
+ var timestamp = element.getAttribute("tstamp");
1992
+ if (timestamp === null) {
1993
+ var parentLayer = element.closest("layer");
1994
+ var count = 0;
1995
+ var units = parentLayer.querySelectorAll(countableNoteUnitSelector);
1996
+ for (var i = 0; i < units.length; i++) {
1997
+ if (units[i].getAttribute("dur") !== null) {
1998
+ if (units[i].id === id) {
1999
+ var fraction = 4;
2000
+ if (currentMEI.querySelector("meterSig") !== null) {
2001
+ fraction = parseInt(currentMEI.querySelector("meterSig").getAttribute("unit"));
2002
+ }
2003
+ timestamp = (count * fraction + 1).toString(); // add 1 to accomodate for shift ratio sum
2004
+ break;
2005
+ }
2006
+ count += getAbsoluteRatio(units[i]);
2007
+ }
2008
+ }
2009
+ }
2010
+ return parseFloat(timestamp);
2011
+ }
2012
+ exports.getElementTimestampById = getElementTimestampById;
2013
+ /**
2014
+ * Get Timestamp in specific layer
2015
+ * @param note
2016
+ * @returns
2017
+ */
2018
+ function getTimestamp(note) {
2019
+ var layer = note.closest("layer");
2020
+ var elements = Array.from(layer.querySelectorAll("*[dur]"));
2021
+ elements = elements.filter((v, i) => i <= elements.indexOf(note));
2022
+ var tstamp;
2023
+ elements.forEach(e => {
2024
+ var dur = parseInt(e.getAttribute("dur"));
2025
+ tstamp += 4 / dur;
2026
+ var dots = e.getAttribute("dots");
2027
+ var add = dur;
2028
+ if (dots !== null) {
2029
+ for (var i = 0; i < parseInt(dots); i++) {
2030
+ add = add / 2;
2031
+ tstamp += add;
2032
+ }
2033
+ }
2034
+ });
2035
+ return tstamp;
2036
+ }
2037
+ exports.getTimestamp = getTimestamp;
2038
+ function setArticulation(currentMEI, artic) {
2039
+ document.querySelectorAll(".activeContainer #vrvSVG :is(.chord.marked, .note.marked, .note.lastAdded").forEach(note => {
2040
+ var meiElement = currentMEI.querySelector("#" + note.id);
2041
+ if (meiElement === null)
2042
+ return;
2043
+ if (meiElement.tagName !== "note")
2044
+ return;
2045
+ if (meiElement.tagName === "note" && meiElement.parentElement.tagName === "chord") {
2046
+ meiElement = meiElement.parentElement;
2047
+ }
2048
+ if (meiElement.getAttribute("artic") === null || meiElement.getAttribute("artic") !== artic) {
2049
+ meiElement.setAttribute("artic", artic);
2050
+ }
2051
+ else {
2052
+ meiElement.removeAttribute("artic");
2053
+ }
2054
+ });
2055
+ return currentMEI;
2056
+ }
2057
+ exports.setArticulation = setArticulation;
2058
+ //PRIVATE
2059
+ function convertToNewNote(element) {
2060
+ var newNote = {
2061
+ id: random_1.uuidv4(),
2062
+ pname: element.getAttribute("pname"),
2063
+ dur: element.getAttribute("dur"),
2064
+ dots: element.getAttribute("dots"),
2065
+ oct: element.getAttribute("oct"),
2066
+ accid: element.getAttribute("accid") || element.getAttribute("accid.ges"),
2067
+ rest: element.tagName.toUpperCase() === "REST" ? true : false
2068
+ };
2069
+ return newNote;
2070
+ }
2071
+ function convertToElement(n, currentMEI) {
2072
+ var nn;
2073
+ var newElement;
2074
+ if (n.hasOwnProperty("pname")) {
2075
+ nn = n;
2076
+ newElement = currentMEI.createElement("note");
2077
+ newElement.setAttribute("pname", nn.pname);
2078
+ newElement.setAttribute("oct", nn.oct);
2079
+ newElement.setAttribute("accid", nn.accid);
2080
+ }
2081
+ else {
2082
+ nn = n;
2083
+ newElement = currentMEI.createElement("chord");
2084
+ nn.noteElements.forEach(ne => {
2085
+ newElement.append(convertToElement(ne, currentMEI));
2086
+ });
2087
+ }
2088
+ newElement.setAttribute("id", nn.id);
2089
+ newElement.setAttribute("dur", nn.dur);
2090
+ newElement.setAttribute("dots", nn.dots);
2091
+ return newElement;
2092
+ }
2093
+ function convertToNewChord(element) {
2094
+ var newNotes = Array.from(element.querySelectorAll("note")).map(n => {
2095
+ return convertToNewNote(n);
2096
+ });
2097
+ var newChord = {
2098
+ id: random_1.uuidv4(),
2099
+ dur: element.getAttribute("dur"),
2100
+ dots: element.getAttribute("dots"),
2101
+ noteElements: newNotes
2102
+ };
2103
+ return newChord;
2104
+ }
2105
+ function createNewRestElement(dur, dots = undefined) {
2106
+ var newElem = document.createElementNS(constants_1.constants._MEINS_, "rest");
2107
+ newElem.setAttribute("dur", dur.toString());
2108
+ if (dots != undefined)
2109
+ newElem.setAttribute("dots", dots.toString());
2110
+ newElem.setAttribute("id", random_1.uuidv4());
2111
+ return newElem;
2112
+ }