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.
- package/.github/workflows/tests.yml +29 -0
- package/CODE_OF_CONDUCT.md +76 -0
- package/CONTRIBUTING.md +1 -0
- package/LICENSE.md +1 -1
- package/README.md +92 -3
- package/RELEASE.md +957 -1
- package/abcjs-audio.css +14 -5
- package/dist/.gitignore +1 -2
- package/dist/abcjs-basic-min.js +3 -0
- package/dist/abcjs-basic-min.js.LICENSE +23 -0
- package/dist/abcjs-basic.js +28231 -0
- package/dist/abcjs-basic.js.map +1 -0
- package/dist/abcjs-plugin-min.js +3 -0
- package/dist/abcjs-plugin-min.js.LICENSE +23 -0
- package/dist/report-basic.html +37 -0
- package/dist/report-before-glyph-compress.html +37 -0
- package/dist/report-brown-ts-target-es5.html +37 -0
- package/dist/report-dev-orig-no-babel.html +37 -0
- package/dist/report-synth.html +37 -0
- package/docker-build.sh +1 -0
- package/glyphs.json +1 -0
- package/index.js +27 -2
- package/{static-wrappers/license.js → license.js} +1 -1
- package/package.json +26 -29
- package/{src/plugin/abc_plugin.js → plugin.js} +31 -19
- package/src/api/abc_animation.js +1 -17
- package/src/api/abc_tablatures.js +144 -0
- package/src/api/abc_timing_callbacks.js +234 -116
- package/src/api/abc_tunebook.js +18 -67
- package/src/api/abc_tunebook_svg.js +38 -46
- package/src/data/abc_tune.js +232 -972
- package/src/data/deline-tune.js +199 -0
- package/src/edit/abc_editarea.js +112 -0
- package/src/edit/abc_editor.js +95 -221
- package/src/midi/abc_midi_create.js +48 -50
- package/src/parse/abc_common.js +0 -14
- package/src/parse/abc_parse.js +167 -1321
- package/src/parse/abc_parse_book.js +62 -0
- package/src/parse/abc_parse_directive.js +164 -41
- package/src/parse/abc_parse_header.js +116 -145
- package/src/parse/abc_parse_key_voice.js +26 -20
- package/src/parse/abc_parse_music.js +1337 -0
- package/src/parse/abc_tokenizer.js +21 -15
- package/src/parse/abc_transpose.js +3 -15
- package/src/parse/tune-builder.js +896 -0
- package/src/parse/wrap_lines.js +205 -453
- package/src/synth/abc_midi_flattener.js +1292 -0
- package/src/{midi → synth}/abc_midi_renderer.js +44 -17
- package/src/synth/abc_midi_sequencer.js +648 -0
- package/src/synth/active-audio-context.js +3 -14
- package/src/synth/cents-to-factor.js +10 -0
- package/src/synth/create-note-map.js +21 -32
- package/src/synth/create-synth-control.js +20 -103
- package/src/synth/create-synth.js +185 -77
- package/src/synth/download-buffer.js +7 -21
- package/src/synth/get-midi-file.js +13 -20
- package/src/synth/images/{loading.svg → loading.svg.js} +4 -0
- package/src/synth/images/loop.svg.js +65 -0
- package/src/synth/images/pause.svg.js +10 -0
- package/src/synth/images/play.svg.js +9 -0
- package/src/synth/images/{reset.svg → reset.svg.js} +5 -1
- package/src/synth/instrument-index-to-name.js +1 -16
- package/src/synth/load-note.js +37 -76
- package/src/synth/pitch-to-note-name.js +0 -15
- package/src/synth/pitches-to-perc.js +64 -0
- package/src/synth/place-note.js +78 -68
- package/src/synth/play-event.js +17 -18
- package/src/synth/register-audio-context.js +11 -23
- package/src/synth/sounds-cache.js +0 -15
- package/src/synth/supports-audio.js +9 -23
- package/src/synth/synth-controller.js +80 -49
- package/src/synth/synth-sequence.js +20 -34
- package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
- package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
- package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
- package/src/tablatures/instruments/string-patterns.js +277 -0
- package/src/tablatures/instruments/string-tablature.js +56 -0
- package/src/tablatures/instruments/tab-note.js +282 -0
- package/src/tablatures/instruments/tab-notes.js +41 -0
- package/src/tablatures/instruments/violin/tab-violin.js +47 -0
- package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
- package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
- package/src/tablatures/tab-absolute-elements.js +310 -0
- package/src/tablatures/tab-common.js +29 -0
- package/src/tablatures/tab-renderer.js +243 -0
- package/src/tablatures/transposer.js +110 -0
- package/src/test/abc_midi_lint.js +5 -22
- package/src/test/abc_midi_sequencer_lint.js +11 -14
- package/src/test/abc_parser_lint.js +136 -32
- package/src/test/abc_vertical_lint.js +94 -32
- package/src/test/rendering-lint.js +38 -5
- package/src/write/abc_absolute_element.js +112 -120
- package/src/write/abc_abstract_engraver.js +102 -253
- package/src/write/abc_beam_element.js +30 -290
- package/src/write/abc_brace_element.js +12 -121
- package/src/write/abc_create_clef.js +21 -32
- package/src/write/abc_create_key_signature.js +8 -26
- package/src/write/abc_create_note_head.js +107 -0
- package/src/write/abc_create_time_signature.js +2 -21
- package/src/write/abc_crescendo_element.js +3 -50
- package/src/write/abc_decoration.js +7 -30
- package/src/write/abc_dynamic_decoration.js +3 -37
- package/src/write/abc_ending_element.js +1 -57
- package/src/write/abc_engraver_controller.js +111 -234
- package/src/write/abc_glyphs.js +9 -19
- package/src/write/abc_relative_element.js +57 -97
- package/src/write/abc_renderer.js +10 -832
- package/src/write/abc_spacing.js +0 -15
- package/src/write/abc_staff_group_element.js +14 -349
- package/src/write/abc_tempo_element.js +9 -117
- package/src/write/abc_tie_element.js +5 -68
- package/src/write/abc_triplet_element.js +6 -124
- package/src/write/abc_voice_element.js +7 -222
- package/src/write/add-chord.js +103 -0
- package/src/write/add-text-if.js +33 -0
- package/src/write/bottom-text.js +79 -0
- package/src/write/calcHeight.js +17 -0
- package/src/write/classes.js +100 -0
- package/src/write/draw/absolute.js +68 -0
- package/src/write/draw/beam.js +56 -0
- package/src/write/draw/brace.js +106 -0
- package/src/write/draw/crescendo.js +38 -0
- package/src/write/draw/debug-box.js +8 -0
- package/src/write/draw/draw.js +56 -0
- package/src/write/draw/dynamics.js +20 -0
- package/src/write/draw/ending.js +46 -0
- package/src/write/draw/group-elements.js +66 -0
- package/src/write/draw/horizontal-line.js +25 -0
- package/src/write/draw/non-music.js +50 -0
- package/src/write/draw/print-line.js +24 -0
- package/src/write/draw/print-path.js +7 -0
- package/src/write/draw/print-stem.js +30 -0
- package/src/write/draw/print-symbol.js +59 -0
- package/src/write/draw/print-vertical-line.js +18 -0
- package/src/write/draw/relative.js +77 -0
- package/src/write/draw/round-number.js +5 -0
- package/src/write/draw/selectables.js +59 -0
- package/src/write/draw/separator.js +16 -0
- package/src/write/draw/set-paper-size.js +45 -0
- package/src/write/{sprintf.js → draw/sprintf.js} +0 -0
- package/src/write/draw/staff-group.js +226 -0
- package/src/write/draw/staff-line.js +9 -0
- package/src/write/draw/staff.js +33 -0
- package/src/write/draw/tab-line.js +40 -0
- package/src/write/draw/tempo.js +45 -0
- package/src/write/draw/text.js +71 -0
- package/src/write/draw/tie.js +97 -0
- package/src/write/draw/triplet.js +46 -0
- package/src/write/draw/voice.js +102 -0
- package/src/write/format-jazz-chord.js +15 -0
- package/src/write/free-text.js +41 -0
- package/src/write/get-font-and-attr.js +37 -0
- package/src/write/get-text-size.js +56 -0
- package/src/write/highlight.js +11 -0
- package/src/write/layout/VoiceElements.js +121 -0
- package/src/write/layout/beam.js +213 -0
- package/src/write/layout/get-left-edge-of-staff.js +56 -0
- package/src/write/layout/getBarYAt.js +6 -0
- package/src/write/layout/layout.js +94 -0
- package/src/write/layout/setUpperAndLowerElements.js +232 -0
- package/src/write/layout/staffGroup.js +146 -0
- package/src/write/layout/triplet.js +75 -0
- package/src/write/layout/voice.js +137 -0
- package/src/write/selection.js +188 -70
- package/src/write/separator.js +10 -0
- package/src/write/set-class.js +21 -0
- package/src/write/subtitle.js +12 -0
- package/src/write/svg.js +95 -43
- package/src/write/top-text.js +54 -0
- package/src/write/unhighlight.js +11 -0
- package/temp.txt +17 -0
- package/test.js +27 -64
- package/types/index.d.ts +1095 -0
- package/version.js +1 -1
- package/.babelrc +0 -5
- package/.eslintrc +0 -3
- package/.gitmodules +0 -3
- package/abcjs-midi.css +0 -166
- package/build-utils/loadPresets.js +0 -14
- package/build-utils/presets/webpack.analyze.js +0 -6
- package/build-utils/presets/webpack.optimize.js +0 -30
- package/build-utils/webpack.development.js +0 -14
- package/build-utils/webpack.production.js +0 -35
- package/deploy-docs.sh +0 -25
- package/docs/README.md +0 -33
- package/fix-versions.sh +0 -23
- package/mei.js +0 -43
- package/midi.js +0 -62
- package/src/api/abc_tunebook_midi.js +0 -116
- package/src/midi/abc_midi_controls.js +0 -701
- package/src/midi/abc_midi_flattener.js +0 -1119
- package/src/midi/abc_midi_js_preparer.js +0 -243
- package/src/midi/abc_midi_sequencer.js +0 -401
- package/src/midi/abc_midi_ui_generator.js +0 -86
- package/src/plugin/abc_plugin_midi.js +0 -220
- package/src/synth/images/loop.svg +0 -61
- package/src/synth/images/pause.svg +0 -6
- package/src/synth/images/play.svg +0 -5
- package/src/transform/abc2abc_write.js +0 -395
- package/static-wrappers/basic.js +0 -2
- package/static-wrappers/midi.js +0 -2
- package/static-wrappers/plugin-midi.js +0 -6
- package/static-wrappers/plugin.js +0 -6
- package/webpack.config.js +0 -29
package/src/edit/abc_editor.js
CHANGED
|
@@ -1,139 +1,3 @@
|
|
|
1
|
-
// abc_editor.js
|
|
2
|
-
// Copyright (C) 2015-2020 Paul Rosen (paul at paulrosen dot net)
|
|
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
|
-
// window.ABCJS.Editor is the interface class for the area that contains the ABC text. It is responsible for
|
|
18
|
-
// holding the text of the tune and calling the parser and the rendering engines.
|
|
19
|
-
//
|
|
20
|
-
// EditArea is an example of using a textarea as the control that is shown to the user. As long as
|
|
21
|
-
// the same interface is used, window.ABCJS.Editor can use a different type of object.
|
|
22
|
-
//
|
|
23
|
-
// EditArea:
|
|
24
|
-
// - constructor(textareaid)
|
|
25
|
-
// This contains the id of a textarea control that will be used.
|
|
26
|
-
// - addSelectionListener(listener)
|
|
27
|
-
// A callback class that contains the entry point fireSelectionChanged()
|
|
28
|
-
// - addChangeListener(listener)
|
|
29
|
-
// A callback class that contains the entry point fireChanged()
|
|
30
|
-
// - getSelection()
|
|
31
|
-
// returns the object { start: , end: } with the current selection in characters
|
|
32
|
-
// - setSelection(start, end)
|
|
33
|
-
// start and end are the character positions that should be selected.
|
|
34
|
-
// - getString()
|
|
35
|
-
// returns the ABC text that is currently displayed.
|
|
36
|
-
// - setString(str)
|
|
37
|
-
// sets the ABC text that is currently displayed, and resets the initialText variable
|
|
38
|
-
// - getElem()
|
|
39
|
-
// returns the textarea element
|
|
40
|
-
// - string initialText
|
|
41
|
-
// Contains the starting text. This can be compared against the current text to see if anything changed.
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
/*global document, window, clearTimeout, setTimeout */
|
|
45
|
-
|
|
46
|
-
var TuneBook = require('../api/abc_tunebook').TuneBook;
|
|
47
|
-
var parseCommon = require('../parse/abc_common');
|
|
48
|
-
var Parse = require('../parse/abc_parse');
|
|
49
|
-
var TextPrinter = require('../transform/abc2abc_write');
|
|
50
|
-
var EngraverController = require('../write/abc_engraver_controller');
|
|
51
|
-
var SynthController = require('../synth/synth-controller');
|
|
52
|
-
var supportsAudio = require('../synth/supports-audio');
|
|
53
|
-
|
|
54
|
-
// Polyfill for CustomEvent for old IE versions
|
|
55
|
-
try {
|
|
56
|
-
if (typeof window.CustomEvent !== "function") {
|
|
57
|
-
var CustomEvent = function (event, params) {
|
|
58
|
-
params = params || {bubbles: false, cancelable: false, detail: undefined};
|
|
59
|
-
var evt = document.createEvent('CustomEvent');
|
|
60
|
-
evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
|
|
61
|
-
return evt;
|
|
62
|
-
};
|
|
63
|
-
CustomEvent.prototype = window.Event.prototype;
|
|
64
|
-
window.CustomEvent = CustomEvent;
|
|
65
|
-
}
|
|
66
|
-
} catch (e) {
|
|
67
|
-
// if we aren't in a browser, this code will crash, but it is not needed then either.
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
var EditArea = function(textareaid) {
|
|
71
|
-
this.textarea = document.getElementById(textareaid);
|
|
72
|
-
this.initialText = this.textarea.value;
|
|
73
|
-
this.isDragging = false;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
EditArea.prototype.addSelectionListener = function(listener) {
|
|
77
|
-
this.textarea.onmousemove = function(ev) {
|
|
78
|
-
if (this.isDragging)
|
|
79
|
-
listener.fireSelectionChanged();
|
|
80
|
-
};
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
EditArea.prototype.addChangeListener = function(listener) {
|
|
84
|
-
this.changelistener = listener;
|
|
85
|
-
this.textarea.onkeyup = function() {
|
|
86
|
-
listener.fireChanged();
|
|
87
|
-
};
|
|
88
|
-
this.textarea.onmousedown = function() {
|
|
89
|
-
this.isDragging = true;
|
|
90
|
-
listener.fireSelectionChanged();
|
|
91
|
-
};
|
|
92
|
-
this.textarea.onmouseup = function() {
|
|
93
|
-
this.isDragging = false;
|
|
94
|
-
listener.fireChanged();
|
|
95
|
-
};
|
|
96
|
-
this.textarea.onchange = function() {
|
|
97
|
-
listener.fireChanged();
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
//TODO won't work under IE?
|
|
102
|
-
EditArea.prototype.getSelection = function() {
|
|
103
|
-
return {start: this.textarea.selectionStart, end: this.textarea.selectionEnd};
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
EditArea.prototype.setSelection = function(start, end) {
|
|
107
|
-
if(this.textarea.setSelectionRange)
|
|
108
|
-
this.textarea.setSelectionRange(start, end);
|
|
109
|
-
else if(this.textarea.createTextRange) {
|
|
110
|
-
// For IE8
|
|
111
|
-
var e = this.textarea.createTextRange();
|
|
112
|
-
e.collapse(true);
|
|
113
|
-
e.moveEnd('character', end);
|
|
114
|
-
e.moveStart('character', start);
|
|
115
|
-
e.select();
|
|
116
|
-
}
|
|
117
|
-
this.textarea.focus();
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
EditArea.prototype.getString = function() {
|
|
121
|
-
return this.textarea.value;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
EditArea.prototype.setString = function(str) {
|
|
125
|
-
this.textarea.value = str;
|
|
126
|
-
this.initialText = this.getString();
|
|
127
|
-
if (this.changelistener) {
|
|
128
|
-
this.changelistener.fireChanged();
|
|
129
|
-
}
|
|
130
|
-
};
|
|
131
|
-
|
|
132
|
-
EditArea.prototype.getElem = function() {
|
|
133
|
-
return this.textarea;
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
//
|
|
137
1
|
// window.ABCJS.Editor:
|
|
138
2
|
//
|
|
139
3
|
// constructor(editarea, params)
|
|
@@ -158,18 +22,13 @@ EditArea.prototype.getElem = function() {
|
|
|
158
22
|
// adds or removes the class abc_textarea_readonly, and adds or removes the attribute readonly=yes
|
|
159
23
|
// - setDirtyStyle(bool)
|
|
160
24
|
// adds or removes the class abc_textarea_dirty
|
|
161
|
-
// - renderTune(abc, parserparams, div)
|
|
162
|
-
// Immediately renders the tune. (Useful for creating the SVG output behind the scenes, if div is hidden)
|
|
163
|
-
// string abc: the ABC text
|
|
164
|
-
// parserparams: params to send to the parser
|
|
165
|
-
// div: the HTML id to render to.
|
|
166
25
|
// - modelChanged()
|
|
167
26
|
// Called when the model has been changed to trigger re-rendering
|
|
168
27
|
// - parseABC()
|
|
169
28
|
// Called internally by fireChanged()
|
|
170
29
|
// returns true if there has been a change since last call.
|
|
171
30
|
// - updateSelection()
|
|
172
|
-
// Called when the user has changed the selection. This calls the
|
|
31
|
+
// Called when the user has changed the selection. This calls the engraver to show the selection.
|
|
173
32
|
// - fireSelectionChanged()
|
|
174
33
|
// Called by the textarea object when the user has changed the selection.
|
|
175
34
|
// - paramChanged(engraverparams)
|
|
@@ -181,43 +40,65 @@ EditArea.prototype.getElem = function() {
|
|
|
181
40
|
// - isDirty()
|
|
182
41
|
// Returns true or false, whether the textarea contains the same text that it started with.
|
|
183
42
|
// - highlight(abcelem)
|
|
184
|
-
// Called by the
|
|
43
|
+
// Called by the engraver to highlight an area.
|
|
185
44
|
// - pause(bool)
|
|
186
45
|
// Stops the automatic rendering when the user is typing.
|
|
187
46
|
//
|
|
47
|
+
var parseCommon = require('../parse/abc_common');
|
|
48
|
+
var SynthController = require('../synth/synth-controller');
|
|
49
|
+
var supportsAudio = require('../synth/supports-audio');
|
|
50
|
+
var renderAbc = require('../api/abc_tunebook_svg');
|
|
51
|
+
var EditArea = require('./abc_editarea');
|
|
188
52
|
|
|
189
|
-
|
|
190
|
-
//
|
|
191
|
-
|
|
53
|
+
function gatherAbcParams(params) {
|
|
54
|
+
// There used to be a bunch of ways parameters can be passed in. This just simplifies it.
|
|
55
|
+
var abcjsParams = {};
|
|
192
56
|
var key;
|
|
193
57
|
if (params.abcjsParams) {
|
|
194
58
|
for (key in params.abcjsParams) {
|
|
195
59
|
if (params.abcjsParams.hasOwnProperty(key)) {
|
|
196
|
-
|
|
60
|
+
abcjsParams[key] = params.abcjsParams[key];
|
|
197
61
|
}
|
|
198
62
|
}
|
|
199
63
|
}
|
|
200
64
|
if (params.midi_options) {
|
|
201
65
|
for (key in params.midi_options) {
|
|
202
66
|
if (params.midi_options.hasOwnProperty(key)) {
|
|
203
|
-
|
|
67
|
+
abcjsParams[key] = params.midi_options[key];
|
|
204
68
|
}
|
|
205
69
|
}
|
|
206
70
|
}
|
|
207
71
|
if (params.parser_options) {
|
|
208
72
|
for (key in params.parser_options) {
|
|
209
73
|
if (params.parser_options.hasOwnProperty(key)) {
|
|
210
|
-
|
|
74
|
+
abcjsParams[key] = params.parser_options[key];
|
|
211
75
|
}
|
|
212
76
|
}
|
|
213
77
|
}
|
|
214
78
|
if (params.render_options) {
|
|
215
79
|
for (key in params.render_options) {
|
|
216
80
|
if (params.render_options.hasOwnProperty(key)) {
|
|
217
|
-
|
|
81
|
+
abcjsParams[key] = params.render_options[key];
|
|
218
82
|
}
|
|
219
83
|
}
|
|
220
84
|
}
|
|
85
|
+
/*
|
|
86
|
+
if (params.tablature_options) {
|
|
87
|
+
abcjsParams['tablatures'] = params.tablature_options;
|
|
88
|
+
}
|
|
89
|
+
*/
|
|
90
|
+
if (abcjsParams.tablature) {
|
|
91
|
+
if (params.warnings_id) {
|
|
92
|
+
// store for plugin error handling
|
|
93
|
+
abcjsParams.tablature.warnings_id = params.warnings_id;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return abcjsParams;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
var Editor = function(editarea, params) {
|
|
100
|
+
// Copy all the options that will be passed through
|
|
101
|
+
this.abcjsParams = gatherAbcParams(params);
|
|
221
102
|
|
|
222
103
|
if (params.indicate_changed)
|
|
223
104
|
this.indicate_changed = true;
|
|
@@ -230,25 +111,30 @@ var Editor = function(editarea, params) {
|
|
|
230
111
|
this.editarea.addChangeListener(this);
|
|
231
112
|
|
|
232
113
|
if (params.canvas_id) {
|
|
233
|
-
this.div =
|
|
114
|
+
this.div = params.canvas_id;
|
|
234
115
|
} else if (params.paper_id) {
|
|
235
|
-
this.div =
|
|
116
|
+
this.div = params.paper_id;
|
|
236
117
|
} else {
|
|
237
118
|
this.div = document.createElement("DIV");
|
|
238
119
|
this.editarea.getElem().parentNode.insertBefore(this.div, this.editarea.getElem());
|
|
239
120
|
}
|
|
121
|
+
if (typeof this.div === 'string')
|
|
122
|
+
this.div = document.getElementById(this.div);
|
|
240
123
|
|
|
241
124
|
if (params.selectionChangeCallback) {
|
|
242
125
|
this.selectionChangeCallback = params.selectionChangeCallback;
|
|
243
126
|
}
|
|
244
127
|
|
|
128
|
+
this.clientClickListener = this.abcjsParams.clickListener;
|
|
129
|
+
this.abcjsParams.clickListener = this.highlight.bind(this);
|
|
130
|
+
|
|
245
131
|
if (params.synth) {
|
|
246
132
|
if (supportsAudio()) {
|
|
247
133
|
this.synth = {
|
|
248
134
|
el: params.synth.el,
|
|
249
135
|
cursorControl: params.synth.cursorControl,
|
|
250
136
|
options: params.synth.options
|
|
251
|
-
}
|
|
137
|
+
};
|
|
252
138
|
}
|
|
253
139
|
}
|
|
254
140
|
// If the user wants midi, then store the elements that it will be written to. The element could either be passed in as an id,
|
|
@@ -269,21 +155,20 @@ var Editor = function(editarea, params) {
|
|
|
269
155
|
}
|
|
270
156
|
}
|
|
271
157
|
|
|
272
|
-
if (params.
|
|
273
|
-
|
|
158
|
+
if (params.warnings_id) {
|
|
159
|
+
if (typeof(params.warnings_id) === "string")
|
|
274
160
|
this.warningsdiv = document.getElementById(params.warnings_id);
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
161
|
+
else
|
|
162
|
+
this.warningsdiv = params.warnings_id;
|
|
163
|
+
} else if (params.generate_warnings) {
|
|
164
|
+
this.warningsdiv = document.createElement("div");
|
|
165
|
+
this.div.parentNode.insertBefore(this.warningsdiv, this.div);
|
|
278
166
|
}
|
|
279
167
|
|
|
280
168
|
this.onchangeCallback = params.onchange;
|
|
281
169
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
this.abcjsParams.editable = true;
|
|
285
|
-
}
|
|
286
|
-
this.oldt = "";
|
|
170
|
+
this.currentAbc = "";
|
|
171
|
+
this.tunes = [];
|
|
287
172
|
this.bReentry = false;
|
|
288
173
|
this.parseABC();
|
|
289
174
|
this.modelChanged();
|
|
@@ -319,15 +204,6 @@ var Editor = function(editarea, params) {
|
|
|
319
204
|
};
|
|
320
205
|
};
|
|
321
206
|
|
|
322
|
-
Editor.prototype.renderTune = function(abc, params, div) {
|
|
323
|
-
var tunebook = new TuneBook(abc);
|
|
324
|
-
var abcParser = Parse();
|
|
325
|
-
abcParser.parse(tunebook.tunes[0].abc, params, tunebook.tunes[0].startPos - tunebook.header.length); //TODO handle multiple tunes
|
|
326
|
-
var tune = abcParser.getTune();
|
|
327
|
-
var engraver_controller = new EngraverController(div, this.abcjsParams);
|
|
328
|
-
engraver_controller.engraveABC(tune);
|
|
329
|
-
};
|
|
330
|
-
|
|
331
207
|
Editor.prototype.redrawMidi = function() {
|
|
332
208
|
if (this.generate_midi && !this.midiPause) {
|
|
333
209
|
var event = new window.CustomEvent("generateMidi", {
|
|
@@ -342,47 +218,44 @@ Editor.prototype.redrawMidi = function() {
|
|
|
342
218
|
window.dispatchEvent(event);
|
|
343
219
|
}
|
|
344
220
|
if (this.synth) {
|
|
221
|
+
var userAction = this.synth.synthControl; // Can't really tell if there was a user action before drawing, but we assume that if the synthControl was created already there was a user action.
|
|
345
222
|
if (!this.synth.synthControl) {
|
|
346
223
|
this.synth.synthControl = new SynthController();
|
|
347
224
|
this.synth.synthControl.load(this.synth.el, this.synth.cursorControl, this.synth.options);
|
|
348
225
|
}
|
|
349
|
-
this.synth.synthControl.setTune(this.tunes[0],
|
|
226
|
+
this.synth.synthControl.setTune(this.tunes[0], userAction, this.synth.options);
|
|
350
227
|
}
|
|
351
228
|
};
|
|
352
229
|
|
|
353
230
|
Editor.prototype.modelChanged = function() {
|
|
354
|
-
if (this.tunes === undefined) {
|
|
355
|
-
if (this.downloadMidi !== undefined)
|
|
356
|
-
this.downloadMidi.innerHTML = "";
|
|
357
|
-
if (this.inlineMidi !== undefined)
|
|
358
|
-
this.inlineMidi.innerHTML = "";
|
|
359
|
-
this.div.innerHTML = "";
|
|
360
|
-
return;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
231
|
if (this.bReentry)
|
|
364
232
|
return; // TODO is this likely? maybe, if we rewrite abc immediately w/ abc2abc
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
233
|
+
this.bReentry = true;
|
|
234
|
+
try {
|
|
235
|
+
this.timerId = null;
|
|
236
|
+
if (this.synth && this.synth.synthControl)
|
|
237
|
+
this.synth.synthControl.disable(true);
|
|
238
|
+
|
|
239
|
+
this.tunes = renderAbc(this.div, this.currentAbc, this.abcjsParams);
|
|
240
|
+
if (this.tunes.length > 0) {
|
|
241
|
+
this.warnings = this.tunes[0].warnings;
|
|
242
|
+
}
|
|
243
|
+
this.redrawMidi();
|
|
244
|
+
} catch(error) {
|
|
245
|
+
console.error("ABCJS error: ", error);
|
|
246
|
+
if (!this.warnings)
|
|
247
|
+
this.warnings = [];
|
|
248
|
+
this.warnings.push(error.message);
|
|
249
|
+
}
|
|
372
250
|
|
|
373
251
|
if (this.warningsdiv) {
|
|
374
252
|
this.warningsdiv.innerHTML = (this.warnings) ? this.warnings.join("<br />") : "No errors";
|
|
375
253
|
}
|
|
376
|
-
if (this.target) {
|
|
377
|
-
var textprinter = new TextPrinter(this.target, true);
|
|
378
|
-
textprinter.printABC(this.tunes[0]); //TODO handle multiple tunes
|
|
379
|
-
}
|
|
380
|
-
this.engraver_controller.addSelectListener(this.highlight.bind(this));
|
|
381
254
|
this.updateSelection();
|
|
382
255
|
this.bReentry = false;
|
|
383
256
|
};
|
|
384
257
|
|
|
385
|
-
// Call this to reparse in response to the
|
|
258
|
+
// Call this to reparse in response to the client changing the parameters on the fly
|
|
386
259
|
Editor.prototype.paramChanged = function(engraverParams) {
|
|
387
260
|
if (engraverParams) {
|
|
388
261
|
for (var key in engraverParams) {
|
|
@@ -391,51 +264,48 @@ Editor.prototype.paramChanged = function(engraverParams) {
|
|
|
391
264
|
}
|
|
392
265
|
}
|
|
393
266
|
}
|
|
394
|
-
this.
|
|
267
|
+
this.currentAbc = "";
|
|
268
|
+
this.fireChanged();
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
Editor.prototype.synthParamChanged = function(options) {
|
|
272
|
+
if (!this.synth)
|
|
273
|
+
return;
|
|
274
|
+
this.synth.options = {};
|
|
275
|
+
if (options) {
|
|
276
|
+
for (var key in options) {
|
|
277
|
+
if (options.hasOwnProperty(key)) {
|
|
278
|
+
this.synth.options[key] = options[key];
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
this.currentAbc = "";
|
|
395
283
|
this.fireChanged();
|
|
396
284
|
};
|
|
397
285
|
|
|
398
286
|
// return true if the model has changed
|
|
399
287
|
Editor.prototype.parseABC = function() {
|
|
400
288
|
var t = this.editarea.getString();
|
|
401
|
-
if (t===this.
|
|
289
|
+
if (t===this.currentAbc) {
|
|
402
290
|
this.updateSelection();
|
|
403
291
|
return false;
|
|
404
292
|
}
|
|
405
293
|
|
|
406
|
-
this.
|
|
407
|
-
if (t === "") {
|
|
408
|
-
this.tunes = undefined;
|
|
409
|
-
this.warnings = "";
|
|
410
|
-
return true;
|
|
411
|
-
}
|
|
412
|
-
var tunebook = new TuneBook(t);
|
|
413
|
-
|
|
414
|
-
this.tunes = [];
|
|
415
|
-
this.startPos = [];
|
|
416
|
-
this.warnings = [];
|
|
417
|
-
for (var i=0; i<tunebook.tunes.length; i++) {
|
|
418
|
-
var abcParser = new Parse();
|
|
419
|
-
abcParser.parse(tunebook.tunes[i].abc, this.abcjsParams, tunebook.tunes[i].startPos - tunebook.header.length);
|
|
420
|
-
this.tunes[i] = abcParser.getTune();
|
|
421
|
-
this.startPos[i] = tunebook.tunes[i].startPos;
|
|
422
|
-
var warnings = abcParser.getWarnings() || [];
|
|
423
|
-
for (var j=0; j<warnings.length; j++) {
|
|
424
|
-
this.warnings.push(warnings[j]);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
294
|
+
this.currentAbc = t;
|
|
427
295
|
return true;
|
|
428
296
|
};
|
|
429
297
|
|
|
430
298
|
Editor.prototype.updateSelection = function() {
|
|
431
299
|
var selection = this.editarea.getSelection();
|
|
432
300
|
try {
|
|
433
|
-
|
|
301
|
+
if (this.tunes.length > 0 && this.tunes[0].engraver)
|
|
302
|
+
this.tunes[0].engraver.rangeHighlight(selection.start, selection.end);
|
|
434
303
|
} catch (e) {} // maybe printer isn't defined yet?
|
|
435
304
|
if (this.selectionChangeCallback)
|
|
436
305
|
this.selectionChangeCallback(selection.start, selection.end);
|
|
437
306
|
};
|
|
438
307
|
|
|
308
|
+
// Called when the textarea's selection is in the process of changing (after mouse down, dragging, or keyboard arrows)
|
|
439
309
|
Editor.prototype.fireSelectionChanged = function() {
|
|
440
310
|
this.updateSelection();
|
|
441
311
|
};
|
|
@@ -470,7 +340,7 @@ Editor.prototype.setDirtyStyle = function(isDirty) {
|
|
|
470
340
|
}
|
|
471
341
|
};
|
|
472
342
|
|
|
473
|
-
// call when abc text is changed and needs re-parsing
|
|
343
|
+
// call when the textarea alerts us that the abc text is changed and needs re-parsing
|
|
474
344
|
Editor.prototype.fireChanged = function() {
|
|
475
345
|
if (this.bIsPaused)
|
|
476
346
|
return;
|
|
@@ -503,13 +373,15 @@ Editor.prototype.isDirty = function() {
|
|
|
503
373
|
return this.editarea.initialText !== this.editarea.getString();
|
|
504
374
|
};
|
|
505
375
|
|
|
506
|
-
Editor.prototype.highlight = function(abcelem, tuneNumber, classes) {
|
|
376
|
+
Editor.prototype.highlight = function(abcelem, tuneNumber, classes, analysis, drag, mouseEvent) {
|
|
507
377
|
// TODO-PER: The marker appears to get off by one for each tune parsed. I'm not sure why, but adding the tuneNumber in corrects it for the time being.
|
|
508
378
|
// var offset = (tuneNumber !== undefined) ? this.startPos[tuneNumber] + tuneNumber : 0;
|
|
509
379
|
|
|
510
380
|
this.editarea.setSelection(abcelem.startChar, abcelem.endChar);
|
|
511
381
|
if (this.selectionChangeCallback)
|
|
512
382
|
this.selectionChangeCallback(abcelem.startChar, abcelem.endChar);
|
|
383
|
+
if (this.clientClickListener)
|
|
384
|
+
this.clientClickListener(abcelem, tuneNumber, classes, analysis, drag, mouseEvent);
|
|
513
385
|
};
|
|
514
386
|
|
|
515
387
|
Editor.prototype.pause = function(shouldPause) {
|
|
@@ -519,6 +391,8 @@ Editor.prototype.pause = function(shouldPause) {
|
|
|
519
391
|
};
|
|
520
392
|
|
|
521
393
|
Editor.prototype.millisecondsPerMeasure = function() {
|
|
394
|
+
if (!this.synth || !this.synth.synthControl || !this.synth.synthControl.visualObj)
|
|
395
|
+
return 0;
|
|
522
396
|
return this.synth.synthControl.visualObj.millisecondsPerMeasure();
|
|
523
397
|
};
|
|
524
398
|
|
|
@@ -1,23 +1,6 @@
|
|
|
1
1
|
// abc_midi_create.js: Turn a linear series of events into a midi file.
|
|
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
2
|
|
|
17
|
-
var
|
|
18
|
-
var Preparer = require('./abc_midi_js_preparer');
|
|
19
|
-
var rendererFactory = require('./abc_midi_renderer');
|
|
20
|
-
var sequence = require('./abc_midi_sequencer');
|
|
3
|
+
var rendererFactory = require('../synth/abc_midi_renderer');
|
|
21
4
|
|
|
22
5
|
var create;
|
|
23
6
|
|
|
@@ -28,22 +11,21 @@ var create;
|
|
|
28
11
|
|
|
29
12
|
create = function(abcTune, options) {
|
|
30
13
|
if (options === undefined) options = {};
|
|
31
|
-
var
|
|
32
|
-
var commands = flatten(sequenceInst, options);
|
|
14
|
+
var commands = abcTune.setUpAudio(options);
|
|
33
15
|
var midi = rendererFactory();
|
|
34
|
-
var midiJs = new Preparer();
|
|
35
16
|
|
|
36
17
|
var title = abcTune.metaText ? abcTune.metaText.title : undefined;
|
|
37
18
|
if (title && title.length > 128)
|
|
38
19
|
title = title.substring(0,124) + '...';
|
|
39
20
|
var key = abcTune.getKeySignature();
|
|
40
21
|
var time = abcTune.getMeterFraction();
|
|
22
|
+
var beatsPerSecond = commands.tempo / 60;
|
|
23
|
+
//var beatLength = abcTune.getBeatLength();
|
|
41
24
|
midi.setGlobalInfo(commands.tempo, title, key, time);
|
|
42
|
-
midiJs.setGlobalInfo(commands.tempo, title);
|
|
43
25
|
|
|
44
26
|
for (var i = 0; i < commands.tracks.length; i++) {
|
|
45
27
|
midi.startTrack();
|
|
46
|
-
|
|
28
|
+
var notePlacement = {};
|
|
47
29
|
for (var j = 0; j < commands.tracks[i].length; j++) {
|
|
48
30
|
var event = commands.tracks[i][j];
|
|
49
31
|
switch (event.cmd) {
|
|
@@ -51,46 +33,62 @@ var create;
|
|
|
51
33
|
midi.setText(event.type, event.text);
|
|
52
34
|
break;
|
|
53
35
|
case 'program':
|
|
54
|
-
|
|
36
|
+
var pan = 0;
|
|
37
|
+
if (options.pan && options.pan.length > i)
|
|
38
|
+
pan = options.pan[i];
|
|
39
|
+
midi.setChannel(event.channel, pan);
|
|
55
40
|
midi.setInstrument(event.instrument);
|
|
56
|
-
midiJs.setChannel(event.channel);
|
|
57
|
-
midiJs.setInstrument(event.instrument);
|
|
58
41
|
break;
|
|
59
|
-
case '
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
42
|
+
case 'note':
|
|
43
|
+
var gapLengthInBeats = event.gap * beatsPerSecond;
|
|
44
|
+
var start = event.start;
|
|
45
|
+
// The staccato and legato are indicated by event.gap.
|
|
46
|
+
// event.gap is in seconds but the durations are in whole notes.
|
|
47
|
+
var end = start + event.duration - gapLengthInBeats;
|
|
48
|
+
if (!notePlacement[start])
|
|
49
|
+
notePlacement[start] = [];
|
|
50
|
+
notePlacement[start].push({ pitch: event.pitch, volume: event.volume, cents: event.cents });
|
|
51
|
+
if (!notePlacement[end])
|
|
52
|
+
notePlacement[end] = [];
|
|
53
|
+
notePlacement[end].push({ pitch: event.pitch, volume: 0 });
|
|
70
54
|
break;
|
|
71
55
|
default:
|
|
72
56
|
console.log("MIDI create Unknown: " + event.cmd);
|
|
73
57
|
}
|
|
74
58
|
}
|
|
59
|
+
addNotes(midi, notePlacement, baseDuration);
|
|
75
60
|
midi.endTrack();
|
|
76
|
-
midiJs.endTrack();
|
|
77
61
|
}
|
|
78
62
|
|
|
79
|
-
|
|
80
|
-
var midiInline = midiJs.getData();
|
|
81
|
-
if (options.generateInline === undefined) // default is to generate inline controls.
|
|
82
|
-
options.generateInline = true;
|
|
83
|
-
if (options.generateInline && options.generateDownload)
|
|
84
|
-
return { download: midiFile, inline: midiInline };
|
|
85
|
-
else if (options.generateInline)
|
|
86
|
-
return midiInline;
|
|
87
|
-
else
|
|
88
|
-
return midiFile;
|
|
63
|
+
return midi.getData();
|
|
89
64
|
};
|
|
90
65
|
|
|
91
|
-
function
|
|
92
|
-
|
|
66
|
+
function addNotes(midi, notePlacement, baseDuration) {
|
|
67
|
+
var times = Object.keys(notePlacement);
|
|
68
|
+
for (var h = 0; h < times.length; h++)
|
|
69
|
+
times[h] = parseFloat(times[h]);
|
|
70
|
+
times.sort(function(a,b) {
|
|
71
|
+
return a - b;
|
|
72
|
+
});
|
|
73
|
+
var lastTime = 0;
|
|
74
|
+
for (var i = 0; i < times.length; i++) {
|
|
75
|
+
var events = notePlacement[times[i]];
|
|
76
|
+
if (times[i] > lastTime) {
|
|
77
|
+
var distance = (times[i] - lastTime) * baseDuration;
|
|
78
|
+
midi.addRest(distance);
|
|
79
|
+
lastTime = times[i];
|
|
80
|
+
}
|
|
81
|
+
for (var j = 0; j < events.length; j++) {
|
|
82
|
+
var event = events[j];
|
|
83
|
+
if (event.volume) {
|
|
84
|
+
midi.startNote(event.pitch, event.volume, event.cents);
|
|
85
|
+
} else {
|
|
86
|
+
midi.endNote(event.pitch);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
93
90
|
}
|
|
91
|
+
|
|
94
92
|
})();
|
|
95
93
|
|
|
96
94
|
module.exports = create;
|
package/src/parse/abc_common.js
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
// abc_parse.js: parses a string representing ABC Music Notation into a usable internal structure.
|
|
2
|
-
// Copyright (C) 2010-2020 Paul Rosen (paul at paulrosen dot net)
|
|
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
2
|
|
|
17
3
|
var parseCommon = {};
|
|
18
4
|
|