vibe-editor 0.0.0 → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +12 -9
  3. package/package.json +11 -5
  4. package/src/scripts/js/Core.js +212 -186
  5. package/src/scripts/js/MusicProcessor.js +286 -128
  6. package/src/scripts/js/{VerovioScoreEditor.js → VIBE.js} +62 -28
  7. package/src/scripts/js/assets/mei_template.js +5 -1
  8. package/src/scripts/js/datastructures/MeasureMatrix.js +6 -85
  9. package/src/scripts/js/datastructures/ScoreGraph.js +1 -1
  10. package/src/scripts/js/entry.js +3 -2
  11. package/src/scripts/js/gui/Annotations.js +188 -111
  12. package/src/scripts/js/gui/HarmonyLabel.js +26 -2
  13. package/src/scripts/js/gui/ScoreManipulator.js +61 -31
  14. package/src/scripts/js/gui/Tabbar.js +41 -21
  15. package/src/scripts/js/gui/Toolbar.js +4 -4
  16. package/src/scripts/js/handlers/AnnotationChangeHandler.js +131 -60
  17. package/src/scripts/js/handlers/ClickModeHandler.js +406 -143
  18. package/src/scripts/js/handlers/CustomToolbarHandler.js +26 -24
  19. package/src/scripts/js/handlers/GlobalKeyboardHandler.js +12 -7
  20. package/src/scripts/js/handlers/InsertModeHandler.js +26 -32
  21. package/src/scripts/js/handlers/KeyModeHandler.js +12 -86
  22. package/src/scripts/js/handlers/LabelHandler.js +3 -2
  23. package/src/scripts/js/handlers/PhantomElementHandler.js +1 -1
  24. package/src/scripts/js/handlers/ScoreManipulatorHandler.js +101 -14
  25. package/src/scripts/js/handlers/SelectionHandler.js +80 -36
  26. package/src/scripts/js/handlers/SideBarHandler.js +10 -3
  27. package/src/scripts/js/handlers/WindowHandler.js +25 -4
  28. package/src/scripts/js/utils/DOMCreator.js +1 -1
  29. package/src/scripts/js/utils/MEIConverter.js +13 -1
  30. package/src/scripts/js/utils/MEIOperations.js +180 -187
  31. package/src/scripts/js/utils/Mouse2SVG.js +200 -43
  32. package/src/scripts/js/utils/ReactWrapper.js +46 -0
  33. package/src/scripts/js/utils/RectWrapper.js +10 -0
  34. package/src/scripts/js/utils/SVGEditor.js +94 -3
  35. package/src/scripts/js/utils/VerovioWrapper.js +6 -1
  36. package/src/scripts/js/utils/convenienceQueries.js +2 -0
  37. package/src/scripts/js/utils/mappings.js +322 -56
  38. package/src/styles/VerovioScoreEditor.css +0 -694
@@ -1,20 +1,22 @@
1
1
  "use strict";
2
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;
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.addLayerForStaff = 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
4
  const meiConverter = require("./MEIConverter");
5
5
  const random_1 = require("./random");
6
6
  const constants_1 = require("../constants");
7
7
  const mappings_1 = require("./mappings");
8
8
  const mei_template_1 = require("../assets/mei_template");
9
9
  const MeasureMatrix_1 = require("../datastructures/MeasureMatrix");
10
+ /**
11
+ * This script is a collection of functions which help to manipulate the underlying MEI, so that it can be renderd anew.
12
+ * E.g.: Add and remove notes, process beams and slurs, cleanup empty elements, etc.
13
+ *
14
+ * Some extract features from the MEI which are not apparent in the MEI itself, like processing ratios and relationsships between notes.
15
+ *
16
+ */
10
17
  const countableNoteUnitSelector = ":scope > *[dur]:not([grace])";
11
18
  const overfillMeasure = false;
12
19
  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
20
  ////// DELETE //////
19
21
  /**
20
22
  * Remove Elements from MEI.
@@ -67,14 +69,7 @@ function removeFromMEI(scoreElements, currentMEI) {
67
69
  }
68
70
  }
69
71
  });
70
- //removeEmptyElements(currentMEI)
71
- // For now: No Shifts (22.07.2021)
72
- // if($(".measure").length > 1){
73
- // checkDeleteShifts(currentMEI);
74
- // }
75
72
  cleanUp(currentMEI);
76
- //fillWithRests(currentMEI)
77
- // Warum ist das ein Problem?
78
73
  currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
79
74
  resolve(currentMEI);
80
75
  });
@@ -161,12 +156,14 @@ exports.getMeterRatioLocal = getMeterRatioLocal;
161
156
  * @returns mei
162
157
  */
