abcjs 6.0.0-beta.8 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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 +959 -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 +28232 -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 +239 -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 +8 -18
  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 +15256 -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,41 +1,25 @@
1
1
  // abc_parse_header.js: parses a the header fields from 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
-
17
- /*global window */
18
2
 
19
3
  var parseCommon = require('./abc_common');
20
4
  var parseDirective = require('./abc_parse_directive');
21
5
  var parseKeyVoice = require('./abc_parse_key_voice');
22
6
 
23
- var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
7
+ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
24
8
  this.reset = function(tokenizer, warn, multilineVars, tune) {
25
- parseKeyVoice.initialize(tokenizer, warn, multilineVars, tune);
26
- parseDirective.initialize(tokenizer, warn, multilineVars, tune);
9
+ parseKeyVoice.initialize(tokenizer, warn, multilineVars, tune, tuneBuilder);
10
+ parseDirective.initialize(tokenizer, warn, multilineVars, tune, tuneBuilder);
27
11
  };
28
12
  this.reset(tokenizer, warn, multilineVars, tune);
29
13
 
30
14
  this.setTitle = function(title) {
31
15
  if (multilineVars.hasMainTitle)
32
- tune.addSubtitle(tokenizer.translateString(tokenizer.stripComment(title))); // display secondary title
16
+ tuneBuilder.addSubtitle(tokenizer.translateString(tokenizer.stripComment(title)), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+title.length+2}); // display secondary title
33
17
  else
34
18
  {
35
19
  var titleStr = tokenizer.translateString(tokenizer.theReverser(tokenizer.stripComment(title)));
36
20
  if (multilineVars.titlecaps)
37
21
  titleStr = titleStr.toUpperCase();
38
- tune.addMetaText("title", titleStr);
22
+ tuneBuilder.addMetaText("title", titleStr, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+title.length+2});
39
23
  multilineVars.hasMainTitle = true;
40
24
  }
41
25
  };
@@ -251,7 +235,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
251
235
  prestissimo: 210,
252
236
  };
253
237
 
