abcjs 6.1.9 → 6.2.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/RELEASE.md +42 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +4318 -4411
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/index.js +1 -1
- package/package.json +1 -1
- package/plugin.js +1 -1
- package/src/api/abc_timing_callbacks.js +7 -3
- package/src/api/abc_tunebook_svg.js +1 -2
- package/src/data/abc_tune.js +2 -2
- package/src/parse/abc_common.js +0 -47
- package/src/parse/abc_parse.js +16 -16
- package/src/parse/abc_parse_book.js +3 -3
- package/src/parse/abc_parse_directive.js +26 -7
- package/src/parse/abc_parse_header.js +11 -9
- package/src/parse/abc_parse_key_voice.js +17 -17
- package/src/parse/abc_parse_music.js +88 -105
- package/src/parse/abc_tokenizer.js +60 -60
- package/src/parse/tune-builder.js +19 -14
- package/src/synth/abc_midi_flattener.js +25 -9
- package/src/synth/create-synth.js +41 -0
- package/src/synth/note-to-midi.js +50 -0
- package/src/tablatures/instruments/guitar/tab-guitar.js +0 -2
- package/src/tablatures/instruments/string-patterns.js +46 -28
- package/src/tablatures/instruments/tab-note.js +26 -103
- package/src/tablatures/instruments/violin/tab-violin.js +0 -2
- package/src/tablatures/tab-absolute-elements.js +9 -31
- package/src/tablatures/tab-renderer.js +2 -2
- package/src/test/abc_parser_lint.js +7 -4
- package/src/write/README.md +31 -0
- package/src/write/creation/abstract-engraver.js +1036 -0
- package/src/write/creation/add-chord.js +102 -0
- package/src/write/{add-text-if.js → creation/add-text-if.js} +6 -6
- package/src/write/{calcHeight.js → creation/calc-height.js} +2 -2
- package/src/write/creation/create-clef.js +72 -0
- package/src/write/creation/create-key-signature.js +31 -0
- package/src/write/creation/create-note-head.js +107 -0
- package/src/write/creation/create-time-signature.js +55 -0
- package/src/write/creation/decoration.js +357 -0
- package/src/write/{abc_absolute_element.js → creation/elements/absolute-element.js} +14 -15
- package/src/write/creation/elements/beam-element.js +113 -0
- package/src/write/{bottom-text.js → creation/elements/bottom-text.js} +14 -15
- package/src/write/{abc_brace_element.js → creation/elements/brace-element.js} +5 -5
- package/src/write/creation/elements/free-text.js +41 -0
- package/src/write/{abc_relative_element.js → creation/elements/relative-element.js} +7 -7
- package/src/write/{separator.js → creation/elements/separator.js} +2 -2
- package/src/write/{abc_staff_group_element.js → creation/elements/staff-group-element.js} +4 -4
- package/src/write/{subtitle.js → creation/elements/subtitle.js} +3 -3
- package/src/write/creation/elements/tempo-element.js +63 -0
- package/src/write/{abc_tie_element.js → creation/elements/tie-element.js} +15 -11
- package/src/write/{top-text.js → creation/elements/top-text.js} +12 -12
- package/src/write/creation/elements/triplet-element.js +28 -0
- package/src/write/{abc_voice_element.js → creation/elements/voice-element.js} +3 -3
- package/src/write/creation/glyphs.js +226 -0
- package/src/write/creation/translate-chord.js +37 -0
- package/src/write/draw/absolute.js +5 -5
- package/src/write/draw/beam.js +8 -8
- package/src/write/draw/brace.js +33 -33
- package/src/write/draw/crescendo.js +4 -4
- package/src/write/draw/debug-box.js +1 -1
- package/src/write/draw/draw.js +7 -7
- package/src/write/draw/dynamics.js +2 -2
- package/src/write/draw/ending.js +6 -6
- package/src/write/draw/glissando.js +17 -17
- package/src/write/draw/group-elements.js +51 -51
- package/src/write/draw/horizontal-line.js +9 -9
- package/src/write/draw/non-music.js +1 -1
- package/src/write/draw/print-line.js +15 -16
- package/src/write/draw/print-stem.js +5 -5
- package/src/write/draw/print-symbol.js +12 -12
- package/src/write/draw/print-vertical-line.js +8 -8
- package/src/write/draw/relative.js +17 -16
- package/src/write/draw/selectables.js +5 -5
- package/src/write/draw/separator.js +4 -4
- package/src/write/draw/set-paper-size.js +2 -2
- package/src/write/draw/sprintf.js +31 -31
- package/src/write/draw/staff-group.js +36 -30
- package/src/write/draw/staff-line.js +2 -2
- package/src/write/draw/staff.js +4 -4
- package/src/write/draw/tab-line.js +26 -26
- package/src/write/draw/tempo.js +30 -30
- package/src/write/draw/text.js +5 -5
- package/src/write/draw/tie.js +18 -18
- package/src/write/draw/triplet.js +6 -6
- package/src/write/draw/voice.js +16 -17
- package/src/write/{abc_engraver_controller.js → engraver-controller.js} +58 -51
- package/src/write/{classes.js → helpers/classes.js} +6 -6
- package/src/write/{get-font-and-attr.js → helpers/get-font-and-attr.js} +9 -7
- package/src/write/{get-text-size.js → helpers/get-text-size.js} +5 -5
- package/src/write/{set-class.js → helpers/set-class.js} +1 -1
- package/src/write/{abc_spacing.js → helpers/spacing.js} +1 -1
- package/src/write/{highlight.js → interactive/highlight.js} +1 -1
- package/src/write/{selection.js → interactive/selection.js} +27 -27
- package/src/write/{unhighlight.js → interactive/unhighlight.js} +1 -1
- package/src/write/layout/beam.js +13 -13
- package/src/write/layout/get-left-edge-of-staff.js +4 -4
- package/src/write/layout/layout.js +74 -74
- package/src/write/layout/{setUpperAndLowerElements.js → set-upper-and-lower-elements.js} +8 -8
- package/src/write/layout/{staffGroup.js → staff-group.js} +32 -32
- package/src/write/layout/triplet.js +4 -4
- package/src/write/layout/{VoiceElements.js → voice-elements.js} +23 -23
- package/src/write/layout/voice.js +6 -6
- package/src/write/{abc_renderer.js → renderer.js} +35 -32
- package/src/write/svg.js +35 -35
- package/test.js +1 -1
- package/types/index.d.ts +36 -7
- package/version.js +1 -1
- package/src/tablatures/instruments/guitar/guitar-fonts.js +0 -19
- package/src/tablatures/instruments/violin/violin-fonts.js +0 -19
- package/src/tablatures/transposer.js +0 -110
- package/src/write/abc_abstract_engraver.js +0 -1026
- package/src/write/abc_beam_element.js +0 -113
- package/src/write/abc_create_clef.js +0 -72
- package/src/write/abc_create_key_signature.js +0 -33
- package/src/write/abc_create_note_head.js +0 -107
- package/src/write/abc_create_time_signature.js +0 -55
- package/src/write/abc_decoration.js +0 -357
- package/src/write/abc_glyphs.js +0 -224
- package/src/write/abc_tempo_element.js +0 -63
- package/src/write/abc_triplet_element.js +0 -28
- package/src/write/add-chord.js +0 -103
- package/src/write/format-jazz-chord.js +0 -15
- package/src/write/free-text.js +0 -41
- /package/src/write/{abc_crescendo_element.js → creation/elements/crescendo-element.js} +0 -0
- /package/src/write/{abc_dynamic_decoration.js → creation/elements/dynamic-decoration.js} +0 -0
- /package/src/write/{abc_ending_element.js → creation/elements/ending-element.js} +0 -0
- /package/src/write/{abc_glissando_element.js → creation/elements/glissando-element.js} +0 -0
- /package/src/write/layout/{getBarYAt.js → get-bar-y-at.js} +0 -0
|
@@ -82,7 +82,7 @@ var isInTie = function(multilineVars, overlayLevel, el) {
|
|
|
82
82
|
if (multilineVars.inTie[overlayLevel] === undefined)
|
|
83
83
|
return false;
|
|
84
84
|
// If this is single voice music then the voice index isn't set, so we use the first voice.
|
|
85
|
-
var voiceIndex = multilineVars.currentVoice ? multilineVars.currentVoice.index : 0;
|
|
85
|
+
var voiceIndex = multilineVars.currentVoice ? multilineVars.currentVoice.staffNum * 100 + multilineVars.currentVoice.index : 0;
|
|
86
86
|
if (multilineVars.inTie[overlayLevel][voiceIndex]) {
|
|
87
87
|
if (el.pitches !== undefined || el.rest.type !== 'spacer')
|
|
88
88
|
return true;
|
|
@@ -98,9 +98,9 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
98
98
|
var i = 0;
|
|
99
99
|
var startOfLine = multilineVars.iChar;
|
|
100
100
|
// see if there is nothing but a comment on this line. If so, just ignore it. A full line comment is optional white space followed by %
|
|
101
|
-
while (tokenizer.isWhiteSpace(line
|
|
101
|
+
while (tokenizer.isWhiteSpace(line[i]) && i < line.length)
|
|
102
102
|
i++;
|
|
103
|
-
if (i === line.length || line
|
|
103
|
+
if (i === line.length || line[i] === '%')
|
|
104
104
|
return;
|
|
105
105
|
|
|
106
106
|
// Start with the standard staff, clef and key symbols on each line
|
|
@@ -126,7 +126,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
126
126
|
while (i < line.length)
|
|
127
127
|
{
|
|
128
128
|
var startI = i;
|
|
129
|
-
if (line
|
|
129
|
+
if (line[i] === '%')
|
|
130
130
|
break;
|
|
131
131
|
|
|
132
132
|
var retInlineHeader = header.letter_to_inline_header(line, i, delayStartNewLine);
|
|
@@ -158,7 +158,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
158
158
|
if (ret > 0) {
|
|
159
159
|
i += ret;
|
|
160
160
|
}
|
|
161
|
-
if (i > 0 && line
|
|
161
|
+
if (i > 0 && line[i-1] === '\x12') {
|
|
162
162
|
// there is one case where a line continuation isn't the same as being on the same line, and that is if the next character after it is a header.
|
|
163
163
|
ret = header.letter_to_body_header(line, i);
|
|
164
164
|
if (ret[0] > 0) {
|
|
@@ -203,7 +203,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
203
203
|
el.force_end_beam_last = true;
|
|
204
204
|
i += ii;
|
|
205
205
|
} else {
|
|
206
|
-
if (nonDecorations.indexOf(line
|
|
206
|
+
if (nonDecorations.indexOf(line[i]) === -1)
|
|
207
207
|
ret = letter_to_accent(line, i);
|
|
208
208
|
else ret = [ 0 ];
|
|
209
209
|
if (ret[0] > 0) {
|
|
@@ -326,7 +326,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
326
326
|
}
|
|
327
327
|
|
|
328
328
|
// handle chords.
|
|
329
|
-
if (line
|
|
329
|
+
if (line[i] === '[') {
|
|
330
330
|
var chordStartChar = i;
|
|
331
331
|
i++;
|
|
332
332
|
var chordDuration = null;
|
|
@@ -373,12 +373,12 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
373
373
|
|
|
374
374
|
i = chordNote.endChar;
|
|
375
375
|
delete chordNote.endChar;
|
|
376
|
-
} else if (line
|
|
376
|
+
} else if (line[i] === ' ') {
|
|
377
377
|
// Spaces are not allowed in chords, but we can recover from it by ignoring it.
|
|
378
378
|
warn("Spaces are not allowed in chords", line, i);
|
|
379
379
|
i++;
|
|
380
380
|
} else {
|
|
381
|
-
if (i < line.length && line
|
|
381
|
+
if (i < line.length && line[i] === ']') {
|
|
382
382
|
// consume the close bracket
|
|
383
383
|
i++;
|
|
384
384
|
|
|
@@ -388,7 +388,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
388
388
|
}
|
|
389
389
|
|
|
390
390
|
if (isInTie(multilineVars, overlayLevel, el)) {
|
|
391
|
-
|
|
391
|
+
el.pitches.forEach(function(pitch) { pitch.endTie = true; });
|
|
392
392
|
setIsInTie(multilineVars, overlayLevel, false);
|
|
393
393
|
}
|
|
394
394
|
|
|
@@ -401,7 +401,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
401
401
|
|
|
402
402
|
var postChordDone = false;
|
|
403
403
|
while (i < line.length && !postChordDone) {
|
|
404
|
-
switch (line
|
|
404
|
+
switch (line[i]) {
|
|
405
405
|
case ' ':
|
|
406
406
|
case '\t':
|
|
407
407
|
addEndBeam(el);
|
|
@@ -410,7 +410,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
410
410
|
if (el.endSlur === undefined) el.endSlur = 1; else el.endSlur++;
|
|
411
411
|
break;
|
|
412
412
|
case '-':
|
|
413
|
-
|
|
413
|
+
el.pitches.forEach(function(pitch) { pitch.startTie = {}; });
|
|
414
414
|
setIsInTie(multilineVars, overlayLevel, true);
|
|
415
415
|
break;
|
|
416
416
|
case '>':
|
|
@@ -436,9 +436,10 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
436
436
|
var fraction = tokenizer.getFraction(line, i);
|
|
437
437
|
chordDuration = fraction.value;
|
|
438
438
|
i = fraction.index;
|
|
439
|
-
|
|
439
|
+
var ch = line[i]
|
|
440
|
+
if (ch === ' ')
|
|
440
441
|
rememberEndBeam = true;
|
|
441
|
-
if (
|
|
442
|
+
if (ch === '-' || ch === ')' || ch === ' ' || ch === '<' || ch === '>')
|
|
442
443
|
i--; // Subtracting one because one is automatically added below
|
|
443
444
|
else
|
|
444
445
|
postChordDone = true;
|
|
@@ -560,7 +561,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
560
561
|
}
|
|
561
562
|
|
|
562
563
|
if (i === startI) { // don't know what this is, so ignore it.
|
|
563
|
-
if (line
|
|
564
|
+
if (line[i] !== ' ' && line[i] !== '`')
|
|
564
565
|
warn("Unknown character ignored", line, i);
|
|
565
566
|
i++;
|
|
566
567
|
}
|
|
@@ -573,14 +574,14 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
573
574
|
|
|
574
575
|
var setIsInTie =function(multilineVars, overlayLevel, value) {
|
|
575
576
|
// If this is single voice music then the voice index isn't set, so we use the first voice.
|
|
576
|
-
var voiceIndex = multilineVars.currentVoice ? multilineVars.currentVoice.index : 0;
|
|
577
|
+
var voiceIndex = multilineVars.currentVoice ? multilineVars.currentVoice.staffNum * 100 + multilineVars.currentVoice.index : 0;
|
|
577
578
|
if (multilineVars.inTie[overlayLevel] === undefined)
|
|
578
579
|
multilineVars.inTie[overlayLevel] = [];
|
|
579
580
|
multilineVars.inTie[overlayLevel][voiceIndex] = value;
|
|
580
581
|
};
|
|
581
582
|
|
|
582
583
|
var letter_to_chord = function(line, i) {
|
|
583
|
-
if (line
|
|
584
|
+
if (line[i] === '"')
|
|
584
585
|
{
|
|
585
586
|
var chord = tokenizer.getBrackettedSubstring(line, i, 5);
|
|
586
587
|
if (!chord[2])
|
|
@@ -588,19 +589,19 @@ var letter_to_chord = function(line, i) {
|
|
|
588
589
|
// If it starts with ^, then the chord appears above.
|
|
589
590
|
// If it starts with _ then the chord appears below.
|
|
590
591
|
// (note that the 2.0 draft standard defines them as not chords, but annotations and also defines @.)
|
|
591
|
-
if (chord[0] > 0 && chord[1].length > 0 && chord[1]
|
|
592
|
+
if (chord[0] > 0 && chord[1].length > 0 && chord[1][0] === '^') {
|
|
592
593
|
chord[1] = chord[1].substring(1);
|
|
593
594
|
chord[2] = 'above';
|
|
594
|
-
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1]
|
|
595
|
+
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1][0] === '_') {
|
|
595
596
|
chord[1] = chord[1].substring(1);
|
|
596
597
|
chord[2] = 'below';
|
|
597
|
-
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1]
|
|
598
|
+
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1][0] === '<') {
|
|
598
599
|
chord[1] = chord[1].substring(1);
|
|
599
600
|
chord[2] = 'left';
|
|
600
|
-
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1]
|
|
601
|
+
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1][0] === '>') {
|
|
601
602
|
chord[1] = chord[1].substring(1);
|
|
602
603
|
chord[2] = 'right';
|
|
603
|
-
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1]
|
|
604
|
+
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1][0] === '@') {
|
|
604
605
|
// @-15,5.7
|
|
605
606
|
chord[1] = chord[1].substring(1);
|
|
606
607
|
var x = tokenizer.getFloat(chord[1]);
|
|
@@ -637,7 +638,7 @@ var letter_to_chord = function(line, i) {
|
|
|
637
638
|
|
|
638
639
|
var letter_to_grace = function(line, i) {
|
|
639
640
|
// Grace notes are an array of: startslur, note, endslur, space; where note is accidental, pitch, duration
|
|
640
|
-
if (line
|
|
641
|
+
if (line[i] === '{') {
|
|
641
642
|
// fetch the gracenotes string and consume that into the array
|
|
642
643
|
var gra = tokenizer.getBrackettedSubstring(line, i, 1, '}');
|
|
643
644
|
if (!gra[2])
|
|
@@ -653,7 +654,7 @@ var letter_to_grace = function(line, i) {
|
|
|
653
654
|
var inTie = false;
|
|
654
655
|
while (ii < gra[1].length) {
|
|
655
656
|
var acciaccatura = false;
|
|
656
|
-
if (gra[1]
|
|
657
|
+
if (gra[1][ii] === '/') {
|
|
657
658
|
acciaccatura = true;
|
|
658
659
|
ii++;
|
|
659
660
|
}
|
|
@@ -682,11 +683,11 @@ var letter_to_grace = function(line, i) {
|
|
|
682
683
|
}
|
|
683
684
|
else {
|
|
684
685
|
// We shouldn't get anything but notes or a space here, so report an error
|
|
685
|
-
if (gra[1]
|
|
686
|
+
if (gra[1][ii] === ' ') {
|
|
686
687
|
if (gracenotes.length > 0)
|
|
687
688
|
gracenotes[gracenotes.length-1].endBeam = true;
|
|
688
689
|
} else
|
|
689
|
-
warn("Unknown character '" + gra[1]
|
|
690
|
+
warn("Unknown character '" + gra[1][ii] + "' while parsing grace note", line, i);
|
|
690
691
|
ii++;
|
|
691
692
|
}
|
|
692
693
|
}
|
|
@@ -697,9 +698,9 @@ var letter_to_grace = function(line, i) {
|
|
|
697
698
|
};
|
|
698
699
|
|
|
699
700
|
function letter_to_overlay(line, i) {
|
|
700
|
-
if (line
|
|
701
|
+
if (line[i] === '&') {
|
|
701
702
|
var start = i;
|
|
702
|
-
while (line
|
|
703
|
+
while (line[i] && line[i] !== ':' && line[i] !== '|')
|
|
703
704
|
i++;
|
|
704
705
|
return [ i-start, line.substring(start+1, i) ];
|
|
705
706
|
}
|
|
@@ -747,38 +748,30 @@ var accentDynamicPseudonyms = [
|
|
|
747
748
|
];
|
|
748
749
|
|
|
749
750
|
var letter_to_accent = function(line, i) {
|
|
750
|
-
var macro = multilineVars.macros[line
|
|
751
|
+
var macro = multilineVars.macros[line[i]];
|
|
751
752
|
|
|
752
753
|
if (macro !== undefined) {
|
|
753
|
-
if (macro
|
|
754
|
+
if (macro[0] === '!' || macro[0] === '+')
|
|
754
755
|
macro = macro.substring(1);
|
|
755
|
-
if (macro
|
|
756
|
+
if (macro[macro.length-1] === '!' || macro[macro.length-1] === '+')
|
|
756
757
|
macro = macro.substring(0, macro.length-1);
|
|
757
|
-
if (
|
|
758
|
-
return (macro === acc);
|
|
759
|
-
}))
|
|
758
|
+
if (legalAccents.includes(macro))
|
|
760
759
|
return [ 1, macro ];
|
|
761
|
-
else if (
|
|
762
|
-
return (macro === acc);
|
|
763
|
-
})) {
|
|
760
|
+
else if (volumeDecorations.includes(macro)) {
|
|
764
761
|
if (multilineVars.volumePosition === 'hidden')
|
|
765
762
|
macro = "";
|
|
766
763
|
return [1, macro];
|
|
767
|
-
} else if (
|
|
764
|
+
} else if (dynamicDecorations.includes(macro)) {
|
|
768
765
|
if (multilineVars.dynamicPosition === 'hidden')
|
|
769
766
|
macro = "";
|
|
770
|
-
return (macro === acc);
|
|
771
|
-
})) {
|
|
772
767
|
return [1, macro];
|
|
773
768
|
} else {
|
|
774
|
-
if (!
|
|
775
|
-
return (macro === dec);
|
|
776
|
-
}))
|
|
769
|
+
if (!multilineVars.ignoredDecorations.includes(macro))
|
|
777
770
|
warn("Unknown macro: " + macro, line, i);
|
|
778
771
|
return [1, '' ];
|
|
779
772
|
}
|
|
780
773
|
}
|
|
781
|
-
switch (line
|
|
774
|
+
switch (line[i])
|
|
782
775
|
{
|
|
783
776
|
case '.':
|
|
784
777
|
if (line[i+1] === '(' || line[i+1] === '-') // a dot then open paren is a dotted slur; likewise dot dash is dotted tie.
|
|
@@ -791,50 +784,38 @@ var letter_to_accent = function(line, i) {
|
|
|
791
784
|
case '+':
|
|
792
785
|
var ret = tokenizer.getBrackettedSubstring(line, i, 5);
|
|
793
786
|
// Be sure that the accent is recognizable.
|
|
794
|
-
if (ret[1].length > 1 && (ret[1]
|
|
787
|
+
if (ret[1].length > 1 && (ret[1][0] === '^' || ret[1][0] ==='_'))
|
|
795
788
|
ret[1] = ret[1].substring(1); // TODO-PER: The test files have indicators forcing the ornament to the top or bottom, but that isn't in the standard. We'll just ignore them.
|
|
796
|
-
if (
|
|
797
|
-
return (ret[1] === acc);
|
|
798
|
-
}))
|
|
789
|
+
if (legalAccents.includes(ret[1]))
|
|
799
790
|
return ret;
|
|
800
|
-
if (
|
|
801
|
-
return (ret[1] === acc);
|
|
802
|
-
})) {
|
|
791
|
+
if (volumeDecorations.includes(ret[1])) {
|
|
803
792
|
if (multilineVars.volumePosition === 'hidden' )
|
|
804
793
|
ret[1] = '';
|
|
805
794
|
return ret;
|
|
806
795
|
}
|
|
807
|
-
if (
|
|
808
|
-
return (ret[1] === acc);
|
|
809
|
-
})) {
|
|
796
|
+
if (dynamicDecorations.includes(ret[1])) {
|
|
810
797
|
if (multilineVars.dynamicPosition === 'hidden' )
|
|
811
798
|
ret[1] = '';
|
|
812
799
|
return ret;
|
|
813
800
|
}
|
|
814
801
|
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
return true;
|
|
819
|
-
} else
|
|
820
|
-
return false;
|
|
821
|
-
}))
|
|
802
|
+
var ind = accentPseudonyms.findIndex(function (acc) { return ret[1] === acc[0]})
|
|
803
|
+
if (ind >= 0) {
|
|
804
|
+
ret[1] = accentPseudonyms[ind][1];
|
|
822
805
|
return ret;
|
|
806
|
+
}
|
|
823
807
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
return true;
|
|
828
|
-
} else
|
|
829
|
-
return false;
|
|
830
|
-
})) {
|
|
808
|
+
ind = accentDynamicPseudonyms.findIndex(function (acc) { return ret[1] === acc[0]})
|
|
809
|
+
if (ind >= 0) {
|
|
810
|
+
ret[1] = accentDynamicPseudonyms[ind][1];
|
|
831
811
|
if (multilineVars.dynamicPosition === 'hidden' )
|
|
832
812
|
ret[1] = '';
|
|
833
813
|
return ret;
|
|
834
814
|
}
|
|
815
|
+
|
|
835
816
|
// We didn't find the accent in the list, so consume the space, but don't return an accent.
|
|
836
817
|
// Although it is possible that ! was used as a line break, so accept that.
|
|
837
|
-
if (line
|
|
818
|
+
if (line[i] === '!' && (ret[0] === 1 || line[i+ret[0]-1] !== '!'))
|
|
838
819
|
return [1, null ];
|
|
839
820
|
warn("Unknown decoration: " + ret[1], line, i);
|
|
840
821
|
ret[1] = "";
|
|
@@ -854,7 +835,7 @@ var letter_to_accent = function(line, i) {
|
|
|
854
835
|
|
|
855
836
|
var letter_to_spacer = function(line, i) {
|
|
856
837
|
var start = i;
|
|
857
|
-
while (tokenizer.isWhiteSpace(line
|
|
838
|
+
while (tokenizer.isWhiteSpace(line[i]))
|
|
858
839
|
i++;
|
|
859
840
|
return [ i-start ];
|
|
860
841
|
};
|
|
@@ -877,15 +858,15 @@ var letter_to_bar = function(line, curr_pos) {
|
|
|
877
858
|
// It can also optionally start with '[', which is ignored.
|
|
878
859
|
// Also, it can have white space before the '['.
|
|
879
860
|
for (var ws = 0; ws < line.length; ws++)
|
|
880
|
-
if (line
|
|
861
|
+
if (line[curr_pos + ret.len + ws] !== ' ')
|
|
881
862
|
break;
|
|
882
863
|
var orig_bar_len = ret.len;
|
|
883
|
-
if (line
|
|
864
|
+
if (line[curr_pos+ret.len+ws] === '[') {
|
|
884
865
|
ret.len += ws + 1;
|
|
885
866
|
}
|
|
886
867
|
|
|
887
868
|
// It can also be a quoted string. It is unclear whether that construct requires '[', but it seems like it would. otherwise it would be confused with a regular chord.
|
|
888
|
-
if (line
|
|
869
|
+
if (line[curr_pos+ret.len] === '"' && line[curr_pos+ret.len-1] === '[') {
|
|
889
870
|
var ending = tokenizer.getBrackettedSubstring(line, curr_pos+ret.len, 5);
|
|
890
871
|
return [ret.len+ending[0], ret.token, ending[1]];
|
|
891
872
|
}
|
|
@@ -916,16 +897,16 @@ var letter_to_open_slurs_and_triplets = function(line, i) {
|
|
|
916
897
|
ret.dottedSlur = true;
|
|
917
898
|
i++;
|
|
918
899
|
}
|
|
919
|
-
while (line
|
|
920
|
-
if (line
|
|
921
|
-
if (i+1 < line.length && (line
|
|
900
|
+
while (line[i] === '(' || tokenizer.isWhiteSpace(line[i])) {
|
|
901
|
+
if (line[i] === '(') {
|
|
902
|
+
if (i+1 < line.length && (line[i+1] >= '2' && line[i+1] <= '9')) {
|
|
922
903
|
if (ret.triplet !== undefined)
|
|
923
904
|
warn("Can't nest triplets", line, i);
|
|
924
905
|
else {
|
|
925
|
-
ret.triplet = line
|
|
906
|
+
ret.triplet = line[i+1] - '0';
|
|
926
907
|
ret.tripletQ = tripletQ[ret.triplet];
|
|
927
908
|
ret.num_notes = ret.triplet;
|
|
928
|
-
if (i+2 < line.length && line
|
|
909
|
+
if (i+2 < line.length && line[i+2] === ':') {
|
|
929
910
|
// We are expecting "(p:q:r" or "(p:q" or "(p::r"
|
|
930
911
|
// That is: "put p notes into the time of q for the next r notes"
|
|
931
912
|
// if r is missing, then it is equal to p.
|
|
@@ -938,18 +919,18 @@ var letter_to_open_slurs_and_triplets = function(line, i) {
|
|
|
938
919
|
// (7 notes in the time of n
|
|
939
920
|
// (8 notes in the time of 3
|
|
940
921
|
// (9 notes in the time of n
|
|
941
|
-
if (i+3 < line.length && line
|
|
922
|
+
if (i+3 < line.length && line[i+3] === ':') {
|
|
942
923
|
// The second number, 'q', is not present.
|
|
943
|
-
if (i+4 < line.length && (line
|
|
944
|
-
ret.num_notes = line
|
|
924
|
+
if (i+4 < line.length && (line[i+4] >= '1' && line[i+4] <= '9')) {
|
|
925
|
+
ret.num_notes = line[i+4] - '0';
|
|
945
926
|
i += 3;
|
|
946
927
|
} else
|
|
947
928
|
warn("expected number after the two colons after the triplet to mark the duration", line, i);
|
|
948
|
-
} else if (i+3 < line.length && (line
|
|
949
|
-
ret.tripletQ = line
|
|
950
|
-
if (i+4 < line.length && line
|
|
951
|
-
if (i+5 < line.length && (line
|
|
952
|
-
ret.num_notes = line
|
|
929
|
+
} else if (i+3 < line.length && (line[i+3] >= '1' && line[i+3] <= '9')) {
|
|
930
|
+
ret.tripletQ = line[i+3] - '0';
|
|
931
|
+
if (i+4 < line.length && line[i+4] === ':') {
|
|
932
|
+
if (i+5 < line.length && (line[i+5] >= '1' && line[i+5] <= '9')) {
|
|
933
|
+
ret.num_notes = line[i+5] - '0';
|
|
953
934
|
i += 4;
|
|
954
935
|
}
|
|
955
936
|
} else {
|
|
@@ -1004,7 +985,7 @@ MusicParser.prototype.startNewLine = function() {
|
|
|
1004
985
|
parseKeyVoice.addPosToKey(params.clef, params.key);
|
|
1005
986
|
if (multilineVars.meter !== null) {
|
|
1006
987
|
if (multilineVars.currentVoice) {
|
|
1007
|
-
|
|
988
|
+
multilineVars.staves.forEach(function(st) {
|
|
1008
989
|
st.meter = multilineVars.meter;
|
|
1009
990
|
});
|
|
1010
991
|
params.meter = multilineVars.staves[multilineVars.currentVoice.staffNum].meter;
|
|
@@ -1042,6 +1023,8 @@ MusicParser.prototype.startNewLine = function() {
|
|
|
1042
1023
|
params.staffscale = multilineVars.currentVoice.staffscale;
|
|
1043
1024
|
if (multilineVars.currentVoice.scale)
|
|
1044
1025
|
params.scale = multilineVars.currentVoice.scale;
|
|
1026
|
+
if (multilineVars.currentVoice.color)
|
|
1027
|
+
params.color = multilineVars.currentVoice.color;
|
|
1045
1028
|
if (multilineVars.currentVoice.style)
|
|
1046
1029
|
params.style = multilineVars.currentVoice.style;
|
|
1047
1030
|
if (multilineVars.currentVoice.transpose)
|
|
@@ -1083,7 +1066,7 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1083
1066
|
var state = 'startSlur';
|
|
1084
1067
|
var durationSetByPreviousNote = false;
|
|
1085
1068
|
while (1) {
|
|
1086
|
-
switch(line
|
|
1069
|
+
switch(line[index]) {
|
|
1087
1070
|
case '(':
|
|
1088
1071
|
if (state === 'startSlur') {
|
|
1089
1072
|
if (el.startSlur === undefined) el.startSlur = 1; else el.startSlur++;
|
|
@@ -1127,9 +1110,9 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1127
1110
|
case 'f':
|
|
1128
1111
|
case 'g':
|
|
1129
1112
|
if (state === 'startSlur' || state === 'sharp2' || state === 'flat2' || state === 'pitch') {
|
|
1130
|
-
el.pitch = pitches[line
|
|
1113
|
+
el.pitch = pitches[line[index]];
|
|
1131
1114
|
el.pitch += 7 * (multilineVars.currentVoice && multilineVars.currentVoice.octave !== undefined ? multilineVars.currentVoice.octave : multilineVars.octave);
|
|
1132
|
-
el.name = line
|
|
1115
|
+
el.name = line[index];
|
|
1133
1116
|
if (el.accidental)
|
|
1134
1117
|
el.name = accMap[el.accidental] + el.name;
|
|
1135
1118
|
transpose.note(multilineVars, el);
|
|
@@ -1144,7 +1127,7 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1144
1127
|
// If the clef is percussion, there is probably some translation of the pitch to a particular drum kit item.
|
|
1145
1128
|
if ((multilineVars.clef && multilineVars.clef.type === "perc") ||
|
|
1146
1129
|
(multilineVars.currentVoice && multilineVars.currentVoice.clef === "perc")) {
|
|
1147
|
-
var key = line
|
|
1130
|
+
var key = line[index];
|
|
1148
1131
|
if (el.accidental) {
|
|
1149
1132
|
key = accMap[el.accidental] + key;
|
|
1150
1133
|
}
|
|
@@ -1170,7 +1153,7 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1170
1153
|
case 'z':
|
|
1171
1154
|
case 'Z':
|
|
1172
1155
|
if (state === 'startSlur') {
|
|
1173
|
-
el.rest = { type: rests[line
|
|
1156
|
+
el.rest = { type: rests[line[index]] };
|
|
1174
1157
|
// There shouldn't be some of the properties that notes have. If some sneak in due to bad syntax in the abc file,
|
|
1175
1158
|
// just nix them here.
|
|
1176
1159
|
delete el.accidental;
|
|
@@ -1214,8 +1197,8 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1214
1197
|
el.duration = el.duration * fraction.value;
|
|
1215
1198
|
// TODO-PER: We can test the returned duration here and give a warning if it isn't the one expected.
|
|
1216
1199
|
el.endChar = fraction.index;
|
|
1217
|
-
while (fraction.index < line.length && (tokenizer.isWhiteSpace(line
|
|
1218
|
-
if (line
|
|
1200
|
+
while (fraction.index < line.length && (tokenizer.isWhiteSpace(line[fraction.index]) || line[fraction.index] === '-')) {
|
|
1201
|
+
if (line[fraction.index] === '-')
|
|
1219
1202
|
el.startTie = {};
|
|
1220
1203
|
else
|
|
1221
1204
|
el = addEndBeam(el);
|
|
@@ -1246,7 +1229,7 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1246
1229
|
state = 'broken_rhythm';
|
|
1247
1230
|
else {
|
|
1248
1231
|
// Peek ahead to the next character. If it is a space, then we have an end beam.
|
|
1249
|
-
if (tokenizer.isWhiteSpace(line
|
|
1232
|
+
if (tokenizer.isWhiteSpace(line[index + 1]))
|
|
1250
1233
|
addEndBeam(el);
|
|
1251
1234
|
el.endChar = index+1;
|
|
1252
1235
|
return el;
|
|
@@ -1261,21 +1244,21 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1261
1244
|
// look ahead to see if there is a tie
|
|
1262
1245
|
dottedTie = false;
|
|
1263
1246
|
do {
|
|
1264
|
-
if (line
|
|
1247
|
+
if (line[index] === '.' && line[index+1] === '-') {
|
|
1265
1248
|
dottedTie = true;
|
|
1266
1249
|
index++;
|
|
1267
1250
|
}
|
|
1268
|
-
if (line
|
|
1251
|
+
if (line[index] === '-') {
|
|
1269
1252
|
el.startTie = {};
|
|
1270
1253
|
if (dottedTie)
|
|
1271
1254
|
el.startTie.style = "dotted";
|
|
1272
1255
|
}
|
|
1273
1256
|
index++;
|
|
1274
1257
|
} while (index < line.length &&
|
|
1275
|
-
(tokenizer.isWhiteSpace(line
|
|
1276
|
-
(line
|
|
1258
|
+
(tokenizer.isWhiteSpace(line[index]) || line[index] === '-') ||
|
|
1259
|
+
(line[index] === '.' && line[index+1] === '-'));
|
|
1277
1260
|
el.endChar = index;
|
|
1278
|
-
if (!durationSetByPreviousNote && canHaveBrokenRhythm && (line
|
|
1261
|
+
if (!durationSetByPreviousNote && canHaveBrokenRhythm && (line[index] === '<' || line[index] === '>')) { // TODO-PER: Don't need the test for < and >, but that makes the endChar work out for the regression test.
|
|
1279
1262
|
index--;
|
|
1280
1263
|
state = 'broken_rhythm';
|
|
1281
1264
|
} else
|
|
@@ -1316,18 +1299,18 @@ var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
|
1316
1299
|
};
|
|
1317
1300
|
|
|
1318
1301
|
var getBrokenRhythm = function(line, index) {
|
|
1319
|
-
switch (line
|
|
1302
|
+
switch (line[index]) {
|
|
1320
1303
|
case '>':
|
|
1321
|
-
if (index < line.length - 2 && line
|
|
1304
|
+
if (index < line.length - 2 && line[index + 1] === '>' && line[index + 2] === '>') // triple >>>
|
|
1322
1305
|
return [3, 1.875, 0.125];
|
|
1323
|
-
else if (index < line.length - 1 && line
|
|
1306
|
+
else if (index < line.length - 1 && line[index + 1] === '>') // double >>
|
|
1324
1307
|
return [2, 1.75, 0.25];
|
|
1325
1308
|
else
|
|
1326
1309
|
return [1, 1.5, 0.5];
|
|
1327
1310
|
case '<':
|
|
1328
|
-
if (index < line.length - 2 && line
|
|
1311
|
+
if (index < line.length - 2 && line[index + 1] === '<' && line[index + 2] === '<') // triple <<<
|
|
1329
1312
|
return [3, 0.125, 1.875];
|
|
1330
|
-
else if (index < line.length - 1 && line
|
|
1313
|
+
else if (index < line.length - 1 && line[index + 1] === '<') // double <<
|
|
1331
1314
|
return [2, 0.25, 1.75];
|
|
1332
1315
|
else
|
|
1333
1316
|
return [1, 0.5, 1.5];
|