163
158
  function addToMEI(newSound, currentMEI, replace = false, scoreGraph = null) {
164
- var _a, _b;
159
+ var _a;
165
160
  //return new Promise<Document>((resolve): void => {
166
161
  var currMeiClone = currentMEI.cloneNode(true);
167
162
  var newElem;
168
163
  var nearestNoteIsSameDurRest = false;
169
164
  if (newSound.hasOwnProperty("pname")) {
165
+ if (!newSound.nearestNoteId)
166
+ return currentMEI;
170
167
  var newNote = newSound;
171
168
  if (newNote.rest) {
172
169
  newElem = currentMEI.createElement("rest");
@@ -264,7 +261,7 @@ function addToMEI(newSound, currentMEI, replace = false, scoreGraph = null) {
264
261
  }
265
262
  }
266
263
  if (replace) {
267
- let ms = Array.from(trueSibling.parentElement.querySelectorAll("note:not(chord note), chord, rest, mRest")); //querySelectorAll(":scope > *")
264
+ let ms = Array.from(trueSibling.parentElement.querySelectorAll("note:not(chord note), chord, rest, mRest"));
268
265
  if (newNote.relPosX === "left") {
269
266
  var measureSiblings = ms.filter((_, i) => i >= ms.indexOf(trueSibling));
270
267
  trueSibling.parentElement.insertBefore(newElem, trueSibling);
@@ -300,8 +297,40 @@ function addToMEI(newSound, currentMEI, replace = false, scoreGraph = null) {
300
297
  var newChord = newSound;
301
298
  newElem = convertToElement(newChord, currentMEI);
302
299
  var nearestElem = currentMEI.getElementById(newChord.nearestNoteId);
303
- if ((nearestElem === null || nearestElem === void 0 ? void 0 : nearestElem.tagName) === "layer") {
304
- nearestElem.insertBefore(newElem, nearestElem.firstChild);
300
+ // if (nearestElem?.tagName === "layer") {
301
+ // nearestElem.insertBefore(newElem, nearestElem.firstChild)
302
+ var sibling = currentMEI.getElementById(newChord.nearestNoteId);
303
+ if (!sibling)
304
+ return;
305
+ var parentLayer = sibling.closest("layer");
306
+ var trueParent = sibling.parentElement;
307
+ var isTrueSibling = parentLayer == trueParent;
308
+ var trueSibling = sibling;
309
+ if (!isTrueSibling) {
310
+ var currParent = trueParent;
311
+ while (!isTrueSibling) {
312
+ trueSibling = currParent;
313
+ currParent = currParent === null || currParent === void 0 ? void 0 : currParent.parentElement;
314
+ isTrueSibling = currParent.tagName === "layer";
315
+ }
316
+ }
317
+ if (replace) {
318
+ let ms = Array.from(trueSibling.parentElement.querySelectorAll("note:not(chord note), chord, rest, mRest"));
319
+ if (newChord.relPosX === "left") {
320
+ var measureSiblings = ms.filter((_, i) => i >= ms.indexOf(trueSibling));
321
+ trueSibling.parentElement.insertBefore(newElem, trueSibling);
322
+ changeDurationsInLayer(currentMEI, measureSiblings, newElem);
323
+ }
324
+ else {
325
+ if (["clef"].every(el => { var _a; return ((_a = trueSibling.nextElementSibling) === null || _a === void 0 ? void 0 : _a.tagName) !== el; }) && trueSibling.nextElementSibling !== null) {
326
+ var measureSiblings = ms.filter((_, i) => i >= ms.indexOf(trueSibling.nextElementSibling));
327
+ trueSibling.parentElement.insertBefore(newElem, trueSibling.nextElementSibling);
328
+ changeDurationsInLayer(currentMEI, measureSiblings, newElem);
329
+ }
330
+ else {
331
+ trueSibling.parentElement.insertBefore(newElem, trueSibling.nextElementSibling);
332
+ }
333
+ }
305
334
  }
306
335
  else if (newChord.relPosX === "left") {
307
336
  nearestElem.parentElement.insertBefore(newElem, currentMEI.getElementById(newChord.nearestNoteId));
@@ -312,11 +341,61 @@ function addToMEI(newSound, currentMEI, replace = false, scoreGraph = null) {
312
341
  }
313
342
  // if measure overfills tie note to next measure
314
343
  var currentLayer = newElem.closest("layer");
344
+ currentMEI = tieToNextMeasure(currentMEI, newElem, currMeiClone, replace, newSound);
345
+ newElem = currentMEI.querySelector("#" + newElem.id);
346
+ fillLayerWithRests(currentLayer, currentMEI);
347
+ //reestablish beams
348
+ beams === null || beams === void 0 ? void 0 : beams.forEach(b => {
349
+ var first;
350
+ var last;
351
+ Array.from(b.children).forEach(bc => {
352
+ var existingChild = currentMEI.querySelector("#" + bc.id);
353
+ if (existingChild !== null) {
354
+ if (first == undefined) {
355
+ first = bc;
356
+ }
357
+ else {
358
+ last = bc;
359
+ }
360
+ }
361
+ else if (!first) {
362
+ first = newElem;
363
+ }
364
+ });
365
+ if (!last) {
366
+ last = newElem;
367
+ }
368
+ if (first && last) {
369
+ var newBeam = currentMEI.createElement("beam");
370
+ newBeam.id = b.id;
371
+ var beamElements = currentMEI.querySelectorAll("#" + first.id + ", #" + first.id + "~ *:not(#" + last.id + "~ *)"); // all elements in between first and last
372
+ beamElements[0].insertAdjacentElement("beforebegin", newBeam);
373
+ beamElements.forEach(be => {
374
+ newBeam.append(be);
375
+ });
376
+ }
377
+ });
378
+ cleanUp(currentMEI);
379
+ adjustAccids(currentMEI);
380
+ currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
381
+ return currentMEI;
382
+ }
383
+ exports.addToMEI = addToMEI;
384
+ /**
385
+ *
386
+ * @param currentMEI MEI to be changed
387
+ * @param newElem Element to tie to next measure
388
+ * @param currMeiClone clone of the original MEI to compute ratios before anything was changed
389
+ * @param replace replace flag, if addToMEI must be called again
390
+ * @param newSound change parameters of newSound if it has to be shifted to the right
391
+ */
392
+ function tieToNextMeasure(currentMEI, newElem, currMeiClone, replace, newSound) {
393
+ var _a;
394
+ var currentLayer = newElem.closest("layer");
315
395
  if (!overfillMeasure) {
316
396
  var newMeasureRatio = getAbsoluteRatio(newElem.closest("layer"));
317
397
  var measureRatio = getMeterRatioLocal(currMeiClone, newElem);
318
398
  if (newMeasureRatio > measureRatio) {
319
- //currentMEI = currMeiClone as Document
320
399
  // Decide if next measure should be created and what should be added
321
400
  var lastElement = Array.from(currentLayer.querySelectorAll(":scope > :is(note, chord)")).reverse()[0];
322
401
  var lastElementRatio = getAbsoluteRatio(lastElement);
@@ -345,54 +424,19 @@ function addToMEI(newSound, currentMEI, replace = false, scoreGraph = null) {
345
424
  if (currentLayer.closest("measure").nextElementSibling === null) { // add measure if there is none to extend into
346
425
  addMeasure(currentMEI);
347
426
  }
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);
427
+ if (newSound) {
428
+ var cl = currentMEI.getElementById(currentLayer.id);
429
+ newSound.nearestNoteId = (_a = cl.closest("measure").nextElementSibling.querySelector("staff[n='" + cl.closest("staff").getAttribute("n") + "'] layer[n='" + cl.getAttribute("n") + "'] :is(chord, note, rest, mRest)")) === null || _a === void 0 ? void 0 : _a.id;
430
+ newSound.relPosX = "left";
431
+ if (newSound.nearestNoteId !== null) {
432
+ currentMEI = addToMEI(newSound, currentMEI, replace);
433
+ }
353
434
  }
354
435
  }
355
436
  }
356
437
  }
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
438
  return currentMEI;
394
439
  }
395
- exports.addToMEI = addToMEI;
396
440
  /**
397
441
  * Check if notes have to be shifted after insertion
398
442
  * @param currentMEI
@@ -1155,105 +1199,6 @@ function replaceWithRest(element, currentMEI) {
1155
1199
  elmei.parentElement.insertBefore(newRest, elmei);
1156
1200
  elmei.remove();
1157
1201
  }
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
1202
  function addRatios(elements) {
1258
1203
  var r = 0;
1259
1204
  elements.forEach((v, i) => {
@@ -1291,11 +1236,6 @@ function changeDurationsInLayer(currentMEI, additionalElements = new Array(), re
1291
1236
  if (remainRatio < nnRatio) {
1292
1237
  var diffRatio = nnRatio - remainRatio;
1293
1238
  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
1239
  changeDur(nextNoteMEI, diffRatio);
1300
1240
  harm = currentMEI.querySelector('harm[startid="' + nextNote.id + '"]');
1301
1241
  if (harm !== null) {
@@ -1323,6 +1263,9 @@ function changeDurationsInLayer(currentMEI, additionalElements = new Array(), re
1323
1263
  changeDurationsInLayer(currentMEI, additionalElements, refElement, remainRatio, meiCopy);
1324
1264
  }
1325
1265
  }
1266
+ else {
1267
+ currentMEI = tieToNextMeasure(currentMEI, refElement, currentMEI.cloneNode(true), true, null);
1268
+ }
1326
1269
  cleanUp(currentMEI);
1327
1270
  return currentMEI;
1328
1271
  }
@@ -1369,6 +1312,7 @@ function cleanUp(currentMEI) {
1369
1312
  removeEmptyElements(currentMEI);
1370
1313
  adjustRests(currentMEI);
1371
1314
  redistributeHarms(currentMEI);
1315
+ reformatBreve(currentMEI);
1372
1316
  }
1373
1317
  exports.cleanUp = cleanUp;
1374
1318
  /**
@@ -1591,6 +1535,9 @@ function removeTiesFromDoc(currentMEI) {
1591
1535
  }
1592
1536
  });
1593
1537
  }
1538
+ function reformatBreve(currentMEI) {
1539
+ currentMEI.querySelectorAll("[dur='0.5']").forEach(d => d.setAttribute("dur", "breve"));
1540
+ }
1594
1541
  function addMeasure(currentMEI) {
1595
1542
  var lastMeasure = Array.from(currentMEI.querySelectorAll("measure")).reverse()[0];
1596
1543
  var staffCounts = Array.from(lastMeasure.querySelectorAll("staff")).map(s => { return parseInt(s.getAttribute("n")); });
@@ -1633,6 +1580,7 @@ function addStaff(currentMEI, referenceStaff, relPos) {
1633
1580
  var refElement;
1634
1581
  currentMEI.querySelectorAll("staff[n=\"" + staffNum + "\"]").forEach(s => {
1635
1582
  var _a;
1583
+ var layers = s.querySelectorAll("layer");
1636
1584
  var newStaff = new mei_template_1.default().createStaff(1, 1);
1637
1585
  switch (relPos) {
1638
1586
  case "above":
@@ -1653,7 +1601,7 @@ function addStaff(currentMEI, referenceStaff, relPos) {
1653
1601
  //copy elements from the current Staff that have to appear in new staff
1654
1602
  var newLayer = newStaff.querySelector("layer");
1655
1603
  var copyMeter = (_a = s.querySelector("meterSig")) === null || _a === void 0 ? void 0 : _a.cloneNode(true);
1656
- if (copyMeter != undefined && copyMeter !== null) {
1604
+ if (copyMeter) {
1657
1605
  newLayer.insertBefore(copyMeter, newLayer.firstChild);
1658
1606
  }
1659
1607
  refn = (refElement === null || refElement === void 0 ? void 0 : refElement.getAttribute("n")) || staffNum; // s.getAttribute("n")
@@ -1714,6 +1662,12 @@ function removeStaff(currentMEI, referenceStaff, relPos) {
1714
1662
  cleanUp(currentMEI);
1715
1663
  }
1716
1664
  exports.removeStaff = removeStaff;
1665
+ function addLayerForStaff(currentMEI, staffN, layerN) {
1666
+ currentMEI.querySelectorAll(`staff[n='${staffN}']`).forEach(staff => {
1667
+ staff.append(new mei_template_1.default().createLayer(layerN));
1668
+ });
1669
+ }
1670
+ exports.addLayerForStaff = addLayerForStaff;
1717
1671
  /**
1718
1672
  * Create a tuplet out of given Elements.
1719
1673
  * Tuplet duration and kind will be derived from number and attributes of the given notes.
@@ -1765,10 +1719,10 @@ exports.createTuplet = createTuplet;
1765
1719
  * Paste copied ids. First position to which the Elements are copied is the Element according to the refId (= RefElement).
1766
1720
  * If multiple staffs are copied, overhanging staffs will be pasted to the staffs below the staff of the RefElement, if definedstaffs exist.
1767
1721
  * Else these copiedId will be not pasted.
1768
- * @param ids
1769
- * @param refId
1722
+ * @param ids Array of Element IDs to be pasted
1723
+ * @param pastePosition
1770
1724
  */
1771
- function paste(ids, refId, currentMEI) {
1725
+ function paste(ids, pastePosition, currentMEI) {
1772
1726
  var _a;
1773
1727
  //ordered by staff
1774
1728
  var meiElements = new Array();
@@ -1788,36 +1742,36 @@ function paste(ids, refId, currentMEI) {
1788
1742
  }
1789
1743
  }
1790
1744
  });
1791
- var refElement = currentMEI.getElementById(refId);
1745
+ var refElement = currentMEI.getElementById(pastePosition);
1792
1746
  refElement = (refElement === null || refElement === void 0 ? void 0 : refElement.closest("chord")) || refElement;
1793
1747
  var refStaff = refElement === null || refElement === void 0 ? void 0 : refElement.closest("staff");
1794
1748
  var refLayer = refElement === null || refElement === void 0 ? void 0 : refElement.closest("layer");
1795
1749
  var refMeasure = refElement === null || refElement === void 0 ? void 0 : refElement.closest("measure");
1796
1750
  var currentMeasure;
1797
- let anyNew;
1751
+ var anyNew;
1798
1752
  //console.log(...meiElements)
1799
1753
  meiElements.forEach((staff, staffIdx) => {
1800
1754
  var _a, _b, _c, _d, _e, _f, _g;
1801
- if (refElement === null)
1755
+ if (!refElement)
1802
1756
  return;
1803
1757
  currentMeasure = refElement.closest("measure");
1804
1758
  staff.forEach((element, elementIdx) => {
1805
1759
  var _a, _b;
1806
1760
  if (["NOTE", "REST"].includes(element.tagName.toUpperCase())) {
1807
- var newNote = convertToNewNote(element);
1761
+ const newNote = convertToNewNote(element);
1808
1762
  newNote.nearestNoteId = refElement.id;
1809
- newNote.relPosX = "right";
1763
+ newNote.relPosX = elementIdx === 0 ? "left" : "right"; // make sure to replace the element on the pasteposition
1810
1764
  anyNew = newNote;
1811
1765
  }
1812
1766
  else if (element.tagName.toUpperCase() === "CHORD") {
1813
- var newChord = convertToNewChord(element);
1767
+ const newChord = convertToNewChord(element);
1814
1768
  newChord.nearestNoteId = refElement.id;
1815
- newChord.relPosX = "right";
1769
+ newChord.relPosX = elementIdx === 0 ? "left" : "right"; // make sure to replace the element on the pasteposition
1816
1770
  anyNew = newChord;
1817
1771
  var elementArr = Array.from(element.querySelectorAll("note"));
1818
1772
  }
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);
1773
+ const replace = ((_b = (_a = document.querySelector(".activeContainer")) === null || _a === void 0 ? void 0 : _a.querySelector("#insertToggle")) === null || _b === void 0 ? void 0 : _b.checked) || true;
1774
+ currentMEI = addToMEI(anyNew, meiConverter.cleanIdAttr(currentMEI), replace);
1821
1775
  refElement = convertToElement(anyNew, currentMEI); //element
1822
1776
  });
1823
1777
  //when changing next staff, refElement musst be staff + 1
@@ -1827,10 +1781,10 @@ function paste(ids, refId, currentMEI) {
1827
1781
  refElement = currentMEI.querySelector("measure[n=\"" + refMeasureN + "\"] > staff[n=\"" + targetStaffN + "\"] > layer[n=\"" + refLayerN + "\"]");
1828
1782
  });
1829
1783
  //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);
1784
+ if (!document.querySelector(".activeContainer").classList.contains("textmode") && ((_a = currentMEI.getElementById(pastePosition)) === null || _a === void 0 ? void 0 : _a.tagName) !== "LAYER") {
1785
+ removeFromMEI([currentMEI.getElementById(pastePosition)], currentMEI);
1832
1786
  }
1833
- return anyNew === null || anyNew === void 0 ? void 0 : anyNew.id;
1787
+ return [currentMEI, anyNew === null || anyNew === void 0 ? void 0 : anyNew.id];
1834
1788
  }
1835
1789
  exports.paste = paste;
1836
1790
  /**
@@ -1841,10 +1795,39 @@ exports.paste = paste;
1841
1795
  * @returns
1842
1796
  */
1843
1797
  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)));
