abcjs 6.0.3 → 6.1.1
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/README.md +8 -0
- package/RELEASE.md +53 -1
- package/SECURITY.md +9 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +1378 -484
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/index.js +2 -0
- package/package.json +2 -2
- package/src/api/abc_tunebook_svg.js +2 -98
- package/src/const/key-accidentals.js +53 -0
- package/src/const/relative-major.js +92 -0
- package/src/parse/abc_parse.js +20 -9
- package/src/parse/abc_parse_book.js +3 -2
- package/src/parse/abc_parse_key_voice.js +1 -148
- package/src/parse/abc_parse_music.js +2 -2
- package/src/parse/abc_transpose.js +9 -68
- package/src/parse/transpose-chord.js +80 -0
- package/src/str/output.js +433 -0
- package/src/synth/abc_midi_flattener.js +1 -1
- package/src/synth/create-note-map.js +4 -0
- package/src/test/abc_parser_lint.js +1 -1
- package/src/write/abc_abstract_engraver.js +12 -0
- package/src/write/abc_beam_element.js +24 -0
- package/src/write/abc_decoration.js +13 -0
- package/src/write/abc_engraver_controller.js +64 -1
- package/src/write/abc_glissando_element.js +7 -0
- package/src/write/draw/draw.js +8 -0
- package/src/write/draw/glissando.js +75 -0
- package/src/write/draw/staff-group.js +5 -5
- package/src/write/draw/voice.js +4 -0
- package/src/write/selection.js +48 -12
- package/src/write/top-text.js +1 -1
- package/types/index.d.ts +56 -8
- package/version.js +1 -1
- package/temp.txt +0 -16
package/index.js
CHANGED
|
@@ -25,6 +25,7 @@ var version = require('./version');
|
|
|
25
25
|
var animation = require('./src/api/abc_animation');
|
|
26
26
|
var tuneBook = require('./src/api/abc_tunebook');
|
|
27
27
|
var sequence = require('./src/synth/abc_midi_sequencer');
|
|
28
|
+
var strTranspose = require('./src/str/output');
|
|
28
29
|
|
|
29
30
|
var abcjs = {};
|
|
30
31
|
|
|
@@ -43,6 +44,7 @@ abcjs.TimingCallbacks = require('./src/api/abc_timing_callbacks');
|
|
|
43
44
|
|
|
44
45
|
var glyphs = require('./src/write/abc_glyphs');
|
|
45
46
|
abcjs.setGlyph = glyphs.setSymbol;
|
|
47
|
+
abcjs.strTranspose = strTranspose;
|
|
46
48
|
|
|
47
49
|
var CreateSynth = require('./src/synth/create-synth');
|
|
48
50
|
var instrumentIndexToName = require('./src/synth/instrument-index-to-name');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "abcjs",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.1",
|
|
4
4
|
"description": "Renderer for abc music notation",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "types/index.d.ts",
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"build:basic": "npm run webpack -- --mode development --config-name basic",
|
|
11
11
|
"build:basic-min": "npm run webpack -- --mode production --config-name basic",
|
|
12
12
|
"build:plugin": "npm run webpack -- --mode production --config-name plugin",
|
|
13
|
-
"test": "
|
|
13
|
+
"test": "echo 'To run tests, open the file tests/all.html in a browser.'",
|
|
14
14
|
"docs:dev": "vuepress dev docs",
|
|
15
15
|
"docs:build": "vuepress build docs",
|
|
16
16
|
"build:analyze": "npm run build:basic -- --env analyze"
|
|
@@ -59,96 +59,6 @@ function renderOne(div, tune, params, tuneNumber, lineOffset) {
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
function renderEachLineSeparately(div, tune, params, tuneNumber) {
|
|
63
|
-
function initializeTuneLine(tune) {
|
|
64
|
-
var obj = new Tune();
|
|
65
|
-
obj.formatting = tune.formatting;
|
|
66
|
-
obj.media = tune.media;
|
|
67
|
-
obj.version = tune.version;
|
|
68
|
-
return obj;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Before rendering, chop up the returned tune into an array where each element is a line.
|
|
72
|
-
// The first element of the array gets the title and other items that go on top, the last element
|
|
73
|
-
// of the array gets the extra text that goes on bottom. Each element gets any non-music info that comes before it.
|
|
74
|
-
var tunes = [];
|
|
75
|
-
var tuneLine;
|
|
76
|
-
for (var i = 0; i < tune.lines.length; i++) {
|
|
77
|
-
var line = tune.lines[i];
|
|
78
|
-
if (!tuneLine)
|
|
79
|
-
tuneLine = initializeTuneLine(tune);
|
|
80
|
-
|
|
81
|
-
if (i === 0) {
|
|
82
|
-
// These items go on top of the music
|
|
83
|
-
tuneLine.copyTopInfo(tune);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// push the lines until we get to a music line
|
|
87
|
-
tuneLine.lines.push(line);
|
|
88
|
-
if (line.staff) {
|
|
89
|
-
tunes.push(tuneLine);
|
|
90
|
-
tuneLine = undefined;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// Add any extra stuff to the last line.
|
|
94
|
-
if (tuneLine) {
|
|
95
|
-
var lastLine = tunes[tunes.length-1];
|
|
96
|
-
for (var j = 0; j < tuneLine.lines.length; j++)
|
|
97
|
-
lastLine.lines.push(tuneLine.lines[j]);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
// These items go below the music
|
|
101
|
-
tuneLine = tunes[tunes.length-1];
|
|
102
|
-
tuneLine.copyBottomInfo(tune);
|
|
103
|
-
|
|
104
|
-
// Now create sub-divs and render each line. Need to copy the params to change the padding for the interior slices.
|
|
105
|
-
var ep = {};
|
|
106
|
-
for (var key in params) {
|
|
107
|
-
if (params.hasOwnProperty(key)) {
|
|
108
|
-
ep[key] = params[key];
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
var origPaddingTop = ep.paddingtop;
|
|
112
|
-
var origPaddingBottom = ep.paddingbottom;
|
|
113
|
-
var currentScrollY = div.parentNode.scrollTop; // If there is scrolling it will be lost during the redraw so remember it.
|
|
114
|
-
var currentScrollX = div.parentNode.scrollLeft;
|
|
115
|
-
div.innerHTML = "";
|
|
116
|
-
var lineCount = 0;
|
|
117
|
-
for (var k = 0; k < tunes.length; k++) {
|
|
118
|
-
var lineEl = document.createElement("div");
|
|
119
|
-
div.appendChild(lineEl);
|
|
120
|
-
|
|
121
|
-
if (k === 0) {
|
|
122
|
-
ep.paddingtop = origPaddingTop;
|
|
123
|
-
ep.paddingbottom = 0;
|
|
124
|
-
} else if (k === tunes.length-1) {
|
|
125
|
-
ep.paddingtop = 10;
|
|
126
|
-
ep.paddingbottom = origPaddingBottom;
|
|
127
|
-
} else {
|
|
128
|
-
ep.paddingtop = 10;
|
|
129
|
-
ep.paddingbottom = 0;
|
|
130
|
-
}
|
|
131
|
-
if (k < tunes.length-1) {
|
|
132
|
-
// If it is not the last line, force stretchlast. If it is, stretchlast might have been set by the input parameters.
|
|
133
|
-
tunes[k].formatting = parseCommon.clone(tunes[k].formatting);
|
|
134
|
-
tunes[k].formatting.stretchlast = true;
|
|
135
|
-
}
|
|
136
|
-
renderOne(lineEl, tunes[k], ep, tuneNumber, lineCount);
|
|
137
|
-
lineCount += tunes[k].lines.length;
|
|
138
|
-
if (k === 0)
|
|
139
|
-
tune.engraver = tunes[k].engraver;
|
|
140
|
-
else {
|
|
141
|
-
if (!tune.engraver.staffgroups)
|
|
142
|
-
tune.engraver.staffgroups = tunes[k].engraver.staffgroups;
|
|
143
|
-
else if (tunes[k].engraver.staffgroups.length > 0)
|
|
144
|
-
tune.engraver.staffgroups.push(tunes[k].engraver.staffgroups[0]);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
if (currentScrollX || currentScrollY) {
|
|
148
|
-
div.parentNode.scrollTo(currentScrollX, currentScrollY);
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
62
|
// A quick way to render a tune from javascript when interactivity is not required.
|
|
153
63
|
// This is used when a javascript routine has some abc text that it wants to render
|
|
154
64
|
// in a div or collection of divs. One tune or many can be rendered.
|
|
@@ -214,10 +124,7 @@ var renderAbc = function(output, abc, parserParams, engraverParams, renderParams
|
|
|
214
124
|
tune = doLineWrapping(div, tune, tuneNumber, abcString, params);
|
|
215
125
|
return tune;
|
|
216
126
|
}
|
|
217
|
-
|
|
218
|
-
renderOne(div, tune, params, tuneNumber, 0);
|
|
219
|
-
else
|
|
220
|
-
renderEachLineSeparately(div, tune, params, tuneNumber);
|
|
127
|
+
renderOne(div, tune, params, tuneNumber, 0);
|
|
221
128
|
if (removeDiv)
|
|
222
129
|
div.parentNode.removeChild(div);
|
|
223
130
|
return null;
|
|
@@ -239,10 +146,7 @@ function doLineWrapping(div, tune, tuneNumber, abcString, params) {
|
|
|
239
146
|
if (warnings)
|
|
240
147
|
tune.warnings = warnings;
|
|
241
148
|
}
|
|
242
|
-
|
|
243
|
-
renderOne(div, tune, ret.revisedParams, tuneNumber, 0);
|
|
244
|
-
else
|
|
245
|
-
renderEachLineSeparately(div, tune, ret.revisedParams, tuneNumber);
|
|
149
|
+
renderOne(div, tune, ret.revisedParams, tuneNumber, 0);
|
|
246
150
|
tune.explanation = ret.explanation;
|
|
247
151
|
return tune;
|
|
248
152
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
var { relativeMajor } = require("./relative-major");
|
|
2
|
+
|
|
3
|
+
var key1sharp = { acc: 'sharp', note: 'f' };
|
|
4
|
+
var key2sharp = { acc: 'sharp', note: 'c' };
|
|
5
|
+
var key3sharp = { acc: 'sharp', note: 'g' };
|
|
6
|
+
var key4sharp = { acc: 'sharp', note: 'd' };
|
|
7
|
+
var key5sharp = { acc: 'sharp', note: 'A' };
|
|
8
|
+
var key6sharp = { acc: 'sharp', note: 'e' };
|
|
9
|
+
var key7sharp = { acc: 'sharp', note: 'B' };
|
|
10
|
+
var key1flat = { acc: 'flat', note: 'B' };
|
|
11
|
+
var key2flat = { acc: 'flat', note: 'e' };
|
|
12
|
+
var key3flat = { acc: 'flat', note: 'A' };
|
|
13
|
+
var key4flat = { acc: 'flat', note: 'd' };
|
|
14
|
+
var key5flat = { acc: 'flat', note: 'G' };
|
|
15
|
+
var key6flat = { acc: 'flat', note: 'c' };
|
|
16
|
+
var key7flat = { acc: 'flat', note: 'F' };
|
|
17
|
+
|
|
18
|
+
var keys = {
|
|
19
|
+
'C#': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
20
|
+
'F#': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
21
|
+
'B': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
22
|
+
'E': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
23
|
+
'A': [key1sharp, key2sharp, key3sharp],
|
|
24
|
+
'D': [key1sharp, key2sharp],
|
|
25
|
+
'G': [key1sharp],
|
|
26
|
+
'C': [],
|
|
27
|
+
'F': [key1flat],
|
|
28
|
+
'Bb': [key1flat, key2flat],
|
|
29
|
+
'Eb': [key1flat, key2flat, key3flat],
|
|
30
|
+
'Cm': [key1flat, key2flat, key3flat],
|
|
31
|
+
'Ab': [key1flat, key2flat, key3flat, key4flat],
|
|
32
|
+
'Db': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
33
|
+
'Gb': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
34
|
+
'Cb': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
35
|
+
|
|
36
|
+
// The following are not in the 2.0 spec, but seem normal enough.
|
|
37
|
+
// TODO-PER: These SOUND the same as what's written, but they aren't right
|
|
38
|
+
'A#': [key1flat, key2flat],
|
|
39
|
+
'B#': [],
|
|
40
|
+
'D#': [key1flat, key2flat, key3flat],
|
|
41
|
+
'E#': [key1flat],
|
|
42
|
+
'G#': [key1flat, key2flat, key3flat, key4flat],
|
|
43
|
+
'none': [],
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
function keyAccidentals(key) {
|
|
47
|
+
var newKey = keys[relativeMajor(key)]
|
|
48
|
+
if (!newKey) // If we don't recognize the key then there is no change
|
|
49
|
+
return null
|
|
50
|
+
return JSON.parse(JSON.stringify(newKey))
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
module.exports = keyAccidentals;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// All these keys have the same number of accidentals
|
|
2
|
+
var keys = {
|
|
3
|
+
'C': { modes: ['CMaj', 'Amin', 'Am', 'GMix', 'DDor', 'EPhr', 'FLyd', 'BLoc'], stepsFromC: 0 },
|
|
4
|
+
'Db': { modes: ['DbMaj', 'Bbmin', 'Bbm', 'AbMix', 'EbDor', 'FPhr', 'GbLyd', 'CLoc'], stepsFromC: 1 },
|
|
5
|
+
'D': { modes: ['DMaj', 'Bmin', 'Bm', 'AMix', 'EDor', 'F#Phr', 'GLyd', 'C#Loc'], stepsFromC: 2 },
|
|
6
|
+
'Eb': { modes: ['EbMaj', 'Cmin', 'Cm', 'BbMix', 'FDor', 'GPhr', 'AbLyd', 'DLoc'], stepsFromC: 3 },
|
|
7
|
+
'E': { modes: ['EMaj', 'C#min', 'C#m', 'BMix', 'F#Dor', 'G#Phr', 'ALyd', 'D#Loc'], stepsFromC: 4 },
|
|
8
|
+
'F': { modes: ['FMaj', 'Dmin', 'Dm', 'CMix', 'GDor', 'APhr', 'BbLyd', 'ELoc'], stepsFromC: 5 },
|
|
9
|
+
'Gb': { modes: ['GbMaj', 'Ebmin', 'Ebm', 'DbMix', 'AbDor', 'BbPhr', 'CbLyd', 'FLoc'], stepsFromC: 6 },
|
|
10
|
+
'G': { modes: ['GMaj', 'Emin', 'Em', 'DMix', 'ADor', 'BPhr', 'CLyd', 'F#Loc'], stepsFromC: 7 },
|
|
11
|
+
'Ab': { modes: ['AbMaj', 'Fmin', 'Fm', 'EbMix', 'BbDor', 'CPhr', 'DbLyd', 'GLoc'], stepsFromC: 8 },
|
|
12
|
+
'A': { modes: ['AMaj', 'F#min', 'F#m', 'EMix', 'BDor', 'C#Phr', 'DLyd', 'G#Loc'], stepsFromC: 9 },
|
|
13
|
+
'Bb': { modes: ['BbMaj', 'Gmin', 'Gm', 'FMix', 'CDor', 'DPhr', 'EbLyd', 'ALoc'], stepsFromC: 10 },
|
|
14
|
+
'B': { modes: ['BMaj', 'G#min', 'G#m', 'F#Mix', 'C#Dor', 'D#Phr', 'ELyd', 'A#Loc'], stepsFromC: 11 },
|
|
15
|
+
// Enharmonic keys
|
|
16
|
+
'C#': { modes: ['C#Maj', 'A#min', 'A#m', 'G#Mix', 'D#Dor', 'E#Phr', 'F#Lyd', 'B#Loc'], stepsFromC: 1 },
|
|
17
|
+
'F#': { modes: ['F#Maj', 'D#min', 'D#m', 'C#Mix', 'G#Dor', 'A#Phr', 'BLyd', 'E#Loc'], stepsFromC: 6 },
|
|
18
|
+
'Cb': { modes: ['CbMaj', 'Abmin', 'Abm', 'GbMix', 'DbDor', 'EbPhr', 'FbLyd', 'BbLoc'], stepsFromC: 11 },
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
var keyReverse = null
|
|
22
|
+
|
|
23
|
+
function createKeyReverse() {
|
|
24
|
+
keyReverse = {}
|
|
25
|
+
var allKeys = Object.keys(keys)
|
|
26
|
+
for (var i = 0 ; i < allKeys.length; i++) {
|
|
27
|
+
var keyObj = keys[allKeys[i]]
|
|
28
|
+
keyReverse[allKeys[i].toLowerCase()] = allKeys[i];
|
|
29
|
+
for (var j = 0; j < keyObj.modes.length; j++) {
|
|
30
|
+
var mode = keyObj.modes[j].toLowerCase()
|
|
31
|
+
keyReverse[mode] = allKeys[i];
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function relativeMajor(key) {
|
|
37
|
+
// Translate a key to its relative major. If it doesn't exist, do the best we can
|
|
38
|
+
// by just returning the original key.
|
|
39
|
+
// There are alternate spellings of these - so the search needs to be case insensitive.
|
|
40
|
+
// To make this efficient, the first time this is called the "keys" object is reversed so this search is fast in the future
|
|
41
|
+
if (!keyReverse) {
|
|
42
|
+
createKeyReverse()
|
|
43
|
+
}
|
|
44
|
+
// get the key portion itself - there might be other stuff, like extra sharps and flats, or the mode written out.
|
|
45
|
+
var mode = key.toLowerCase().match(/([a-g][b#]?)(maj|min|mix|dor|phr|lyd|loc|m)?/)
|
|
46
|
+
if (!mode || !mode[2])
|
|
47
|
+
return key;
|
|
48
|
+
mode = mode[1] + mode[2]
|
|
49
|
+
var maj = keyReverse[mode]
|
|
50
|
+
if (maj)
|
|
51
|
+
return maj;
|
|
52
|
+
return key;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function relativeMode(majorKey, mode) {
|
|
56
|
+
// The reverse of the relativeMajor. Translate it back to the original mode.
|
|
57
|
+
// If it isn't a recognized mode or it is already major, then just return the major key.
|
|
58
|
+
var group = keys[majorKey]
|
|
59
|
+
if (!group)
|
|
60
|
+
return majorKey;
|
|
61
|
+
if (mode === '')
|
|
62
|
+
return majorKey;
|
|
63
|
+
var match = mode.toLowerCase().match(/^(maj|min|mix|dor|phr|lyd|loc|m)/)
|
|
64
|
+
if (!match)
|
|
65
|
+
return majorKey
|
|
66
|
+
var regMode = match[1]
|
|
67
|
+
for (var i = 0; i < group.modes.length; i++) {
|
|
68
|
+
var thisMode = group.modes[i]
|
|
69
|
+
var ind = thisMode.toLowerCase().indexOf(regMode)
|
|
70
|
+
if (ind !== -1 && ind === thisMode.length - regMode.length)
|
|
71
|
+
return thisMode.substring(0, thisMode.length - regMode.length)
|
|
72
|
+
}
|
|
73
|
+
return majorKey;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function transposeKey(key, steps) {
|
|
77
|
+
// This takes a major key and adds the desired steps.
|
|
78
|
+
// It assigns each key a number that is the number of steps from C so that there can just be arithmetic.
|
|
79
|
+
var match = keys[key]
|
|
80
|
+
if (!match)
|
|
81
|
+
return key;
|
|
82
|
+
while (steps < 0) steps += 12;
|
|
83
|
+
var fromC = (match.stepsFromC + steps) % 12;
|
|
84
|
+
for (var i = 0; i < Object.keys(keys).length; i++) {
|
|
85
|
+
var k = Object.keys(keys)[i]
|
|
86
|
+
if (keys[k].stepsFromC === fromC)
|
|
87
|
+
return k;
|
|
88
|
+
}
|
|
89
|
+
return key;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {relativeMajor: relativeMajor, relativeMode: relativeMode, transposeKey: transposeKey};
|
package/src/parse/abc_parse.js
CHANGED
|
@@ -224,6 +224,7 @@ var Parse = function() {
|
|
|
224
224
|
var replace = false;
|
|
225
225
|
var addWord = function(i) {
|
|
226
226
|
var word = parseCommon.strip(words.substring(last_divider, i));
|
|
227
|
+
word = word.replace(/\\([-_*|~])/g, '$1')
|
|
227
228
|
last_divider = i+1;
|
|
228
229
|
if (word.length > 0) {
|
|
229
230
|
if (replace)
|
|
@@ -237,34 +238,44 @@ var Parse = function() {
|
|
|
237
238
|
}
|
|
238
239
|
return false;
|
|
239
240
|
};
|
|
241
|
+
var escNext = false;
|
|
240
242
|
for (var i = 0; i < words.length; i++) {
|
|
241
|
-
switch (words
|
|
243
|
+
switch (words[i]) {
|
|
242
244
|
case ' ':
|
|
243
245
|
case '\x12':
|
|
244
246
|
addWord(i);
|
|
245
247
|
break;
|
|
246
248
|
case '-':
|
|
247
|
-
if (!addWord(i) && word_list.length > 0) {
|
|
249
|
+
if (!escNext && !addWord(i) && word_list.length > 0) {
|
|
248
250
|
parseCommon.last(word_list).divider = '-';
|
|
249
251
|
word_list.push({skip: true, to: 'next'});
|
|
250
252
|
}
|
|
251
253
|
break;
|
|
252
254
|
case '_':
|
|
253
|
-
|
|
254
|
-
|
|
255
|
+
if (!escNext) {
|
|
256
|
+
addWord(i);
|
|
257
|
+
word_list.push({skip: true, to: 'slur'});
|
|
258
|
+
}
|
|
255
259
|
break;
|
|
256
260
|
case '*':
|
|
257
|
-
|
|
258
|
-
|
|
261
|
+
if (!escNext) {
|
|
262
|
+
addWord(i);
|
|
263
|
+
word_list.push({skip: true, to: 'next'});
|
|
264
|
+
}
|
|
259
265
|
break;
|
|
260
266
|
case '|':
|
|
261
|
-
|
|
262
|
-
|
|
267
|
+
if (!escNext) {
|
|
268
|
+
addWord(i);
|
|
269
|
+
word_list.push({skip: true, to: 'bar'});
|
|
270
|
+
}
|
|
263
271
|
break;
|
|
264
272
|
case '~':
|
|
265
|
-
|
|
273
|
+
if (!escNext) {
|
|
274
|
+
replace = true;
|
|
275
|
+
}
|
|
266
276
|
break;
|
|
267
277
|
}
|
|
278
|
+
escNext = words[i] === '\\'
|
|
268
279
|
}
|
|
269
280
|
|
|
270
281
|
var inSlur = false;
|
|
@@ -6,13 +6,14 @@ var bookParser = function(book) {
|
|
|
6
6
|
"use strict";
|
|
7
7
|
|
|
8
8
|
var directives = "";
|
|
9
|
+
var initialWhiteSpace = book.match(/(\s*)/)
|
|
9
10
|
book = parseCommon.strip(book);
|
|
10
11
|
var tuneStrings = book.split("\nX:");
|
|
11
12
|
// Put back the X: that we lost when splitting the tunes.
|
|
12
13
|
for (var i = 1; i < tuneStrings.length; i++)
|
|
13
14
|
tuneStrings[i] = "X:" + tuneStrings[i];
|
|
14
|
-
// Keep track of the character position each tune starts with.
|
|
15
|
-
var pos = 0;
|
|
15
|
+
// Keep track of the character position each tune starts with. If the string starts with white space, count that, too.
|
|
16
|
+
var pos = initialWhiteSpace ? initialWhiteSpace[0].length : 0;
|
|
16
17
|
var tunes = [];
|
|
17
18
|
parseCommon.each(tuneStrings, function(tune) {
|
|
18
19
|
tunes.push({ abc: tune, startPos: pos});
|
|
@@ -19,154 +19,7 @@ var parseKeyVoice = {};
|
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
parseKeyVoice.standardKey = function(keyName, root, acc, localTranspose) {
|
|
22
|
-
|
|
23
|
-
var key2sharp = {acc: 'sharp', note: 'c'};
|
|
24
|
-
var key3sharp = {acc: 'sharp', note: 'g'};
|
|
25
|
-
var key4sharp = {acc: 'sharp', note: 'd'};
|
|
26
|
-
var key5sharp = {acc: 'sharp', note: 'A'};
|
|
27
|
-
var key6sharp = {acc: 'sharp', note: 'e'};
|
|
28
|
-
var key7sharp = {acc: 'sharp', note: 'B'};
|
|
29
|
-
var key1flat = {acc: 'flat', note: 'B'};
|
|
30
|
-
var key2flat = {acc: 'flat', note: 'e'};
|
|
31
|
-
var key3flat = {acc: 'flat', note: 'A'};
|
|
32
|
-
var key4flat = {acc: 'flat', note: 'd'};
|
|
33
|
-
var key5flat = {acc: 'flat', note: 'G'};
|
|
34
|
-
var key6flat = {acc: 'flat', note: 'c'};
|
|
35
|
-
var key7flat = {acc: 'flat', note: 'F'};
|
|
36
|
-
|
|
37
|
-
var keys = {
|
|
38
|
-
'C#': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
39
|
-
'A#m': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
40
|
-
'G#Mix': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
41
|
-
'D#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
42
|
-
'E#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
43
|
-
'F#Lyd': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
44
|
-
'B#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
45
|
-
|
|
46
|
-
'F#': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
|
|
47
|
-
'D#m': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
|
|
48
|
-
'C#Mix': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
|
|
49
|
-
'G#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
|
|
50
|
-
'A#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
|
|
51
|
-
'BLyd': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
|
|
52
|
-
'E#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp ],
|
|
53
|
-
|
|
54
|
-
'B': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
|
|
55
|
-
'G#m': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
|
|
56
|
-
'F#Mix': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
|
|
57
|
-
'C#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
|
|
58
|
-
'D#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
|
|
59
|
-
'ELyd': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
|
|
60
|
-
'A#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp ],
|
|
61
|
-
|
|
62
|
-
'E': [ key1sharp, key2sharp, key3sharp, key4sharp ],
|
|
63
|
-
'C#m': [ key1sharp, key2sharp, key3sharp, key4sharp ],
|
|
64
|
-
'BMix': [ key1sharp, key2sharp, key3sharp, key4sharp ],
|
|
65
|
-
'F#Dor': [ key1sharp, key2sharp, key3sharp, key4sharp ],
|
|
66
|
-
'G#Phr': [ key1sharp, key2sharp, key3sharp, key4sharp ],
|
|
67
|
-
'ALyd': [ key1sharp, key2sharp, key3sharp, key4sharp ],
|
|
68
|
-
'D#Loc': [ key1sharp, key2sharp, key3sharp, key4sharp ],
|
|
69
|
-
|
|
70
|
-
'A': [ key1sharp, key2sharp, key3sharp ],
|
|
71
|
-
'F#m': [ key1sharp, key2sharp, key3sharp ],
|
|
72
|
-
'EMix': [ key1sharp, key2sharp, key3sharp ],
|
|
73
|
-
'BDor': [ key1sharp, key2sharp, key3sharp ],
|
|
74
|
-
'C#Phr': [ key1sharp, key2sharp, key3sharp ],
|
|
75
|
-
'DLyd': [ key1sharp, key2sharp, key3sharp ],
|
|
76
|
-
'G#Loc': [ key1sharp, key2sharp, key3sharp ],
|
|
77
|
-
|
|
78
|
-
'D': [ key1sharp, key2sharp ],
|
|
79
|
-
'Bm': [ key1sharp, key2sharp ],
|
|
80
|
-
'AMix': [ key1sharp, key2sharp ],
|
|
81
|
-
'EDor': [ key1sharp, key2sharp ],
|
|
82
|
-
'F#Phr': [ key1sharp, key2sharp ],
|
|
83
|
-
'GLyd': [ key1sharp, key2sharp ],
|
|
84
|
-
'C#Loc': [ key1sharp, key2sharp ],
|
|
85
|
-
|
|
86
|
-
'G': [ key1sharp ],
|
|
87
|
-
'Em': [ key1sharp ],
|
|
88
|
-
'DMix': [ key1sharp ],
|
|
89
|
-
'ADor': [ key1sharp ],
|
|
90
|
-
'BPhr': [ key1sharp ],
|
|
91
|
-
'CLyd': [ key1sharp ],
|
|
92
|
-
'F#Loc': [ key1sharp ],
|
|
93
|
-
|
|
94
|
-
'C': [],
|
|
95
|
-
'Am': [],
|
|
96
|
-
'GMix': [],
|
|
97
|
-
'DDor': [],
|
|
98
|
-
'EPhr': [],
|
|
99
|
-
'FLyd': [],
|
|
100
|
-
'BLoc': [],
|
|
101
|
-
|
|
102
|
-
'F': [ key1flat ],
|
|
103
|
-
'Dm': [ key1flat ],
|
|
104
|
-
'CMix': [ key1flat ],
|
|
105
|
-
'GDor': [ key1flat ],
|
|
106
|
-
'APhr': [ key1flat ],
|
|
107
|
-
'BbLyd': [ key1flat ],
|
|
108
|
-
'ELoc': [ key1flat ],
|
|
109
|
-
|
|
110
|
-
'Bb': [ key1flat, key2flat ],
|
|
111
|
-
'Gm': [ key1flat, key2flat ],
|
|
112
|
-
'FMix': [ key1flat, key2flat ],
|
|
113
|
-
'CDor': [ key1flat, key2flat ],
|
|
114
|
-
'DPhr': [ key1flat, key2flat ],
|
|
115
|
-
'EbLyd': [ key1flat, key2flat ],
|
|
116
|
-
'ALoc': [ key1flat, key2flat ],
|
|
117
|
-
|
|
118
|
-
'Eb': [ key1flat, key2flat, key3flat ],
|
|
119
|
-
'Cm': [ key1flat, key2flat, key3flat ],
|
|
120
|
-
'BbMix': [ key1flat, key2flat, key3flat ],
|
|
121
|
-
'FDor': [ key1flat, key2flat, key3flat ],
|
|
122
|
-
'GPhr': [ key1flat, key2flat, key3flat ],
|
|
123
|
-
'AbLyd': [ key1flat, key2flat, key3flat ],
|
|
124
|
-
'DLoc': [ key1flat, key2flat, key3flat ],
|
|
125
|
-
|
|
126
|
-
'Ab': [ key1flat, key2flat, key3flat, key4flat ],
|
|
127
|
-
'Fm': [ key1flat, key2flat, key3flat, key4flat ],
|
|
128
|
-
'EbMix': [ key1flat, key2flat, key3flat, key4flat ],
|
|
129
|
-
'BbDor': [ key1flat, key2flat, key3flat, key4flat ],
|
|
130
|
-
'CPhr': [ key1flat, key2flat, key3flat, key4flat ],
|
|
131
|
-
'DbLyd': [ key1flat, key2flat, key3flat, key4flat ],
|
|
132
|
-
'GLoc': [ key1flat, key2flat, key3flat, key4flat ],
|
|
133
|
-
|
|
134
|
-
'Db': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
|
|
135
|
-
'Bbm': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
|
|
136
|
-
'AbMix': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
|
|
137
|
-
'EbDor': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
|
|
138
|
-
'FPhr': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
|
|
139
|
-
'GbLyd': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
|
|
140
|
-
'CLoc': [ key1flat, key2flat, key3flat, key4flat, key5flat ],
|
|
141
|
-
|
|
142
|
-
'Gb': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
|
|
143
|
-
'Ebm': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
|
|
144
|
-
'DbMix': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
|
|
145
|
-
'AbDor': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
|
|
146
|
-
'BbPhr': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
|
|
147
|
-
'CbLyd': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
|
|
148
|
-
'FLoc': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat ],
|
|
149
|
-
|
|
150
|
-
'Cb': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
|
|
151
|
-
'Abm': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
|
|
152
|
-
'GbMix': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
|
|
153
|
-
'DbDor': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
|
|
154
|
-
'EbPhr': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
|
|
155
|
-
'FbLyd': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
|
|
156
|
-
'BbLoc': [ key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat ],
|
|
157
|
-
|
|
158
|
-
// The following are not in the 2.0 spec, but seem normal enough.
|
|
159
|
-
// TODO-PER: These SOUND the same as what's written, but they aren't right
|
|
160
|
-
'A#': [ key1flat, key2flat ],
|
|
161
|
-
'B#': [],
|
|
162
|
-
'D#': [ key1flat, key2flat, key3flat ],
|
|
163
|
-
'E#': [ key1flat ],
|
|
164
|
-
'G#': [ key1flat, key2flat, key3flat, key4flat ],
|
|
165
|
-
'Gbm': [ key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp ],
|
|
166
|
-
'none': []
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
return transpose.keySignature(multilineVars, keys, keyName, root, acc, localTranspose);
|
|
22
|
+
return transpose.keySignature(multilineVars, keyName, root, acc, localTranspose);
|
|
170
23
|
};
|
|
171
24
|
|
|
172
25
|
var clefLines = {
|
|
@@ -289,7 +289,7 @@ MusicParser.prototype.parseMusic = function(line) {
|
|
|
289
289
|
}
|
|
290
290
|
}
|
|
291
291
|
multilineVars.addFormattingOptions(el, tune.formatting, 'bar');
|
|
292
|
-
tuneBuilder.appendElement('bar', startOfLine+
|
|
292
|
+
tuneBuilder.appendElement('bar', startOfLine+startI, startOfLine+i+ret[0], bar);
|
|
293
293
|
multilineVars.measureNotEmpty = false;
|
|
294
294
|
el = {};
|
|
295
295
|
}
|
|
@@ -732,7 +732,7 @@ var volumeDecorations = [
|
|
|
732
732
|
];
|
|
733
733
|
|
|
734
734
|
var dynamicDecorations = [
|
|
735
|
-
"crescendo(", "crescendo)", "diminuendo(", "diminuendo)"
|
|
735
|
+
"crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)"
|
|
736
736
|
];
|
|
737
737
|
|
|
738
738
|
var accentPseudonyms = [
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// abc_transpose.js: Handles the automatic transposition of key signatures, chord symbols, and notes.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
var allNotes = require("./all-notes");
|
|
4
|
+
var transposeChordName = require("../parse/transpose-chord")
|
|
5
|
+
var keyAccidentals = require('../const/key-accidentals');
|
|
4
6
|
var transpose = {};
|
|
5
7
|
|
|
6
8
|
var keyIndex = {
|
|
@@ -25,13 +27,13 @@ var keyIndex = {
|
|
|
25
27
|
var newKey = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'];
|
|
26
28
|
var newKeyMinor = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'];
|
|
27
29
|
|
|
28
|
-
transpose.keySignature = function(multilineVars,
|
|
29
|
-
if (multilineVars.clef.type === "perc")
|
|
30
|
-
return { accidentals:
|
|
30
|
+
transpose.keySignature = function(multilineVars, keyName, root, acc, localTranspose) {
|
|
31
|
+
if (multilineVars.clef.type === "perc" || multilineVars.clef.type === "none")
|
|
32
|
+
return { accidentals: keyAccidentals(keyName), root: root, acc: acc };
|
|
31
33
|
if (!localTranspose) localTranspose = 0;
|
|
32
34
|
multilineVars.localTransposeVerticalMovement = 0;
|
|
33
35
|
multilineVars.localTransposePreferFlats = false;
|
|
34
|
-
var k =
|
|
36
|
+
var k = keyAccidentals(keyName);
|
|
35
37
|
if (!k) return multilineVars.key; // If the key isn't in the list, it is non-standard. We won't attempt to transpose it.
|
|
36
38
|
multilineVars.localTranspose = (multilineVars.globalTranspose ? multilineVars.globalTranspose : 0) + localTranspose;
|
|
37
39
|
|
|
@@ -54,7 +56,7 @@ transpose.keySignature = function(multilineVars, keys, keyName, root, acc, local
|
|
|
54
56
|
if (index > 11) index = index % 12;
|
|
55
57
|
var newKeyName = (keyName[0] === 'm' ? newKeyMinor[index] : newKey[index]);
|
|
56
58
|
var transposedKey = newKeyName + keyName;
|
|
57
|
-
var newKeySig =
|
|
59
|
+
var newKeySig = keyAccidentals(transposedKey);
|
|
58
60
|
if (newKeySig.length > 0 && newKeySig[0].acc === 'flat')
|
|
59
61
|
multilineVars.localTransposePreferFlats = true;
|
|
60
62
|
var distance = transposedKey.charCodeAt(0) - baseKey.charCodeAt(0);
|
|
@@ -88,69 +90,8 @@ transpose.keySignature = function(multilineVars, keys, keyName, root, acc, local
|
|
|
88
90
|
return { accidentals: newKeySig, root: newKeyName[0], acc: newKeyName.length > 1 ? newKeyName[1] : "" };
|
|
89
91
|
};
|
|
90
92
|
|
|
91
|
-
var sharpChords = [ 'C', 'C♯', 'D', "D♯", 'E', 'F', "F♯", 'G', 'G♯', 'A', 'A♯', 'B'];
|
|
92
|
-
var flatChords = [ 'C', 'D♭', 'D', 'E♭', 'E', 'F', 'G♭', 'G', 'A♭', 'A', 'B♭', 'B'];
|
|
93
|
-
var sharpChordsFree = [ 'C', 'C#', 'D', "D#", 'E', 'F', "F#", 'G', 'G#', 'A', 'A#', 'B'];
|
|
94
|
-
var flatChordsFree = [ 'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
|
|
95
|
-
|
|
96
93
|
transpose.chordName = function(multilineVars, chord) {
|
|
97
|
-
|
|
98
|
-
var transposeFactor = multilineVars.localTranspose;
|
|
99
|
-
while (transposeFactor < 0) transposeFactor += 12;
|
|
100
|
-
if (transposeFactor > 11) transposeFactor = transposeFactor % 12;
|
|
101
|
-
if (multilineVars.freegchord) {
|
|
102
|
-
chord = chord.replace(/Cb/g, "`~11`");
|
|
103
|
-
chord = chord.replace(/Db/g, "`~1`");
|
|
104
|
-
chord = chord.replace(/Eb/g, "`~3`");
|
|
105
|
-
chord = chord.replace(/Fb/g, "`~4`");
|
|
106
|
-
chord = chord.replace(/Gb/g, "`~6`");
|
|
107
|
-
chord = chord.replace(/Ab/g, "`~8`");
|
|
108
|
-
chord = chord.replace(/Bb/g, "`~10`");
|
|
109
|
-
chord = chord.replace(/C#/g, "`~1`");
|
|
110
|
-
chord = chord.replace(/D#/g, "`~3`");
|
|
111
|
-
chord = chord.replace(/E#/g, "`~5`");
|
|
112
|
-
chord = chord.replace(/F#/g, "`~6`");
|
|
113
|
-
chord = chord.replace(/G#/g, "`~8`");
|
|
114
|
-
chord = chord.replace(/A#/g, "`~10`");
|
|
115
|
-
chord = chord.replace(/B#/g, "`~0`");
|
|
116
|
-
} else {
|
|
117
|
-
chord = chord.replace(/C♭/g, "`~11`");
|
|
118
|
-
chord = chord.replace(/D♭/g, "`~1`");
|
|
119
|
-
chord = chord.replace(/E♭/g, "`~3`");
|
|
120
|
-
chord = chord.replace(/F♭/g, "`~4`");
|
|
121
|
-
chord = chord.replace(/G♭/g, "`~6`");
|
|
122
|
-
chord = chord.replace(/A♭/g, "`~8`");
|
|
123
|
-
chord = chord.replace(/B♭/g, "`~10`");
|
|
124
|
-
chord = chord.replace(/C♯/g, "`~1`");
|
|
125
|
-
chord = chord.replace(/D♯/g, "`~3`");
|
|
126
|
-
chord = chord.replace(/E♯/g, "`~5`");
|
|
127
|
-
chord = chord.replace(/F♯/g, "`~6`");
|
|
128
|
-
chord = chord.replace(/G♯/g, "`~8`");
|
|
129
|
-
chord = chord.replace(/A♯/g, "`~10`");
|
|
130
|
-
chord = chord.replace(/B♯/g, "`~0`");
|
|
131
|
-
}
|
|
132
|
-
chord = chord.replace(/C/g, "`~0`");
|
|
133
|
-
chord = chord.replace(/D/g, "`~2`");
|
|
134
|
-
chord = chord.replace(/E/g, "`~4`");
|
|
135
|
-
chord = chord.replace(/F/g, "`~5`");
|
|
136
|
-
chord = chord.replace(/G/g, "`~7`");
|
|
137
|
-
chord = chord.replace(/A/g, "`~9`");
|
|
138
|
-
chord = chord.replace(/B/g, "`~11`");
|
|
139
|
-
var arr = chord.split("`");
|
|
140
|
-
for (var i = 0; i < arr.length; i++) {
|
|
141
|
-
if (arr[i][0] === '~') {
|
|
142
|
-
var chordNum = parseInt(arr[i].substr(1),10);
|
|
143
|
-
chordNum += transposeFactor;
|
|
144
|
-
if (chordNum > 11) chordNum -= 12;
|
|
145
|
-
if (multilineVars.freegchord)
|
|
146
|
-
arr[i] = multilineVars.localTransposePreferFlats ? flatChordsFree[chordNum] : sharpChordsFree[chordNum];
|
|
147
|
-
else
|
|
148
|
-
arr[i] = multilineVars.localTransposePreferFlats ? flatChords[chordNum] : sharpChords[chordNum];
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
chord = arr.join("");
|
|
152
|
-
}
|
|
153
|
-
return chord;
|
|
94
|
+
return transposeChordName(chord, multilineVars.localTranspose, multilineVars.localTransposePreferFlats, multilineVars.freegchord)
|
|
154
95
|
};
|
|
155
96
|
|
|
156
97
|
var pitchToLetter = [ 'c', 'd', 'e', 'f', 'g', 'a', 'b' ];
|