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
|
@@ -13,7 +13,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
13
13
|
|
|
14
14
|
this.skipWhiteSpace = function(str) {
|
|
15
15
|
for (var i = 0; i < str.length; i++) {
|
|
16
|
-
if (!this.isWhiteSpace(str
|
|
16
|
+
if (!this.isWhiteSpace(str[i]))
|
|
17
17
|
return i;
|
|
18
18
|
}
|
|
19
19
|
return str.length; // It must have been all white space
|
|
@@ -23,7 +23,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
23
23
|
};
|
|
24
24
|
this.eatWhiteSpace = function(line, index) {
|
|
25
25
|
for (var i = index; i < line.length; i++) {
|
|
26
|
-
if (!this.isWhiteSpace(line
|
|
26
|
+
if (!this.isWhiteSpace(line[i]))
|
|
27
27
|
return i-index;
|
|
28
28
|
}
|
|
29
29
|
return i-index;
|
|
@@ -34,7 +34,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
34
34
|
var i = this.skipWhiteSpace(str);
|
|
35
35
|
if (finished(str, i))
|
|
36
36
|
return {len: 0};
|
|
37
|
-
switch (str
|
|
37
|
+
switch (str[i]) {
|
|
38
38
|
case 'A':return {len: i+1, token: 'A'};
|
|
39
39
|
case 'B':return {len: i+1, token: 'B'};
|
|
40
40
|
case 'C':return {len: i+1, token: 'C'};
|
|
@@ -57,7 +57,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
57
57
|
this.getSharpFlat = function(str) {
|
|
58
58
|
if (str === 'bass')
|
|
59
59
|
return {len: 0};
|
|
60
|
-
switch (str
|
|
60
|
+
switch (str[0]) {
|
|
61
61
|
case '#':return {len: 1, token: '#'};
|
|
62
62
|
case 'b':return {len: 1, token: 'b'};
|
|
63
63
|
}
|
|
@@ -67,7 +67,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
67
67
|
this.getMode = function(str) {
|
|
68
68
|
var skipAlpha = function(str, start) {
|
|
69
69
|
// This returns the index of the next non-alphabetic char, or the entire length of the string if not found.
|
|
70
|
-
while (start < str.length && ((str
|
|
70
|
+
while (start < str.length && ((str[start] >= 'a' && str[start] <= 'z') || (str[start] >= 'A' && str[start] <= 'Z')))
|
|
71
71
|
start++;
|
|
72
72
|
return start;
|
|
73
73
|
};
|
|
@@ -76,7 +76,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
76
76
|
if (finished(str, i))
|
|
77
77
|
return {len: 0};
|
|
78
78
|
var firstThree = str.substring(i,i+3).toLowerCase();
|
|
79
|
-
if (firstThree.length > 1 && firstThree
|
|
79
|
+
if (firstThree.length > 1 && firstThree[1] === ' ' || firstThree[1] === '^' || firstThree[1] === '_' || firstThree[1] === '=') firstThree = firstThree[0]; // This will handle the case of 'm'
|
|
80
80
|
switch (firstThree) {
|
|
81
81
|
case 'mix':return {len: skipAlpha(str, i), token: 'Mix'};
|
|
82
82
|
case 'dor':return {len: skipAlpha(str, i), token: 'Dor'};
|
|
@@ -158,14 +158,14 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
158
158
|
// This returns one of the legal bar lines
|
|
159
159
|
// This is called alot and there is no obvious tokenable items, so this is broken apart.
|
|
160
160
|
this.getBarLine = function(line, i) {
|
|
161
|
-
switch (line
|
|
161
|
+
switch (line[i]) {
|
|
162
162
|
case ']':
|
|
163
163
|
++i;
|
|
164
|
-
switch (line
|
|
164
|
+
switch (line[i]) {
|
|
165
165
|
case '|': return {len: 2, token: "bar_thick_thin"};
|
|
166
166
|
case '[':
|
|
167
167
|
++i;
|
|
168
|
-
if ((line
|
|
168
|
+
if ((line[i] >= '1' && line[i] <= '9') || line[i] === '"')
|
|
169
169
|
return {len: 2, token: "bar_invisible"};
|
|
170
170
|
return {len: 1, warn: "Unknown bar symbol"};
|
|
171
171
|
default:
|
|
@@ -174,17 +174,17 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
174
174
|
break;
|
|
175
175
|
case ':':
|
|
176
176
|
++i;
|
|
177
|
-
switch (line
|
|
177
|
+
switch (line[i]) {
|
|
178
178
|
case ':': return {len: 2, token: "bar_dbl_repeat"};
|
|
179
179
|
case '|': // :|
|
|
180
180
|
++i;
|
|
181
|
-
switch (line
|
|
181
|
+
switch (line[i]) {
|
|
182
182
|
case ']': // :|]
|
|
183
183
|
++i;
|
|
184
|
-
switch (line
|
|
184
|
+
switch (line[i]) {
|
|
185
185
|
case '|': // :|]|
|
|
186
186
|
++i;
|
|
187
|
-
if (line
|
|
187
|
+
if (line[i] === ':') return {len: 5, token: "bar_dbl_repeat"};
|
|
188
188
|
return {len: 3, token: "bar_right_repeat"};
|
|
189
189
|
default:
|
|
190
190
|
return {len: 3, token: "bar_right_repeat"};
|
|
@@ -192,7 +192,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
192
192
|
break;
|
|
193
193
|
case '|': // :||
|
|
194
194
|
++i;
|
|
195
|
-
if (line
|
|
195
|
+
if (line[i] === ':') return {len: 4, token: "bar_dbl_repeat"};
|
|
196
196
|
return {len: 3, token: "bar_right_repeat"};
|
|
197
197
|
default:
|
|
198
198
|
return {len: 2, token: "bar_right_repeat"};
|
|
@@ -204,30 +204,30 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
204
204
|
break;
|
|
205
205
|
case '[': // [
|
|
206
206
|
++i;
|
|
207
|
-
if (line
|
|
207
|
+
if (line[i] === '|') { // [|
|
|
208
208
|
++i;
|
|
209
|
-
switch (line
|
|
209
|
+
switch (line[i]) {
|
|
210
210
|
case ':': return {len: 3, token: "bar_left_repeat"};
|
|
211
211
|
case ']': return {len: 3, token: "bar_invisible"};
|
|
212
212
|
default: return {len: 2, token: "bar_thick_thin"};
|
|
213
213
|
}
|
|
214
214
|
} else {
|
|
215
|
-
if ((line
|
|
215
|
+
if ((line[i] >= '1' && line[i] <= '9') || line[i] === '"')
|
|
216
216
|
return {len: 1, token: "bar_invisible"};
|
|
217
217
|
return {len: 0};
|
|
218
218
|
}
|
|
219
219
|
break;
|
|
220
220
|
case '|': // |
|
|
221
221
|
++i;
|
|
222
|
-
switch (line
|
|
222
|
+
switch (line[i]) {
|
|
223
223
|
case ']': return {len: 2, token: "bar_thin_thick"};
|
|
224
224
|
case '|': // ||
|
|
225
225
|
++i;
|
|
226
|
-
if (line
|
|
226
|
+
if (line[i] === ':') return {len: 3, token: "bar_left_repeat"};
|
|
227
227
|
return {len: 2, token: "bar_thin_thin"};
|
|
228
228
|
case ':': // |:
|
|
229
229
|
var colons = 0;
|
|
230
|
-
while (line
|
|
230
|
+
while (line[i+colons] === ':') colons++;
|
|
231
231
|
return { len: 1+colons, token: "bar_left_repeat"};
|
|
232
232
|
default: return {len: 1, token: "bar_thin"};
|
|
233
233
|
}
|
|
@@ -239,7 +239,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
239
239
|
// this returns all the characters in the string that match one of the characters in the legalChars string
|
|
240
240
|
this.getTokenOf = function(str, legalChars) {
|
|
241
241
|
for (var i = 0; i < str.length; i++) {
|
|
242
|
-
if (legalChars.indexOf(str
|
|
242
|
+
if (legalChars.indexOf(str[i]) < 0)
|
|
243
243
|
return {len: i, token: str.substring(0, i)};
|
|
244
244
|
}
|
|
245
245
|
return {len: i, token: str};
|
|
@@ -248,7 +248,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
248
248
|
this.getToken = function(str, start, end) {
|
|
249
249
|
// This returns the next set of chars that doesn't contain spaces
|
|
250
250
|
var i = start;
|
|
251
|
-
while (i < end && !this.isWhiteSpace(str
|
|
251
|
+
while (i < end && !this.isWhiteSpace(str[i]))
|
|
252
252
|
i++;
|
|
253
253
|
return str.substring(start, i);
|
|
254
254
|
};
|
|
@@ -309,7 +309,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
309
309
|
return { accs: accs };
|
|
310
310
|
}
|
|
311
311
|
if (tokens.length === 0) return {accs: accs, warn: 'Expected note name after ' + acc};
|
|
312
|
-
switch (tokens[0].token
|
|
312
|
+
switch (tokens[0].token[0])
|
|
313
313
|
{
|
|
314
314
|
case 'a':
|
|
315
315
|
case 'b':
|
|
@@ -327,7 +327,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
327
327
|
case 'G':
|
|
328
328
|
if (accs === undefined)
|
|
329
329
|
accs = [];
|
|
330
|
-
accs.push({ acc: acc, note: tokens[0].token
|
|
330
|
+
accs.push({ acc: acc, note: tokens[0].token[0] });
|
|
331
331
|
if (tokens[0].token.length === 1)
|
|
332
332
|
tokens.shift();
|
|
333
333
|
else
|
|
@@ -355,19 +355,19 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
355
355
|
if (finished(str, i))
|
|
356
356
|
return {len: 0};
|
|
357
357
|
var acc = null;
|
|
358
|
-
switch (str
|
|
358
|
+
switch (str[i])
|
|
359
359
|
{
|
|
360
360
|
case '^':
|
|
361
361
|
case '_':
|
|
362
362
|
case '=':
|
|
363
|
-
acc = str
|
|
363
|
+
acc = str[i];
|
|
364
364
|
break;
|
|
365
365
|
default:return {len: 0};
|
|
366
366
|
}
|
|
367
367
|
i++;
|
|
368
368
|
if (finished(str, i))
|
|
369
369
|
return {len: 1, warn: 'Expected note name after accidental'};
|
|
370
|
-
switch (str
|
|
370
|
+
switch (str[i])
|
|
371
371
|
{
|
|
372
372
|
case 'a':
|
|
373
373
|
case 'b':
|
|
@@ -383,15 +383,15 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
383
383
|
case 'E':
|
|
384
384
|
case 'F':
|
|
385
385
|
case 'G':
|
|
386
|
-
return {len: i+1, token: {acc: accTranslation[acc], note: str
|
|
386
|
+
return {len: i+1, token: {acc: accTranslation[acc], note: str[i]}};
|
|
387
387
|
case '^':
|
|
388
388
|
case '_':
|
|
389
389
|
case '/':
|
|
390
|
-
acc += str
|
|
390
|
+
acc += str[i];
|
|
391
391
|
i++;
|
|
392
392
|
if (finished(str, i))
|
|
393
393
|
return {len: 2, warn: 'Expected note name after accidental'};
|
|
394
|
-
switch (str
|
|
394
|
+
switch (str[i])
|
|
395
395
|
{
|
|
396
396
|
case 'a':
|
|
397
397
|
case 'b':
|
|
@@ -407,7 +407,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
407
407
|
case 'E':
|
|
408
408
|
case 'F':
|
|
409
409
|
case 'G':
|
|
410
|
-
return {len: i+1, token: {acc: accTranslation[acc], note: str
|
|
410
|
+
return {len: i+1, token: {acc: accTranslation[acc], note: str[i]}};
|
|
411
411
|
default:
|
|
412
412
|
return {len: 2, warn: 'Expected note name after accidental'};
|
|
413
413
|
}
|
|
@@ -427,9 +427,9 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
427
427
|
var comment = line.indexOf('%', start);
|
|
428
428
|
if (comment >= 0 && comment < end)
|
|
429
429
|
end = comment;
|
|
430
|
-
while (start < end && (line
|
|
430
|
+
while (start < end && (line[start] === ' ' || line[start] === '\t' || line[start] === '\x12'))
|
|
431
431
|
start++;
|
|
432
|
-
while (start < end && (line
|
|
432
|
+
while (start < end && (line[end-1] === ' ' || line[end-1] === '\t' || line[end-1] === '\x12'))
|
|
433
433
|
end--;
|
|
434
434
|
return {start: start, end: end};
|
|
435
435
|
};
|
|
@@ -456,46 +456,46 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
456
456
|
var tokens = [];
|
|
457
457
|
var i;
|
|
458
458
|
while (start < end) {
|
|
459
|
-
if (line
|
|
459
|
+
if (line[start] === '"') {
|
|
460
460
|
i = start+1;
|
|
461
|
-
while (i < end && line
|
|
461
|
+
while (i < end && line[i] !== '"') i++;
|
|
462
462
|
tokens.push({ type: 'quote', token: line.substring(start+1, i), start: start+1, end: i});
|
|
463
463
|
i++;
|
|
464
|
-
} else if (isLetter(line
|
|
464
|
+
} else if (isLetter(line[start])) {
|
|
465
465
|
i = start+1;
|
|
466
466
|
if (alphaUntilWhiteSpace)
|
|
467
|
-
while (i < end && !this.isWhiteSpace(line
|
|
467
|
+
while (i < end && !this.isWhiteSpace(line[i])) i++;
|
|
468
468
|
else
|
|
469
|
-
while (i < end && isLetter(line
|
|
470
|
-
tokens.push({ type: 'alpha', token: line.substring(start, i), continueId: isNumber(line
|
|
469
|
+
while (i < end && isLetter(line[i])) i++;
|
|
470
|
+
tokens.push({ type: 'alpha', token: line.substring(start, i), continueId: isNumber(line[i]), start: start, end: i});
|
|
471
471
|
start = i + 1;
|
|
472
|
-
} else if (line
|
|
472
|
+
} else if (line[start] === '.' && isNumber(line[i+1])) {
|
|
473
473
|
i = start+1;
|
|
474
474
|
var int2 = null;
|
|
475
475
|
var float2 = null;
|
|
476
|
-
while (i < end && isNumber(line
|
|
476
|
+
while (i < end && isNumber(line[i])) i++;
|
|
477
477
|
|
|
478
478
|
float2 = parseFloat(line.substring(start, i));
|
|
479
|
-
tokens.push({ type: 'number', token: line.substring(start, i), intt: int2, floatt: float2, continueId: isLetter(line
|
|
479
|
+
tokens.push({ type: 'number', token: line.substring(start, i), intt: int2, floatt: float2, continueId: isLetter(line[i]), start: start, end: i});
|
|
480
480
|
start = i + 1;
|
|
481
|
-
} else if (isNumber(line
|
|
481
|
+
} else if (isNumber(line[start]) || (line[start] === '-' && isNumber(line[i+1]))) {
|
|
482
482
|
i = start+1;
|
|
483
483
|
var intt = null;
|
|
484
484
|
var floatt = null;
|
|
485
|
-
while (i < end && isNumber(line
|
|
486
|
-
if (line
|
|
485
|
+
while (i < end && isNumber(line[i])) i++;
|
|
486
|
+
if (line[i] === '.' && isNumber(line[i+1])) {
|
|
487
487
|
i++;
|
|
488
|
-
while (i < end && isNumber(line
|
|
488
|
+
while (i < end && isNumber(line[i])) i++;
|
|
489
489
|
} else
|
|
490
490
|
intt = parseInt(line.substring(start, i));
|
|
491
491
|
|
|
492
492
|
floatt = parseFloat(line.substring(start, i));
|
|
493
|
-
tokens.push({ type: 'number', token: line.substring(start, i), intt: intt, floatt: floatt, continueId: isLetter(line
|
|
493
|
+
tokens.push({ type: 'number', token: line.substring(start, i), intt: intt, floatt: floatt, continueId: isLetter(line[i]), start: start, end: i});
|
|
494
494
|
start = i + 1;
|
|
495
|
-
} else if (line
|
|
495
|
+
} else if (line[start] === ' ' || line[start] === '\t') {
|
|
496
496
|
i = start+1;
|
|
497
497
|
} else {
|
|
498
|
-
tokens.push({ type: 'punct', token: line
|
|
498
|
+
tokens.push({ type: 'punct', token: line[start], start: start, end: start+1});
|
|
499
499
|
i = start+1;
|
|
500
500
|
}
|
|
501
501
|
start = i;
|
|
@@ -506,17 +506,17 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
506
506
|
this.getVoiceToken = function(line, start, end) {
|
|
507
507
|
// This finds the next token. A token is delimited by a space or an equal sign. If it starts with a quote, then the portion between the quotes is returned.
|
|
508
508
|
var i = start;
|
|
509
|
-
while (i < end && this.isWhiteSpace(line
|
|
509
|
+
while (i < end && this.isWhiteSpace(line[i]) || line[i] === '=')
|
|
510
510
|
i++;
|
|
511
511
|
|
|
512
|
-
if (line
|
|
512
|
+
if (line[i] === '"') {
|
|
513
513
|
var close = line.indexOf('"', i+1);
|
|
514
514
|
if (close === -1 || close >= end)
|
|
515
515
|
return {len: 1, err: "Missing close quote"};
|
|
516
516
|
return {len: close-start+1, token: this.translateString(line.substring(i+1, close))};
|
|
517
517
|
} else {
|
|
518
518
|
var ii = i;
|
|
519
|
-
while (ii < end && !this.isWhiteSpace(line
|
|
519
|
+
while (ii < end && !this.isWhiteSpace(line[ii]) && line[ii] !== '=')
|
|
520
520
|
ii++;
|
|
521
521
|
return {len: ii-start+1, token: line.substring(i, ii)};
|
|
522
522
|
}
|
|
@@ -566,7 +566,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
566
566
|
var arr = str.split('\\');
|
|
567
567
|
if (arr.length === 1) return str;
|
|
568
568
|
var out = null;
|
|
569
|
-
|
|
569
|
+
arr.forEach(function(s) {
|
|
570
570
|
if (out === null)
|
|
571
571
|
out = s;
|
|
572
572
|
else {
|
|
@@ -592,7 +592,7 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
592
592
|
this.getNumber = function(line, index) {
|
|
593
593
|
var num = 0;
|
|
594
594
|
while (index < line.length) {
|
|
595
|
-
switch (line
|
|
595
|
+
switch (line[index]) {
|
|
596
596
|
case '0':num = num*10;index++;break;
|
|
597
597
|
case '1':num = num*10+1;index++;break;
|
|
598
598
|
case '2':num = num*10+2;index++;break;
|
|
@@ -613,16 +613,16 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
613
613
|
this.getFraction = function(line, index) {
|
|
614
614
|
var num = 1;
|
|
615
615
|
var den = 1;
|
|
616
|
-
if (line
|
|
616
|
+
if (line[index] !== '/') {
|
|
617
617
|
var ret = this.getNumber(line, index);
|
|
618
618
|
num = ret.num;
|
|
619
619
|
index = ret.index;
|
|
620
620
|
}
|
|
621
|
-
if (line
|
|
621
|
+
if (line[index] === '/') {
|
|
622
622
|
index++;
|
|
623
|
-
if (line
|
|
623
|
+
if (line[index] === '/') {
|
|
624
624
|
var div = 0.5;
|
|
625
|
-
while (line
|
|
625
|
+
while (line[index++] === '/')
|
|
626
626
|
div = div /2;
|
|
627
627
|
return {value: num * div, index: index-1};
|
|
628
628
|
} else {
|
|
@@ -723,14 +723,14 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
723
723
|
// It returns the substring and the number of characters consumed.
|
|
724
724
|
// The number of characters consumed is normally two more than the size of the substring,
|
|
725
725
|
// but in the error case it might not be.
|
|
726
|
-
var matchChar = _matchChar || line
|
|
726
|
+
var matchChar = _matchChar || line[i];
|
|
727
727
|
var pos = i+1;
|
|
728
728
|
var esc = false;
|
|
729
729
|
while ((pos < line.length) && (esc || line[pos] !== matchChar)) {
|
|
730
730
|
esc = line[pos] === '\\';
|
|
731
731
|
++pos;
|
|
732
732
|
}
|
|
733
|
-
if (line
|
|
733
|
+
if (line[pos] === matchChar)
|
|
734
734
|
return [pos-i+1,substInChord(line.substring(i+1, pos)), true];
|
|
735
735
|
else // we hit the end of line, so we'll just pick an arbitrary num of chars so the line doesn't disappear.
|
|
736
736
|
{
|
|
@@ -51,7 +51,15 @@ transpose.keySignature = function(multilineVars, keyName, root, acc, localTransp
|
|
|
51
51
|
keyName = keyName.substr(2);
|
|
52
52
|
} else
|
|
53
53
|
keyName = keyName.substr(1);
|
|
54
|
-
var
|
|
54
|
+
var thisKeyIndex = keyIndex[baseKey]
|
|
55
|
+
var recognized = thisKeyIndex !== undefined
|
|
56
|
+
if (!recognized) {
|
|
57
|
+
// Either the key sig is "none" or we don't recognize it. Either way we don't change it, and we assume key of C for the purposes of this calculation.
|
|
58
|
+
thisKeyIndex = 0
|
|
59
|
+
baseKey = "C"
|
|
60
|
+
keyName = ""
|
|
61
|
+
}
|
|
62
|
+
var index = thisKeyIndex + multilineVars.localTranspose;
|
|
55
63
|
while (index < 0) index += 12;
|
|
56
64
|
if (index > 11) index = index % 12;
|
|
57
65
|
var newKeyName = (keyName[0] === 'm' ? newKeyMinor[index] : newKey[index]);
|
|
@@ -87,7 +95,10 @@ transpose.keySignature = function(multilineVars, keyName, root, acc, localTransp
|
|
|
87
95
|
multilineVars.localTransposeVerticalMovement = distance + Math.floor(multilineVars.localTranspose / 12) * 7;
|
|
88
96
|
else
|
|
89
97
|
multilineVars.localTransposeVerticalMovement = distance + Math.ceil(multilineVars.localTranspose / 12) * 7;
|
|
90
|
-
|
|
98
|
+
if (recognized)
|
|
99
|
+
return { accidentals: newKeySig, root: newKeyName[0], acc: newKeyName.length > 1 ? newKeyName[1] : "" };
|
|
100
|
+
else
|
|
101
|
+
return { accidentals: [], root: root, acc: acc };
|
|
91
102
|
};
|
|
92
103
|
|
|
93
104
|
transpose.chordName = function(multilineVars, chord) {
|
|
@@ -145,7 +156,7 @@ var accidentals3 = {
|
|
|
145
156
|
"1": "^",
|
|
146
157
|
"2": "^^"
|
|
147
158
|
};
|
|
148
|
-
var count = 0
|
|
159
|
+
//var count = 0
|
|
149
160
|
transpose.note = function(multilineVars, el) {
|
|
150
161
|
// the "el" that is passed in has el.name, el.accidental, and el.pitch. "pitch" is the vertical position (0=middle C)
|
|
151
162
|
// localTranspose is the number of half steps
|
|
@@ -68,7 +68,7 @@ var TuneBuilder = function(tune) {
|
|
|
68
68
|
durationThisBar += event.duration;
|
|
69
69
|
durationsPerLines[i] += event.duration;
|
|
70
70
|
}
|
|
71
|
-
} else if (event.el_type === "scale" || event.el_type === "stem" || event.el_type === "overlay" || event.el_type === "style" || event.el_type === "transpose") {
|
|
71
|
+
} else if (event.el_type === "scale" || event.el_type === "stem" || event.el_type === "overlay" || event.el_type === "style" || event.el_type === "transpose" || event.el_type === "color") {
|
|
72
72
|
// These types of events are duplicated on the overlay layer.
|
|
73
73
|
overlayVoice[k].voice.push(event);
|
|
74
74
|
}
|
|
@@ -178,10 +178,10 @@ var TuneBuilder = function(tune) {
|
|
|
178
178
|
}
|
|
179
179
|
}
|
|
180
180
|
if (anyDeleted) {
|
|
181
|
-
tune.lines =
|
|
182
|
-
|
|
181
|
+
tune.lines = tune.lines.filter(function (line) { return !!line });
|
|
182
|
+
tune.lines.forEach(function(line) {
|
|
183
183
|
if (line.staff)
|
|
184
|
-
line.staff =
|
|
184
|
+
line.staff = line.staff.filter(function (line) { return !!line });
|
|
185
185
|
});
|
|
186
186
|
}
|
|
187
187
|
|
|
@@ -212,9 +212,9 @@ var TuneBuilder = function(tune) {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
if (anyDeleted) {
|
|
215
|
-
|
|
215
|
+
tune.lines.forEach(function(line) {
|
|
216
216
|
if (line.staff)
|
|
217
|
-
line.staff =
|
|
217
|
+
line.staff = line.staff.filter(function (staff) { return !!staff });
|
|
218
218
|
});
|
|
219
219
|
}
|
|
220
220
|
}
|
|
@@ -253,7 +253,7 @@ var TuneBuilder = function(tune) {
|
|
|
253
253
|
}
|
|
254
254
|
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
255
255
|
var offNum = chordPos*100+1;
|
|
256
|
-
|
|
256
|
+
obj.endSlur.forEach(function(x) { if (offNum === x) --offNum; });
|
|
257
257
|
currSlur[staffNum][voiceNum][chordPos] = [offNum];
|
|
258
258
|
}
|
|
259
259
|
}
|
|
@@ -276,12 +276,12 @@ var TuneBuilder = function(tune) {
|
|
|
276
276
|
var nextNum = chordPos*100+1;
|
|
277
277
|
for (var i = 0; i < num; i++) {
|
|
278
278
|
if (usedNums) {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
279
|
+
usedNums.forEach(function(x) { if (nextNum === x) ++nextNum; });
|
|
280
|
+
usedNums.forEach(function(x) { if (nextNum === x) ++nextNum; });
|
|
281
|
+
usedNums.forEach(function(x) { if (nextNum === x) ++nextNum; });
|
|
282
282
|
}
|
|
283
|
-
|
|
284
|
-
|
|
283
|
+
currSlur[staffNum][voiceNum][chordPos].forEach(function(x) { if (nextNum === x) ++nextNum; });
|
|
284
|
+
currSlur[staffNum][voiceNum][chordPos].forEach(function(x) { if (nextNum === x) ++nextNum; });
|
|
285
285
|
|
|
286
286
|
currSlur[staffNum][voiceNum][chordPos].push(nextNum);
|
|
287
287
|
obj.startSlur.push({ label: nextNum });
|
|
@@ -512,11 +512,11 @@ var TuneBuilder = function(tune) {
|
|
|
512
512
|
}
|
|
513
513
|
if (hp.pitches !== undefined) {
|
|
514
514
|
var mid = currStaff.workingClef.verticalPos;
|
|
515
|
-
|
|
515
|
+
hp.pitches.forEach(function(p) { p.verticalPos = p.pitch - mid; });
|
|
516
516
|
}
|
|
517
517
|
if (hp.gracenotes !== undefined) {
|
|
518
518
|
var mid2 = currStaff.workingClef.verticalPos;
|
|
519
|
-
|
|
519
|
+
hp.gracenotes.forEach(function(p) { p.verticalPos = p.pitch - mid2; });
|
|
520
520
|
}
|
|
521
521
|
currStaff.voices[This.voiceNum].push(hp);
|
|
522
522
|
};
|
|
@@ -702,6 +702,9 @@ var TuneBuilder = function(tune) {
|
|
|
702
702
|
this.changeVoiceScale = function(scale) {
|
|
703
703
|
self.appendElement('scale', null, null, { size: scale} );
|
|
704
704
|
};
|
|
705
|
+
this.changeVoiceColor = function(color) {
|
|
706
|
+
self.appendElement('color', null, null, { color: color} );
|
|
707
|
+
};
|
|
705
708
|
|
|
706
709
|
this.startNewLine = function(params) {
|
|
707
710
|
// If the pointed to line doesn't exist, just create that. If the line does exist, but doesn't have any music on it, just use it.
|
|
@@ -734,6 +737,8 @@ var TuneBuilder = function(tune) {
|
|
|
734
737
|
}
|
|
735
738
|
if (params.scale)
|
|
736
739
|
self.appendElement('scale', null, null, { size: params.scale} );
|
|
740
|
+
if (params.color)
|
|
741
|
+
self.appendElement('color', null, null, { color: params.color} );
|
|
737
742
|
};
|
|
738
743
|
var createStaff = function(params) {
|
|
739
744
|
if (params.key && params.key.impliedNaturals) {
|
|
@@ -32,6 +32,7 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
32
32
|
var chordSourceTrack;
|
|
33
33
|
var chordTrackFinished;
|
|
34
34
|
var chordChannel;
|
|
35
|
+
var bassInstrument = 0;
|
|
35
36
|
var chordInstrument = 0;
|
|
36
37
|
var drumInstrument = 128;
|
|
37
38
|
var boomVolume = 64;
|
|
@@ -54,6 +55,7 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
54
55
|
var drumTrack;
|
|
55
56
|
var drumTrackFinished;
|
|
56
57
|
var drumDefinition = {};
|
|
58
|
+
var drumBars;
|
|
57
59
|
|
|
58
60
|
var pickupLength = 0;
|
|
59
61
|
var percmap;
|
|
@@ -63,8 +65,9 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
63
65
|
var slurredBreakBetweenNotes = -0.001; // make the slurred notes actually overlap
|
|
64
66
|
var staccatoBreakBetweenNotes = 0.4; // some people say staccato is half duration, some say 3/4 so this splits it
|
|
65
67
|
|
|
66
|
-
flatten = function(voices, options, percmap_) {
|
|
68
|
+
flatten = function(voices, options, percmap_, midiOptions) {
|
|
67
69
|
if (!options) options = {};
|
|
70
|
+
if (!midiOptions) midiOptions = {};
|
|
68
71
|
barAccidentals = [];
|
|
69
72
|
accidentals = [0,0,0,0,0,0,0];
|
|
70
73
|
bagpipes = false;
|
|
@@ -87,8 +90,10 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
87
90
|
chordChannel = voices.length; // first free channel for chords
|
|
88
91
|
chordTrackFinished = false;
|
|
89
92
|
currentChords = [];
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
bassInstrument = midiOptions.bassprog && midiOptions.bassprog.length === 1 ? midiOptions.bassprog[0] : 0;
|
|
94
|
+
chordInstrument = midiOptions.chordprog && midiOptions.chordprog.length === 1 ? midiOptions.chordprog[0] : 0;
|
|
95
|
+
boomVolume = midiOptions.bassvol && midiOptions.bassvol.length === 1 ? midiOptions.bassvol[0] : 64;
|
|
96
|
+
chickVolume = midiOptions.chordvol && midiOptions.chordvol.length === 1 ? midiOptions.chordvol[0] : 48;
|
|
92
97
|
lastChord = undefined;
|
|
93
98
|
chordLastBar = undefined;
|
|
94
99
|
gChordTacet = options.chordsOff ? true : false;
|
|
@@ -107,6 +112,7 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
107
112
|
drumTrack = [];
|
|
108
113
|
drumTrackFinished = false;
|
|
109
114
|
drumDefinition = {};
|
|
115
|
+
drumBars = 1;
|
|
110
116
|
|
|
111
117
|
if (voices.length > 0 && voices[0].length > 0)
|
|
112
118
|
pickupLength = voices[0][0].pickupLength;
|
|
@@ -145,6 +151,7 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
145
151
|
startingMeter = element;
|
|
146
152
|
meter = element;
|
|
147
153
|
beatFraction = getBeatFraction(meter);
|
|
154
|
+
alignDrumToMeter();
|
|
148
155
|
break;
|
|
149
156
|
case "tempo":
|
|
150
157
|
if (!startingTempo)
|
|
@@ -189,6 +196,7 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
189
196
|
break;
|
|
190
197
|
case "drum":
|
|
191
198
|
drumDefinition = normalizeDrumDefinition(element.params);
|
|
199
|
+
alignDrumToMeter();
|
|
192
200
|
break;
|
|
193
201
|
case "gchord":
|
|
194
202
|
if (!options.chordsOff)
|
|
@@ -995,9 +1003,9 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
995
1003
|
function chordNotes(bass, modifier) {
|
|
996
1004
|
var intervals = chordIntervals[modifier];
|
|
997
1005
|
if (!intervals) {
|
|
998
|
-
if (modifier.slice(0,2).toLowerCase() === 'ma' || modifier
|
|
1006
|
+
if (modifier.slice(0,2).toLowerCase() === 'ma' || modifier[0] === 'M')
|
|
999
1007
|
intervals = chordIntervals.M;
|
|
1000
|
-
else if (modifier
|
|
1008
|
+
else if (modifier[0] === 'm' || modifier[0] === '-')
|
|
1001
1009
|
intervals = chordIntervals.m;
|
|
1002
1010
|
else
|
|
1003
1011
|
intervals = chordIntervals.M;
|
|
@@ -1013,7 +1021,7 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
1013
1021
|
function writeBoom(boom, beatLength, volume, beat, noteLength) {
|
|
1014
1022
|
// undefined means there is a stop time.
|
|
1015
1023
|
if (boom !== undefined)
|
|
1016
|
-
chordTrack.push({cmd: 'note', pitch: boom, volume: volume, start: lastBarTime+beat*durationRounded(beatLength), duration: durationRounded(noteLength), gap: 0, instrument:
|
|
1024
|
+
chordTrack.push({cmd: 'note', pitch: boom, volume: volume, start: lastBarTime+beat*durationRounded(beatLength), duration: durationRounded(noteLength), gap: 0, instrument: bassInstrument});
|
|
1017
1025
|
}
|
|
1018
1026
|
|
|
1019
1027
|
function writeChick(chick, beatLength, volume, beat, noteLength) {
|
|
@@ -1208,16 +1216,24 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
1208
1216
|
} else
|
|
1209
1217
|
ret.pattern.push({ len: len * beatLength, pitch: null});
|
|
1210
1218
|
}
|
|
1219
|
+
drumBars = params.bars ? params.bars : 1;
|
|
1220
|
+
return ret;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
function alignDrumToMeter() {
|
|
1224
|
+
if (!drumDefinition ||!drumDefinition.pattern) {
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
var ret = drumDefinition;
|
|
1211
1228
|
// Now normalize the pattern to cover the correct number of measures. The note lengths passed are relative to each other and need to be scaled to fit a measure.
|
|
1212
1229
|
var totalTime = 0;
|
|
1213
1230
|
var measuresPerBeat = meter.num/meter.den;
|
|
1214
1231
|
for (var ii = 0; ii < ret.pattern.length; ii++)
|
|
1215
1232
|
totalTime += ret.pattern[ii].len;
|
|
1216
|
-
var
|
|
1217
|
-
var factor = totalTime / numBars / measuresPerBeat;
|
|
1233
|
+
var factor = totalTime / drumBars / measuresPerBeat;
|
|
1218
1234
|
for (ii = 0; ii < ret.pattern.length; ii++)
|
|
1219
1235
|
ret.pattern[ii].len = ret.pattern[ii].len / factor;
|
|
1220
|
-
|
|
1236
|
+
drumDefinition = ret;
|
|
1221
1237
|
}
|
|
1222
1238
|
|
|
1223
1239
|
function writeDrum(channel) {
|
|
@@ -6,7 +6,7 @@ var parseCommon = require("../parse/abc_common");
|
|
|
6
6
|
(function() {
|
|
7
7
|
"use strict";
|
|
8
8
|
|
|
9
|
-
var measureLength;
|
|
9
|
+
var measureLength = 1; // This should be set by the meter, but just in case that is missing, we'll take a guess.
|
|
10
10
|
// The abc is provided to us line by line. It might have repeats in it. We want to re arrange the elements to
|
|
11
11
|
// be an array of voices with all the repeats embedded, and no lines. Then it is trivial to go through the events
|
|
12
12
|
// one at a time and turn it into midi.
|