254
- this.setTempo = function(line, start, end) {
238
+ this.setTempo = function(line, start, end, iChar) {
255
239
  //Q - tempo; can be used to specify the notes per minute, e.g. If
256
240
  //the meter denominator is a 4 note then Q:120 or Q:C=120
257
241
  //is 120 quarter notes per minute. Similarly Q:C3=40 would be 40
@@ -271,7 +255,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
271
255
 
272
256
  if (tokens.length === 0) throw "Missing parameter in Q: field";
273
257
 
274
- var tempo = {};
258
+ var tempo = { startChar: iChar+start-2, endChar: iChar+end };
275
259
  var delaySet = true;
276
260
  var token = tokens.shift();
277
261
  if (token.type === 'quote') {
@@ -358,7 +342,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
358
342
  }
359
343
  };
360
344
 
361
- this.letter_to_inline_header = function(line, i)
345
+ this.letter_to_inline_header = function(line, i, startLine)
362
346
  {
363
347
  var ws = tokenizer.eatWhiteSpace(line, i);
364
348
  i +=ws;
@@ -374,32 +358,41 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
374
358
  return [ e-i+1+ws ];
375
359
  case "[M:":
376
360
  var meter = this.setMeter(line.substring(i+3, e));
377
- if (tune.hasBeginMusic() && meter)
378
- tune.appendStartingElement('meter', startChar, endChar, meter);
361
+ if (tuneBuilder.hasBeginMusic() && meter)
362
+ tuneBuilder.appendStartingElement('meter', startChar, endChar, meter);
379
363
  else
380
364
  multilineVars.meter = meter;
381
365
  return [ e-i+1+ws ];
382
366
  case "[K:":
383
367
  var result = parseKeyVoice.parseKey(line.substring(i+3, e));
384
- if (result.foundClef && tune.hasBeginMusic())
385
- tune.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
386
- if (result.foundKey && tune.hasBeginMusic())
387
- tune.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
368
+ if (result.foundClef && tuneBuilder.hasBeginMusic())
369
+ tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
370
+ if (result.foundKey && tuneBuilder.hasBeginMusic())
371
+ tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
388
372
  return [ e-i+1+ws ];
389
373
  case "[P:":
390
- if (tune.lines.length <= tune.lineNum)
374
+ if (startLine || tune.lines.length <= tune.lineNum)
391
375
  multilineVars.partForNextLine = { title: line.substring(i+3, e), startChar: startChar, endChar: endChar };
392
376
  else
393
- tune.appendElement('part', startChar, endChar, {title: line.substring(i+3, e)});
377
+ tuneBuilder.appendElement('part', startChar, endChar, {title: line.substring(i+3, e)});
394
378
  return [ e-i+1+ws ];
395
379
  case "[L:":
396
380
  this.setDefaultLength(line, i+3, e);
397
381
  return [ e-i+1+ws ];
398
382
  case "[Q:":
399
383
  if (e > 0) {
400
- var tempo = this.setTempo(line, i+3, e);
401
- if (tempo.type === 'delaySet') tune.appendElement('tempo', startChar, endChar, this.calcTempo(tempo.tempo));
402
- else if (tempo.type === 'immediate') tune.appendElement('tempo', startChar, endChar, tempo.tempo);
384
+ var tempo = this.setTempo(line, i+3, e, multilineVars.iChar);
385
+ if (tempo.type === 'delaySet') {
386
+ if (tuneBuilder.hasBeginMusic())
387
+ tuneBuilder.appendElement('tempo', startChar, endChar, this.calcTempo(tempo.tempo));
388
+ else
389
+ multilineVars.tempoForNextLine = ['tempo', startChar, endChar, this.calcTempo(tempo.tempo)]
390
+ } else if (tempo.type === 'immediate') {
391
+ if (!startLine && tuneBuilder.hasBeginMusic())
392
+ tuneBuilder.appendElement('tempo', startChar, endChar, tempo.tempo);
393
+ else
394
+ multilineVars.tempoForNextLine = ['tempo', startChar, endChar, tempo.tempo]
395
+ }
403
396
  return [ e-i+1+ws, line.charAt(i+1), line.substring(i+3, e)];
404
397
  }
405
398
  break;
@@ -429,19 +422,19 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
429
422
  return [ line.length ];
430
423
  case "M:":
431
424
  var meter = this.setMeter(line.substring(i+2));
432
- if (tune.hasBeginMusic() && meter)
433
- tune.appendStartingElement('meter', multilineVars.iChar + i, multilineVars.iChar + line.length, meter);
425
+ if (tuneBuilder.hasBeginMusic() && meter)
426
+ tuneBuilder.appendStartingElement('meter', multilineVars.iChar + i, multilineVars.iChar + line.length, meter);
434
427
  return [ line.length ];
435
428
  case "K:":
436
429
  var result = parseKeyVoice.parseKey(line.substring(i+2));
437
- if (result.foundClef && tune.hasBeginMusic())
438
- tune.appendStartingElement('clef', multilineVars.iChar + i, multilineVars.iChar + line.length, multilineVars.clef);
439
- if (result.foundKey && tune.hasBeginMusic())
440
- tune.appendStartingElement('key', multilineVars.iChar + i, multilineVars.iChar + line.length, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
430
+ if (result.foundClef && tuneBuilder.hasBeginMusic())
431
+ tuneBuilder.appendStartingElement('clef', multilineVars.iChar + i, multilineVars.iChar + line.length, multilineVars.clef);
432
+ if (result.foundKey && tuneBuilder.hasBeginMusic())
433
+ tuneBuilder.appendStartingElement('key', multilineVars.iChar + i, multilineVars.iChar + line.length, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
441
434
  return [ line.length ];
442
435
  case "P:":
443
- if (tune.hasBeginMusic())
444
- tune.appendElement('part', multilineVars.iChar + i, multilineVars.iChar + line.length, {title: line.substring(i+2)});
436
+ if (tuneBuilder.hasBeginMusic())
437
+ tuneBuilder.appendElement('part', multilineVars.iChar + i, multilineVars.iChar + line.length, {title: line.substring(i+2)});
445
438
  return [ line.length ];
446
439
  case "L:":
447
440
  this.setDefaultLength(line, i+2, line.length);
@@ -449,9 +442,9 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
449
442
  case "Q:":
450
443
  var e = line.indexOf('\x12', i+2);
451
444
  if (e === -1) e = line.length;
452
- var tempo = this.setTempo(line, i+2, e);
453
- if (tempo.type === 'delaySet') tune.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, this.calcTempo(tempo.tempo));
454
- else if (tempo.type === 'immediate') tune.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, tempo.tempo);
445
+ var tempo = this.setTempo(line, i+2, e, multilineVars.iChar);
446
+ if (tempo.type === 'delaySet') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, this.calcTempo(tempo.tempo));
447
+ else if (tempo.type === 'immediate') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, tempo.tempo);
455
448
  return [ e, line.charAt(i), parseCommon.strip(line.substring(i+2))];