1798
+ const staffN = document.querySelector(".activeContainer #vrvSVG #" + target.id).closest(".staff").getAttribute("n");
1799
+ const staffDefClef = currentMEI.querySelector("staffDef[n=\"" + staffN + "\"] > clef");
1800
+ const shape = newClef.charAt(0);
1801
+ var line = mappings_1.clefToLine.get(newClef.charAt(0));
1802
+ if (shape === "C") { // get line depending on id of the cclef
1803
+ line = mappings_1.clefToLine.get(newClef.match(/CClef(.*)/)[1]);
1804
+ }
1805
+ const disPlace = newClef.includes("OctDown") ? "below" : newClef.includes("OctUp") ? "above" : null;
1806
+ if (staffDefClef) {
1807
+ staffDefClef.setAttribute("shape", shape);
1808
+ staffDefClef.setAttribute("line", line);
1809
+ if (disPlace) {
1810
+ staffDefClef.setAttribute("dis", "8");
1811
+ staffDefClef.setAttribute("dis.place", disPlace);
1812
+ }
1813
+ else {
1814
+ staffDefClef.removeAttribute("dis");
1815
+ staffDefClef.removeAttribute("dis.place");
1816
+ }
1817
+ }
1818
+ else {
1819
+ const staffDef = currentMEI.querySelector("staffDef[n=\"" + staffN + "\"]");
1820
+ staffDef === null || staffDef === void 0 ? void 0 : staffDef.setAttribute("clef.shape", shape);
1821
+ staffDef === null || staffDef === void 0 ? void 0 : staffDef.setAttribute("clef.line", line);
1822
+ if (disPlace) {
1823
+ staffDef === null || staffDef === void 0 ? void 0 : staffDef.setAttribute("clef.dis", "8");
1824
+ staffDef === null || staffDef === void 0 ? void 0 : staffDef.setAttribute("clef.dis.place", disPlace);
1825
+ }
1826
+ else {
1827
+ staffDef === null || staffDef === void 0 ? void 0 : staffDef.removeAttribute("clef.dis");
1828
+ staffDef === null || staffDef === void 0 ? void 0 : staffDef.removeAttribute("clef.dis.place");
1829
+ }
1830
+ }
1848
1831
  cleanUp(currentMEI);
