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/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.3",
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": "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"
@@ -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
- else if (removeDiv || !params.oneSvgPerLine || tune.lines.length < 2)
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
- if (!params.oneSvgPerLine || tune.lines.length < 2)
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};
@@ -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});
@@ -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 = {
@@ -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 = [
@@ -1,6 +1,8 @@
1
1
  // abc_transpose.js: Handles the automatic transposition of key signatures, chord symbols, and notes.
2
2
 
3
- const allNotes = require("./all-notes");
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, keys, keyName, root, acc, localTranspose) {
29
- if (multilineVars.clef.type === "perc")
30
- return { accidentals: keys[keyName], root: root, acc: acc };
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 = keys[keyName];
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 = keys[transposedKey];
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
- if (multilineVars.localTranspose && (multilineVars.localTranspose % 12 !== 0)) { // The chords are the same if it is an exact octave change.
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' ];