abcjs 6.0.0-beta.7 → 6.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 (204) hide show
  1. package/.github/workflows/tests.yml +29 -0
  2. package/CODE_OF_CONDUCT.md +76 -0
  3. package/CONTRIBUTING.md +1 -0
  4. package/LICENSE.md +1 -1
  5. package/README.md +92 -3
  6. package/RELEASE.md +957 -1
  7. package/abcjs-audio.css +14 -5
  8. package/dist/.gitignore +1 -2
  9. package/dist/abcjs-basic-min.js +3 -0
  10. package/dist/abcjs-basic-min.js.LICENSE +23 -0
  11. package/dist/abcjs-basic.js +28231 -0
  12. package/dist/abcjs-basic.js.map +1 -0
  13. package/dist/abcjs-plugin-min.js +3 -0
  14. package/dist/abcjs-plugin-min.js.LICENSE +23 -0
  15. package/dist/report-basic.html +37 -0
  16. package/dist/report-before-glyph-compress.html +37 -0
  17. package/dist/report-brown-ts-target-es5.html +37 -0
  18. package/dist/report-dev-orig-no-babel.html +37 -0
  19. package/dist/report-synth.html +37 -0
  20. package/docker-build.sh +1 -0
  21. package/glyphs.json +1 -0
  22. package/index.js +27 -2
  23. package/{static-wrappers/license.js → license.js} +1 -1
  24. package/package.json +26 -29
  25. package/{src/plugin/abc_plugin.js → plugin.js} +31 -19
  26. package/src/api/abc_animation.js +1 -17
  27. package/src/api/abc_tablatures.js +144 -0
  28. package/src/api/abc_timing_callbacks.js +234 -116
  29. package/src/api/abc_tunebook.js +18 -67
  30. package/src/api/abc_tunebook_svg.js +38 -46
  31. package/src/data/abc_tune.js +232 -972
  32. package/src/data/deline-tune.js +199 -0
  33. package/src/edit/abc_editarea.js +112 -0
  34. package/src/edit/abc_editor.js +95 -221
  35. package/src/midi/abc_midi_create.js +48 -50
  36. package/src/parse/abc_common.js +0 -14
  37. package/src/parse/abc_parse.js +167 -1321
  38. package/src/parse/abc_parse_book.js +62 -0
  39. package/src/parse/abc_parse_directive.js +164 -41
  40. package/src/parse/abc_parse_header.js +116 -145
  41. package/src/parse/abc_parse_key_voice.js +26 -20
  42. package/src/parse/abc_parse_music.js +1337 -0
  43. package/src/parse/abc_tokenizer.js +21 -15
  44. package/src/parse/abc_transpose.js +3 -15
  45. package/src/parse/tune-builder.js +896 -0
  46. package/src/parse/wrap_lines.js +205 -453
  47. package/src/synth/abc_midi_flattener.js +1292 -0
  48. package/src/{midi → synth}/abc_midi_renderer.js +44 -17
  49. package/src/synth/abc_midi_sequencer.js +648 -0
  50. package/src/synth/active-audio-context.js +3 -14
  51. package/src/synth/cents-to-factor.js +10 -0
  52. package/src/synth/create-note-map.js +21 -32
  53. package/src/synth/create-synth-control.js +20 -103
  54. package/src/synth/create-synth.js +185 -77
  55. package/src/synth/download-buffer.js +7 -21
  56. package/src/synth/get-midi-file.js +13 -20
  57. package/src/synth/images/{loading.svg → loading.svg.js} +4 -0
  58. package/src/synth/images/loop.svg.js +65 -0
  59. package/src/synth/images/pause.svg.js +10 -0
  60. package/src/synth/images/play.svg.js +9 -0
  61. package/src/synth/images/{reset.svg → reset.svg.js} +5 -1
  62. package/src/synth/instrument-index-to-name.js +1 -16
  63. package/src/synth/load-note.js +37 -76
  64. package/src/synth/pitch-to-note-name.js +0 -15
  65. package/src/synth/pitches-to-perc.js +64 -0
  66. package/src/synth/place-note.js +78 -68
  67. package/src/synth/play-event.js +17 -18
  68. package/src/synth/register-audio-context.js +11 -23
  69. package/src/synth/sounds-cache.js +0 -15
  70. package/src/synth/supports-audio.js +9 -23
  71. package/src/synth/synth-controller.js +80 -49
  72. package/src/synth/synth-sequence.js +20 -34
  73. package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
  74. package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
  75. package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
  76. package/src/tablatures/instruments/string-patterns.js +277 -0
  77. package/src/tablatures/instruments/string-tablature.js +56 -0
  78. package/src/tablatures/instruments/tab-note.js +282 -0
  79. package/src/tablatures/instruments/tab-notes.js +41 -0
  80. package/src/tablatures/instruments/violin/tab-violin.js +47 -0
  81. package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
  82. package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
  83. package/src/tablatures/tab-absolute-elements.js +310 -0
  84. package/src/tablatures/tab-common.js +29 -0
  85. package/src/tablatures/tab-renderer.js +243 -0
  86. package/src/tablatures/transposer.js +110 -0
  87. package/src/test/abc_midi_lint.js +5 -22
  88. package/src/test/abc_midi_sequencer_lint.js +11 -14
  89. package/src/test/abc_parser_lint.js +136 -32
  90. package/src/test/abc_vertical_lint.js +94 -32
  91. package/src/test/rendering-lint.js +38 -5
  92. package/src/write/abc_absolute_element.js +112 -120
  93. package/src/write/abc_abstract_engraver.js +102 -253
  94. package/src/write/abc_beam_element.js +30 -290
  95. package/src/write/abc_brace_element.js +12 -121
  96. package/src/write/abc_create_clef.js +21 -32
  97. package/src/write/abc_create_key_signature.js +8 -26
  98. package/src/write/abc_create_note_head.js +107 -0
  99. package/src/write/abc_create_time_signature.js +2 -21
  100. package/src/write/abc_crescendo_element.js +3 -50
  101. package/src/write/abc_decoration.js +7 -30
  102. package/src/write/abc_dynamic_decoration.js +3 -37
  103. package/src/write/abc_ending_element.js +1 -57
  104. package/src/write/abc_engraver_controller.js +111 -234
  105. package/src/write/abc_glyphs.js +9 -19
  106. package/src/write/abc_relative_element.js +57 -97
  107. package/src/write/abc_renderer.js +10 -832
  108. package/src/write/abc_spacing.js +0 -15
  109. package/src/write/abc_staff_group_element.js +14 -349
  110. package/src/write/abc_tempo_element.js +9 -117
  111. package/src/write/abc_tie_element.js +5 -68
  112. package/src/write/abc_triplet_element.js +6 -124
  113. package/src/write/abc_voice_element.js +7 -222
  114. package/src/write/add-chord.js +103 -0
  115. package/src/write/add-text-if.js +33 -0
  116. package/src/write/bottom-text.js +79 -0
  117. package/src/write/calcHeight.js +17 -0
  118. package/src/write/classes.js +100 -0
  119. package/src/write/draw/absolute.js +68 -0
  120. package/src/write/draw/beam.js +56 -0
  121. package/src/write/draw/brace.js +106 -0
  122. package/src/write/draw/crescendo.js +38 -0
  123. package/src/write/draw/debug-box.js +8 -0
  124. package/src/write/draw/draw.js +56 -0
  125. package/src/write/draw/dynamics.js +20 -0
  126. package/src/write/draw/ending.js +46 -0
  127. package/src/write/draw/group-elements.js +66 -0
  128. package/src/write/draw/horizontal-line.js +25 -0
  129. package/src/write/draw/non-music.js +50 -0
  130. package/src/write/draw/print-line.js +24 -0
  131. package/src/write/draw/print-path.js +7 -0
  132. package/src/write/draw/print-stem.js +30 -0
  133. package/src/write/draw/print-symbol.js +59 -0
  134. package/src/write/draw/print-vertical-line.js +18 -0
  135. package/src/write/draw/relative.js +77 -0
  136. package/src/write/draw/round-number.js +5 -0
  137. package/src/write/draw/selectables.js +59 -0
  138. package/src/write/draw/separator.js +16 -0
  139. package/src/write/draw/set-paper-size.js +45 -0
  140. package/src/write/{sprintf.js → draw/sprintf.js} +0 -0
  141. package/src/write/draw/staff-group.js +226 -0
  142. package/src/write/draw/staff-line.js +9 -0
  143. package/src/write/draw/staff.js +33 -0
  144. package/src/write/draw/tab-line.js +40 -0
  145. package/src/write/draw/tempo.js +45 -0
  146. package/src/write/draw/text.js +71 -0
  147. package/src/write/draw/tie.js +97 -0
  148. package/src/write/draw/triplet.js +46 -0
  149. package/src/write/draw/voice.js +102 -0
  150. package/src/write/format-jazz-chord.js +15 -0
  151. package/src/write/free-text.js +41 -0
  152. package/src/write/get-font-and-attr.js +37 -0
  153. package/src/write/get-text-size.js +56 -0
  154. package/src/write/highlight.js +11 -0
  155. package/src/write/layout/VoiceElements.js +121 -0
  156. package/src/write/layout/beam.js +213 -0
  157. package/src/write/layout/get-left-edge-of-staff.js +56 -0
  158. package/src/write/layout/getBarYAt.js +6 -0
  159. package/src/write/layout/layout.js +94 -0
  160. package/src/write/layout/setUpperAndLowerElements.js +232 -0
  161. package/src/write/layout/staffGroup.js +146 -0
  162. package/src/write/layout/triplet.js +75 -0
  163. package/src/write/layout/voice.js +137 -0
  164. package/src/write/selection.js +188 -70
  165. package/src/write/separator.js +10 -0
  166. package/src/write/set-class.js +21 -0
  167. package/src/write/subtitle.js +12 -0
  168. package/src/write/svg.js +95 -43
  169. package/src/write/top-text.js +54 -0
  170. package/src/write/unhighlight.js +11 -0
  171. package/temp.txt +17 -0
  172. package/test.js +27 -64
  173. package/types/index.d.ts +1095 -0
  174. package/version.js +1 -1
  175. package/.babelrc +0 -5
  176. package/.eslintrc +0 -3
  177. package/.gitmodules +0 -3
  178. package/abcjs-midi.css +0 -166
  179. package/build-utils/loadPresets.js +0 -14
  180. package/build-utils/presets/webpack.analyze.js +0 -6
  181. package/build-utils/presets/webpack.optimize.js +0 -30
  182. package/build-utils/webpack.development.js +0 -14
  183. package/build-utils/webpack.production.js +0 -35
  184. package/deploy-docs.sh +0 -25
  185. package/docs/README.md +0 -33
  186. package/fix-versions.sh +0 -23
  187. package/mei.js +0 -43
  188. package/midi.js +0 -62
  189. package/src/api/abc_tunebook_midi.js +0 -116
  190. package/src/midi/abc_midi_controls.js +0 -701
  191. package/src/midi/abc_midi_flattener.js +0 -1119
  192. package/src/midi/abc_midi_js_preparer.js +0 -243
  193. package/src/midi/abc_midi_sequencer.js +0 -401
  194. package/src/midi/abc_midi_ui_generator.js +0 -86
  195. package/src/plugin/abc_plugin_midi.js +0 -220
  196. package/src/synth/images/loop.svg +0 -61
  197. package/src/synth/images/pause.svg +0 -6
  198. package/src/synth/images/play.svg +0 -5
  199. package/src/transform/abc2abc_write.js +0 -395
  200. package/static-wrappers/basic.js +0 -2
  201. package/static-wrappers/midi.js +0 -2
  202. package/static-wrappers/plugin-midi.js +0 -6
  203. package/static-wrappers/plugin.js +0 -6
  204. package/webpack.config.js +0 -29
