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,652 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const Tone = require("tone");
4
+ const mappings_1 = require("./utils/mappings");
5
+ const midi_player_js_1 = require("midi-player-js");
6
+ const Soundfont = require("soundfont-player");
7
+ const constants_1 = require("./constants");
8
+ const coordinates = require("./utils/coordinates");
9
+ const cq = require("./utils/convenienceQueries");
10
+ const meiConverter = require("./utils/MEIConverter");
11
+ const buffer_1 = require("buffer");
12
+ const axios_1 = require("axios");
13
+ const currentlyPlayingFlag = "currentlyPlaying";
14
+ const followerRectID = "followerRect";
15
+ const ac = window.AudioContext;
16
+ const synth = new Tone.Synth().toDestination();
17
+ class MusicProcessor {
18
+ constructor(containerId) {
19
+ this.playBtn = (function playBtn(e) {
20
+ e.preventDefault();
21
+ this.context.resume().then(() => this.playMidi());
22
+ }).bind(this);
23
+ this.rewindBtn = (function rewindBtn(e) {
24
+ e.preventDefault();
25
+ this.rewindMidi();
26
+ }).bind(this);
27
+ this.fetchAudioSeconds = (function fetchAudioSeconds(e) {
28
+ var sec = e.target.currentTime;
29
+ this.highlight(sec, 100, "audio");
30
+ this.drawFollowerRect();
31
+ }).bind(this);
32
+ this.midiPlayHandler = (function midiPlayHandler(e) {
33
+ if (!this.hasContainerFocus())
34
+ return;
35
+ this.midiPlayFunction(e);
36
+ }).bind(this);
37
+ this.setCurrentNoteHandler = (function setCurrentNoteHandler(e) {
38
+ this.currentNote = e.target;
39
+ }).bind(this);
40
+ /**
41
+ * Set last clicked element to restartpoint
42
+ */
43
+ this.startPointHandler = (function startPointHandler(e) {
44
+ if (!this.hasContainerFocus())
45
+ return;
46
+ var playingNote = e.target;
47
+ playingNote = cq.getVrvSVG(this.containerId).querySelector("#" + playingNote.closest("[refId]").getAttribute("refId"));
48
+ playingNote = playingNote.closest(".note") || playingNote.closest(".rest") || playingNote.closest(".mRest");
49
+ if (playingNote !== null) {
50
+ var it = this.durationMap.values();
51
+ var res = it.next();
52
+ while (!res.done) {
53
+ if (playingNote.id === res.value.note.id) {
54
+ this.restartTime = res.value.tick;
55
+ break;
56
+ }
57
+ res = it.next();
58
+ }
59
+ }
60
+ }).bind(this);
61
+ /**
62
+ * Adds Class to be highlighted.
63
+ * Dispatches event for every Note which was started most currently
64
+ */
65
+ this.addClass = (function addClass(n, className) {
66
+ return new Promise(resolve => {
67
+ n.classList.add(className);
68
+ n.dispatchEvent(this.noteEvent);
69
+ resolve(true);
70
+ });
71
+ }).bind(this);
72
+ this.setContainerId(containerId);
73
+ this.noteEvent = new Event("currentNote");
74
+ this.playStartEvent = new Event("playStart");
75
+ this.playEndEvent = new Event("playEnd");
76
+ this.restartTime = 0;
77
+ this.setPlayListener();
78
+ if (navigator.userAgent.toLocaleLowerCase().indexOf("firefox") > 0) {
79
+ this.isFirefox = true;
80
+ }
81
+ else {
82
+ this.isFirefox = false;
83
+ }
84
+ this.getMidiInput();
85
+ }
86
+ /**
87
+ * Add Canvas in which all MusicPlayer SVGs are contained
88
+ */
89
+ addCanvas() {
90
+ //this.root = this.interactionOverlay //document.getElementById(c._vrvSVGID_)
91
+ this.rootBBox = this.interactionOverlay.getBoundingClientRect();
92
+ var rootWidth = this.rootBBox.width.toString();
93
+ var rootHeigth = this.rootBBox.height.toString();
94
+ if (this.canvasMP == undefined) {
95
+ this.canvasMP = document.createElementNS(constants_1.constants._SVGNS_, "svg");
96
+ this.canvasMP.setAttribute("id", "canvasMusicPlayer");
97
+ this.canvasMP.classList.add("canvas");
98
+ this.canvasMP.setAttribute("viewBox", ["0", "0", rootWidth, rootHeigth].join(" "));
99
+ }
100
+ this.canvasMP.innerHTML = ""; // will delete followerRect if present (usually when score is loaded)
101
+ this.interactionOverlay = cq.getInteractOverlay(this.containerId);
102
+ this.interactionOverlay.insertBefore(this.canvasMP, this.interactionOverlay.firstChild);
103
+ }
104
+ /**
105
+ * Initialize Player
106
+ */
107
+ initMidiPlayer() {
108
+ var that = this;
109
+ //@ts-ignore
110
+ this.midiPlayer = new midi_player_js_1.default.Player(function (event) {
111
+ if (event.name === "Set Tempo") {
112
+ that.tempo = event.data;
113
+ //that.pulse = (60000/ (event.data / 2 * 24))/10 //(60000/ (event.data * 24))/10000 //duration is in seconds
114
+ that.pulse = ((60 / event.data) * 1000) / 120;
115
+ }
116
+ if (event.name === 'Note on' && event.velocity !== 0) {
117
+ var track = event.track;
118
+ var time = event.tick;
119
+ var key = track.toString() + "," + event.byteIndex.toString();
120
+ if (!that.midiDurationMap.has(key)) {
121
+ return;
122
+ }
123
+ var duration = that.midiDurationMap.get(key).duration;
124
+ that.restartTime = event.tick;
125
+ that.highlight(time, duration * 1000, "midi");
126
+ if (!that.isFirefox) {
127
+ that.drawFollowerRect();
128
+ }
129
+ if (that.instruments != undefined) {
130
+ var instr = that.instruments[track - 2];
131
+ instr.play(event.noteName, that.context.currentTime, { gain: event.velocity / 100, duration: duration });
132
+ }
133
+ }
134
+ });
135
+ this.midiPlayer.loadArrayBuffer(buffer_1.Buffer.from(this.midi, "base64"));
136
+ this.mapDurations();
137
+ if (this.instruments == undefined) { // instruments only have to be updated, when new instrument (= track) is added
138
+ this.context = new ac();
139
+ this.instruments = new Array(this.midiPlayer.getEvents().length - 1);
140
+ this.initMidiInstruments();
141
+ }
142
+ }
143
+ //some change
144
+ /**
145
+ * Stop playing
146
+ */
147
+ stopMidiInstruments() {
148
+ var _a;
149
+ document.dispatchEvent(this.playEndEvent);
150
+ this.midiPlayer.stop();
151
+ (_a = this.instruments) === null || _a === void 0 ? void 0 : _a.forEach(instr => instr.stop(this.context.currentTime));
152
+ this.midiPlayer = undefined;
153
+ this.stopTimeouts();
154
+ if (this.restartTime === 0) {
155
+ if (document.getElementById(followerRectID) !== null) {
156
+ document.getElementById(followerRectID).remove();
157
+ }
158
+ Array.from(document.getElementsByClassName(currentlyPlayingFlag)).forEach(element => {
159
+ element.classList.remove(currentlyPlayingFlag);
160
+ });
161
+ }
162
+ this.initMidiPlayer();
163
+ }
164
+ rewindMidi() {
165
+ if (this.midiPlayer != undefined) {
166
+ this.restartTime = 0;
167
+ this.stopMidiInstruments();
168
+ }
169
+ }
170
+ /**
171
+ * Initialize Instrument for
172
+ */
173
+ initMidiInstruments() {
174
+ this.setSoundfontsRecursive();
175
+ }
176
+ setSoundfontsRecursive(counter = 0) {
177
+ var i = counter;
178
+ var that = this;
179
+ if (i < this.instruments.length) {
180
+ Soundfont.instrument(this.context, "acoustic_grand_piano").then((instrument) => {
181
+ that.instruments[i] = instrument;
182
+ i += 1;
183
+ that.setSoundfontsRecursive(i);
184
+ });
185
+ }
186
+ }
187
+ playMidi() {
188
+ if (!cq.hasActiveElement(this.containerId))
189
+ return;
190
+ if (this.midiPlayer.isPlaying()) {
191
+ this.stopMidiInstruments();
192
+ }
193
+ else {
194
+ this.midiPlayer.on("endOfFile", () => {
195
+ this.rewindMidi();
196
+ });
197
+ this.midiPlayer.division = 120;
198
+ //this.player.tempo = this.tempo
199
+ this.midiPlayer.tick = this.restartTime;
200
+ this.midiPlayer.skipToTick(this.restartTime);
201
+ this.midiPlayer.play();
202
+ document.dispatchEvent(this.playStartEvent);
203
+ }
204
+ }
205
+ ///// LISTENERS ////
206
+ setListeners() {
207
+ var that = this;
208
+ if (this.midiTimes == undefined) {
209
+ return;
210
+ }
211
+ var it = this.midiTimes.values();
212
+ var result = it.next();
213
+ while (!result.done) {
214
+ var arr = result.value;
215
+ arr.forEach(note => {
216
+ var _a;
217
+ if (note == undefined)
218
+ return;
219
+ note.addEventListener("currentNote", this.setCurrentNoteHandler);
220
+ var id = ((_a = note.querySelector(".notehead")) === null || _a === void 0 ? void 0 : _a.id) || note.id;
221
+ var interactRect = cq.getInteractOverlay(that.containerId).querySelector("#scoreRects g[refId=\"" + id + "\"]");
222
+ interactRect.addEventListener("click", this.startPointHandler);
223
+ });
224
+ result = it.next();
225
+ }
226
+ this.container.querySelector("#playBtn").addEventListener("click", this.playBtn);
227
+ this.container.querySelector("#rewindBtn").addEventListener("click", this.rewindBtn);
228
+ this.container.addEventListener("timeupdate", this.fetchAudioSeconds, true);
229
+ }
230
+ removeListeners() {
231
+ var that = this;
232
+ if (this.midiTimes == undefined) {
233
+ return;
234
+ }
235
+ var it = this.midiTimes.values();
236
+ console.log("midiTimes", this.midiTimes);
237
+ var result = it.next();
238
+ while (!result.done) {
239
+ var arr = result.value;
240
+ arr.forEach(note => {
241
+ var _a;
242
+ note.removeEventListener("currentNote", this.setCurrentNoteHandler);
243
+ var id = ((_a = note.querySelector(".notehead")) === null || _a === void 0 ? void 0 : _a.id) || note.id;
244
+ var interactRect = cq.getInteractOverlay(that.containerId).querySelector("#scoreRects g[refId=\"" + id + "\"]");
245
+ interactRect.removeEventListener("click", this.startPointHandler);
246
+ });
247
+ result = it.next();
248
+ }
249
+ this.container.removeEventListener("timeupdate", this.fetchAudioSeconds, true);
250
+ }
251
+ resetListeners() {
252
+ this.removeListeners();
253
+ this.setListeners();
254
+ }
255
+ /**
256
+ * Separate Listeners to set player options externally
257
+ */
258
+ setPlayListener() {
259
+ document.addEventListener("keydown", this.midiPlayHandler);
260
+ }
261
+ removePlayListener() {
262
+ document.removeEventListener("keydown", this.midiPlayHandler);
263
+ }
264
+ midiPlayFunction(e) {
265
+ if (!this.hasContainerFocus())
266
+ return;
267
+ if (e.code === "Space") {
268
+ e.preventDefault();
269
+ if (e.shiftKey || document.getElementById("followerRect") !== null) {
270
+ this.context.resume().then(() => this.playMidi());
271
+ }
272
+ else if (typeof this.midiPlayer != undefined) {
273
+ this.stopMidiInstruments();
274
+ }
275
+ }
276
+ }
277
+ /**
278
+ * Call score tube alignment service and map the cursor to notes.
279
+ * @param file Bufferarray of imported file (Blob)
280
+ */
281
+ align(file) {
282
+ var that = this;
283
+ var fd = new FormData();
284
+ fd.append('mei', new Blob([meiConverter.docToMei(this.mei)]));
285
+ fd.append('audio', file);
286
+ console.log("in musicprocessor", this.mei, file);
287
+ var devUrl = 'http://localhost:8001/align';
288
+ axios_1.default.post(devUrl, fd, {
289
+ headers: {
290
+ 'Content-Type': 'multipart/form-data',
291
+ },
292
+ }).then((response) => {
293
+ var data = response.data;
294
+ that.audioTimes = new Map();
295
+ for (const [key, value] of Object.entries(data)) {
296
+ var val = value;
297
+ if (!that.audioTimes.has(val)) {
298
+ that.audioTimes.set(val, new Array());
299
+ }
300
+ that.audioTimes.get(val).push(that.container.querySelector("#" + key));
301
+ }
302
+ }).catch((error) => {
303
+ console.log(["An error occured while aligning the soundfile:", error].join(" "));
304
+ });
305
+ }
306
+ /**
307
+ * Map all durations and notes to make them available asynchronically
308
+ */
309
+ mapDurations() {
310
+ var durationMap = new Map(); // key: tracknumber,byteindex
311
+ var mapByNote = new Map();
312
+ var eventTracks = this.midiPlayer.getEvents();
313
+ eventTracks.forEach(eventArray => {
314
+ //@ts-ignore
315
+ Array.from(eventArray).forEach((event, eventIdx) => {
316
+ var e = event;
317
+ if (e.name === "Set Tempo") {
318
+ this.tempo = e.data;
319
+ this.pulse = ((60 / e.data) * 1000) / 120;
320
+ }
321
+ else if (e.name === "Note on") {
322
+ var time = e.tick; //* this.pulse //* 1000 * 2
323
+ var notes = this.getClosestEntry(time, "midi");
324
+ if (notes == undefined) {
325
+ return;
326
+ }
327
+ //iterate because notes can be in a chord
328
+ notes.forEach(note => {
329
+ var meiNote = this.mei.getElementById(note.id);
330
+ var staffNumber = parseInt(meiNote.closest("staff").getAttribute("n")) + 1;
331
+ if (!meiNote.hasAttribute("grace")) {
332
+ var key = e.track.toString() + "," + e.byteIndex.toString();
333
+ if (!durationMap.has(key) && e.track === staffNumber) {
334
+ if (!meiNote.hasAttribute("dur")) {
335
+ meiNote = meiNote.closest("chord");
336
+ }
337
+ var baseDur = this.getDur(parseInt(meiNote.getAttribute("dur")), parseInt(meiNote.getAttribute("dots")) || 0, 4);
338
+ //find any prolongated Notes
339
+ var tie = this.mei.querySelector("tie[startid='#" + note.id + "']");
340
+ if (tie !== null) {
341
+ var endid = tie.getAttribute("endid"); //endid alway includes # at beginnig
342
+ var prolongNote = this.mei.querySelector(endid);
343
+ if (prolongNote !== null) {
344
+ var pnDur = prolongNote.getAttribute("dur");
345
+ var pnDot = prolongNote.getAttribute("dots");
346
+ baseDur += this.getDur(parseInt(pnDur), parseInt(pnDot) || 0, 4);
347
+ }
348
+ }
349
+ //concat duration
350
+ var dur = baseDur * 60 / this.tempo;
351
+ var valueFound = false;
352
+ var it = durationMap.values();
353
+ var res = it.next();
354
+ if (!valueFound) { // why do I check here?
355
+ durationMap.set(key, { note: note, duration: dur, tick: e.tick });
356
+ mapByNote.set(note, { duration: dur, tick: e.tick });
357
+ }
358
+ else {
359
+ //console.log(key, note, dur, e.tick)
360
+ //console.log(durationMap.get(key))
361
+ }
362
+ }
363
+ }
364
+ });
365
+ }
366
+ });
367
+ });
368
+ this.midiDurationMap = durationMap;
369
+ this.durationMapByNote = mapByNote;
370
+ //console.log(this.durationMap, this.durationMapByNote)
371
+ }
372
+ /**
373
+ * Computation of time and midi times have some divergence (by floating number)
374
+ * Finding closest entry is sufficient, but has to be made for all entries, since the miditimes-iterator is not ordered.
375
+ * @param time
376
+ * @returns
377
+ */
378
+ getClosestEntry(time, source) {
379
+ var targetEntry;
380
+ var temp = Infinity;
381
+ var entries;
382
+ if (source === "midi") {
383
+ entries = this.midiTimes.entries();
384
+ }
385
+ else if (source === "audio") {
386
+ entries = this.audioTimes.entries();
387
+ }
388
+ for (const [key, value] of entries) {
389
+ var diff = Math.abs(time - key);
390
+ if (diff < temp) {
391
+ targetEntry = value;
392
+ temp = diff;
393
+ }
394
+ }
395
+ return targetEntry;
396
+ }
397
+ getDur(dur, dots, base) {
398
+ var baseDur = base / dur;
399
+ var add = baseDur;
400
+ if (dots > 0) {
401
+ for (var i = 0; i < dots; i++) {
402
+ add = add / 2;
403
+ baseDur += add;
404
+ }
405
+ }
406
+ return baseDur;
407
+ }
408
+ setAudioContext() {
409
+ var that = this;
410
+ return new Promise((resolve, reject) => {
411
+ window.onload = function () {
412
+ resolve();
413
+ };
414
+ });
415
+ }
416
+ setMidi(midi) {
417
+ this.midi = midi;
418
+ return this;
419
+ }
420
+ /**
421
+ * Highlight playing Elements
422
+ * @param time Time at which Element is played (in ms)
423
+ * @param duration Duration of Element (in ms)
424
+ */
425
+ highlight(time, duration, source) {
426
+ var notes = this.getClosestEntry(time, source);
427
+ this.timeouts = new Array();
428
+ notes.forEach(n => {
429
+ this.addClass(n, currentlyPlayingFlag).then(() => {
430
+ if (source === "audio") { //we have no proper duration display yet, so no red coloring for notes, just the followerRect
431
+ n.classList.remove(currentlyPlayingFlag);
432
+ return;
433
+ }
434
+ var to = setTimeout(() => { n.classList.remove(currentlyPlayingFlag); }, duration);
435
+ this.timeouts.push(to);
436
+ });
437
+ });
438
+ }
439
+ /**
440
+ * Draw follower rectangle over all staves for last sounding element
441
+ */
442
+ drawFollowerRect() {
443
+ // var canvas = document.getElementById(this.containerId).querySelector("#canvasMusicPlayer") //document.getElementById("canvasMusicPlayer")
444
+ // var canvasBBox = canvas.getBoundingClientRect();
445
+ var followerRect;
446
+ if (document.getElementById(followerRectID) !== null) {
447
+ followerRect = document.getElementById(followerRectID);
448
+ }
449
+ else {
450
+ followerRect = document.createElementNS(constants_1.constants._SVGNS_, "rect");
451
+ this.canvasMP.appendChild(followerRect);
452
+ }
453
+ var margin = 5;
454
+ var ptCurrentNote = coordinates.getDOMMatrixCoordinates(this.currentNote, this.canvasMP);
455
+ var parentMeasureRect = this.currentNote.closest(".measure").getBoundingClientRect();
456
+ var ptParentMeasure = coordinates.getDOMMatrixCoordinates(parentMeasureRect, this.canvasMP);
457
+ var upperBound = (ptParentMeasure.top - margin);
458
+ var lowerBound = (ptParentMeasure.bottom + margin);
459
+ var leftBound = (ptCurrentNote.left - margin);
460
+ var rightBound = (ptCurrentNote.right + margin);
461
+ followerRect.setAttribute("id", followerRectID);
462
+ followerRect.setAttribute("y", upperBound.toString());
463
+ followerRect.setAttribute("x", leftBound.toString());
464
+ followerRect.setAttribute("width", (rightBound - leftBound).toString());
465
+ followerRect.setAttribute("height", (lowerBound - upperBound).toString());
466
+ }
467
+ hasContainerFocus() {
468
+ return document.getElementById(this.containerId).classList.contains("activeContainer");
469
+ }
470
+ ///SYNTH////
471
+ generateTone(newNote) {
472
+ if (newNote.rest) {
473
+ return;
474
+ }
475
+ let note = newNote.pname;
476
+ let dur = newNote.dur + "n";
477
+ var accid = newNote.accid != undefined ? newNote.accid.replace("f", "b").replace("s", "#").replace("n", "") : "";
478
+ if (typeof newNote.keysig !== "undefined" && newNote.keysig !== "0") {
479
+ let signMap;
480
+ if (newNote.keysig.charAt(1) === "s") {
481
+ signMap = mappings_1.noteToCross;
482
+ }
483
+ else if (newNote.keysig.charAt(1) === "f") {
484
+ signMap = mappings_1.noteToB;
485
+ }
486
+ let signCount = parseInt(newNote.keysig.charAt(0));
487
+ let submap = new Map();
488
+ let i = 0;
489
+ for (const [key, value] of signMap.entries()) {
490
+ if (i < signCount) {
491
+ submap.set(key, value);
492
+ }
493
+ i += 1;
494
+ }
495
+ if (submap.has(note)) {
496
+ note = submap.get(note);
497
+ note = note.charAt(0).toUpperCase() + note.charAt(1).toUpperCase() + newNote.oct;
498
+ }
499
+ else {
500
+ note = note.toUpperCase() + accid + newNote.oct;
501
+ }
502
+ }
503
+ else {
504
+ note = note.toUpperCase() + accid + newNote.oct;
505
+ }
506
+ if (!note.includes("undefined") && !dur.includes("undefined")) {
507
+ dur = "16n";
508
+ synth.triggerAttackRelease(note, dur);
509
+ Tone.start();
510
+ }
511
+ }
512
+ // UTILS
513
+ setMEI(mei) {
514
+ this.mei = mei;
515
+ return this;
516
+ }
517
+ setMidiTimes(midiTimes) {
518
+ this.midiTimes = midiTimes;
519
+ return this;
520
+ }
521
+ setScoreGraph(scoreGraph) {
522
+ this.scoreGraph = scoreGraph;
523
+ return this;
524
+ }
525
+ stopTimeouts() {
526
+ if (typeof this.timeouts !== "undefined") {
527
+ this.timeouts.forEach(to => {
528
+ clearTimeout(to);
529
+ });
530
+ }
531
+ }
532
+ setContainerId(containerId) {
533
+ this.containerId = containerId;
534
+ this.interactionOverlay = cq.getInteractOverlay(containerId);
535
+ this.vrvSVG = cq.getVrvSVG(containerId);
536
+ this.container = document.getElementById(containerId);
537
+ return this;
538
+ }
539
+ resetMidiInstruments() {
540
+ this.instruments = undefined;
541
+ }
542
+ getRestartTime() {
543
+ return this.restartTime;
544
+ }
545
+ setRestartTimeBySeconds(time) {
546
+ return this.restartTime = time;
547
+ }
548
+ setRestartTimeByElement(el) {
549
+ throw Error("Not yet implemented");
550
+ }
551
+ getIsPlaying() {
552
+ var _a;
553
+ return (_a = this.midiPlayer) === null || _a === void 0 ? void 0 : _a.isPlaying();
554
+ }
555
+ update() {
556
+ this.resetMidiInstruments();
557
+ this.resetListeners();
558
+ this.initMidiPlayer();
559
+ return this;
560
+ }
561
+ //// Experimantal
562
+ getMidiInput() {
563
+ var that = this;
564
+ var navigator = require('web-midi-api');
565
+ // consider using var navigator = require('jzz');
566
+ var midi;
567
+ var inputs;
568
+ var outputs;
569
+ function onMIDIFailure(msg) {
570
+ console.log('Failed to get MIDI access - ' + msg);
571
+ //process?.exit(1);
572
+ }
573
+ function onMIDISuccess(midiAccess) {
574
+ midi = midiAccess;
575
+ inputs = midi.inputs;
576
+ outputs = midi.outputs;
577
+ console.log("general midi info:", midi);
578
+ setTimeout(testOutputs, 100);
579
+ }
580
+ function testOutputs() {
581
+ console.log('Testing MIDI-Out ports...');
582
+ outputs.forEach(function (port) {
583
+ console.log('id:', port.id, 'manufacturer:', port.manufacturer, 'name:', port.name, 'version:', port.version);
584
+ port.open();
585
+ port.send([0x90, 60, 0x7f]);
586
+ });
587
+ setTimeout(stopOutputs, 1000);
588
+ }
589
+ function stopOutputs() {
590
+ outputs.forEach(function (port) {
591
+ port.send([0x80, 60, 0]);
592
+ });
593
+ testInputs();
594
+ }
595
+ function onMidiIn(ev) {
596
+ document.dispatchEvent(new CustomEvent("midiin", { detail: ev.data })); // goes to KeyModeHandler since there already most of the logic is implemented
597
+ }
598
+ function testInputs() {
599
+ console.log('Testing MIDI-In ports...');
600
+ inputs.forEach(function (port) {
601
+ console.log('id:', port.id, 'manufacturer:', port.manufacturer, 'name:', port.name, 'version:', port.version);
602
+ port.onmidimessage = onMidiIn;
603
+ });
604
+ //setTimeout(stopInputs, 5000);
605
+ }
606
+ function fillDeviceList(e) {
607
+ var _a;
608
+ var deviceList = (_a = cq.getContainer(that.containerId)) === null || _a === void 0 ? void 0 : _a.querySelector("#midiDeviceSelect");
609
+ if (deviceList === null)
610
+ return;
611
+ var value = e.port.name;
612
+ if (e.port.type === "input" && !e.port.name.includes("EDITOR")) {
613
+ var optionEntry = deviceList.querySelector("option[value='" + value + "']");
614
+ if (optionEntry !== null) {
615
+ optionEntry.remove();
616
+ console.log("Removed MIDI Device", e.port);
617
+ }
618
+ else {
619
+ var option = document.createElement("option");
620
+ option.setAttribute("value", value);
621
+ option.textContent = e.port.manufacturer + " " + e.port.name;
622
+ deviceList.append(option);
623
+ console.log("Added MIDI Device", e.port);
624
+ }
625
+ deviceList.removeEventListener("change", chooseInput);
626
+ deviceList.addEventListener("change", chooseInput);
627
+ }
628
+ }
629
+ function chooseInput(e) {
630
+ var target = e.target;
631
+ console.log(e, target.value);
632
+ inputs.forEach(port => {
633
+ if (target.value === port.name) {
634
+ port.onmidimessage = onMidiIn;
635
+ console.log("Chosen MIDI Device", port);
636
+ }
637
+ else {
638
+ port.close();
639
+ }
640
+ });
641
+ }
642
+ navigator.requestMIDIAccess().then(access => {
643
+ console.log(access);
644
+ access.onstatechange = (e) => {
645
+ fillDeviceList(e);
646
+ };
647
+ onMIDISuccess(access);
648
+ onMIDIFailure(access);
649
+ });
650
+ }
651
+ }
652
+ exports.default = MusicProcessor;