abcjs 6.2.2 → 6.2.3
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 +39 -0
- package/abc2xml_239/abc2xml.html +769 -0
- package/abc2xml_239/abc2xml.py +2248 -0
- package/abc2xml_239/abc2xml_changelog.html +124 -0
- package/abc2xml_239/lazy-river.abc +26 -0
- package/abc2xml_239/lazy-river.xml +3698 -0
- package/abc2xml_239/mean-to-me.abc +22 -0
- package/abc2xml_239/mean-to-me.xml +2954 -0
- package/abc2xml_239/pyparsing.py +3672 -0
- package/abc2xml_239/pyparsing.pyc +0 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +160 -71
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/package.json +1 -1
- package/src/api/abc_tablatures.js +3 -0
- package/src/api/abc_tunebook_svg.js +5 -3
- package/src/parse/abc_parse_music.js +18 -53
- package/src/parse/abc_parse_settings.js +165 -0
- package/src/synth/create-synth.js +4 -0
- package/src/synth/place-note.js +6 -0
- package/src/synth/play-event.js +7 -5
- package/src/tablatures/tab-absolute-elements.js +3 -2
- package/src/tablatures/tab-renderer.js +2 -1
- package/src/test/abc_parser_lint.js +12 -12
- package/src/write/creation/abstract-engraver.js +6 -0
- package/src/write/creation/decoration.js +2 -0
- package/src/write/creation/glyphs.js +1 -1
- package/src/write/draw/glissando.js +1 -0
- package/src/write/draw/set-paper-size.js +1 -1
- package/src/write/draw/tie.js +9 -1
- package/src/write/engraver-controller.js +7 -1
- package/src/write/interactive/selection.js +6 -0
- package/src/write/layout/layout.js +33 -3
- package/types/index.d.ts +28 -20
- package/version.js +1 -1
package/package.json
CHANGED
|
@@ -84,6 +84,9 @@ var abcTablatures = {
|
|
|
84
84
|
// plugin.init(tune, tuneNumber, args, ii);
|
|
85
85
|
returned.push(pluginInstance);
|
|
86
86
|
nbPlugins++;
|
|
87
|
+
} else if (instrument === '') {
|
|
88
|
+
// create a placeholder - there is no tab for this staff
|
|
89
|
+
returned.push(null)
|
|
87
90
|
} else {
|
|
88
91
|
// unknown tab plugin
|
|
89
92
|
//this.emit_error('Undefined tablature plugin: ' + tabName)
|
|
@@ -117,12 +117,12 @@ var renderAbc = function(output, abc, parserParams, engraverParams, renderParams
|
|
|
117
117
|
div.setAttribute("style", "visibility: hidden;");
|
|
118
118
|
document.body.appendChild(div);
|
|
119
119
|
}
|
|
120
|
-
if (params.afterParsing)
|
|
121
|
-
params.afterParsing(tune, tuneNumber, abcString);
|
|
122
120
|
if (!removeDiv && params.wrap && params.staffwidth) {
|
|
123
|
-
|
|
121
|
+
tune = doLineWrapping(div, tune, tuneNumber, abcString, params);
|
|
124
122
|
return tune;
|
|
125
123
|
}
|
|
124
|
+
if (params.afterParsing)
|
|
125
|
+
params.afterParsing(tune, tuneNumber, abcString);
|
|
126
126
|
renderOne(div, tune, params, tuneNumber, 0);
|
|
127
127
|
if (removeDiv)
|
|
128
128
|
div.parentNode.removeChild(div);
|
|
@@ -145,6 +145,8 @@ function doLineWrapping(div, tune, tuneNumber, abcString, params) {
|
|
|
145
145
|
if (warnings)
|
|
146
146
|
tune.warnings = warnings;
|
|
147
147
|
}
|
|
148
|
+
if (params.afterParsing)
|
|
149
|
+
params.afterParsing(tune, tuneNumber, abcString);
|
|
148
150
|
renderOne(div, tune, ret.revisedParams, tuneNumber, 0);
|
|
149
151
|
tune.explanation = ret.explanation;
|
|
150
152
|
return tune;
|
|
@@ -9,6 +9,20 @@ var tune;
|
|
|
9
9
|
var tuneBuilder;
|
|
10
10
|
var header;
|
|
11
11
|
|
|
12
|
+
var {
|
|
13
|
+
legalAccents,
|
|
14
|
+
volumeDecorations,
|
|
15
|
+
dynamicDecorations,
|
|
16
|
+
accentPseudonyms,
|
|
17
|
+
accentDynamicPseudonyms,
|
|
18
|
+
nonDecorations,
|
|
19
|
+
durations,
|
|
20
|
+
pitches,
|
|
21
|
+
rests,
|
|
22
|
+
accMap,
|
|
23
|
+
tripletQ
|
|
24
|
+
} = require('./abc_parse_settings')
|
|
25
|
+
|
|
12
26
|
var MusicParser = function(_tokenizer, _warn, _multilineVars, _tune, _tuneBuilder, _header) {
|
|
13
27
|
tokenizer = _tokenizer;
|
|
14
28
|
warn = _warn;
|
|
@@ -76,7 +90,6 @@ var MusicParser = function(_tokenizer, _warn, _multilineVars, _tune, _tuneBuilde
|
|
|
76
90
|
// double-quote: chord symbol
|
|
77
91
|
// less-than, greater-than, slash: duration
|
|
78
92
|
// back-tick, space, tab: space
|
|
79
|
-
var nonDecorations = "ABCDEFGabcdefgxyzZ[]|^_{"; // use this to prescreen so we don't have to look for a decoration at every note.
|
|
80
93
|
|
|
81
94
|
var isInTie = function(multilineVars, overlayLevel, el) {
|
|
82
95
|
if (multilineVars.inTie[overlayLevel] === undefined)
|
|
@@ -540,15 +553,8 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
540
553
|
// Create a warning if this is not a displayable duration.
|
|
541
554
|
// The first item on a line is a regular note value, each item after that represents a dot placed after the previous note.
|
|
542
555
|
// Only durations less than a whole note are tested because whole note durations have some tricky rules.
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
0.25, 0.375, 0.4375, 0.46875, 0.484375, 0.4921875,
|
|
546
|
-
0.125, 0.1875, 0.21875, 0.234375, 0.2421875, 0.24609375,
|
|
547
|
-
0.0625, 0.09375, 0.109375, 0.1171875, 0.12109375, 0.123046875,
|
|
548
|
-
0.03125, 0.046875, 0.0546875, 0.05859375, 0.060546875, 0.0615234375,
|
|
549
|
-
0.015625, 0.0234375, 0.02734375, 0.029296875, 0.0302734375, 0.03076171875,
|
|
550
|
-
];
|
|
551
|
-
if (el.duration < 1 && durations.indexOf(el.duration) === -1 && el.duration !== 0) {
|
|
556
|
+
|
|
557
|
+
if (el.duration < 1 && durations.indexOf(el.duration) === -1 && el.duration !== 0) {
|
|
552
558
|
if (!el.rest || el.rest.type !== 'spacer')
|
|
553
559
|
warn("Duration not representable: " + line.substring(startI, i), line, i);
|
|
554
560
|
}
|
|
@@ -717,35 +723,8 @@ function durationOfMeasure(multilineVars) {
|
|
|
717
723
|
return parseInt(meter.value[0].num, 10) / parseInt(meter.value[0].den, 10);
|
|
718
724
|
}
|
|
719
725
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
"fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge",
|
|
723
|
-
"open", "thumb", "snap", "turn", "roll", "breath", "shortphrase", "mediumphrase", "longphrase",
|
|
724
|
-
"segno", "coda", "D.S.", "D.C.", "fine", "beambr1", "beambr2",
|
|
725
|
-
"slide", "marcato",
|
|
726
|
-
"upbow", "downbow", "/", "//", "///", "////", "trem1", "trem2", "trem3", "trem4",
|
|
727
|
-
"turnx", "invertedturn", "invertedturnx", "trill(", "trill)", "arpeggio", "xstem", "mark", "umarcato",
|
|
728
|
-
"style=normal", "style=harmonic", "style=rhythm", "style=x", "style=triangle", "D.C.alcoda", "D.C.alfine", "D.S.alcoda", "D.S.alfine", "editorial", "courtesy"
|
|
729
|
-
];
|
|
730
|
-
|
|
731
|
-
var volumeDecorations = [
|
|
732
|
-
"p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz"
|
|
733
|
-
];
|
|
734
|
-
|
|
735
|
-
var dynamicDecorations = [
|
|
736
|
-
"crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)"
|
|
737
|
-
];
|
|
738
|
-
|
|
739
|
-
var accentPseudonyms = [
|
|
740
|
-
["<", "accent"], [">", "accent"], ["tr", "trill"],
|
|
741
|
-
["plus", "+"], [ "emphasis", "accent"],
|
|
742
|
-
[ "^", "umarcato" ], [ "marcato", "umarcato" ]
|
|
743
|
-
];
|
|
744
|
-
|
|
745
|
-
var accentDynamicPseudonyms = [
|
|
746
|
-
["<(", "crescendo("], ["<)", "crescendo)"],
|
|
747
|
-
[">(", "diminuendo("], [">)", "diminuendo)"]
|
|
748
|
-
];
|
|
726
|
+
|
|
727
|
+
|
|
749
728
|
|
|
750
729
|
var letter_to_accent = function(line, i) {
|
|
751
730
|
var macro = multilineVars.macros[line[i]];
|
|
@@ -877,17 +856,6 @@ var letter_to_bar = function(line, curr_pos) {
|
|
|
877
856
|
return [ret.len+retRep.len, ret.token, retRep.token];
|
|
878
857
|
};
|
|
879
858
|
|
|
880
|
-
var tripletQ = {
|
|
881
|
-
2: 3,
|
|
882
|
-
3: 2,
|
|
883
|
-
4: 3,
|
|
884
|
-
5: 2, // TODO-PER: not handling 6/8 rhythm yet
|
|
885
|
-
6: 2,
|
|
886
|
-
7: 2, // TODO-PER: not handling 6/8 rhythm yet
|
|
887
|
-
8: 3,
|
|
888
|
-
9: 2 // TODO-PER: not handling 6/8 rhythm yet
|
|
889
|
-
};
|
|
890
|
-
|
|
891
859
|
var letter_to_open_slurs_and_triplets = function(line, i) {
|
|
892
860
|
// consume spaces, and look for all the open parens. If there is a number after the open paren,
|
|
893
861
|
// that is a triplet. Otherwise that is a slur. Collect all the slurs and the first triplet.
|
|
@@ -1050,9 +1018,6 @@ var addEndBeam = function(el) {
|
|
|
1050
1018
|
return el;
|
|
1051
1019
|
};
|
|
1052
1020
|
|
|
1053
|
-
var pitches = {A: 5, B: 6, C: 0, D: 1, E: 2, F: 3, G: 4, a: 12, b: 13, c: 7, d: 8, e: 9, f: 10, g: 11};
|
|
1054
|
-
var rests = {x: 'invisible', X: 'invisible-multimeasure', y: 'spacer', z: 'rest', Z: 'multimeasure' };
|
|
1055
|
-
var accMap = { 'dblflat': '__', 'flat': '_', 'natural': '=', 'sharp': '^', 'dblsharp': '^^', 'quarterflat': '_/', 'quartersharp': '^/'};
|
|
1056
1021
|
var getCoreNote = function(line, index, el, canHaveBrokenRhythm) {
|
|
1057
1022
|
//var el = { startChar: index };
|
|
1058
1023
|
var isComplete = function(state) {
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
module.exports.legalAccents = [
|
|
2
|
+
'trill',
|
|
3
|
+
'lowermordent',
|
|
4
|
+
'uppermordent',
|
|
5
|
+
'mordent',
|
|
6
|
+
'pralltriller',
|
|
7
|
+
'accent',
|
|
8
|
+
'fermata',
|
|
9
|
+
'invertedfermata',
|
|
10
|
+
'tenuto',
|
|
11
|
+
'0',
|
|
12
|
+
'1',
|
|
13
|
+
'2',
|
|
14
|
+
'3',
|
|
15
|
+
'4',
|
|
16
|
+
'5',
|
|
17
|
+
'+',
|
|
18
|
+
'wedge',
|
|
19
|
+
'open',
|
|
20
|
+
'thumb',
|
|
21
|
+
'snap',
|
|
22
|
+
'turn',
|
|
23
|
+
'roll',
|
|
24
|
+
'breath',
|
|
25
|
+
'shortphrase',
|
|
26
|
+
'mediumphrase',
|
|
27
|
+
'longphrase',
|
|
28
|
+
'segno',
|
|
29
|
+
'coda',
|
|
30
|
+
'D.S.',
|
|
31
|
+
'D.C.',
|
|
32
|
+
'fine',
|
|
33
|
+
'beambr1',
|
|
34
|
+
'beambr2',
|
|
35
|
+
'slide',
|
|
36
|
+
'marcato',
|
|
37
|
+
'upbow',
|
|
38
|
+
'downbow',
|
|
39
|
+
'/',
|
|
40
|
+
'//',
|
|
41
|
+
'///',
|
|
42
|
+
'////',
|
|
43
|
+
'trem1',
|
|
44
|
+
'trem2',
|
|
45
|
+
'trem3',
|
|
46
|
+
'trem4',
|
|
47
|
+
'turnx',
|
|
48
|
+
'invertedturn',
|
|
49
|
+
'invertedturnx',
|
|
50
|
+
'trill(',
|
|
51
|
+
'trill)',
|
|
52
|
+
'arpeggio',
|
|
53
|
+
'xstem',
|
|
54
|
+
'mark',
|
|
55
|
+
'umarcato',
|
|
56
|
+
'style=normal',
|
|
57
|
+
'style=harmonic',
|
|
58
|
+
'style=rhythm',
|
|
59
|
+
'style=x',
|
|
60
|
+
'style=triangle',
|
|
61
|
+
'D.C.alcoda',
|
|
62
|
+
'D.C.alfine',
|
|
63
|
+
'D.S.alcoda',
|
|
64
|
+
'D.S.alfine',
|
|
65
|
+
'editorial',
|
|
66
|
+
'courtesy'
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
module.exports.volumeDecorations = [
|
|
70
|
+
'p',
|
|
71
|
+
'pp',
|
|
72
|
+
'f',
|
|
73
|
+
'ff',
|
|
74
|
+
'mf',
|
|
75
|
+
'mp',
|
|
76
|
+
'ppp',
|
|
77
|
+
'pppp',
|
|
78
|
+
'fff',
|
|
79
|
+
'ffff',
|
|
80
|
+
'sfz'
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
module.exports.dynamicDecorations = [
|
|
84
|
+
'crescendo(',
|
|
85
|
+
'crescendo)',
|
|
86
|
+
'diminuendo(',
|
|
87
|
+
'diminuendo)',
|
|
88
|
+
'glissando(',
|
|
89
|
+
'glissando)',
|
|
90
|
+
'~(',
|
|
91
|
+
'~)'
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
module.exports.accentPseudonyms = [
|
|
95
|
+
['<', 'accent'],
|
|
96
|
+
['>', 'accent'],
|
|
97
|
+
['tr', 'trill'],
|
|
98
|
+
['plus', '+'],
|
|
99
|
+
['emphasis', 'accent'],
|
|
100
|
+
['^', 'umarcato'],
|
|
101
|
+
['marcato', 'umarcato']
|
|
102
|
+
];
|
|
103
|
+
|
|
104
|
+
module.exports.accentDynamicPseudonyms = [
|
|
105
|
+
['<(', 'crescendo('],
|
|
106
|
+
['<)', 'crescendo)'],
|
|
107
|
+
['>(', 'diminuendo('],
|
|
108
|
+
['>)', 'diminuendo)']
|
|
109
|
+
];
|
|
110
|
+
|
|
111
|
+
module.exports.nonDecorations = 'ABCDEFGabcdefgxyzZ[]|^_{'; // use this to prescreen so we don't have to look for a decoration at every note.
|
|
112
|
+
|
|
113
|
+
module.exports.durations = [
|
|
114
|
+
0.5, 0.75, 0.875, 0.9375, 0.96875, 0.984375, 0.25, 0.375, 0.4375, 0.46875,
|
|
115
|
+
0.484375, 0.4921875, 0.125, 0.1875, 0.21875, 0.234375, 0.2421875, 0.24609375,
|
|
116
|
+
0.0625, 0.09375, 0.109375, 0.1171875, 0.12109375, 0.123046875, 0.03125,
|
|
117
|
+
0.046875, 0.0546875, 0.05859375, 0.060546875, 0.0615234375, 0.015625,
|
|
118
|
+
0.0234375, 0.02734375, 0.029296875, 0.0302734375, 0.03076171875
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
module.exports.pitches = {
|
|
122
|
+
A: 5,
|
|
123
|
+
B: 6,
|
|
124
|
+
C: 0,
|
|
125
|
+
D: 1,
|
|
126
|
+
E: 2,
|
|
127
|
+
F: 3,
|
|
128
|
+
G: 4,
|
|
129
|
+
a: 12,
|
|
130
|
+
b: 13,
|
|
131
|
+
c: 7,
|
|
132
|
+
d: 8,
|
|
133
|
+
e: 9,
|
|
134
|
+
f: 10,
|
|
135
|
+
g: 11
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
module.exports.rests = {
|
|
139
|
+
x: 'invisible',
|
|
140
|
+
X: 'invisible-multimeasure',
|
|
141
|
+
y: 'spacer',
|
|
142
|
+
z: 'rest',
|
|
143
|
+
Z: 'multimeasure'
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
module.exports.accMap = {
|
|
147
|
+
dblflat: '__',
|
|
148
|
+
flat: '_',
|
|
149
|
+
natural: '=',
|
|
150
|
+
sharp: '^',
|
|
151
|
+
dblsharp: '^^',
|
|
152
|
+
quarterflat: '_/',
|
|
153
|
+
quartersharp: '^/'
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
module.exports.tripletQ = {
|
|
157
|
+
2: 3,
|
|
158
|
+
3: 2,
|
|
159
|
+
4: 3,
|
|
160
|
+
5: 2, // TODO-PER: not handling 6/8 rhythm yet
|
|
161
|
+
6: 2,
|
|
162
|
+
7: 2, // TODO-PER: not handling 6/8 rhythm yet
|
|
163
|
+
8: 3,
|
|
164
|
+
9: 2 // TODO-PER: not handling 6/8 rhythm yet
|
|
165
|
+
};
|
package/src/synth/place-note.js
CHANGED
|
@@ -17,6 +17,12 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
|
|
|
17
17
|
len = 0.005; // Have some small audible length no matter how short the note is.
|
|
18
18
|
var offlineCtx = new OfflineAC(2,Math.floor((len+fadeTimeSec)*sampleRate),sampleRate);
|
|
19
19
|
var noteName = pitchToNoteName[sound.pitch];
|
|
20
|
+
if (!soundsCache[sound.instrument]) {
|
|
21
|
+
// It shouldn't happen that the entire instrument cache wasn't created, but this has been seen in practice, so guard against it.
|
|
22
|
+
if (debugCallback)
|
|
23
|
+
debugCallback('placeNote skipped (instrument empty): '+sound.instrument+':'+noteName)
|
|
24
|
+
return Promise.resolve();
|
|
25
|
+
}
|
|
20
26
|
var noteBufferPromise = soundsCache[sound.instrument][noteName];
|
|
21
27
|
|
|
22
28
|
if (!noteBufferPromise) {
|
package/src/synth/play-event.js
CHANGED
|
@@ -2,7 +2,7 @@ var SynthSequence = require('./synth-sequence');
|
|
|
2
2
|
var CreateSynth = require('./create-synth');
|
|
3
3
|
var activeAudioContext = require("./active-audio-context");
|
|
4
4
|
|
|
5
|
-
function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure) {
|
|
5
|
+
function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure, soundFontUrl, debugCallback) {
|
|
6
6
|
var sequence = new SynthSequence();
|
|
7
7
|
|
|
8
8
|
for (var i = 0; i < midiPitches.length; i++) {
|
|
@@ -21,18 +21,20 @@ function playEvent(midiPitches, midiGracePitches, millisecondsPerMeasure) {
|
|
|
21
21
|
var ac = activeAudioContext();
|
|
22
22
|
if (ac.state === "suspended") {
|
|
23
23
|
return ac.resume().then(function () {
|
|
24
|
-
return doPlay(sequence, millisecondsPerMeasure);
|
|
24
|
+
return doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback);
|
|
25
25
|
});
|
|
26
26
|
} else {
|
|
27
|
-
return doPlay(sequence, millisecondsPerMeasure);
|
|
27
|
+
return doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback);
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
function doPlay(sequence, millisecondsPerMeasure) {
|
|
31
|
+
function doPlay(sequence, millisecondsPerMeasure, soundFontUrl, debugCallback) {
|
|
32
32
|
var buffer = new CreateSynth();
|
|
33
33
|
return buffer.init({
|
|
34
34
|
sequence: sequence,
|
|
35
|
-
millisecondsPerMeasure: millisecondsPerMeasure
|
|
35
|
+
millisecondsPerMeasure: millisecondsPerMeasure,
|
|
36
|
+
options: { soundFontUrl: soundFontUrl },
|
|
37
|
+
debugCallback: debugCallback,
|
|
36
38
|
}).then(function () {
|
|
37
39
|
return buffer.prime();
|
|
38
40
|
}).then(function () {
|
|
@@ -177,10 +177,11 @@ TabAbsoluteElements.prototype.build = function (plugin,
|
|
|
177
177
|
tabVoice,
|
|
178
178
|
voiceIndex,
|
|
179
179
|
staffIndex,
|
|
180
|
-
keySig
|
|
180
|
+
keySig,
|
|
181
|
+
tabVoiceIndex ) {
|
|
181
182
|
var staffSize = getInitialStaffSize(staffAbsolute);
|
|
182
183
|
var source = staffAbsolute[staffIndex+voiceIndex];
|
|
183
|
-
var dest = staffAbsolute[
|
|
184
|
+
var dest = staffAbsolute[tabVoiceIndex];
|
|
184
185
|
var tabPos = null;
|
|
185
186
|
var defNote = null;
|
|
186
187
|
if (source.children[0].abcelem.el_type != 'clef') {
|
|
@@ -233,10 +233,11 @@ TabRenderer.prototype.doLayout = function () {
|
|
|
233
233
|
staffGroup.staffs[this.staffIndex].top += nameHeight;
|
|
234
234
|
staffGroup.height += nameHeight * spacing.STEP;
|
|
235
235
|
tabVoice.staff = staffGroupInfos;
|
|
236
|
+
var tabVoiceIndex = voices.length
|
|
236
237
|
voices.splice(voices.length, 0, tabVoice);
|
|
237
238
|
var keySig = checkVoiceKeySig(voices, ii + this.staffIndex);
|
|
238
239
|
this.tabStaff.voices[ii] = [];
|
|
239
|
-
this.absolutes.build(this.plugin, voices, this.tabStaff.voices[ii], ii , this.staffIndex ,keySig);
|
|
240
|
+
this.absolutes.build(this.plugin, voices, this.tabStaff.voices[ii], ii , this.staffIndex ,keySig, tabVoiceIndex);
|
|
240
241
|
}
|
|
241
242
|
linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
|
|
242
243
|
};
|
|
@@ -51,18 +51,18 @@
|
|
|
51
51
|
var parseCommon = require('../parse/abc_common');
|
|
52
52
|
var JSONSchema = require('./jsonschema-b4');
|
|
53
53
|
|
|
54
|
-
var
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
54
|
+
var { legalAccents } = require('../parse/abc_parse_settings');
|
|
55
|
+
|
|
56
|
+
var ParserLint = function () {
|
|
57
|
+
'use strict';
|
|
58
|
+
var decorationList = {
|
|
59
|
+
type: 'array',
|
|
60
|
+
optional: true,
|
|
61
|
+
items: {
|
|
62
|
+
type: 'string',
|
|
63
|
+
Enum: legalAccents
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
66
|
|
|
67
67
|
var tempoProperties = {
|
|
68
68
|
duration: { type: "array", optional: true, output: "join", requires: [ 'bpm'], items: { type: "number"} },
|
|
@@ -747,6 +747,12 @@ AbstractEngraver.prototype.addNoteToAbcElement = function (abselem, elem, dot, s
|
|
|
747
747
|
else
|
|
748
748
|
p1 += 1;
|
|
749
749
|
}
|
|
750
|
+
if (noteHead && noteHead.c === 'noteheads.triangle.quarter') {
|
|
751
|
+
if (dir === 'down')
|
|
752
|
+
p2 -= 0.7;
|
|
753
|
+
else
|
|
754
|
+
p1 -= 1.2;
|
|
755
|
+
}
|
|
750
756
|
abselem.addRight(new RelativeElement(null, dx, 0, p1, { "type": "stem", "pitch2": p2, linewidth: width, bottom: p1 - 1 }));
|
|
751
757
|
//var RelativeElement = function RelativeElement(c, dx, w, pitch, opt) {
|
|
752
758
|
min = Math.min(p1, p2);
|
|
@@ -313,10 +313,12 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
|
|
|
313
313
|
crescendo = { start: this.startCrescendoX, stop: abselem };
|
|
314
314
|
this.startCrescendoX = undefined;
|
|
315
315
|
break;
|
|
316
|
+
case '~(':
|
|
316
317
|
case "glissando(":
|
|
317
318
|
this.startGlissandoX = abselem;
|
|
318
319
|
glissando = undefined;
|
|
319
320
|
break;
|
|
321
|
+
case '~)':
|
|
320
322
|
case "glissando)":
|
|
321
323
|
glissando = { start: this.startGlissandoX, stop: abselem };
|
|
322
324
|
this.startGlissandoX = undefined;
|
|
@@ -105,7 +105,7 @@ glyphs['noteheads.slash.quarter'] = { d: [['M', 9, -6], ['l', 0, 4], ['l', -9, 9
|
|
|
105
105
|
|
|
106
106
|
glyphs['noteheads.harmonic.quarter'] = { d: [['M', 3.63, -4.02], ['c', 0.09, -0.06, 0.18, -0.09, 0.24, -0.03], ['c', 0.03, 0.03, 0.87, 0.93, 1.83, 2.01], ['c', 1.50, 1.65, 1.80, 1.98, 1.80, 2.04], ['c', 0.00, 0.06, -0.30, 0.39, -1.80, 2.04], ['c', -0.96, 1.08, -1.80, 1.98, -1.83, 2.01], ['c', -0.06, 0.06, -0.15, 0.03, -0.24, -0.03], ['c', -0.12, -0.09, -3.54, -3.84, -3.60, -3.93], ['c', -0.03, -0.03, -0.03, -0.09, -0.03, -0.15], ['c', 0.03, -0.06, 3.45, -3.84, 3.63, -3.96], ['z']], w: 7.5, h: 8.165 };
|
|
107
107
|
|
|
108
|
-
glyphs['noteheads.triangle.quarter'] = { d: [['M', 0,
|
|
108
|
+
glyphs['noteheads.triangle.quarter'] = { d: [['M', 0, 4], ['l', 9, 0], ['l', -4.5, -9], ['z']], w: 9, h: 9 };
|
|
109
109
|
|
|
110
110
|
var pathClone = function (pathArray) {
|
|
111
111
|
var res = [];
|
|
@@ -11,6 +11,7 @@ function drawGlissando(renderer, params, selectables) {
|
|
|
11
11
|
var rightY = renderer.calcY(params.anchor2.heads[0].pitch)
|
|
12
12
|
var leftX = params.anchor1.x + params.anchor1.w / 2
|
|
13
13
|
var rightX = params.anchor2.x + params.anchor2.w / 2
|
|
14
|
+
|
|
14
15
|
var len = lineLength(leftX, leftY, rightX, rightY)
|
|
15
16
|
var marginLeft = params.anchor1.w / 2 + margin
|
|
16
17
|
var marginRight = params.anchor2.w / 2 + margin
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function setPaperSize(renderer, maxwidth, scale, responsive) {
|
|
2
|
-
var w = (maxwidth + renderer.padding.right) * scale;
|
|
2
|
+
var w = (maxwidth + renderer.padding.left + renderer.padding.right) * scale;
|
|
3
3
|
var h = (renderer.y + renderer.padding.bottom) * scale;
|
|
4
4
|
if (renderer.isPrint)
|
|
5
5
|
h = Math.max(h, 1056); // 11in x 72pt/in x 1.33px/pt
|
package/src/write/draw/tie.js
CHANGED
|
@@ -17,7 +17,15 @@ function drawTie(renderer, params, linestartx, lineendx, selectables) {
|
|
|
17
17
|
klass = "abcjs-hint";
|
|
18
18
|
var fudgeY = params.fixedY ? 1.5 : 0; // TODO-PER: This just compensates for drawArc, which contains too much knowledge of ties and slurs.
|
|
19
19
|
var el = drawArc(renderer, params.startX, params.endX, params.startY + fudgeY, params.endY + fudgeY, params.above, klass, params.isTie, params.dotted);
|
|
20
|
-
|
|
20
|
+
var startChar = -1
|
|
21
|
+
// This gets the start and end points of the contents of the slur. We assume that the parenthesis are just to the outside of that.
|
|
22
|
+
if (params.anchor1 && !params.isTie)
|
|
23
|
+
startChar = params.anchor1.parent.abcelem.startChar - 1
|
|
24
|
+
var endChar = -1
|
|
25
|
+
if (params.anchor2 && !params.isTie)
|
|
26
|
+
endChar = params.anchor2.parent.abcelem.endChar + 1
|
|
27
|
+
|
|
28
|
+
selectables.wrapSvgEl({ el_type: "slur", startChar: startChar, endChar: endChar }, el);
|
|
21
29
|
return [el];
|
|
22
30
|
}
|
|
23
31
|
|
|
@@ -40,6 +40,7 @@ var EngraverController = function (paper, params) {
|
|
|
40
40
|
this.responsive = params.responsive;
|
|
41
41
|
this.space = 3 * spacing.SPACE;
|
|
42
42
|
this.initialClef = params.initialClef;
|
|
43
|
+
this.expandToWidest = !!params.expandToWidest;
|
|
43
44
|
this.scale = params.scale ? parseFloat(params.scale) : 0;
|
|
44
45
|
this.classes = new Classes({ shouldAddClasses: params.add_classes });
|
|
45
46
|
if (!(this.scale > 0.1))
|
|
@@ -242,7 +243,12 @@ EngraverController.prototype.engraveTune = function (abcTune, tuneNumber, lineOf
|
|
|
242
243
|
this.constructTuneElements(abcTune);
|
|
243
244
|
|
|
244
245
|
// Do all the positioning, both horizontally and vertically
|
|
245
|
-
var maxWidth = layout(this.renderer, abcTune, this.width, this.space);
|
|
246
|
+
var maxWidth = layout(this.renderer, abcTune, this.width, this.space, this.expandToWidest);
|
|
247
|
+
|
|
248
|
+
//Set the top text now that we know the width
|
|
249
|
+
if (this.expandToWidest && maxWidth > this.width+1) {
|
|
250
|
+
abcTune.topText = new TopText(abcTune.metaText, abcTune.metaTextInfo, abcTune.formatting, abcTune.lines, maxWidth, this.renderer.isPrint, this.renderer.padding.left, this.renderer.spacing, this.getTextSize);
|
|
251
|
+
}
|
|
246
252
|
|
|
247
253
|
// Deal with tablature for staff
|
|
248
254
|
if (abcTune.tablatures) {
|
|
@@ -127,6 +127,8 @@ function keyboardSelection(ev) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
function findElementInHistory(selectables, el) {
|
|
130
|
+
if (!el)
|
|
131
|
+
return -1;
|
|
130
132
|
for (var i = 0; i < selectables.length; i++) {
|
|
131
133
|
if (el.dataset.index === selectables[i].svgEl.dataset.index)
|
|
132
134
|
return i;
|
|
@@ -195,9 +197,13 @@ function getBestMatchCoordinates(dim, ev, scale) {
|
|
|
195
197
|
|
|
196
198
|
function getTarget(target) {
|
|
197
199
|
// This searches up the dom for the first item containing the attribute "selectable", or stopping at the SVG.
|
|
200
|
+
if (!target)
|
|
201
|
+
return null;
|
|
198
202
|
if (target.tagName === "svg")
|
|
199
203
|
return target;
|
|
200
204
|
|
|
205
|
+
if (!target.getAttribute)
|
|
206
|
+
return null;
|
|
201
207
|
var found = target.getAttribute("selectable");
|
|
202
208
|
while (!found) {
|
|
203
209
|
if (!target.parentElement)
|
|
@@ -3,7 +3,7 @@ var setUpperAndLowerElements = require('./set-upper-and-lower-elements');
|
|
|
3
3
|
var layoutStaffGroup = require('./staff-group');
|
|
4
4
|
var getLeftEdgeOfStaff = require('./get-left-edge-of-staff');
|
|
5
5
|
|
|
6
|
-
var layout = function (renderer, abctune, width, space) {
|
|
6
|
+
var layout = function (renderer, abctune, width, space, expandToWidest) {
|
|
7
7
|
var i;
|
|
8
8
|
var abcLine;
|
|
9
9
|
// Adjust the x-coordinates to their absolute positions
|
|
@@ -11,8 +11,14 @@ var layout = function (renderer, abctune, width, space) {
|
|
|
11
11
|
for (i = 0; i < abctune.lines.length; i++) {
|
|
12
12
|
abcLine = abctune.lines[i];
|
|
13
13
|
if (abcLine.staff) {
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
// console.log("=== line", i)
|
|
15
|
+
var thisWidth = setXSpacing(renderer, maxWidth, space, abcLine.staffGroup, abctune.formatting, i === abctune.lines.length - 1, false);
|
|
16
|
+
// console.log(thisWidth, maxWidth)
|
|
17
|
+
if (Math.round(thisWidth) > Math.round(maxWidth)) { // to take care of floating point weirdness
|
|
18
|
+
maxWidth = thisWidth
|
|
19
|
+
if (expandToWidest)
|
|
20
|
+
i = -1 // do the calculations over with the new width
|
|
21
|
+
}
|
|
16
22
|
}
|
|
17
23
|
}
|
|
18
24
|
|
|
@@ -41,15 +47,39 @@ var setXSpacing = function (renderer, width, space, staffGroup, formatting, isLa
|
|
|
41
47
|
var leftEdge = getLeftEdgeOfStaff(renderer, staffGroup.getTextSize, staffGroup.voices, staffGroup.brace, staffGroup.bracket);
|
|
42
48
|
var newspace = space;
|
|
43
49
|
for (var it = 0; it < 8; it++) { // TODO-PER: shouldn't need multiple passes, but each pass gets it closer to the right spacing. (Only affects long lines: normal lines break out of this loop quickly.)
|
|
50
|
+
// console.log("iteration", it)
|
|
51
|
+
// dumpGroup("before", staffGroup)
|
|
44
52
|
var ret = layoutStaffGroup(newspace, renderer, debug, staffGroup, leftEdge);
|
|
53
|
+
// dumpGroup("after",staffGroup)
|
|
45
54
|
newspace = calcHorizontalSpacing(isLastLine, formatting.stretchlast, width + renderer.padding.left, staffGroup.w, newspace, ret.spacingUnits, ret.minSpace, renderer.padding.left + renderer.padding.right);
|
|
46
55
|
if (debug)
|
|
47
56
|
console.log("setXSpace", it, staffGroup.w, newspace, staffGroup.minspace);
|
|
48
57
|
if (newspace === null) break;
|
|
49
58
|
}
|
|
50
59
|
centerWholeRests(staffGroup.voices);
|
|
60
|
+
return staffGroup.w - leftEdge
|
|
51
61
|
};
|
|
52
62
|
|
|
63
|
+
// function dumpGroup(label, staffGroup) {
|
|
64
|
+
// var output = {
|
|
65
|
+
// line: staffGroup.line,
|
|
66
|
+
// w: staffGroup.w,
|
|
67
|
+
// voice: {
|
|
68
|
+
// i: staffGroup.voices[0].i,
|
|
69
|
+
// minx: staffGroup.voices[0].minx,
|
|
70
|
+
// nextx: staffGroup.voices[0].nextx,
|
|
71
|
+
// spacingduration: staffGroup.voices[0].spacingduration,
|
|
72
|
+
// w: staffGroup.voices[0].w,
|
|
73
|
+
// children: [],
|
|
74
|
+
// }
|
|
75
|
+
// }
|
|
76
|
+
// for (var i = 0; i < staffGroup.voices[0].children.length; i++) {
|
|
77
|
+
// var child = staffGroup.voices[0].children[i]
|
|
78
|
+
// output.voice.children.push({ fixedW: child.fixed.w, w: child.w, x: child.x, type: child.type })
|
|
79
|
+
// }
|
|
80
|
+
// console.log(label,output)
|
|
81
|
+
// }
|
|
82
|
+
|
|
53
83
|
function calcHorizontalSpacing(isLastLine, stretchLast, targetWidth, lineWidth, spacing, spacingUnits, minSpace, padding) {
|
|
54
84
|
if (isLastLine) {
|
|
55
85
|
if (stretchLast === undefined) {
|