@@ -1,701 +0,0 @@
1
- // abc_midi_controls.js: Handle the visual part of playing MIDI
2
- // Copyright (C) 2010-2020 Gregory Dyke (gregdyke at gmail dot com) and Paul Rosen
3
- //
4
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
5
- // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
6
- // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
7
- // to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
- //
9
- // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
- //
11
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
12
- // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
13
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
14
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16
-
17
- function performanceOk() {
18
- if (!('performance' in window))
19
- return false;
20
- if (!('now' in window.performance))
21
- return false;
22
- return true;
23
- }
24
-
25
- // Unfortunately, a few versions of Safari don't support the performance interface. For those browsers, MIDI just won't work.
26
- if (performanceOk()) {
27
- if (!('galactic' in window))
28
- window.galactic = {};
29
- window.galactic.loc = {
30
- isLocalUrl: function () { return false }
31
- };
32
-
33
- require('midi/inc/dom/request_xhr');
34
- require('midi/inc/dom/util')(window.galactic);
35
- require('midi/inc/AudioSupports');
36
- require('midi/inc/EventEmitter');
37
- require('midi/js/loader');
38
- require('midi/js/adaptors');
39
- require('midi/js/adaptors-Audio');
40
- require('midi/js/adaptors-AudioAPI');
41
- require('midi/js/adaptors-MIDI');
42
- require('midi/js/channels');
43
- require('midi/js/gm');
44
- require('midi/js/player');
45
- }
46
-
47
- var midi = {};
48
-
49
- (function() {
50
- "use strict";
51
- function isFunction(functionToCheck) {
52
- var getType = {};
53
- return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
54
- }
55
-
56
- midi.generateMidiDownloadLink = function(tune, midiParams, midi, index) {
57
- var divClasses = ['abcjs-download-midi', 'abcjs-midi-' + index]
58
- if (midiParams.downloadClass)
59
- divClasses.push(midiParams.downloadClass)
60
- var html = '<div class="' + divClasses.join(' ') + '">';
61
- if (midiParams.preTextDownload)
62
- html += midiParams.preTextDownload;
63
- var title = tune.metaText && tune.metaText.title ? tune.metaText.title : 'Untitled';
64
- var label;
65
- if (midiParams.downloadLabel && isFunction(midiParams.downloadLabel))
66
- label = midiParams.downloadLabel(tune, index);
67
- else if (midiParams.downloadLabel)
68
- label = midiParams.downloadLabel.replace(/%T/, title);
69
- else
70
- label = "Download MIDI for \"" + title + "\"";
71
- title = title.toLowerCase().replace(/'/g, '').replace(/\W/g, '_').replace(/__/g, '_');
72
- html += '<a download="' + title + '.midi" href="' + midi + '">' + label + '</a>';
73
- if (midiParams.postTextDownload)
74
- html += midiParams.postTextDownload;
75
- return html + "</div>";
76
- };
77
-
78
- function preprocessLabel(label, title) {
79
- return label.replace(/%T/g, title);
80
- }
81
-
82
- midi.deviceSupportsMidi = function() {
83
- if (!performanceOk())
84
- return false;
85
- if (midi.midiInlineInitialized === 'not loaded')
86
- return false;
87
- return true;
88
- };
89
-
90
- midi.generateMidiControls = function(tune, midiParams, midi, index, stopOld) {
91
- if (!performanceOk())
92
- return '<div class="abcjs-inline-midi abcjs-midi-' + index + '">ERROR: this browser doesn\'t support window.performance</div>';
93
- if (midi.midiInlineInitialized === 'not loaded')
94
- return '<div class="abcjs-inline-midi abcjs-midi-' + index + '">MIDI NOT PRESENT</div>';
95
-
96
- if (stopOld)
97
- stopCurrentlyPlayingTune();
98
- var title = tune.metaText && tune.metaText.title ? tune.metaText.title : 'Untitled';
99
- var options = midiParams.inlineControls || {};
100
- if (options.standard === undefined) options.standard = true;
101
-
102
- if (options.tooltipSelection === undefined) options.tooltipSelection = "Click to toggle play selection/play all.";
103
- if (options.tooltipLoop === undefined) options.tooltipLoop = "Click to toggle play once/repeat.";
104
- if (options.tooltipReset === undefined) options.tooltipReset = "Click to go to beginning.";
105
- if (options.tooltipPlay === undefined) options.tooltipPlay = "Click to play/pause.";
106
- if (options.tooltipProgress === undefined) options.tooltipProgress = "Click to change the playback position.";
107
- if (options.tooltipTempo === undefined) options.tooltipTempo = "Change the playback speed.";
108
-
109
- var style = "";
110
- if (options.hide)
111
- style = 'style="display:none;"';
112
- var html = '<div class="abcjs-inline-midi abcjs-midi-' + index + '" ' + style + '>';
113
- html += '<span class="abcjs-data" style="display:none;">' + JSON.stringify(midi) + '</span>';
114
- if (midiParams.preTextInline)
115
- html += '<span class="abcjs-midi-pre">' + preprocessLabel(midiParams.preTextInline, title) + '</span>';
116
-
117
- if (options.selectionToggle)
118
- html += '<button type="button" class="abcjs-midi-selection abcjs-btn" title="' + options.tooltipSelection + '"></button>';
119
- if (options.loopToggle)
120
- html += '<button type="button" class="abcjs-midi-loop abcjs-btn" title="' + options.tooltipLoop + '"></button>';
121
- if (options.standard)
122
- html += '<button type="button" class="abcjs-midi-reset abcjs-btn" title="' + options.tooltipReset + '"></button><button type="button" class="abcjs-midi-start abcjs-btn" title="' + options.tooltipPlay + '"></button><button type="button" class="abcjs-midi-progress-background" title="' + options.tooltipProgress + '"><span class="abcjs-midi-progress-indicator"></span></button><span class="abcjs-midi-clock"> 0:00</span>';
123
- if (options.tempo) {
124
- var startTempo = tune && tune.metaText && tune.metaText.tempo && tune.metaText.tempo.bpm ? tune.metaText.tempo.bpm : 180;
125
- html += '<span class="abcjs-tempo-wrapper"><input class="abcjs-midi-tempo" value="100" type="number" min="1" max="300" data-start-tempo="' + startTempo + '" title="' + options.tooltipTempo + '" />% (<span class="abcjs-midi-current-tempo">' + startTempo + '</span> BPM)</span>';
126
- }
127
-
128
- if (midiParams.postTextInline)
129
- html += '<span class="abcjs-midi-post">' + preprocessLabel(midiParams.postTextInline, title) + '</span>';
130
- return html + "</div>";
131
- };
132
-
133
- // The default location for the sound font files. Simply set this to a different value if the files are served in a different place.
134
- // midi.soundfontUrl = "node_modules/midi/examples/soundfont/";
135
- var soundfontUrl = "https://paulrosen.github.io/midi-js-soundfonts/FluidR3_GM/";
136
- midi.setSoundFont = function(url) {
137
- soundfontUrl = url;
138
- };
139
-
140
- var interactiveProgressBar = true;
141
- midi.setInteractiveProgressBar = function(interactive) {
142
- interactiveProgressBar = interactive;
143
- };
144
-
145
- function hasClass(element, cls) {
146
- if (!element)
147
- return false;
148
- return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
149
- }
150
-
151
- function addClass(element, cls) {
152
- if (!element)
153
- return;
154
- if (!hasClass(element, cls))
155
- element.className = element.className + " " + cls;
156
- }
157
-
158
- function removeClass(element, cls) {
159
- if (!element)
160
- return;
161
- element.className = element.className.replace(cls, "").trim().replace(" ", " ");
162
- }
163
-
164
- function toggleClass(element, cls) {
165
- if (!element)
166
- return;
167
- if (hasClass(element, cls))
168
- removeClass(element, cls);
169
- else
170
- addClass(element, cls);
171
- }
172
-
173
- function closest(element, cls) {
174
- // This finds the closest parent that contains the class passed in.
175
- if (!element)
176
- return null;
177
- while (element !== document.body) {
178
- if (hasClass(element, cls))
179
- return element;
180
- element = element.parentNode;
181
- }
182
- return null;
183
- }
184
-
185
- function find(element, cls) {
186
- if (!element)
187
- return null;
188
- var els = element.getElementsByClassName(cls);
189
- if (els.length === 0)
190
- return null;
191
- return els[0];
192
- }
193
-
194
- // function addLoadEvent(func) {
195
- // if (window.document.readyState === 'loading') {
196
- // window.addEventListener('load', func);
197
- // } else {
198
- // func();
199
- // }
200
- // }
201
-
202
- var midiJsInitialized = false;
203
-
204
- function afterSetup(timeWarp, data, onSuccess) {
205
- MIDI.player.currentTime = 0;
206
- MIDI.player.warp = timeWarp;
207
-
208
- MIDI.player.load({ events: data });
209
- onSuccess();
210
- }
211
-
212
- function listInstruments(data) {
213
- var instruments = [];
214
- for (var i = 0; i < data.length; i++) {
215
- if (data[i][0] && data[i][0].event && data[i][0].event.programNumber) {
216
- instruments.push(data[i][0].event.programNumber);
217
- }
218
- }
219
- return instruments;
220
- }
221
-
222
- function setCurrentMidiTune(timeWarp, data, onSuccess) {
223
- if (!midiJsInitialized) {
224
- MIDI.setup({
225
- debug: false,
226
- soundfontUrl: soundfontUrl,
227
- instruments: listInstruments(data)
228
- }).then(function() {
229
- midiJsInitialized = true;
230
- afterSetup(timeWarp, data, onSuccess);
231
- }).catch(function(e) {
232
- console.log("MIDI.setup failed:", e.message);
233
- });
234
- } else {
235
- afterSetup(timeWarp, data, onSuccess);
236
- }
237
- }
238
-
239
- function startCurrentlySelectedTune() {
240
- MIDI.player.start(MIDI.player.currentTime);
241
- }
242
-
243
- function stopCurrentlyPlayingTune() {
244
- MIDI.player.stop();
245
- }
246
-
247
- function pauseCurrentlyPlayingTune() {
248
- MIDI.player.pause();
249
- }
250
-
251
- function setMidiCallback(midiJsListener) {
252
- if(midiJsListener) {
253
- MIDI.player.setAnimation(midiJsListener);
254
- } else {
255
- MIDI.player.clearAnimation();
256
- }
257
- }
258
-
259
- function jumpToMidiPosition(play, offset, width) {
260
- var ratio = offset / width;
261
- var endTime = MIDI.player.duration; // MIDI.Player.endTime;
262
- if (play)
263
- pauseCurrentlyPlayingTune();
264
- MIDI.player.currentTime = endTime * ratio;
265
- if (play)
266
- startCurrentlySelectedTune();
267
- else if (midiJsListener) {
268
- var ret = MIDI.player;
269
- var progress = ret.currentTime/ret.duration;
270
- midiJsListener({ currentTime: ret.currentTime/1000, duration: ret.duration/1000, progress: progress });
271
- }
272
- }
273
-
274
- function setTimeWarp(percent) {
275
- // Time warp is a multiplier: the larger the number, the longer the time. Therefore,
276
- // it is opposite of the percentage. That is, playing at 50% is actually multiplying the time by 2.
277
- MIDI.player.warp = (percent > 0) ? 100 / percent : 1;
278
- }
279
-
280
- function loadMidi(target, onSuccess) {
281
- var dataEl = find(target, "abcjs-data");
282
- var data = JSON.parse(dataEl.innerHTML);
283
-
284
- // See if the tempo changer is present, and use that tempo if so.
285
- var timeWarp = 1;
286
- var tempoEl = find(target, "abcjs-midi-tempo");
287
- if (tempoEl) {
288
- // Time warp is a multiplier: the larger the number, the longer the time. Therefore,
289
- // it is opposite of the percentage. That is, playing at 50% is actually multiplying the time by 2.
290
- var percent = parseInt(tempoEl.value, 10);
291
- if (percent > 0)
292
- timeWarp = 100 / percent;
293
- }
294
- setCurrentMidiTune(timeWarp, data, onSuccess);
295
- }
296
-
297
- function deselectMidiControl() {
298
- var otherMidi = find(document, "abcjs-midi-current");
299
- if (otherMidi) {
300
- stopCurrentlyPlayingTune();
301
- removeClass(otherMidi, "abcjs-midi-current");
302
- var otherMidiStart = find(otherMidi, "abcjs-midi-start");
303
- removeClass(otherMidiStart, "abcjs-pushed");
304
- }
305
- }
306
-
307
- var lastNow;
308
-
309
- function findElements(visualItems, currentTime, epsilon) {
310
-
311
- var minIndex = 0;
312
- var maxIndex = visualItems.length - 1;
313
- var currentIndex;
314
- var currentElement;
315
-
316
- while (minIndex <= maxIndex) {
317
- currentIndex = Math.floor((minIndex + maxIndex) / 2);
318
- currentElement = visualItems[currentIndex];
319
-
320
- // A match is if the currentTime is within .1 seconds before the exact time.
321
- // We get callback events at somewhat random times, so they won't match up exactly.
322
- if (currentElement.milliseconds/1000 - epsilon < currentTime) {
323
- minIndex = currentIndex + 1;
324
- }
325
- else if (currentElement.milliseconds/1000 - epsilon > currentTime) {
326
- maxIndex = currentIndex - 1;
327
- }
328
- else {
329
- // We have a match.
330
- return currentIndex;
331
- }
332
- }
333
-
334
- // There was no match, so find the closest element that is less than the current time.
335
- while (visualItems[currentIndex].milliseconds/1000 - epsilon >= currentTime && currentIndex > 0)
336
- currentIndex--;
337
- // If the time is way before the first element, then we're not ready to select any of them.
338
- if (currentIndex === 0 && visualItems[currentIndex].milliseconds/1000 - epsilon >= currentTime)
339
- return -1;
340
- return currentIndex;
341
- }
342
-
343
- function midiJsListener(position) {
344
- // { currentTime: in seconds, duration: total length in seconds, progress: percent between 0 and 1 }
345
- var midiControl;
346
- if (position.duration > 0 && lastNow !== position.progress) {
347
- lastNow = position.progress;
348
- midiControl = find(document, "abcjs-midi-current");
349
- if (midiControl) {
350
- var startButton = find(midiControl, 'abcjs-midi-start');
351
- if (hasClass(startButton, 'abcjs-loaded')) {
352
- if(!isIndicatorPressed) {
353
- var progressBackground = find(midiControl, "abcjs-midi-progress-background");
354
- var totalWidth = progressBackground.offsetWidth;
355
- var progressIndicator = find(midiControl, "abcjs-midi-progress-indicator");
356
- var scaled = totalWidth * lastNow; // The number of pixels
357
- progressIndicator.style.left = scaled + "px";
358
- }
359
- var clock = find(midiControl, "abcjs-midi-clock");
360
- if (clock) {
361
- var seconds = Math.floor(position.currentTime);
362
- var minutes = Math.floor(seconds / 60);
363
- seconds = seconds % 60;
364
- if (seconds < 10) seconds = "0" + seconds;
365
- if (minutes < 10) minutes = " " + minutes;
366
- clock.innerHTML = minutes + ":" + seconds;
367
- }
368
- var tempo = midiControl.abcjsQpm;
369
- if (!tempo && midiControl.abcjsTune && midiControl.abcjsTune.metaText && midiControl.abcjsTune.metaText.tempo)
370
- tempo = midiControl.abcjsTune.metaText.tempo.bpm;
371
- if (!tempo)
372
- tempo = 180;
373
- var beatsPerSecond = parseInt(tempo, 10) / 60;
374
- var currentTime = position.currentTime;
375
- if (midiControl.abcjsListener) {
376
- var thisBeat = Math.floor(currentTime * beatsPerSecond);
377
- position.newBeat = thisBeat !== midiControl.abcjsLastBeat;
378
- position.thisBeat = thisBeat;
379
- midiControl.abcjsLastBeat = thisBeat;
380
- midiControl.abcjsListener(midiControl, position, midiControl.abcjsContext);
381
- }
382
- if (midiControl.abcjsAnimate) {
383
- var epsilon = beatsPerSecond / 64; // pick a small division to round to. This is called at small, random times.
384
- var index = findElements(midiControl.abcjsTune.noteTimings, currentTime, epsilon);
385
- if (index !== midiControl.abcjsLastIndex) {
386
- var last = midiControl.abcjsLastIndex >= 0 ? midiControl.abcjsTune.noteTimings[midiControl.abcjsLastIndex] : null;
387
- midiControl.abcjsAnimate(last,
388
- midiControl.abcjsTune.noteTimings[index], midiControl.abcjsContext);
389
- midiControl.abcjsLastIndex = index;
390
- }
391
- }
392
- }
393
- }
394
- }
395
- if (position.progress === 1) {
396
- // The playback is stopping. We need to either indicate that
397
- // it has stopped, or start over at the beginning.
398
- midiControl = find(document, "abcjs-midi-current");
399
- var loopControl = find(midiControl, "abcjs-midi-loop");
400
-
401
- var finishedResetting = function() {
402
- if (loopControl && hasClass(loopControl, "abcjs-pushed")) {
403
- onStart(find(midiControl, "abcjs-midi-start"));
404
- }
405
- };
406
-
407
- // midi.js is not quite finished: it still will process the last event, so we wait a minimum amount of time
408
- // before doing another action.
409
- setTimeout(function() {
410
- doReset(midiControl, finishedResetting);
411
- if (midiControl && midiControl.abcjsAnimate)
412
- midiControl.abcjsAnimate(midiControl.abcjsTune.noteTimings[midiControl.abcjsLastIndex], null, midiControl.abcjsContext);
413
- }, 1);
414
- }
415
- }
416
-
417
- function onStart(target) {
418
- var parent = closest(target, "abcjs-inline-midi");
419
- // If this midi is already playing,
420
- if (hasClass(target, 'abcjs-pushed')) {
421
- // Stop it.
422
- pauseCurrentlyPlayingTune();
423
- // Change the element so that the start icon is shown.
424
- removeClass(target, "abcjs-pushed");
425
- return;
426
- } else { // Else,
427
- // If some other midi is running, turn it off.
428
-
429
- // If this is the current midi, just continue.
430
- if (hasClass(parent, "abcjs-midi-current"))
431
- // Start this tune playing from wherever it had stopped.
432
- startCurrentlySelectedTune();
433
- else {
434
- deselectMidiControl();
435
- onLoadMidi(target, parent, function() {
436
- startCurrentlySelectedTune();
437
- });
438
- }
439
- addClass(target, "abcjs-pushed");
440
- }
441
- }
442
-
443
- function setCurrentMidiControl(el) {
444
- var els = document.querySelectorAll('.abcjs-midi-current');
445
- for (var i = 0; i < els.length; i++)
446
- removeClass(els[i], 'abcjs-midi-current');
447
- addClass(el, 'abcjs-midi-current');
448
- }
449
-
450
- function onLoadMidi(target, parent, cb) {
451
- // else, load this midi from scratch.
452
- var onSuccess = function() {
453
- removeClass(target, "abcjs-loading");
454
- setCurrentMidiControl(parent);
455
- addClass(target, 'abcjs-loaded');
456
- if(cb) {
457
- cb();
458
- }
459
- };
460
- addClass(target, "abcjs-loading");
461
- loadMidi(parent, onSuccess);
462
- parent.abcjsLastBeat = -1;
463
- parent.abcjsLastIndex = -1;
464
- setMidiCallback(midiJsListener);
465
- }
466
-
467
- midi.startPlaying = function(target) {
468
- // This can be called with the target being entire control, and if so, first find the start button.
469
- var btn = target;
470
- if (hasClass(target, "abcjs-inline-midi"))
471
- btn = target.querySelector('.abcjs-midi-start');
472
- onStart(btn);
473
- };
474
-
475
- midi.stopPlaying = function() {
476
- stopCurrentlyPlayingTune();
477
- var playingEl = document.querySelector(".abcjs-midi-current");
478
- if (playingEl) {
479
- resetProgress(playingEl);
480
- var startBtn = find(playingEl, "abcjs-midi-start");
481
- if (startBtn)
482
- removeClass(startBtn, "abcjs-pushed");
483
- }
484
- };
485
- midi.restartPlaying = function() {
486
- var target = document.querySelector(".abcjs-midi-current");
487
- onReset(target);
488
- };
489
-
490
- midi.setLoop = function(target, state) {
491
- var loop = target.querySelector('.abcjs-midi-loop');
492
- if (!loop)
493
- return;
494
- if (state)
495
- addClass(loop, 'abcjs-pushed');
496
- else
497
- removeClass(loop, 'abcjs-pushed');
498
- };
499
-
500
- midi.setRandomProgress = function(percent) {
501
- var target = document.querySelector(".abcjs-midi-current");
502
- var playEl = find(target, "abcjs-midi-start");
503
- var play = hasClass(playEl, "abcjs-pushed");
504
- var endTime = MIDI.player.duration;
505
- if (play)
506
- pauseCurrentlyPlayingTune();
507
- MIDI.player.currentTime = endTime * percent;
508
- if (play)
509
- startCurrentlySelectedTune();
510
- };
511
-
512
- function resetProgress(parent) {
513
- var progressIndicator = find(parent, "abcjs-midi-progress-indicator");
514
- progressIndicator.style.left = "0px";
515
- var clock = find(parent, "abcjs-midi-clock");
516
- clock.innerHTML = " 0:00";
517
- }
518
-
519
- function onSelection(target) {
520
- toggleClass(target, 'abcjs-pushed');
521
- }
522
-
523
- function onLoop(target) {
524
- toggleClass(target, 'abcjs-pushed');
525
- }
526
-
527
- function doReset(target, callback) {
528
- var parent = closest(target, "abcjs-inline-midi");
529
-
530
- function onSuccess() {
531
- setCurrentMidiControl(parent);
532
- resetProgress(parent);
533
- if (callback)
534
- callback();
535
- }
536
-
537
- // If the tune is playing, stop it.
538
- deselectMidiControl();
539
- if (parent) // parent can be null if the music was changed while the midi is playing. This is called to stop it, but the object is already gone.
540
- loadMidi(parent, onSuccess);
541
- }
542
-
543
- function onReset(target) {
544
- var parent = closest(target, "abcjs-inline-midi");
545
- var playEl = find(parent, "abcjs-midi-start");
546
- var play = hasClass(playEl, "abcjs-pushed");
547
- function keepPlaying() {
548
- if (play) {
549
- startCurrentlySelectedTune();
550
- addClass(playEl, 'abcjs-pushed');
551
- }
552
- }
553
- if (hasClass(parent, "abcjs-midi-current")) // Only listen to the reset for the currently playing tune.
554
- doReset(target, keepPlaying);
555
- }
556
-
557
- function relMouseX(target, event) {
558
- var totalOffsetX = 0;
559
-
560
- var width = target.offsetWidth;
561
- do {
562
- totalOffsetX += target.offsetLeft - target.scrollLeft;
563
- target = target.offsetParent;
564
- }
565
- while (target);
566
-
567
- var x = event.pageX - totalOffsetX;
568
- if (x < 0)
569
- x = 0;
570
- if (x > width)
571
- x = width - 1;
572
- return x;
573
- }
574
-
575
- function isPlaying(target) {
576
- var parent = closest(target, "abcjs-inline-midi");
577
- var play = find(parent, "abcjs-midi-start");
578
- if (hasClass(parent, "abcjs-midi-current")) {
579
- return hasClass(play, "abcjs-pushed");
580
- }
581
- return false;
582
- }
583
-
584
- function onProgress(target, event) {
585
- var parent = closest(target, "abcjs-inline-midi");
586
- var play = find(parent, "abcjs-midi-start");
587
- var width = target.offsetWidth;
588
- var offset = relMouseX(target, event);
589
- if (hasClass(parent, "abcjs-midi-current")) {
590
- jumpToMidiPosition(isPlaying(target), offset, width);
591
- } else {
592
- onLoadMidi(play, parent, function() {
593
- jumpToMidiPosition(false, offset, width);
594
- })
595
- }
596
- }
597
-
598
- function onTempo(el) {
599
- var percent = parseInt(el.value, 10);
600
- var startTempo = parseInt(el.getAttribute("data-start-tempo"), 10);
601
-
602
- while (el && !hasClass(el, 'abcjs-midi-current-tempo')) {
603
- el = el.nextSibling;
604
- }
605
- el.innerHTML = Math.floor(percent * startTempo / 100);
606
- setTimeWarp(percent);
607
- }
608
- var isIndicatorPressed = false;
609
- var dragIndicator, dragParent;
610
- var hasAddedMouseEvents = false;
611
-
612
- midi.attachListeners = function(parentElement) {
613
- var audioControls = parentElement.querySelectorAll(".abcjs-inline-midi");
614
- for (var a = 0; a < audioControls.length; a++) {
615
- var audioCtl = audioControls[a];
616
-
617
- audioCtl.addEventListener("click", function (event) {
618
- event = event || window.event;
619
- var target = event.target || event.srcElement;
620
- while (target && target !== document.body) {
621
- if (hasClass(target, 'abcjs-midi-start')) {
622
- onStart(target, event);
623
- return;
624
- } else if (hasClass(target, 'abcjs-midi-selection')) {
625
- onSelection(target, event);
626
- return;
627
- } else if (hasClass(target, 'abcjs-midi-loop')) {
628
- onLoop(target, event);
629
- return;
630
- } else if (hasClass(target, 'abcjs-midi-reset')) {
631
- onReset(target, event);
632
- return;
633
- } else if (hasClass(target, 'abcjs-midi-progress-background')) {
634
- if (interactiveProgressBar) {
635
- onProgress(target, event);
636
- }
637
- return;
638
- }
639
- target = target.parentNode;
640
- }
641
- });
642
- audioCtl.addEventListener("change", function (event) {
643
- event = event || window.event;
644
- var target = event.target || event.srcElement;
645
- while (target !== document.body) {
646
- if (hasClass(target, 'abcjs-midi-tempo'))
647
- onTempo(target, event);
648
- target = target.parentNode;
649
- }
650
- });
651
-
652
- audioCtl.addEventListener("mousedown", function (event) {
653
- if (interactiveProgressBar) {
654
- event = event || window.event;
655
- var target = event.target || event.srcElement;
656
- if (hasClass(target, 'abcjs-midi-progress-indicator')) {
657
- dragIndicator = target;
658
- isIndicatorPressed = true;
659
- dragParent = closest(target, 'abcjs-midi-progress-background');
660
- }
661
- }
662
- });
663
- }
664
- if (!hasAddedMouseEvents) {
665
- hasAddedMouseEvents = true;
666
- document.body.addEventListener('mousemove', function (event) {
667
- if (isIndicatorPressed) {
668
- event = event || window.event;
669
- event.preventDefault();
670
- var pos = relMouseX(dragParent, event);
671
- dragIndicator.style.left = pos + 'px';
672
- }
673
- }, true);
674
-
675
- document.body.addEventListener("mouseup", function (event) {
676
- if (isIndicatorPressed) {
677
- event = event || window.event;
678
- event.preventDefault();
679
- var pos = relMouseX(dragParent, event);
680
- var width = dragParent.offsetWidth;
681
- jumpToMidiPosition(isPlaying(dragParent), pos, width);
682
- onProgress(dragParent, event);
683
- isIndicatorPressed = false;
684
- dragIndicator = null;
685
- dragParent = null;
686
- }
687
- });
688
- }
689
- if (window.MIDI === undefined) {
690
- midi.midiInlineInitialized = 'not loaded';
691
- var els = document.getElementsByClassName('abcjs-inline-midi');
692
- for (var i = 0; i < els.length; i++)
693
- els[i].innerHTML = "MIDI NOT PRESENT";
694
- }
695
- }
696
-
697
- //addLoadEvent(addDelegates);
698
-
699
- })();
700
-
701
- module.exports = midi;