1849
1832
  currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
1850
1833
  return currentMEI;
@@ -1860,10 +1843,20 @@ function insertClef(target, newClef, currentMEI) {
1860
1843
  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
1844
  var targetLayerId = currentMEI.getElementById(targetStaffId).querySelector("layer").id;
1862
1845
  currentMEI.getElementById(targetLayerId).querySelectorAll("clef").forEach(c => c.remove());
1846
+ const shape = newClef.charAt(0);
1847
+ var line = mappings_1.clefToLine.get(newClef.charAt(0));
1848
+ if (shape === "C") { // get line depending on id of the cclef
1849
+ line = mappings_1.clefToLine.get(newClef.match(/CClef(.*)/)[1]);
1850
+ }
1851
+ var disPlace = newClef.includes("OctDown") ? "below" : newClef.includes("OctUp") ? "above" : null;
1863
1852
  var clefElement = currentMEI.createElement("clef");
1864
1853
  clefElement.setAttribute("id", random_1.uuidv4());
1865
- clefElement.setAttribute("shape", newClef.charAt(0));
1866
- clefElement.setAttribute("line", mappings_1.clefToLine.get(newClef.charAt(0)));
1854
+ clefElement.setAttribute("shape", shape);
1855
+ clefElement.setAttribute("line", line);
1856
+ if (disPlace) {
1857
+ clefElement.setAttribute("dis", "8");
1858
+ clefElement.setAttribute("dis.place", disPlace);
1859
+ }
1867
1860
  currentMEI.getElementById(targetLayerId).append(clefElement);
1868
1861
  cleanUp(currentMEI);
1869
1862
  currentMEI = meiConverter.restoreXmlIdTags(currentMEI);
@@ -2019,7 +2012,7 @@ function getTimestamp(note) {
2019
2012
  var layer = note.closest("layer");
2020
2013
  var elements = Array.from(layer.querySelectorAll("*[dur]"));
2021
2014
  elements = elements.filter((v, i) => i <= elements.indexOf(note));
2022
- var tstamp;
2015
+ var tstamp = 0;
2023
2016
  elements.forEach(e => {
2024
2017
  var dur = parseInt(e.getAttribute("dur"));
2025
2018
  tstamp += 4 / dur;