456
449
  case "V:":
457
450
  parseKeyVoice.parseVoice(line, i+2, line.length);
@@ -481,110 +474,88 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune) {
481
474
  };
482
475
 
483
476
  this.parseHeader = function(line) {
484
- if (parseCommon.startsWith(line, '%%')) {
485
- var err = parseDirective.addDirective(line.substring(2));
486
- if (err) warn(err, line, 2);
487
- return {};
488
- }
489
- var i = line.indexOf('%');
490
- if (i >= 0)
491
- line = line.substring(0, i);
492
- line = line.replace(/\s+$/, '');
493
-
494
- if (line.length === 0)
477
+ var field = metaTextHeaders[line.charAt(0)];
478
+ if (field !== undefined) {
479
+ if (field === 'unalignedWords')
480
+ tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line.substring(2)))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
481
+ else
482
+ tuneBuilder.addMetaText(field, tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
495
483
  return {};
496
-
497
- if (line.length >= 2) {
498
- if (line.charAt(1) === ':') {
499
- var nextLine = "";
500
- if (line.indexOf('\x12') >= 0 && line.charAt(0) !== 'w') { // w: is the only header field that can have a continuation.
501
- nextLine = line.substring(line.indexOf('\x12')+1);
502
- line = line.substring(0, line.indexOf('\x12')); //This handles a continuation mark on a header field
503
- }
504
- var field = metaTextHeaders[line.charAt(0)];
505
- if (field !== undefined) {
506
- if (field === 'unalignedWords')
507
- tune.addMetaTextArray(field, parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line.substring(2)))));
484
+ } else {
485
+ var startChar = multilineVars.iChar;
486
+ var endChar = startChar + line.length;
487
+ switch(line.charAt(0))
488
+ {
489
+ case 'H':
490
+ tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
491
+ line = tokenizer.peekLine()
492
+ while (line && line.charAt(1) !== ':') {
493
+ tokenizer.nextLine()
494
+ tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line)), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
495
+ line = tokenizer.peekLine()
496
+ }
497
+ break;
498
+ case 'K':
499
+ // since the key is the last thing that can happen in the header, we can resolve the tempo now
500
+ this.resolveTempo();
501
+ var result = parseKeyVoice.parseKey(line.substring(2));
502
+ if (!multilineVars.is_in_header && tuneBuilder.hasBeginMusic()) {
503
+ if (result.foundClef)
504
+ tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
505
+ if (result.foundKey)
506
+ tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
507
+ }
508
+ multilineVars.is_in_header = false; // The first key signifies the end of the header.
509
+ break;
510
+ case 'L':
511
+ this.setDefaultLength(line, 2, line.length);
512
+ break;
513
+ case 'M':
514
+ multilineVars.origMeter = multilineVars.meter = this.setMeter(line.substring(2));
515
+ break;
516
+ case 'P':
517
+ // TODO-PER: There is more to do with parts, but the writer doesn't care.
518
+ if (multilineVars.is_in_header)
519
+ tuneBuilder.addMetaText("partOrder", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
508
520
  else
509
- tune.addMetaText(field, tokenizer.translateString(tokenizer.stripComment(line.substring(2))));
510
- return {};
511
- } else {
512
- var startChar = multilineVars.iChar;
513
- var endChar = startChar + line.length;
514
- switch(line.charAt(0))
515
- {
516
- case 'H':
517
- tune.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line.substring(2))));
518
- multilineVars.is_in_history = true;
519
- break;
520
- case 'K':
521
- // since the key is the last thing that can happen in the header, we can resolve the tempo now
522
- this.resolveTempo();
523
- var result = parseKeyVoice.parseKey(line.substring(2));
524
- if (!multilineVars.is_in_header && tune.hasBeginMusic()) {
525
- if (result.foundClef)
526
- tune.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
527
- if (result.foundKey)
528
- tune.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
529
- }
530
- multilineVars.is_in_header = false; // The first key signifies the end of the header.
531
- break;
532
- case 'L':
533
- this.setDefaultLength(line, 2, line.length);
534
- break;
535
- case 'M':
536
- multilineVars.origMeter = multilineVars.meter = this.setMeter(line.substring(2));
537
- break;
538
- case 'P':
539
- // TODO-PER: There is more to do with parts, but the writer doesn't care.
540
- if (multilineVars.is_in_header)
541
- tune.addMetaText("partOrder", tokenizer.translateString(tokenizer.stripComment(line.substring(2))));
542
- else
543
- multilineVars.partForNextLine = { title: tokenizer.translateString(tokenizer.stripComment(line.substring(2))), startChar: startChar, endChar: endChar};
544
- break;
545
- case 'Q':
546
- var tempo = this.setTempo(line, 2, line.length);
547
- if (tempo.type === 'delaySet') multilineVars.tempo = tempo.tempo;
548
- else if (tempo.type === 'immediate') tune.metaText.tempo = tempo.tempo;
549
- break;
550
- case 'T':
551
- this.setTitle(line.substring(2));
552
- break;
553
- case 'U':
554
- this.addUserDefinition(line, 2, line.length);
555
- break;
556
- case 'V':
557
- parseKeyVoice.parseVoice(line, 2, line.length);
558
- if (!multilineVars.is_in_header)
559
- return {newline: true};
560
- break;
561
- case 's':
562
- return {symbols: true};
563
- case 'w':
564
- return {words: true};
565
- case 'X':
566
- break;
567
- case 'E':
568
- case 'm':
569
- warn("Ignored header", line, 0);
570
- break;
571
- default:
572
- // It wasn't a recognized header value, so parse it as music.
573
- if (nextLine.length)
574
- nextLine = "\x12" + nextLine;
575
- //parseRegularMusicLine(line+nextLine);
576
- //nextLine = "";
577
- return {regular: true, str: line+nextLine};
521
+ multilineVars.partForNextLine = { title: tokenizer.translateString(tokenizer.stripComment(line.substring(2))), startChar: startChar, endChar: endChar};
522
+ break;
523
+ case 'Q':
524
+ var tempo = this.setTempo(line, 2, line.length, multilineVars.iChar);
525
+ if (tempo.type === 'delaySet') multilineVars.tempo = tempo.tempo;
526
+ else if (tempo.type === 'immediate') {
527
+ if (!tune.metaText.tempo)
528
+ tune.metaText.tempo = tempo.tempo;
529
+ else
530
+ multilineVars.tempoForNextLine = ['tempo', startChar, endChar, tempo.tempo]
578
531
  }
