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,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 engraver_controller to show the selection.
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 engraver_controller to highlight an area.
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
- var Editor = function(editarea, params) {
190
- // Copy all the options that will be passed through
191
- this.abcjsParams = {};
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
- this.abcjsParams[key] = params.abcjsParams[key];
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
- this.abcjsParams[key] = params.midi_options[key];
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
- this.abcjsParams[key] = params.parser_options[key];
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
- this.abcjsParams[key] = params.render_options[key];
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 = document.getElementById(params.canvas_id);
114
+ this.div = params.canvas_id;
234
115
  } else if (params.paper_id) {
235
- this.div = document.getElementById(params.paper_id);
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.generate_warnings || params.warnings_id) {
273
- if (params.warnings_id) {
158
+ if (params.warnings_id) {
159
+ if (typeof(params.warnings_id) === "string")
274
160
  this.warningsdiv = document.getElementById(params.warnings_id);
275
- } else {
276
- this.warningsdiv = this.div;
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
- if (params.gui) {
283
- this.target = document.getElementById(editarea);
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], false, this.abcjsParams);
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
- this.bReentry = true;
366
- this.timerId = null;
367
- this.div.innerHTML = "";
368
- this.engraver_controller = new EngraverController(this.div, this.abcjsParams);
369
- this.engraver_controller.engraveABC(this.tunes);
370
- this.tunes[0].engraver = this.engraver_controller; // TODO-PER: We actually want an output object for each tune, not the entire controller. When refactoring, don't save data in the controller.
371
- this.redrawMidi();
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 printing parameters changing
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.oldt = "";
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.oldt) {
289
+ if (t===this.currentAbc) {
402
290
  this.updateSelection();
403
291
  return false;
404
292
  }
405
293
 
406
- this.oldt = t;
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
- this.engraver_controller.rangeHighlight(selection.start, selection.end);
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 flatten = require('./abc_midi_flattener');
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 sequenceInst = sequence(abcTune, options);
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
- midiJs.startTrack();
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
- midi.setChannel(event.channel);
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 'start':
60
- midi.startNote(convertPitch(event.pitch), event.volume);
61
- midiJs.startNote(convertPitch(event.pitch), event.volume);
62
- break;
63
- case 'stop':
64
- midi.endNote(convertPitch(event.pitch));
65
- midiJs.endNote(convertPitch(event.pitch));
66
- break;
67
- case 'move':
68
- midi.addRest(event.duration * baseDuration);
69
- midiJs.addRest(event.duration * baseDuration);
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
- var midiFile = midi.getData();
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 convertPitch(pitch) {
92
- return 60 + pitch;
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;
@@ -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