abcjs 6.1.8 → 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 +66 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +4373 -4424
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/index.js +1 -1
- package/package.json +6 -6
- 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/midi/abc_midi_create.js +8 -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 +89 -106
- package/src/parse/abc_tokenizer.js +60 -60
- package/src/parse/abc_transpose.js +14 -3
- package/src/parse/tune-builder.js +19 -14
- package/src/synth/abc_midi_flattener.js +25 -9
- package/src/synth/abc_midi_sequencer.js +1 -1
- 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 +8 -5
- 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} +8 -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 +99 -22
- 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 -341
- 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
package/index.js
CHANGED
|
@@ -42,7 +42,7 @@ Object.keys(tuneBook).forEach(function (key) {
|
|
|
42
42
|
abcjs.renderAbc = require('./src/api/abc_tunebook_svg');
|
|
43
43
|
abcjs.TimingCallbacks = require('./src/api/abc_timing_callbacks');
|
|
44
44
|
|
|
45
|
-
var glyphs = require('./src/write/
|
|
45
|
+
var glyphs = require('./src/write/creation/glyphs');
|
|
46
46
|
abcjs.setGlyph = glyphs.setSymbol;
|
|
47
47
|
abcjs.strTranspose = strTranspose;
|
|
48
48
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abcjs",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.2.0",
|
|
4
4
|
"description": "Renderer for abc music notation",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -44,16 +44,16 @@
|
|
|
44
44
|
},
|
|
45
45
|
"homepage": "https://abcjs.net",
|
|
46
46
|
"devDependencies": {
|
|
47
|
-
"@babel/core": "7.20.
|
|
47
|
+
"@babel/core": "7.20.12",
|
|
48
48
|
"@babel/preset-env": "7.20.2",
|
|
49
49
|
"@tarp/require": "1.4.3",
|
|
50
|
-
"babel-loader": "9.1.
|
|
50
|
+
"babel-loader": "9.1.2",
|
|
51
51
|
"chai": "4.3.7",
|
|
52
|
-
"concurrently": "7.
|
|
52
|
+
"concurrently": "7.6.0",
|
|
53
53
|
"http-server": "14.1.1",
|
|
54
|
-
"mocha": "10.
|
|
54
|
+
"mocha": "10.2.0",
|
|
55
55
|
"opener": "1.5.2",
|
|
56
|
-
"vuepress": "2.0.0-beta.
|
|
56
|
+
"vuepress": "2.0.0-beta.60",
|
|
57
57
|
"vuex": "4.1.0",
|
|
58
58
|
"webpack-bundle-analyzer": "4.7.0",
|
|
59
59
|
"webpack-cli": "4.10.0"
|
package/plugin.js
CHANGED
|
@@ -28,7 +28,7 @@ THE SOFTWARE.
|
|
|
28
28
|
|
|
29
29
|
var TuneBook = require('./src/api/abc_tunebook').TuneBook;
|
|
30
30
|
var Parse = require('./src/parse/abc_parse');
|
|
31
|
-
var EngraverController = require('./src/write/
|
|
31
|
+
var EngraverController = require('./src/write/engraver-controller');
|
|
32
32
|
|
|
33
33
|
var Plugin = function() {
|
|
34
34
|
"use strict";
|
|
@@ -128,7 +128,7 @@ var TimingCallbacks = function(target, params) {
|
|
|
128
128
|
var ev;
|
|
129
129
|
if (next < self.noteTimings.length) {
|
|
130
130
|
endMs = self.noteTimings[next].milliseconds;
|
|
131
|
-
next = self.currentEvent - 1;
|
|
131
|
+
next = Math.max(0, self.currentEvent - 1);
|
|
132
132
|
while (next >= 0 && self.noteTimings[next].left === null)
|
|
133
133
|
next--;
|
|
134
134
|
|
|
@@ -153,15 +153,19 @@ var TimingCallbacks = function(target, params) {
|
|
|
153
153
|
var offMs = Math.max(0, timestamp-self.startTime-ev.milliseconds); // Offset in time from the last beat
|
|
154
154
|
var gapMs = endMs - ev.milliseconds; // Length of this event in time
|
|
155
155
|
var gapPx = ev.endX - ev.left; // The length in pixels
|
|
156
|
-
var offPx = offMs * gapPx / gapMs;
|
|
156
|
+
var offPx = gapMs ? offMs * gapPx / gapMs : 0;
|
|
157
157
|
position.left = ev.left + offPx;
|
|
158
|
+
// See if this is before the first event - that is the case where there are "prep beats"
|
|
159
|
+
if (self.currentEvent === 0 && ev.milliseconds > timestamp-self.startTime)
|
|
160
|
+
position.left = undefined
|
|
161
|
+
|
|
158
162
|
debugInfo = {
|
|
159
163
|
timestamp: timestamp,
|
|
160
164
|
startTime: self.startTime,
|
|
161
165
|
ev: ev,
|
|
162
166
|
endMs: endMs,
|
|
163
167
|
offMs: offMs,
|
|
164
|
-
|
|
168
|
+
offPx: offPx,
|
|
165
169
|
gapMs: gapMs,
|
|
166
170
|
gapPx: gapPx
|
|
167
171
|
};
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
var tunebook = require('./abc_tunebook');
|
|
2
2
|
var Tune = require('../data/abc_tune');
|
|
3
3
|
|
|
4
|
-
var EngraverController = require('../write/
|
|
4
|
+
var EngraverController = require('../write/engraver-controller');
|
|
5
5
|
var Parse = require('../parse/abc_parse');
|
|
6
6
|
var wrap = require('../parse/wrap_lines');
|
|
7
|
-
var parseCommon = require("../parse/abc_common");
|
|
8
7
|
// var tablatures = require('./abc_tablatures');
|
|
9
8
|
|
|
10
9
|
|
package/src/data/abc_tune.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// abc_tune.js: a computer usable internal structure representing one tune.
|
|
2
2
|
|
|
3
3
|
var parseCommon = require('../parse/abc_common');
|
|
4
|
-
var spacing = require('../write/
|
|
4
|
+
var spacing = require('../write/helpers/spacing');
|
|
5
5
|
var sequence = require('../synth/abc_midi_sequencer');
|
|
6
6
|
var flatten = require('../synth/abc_midi_flattener');
|
|
7
7
|
var delineTune = require("./deline-tune");
|
|
@@ -611,7 +611,7 @@ var Tune = function() {
|
|
|
611
611
|
this.setUpAudio = function(options) {
|
|
612
612
|
if (!options) options = {};
|
|
613
613
|
var seq = sequence(this, options);
|
|
614
|
-
return flatten(seq, options, this.formatting.percmap);
|
|
614
|
+
return flatten(seq, options, this.formatting.percmap, this.formatting.midi);
|
|
615
615
|
};
|
|
616
616
|
this.deline = function(options) {
|
|
617
617
|
return delineTune(this.lines, options);
|
|
@@ -36,8 +36,14 @@ var create;
|
|
|
36
36
|
var pan = 0;
|
|
37
37
|
if (options.pan && options.pan.length > i)
|
|
38
38
|
pan = options.pan[i];
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
if (event.instrument === 128) {
|
|
40
|
+
// If we're using the percussion voice, change to Channel 10
|
|
41
|
+
midi.setChannel(9, pan);
|
|
42
|
+
midi.setInstrument(0);
|
|
43
|
+
} else {
|
|
44
|
+
midi.setChannel(event.channel, pan);
|
|
45
|
+
midi.setInstrument(event.instrument);
|
|
46
|
+
}
|
|
41
47
|
break;
|
|
42
48
|
case 'note':
|
|
43
49
|
var gapLengthInBeats = event.gap * beatsPerSecond;
|
package/src/parse/abc_common.js
CHANGED
|
@@ -34,10 +34,6 @@ parseCommon.cloneHashOfArrayOfHash = function(source) {
|
|
|
34
34
|
return destination;
|
|
35
35
|
};
|
|
36
36
|
|
|
37
|
-
parseCommon.gsub = function(source, pattern, replacement) {
|
|
38
|
-
return source.split(pattern).join(replacement);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
37
|
parseCommon.strip = function(str) {
|
|
42
38
|
return str.replace(/^\s+/, '').replace(/\s+$/, '');
|
|
43
39
|
};
|
|
@@ -51,54 +47,11 @@ parseCommon.endsWith = function(str, pattern) {
|
|
|
51
47
|
return d >= 0 && str.lastIndexOf(pattern) === d;
|
|
52
48
|
};
|
|
53
49
|
|
|
54
|
-
parseCommon.each = function(arr, iterator, context) {
|
|
55
|
-
for (var i = 0, length = arr.length; i < length; i++)
|
|
56
|
-
iterator.apply(context, [arr[i],i]);
|
|
57
|
-
};
|
|
58
|
-
|
|
59
50
|
parseCommon.last = function(arr) {
|
|
60
51
|
if (arr.length === 0)
|
|
61
52
|
return null;
|
|
62
53
|
return arr[arr.length-1];
|
|
63
54
|
};
|
|
64
55
|
|
|
65
|
-
parseCommon.compact = function(arr) {
|
|
66
|
-
var output = [];
|
|
67
|
-
for (var i = 0; i < arr.length; i++) {
|
|
68
|
-
if (arr[i])
|
|
69
|
-
output.push(arr[i]);
|
|
70
|
-
}
|
|
71
|
-
return output;
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
parseCommon.detect = function(arr, iterator) {
|
|
75
|
-
for (var i = 0; i < arr.length; i++) {
|
|
76
|
-
if (iterator(arr[i]))
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
return false;
|
|
80
|
-
};
|
|
81
56
|
|
|
82
|
-
// The following is a polyfill for Object.remove for IE9, IE10, and IE11.
|
|
83
|
-
// from:https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md
|
|
84
|
-
try {
|
|
85
|
-
(function (arr) {
|
|
86
|
-
arr.forEach(function (item) {
|
|
87
|
-
if (item.hasOwnProperty('remove')) {
|
|
88
|
-
return;
|
|
89
|
-
}
|
|
90
|
-
Object.defineProperty(item, 'remove', {
|
|
91
|
-
configurable: true,
|
|
92
|
-
enumerable: true,
|
|
93
|
-
writable: true,
|
|
94
|
-
value: function remove() {
|
|
95
|
-
if (this.parentNode !== null)
|
|
96
|
-
this.parentNode.removeChild(this);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
})([Element.prototype, CharacterData.prototype, DocumentType.prototype]);
|
|
101
|
-
} catch(e) {
|
|
102
|
-
// if we aren't in a browser, this code will crash, but it is not needed then either.
|
|
103
|
-
}
|
|
104
57
|
module.exports = parseCommon;
|
package/src/parse/abc_parse.js
CHANGED
|
@@ -181,16 +181,16 @@ var Parse = function() {
|
|
|
181
181
|
};
|
|
182
182
|
|
|
183
183
|
var encode = function(str) {
|
|
184
|
-
var ret =
|
|
185
|
-
ret =
|
|
186
|
-
ret =
|
|
187
|
-
return
|
|
184
|
+
var ret = str.replace(/\x12/g, ' ');
|
|
185
|
+
ret = ret.replace(/&/g, '&');
|
|
186
|
+
ret = ret.replace(/</g, '<');
|
|
187
|
+
return ret.replace(/>/g, '>');
|
|
188
188
|
};
|
|
189
189
|
|
|
190
190
|
var warn = function(str, line, col_num) {
|
|
191
191
|
if (!line) line = " ";
|
|
192
|
-
var bad_char = line
|
|
193
|
-
if (bad_char === ' ')
|
|
192
|
+
var bad_char = line[col_num];
|
|
193
|
+
if (bad_char === ' ' || !bad_char)
|
|
194
194
|
bad_char = "SPACE";
|
|
195
195
|
var clean_line = encode(line.substring(col_num - 64, col_num)) + '<span style="text-decoration:underline;font-size:1.3em;font-weight:bold;">' + bad_char + '</span>' + encode(line.substring(col_num + 1).substring(0,64));
|
|
196
196
|
addWarning("Music Line:" + tokenizer.lineIndex + ":" + (col_num+1) + ': ' + str + ": " + clean_line);
|
|
@@ -217,7 +217,7 @@ var Parse = function() {
|
|
|
217
217
|
|
|
218
218
|
if (!line) { warn("Can't add words before the first line of music", line, 0); return; }
|
|
219
219
|
words = parseCommon.strip(words);
|
|
220
|
-
if (words
|
|
220
|
+
if (words[words.length-1] !== '-')
|
|
221
221
|
words = words + ' '; // Just makes it easier to parse below, since every word has a divider after it.
|
|
222
222
|
var word_list = [];
|
|
223
223
|
// first make a list of words from the string we are passed. A word is divided on either a space or dash.
|
|
@@ -229,8 +229,8 @@ var Parse = function() {
|
|
|
229
229
|
last_divider = i+1;
|
|
230
230
|
if (word.length > 0) {
|
|
231
231
|
if (replace)
|
|
232
|
-
word =
|
|
233
|
-
var div = words
|
|
232
|
+
word = word.replace(/~/g, ' ');
|
|
233
|
+
var div = words[i];
|
|
234
234
|
if (div !== '_' && div !== '-')
|
|
235
235
|
div = ' ';
|
|
236
236
|
word_list.push({syllable: tokenizer.translateString(word), divider: div});
|
|
@@ -280,7 +280,7 @@ var Parse = function() {
|
|
|
280
280
|
}
|
|
281
281
|
|
|
282
282
|
var inSlur = false;
|
|
283
|
-
|
|
283
|
+
line.forEach(function(el) {
|
|
284
284
|
if (word_list.length !== 0) {
|
|
285
285
|
if (word_list[0].skip) {
|
|
286
286
|
switch (word_list[0].to) {
|
|
@@ -320,7 +320,7 @@ var Parse = function() {
|
|
|
320
320
|
// TODO-PER: Currently copied from w: line. This needs to be read as symbols instead.
|
|
321
321
|
if (!line) { warn("Can't add symbols before the first line of music", line, 0); return; }
|
|
322
322
|
words = parseCommon.strip(words);
|
|
323
|
-
if (words
|
|
323
|
+
if (words[words.length-1] !== '-')
|
|
324
324
|
words = words + ' '; // Just makes it easier to parse below, since every word has a divider after it.
|
|
325
325
|
var word_list = [];
|
|
326
326
|
// first make a list of words from the string we are passed. A word is divided on either a space or dash.
|
|
@@ -331,8 +331,8 @@ var Parse = function() {
|
|
|
331
331
|
last_divider = i+1;
|
|
332
332
|
if (word.length > 0) {
|
|
333
333
|
if (replace)
|
|
334
|
-
word =
|
|
335
|
-
var div = words
|
|
334
|
+
word = word.replace(/~/g, ' ');
|
|
335
|
+
var div = words[i];
|
|
336
336
|
if (div !== '_' && div !== '-')
|
|
337
337
|
div = ' ';
|
|
338
338
|
word_list.push({syllable: tokenizer.translateString(word), divider: div});
|
|
@@ -342,7 +342,7 @@ var Parse = function() {
|
|
|
342
342
|
return false;
|
|
343
343
|
};
|
|
344
344
|
for (var i = 0; i < words.length; i++) {
|
|
345
|
-
switch (words
|
|
345
|
+
switch (words[i]) {
|
|
346
346
|
case ' ':
|
|
347
347
|
case '\x12':
|
|
348
348
|
addWord(i);
|
|
@@ -372,7 +372,7 @@ var Parse = function() {
|
|
|
372
372
|
}
|
|
373
373
|
|
|
374
374
|
var inSlur = false;
|
|
375
|
-
|
|
375
|
+
line.forEach(function(el) {
|
|
376
376
|
if (word_list.length !== 0) {
|
|
377
377
|
if (word_list[0].skip) {
|
|
378
378
|
switch (word_list[0].to) {
|
|
@@ -416,7 +416,7 @@ var Parse = function() {
|
|
|
416
416
|
addSymbols(tuneBuilder.getCurrentVoice(), line.substring(2));
|
|
417
417
|
return
|
|
418
418
|
}
|
|
419
|
-
if (line.length < 2 || line
|
|
419
|
+
if (line.length < 2 || line[1] !== ':' || music.lineContinuation) {
|
|
420
420
|
music.parseMusic(line);
|
|
421
421
|
return
|
|
422
422
|
}
|
|
@@ -15,7 +15,7 @@ var bookParser = function(book) {
|
|
|
15
15
|
// Keep track of the character position each tune starts with. If the string starts with white space, count that, too.
|
|
16
16
|
var pos = initialWhiteSpace ? initialWhiteSpace[0].length : 0;
|
|
17
17
|
var tunes = [];
|
|
18
|
-
|
|
18
|
+
tuneStrings.forEach(function(tune) {
|
|
19
19
|
tunes.push({ abc: tune, startPos: pos});
|
|
20
20
|
pos += tune.length + 1; // We also lost a newline when splitting, so count that.
|
|
21
21
|
});
|
|
@@ -25,7 +25,7 @@ var bookParser = function(book) {
|
|
|
25
25
|
// the tune is parsed all at once. The directives will be seen before the engraver begins processing.
|
|
26
26
|
var dir = tunes.shift();
|
|
27
27
|
var arrDir = dir.abc.split('\n');
|
|
28
|
-
|
|
28
|
+
arrDir.forEach(function(line) {
|
|
29
29
|
if (parseCommon.startsWith(line, '%%'))
|
|
30
30
|
directives += line + '\n';
|
|
31
31
|
});
|
|
@@ -33,7 +33,7 @@ var bookParser = function(book) {
|
|
|
33
33
|
var header = directives;
|
|
34
34
|
|
|
35
35
|
// Now, the tune ends at a blank line, so truncate it if needed. There may be "intertune" stuff.
|
|
36
|
-
|
|
36
|
+
tunes.forEach(function(tune) {
|
|
37
37
|
var end = tune.abc.indexOf('\n\n');
|
|
38
38
|
if (end > 0)
|
|
39
39
|
tune.abc = tune.abc.substring(0, end);
|
|
@@ -330,7 +330,7 @@ var parseDirective = {};
|
|
|
330
330
|
|
|
331
331
|
var setScale = function(cmd, tokens) {
|
|
332
332
|
var scratch = "";
|
|
333
|
-
|
|
333
|
+
tokens.forEach(function(tok) {
|
|
334
334
|
scratch += tok.token;
|
|
335
335
|
});
|
|
336
336
|
var num = parseFloat(scratch);
|
|
@@ -485,6 +485,8 @@ var parseDirective = {};
|
|
|
485
485
|
var midiCmdParam1Integer = [
|
|
486
486
|
"bassvol",
|
|
487
487
|
"chordvol",
|
|
488
|
+
"bassprog",
|
|
489
|
+
"chordprog",
|
|
488
490
|
"c",
|
|
489
491
|
"channel",
|
|
490
492
|
"beatmod",
|
|
@@ -686,15 +688,15 @@ var parseDirective = {};
|
|
|
686
688
|
if (textParts.length > 1 && multilineVars.setfont) {
|
|
687
689
|
var textarr = [ { text: textParts[0] }];
|
|
688
690
|
for (var i = 1; i < textParts.length; i++) {
|
|
689
|
-
if (textParts[i]
|
|
691
|
+
if (textParts[i][0] === '0')
|
|
690
692
|
textarr.push({ text: textParts[i].substring(1) });
|
|
691
|
-
else if (textParts[i]
|
|
693
|
+
else if (textParts[i][0] === '1' && multilineVars.setfont[1])
|
|
692
694
|
textarr.push({font: multilineVars.setfont[1], text: textParts[i].substring(1) });
|
|
693
|
-
else if (textParts[i]
|
|
695
|
+
else if (textParts[i][0] === '2' && multilineVars.setfont[2])
|
|
694
696
|
textarr.push({font: multilineVars.setfont[2], text: textParts[i].substring(1) });
|
|
695
|
-
else if (textParts[i]
|
|
697
|
+
else if (textParts[i][0] === '3' && multilineVars.setfont[3])
|
|
696
698
|
textarr.push({font: multilineVars.setfont[3], text: textParts[i].substring(1) });
|
|
697
|
-
else if (textParts[i]
|
|
699
|
+
else if (textParts[i][0] === '4' && multilineVars.setfont[4])
|
|
698
700
|
textarr.push({font: multilineVars.setfont[4], text: textParts[i].substring(1) });
|
|
699
701
|
else
|
|
700
702
|
textarr[textarr.length-1].text += '$' + textParts[i];
|
|
@@ -746,6 +748,7 @@ var parseDirective = {};
|
|
|
746
748
|
case "bagpipes":tune.formatting.bagpipes = true;break;
|
|
747
749
|
case "flatbeams":tune.formatting.flatbeams = true;break;
|
|
748
750
|
case "jazzchords":tune.formatting.jazzchords = true;break;
|
|
751
|
+
case "germanAlphabet":tune.formatting.germanAlphabet = true;break;
|
|
749
752
|
case "landscape":multilineVars.landscape = true;break;
|
|
750
753
|
case "papersize":multilineVars.papersize = restOfString;break;
|
|
751
754
|
case "graceslurs":
|
|
@@ -758,6 +761,13 @@ var parseDirective = {};
|
|
|
758
761
|
else
|
|
759
762
|
return "Directive graceslurs requires one parameter: 0 or 1 (received " + tokens[0].token + ')';
|
|
760
763
|
break;
|
|
764
|
+
case "lineThickness":
|
|
765
|
+
var lt = parseStretchLast(tokens);
|
|
766
|
+
if (lt.value !== undefined)
|
|
767
|
+
tune.formatting.lineThickness = lt.value;
|
|
768
|
+
if (lt.error)
|
|
769
|
+
return lt.error;
|
|
770
|
+
break;
|
|
761
771
|
case "stretchlast":
|
|
762
772
|
var sl = parseStretchLast(tokens);
|
|
763
773
|
if (sl.value !== undefined)
|
|
@@ -807,6 +817,15 @@ var parseDirective = {};
|
|
|
807
817
|
tuneBuilder.changeVoiceScale(multilineVars.currentVoice.scale);
|
|
808
818
|
}
|
|
809
819
|
return null;
|
|
820
|
+
case "voicecolor":
|
|
821
|
+
if (tokens.length !== 1) // this could either be of type alpha or quote, but it's ok if it is a number
|
|
822
|
+
return "voicecolor requires one string as a parameter";
|
|
823
|
+
var voiceColor = tokens.shift();
|
|
824
|
+
if (multilineVars.currentVoice) {
|
|
825
|
+
multilineVars.currentVoice.color = voiceColor.token;
|
|
826
|
+
tuneBuilder.changeVoiceColor(multilineVars.currentVoice.color);
|
|
827
|
+
}
|
|
828
|
+
return null;
|
|
810
829
|
case "vskip":
|
|
811
830
|
var vskip = Math.round(getRequiredMeasurement(cmd, tokens));
|
|
812
831
|
if (vskip.error)
|
|
@@ -1081,7 +1100,7 @@ var parseDirective = {};
|
|
|
1081
1100
|
case "footer":
|
|
1082
1101
|
var footerStr = tokenizer.getMeat(restOfString, 0, restOfString.length);
|
|
1083
1102
|
footerStr = restOfString.substring(footerStr.start, footerStr.end);
|
|
1084
|
-
if (footerStr
|
|
1103
|
+
if (footerStr[0] === '"' && footerStr[footerStr.length-1] === '"' )
|
|
1085
1104
|
footerStr = footerStr.substring(1, footerStr.length-1);
|
|
1086
1105
|
var footerArr = footerStr.split('\t');
|
|
1087
1106
|
var footer = {};
|
|
@@ -189,7 +189,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
189
189
|
};
|
|
190
190
|
|
|
191
191
|
this.setDefaultLength = function(line, start, end) {
|
|
192
|
-
var len =
|
|
192
|
+
var len = line.substring(start, end).replace(/ /g, "");
|
|
193
193
|
var len_arr = len.split('/');
|
|
194
194
|
if (len_arr.length === 2) {
|
|
195
195
|
var n = parseInt(len_arr[0]);
|
|
@@ -346,7 +346,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
346
346
|
{
|
|
347
347
|
var ws = tokenizer.eatWhiteSpace(line, i);
|
|
348
348
|
i +=ws;
|
|
349
|
-
if (line.length >= i+5 && line
|
|
349
|
+
if (line.length >= i+5 && line[i] === '[' && line[i+2] === ':') {
|
|
350
350
|
var e = line.indexOf(']', i);
|
|
351
351
|
var startChar = multilineVars.iChar + i;
|
|
352
352
|
var endChar = multilineVars.iChar + e + 1;
|
|
@@ -393,16 +393,18 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
393
393
|
else
|
|
394
394
|
multilineVars.tempoForNextLine = ['tempo', startChar, endChar, tempo.tempo]
|
|
395
395
|
}
|
|
396
|
-
return [ e-i+1+ws, line
|
|
396
|
+
return [ e-i+1+ws, line[i+1], line.substring(i+3, e)];
|
|
397
397
|
}
|
|
398
398
|
break;
|
|
399
399
|
case "[V:":
|
|
400
400
|
if (e > 0) {
|
|
401
401
|
parseKeyVoice.parseVoice(line, i+3, e);
|
|
402
402
|
//startNewLine();
|
|
403
|
-
return [ e-i+1+ws, line
|
|
403
|
+
return [ e-i+1+ws, line[i+1], line.substring(i+3, e)];
|
|
404
404
|
}
|
|
405
405
|
break;
|
|
406
|
+
case "[r:":
|
|
407
|
+
return [ e-i+1+ws ];
|
|
406
408
|
|
|
407
409
|
default:
|
|
408
410
|
// TODO: complain about unhandled header
|
|
@@ -445,11 +447,11 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
445
447
|
var tempo = this.setTempo(line, i+2, e, multilineVars.iChar);
|
|
446
448
|
if (tempo.type === 'delaySet') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, this.calcTempo(tempo.tempo));
|
|
447
449
|
else if (tempo.type === 'immediate') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, tempo.tempo);
|
|
448
|
-
return [ e, line
|
|
450
|
+
return [ e, line[i], parseCommon.strip(line.substring(i+2))];
|
|
449
451
|
case "V:":
|
|
450
452
|
parseKeyVoice.parseVoice(line, i+2, line.length);
|
|
451
453
|
// startNewLine();
|
|
452
|
-
return [ line.length, line
|
|
454
|
+
return [ line.length, line[i], parseCommon.strip(line.substring(i+2))];
|
|
453
455
|
default:
|
|
454
456
|
// TODO: complain about unhandled header
|
|
455
457
|
}
|
|
@@ -474,7 +476,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
474
476
|
};
|
|
475
477
|
|
|
476
478
|
this.parseHeader = function(line) {
|
|
477
|
-
var field = metaTextHeaders[line
|
|
479
|
+
var field = metaTextHeaders[line[0]];
|
|
478
480
|
if (field !== undefined) {
|
|
479
481
|
if (field === 'unalignedWords')
|
|
480
482
|
tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line.substring(2)))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
@@ -484,12 +486,12 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
484
486
|
} else {
|
|
485
487
|
var startChar = multilineVars.iChar;
|
|
486
488
|
var endChar = startChar + line.length;
|
|
487
|
-
switch(line
|
|
489
|
+
switch(line[0])
|
|
488
490
|
{
|
|
489
491
|
case 'H':
|
|
490
492
|
tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line.substring(2))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
491
493
|
line = tokenizer.peekLine()
|
|
492
|
-
while (line && line
|
|
494
|
+
while (line && line[1] !== ':') {
|
|
493
495
|
tokenizer.nextLine()
|
|
494
496
|
tuneBuilder.addMetaText("history", tokenizer.translateString(tokenizer.stripComment(line)), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
495
497
|
line = tokenizer.peekLine()
|
|
@@ -83,7 +83,7 @@ var parseKeyVoice = {};
|
|
|
83
83
|
|
|
84
84
|
parseKeyVoice.deepCopyKey = function(key) {
|
|
85
85
|
var ret = { accidentals: [], root: key.root, acc: key.acc, mode: key.mode };
|
|
86
|
-
|
|
86
|
+
key.accidentals.forEach(function(k) {
|
|
87
87
|
ret.accidentals.push(parseCommon.clone(k));
|
|
88
88
|
});
|
|
89
89
|
return ret;
|
|
@@ -95,20 +95,20 @@ var parseKeyVoice = {};
|
|
|
95
95
|
// Shift the key signature from the treble positions to whatever position is needed for the clef.
|
|
96
96
|
// This may put the key signature unnaturally high or low, so if it does, then shift it.
|
|
97
97
|
var mid = clef.verticalPos;
|
|
98
|
-
|
|
98
|
+
key.accidentals.forEach(function(acc) {
|
|
99
99
|
var pitch = pitches[acc.note];
|
|
100
100
|
pitch = pitch - mid;
|
|
101
101
|
acc.verticalPos = pitch;
|
|
102
102
|
});
|
|
103
103
|
if (key.impliedNaturals)
|
|
104
|
-
|
|
104
|
+
key.impliedNaturals.forEach(function(acc) {
|
|
105
105
|
var pitch = pitches[acc.note];
|
|
106
106
|
pitch = pitch - mid;
|
|
107
107
|
acc.verticalPos = pitch;
|
|
108
108
|
});
|
|
109
109
|
|
|
110
110
|
if (mid < -10) {
|
|
111
|
-
|
|
111
|
+
key.accidentals.forEach(function(acc) {
|
|
112
112
|
acc.verticalPos -= 7;
|
|
113
113
|
if (acc.verticalPos >= 11 || (acc.verticalPos === 10 && acc.acc === 'flat'))
|
|
114
114
|
acc.verticalPos -= 7;
|
|
@@ -118,7 +118,7 @@ var parseKeyVoice = {};
|
|
|
118
118
|
acc.verticalPos -=7;
|
|
119
119
|
});
|
|
120
120
|
if (key.impliedNaturals)
|
|
121
|
-
|
|
121
|
+
key.impliedNaturals.forEach(function(acc) {
|
|
122
122
|
acc.verticalPos -= 7;
|
|
123
123
|
if (acc.verticalPos >= 11 || (acc.verticalPos === 10 && acc.acc === 'flat'))
|
|
124
124
|
acc.verticalPos -= 7;
|
|
@@ -128,23 +128,23 @@ var parseKeyVoice = {};
|
|
|
128
128
|
acc.verticalPos -=7;
|
|
129
129
|
});
|
|
130
130
|
} else if (mid < -4) {
|
|
131
|
-
|
|
131
|
+
key.accidentals.forEach(function(acc) {
|
|
132
132
|
acc.verticalPos -= 7;
|
|
133
133
|
if (mid === -8 && (acc.note === 'f' || acc.note === 'g') && acc.acc === 'sharp' )
|
|
134
134
|
acc.verticalPos -=7;
|
|
135
135
|
});
|
|
136
136
|
if (key.impliedNaturals)
|
|
137
|
-
|
|
137
|
+
key.impliedNaturals.forEach(function(acc) {
|
|
138
138
|
acc.verticalPos -= 7;
|
|
139
139
|
if (mid === -8 && (acc.note === 'f' || acc.note === 'g') && acc.acc === 'sharp' )
|
|
140
140
|
acc.verticalPos -=7;
|
|
141
141
|
});
|
|
142
142
|
} else if (mid >= 7) {
|
|
143
|
-
|
|
143
|
+
key.accidentals.forEach(function(acc) {
|
|
144
144
|
acc.verticalPos += 7;
|
|
145
145
|
});
|
|
146
146
|
if (key.impliedNaturals)
|
|
147
|
-
|
|
147
|
+
key.impliedNaturals.forEach(function(acc) {
|
|
148
148
|
acc.verticalPos += 7;
|
|
149
149
|
});
|
|
150
150
|
}
|
|
@@ -158,15 +158,15 @@ var parseKeyVoice = {};
|
|
|
158
158
|
|
|
159
159
|
var parseMiddle = function(str) {
|
|
160
160
|
var i = 0;
|
|
161
|
-
var p = str
|
|
161
|
+
var p = str[i++];
|
|
162
162
|
if (p === '^' || p === '_')
|
|
163
|
-
p = str
|
|
163
|
+
p = str[i++];
|
|
164
164
|
var mid = pitches[p];
|
|
165
165
|
if (mid === undefined)
|
|
166
166
|
mid = 6; // If a legal middle note wasn't received, just ignore it.
|
|
167
167
|
for ( ; i < str.length; i++) {
|
|
168
|
-
if (str
|
|
169
|
-
else if (str
|
|
168
|
+
if (str[i] === ',') mid -= 7;
|
|
169
|
+
else if (str[i] === "'") mid += 7;
|
|
170
170
|
else break;
|
|
171
171
|
}
|
|
172
172
|
return { mid: mid - 6, str: str.substring(i) }; // We get the note in the middle of the staff. We want the note that appears as the first ledger line below the staff.
|
|
@@ -528,7 +528,7 @@ var parseKeyVoice = {};
|
|
|
528
528
|
warn("Expected value for " + name + " in voice: " + attr.warn, line, start);
|
|
529
529
|
else if (attr.err !== undefined)
|
|
530
530
|
warn("Expected value for " + name + " in voice: " + attr.err, line, start);
|
|
531
|
-
else if (attr.token.length === 0 && line
|
|
531
|
+
else if (attr.token.length === 0 && line[start] !== '"')
|
|
532
532
|
warn("Expected value for " + name + " in voice", line, start);
|
|
533
533
|
else
|
|
534
534
|
staffInfo[name] = attr.token;
|
|
@@ -540,7 +540,7 @@ var parseKeyVoice = {};
|
|
|
540
540
|
warn("Expected value for " + name + " in voice: " + attr.warn, line, start);
|
|
541
541
|
else if (attr.err !== undefined)
|
|
542
542
|
warn("Expected value for " + name + " in voice: " + attr.err, line, start);
|
|
543
|
-
else if (attr.token.length === 0 && line
|
|
543
|
+
else if (attr.token.length === 0 && line[start] !== '"')
|
|
544
544
|
warn("Expected value for " + name + " in voice", line, start);
|
|
545
545
|
else {
|
|
546
546
|
if (type === 'number')
|
|
@@ -555,7 +555,7 @@ var parseKeyVoice = {};
|
|
|
555
555
|
warn("Expected value for " + name + " in voice: " + attr.warn, line, start);
|
|
556
556
|
else if (attr.err !== undefined)
|
|
557
557
|
warn("Expected value for " + name + " in voice: " + attr.err, line, start);
|
|
558
|
-
else if (attr.token.length === 0 && line
|
|
558
|
+
else if (attr.token.length === 0 && line[start] !== '"')
|
|
559
559
|
warn("Expected value for " + name + " in voice", line, start);
|
|
560
560
|
else {
|
|
561
561
|
if (type === 'number')
|
|
@@ -574,7 +574,7 @@ var parseKeyVoice = {};
|
|
|
574
574
|
var attr = tokenizer.getVoiceToken(line, start, end);
|
|
575
575
|
if (attr.warn !== undefined)
|
|
576
576
|
warn("Expected one of (_B, _E, _b, _e) for " + name + " in voice: " + attr.warn, line, start);
|
|
577
|
-
else if (attr.token.length === 0 && line
|
|
577
|
+
else if (attr.token.length === 0 && line[start] !== '"')
|
|
578
578
|
warn("Expected one of (_B, _E, _b, _e) for " + name + " in voice", line, start);
|
|
579
579
|
else {
|
|
580
580
|
var t = noteToTransposition[attr.token];
|