579
- }
580
- if (nextLine.length > 0)
581
- return {recurse: true, str: nextLine};
582
- return {};
532
+ break;
533
+ case 'T':
534
+ this.setTitle(line.substring(2));
535
+ break;
536
+ case 'U':
537
+ this.addUserDefinition(line, 2, line.length);
538
+ break;
539
+ case 'V':
540
+ parseKeyVoice.parseVoice(line, 2, line.length);
541
+ if (!multilineVars.is_in_header)
542
+ return {newline: true};
543
+ break;
544
+ case 's':
545
+ return {symbols: true};
546
+ case 'w':
547
+ return {words: true};
548
+ case 'X':
549
+ break;
550
+ case 'E':
551
+ case 'm':
552
+ warn("Ignored header", line, 0);
553
+ break;
554
+ default:
555
+ return {regular: true};
583
556
  }
584
557
  }
585
-
586
- // If we got this far, we have a regular line of mulsic
587
- return {regular: true, str: line};
558
+ return {};
588
559
  };
589
560
  };
590
561
 
@@ -1,18 +1,3 @@
1
- // Copyright (C) 2010-2020 Paul Rosen (paul at paulrosen dot net)
2
- //
3
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
4
- // documentation files (the "Software"), to deal in the Software without restriction, including without limitation
5
- // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
6
- // to permit persons to whom the Software is furnished to do so, subject to the following conditions:
7
- //
8
- // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
9
- //
10
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
11
- // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
12
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
13
- // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
14
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
-
16
1
  var parseCommon = require('./abc_common');
