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
|
@@ -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
|
-
|
|
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
|
-
|
|
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 (
|
|
378
|
-
|
|
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 &&
|
|
385
|
-
|
|
386
|
-
if (result.foundKey &&
|
|
387
|
-
|
|
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
|
-
|
|
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')
|
|
402
|
-
|
|
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 (
|
|
433
|
-
|
|
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 &&
|
|
438
|
-
|
|
439
|
-
if (result.foundKey &&
|
|
440
|
-
|
|
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 (
|
|
444
|
-
|
|
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')
|
|
454
|
-
else if (tempo.type === 'immediate')
|
|
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
|
-
|
|
485
|
-
|
|
486
|
-
if (
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
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
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
var
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
multilineVars.
|
|
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
|
-
|
|
581
|
-
|
|
582
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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:
|