abcjs 6.0.2 → 6.1.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/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.0.2",
3
+ "version": "6.1.0",
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": "mocha 'tests/**/*.js'",
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"
@@ -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};
@@ -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.charAt(i)) {
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
- addWord(i);
254
- word_list.push({skip: true, to: 'slur'});
255
+ if (!escNext) {
256
+ addWord(i);
257
+ word_list.push({skip: true, to: 'slur'});
258
+ }
255
259
  break;
256
260
  case '*':
257
- addWord(i);
258
- word_list.push({skip: true, to: 'next'});
261
+ if (!escNext) {
262
+ addWord(i);
263
+ word_list.push({skip: true, to: 'next'});
264
+ }
259
265
  break;
260
266
  case '|':
261
- addWord(i);
262
- word_list.push({skip: true, to: 'bar'});
267
+ if (!escNext) {
268
+ addWord(i);
269
+ word_list.push({skip: true, to: 'bar'});
270
+ }
263
271
  break;
264
272
  case '~':
265
- replace = true;
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});
@@ -364,7 +364,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
364
364
  multilineVars.meter = meter;
365
365
  return [ e-i+1+ws ];
366
366
  case "[K:":
367
- var result = parseKeyVoice.parseKey(line.substring(i+3, e));
367
+ var result = parseKeyVoice.parseKey(line.substring(i+3, e), true);
368
368
  if (result.foundClef && tuneBuilder.hasBeginMusic())
369
369
  tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
370
370
  if (result.foundKey && tuneBuilder.hasBeginMusic())
@@ -426,7 +426,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
426
426
  tuneBuilder.appendStartingElement('meter', multilineVars.iChar + i, multilineVars.iChar + line.length, meter);
427
427
  return [ line.length ];
428
428
  case "K:":
429
- var result = parseKeyVoice.parseKey(line.substring(i+2));
429
+ var result = parseKeyVoice.parseKey(line.substring(i+2), tuneBuilder.hasBeginMusic());
430
430
  if (result.foundClef && tuneBuilder.hasBeginMusic())
431
431
  tuneBuilder.appendStartingElement('clef', multilineVars.iChar + i, multilineVars.iChar + line.length, multilineVars.clef);
432
432
  if (result.foundKey && tuneBuilder.hasBeginMusic())
@@ -498,7 +498,7 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
498
498
  case 'K':
499
499
  // since the key is the last thing that can happen in the header, we can resolve the tempo now
500
500
  this.resolveTempo();
501
- var result = parseKeyVoice.parseKey(line.substring(2));
501
+ var result = parseKeyVoice.parseKey(line.substring(2), false);
502
502
  if (!multilineVars.is_in_header && tuneBuilder.hasBeginMusic()) {
503
503
  if (result.foundClef)
504
504
  tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
@@ -19,154 +19,7 @@ var parseKeyVoice = {};
19
19
  };
20
20
 
21
21
  parseKeyVoice.standardKey = function(keyName, root, acc, localTranspose) {
22
- var key1sharp = {acc: 'sharp', note: 'f'};
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 = {
@@ -340,7 +193,7 @@ var parseKeyVoice = {};
340
193
  }
341
194
  };
342
195
 
343
- parseKeyVoice.parseKey = function(str) // (and clef)
196
+ parseKeyVoice.parseKey = function(str, isInline) // (and clef)
344
197
  {
345
198
  // returns:
346
199
  // { foundClef: true, foundKey: true }
@@ -431,8 +284,14 @@ var parseKeyVoice = {};
431
284
  // We need to do a deep copy because we are going to modify it
432
285
  var oldKey = parseKeyVoice.deepCopyKey(multilineVars.key);
433
286
  //TODO-PER: HACK! To get the local transpose to work, the transposition is done for each line. This caused the global transposition variable to be factored in twice, so, instead of rewriting that right now, I'm just subtracting one of them here.
434
- var keyCompensate = multilineVars.globalTranspose ? -multilineVars.globalTranspose : 0;
287
+ var keyCompensate = !isInline && multilineVars.globalTranspose ? -multilineVars.globalTranspose : 0;
288
+ //console.log("parse", JSON.stringify(multilineVars), isInline)
289
+ var savedOrigKey;
290
+ if (isInline)
291
+ savedOrigKey = multilineVars.globalTransposeOrigKeySig
435
292
  multilineVars.key = parseKeyVoice.deepCopyKey(parseKeyVoice.standardKey(key, retPitch.token, acc, keyCompensate));
293
+ if (isInline)
294
+ multilineVars.globalTransposeOrigKeySig = savedOrigKey
436
295
  multilineVars.key.mode = mode;
437
296
  if (oldKey) {
438
297
  // Add natural in all places that the old key had an accidental.
@@ -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+i, startOfLine+i+ret[0], bar);
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 = [
@@ -702,18 +702,15 @@ var Tokenizer = function(lines, multilineVars) {
702
702
  }
703
703
  switch (x.token) {
704
704
  case 'pt': return { used: used+1, value: parseFloat(num) };
705
+ case 'px': return { used: used+1, value: parseFloat(num) };
705
706
  case 'cm': return { used: used+1, value: parseFloat(num)/2.54*72 };
706
707
  case 'in': return { used: used+1, value: parseFloat(num)*72 };
707
708
  default: tokens.unshift(x); return { used: used, value: parseFloat(num) };
708
709
  }
709
- return { used: 0 };
710
710
  };
711
- var substInChord = function(str)
712
- {
713
- while ( str.indexOf("\\n") !== -1)
714
- {
715
- str = str.replace("\\n", "\n");
716
- }
711
+ var substInChord = function(str) {
712
+ str = str.replace(/\\n/g, "\n");
713
+ str = str.replace(/\\"/g, '"');
717
714
  return str;
718
715
  };
719
716
  this.getBrackettedSubstring = function(line, i, maxErrorChars, _matchChar)
@@ -728,8 +725,11 @@ var Tokenizer = function(lines, multilineVars) {
728
725
  // but in the error case it might not be.
729
726
  var matchChar = _matchChar || line.charAt(i);
730
727
  var pos = i+1;
731
- while ((pos < line.length) && (line.charAt(pos) !== matchChar))
728
+ var esc = false;
729
+ while ((pos < line.length) && (esc || line[pos] !== matchChar)) {
730
+ esc = line[pos] === '\\';
732
731
  ++pos;
732
+ }
733
733
  if (line.charAt(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.