17
2
  var parseDirective = require('./abc_parse_directive');
18
3
  var transpose = require('./abc_transpose');
@@ -24,11 +9,13 @@ var parseKeyVoice = {};
24
9
  var warn;
25
10
  var multilineVars;
26
11
  var tune;
27
- parseKeyVoice.initialize = function(tokenizer_, warn_, multilineVars_, tune_) {
12
+ var tuneBuilder;
13
+ parseKeyVoice.initialize = function(tokenizer_, warn_, multilineVars_, tune_, tuneBuilder_) {
28
14
  tokenizer = tokenizer_;
29
15
  warn = warn_;
30
16
  multilineVars = multilineVars_;
31
17
  tune = tune_;
18
+ tuneBuilder = tuneBuilder_;
32
19
  };
33
20
 
34
21
  parseKeyVoice.standardKey = function(keyName, root, acc, localTranspose) {
@@ -175,7 +162,8 @@ var parseKeyVoice = {};
175
162
  'D#': [ key1flat, key2flat, key3flat ],
176
163
  'E#': [ key1flat ],
177
164
  'G#': [ key1flat, key2flat, key3flat, key4flat ],
178
- 'Gbm': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ]
165
+ 'Gbm': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
166
+ 'none': []
179
167
  };
180
168
 
181
169
  return transpose.keySignature(multilineVars, keys, keyName, root, acc, localTranspose);
@@ -377,6 +365,12 @@ var parseKeyVoice = {};
377
365
  var tokens = tokenizer.tokenize(str, 0, str.length);
378
366
  var ret = {};
379
367
 
368
+ // Be sure that a key was passed in
369
+ if (tokens.length === 0) {
370
+ warn("Must pass in key signature.", str, 0);
371
+ return ret;
372
+ }
373
+
380
374
  // first the key
381
375
  switch (tokens[0].token) {
382
376
  case 'HP':
@@ -566,6 +560,7 @@ var parseKeyVoice = {};
566
560
  case "harmonic":
567
561
  case "rhythm":
568
562
  case "x":
563
+ case "triangle":
569
564
  multilineVars.style = tokens[0].token;
570
565
  tokens.shift();
571
566
  break;
@@ -586,6 +581,7 @@ var parseKeyVoice = {};
586
581
  case "alto":
587
582
  case "tenor":
588
583
  case "perc":
584
+ case "none":
589
585
  // clef is [clef=] [⟨clef type⟩] [⟨line number⟩] [+8|-8]
590
586
  var clef = tokens.shift();
591
587
  switch (clef.token) {
@@ -630,7 +626,7 @@ var parseKeyVoice = {};
630
626
 
631
627
  var setCurrentVoice = function(id) {
632
628
  multilineVars.currentVoice = multilineVars.voices[id];
633
- tune.setCurrentVoice(multilineVars.currentVoice.staffNum, multilineVars.currentVoice.index);
629
+ tuneBuilder.setCurrentVoice(multilineVars.currentVoice.staffNum, multilineVars.currentVoice.index);
634
630
  };
635
631
 
636
632
  parseKeyVoice.parseVoice = function(line, i, e) {
@@ -661,6 +657,8 @@ var parseKeyVoice = {};
661
657
  var attr = tokenizer.getVoiceToken(line, start, end);
662
658
  if (attr.warn !== undefined)
663
659
  warn("Expected value for " + name + " in voice: " + attr.warn, line, start);
660
+ else if (attr.err !== undefined)
661
+ warn("Expected value for " + name + " in voice: " + attr.err, line, start);
664
662
  else if (attr.token.length === 0 && line.charAt(start) !== '"')
665
663
  warn("Expected value for " + name + " in voice", line, start);
666
664
  else
@@ -671,6 +669,8 @@ var parseKeyVoice = {};
671
669
  var attr = tokenizer.getVoiceToken(line, start, end);
672
670
  if (attr.warn !== undefined)
673
671
  warn("Expected value for " + name + " in voice: " + attr.warn, line, start);
672
+ else if (attr.err !== undefined)
673
+ warn("Expected value for " + name + " in voice: " + attr.err, line, start);
674
674
  else if (attr.token.length === 0 && line.charAt(start) !== '"')
675
675
  warn("Expected value for " + name + " in voice", line, start);
676
676
  else {
@@ -684,6 +684,8 @@ var parseKeyVoice = {};
684
684
  var attr = tokenizer.getVoiceToken(line, start, end);
685
685
  if (attr.warn !== undefined)
686
686
  warn("Expected value for " + name + " in voice: " + attr.warn, line, start);
687
+ else if (attr.err !== undefined)
688
+ warn("Expected value for " + name + " in voice: " + attr.err, line, start);
687
689
  else if (attr.token.length === 0 && line.charAt(start) !== '"')
688
690
  warn("Expected value for " + name + " in voice", line, start);
689
691
  else {
@@ -809,6 +811,8 @@ var parseKeyVoice = {};
809
811
  attr = tokenizer.getVoiceToken(line, start, end);
810
812
  if (attr.warn !== undefined)
811
813
  warn("Expected value for stems in voice: " + attr.warn, line, start);
814
+ else if (attr.err !== undefined)
815
+ warn("Expected value for stems in voice: " + attr.err, line, start);
812
816
  else if (attr.token === 'up' || attr.token === 'down')
813
817
  multilineVars.voices[id].stem = attr.token;
814
818
  else
@@ -871,10 +875,12 @@ var parseKeyVoice = {};
871
875
  attr = tokenizer.getVoiceToken(line, start, end);
872
876
  if (attr.warn !== undefined)
873
877
  warn("Expected value for style in voice: " + attr.warn, line, start);
874
- else if (attr.token === 'normal' || attr.token === 'harmonic' || attr.token === 'rhythm' || attr.token === 'x')
878
+ else if (attr.err !== undefined)
879
+ warn("Expected value for style in voice: " + attr.err, line, start);
880
+ else if (attr.token === 'normal' || attr.token === 'harmonic' || attr.token === 'rhythm' || attr.token === 'x' || attr.token === 'triangle')
875
881
  multilineVars.voices[id].style = attr.token;
876
882
  else
877
- warn("Expected one of [normal, harmonic, rhythm, x] for voice style", line, start);
883
+ warn("Expected one of [normal, harmonic, rhythm, x, triangle] for voice style", line, start);
878
884
  start += attr.len;
879
885
  break;
880
886
  // default: