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/README.md +6 -0
- package/RELEASE.md +60 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +1344 -401
- 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/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_header.js +3 -3
- package/src/parse/abc_parse_key_voice.js +9 -150
- package/src/parse/abc_parse_music.js +2 -2
- package/src/parse/abc_tokenizer.js +8 -8
- package/src/parse/abc_transpose.js +31 -69
- package/src/parse/all-notes.js +22 -0
- 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/synth/place-note.js +1 -1
- package/src/test/abc_parser_lint.js +1 -1
- package/src/write/abc_abstract_engraver.js +15 -0
- package/src/write/abc_beam_element.js +24 -0
- package/src/write/abc_decoration.js +13 -0
- package/src/write/abc_glissando_element.js +7 -0
- package/src/write/abc_tie_element.js +11 -0
- package/src/write/draw/glissando.js +75 -0
- package/src/write/draw/voice.js +4 -0
- package/src/write/format-jazz-chord.js +1 -1
- package/src/write/top-text.js +1 -1
- package/types/index.d.ts +12 -8
- package/version.js +1 -1
package/dist/abcjs-basic.js
CHANGED
|
@@ -48,6 +48,8 @@ var tuneBook = __webpack_require__(/*! ./src/api/abc_tunebook */ "./src/api/abc_
|
|
|
48
48
|
|
|
49
49
|
var sequence = __webpack_require__(/*! ./src/synth/abc_midi_sequencer */ "./src/synth/abc_midi_sequencer.js");
|
|
50
50
|
|
|
51
|
+
var strTranspose = __webpack_require__(/*! ./src/str/output */ "./src/str/output.js");
|
|
52
|
+
|
|
51
53
|
var abcjs = {};
|
|
52
54
|
abcjs.signature = "abcjs-basic v" + version;
|
|
53
55
|
Object.keys(animation).forEach(function (key) {
|
|
@@ -62,6 +64,7 @@ abcjs.TimingCallbacks = __webpack_require__(/*! ./src/api/abc_timing_callbacks *
|
|
|
62
64
|
var glyphs = __webpack_require__(/*! ./src/write/abc_glyphs */ "./src/write/abc_glyphs.js");
|
|
63
65
|
|
|
64
66
|
abcjs.setGlyph = glyphs.setSymbol;
|
|
67
|
+
abcjs.strTranspose = strTranspose;
|
|
65
68
|
|
|
66
69
|
var CreateSynth = __webpack_require__(/*! ./src/synth/create-synth */ "./src/synth/create-synth.js");
|
|
67
70
|
|
|
@@ -1294,6 +1297,262 @@ module.exports = renderAbc;
|
|
|
1294
1297
|
|
|
1295
1298
|
/***/ }),
|
|
1296
1299
|
|
|
1300
|
+
/***/ "./src/const/key-accidentals.js":
|
|
1301
|
+
/*!**************************************!*\
|
|
1302
|
+
!*** ./src/const/key-accidentals.js ***!
|
|
1303
|
+
\**************************************/
|
|
1304
|
+
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
1305
|
+
|
|
1306
|
+
var _require = __webpack_require__(/*! ./relative-major */ "./src/const/relative-major.js"),
|
|
1307
|
+
relativeMajor = _require.relativeMajor;
|
|
1308
|
+
|
|
1309
|
+
var key1sharp = {
|
|
1310
|
+
acc: 'sharp',
|
|
1311
|
+
note: 'f'
|
|
1312
|
+
};
|
|
1313
|
+
var key2sharp = {
|
|
1314
|
+
acc: 'sharp',
|
|
1315
|
+
note: 'c'
|
|
1316
|
+
};
|
|
1317
|
+
var key3sharp = {
|
|
1318
|
+
acc: 'sharp',
|
|
1319
|
+
note: 'g'
|
|
1320
|
+
};
|
|
1321
|
+
var key4sharp = {
|
|
1322
|
+
acc: 'sharp',
|
|
1323
|
+
note: 'd'
|
|
1324
|
+
};
|
|
1325
|
+
var key5sharp = {
|
|
1326
|
+
acc: 'sharp',
|
|
1327
|
+
note: 'A'
|
|
1328
|
+
};
|
|
1329
|
+
var key6sharp = {
|
|
1330
|
+
acc: 'sharp',
|
|
1331
|
+
note: 'e'
|
|
1332
|
+
};
|
|
1333
|
+
var key7sharp = {
|
|
1334
|
+
acc: 'sharp',
|
|
1335
|
+
note: 'B'
|
|
1336
|
+
};
|
|
1337
|
+
var key1flat = {
|
|
1338
|
+
acc: 'flat',
|
|
1339
|
+
note: 'B'
|
|
1340
|
+
};
|
|
1341
|
+
var key2flat = {
|
|
1342
|
+
acc: 'flat',
|
|
1343
|
+
note: 'e'
|
|
1344
|
+
};
|
|
1345
|
+
var key3flat = {
|
|
1346
|
+
acc: 'flat',
|
|
1347
|
+
note: 'A'
|
|
1348
|
+
};
|
|
1349
|
+
var key4flat = {
|
|
1350
|
+
acc: 'flat',
|
|
1351
|
+
note: 'd'
|
|
1352
|
+
};
|
|
1353
|
+
var key5flat = {
|
|
1354
|
+
acc: 'flat',
|
|
1355
|
+
note: 'G'
|
|
1356
|
+
};
|
|
1357
|
+
var key6flat = {
|
|
1358
|
+
acc: 'flat',
|
|
1359
|
+
note: 'c'
|
|
1360
|
+
};
|
|
1361
|
+
var key7flat = {
|
|
1362
|
+
acc: 'flat',
|
|
1363
|
+
note: 'F'
|
|
1364
|
+
};
|
|
1365
|
+
var keys = {
|
|
1366
|
+
'C#': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
1367
|
+
'F#': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
1368
|
+
'B': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
1369
|
+
'E': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
1370
|
+
'A': [key1sharp, key2sharp, key3sharp],
|
|
1371
|
+
'D': [key1sharp, key2sharp],
|
|
1372
|
+
'G': [key1sharp],
|
|
1373
|
+
'C': [],
|
|
1374
|
+
'F': [key1flat],
|
|
1375
|
+
'Bb': [key1flat, key2flat],
|
|
1376
|
+
'Eb': [key1flat, key2flat, key3flat],
|
|
1377
|
+
'Cm': [key1flat, key2flat, key3flat],
|
|
1378
|
+
'Ab': [key1flat, key2flat, key3flat, key4flat],
|
|
1379
|
+
'Db': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
1380
|
+
'Gb': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
1381
|
+
'Cb': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
1382
|
+
// The following are not in the 2.0 spec, but seem normal enough.
|
|
1383
|
+
// TODO-PER: These SOUND the same as what's written, but they aren't right
|
|
1384
|
+
'A#': [key1flat, key2flat],
|
|
1385
|
+
'B#': [],
|
|
1386
|
+
'D#': [key1flat, key2flat, key3flat],
|
|
1387
|
+
'E#': [key1flat],
|
|
1388
|
+
'G#': [key1flat, key2flat, key3flat, key4flat],
|
|
1389
|
+
'none': []
|
|
1390
|
+
};
|
|
1391
|
+
|
|
1392
|
+
function keyAccidentals(key) {
|
|
1393
|
+
var newKey = keys[relativeMajor(key)];
|
|
1394
|
+
if (!newKey) // If we don't recognize the key then there is no change
|
|
1395
|
+
return null;
|
|
1396
|
+
return JSON.parse(JSON.stringify(newKey));
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
;
|
|
1400
|
+
module.exports = keyAccidentals;
|
|
1401
|
+
|
|
1402
|
+
/***/ }),
|
|
1403
|
+
|
|
1404
|
+
/***/ "./src/const/relative-major.js":
|
|
1405
|
+
/*!*************************************!*\
|
|
1406
|
+
!*** ./src/const/relative-major.js ***!
|
|
1407
|
+
\*************************************/
|
|
1408
|
+
/***/ (function(module) {
|
|
1409
|
+
|
|
1410
|
+
// All these keys have the same number of accidentals
|
|
1411
|
+
var keys = {
|
|
1412
|
+
'C': {
|
|
1413
|
+
modes: ['CMaj', 'Amin', 'Am', 'GMix', 'DDor', 'EPhr', 'FLyd', 'BLoc'],
|
|
1414
|
+
stepsFromC: 0
|
|
1415
|
+
},
|
|
1416
|
+
'Db': {
|
|
1417
|
+
modes: ['DbMaj', 'Bbmin', 'Bbm', 'AbMix', 'EbDor', 'FPhr', 'GbLyd', 'CLoc'],
|
|
1418
|
+
stepsFromC: 1
|
|
1419
|
+
},
|
|
1420
|
+
'D': {
|
|
1421
|
+
modes: ['DMaj', 'Bmin', 'Bm', 'AMix', 'EDor', 'F#Phr', 'GLyd', 'C#Loc'],
|
|
1422
|
+
stepsFromC: 2
|
|
1423
|
+
},
|
|
1424
|
+
'Eb': {
|
|
1425
|
+
modes: ['EbMaj', 'Cmin', 'Cm', 'BbMix', 'FDor', 'GPhr', 'AbLyd', 'DLoc'],
|
|
1426
|
+
stepsFromC: 3
|
|
1427
|
+
},
|
|
1428
|
+
'E': {
|
|
1429
|
+
modes: ['EMaj', 'C#min', 'C#m', 'BMix', 'F#Dor', 'G#Phr', 'ALyd', 'D#Loc'],
|
|
1430
|
+
stepsFromC: 4
|
|
1431
|
+
},
|
|
1432
|
+
'F': {
|
|
1433
|
+
modes: ['FMaj', 'Dmin', 'Dm', 'CMix', 'GDor', 'APhr', 'BbLyd', 'ELoc'],
|
|
1434
|
+
stepsFromC: 5
|
|
1435
|
+
},
|
|
1436
|
+
'Gb': {
|
|
1437
|
+
modes: ['GbMaj', 'Ebmin', 'Ebm', 'DbMix', 'AbDor', 'BbPhr', 'CbLyd', 'FLoc'],
|
|
1438
|
+
stepsFromC: 6
|
|
1439
|
+
},
|
|
1440
|
+
'G': {
|
|
1441
|
+
modes: ['GMaj', 'Emin', 'Em', 'DMix', 'ADor', 'BPhr', 'CLyd', 'F#Loc'],
|
|
1442
|
+
stepsFromC: 7
|
|
1443
|
+
},
|
|
1444
|
+
'Ab': {
|
|
1445
|
+
modes: ['AbMaj', 'Fmin', 'Fm', 'EbMix', 'BbDor', 'CPhr', 'DbLyd', 'GLoc'],
|
|
1446
|
+
stepsFromC: 8
|
|
1447
|
+
},
|
|
1448
|
+
'A': {
|
|
1449
|
+
modes: ['AMaj', 'F#min', 'F#m', 'EMix', 'BDor', 'C#Phr', 'DLyd', 'G#Loc'],
|
|
1450
|
+
stepsFromC: 9
|
|
1451
|
+
},
|
|
1452
|
+
'Bb': {
|
|
1453
|
+
modes: ['BbMaj', 'Gmin', 'Gm', 'FMix', 'CDor', 'DPhr', 'EbLyd', 'ALoc'],
|
|
1454
|
+
stepsFromC: 10
|
|
1455
|
+
},
|
|
1456
|
+
'B': {
|
|
1457
|
+
modes: ['BMaj', 'G#min', 'G#m', 'F#Mix', 'C#Dor', 'D#Phr', 'ELyd', 'A#Loc'],
|
|
1458
|
+
stepsFromC: 11
|
|
1459
|
+
},
|
|
1460
|
+
// Enharmonic keys
|
|
1461
|
+
'C#': {
|
|
1462
|
+
modes: ['C#Maj', 'A#min', 'A#m', 'G#Mix', 'D#Dor', 'E#Phr', 'F#Lyd', 'B#Loc'],
|
|
1463
|
+
stepsFromC: 1
|
|
1464
|
+
},
|
|
1465
|
+
'F#': {
|
|
1466
|
+
modes: ['F#Maj', 'D#min', 'D#m', 'C#Mix', 'G#Dor', 'A#Phr', 'BLyd', 'E#Loc'],
|
|
1467
|
+
stepsFromC: 6
|
|
1468
|
+
},
|
|
1469
|
+
'Cb': {
|
|
1470
|
+
modes: ['CbMaj', 'Abmin', 'Abm', 'GbMix', 'DbDor', 'EbPhr', 'FbLyd', 'BbLoc'],
|
|
1471
|
+
stepsFromC: 11
|
|
1472
|
+
}
|
|
1473
|
+
};
|
|
1474
|
+
var keyReverse = null;
|
|
1475
|
+
|
|
1476
|
+
function createKeyReverse() {
|
|
1477
|
+
keyReverse = {};
|
|
1478
|
+
var allKeys = Object.keys(keys);
|
|
1479
|
+
|
|
1480
|
+
for (var i = 0; i < allKeys.length; i++) {
|
|
1481
|
+
var keyObj = keys[allKeys[i]];
|
|
1482
|
+
keyReverse[allKeys[i].toLowerCase()] = allKeys[i];
|
|
1483
|
+
|
|
1484
|
+
for (var j = 0; j < keyObj.modes.length; j++) {
|
|
1485
|
+
var mode = keyObj.modes[j].toLowerCase();
|
|
1486
|
+
keyReverse[mode] = allKeys[i];
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
|
|
1491
|
+
function relativeMajor(key) {
|
|
1492
|
+
// Translate a key to its relative major. If it doesn't exist, do the best we can
|
|
1493
|
+
// by just returning the original key.
|
|
1494
|
+
// There are alternate spellings of these - so the search needs to be case insensitive.
|
|
1495
|
+
// To make this efficient, the first time this is called the "keys" object is reversed so this search is fast in the future
|
|
1496
|
+
if (!keyReverse) {
|
|
1497
|
+
createKeyReverse();
|
|
1498
|
+
} // get the key portion itself - there might be other stuff, like extra sharps and flats, or the mode written out.
|
|
1499
|
+
|
|
1500
|
+
|
|
1501
|
+
var mode = key.toLowerCase().match(/([a-g][b#]?)(maj|min|mix|dor|phr|lyd|loc|m)?/);
|
|
1502
|
+
if (!mode || !mode[2]) return key;
|
|
1503
|
+
mode = mode[1] + mode[2];
|
|
1504
|
+
var maj = keyReverse[mode];
|
|
1505
|
+
if (maj) return maj;
|
|
1506
|
+
return key;
|
|
1507
|
+
}
|
|
1508
|
+
|
|
1509
|
+
function relativeMode(majorKey, mode) {
|
|
1510
|
+
// The reverse of the relativeMajor. Translate it back to the original mode.
|
|
1511
|
+
// If it isn't a recognized mode or it is already major, then just return the major key.
|
|
1512
|
+
var group = keys[majorKey];
|
|
1513
|
+
if (!group) return majorKey;
|
|
1514
|
+
if (mode === '') return majorKey;
|
|
1515
|
+
var match = mode.toLowerCase().match(/^(maj|min|mix|dor|phr|lyd|loc|m)/);
|
|
1516
|
+
if (!match) return majorKey;
|
|
1517
|
+
var regMode = match[1];
|
|
1518
|
+
|
|
1519
|
+
for (var i = 0; i < group.modes.length; i++) {
|
|
1520
|
+
var thisMode = group.modes[i];
|
|
1521
|
+
var ind = thisMode.toLowerCase().indexOf(regMode);
|
|
1522
|
+
if (ind !== -1 && ind === thisMode.length - regMode.length) return thisMode.substring(0, thisMode.length - regMode.length);
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
return majorKey;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1528
|
+
function transposeKey(key, steps) {
|
|
1529
|
+
// This takes a major key and adds the desired steps.
|
|
1530
|
+
// It assigns each key a number that is the number of steps from C so that there can just be arithmetic.
|
|
1531
|
+
var match = keys[key];
|
|
1532
|
+
if (!match) return key;
|
|
1533
|
+
|
|
1534
|
+
while (steps < 0) {
|
|
1535
|
+
steps += 12;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
var fromC = (match.stepsFromC + steps) % 12;
|
|
1539
|
+
|
|
1540
|
+
for (var i = 0; i < Object.keys(keys).length; i++) {
|
|
1541
|
+
var k = Object.keys(keys)[i];
|
|
1542
|
+
if (keys[k].stepsFromC === fromC) return k;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
return key;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
module.exports = {
|
|
1549
|
+
relativeMajor: relativeMajor,
|
|
1550
|
+
relativeMode: relativeMode,
|
|
1551
|
+
transposeKey: transposeKey
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
/***/ }),
|
|
1555
|
+
|
|
1297
1556
|
/***/ "./src/data/abc_tune.js":
|
|
1298
1557
|
/*!******************************!*\
|
|
1299
1558
|
!*** ./src/data/abc_tune.js ***!
|
|
@@ -3232,6 +3491,7 @@ var Parse = function Parse() {
|
|
|
3232
3491
|
|
|
3233
3492
|
var addWord = function addWord(i) {
|
|
3234
3493
|
var word = parseCommon.strip(words.substring(last_divider, i));
|
|
3494
|
+
word = word.replace(/\\([-_*|~])/g, '$1');
|
|
3235
3495
|
last_divider = i + 1;
|
|
3236
3496
|
|
|
3237
3497
|
if (word.length > 0) {
|
|
@@ -3249,15 +3509,17 @@ var Parse = function Parse() {
|
|
|
3249
3509
|
return false;
|
|
3250
3510
|
};
|
|
3251
3511
|
|
|
3512
|
+
var escNext = false;
|
|
3513
|
+
|
|
3252
3514
|
for (var i = 0; i < words.length; i++) {
|
|
3253
|
-
switch (words
|
|
3515
|
+
switch (words[i]) {
|
|
3254
3516
|
case ' ':
|
|
3255
3517
|
case '\x12':
|
|
3256
3518
|
addWord(i);
|
|
3257
3519
|
break;
|
|
3258
3520
|
|
|
3259
3521
|
case '-':
|
|
3260
|
-
if (!addWord(i) && word_list.length > 0) {
|
|
3522
|
+
if (!escNext && !addWord(i) && word_list.length > 0) {
|
|
3261
3523
|
parseCommon.last(word_list).divider = '-';
|
|
3262
3524
|
word_list.push({
|
|
3263
3525
|
skip: true,
|
|
@@ -3268,33 +3530,47 @@ var Parse = function Parse() {
|
|
|
3268
3530
|
break;
|
|
3269
3531
|
|
|
3270
3532
|
case '_':
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3533
|
+
if (!escNext) {
|
|
3534
|
+
addWord(i);
|
|
3535
|
+
word_list.push({
|
|
3536
|
+
skip: true,
|
|
3537
|
+
to: 'slur'
|
|
3538
|
+
});
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3276
3541
|
break;
|
|
3277
3542
|
|
|
3278
3543
|
case '*':
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3544
|
+
if (!escNext) {
|
|
3545
|
+
addWord(i);
|
|
3546
|
+
word_list.push({
|
|
3547
|
+
skip: true,
|
|
3548
|
+
to: 'next'
|
|
3549
|
+
});
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3284
3552
|
break;
|
|
3285
3553
|
|
|
3286
3554
|
case '|':
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
3555
|
+
if (!escNext) {
|
|
3556
|
+
addWord(i);
|
|
3557
|
+
word_list.push({
|
|
3558
|
+
skip: true,
|
|
3559
|
+
to: 'bar'
|
|
3560
|
+
});
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3292
3563
|
break;
|
|
3293
3564
|
|
|
3294
3565
|
case '~':
|
|
3295
|
-
|
|
3566
|
+
if (!escNext) {
|
|
3567
|
+
replace = true;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3296
3570
|
break;
|
|
3297
3571
|
}
|
|
3572
|
+
|
|
3573
|
+
escNext = words[i] === '\\';
|
|
3298
3574
|
}
|
|
3299
3575
|
|
|
3300
3576
|
var inSlur = false;
|
|
@@ -3678,15 +3954,16 @@ var bookParser = function bookParser(book) {
|
|
|
3678
3954
|
"use strict";
|
|
3679
3955
|
|
|
3680
3956
|
var directives = "";
|
|
3957
|
+
var initialWhiteSpace = book.match(/(\s*)/);
|
|
3681
3958
|
book = parseCommon.strip(book);
|
|
3682
3959
|
var tuneStrings = book.split("\nX:"); // Put back the X: that we lost when splitting the tunes.
|
|
3683
3960
|
|
|
3684
3961
|
for (var i = 1; i < tuneStrings.length; i++) {
|
|
3685
3962
|
tuneStrings[i] = "X:" + tuneStrings[i];
|
|
3686
|
-
} // Keep track of the character position each tune starts with.
|
|
3963
|
+
} // Keep track of the character position each tune starts with. If the string starts with white space, count that, too.
|
|
3687
3964
|
|
|
3688
3965
|
|
|
3689
|
-
var pos = 0;
|
|
3966
|
+
var pos = initialWhiteSpace ? initialWhiteSpace[0].length : 0;
|
|
3690
3967
|
var tunes = [];
|
|
3691
3968
|
parseCommon.each(tuneStrings, function (tune) {
|
|
3692
3969
|
tunes.push({
|
|
@@ -5709,7 +5986,7 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5709
5986
|
return [e - i + 1 + ws];
|
|
5710
5987
|
|
|
5711
5988
|
case "[K:":
|
|
5712
|
-
var result = parseKeyVoice.parseKey(line.substring(i + 3, e));
|
|
5989
|
+
var result = parseKeyVoice.parseKey(line.substring(i + 3, e), true);
|
|
5713
5990
|
if (result.foundClef && tuneBuilder.hasBeginMusic()) tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
|
|
5714
5991
|
if (result.foundKey && tuneBuilder.hasBeginMusic()) tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
|
|
5715
5992
|
return [e - i + 1 + ws];
|
|
@@ -5774,7 +6051,7 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5774
6051
|
return [line.length];
|
|
5775
6052
|
|
|
5776
6053
|
case "K:":
|
|
5777
|
-
var result = parseKeyVoice.parseKey(line.substring(i + 2));
|
|
6054
|
+
var result = parseKeyVoice.parseKey(line.substring(i + 2), tuneBuilder.hasBeginMusic());
|
|
5778
6055
|
if (result.foundClef && tuneBuilder.hasBeginMusic()) tuneBuilder.appendStartingElement('clef', multilineVars.iChar + i, multilineVars.iChar + line.length, multilineVars.clef);
|
|
5779
6056
|
if (result.foundKey && tuneBuilder.hasBeginMusic()) tuneBuilder.appendStartingElement('key', multilineVars.iChar + i, multilineVars.iChar + line.length, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
|
|
5780
6057
|
return [line.length];
|
|
@@ -5863,7 +6140,7 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5863
6140
|
case 'K':
|
|
5864
6141
|
// since the key is the last thing that can happen in the header, we can resolve the tempo now
|
|
5865
6142
|
this.resolveTempo();
|
|
5866
|
-
var result = parseKeyVoice.parseKey(line.substring(2));
|
|
6143
|
+
var result = parseKeyVoice.parseKey(line.substring(2), false);
|
|
5867
6144
|
|
|
5868
6145
|
if (!multilineVars.is_in_header && tuneBuilder.hasBeginMusic()) {
|
|
5869
6146
|
if (result.foundClef) tuneBuilder.appendStartingElement('clef', startChar, endChar, multilineVars.clef);
|
|
@@ -5979,179 +6256,7 @@ var parseKeyVoice = {};
|
|
|
5979
6256
|
};
|
|
5980
6257
|
|
|
5981
6258
|
parseKeyVoice.standardKey = function (keyName, root, acc, localTranspose) {
|
|
5982
|
-
|
|
5983
|
-
acc: 'sharp',
|
|
5984
|
-
note: 'f'
|
|
5985
|
-
};
|
|
5986
|
-
var key2sharp = {
|
|
5987
|
-
acc: 'sharp',
|
|
5988
|
-
note: 'c'
|
|
5989
|
-
};
|
|
5990
|
-
var key3sharp = {
|
|
5991
|
-
acc: 'sharp',
|
|
5992
|
-
note: 'g'
|
|
5993
|
-
};
|
|
5994
|
-
var key4sharp = {
|
|
5995
|
-
acc: 'sharp',
|
|
5996
|
-
note: 'd'
|
|
5997
|
-
};
|
|
5998
|
-
var key5sharp = {
|
|
5999
|
-
acc: 'sharp',
|
|
6000
|
-
note: 'A'
|
|
6001
|
-
};
|
|
6002
|
-
var key6sharp = {
|
|
6003
|
-
acc: 'sharp',
|
|
6004
|
-
note: 'e'
|
|
6005
|
-
};
|
|
6006
|
-
var key7sharp = {
|
|
6007
|
-
acc: 'sharp',
|
|
6008
|
-
note: 'B'
|
|
6009
|
-
};
|
|
6010
|
-
var key1flat = {
|
|
6011
|
-
acc: 'flat',
|
|
6012
|
-
note: 'B'
|
|
6013
|
-
};
|
|
6014
|
-
var key2flat = {
|
|
6015
|
-
acc: 'flat',
|
|
6016
|
-
note: 'e'
|
|
6017
|
-
};
|
|
6018
|
-
var key3flat = {
|
|
6019
|
-
acc: 'flat',
|
|
6020
|
-
note: 'A'
|
|
6021
|
-
};
|
|
6022
|
-
var key4flat = {
|
|
6023
|
-
acc: 'flat',
|
|
6024
|
-
note: 'd'
|
|
6025
|
-
};
|
|
6026
|
-
var key5flat = {
|
|
6027
|
-
acc: 'flat',
|
|
6028
|
-
note: 'G'
|
|
6029
|
-
};
|
|
6030
|
-
var key6flat = {
|
|
6031
|
-
acc: 'flat',
|
|
6032
|
-
note: 'c'
|
|
6033
|
-
};
|
|
6034
|
-
var key7flat = {
|
|
6035
|
-
acc: 'flat',
|
|
6036
|
-
note: 'F'
|
|
6037
|
-
};
|
|
6038
|
-
var keys = {
|
|
6039
|
-
'C#': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6040
|
-
'A#m': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6041
|
-
'G#Mix': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6042
|
-
'D#Dor': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6043
|
-
'E#Phr': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6044
|
-
'F#Lyd': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6045
|
-
'B#Loc': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6046
|
-
'F#': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
6047
|
-
'D#m': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
6048
|
-
'C#Mix': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
6049
|
-
'G#Dor': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
6050
|
-
'A#Phr': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
6051
|
-
'BLyd': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
6052
|
-
'E#Loc': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp],
|
|
6053
|
-
'B': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
6054
|
-
'G#m': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
6055
|
-
'F#Mix': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
6056
|
-
'C#Dor': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
6057
|
-
'D#Phr': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
6058
|
-
'ELyd': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
6059
|
-
'A#Loc': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp],
|
|
6060
|
-
'E': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
6061
|
-
'C#m': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
6062
|
-
'BMix': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
6063
|
-
'F#Dor': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
6064
|
-
'G#Phr': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
6065
|
-
'ALyd': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
6066
|
-
'D#Loc': [key1sharp, key2sharp, key3sharp, key4sharp],
|
|
6067
|
-
'A': [key1sharp, key2sharp, key3sharp],
|
|
6068
|
-
'F#m': [key1sharp, key2sharp, key3sharp],
|
|
6069
|
-
'EMix': [key1sharp, key2sharp, key3sharp],
|
|
6070
|
-
'BDor': [key1sharp, key2sharp, key3sharp],
|
|
6071
|
-
'C#Phr': [key1sharp, key2sharp, key3sharp],
|
|
6072
|
-
'DLyd': [key1sharp, key2sharp, key3sharp],
|
|
6073
|
-
'G#Loc': [key1sharp, key2sharp, key3sharp],
|
|
6074
|
-
'D': [key1sharp, key2sharp],
|
|
6075
|
-
'Bm': [key1sharp, key2sharp],
|
|
6076
|
-
'AMix': [key1sharp, key2sharp],
|
|
6077
|
-
'EDor': [key1sharp, key2sharp],
|
|
6078
|
-
'F#Phr': [key1sharp, key2sharp],
|
|
6079
|
-
'GLyd': [key1sharp, key2sharp],
|
|
6080
|
-
'C#Loc': [key1sharp, key2sharp],
|
|
6081
|
-
'G': [key1sharp],
|
|
6082
|
-
'Em': [key1sharp],
|
|
6083
|
-
'DMix': [key1sharp],
|
|
6084
|
-
'ADor': [key1sharp],
|
|
6085
|
-
'BPhr': [key1sharp],
|
|
6086
|
-
'CLyd': [key1sharp],
|
|
6087
|
-
'F#Loc': [key1sharp],
|
|
6088
|
-
'C': [],
|
|
6089
|
-
'Am': [],
|
|
6090
|
-
'GMix': [],
|
|
6091
|
-
'DDor': [],
|
|
6092
|
-
'EPhr': [],
|
|
6093
|
-
'FLyd': [],
|
|
6094
|
-
'BLoc': [],
|
|
6095
|
-
'F': [key1flat],
|
|
6096
|
-
'Dm': [key1flat],
|
|
6097
|
-
'CMix': [key1flat],
|
|
6098
|
-
'GDor': [key1flat],
|
|
6099
|
-
'APhr': [key1flat],
|
|
6100
|
-
'BbLyd': [key1flat],
|
|
6101
|
-
'ELoc': [key1flat],
|
|
6102
|
-
'Bb': [key1flat, key2flat],
|
|
6103
|
-
'Gm': [key1flat, key2flat],
|
|
6104
|
-
'FMix': [key1flat, key2flat],
|
|
6105
|
-
'CDor': [key1flat, key2flat],
|
|
6106
|
-
'DPhr': [key1flat, key2flat],
|
|
6107
|
-
'EbLyd': [key1flat, key2flat],
|
|
6108
|
-
'ALoc': [key1flat, key2flat],
|
|
6109
|
-
'Eb': [key1flat, key2flat, key3flat],
|
|
6110
|
-
'Cm': [key1flat, key2flat, key3flat],
|
|
6111
|
-
'BbMix': [key1flat, key2flat, key3flat],
|
|
6112
|
-
'FDor': [key1flat, key2flat, key3flat],
|
|
6113
|
-
'GPhr': [key1flat, key2flat, key3flat],
|
|
6114
|
-
'AbLyd': [key1flat, key2flat, key3flat],
|
|
6115
|
-
'DLoc': [key1flat, key2flat, key3flat],
|
|
6116
|
-
'Ab': [key1flat, key2flat, key3flat, key4flat],
|
|
6117
|
-
'Fm': [key1flat, key2flat, key3flat, key4flat],
|
|
6118
|
-
'EbMix': [key1flat, key2flat, key3flat, key4flat],
|
|
6119
|
-
'BbDor': [key1flat, key2flat, key3flat, key4flat],
|
|
6120
|
-
'CPhr': [key1flat, key2flat, key3flat, key4flat],
|
|
6121
|
-
'DbLyd': [key1flat, key2flat, key3flat, key4flat],
|
|
6122
|
-
'GLoc': [key1flat, key2flat, key3flat, key4flat],
|
|
6123
|
-
'Db': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
6124
|
-
'Bbm': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
6125
|
-
'AbMix': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
6126
|
-
'EbDor': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
6127
|
-
'FPhr': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
6128
|
-
'GbLyd': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
6129
|
-
'CLoc': [key1flat, key2flat, key3flat, key4flat, key5flat],
|
|
6130
|
-
'Gb': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
6131
|
-
'Ebm': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
6132
|
-
'DbMix': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
6133
|
-
'AbDor': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
6134
|
-
'BbPhr': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
6135
|
-
'CbLyd': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
6136
|
-
'FLoc': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat],
|
|
6137
|
-
'Cb': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
6138
|
-
'Abm': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
6139
|
-
'GbMix': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
6140
|
-
'DbDor': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
6141
|
-
'EbPhr': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
6142
|
-
'FbLyd': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
6143
|
-
'BbLoc': [key1flat, key2flat, key3flat, key4flat, key5flat, key6flat, key7flat],
|
|
6144
|
-
// The following are not in the 2.0 spec, but seem normal enough.
|
|
6145
|
-
// TODO-PER: These SOUND the same as what's written, but they aren't right
|
|
6146
|
-
'A#': [key1flat, key2flat],
|
|
6147
|
-
'B#': [],
|
|
6148
|
-
'D#': [key1flat, key2flat, key3flat],
|
|
6149
|
-
'E#': [key1flat],
|
|
6150
|
-
'G#': [key1flat, key2flat, key3flat, key4flat],
|
|
6151
|
-
'Gbm': [key1sharp, key2sharp, key3sharp, key4sharp, key5sharp, key6sharp, key7sharp],
|
|
6152
|
-
'none': []
|
|
6153
|
-
};
|
|
6154
|
-
return transpose.keySignature(multilineVars, keys, keyName, root, acc, localTranspose);
|
|
6259
|
+
return transpose.keySignature(multilineVars, keyName, root, acc, localTranspose);
|
|
6155
6260
|
};
|
|
6156
6261
|
|
|
6157
6262
|
var clefLines = {
|
|
@@ -6487,7 +6592,7 @@ var parseKeyVoice = {};
|
|
|
6487
6592
|
}
|
|
6488
6593
|
};
|
|
6489
6594
|
|
|
6490
|
-
parseKeyVoice.parseKey = function (str) // (and clef)
|
|
6595
|
+
parseKeyVoice.parseKey = function (str, isInline) // (and clef)
|
|
6491
6596
|
{
|
|
6492
6597
|
// returns:
|
|
6493
6598
|
// { foundClef: true, foundKey: true }
|
|
@@ -6605,8 +6710,12 @@ var parseKeyVoice = {};
|
|
|
6605
6710
|
|
|
6606
6711
|
var oldKey = parseKeyVoice.deepCopyKey(multilineVars.key); //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.
|
|
6607
6712
|
|
|
6608
|
-
var keyCompensate = multilineVars.globalTranspose ? -multilineVars.globalTranspose : 0;
|
|
6713
|
+
var keyCompensate = !isInline && multilineVars.globalTranspose ? -multilineVars.globalTranspose : 0; //console.log("parse", JSON.stringify(multilineVars), isInline)
|
|
6714
|
+
|
|
6715
|
+
var savedOrigKey;
|
|
6716
|
+
if (isInline) savedOrigKey = multilineVars.globalTransposeOrigKeySig;
|
|
6609
6717
|
multilineVars.key = parseKeyVoice.deepCopyKey(parseKeyVoice.standardKey(key, retPitch.token, acc, keyCompensate));
|
|
6718
|
+
if (isInline) multilineVars.globalTransposeOrigKeySig = savedOrigKey;
|
|
6610
6719
|
multilineVars.key.mode = mode;
|
|
6611
6720
|
|
|
6612
6721
|
if (oldKey) {
|
|
@@ -7542,7 +7651,7 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
7542
7651
|
}
|
|
7543
7652
|
|
|
7544
7653
|
multilineVars.addFormattingOptions(el, tune.formatting, 'bar');
|
|
7545
|
-
tuneBuilder.appendElement('bar', startOfLine +
|
|
7654
|
+
tuneBuilder.appendElement('bar', startOfLine + startI, startOfLine + i + ret[0], bar);
|
|
7546
7655
|
multilineVars.measureNotEmpty = false;
|
|
7547
7656
|
el = {};
|
|
7548
7657
|
}
|
|
@@ -7981,7 +8090,7 @@ function durationOfMeasure(multilineVars) {
|
|
|
7981
8090
|
|
|
7982
8091
|
var legalAccents = ["trill", "lowermordent", "uppermordent", "mordent", "pralltriller", "accent", "fermata", "invertedfermata", "tenuto", "0", "1", "2", "3", "4", "5", "+", "wedge", "open", "thumb", "snap", "turn", "roll", "breath", "shortphrase", "mediumphrase", "longphrase", "segno", "coda", "D.S.", "D.C.", "fine", "beambr1", "beambr2", "slide", "marcato", "upbow", "downbow", "/", "//", "///", "////", "trem1", "trem2", "trem3", "trem4", "turnx", "invertedturn", "invertedturnx", "trill(", "trill)", "arpeggio", "xstem", "mark", "umarcato", "style=normal", "style=harmonic", "style=rhythm", "style=x", "style=triangle"];
|
|
7983
8092
|
var volumeDecorations = ["p", "pp", "f", "ff", "mf", "mp", "ppp", "pppp", "fff", "ffff", "sfz"];
|
|
7984
|
-
var dynamicDecorations = ["crescendo(", "crescendo)", "diminuendo(", "diminuendo)"];
|
|
8093
|
+
var dynamicDecorations = ["crescendo(", "crescendo)", "diminuendo(", "diminuendo)", "glissando(", "glissando)"];
|
|
7985
8094
|
var accentPseudonyms = [["<", "accent"], [">", "accent"], ["tr", "trill"], ["plus", "+"], ["emphasis", "accent"], ["^", "umarcato"], ["marcato", "umarcato"]];
|
|
7986
8095
|
var accentDynamicPseudonyms = [["<(", "crescendo("], ["<)", "crescendo)"], [">(", "diminuendo("], [">)", "diminuendo)"]];
|
|
7987
8096
|
|
|
@@ -10039,6 +10148,12 @@ var Tokenizer = function Tokenizer(lines, multilineVars) {
|
|
|
10039
10148
|
value: parseFloat(num)
|
|
10040
10149
|
};
|
|
10041
10150
|
|
|
10151
|
+
case 'px':
|
|
10152
|
+
return {
|
|
10153
|
+
used: used + 1,
|
|
10154
|
+
value: parseFloat(num)
|
|
10155
|
+
};
|
|
10156
|
+
|
|
10042
10157
|
case 'cm':
|
|
10043
10158
|
return {
|
|
10044
10159
|
used: used + 1,
|
|
@@ -10058,17 +10173,11 @@ var Tokenizer = function Tokenizer(lines, multilineVars) {
|
|
|
10058
10173
|
value: parseFloat(num)
|
|
10059
10174
|
};
|
|
10060
10175
|
}
|
|
10061
|
-
|
|
10062
|
-
return {
|
|
10063
|
-
used: 0
|
|
10064
|
-
};
|
|
10065
10176
|
};
|
|
10066
10177
|
|
|
10067
10178
|
var substInChord = function substInChord(str) {
|
|
10068
|
-
|
|
10069
|
-
|
|
10070
|
-
}
|
|
10071
|
-
|
|
10179
|
+
str = str.replace(/\\n/g, "\n");
|
|
10180
|
+
str = str.replace(/\\"/g, '"');
|
|
10072
10181
|
return str;
|
|
10073
10182
|
};
|
|
10074
10183
|
|
|
@@ -10084,8 +10193,10 @@ var Tokenizer = function Tokenizer(lines, multilineVars) {
|
|
|
10084
10193
|
var matchChar = _matchChar || line.charAt(i);
|
|
10085
10194
|
|
|
10086
10195
|
var pos = i + 1;
|
|
10196
|
+
var esc = false;
|
|
10087
10197
|
|
|
10088
|
-
while (pos < line.length && line
|
|
10198
|
+
while (pos < line.length && (esc || line[pos] !== matchChar)) {
|
|
10199
|
+
esc = line[pos] === '\\';
|
|
10089
10200
|
++pos;
|
|
10090
10201
|
}
|
|
10091
10202
|
|
|
@@ -10124,9 +10235,15 @@ module.exports = Tokenizer;
|
|
|
10124
10235
|
/*!************************************!*\
|
|
10125
10236
|
!*** ./src/parse/abc_transpose.js ***!
|
|
10126
10237
|
\************************************/
|
|
10127
|
-
/***/ (function(module) {
|
|
10238
|
+
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
10128
10239
|
|
|
10129
10240
|
// abc_transpose.js: Handles the automatic transposition of key signatures, chord symbols, and notes.
|
|
10241
|
+
var allNotes = __webpack_require__(/*! ./all-notes */ "./src/parse/all-notes.js");
|
|
10242
|
+
|
|
10243
|
+
var transposeChordName = __webpack_require__(/*! ../parse/transpose-chord */ "./src/parse/transpose-chord.js");
|
|
10244
|
+
|
|
10245
|
+
var keyAccidentals = __webpack_require__(/*! ../const/key-accidentals */ "./src/const/key-accidentals.js");
|
|
10246
|
+
|
|
10130
10247
|
var transpose = {};
|
|
10131
10248
|
var keyIndex = {
|
|
10132
10249
|
'C': 0,
|
|
@@ -10150,16 +10267,16 @@ var keyIndex = {
|
|
|
10150
10267
|
var newKey = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'];
|
|
10151
10268
|
var newKeyMinor = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'];
|
|
10152
10269
|
|
|
10153
|
-
transpose.keySignature = function (multilineVars,
|
|
10154
|
-
if (multilineVars.clef.type === "perc") return {
|
|
10155
|
-
accidentals:
|
|
10270
|
+
transpose.keySignature = function (multilineVars, keyName, root, acc, localTranspose) {
|
|
10271
|
+
if (multilineVars.clef.type === "perc" || multilineVars.clef.type === "none") return {
|
|
10272
|
+
accidentals: keyAccidentals(keyName),
|
|
10156
10273
|
root: root,
|
|
10157
10274
|
acc: acc
|
|
10158
10275
|
};
|
|
10159
10276
|
if (!localTranspose) localTranspose = 0;
|
|
10160
10277
|
multilineVars.localTransposeVerticalMovement = 0;
|
|
10161
10278
|
multilineVars.localTransposePreferFlats = false;
|
|
10162
|
-
var k =
|
|
10279
|
+
var k = keyAccidentals(keyName);
|
|
10163
10280
|
if (!k) return multilineVars.key; // If the key isn't in the list, it is non-standard. We won't attempt to transpose it.
|
|
10164
10281
|
|
|
10165
10282
|
multilineVars.localTranspose = (multilineVars.globalTranspose ? multilineVars.globalTranspose : 0) + localTranspose;
|
|
@@ -10195,7 +10312,7 @@ transpose.keySignature = function (multilineVars, keys, keyName, root, acc, loca
|
|
|
10195
10312
|
if (index > 11) index = index % 12;
|
|
10196
10313
|
var newKeyName = keyName[0] === 'm' ? newKeyMinor[index] : newKey[index];
|
|
10197
10314
|
var transposedKey = newKeyName + keyName;
|
|
10198
|
-
var newKeySig =
|
|
10315
|
+
var newKeySig = keyAccidentals(transposedKey);
|
|
10199
10316
|
if (newKeySig.length > 0 && newKeySig[0].acc === 'flat') multilineVars.localTransposePreferFlats = true;
|
|
10200
10317
|
var distance = transposedKey.charCodeAt(0) - baseKey.charCodeAt(0);
|
|
10201
10318
|
|
|
@@ -10224,76 +10341,8 @@ transpose.keySignature = function (multilineVars, keys, keyName, root, acc, loca
|
|
|
10224
10341
|
};
|
|
10225
10342
|
};
|
|
10226
10343
|
|
|
10227
|
-
var sharpChords = ['C', 'C♯', 'D', "D♯", 'E', 'F', "F♯", 'G', 'G♯', 'A', 'A♯', 'B'];
|
|
10228
|
-
var flatChords = ['C', 'D♭', 'D', 'E♭', 'E', 'F', 'G♭', 'G', 'A♭', 'A', 'B♭', 'B'];
|
|
10229
|
-
var sharpChordsFree = ['C', 'C#', 'D', "D#", 'E', 'F', "F#", 'G', 'G#', 'A', 'A#', 'B'];
|
|
10230
|
-
var flatChordsFree = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
|
|
10231
|
-
|
|
10232
10344
|
transpose.chordName = function (multilineVars, chord) {
|
|
10233
|
-
|
|
10234
|
-
// The chords are the same if it is an exact octave change.
|
|
10235
|
-
var transposeFactor = multilineVars.localTranspose;
|
|
10236
|
-
|
|
10237
|
-
while (transposeFactor < 0) {
|
|
10238
|
-
transposeFactor += 12;
|
|
10239
|
-
}
|
|
10240
|
-
|
|
10241
|
-
if (transposeFactor > 11) transposeFactor = transposeFactor % 12;
|
|
10242
|
-
|
|
10243
|
-
if (multilineVars.freegchord) {
|
|
10244
|
-
chord = chord.replace(/Cb/g, "`~11`");
|
|
10245
|
-
chord = chord.replace(/Db/g, "`~1`");
|
|
10246
|
-
chord = chord.replace(/Eb/g, "`~3`");
|
|
10247
|
-
chord = chord.replace(/Fb/g, "`~4`");
|
|
10248
|
-
chord = chord.replace(/Gb/g, "`~6`");
|
|
10249
|
-
chord = chord.replace(/Ab/g, "`~8`");
|
|
10250
|
-
chord = chord.replace(/Bb/g, "`~10`");
|
|
10251
|
-
chord = chord.replace(/C#/g, "`~1`");
|
|
10252
|
-
chord = chord.replace(/D#/g, "`~3`");
|
|
10253
|
-
chord = chord.replace(/E#/g, "`~5`");
|
|
10254
|
-
chord = chord.replace(/F#/g, "`~6`");
|
|
10255
|
-
chord = chord.replace(/G#/g, "`~8`");
|
|
10256
|
-
chord = chord.replace(/A#/g, "`~10`");
|
|
10257
|
-
chord = chord.replace(/B#/g, "`~0`");
|
|
10258
|
-
} else {
|
|
10259
|
-
chord = chord.replace(/C♭/g, "`~11`");
|
|
10260
|
-
chord = chord.replace(/D♭/g, "`~1`");
|
|
10261
|
-
chord = chord.replace(/E♭/g, "`~3`");
|
|
10262
|
-
chord = chord.replace(/F♭/g, "`~4`");
|
|
10263
|
-
chord = chord.replace(/G♭/g, "`~6`");
|
|
10264
|
-
chord = chord.replace(/A♭/g, "`~8`");
|
|
10265
|
-
chord = chord.replace(/B♭/g, "`~10`");
|
|
10266
|
-
chord = chord.replace(/C♯/g, "`~1`");
|
|
10267
|
-
chord = chord.replace(/D♯/g, "`~3`");
|
|
10268
|
-
chord = chord.replace(/E♯/g, "`~5`");
|
|
10269
|
-
chord = chord.replace(/F♯/g, "`~6`");
|
|
10270
|
-
chord = chord.replace(/G♯/g, "`~8`");
|
|
10271
|
-
chord = chord.replace(/A♯/g, "`~10`");
|
|
10272
|
-
chord = chord.replace(/B♯/g, "`~0`");
|
|
10273
|
-
}
|
|
10274
|
-
|
|
10275
|
-
chord = chord.replace(/C/g, "`~0`");
|
|
10276
|
-
chord = chord.replace(/D/g, "`~2`");
|
|
10277
|
-
chord = chord.replace(/E/g, "`~4`");
|
|
10278
|
-
chord = chord.replace(/F/g, "`~5`");
|
|
10279
|
-
chord = chord.replace(/G/g, "`~7`");
|
|
10280
|
-
chord = chord.replace(/A/g, "`~9`");
|
|
10281
|
-
chord = chord.replace(/B/g, "`~11`");
|
|
10282
|
-
var arr = chord.split("`");
|
|
10283
|
-
|
|
10284
|
-
for (var i = 0; i < arr.length; i++) {
|
|
10285
|
-
if (arr[i][0] === '~') {
|
|
10286
|
-
var chordNum = parseInt(arr[i].substr(1), 10);
|
|
10287
|
-
chordNum += transposeFactor;
|
|
10288
|
-
if (chordNum > 11) chordNum -= 12;
|
|
10289
|
-
if (multilineVars.freegchord) arr[i] = multilineVars.localTransposePreferFlats ? flatChordsFree[chordNum] : sharpChordsFree[chordNum];else arr[i] = multilineVars.localTransposePreferFlats ? flatChords[chordNum] : sharpChords[chordNum];
|
|
10290
|
-
}
|
|
10291
|
-
}
|
|
10292
|
-
|
|
10293
|
-
chord = arr.join("");
|
|
10294
|
-
}
|
|
10295
|
-
|
|
10296
|
-
return chord;
|
|
10345
|
+
return transposeChordName(chord, multilineVars.localTranspose, multilineVars.localTransposePreferFlats, multilineVars.freegchord);
|
|
10297
10346
|
};
|
|
10298
10347
|
|
|
10299
10348
|
var pitchToLetter = ['c', 'd', 'e', 'f', 'g', 'a', 'b'];
|
|
@@ -10346,19 +10395,42 @@ var accidentals2 = {
|
|
|
10346
10395
|
"1": "sharp",
|
|
10347
10396
|
"2": "dblsharp"
|
|
10348
10397
|
};
|
|
10398
|
+
var accidentals3 = {
|
|
10399
|
+
"-2": "__",
|
|
10400
|
+
"-1": "_",
|
|
10401
|
+
"0": "=",
|
|
10402
|
+
"1": "^",
|
|
10403
|
+
"2": "^^"
|
|
10404
|
+
};
|
|
10405
|
+
var count = 0;
|
|
10349
10406
|
|
|
10350
10407
|
transpose.note = function (multilineVars, el) {
|
|
10351
|
-
// the "el" that is passed in has el.accidental, and el.pitch. "pitch" is the vertical position (0=middle C)
|
|
10408
|
+
// the "el" that is passed in has el.name, el.accidental, and el.pitch. "pitch" is the vertical position (0=middle C)
|
|
10352
10409
|
// localTranspose is the number of half steps
|
|
10353
10410
|
// localTransposeVerticalMovement is the vertical distance to move.
|
|
10411
|
+
//console.log(count++,multilineVars.localTranspose, el)
|
|
10354
10412
|
if (!multilineVars.localTranspose || multilineVars.clef.type === "perc") return;
|
|
10355
10413
|
var origPitch = el.pitch;
|
|
10356
|
-
|
|
10414
|
+
|
|
10415
|
+
if (multilineVars.localTransposeVerticalMovement) {
|
|
10416
|
+
el.pitch = el.pitch + multilineVars.localTransposeVerticalMovement;
|
|
10417
|
+
|
|
10418
|
+
if (el.name) {
|
|
10419
|
+
var actual = el.accidental ? el.name.substring(1) : el.name;
|
|
10420
|
+
var acc = el.accidental ? el.name[0] : '';
|
|
10421
|
+
var p = allNotes.pitchIndex(actual);
|
|
10422
|
+
el.name = acc + allNotes.noteName(p + multilineVars.localTransposeVerticalMovement);
|
|
10423
|
+
}
|
|
10424
|
+
}
|
|
10357
10425
|
|
|
10358
10426
|
if (el.accidental) {
|
|
10359
10427
|
var ret = accidentalChange(origPitch, el.pitch, el.accidental, multilineVars.globalTransposeOrigKeySig, multilineVars.targetKey);
|
|
10360
10428
|
el.pitch = ret[0];
|
|
10361
10429
|
el.accidental = accidentals2[ret[1]];
|
|
10430
|
+
|
|
10431
|
+
if (el.name) {
|
|
10432
|
+
el.name = accidentals3[ret[1]] + el.name.replace(/[_^=]/g, '');
|
|
10433
|
+
}
|
|
10362
10434
|
}
|
|
10363
10435
|
};
|
|
10364
10436
|
|
|
@@ -10366,6 +10438,104 @@ module.exports = transpose;
|
|
|
10366
10438
|
|
|
10367
10439
|
/***/ }),
|
|
10368
10440
|
|
|
10441
|
+
/***/ "./src/parse/all-notes.js":
|
|
10442
|
+
/*!********************************!*\
|
|
10443
|
+
!*** ./src/parse/all-notes.js ***!
|
|
10444
|
+
\********************************/
|
|
10445
|
+
/***/ (function(module) {
|
|
10446
|
+
|
|
10447
|
+
var allNotes = {};
|
|
10448
|
+
var allPitches = ['C,,,', 'D,,,', 'E,,,', 'F,,,', 'G,,,', 'A,,,', 'B,,,', 'C,,', 'D,,', 'E,,', 'F,,', 'G,,', 'A,,', 'B,,', 'C,', 'D,', 'E,', 'F,', 'G,', 'A,', 'B,', 'C', 'D', 'E', 'F', 'G', 'A', 'B', 'c', 'd', 'e', 'f', 'g', 'a', 'b', "c'", "d'", "e'", "f'", "g'", "a'", "b'", "c''", "d''", "e''", "f''", "g''", "a''", "b''", "c'''", "d'''", "e'''", "f'''", "g'''", "a'''", "b'''"];
|
|
10449
|
+
|
|
10450
|
+
allNotes.pitchIndex = function (noteName) {
|
|
10451
|
+
return allPitches.indexOf(noteName);
|
|
10452
|
+
};
|
|
10453
|
+
|
|
10454
|
+
allNotes.noteName = function (pitchIndex) {
|
|
10455
|
+
return allPitches[pitchIndex];
|
|
10456
|
+
};
|
|
10457
|
+
|
|
10458
|
+
module.exports = allNotes;
|
|
10459
|
+
|
|
10460
|
+
/***/ }),
|
|
10461
|
+
|
|
10462
|
+
/***/ "./src/parse/transpose-chord.js":
|
|
10463
|
+
/*!**************************************!*\
|
|
10464
|
+
!*** ./src/parse/transpose-chord.js ***!
|
|
10465
|
+
\**************************************/
|
|
10466
|
+
/***/ (function(module) {
|
|
10467
|
+
|
|
10468
|
+
var sharpChords = ['C', 'C♯', 'D', "D♯", 'E', 'F', "F♯", 'G', 'G♯', 'A', 'A♯', 'B'];
|
|
10469
|
+
var flatChords = ['C', 'D♭', 'D', 'E♭', 'E', 'F', 'G♭', 'G', 'A♭', 'A', 'B♭', 'B'];
|
|
10470
|
+
var sharpChordsFree = ['C', 'C#', 'D', "D#", 'E', 'F', "F#", 'G', 'G#', 'A', 'A#', 'B'];
|
|
10471
|
+
var flatChordsFree = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'];
|
|
10472
|
+
|
|
10473
|
+
function transposeChordName(chord, steps, preferFlats, freeGCchord) {
|
|
10474
|
+
if (!steps || steps % 12 === 0) // The chords are the same if it is an exact octave change.
|
|
10475
|
+
return chord; // There are two things in the chord that might need to be transposed:
|
|
10476
|
+
// The chord will start with a letter from A-G, and might have one accidental after it.
|
|
10477
|
+
// That accidental might be an actual sharp or flat char, or it might be a pound sign or lower case "b".
|
|
10478
|
+
// Then there is a bunch of stuff that isn't transposed and should just be copied. That is stuff like "7" and more complicated chords.
|
|
10479
|
+
// But there is one other exception: right after a slash there will be a bass note and possibly an accidental. That should also be transposed.
|
|
10480
|
+
|
|
10481
|
+
while (steps < 0) {
|
|
10482
|
+
steps += 12;
|
|
10483
|
+
}
|
|
10484
|
+
|
|
10485
|
+
if (steps > 11) steps = steps % 12; // (chord name w/accidental) (a bunch of stuff) (/) (bass note) (anything else)
|
|
10486
|
+
|
|
10487
|
+
var match = chord.match(/^([A-G][b#♭♯]?)([^\/]+)?\/?([A-G][b#♭♯]?)?(.+)?/);
|
|
10488
|
+
if (!match) return chord; // We don't recognize the format of the chord, so skip it.
|
|
10489
|
+
|
|
10490
|
+
var name = match[1];
|
|
10491
|
+
var extra1 = match[2];
|
|
10492
|
+
var bass = match[3];
|
|
10493
|
+
var extra2 = match[4];
|
|
10494
|
+
var index = sharpChords.indexOf(name);
|
|
10495
|
+
if (index < 0) index = flatChords.indexOf(name);
|
|
10496
|
+
if (index < 0) index = sharpChordsFree.indexOf(name);
|
|
10497
|
+
if (index < 0) index = flatChordsFree.indexOf(name);
|
|
10498
|
+
if (index < 0) return chord; // This should never happen, but if we can't find the chord just bail.
|
|
10499
|
+
|
|
10500
|
+
index += steps;
|
|
10501
|
+
index = index % 12;
|
|
10502
|
+
|
|
10503
|
+
if (preferFlats) {
|
|
10504
|
+
if (freeGCchord) chord = flatChordsFree[index];else chord = flatChords[index];
|
|
10505
|
+
} else {
|
|
10506
|
+
if (freeGCchord) chord = sharpChordsFree[index];else chord = sharpChords[index];
|
|
10507
|
+
}
|
|
10508
|
+
|
|
10509
|
+
if (extra1) chord += extra1;
|
|
10510
|
+
|
|
10511
|
+
if (bass) {
|
|
10512
|
+
var index = sharpChords.indexOf(bass);
|
|
10513
|
+
if (index < 0) index = flatChords.indexOf(bass);
|
|
10514
|
+
if (index < 0) index = sharpChordsFree.indexOf(bass);
|
|
10515
|
+
if (index < 0) index = flatChordsFree.indexOf(bass);
|
|
10516
|
+
chord += '/';
|
|
10517
|
+
|
|
10518
|
+
if (index >= 0) {
|
|
10519
|
+
index += steps;
|
|
10520
|
+
index = index % 12;
|
|
10521
|
+
|
|
10522
|
+
if (preferFlats) {
|
|
10523
|
+
if (freeGCchord) chord += flatChordsFree[index];else chord += flatChords[index];
|
|
10524
|
+
} else {
|
|
10525
|
+
if (freeGCchord) chord += sharpChordsFree[index];else chord += sharpChords[index];
|
|
10526
|
+
}
|
|
10527
|
+
} else chord += bass; // Don't know what to do so do nothing
|
|
10528
|
+
|
|
10529
|
+
}
|
|
10530
|
+
|
|
10531
|
+
if (extra2) chord += extra2;
|
|
10532
|
+
return chord;
|
|
10533
|
+
}
|
|
10534
|
+
|
|
10535
|
+
module.exports = transposeChordName;
|
|
10536
|
+
|
|
10537
|
+
/***/ }),
|
|
10538
|
+
|
|
10369
10539
|
/***/ "./src/parse/tune-builder.js":
|
|
10370
10540
|
/*!***********************************!*\
|
|
10371
10541
|
!*** ./src/parse/tune-builder.js ***!
|
|
@@ -11804,141 +11974,710 @@ function fixedMeasureLineBreaks(widths, lineBreakPoint, preferredMeasuresPerLine
|
|
|
11804
11974
|
var thisWidth = 0;
|
|
11805
11975
|
var failed = false;
|
|
11806
11976
|
|
|
11807
|
-
for (var i = 0; i < widths.length; i++) {
|
|
11808
|
-
thisWidth += widths[i];
|
|
11977
|
+
for (var i = 0; i < widths.length; i++) {
|
|
11978
|
+
thisWidth += widths[i];
|
|
11979
|
+
|
|
11980
|
+
if (thisWidth > lineBreakPoint) {
|
|
11981
|
+
failed = true;
|
|
11982
|
+
}
|
|
11983
|
+
|
|
11984
|
+
if (i % preferredMeasuresPerLine === preferredMeasuresPerLine - 1) {
|
|
11985
|
+
if (i !== widths.length - 1) // Don't bother putting a line break for the last line - it's already a break.
|
|
11986
|
+
lineBreaks.push(i);
|
|
11987
|
+
totals.push(Math.round(thisWidth));
|
|
11988
|
+
thisWidth = 0;
|
|
11989
|
+
}
|
|
11990
|
+
}
|
|
11991
|
+
|
|
11992
|
+
return {
|
|
11993
|
+
failed: failed,
|
|
11994
|
+
totals: totals,
|
|
11995
|
+
lineBreaks: lineBreaks
|
|
11996
|
+
};
|
|
11997
|
+
}
|
|
11998
|
+
|
|
11999
|
+
function getRevisedTuneParams(lineBreaks, staffWidth, params) {
|
|
12000
|
+
var revisedParams = {
|
|
12001
|
+
lineBreaks: lineBreaks,
|
|
12002
|
+
staffwidth: staffWidth
|
|
12003
|
+
};
|
|
12004
|
+
|
|
12005
|
+
for (var key in params) {
|
|
12006
|
+
if (params.hasOwnProperty(key) && key !== 'wrap' && key !== 'staffwidth') {
|
|
12007
|
+
revisedParams[key] = params[key];
|
|
12008
|
+
}
|
|
12009
|
+
}
|
|
12010
|
+
|
|
12011
|
+
return {
|
|
12012
|
+
revisedParams: revisedParams
|
|
12013
|
+
};
|
|
12014
|
+
}
|
|
12015
|
+
|
|
12016
|
+
function calcLineWraps(tune, widths, params) {
|
|
12017
|
+
// For calculating how much can go on the line, it depends on the width of the line. It is a convenience to just divide it here
|
|
12018
|
+
// by the minimum spacing instead of multiplying the min spacing later.
|
|
12019
|
+
// The scaling works differently: this is done by changing the scaling of the outer SVG, so the scaling needs to be compensated
|
|
12020
|
+
// for here, because the actual width will be different from the calculated numbers.
|
|
12021
|
+
// If the desired width is less than the margin, just punt and return the original tune
|
|
12022
|
+
//console.log(widths)
|
|
12023
|
+
if (widths.length === 0 || params.staffwidth < widths[0].left) {
|
|
12024
|
+
return {
|
|
12025
|
+
reParse: false,
|
|
12026
|
+
explanation: "Staff width is narrower than the margin",
|
|
12027
|
+
revisedParams: params
|
|
12028
|
+
};
|
|
12029
|
+
}
|
|
12030
|
+
|
|
12031
|
+
var scale = params.scale ? Math.max(params.scale, 0.1) : 1;
|
|
12032
|
+
var minSpacing = params.wrap.minSpacing ? Math.max(parseFloat(params.wrap.minSpacing), 1) : 1;
|
|
12033
|
+
var minSpacingLimit = params.wrap.minSpacingLimit ? Math.max(parseFloat(params.wrap.minSpacingLimit), 1) : minSpacing - 0.1;
|
|
12034
|
+
var maxSpacing = params.wrap.maxSpacing ? Math.max(parseFloat(params.wrap.maxSpacing), 1) : undefined;
|
|
12035
|
+
if (params.wrap.lastLineLimit && !maxSpacing) maxSpacing = Math.max(parseFloat(params.wrap.lastLineLimit), 1); // var targetHeight = params.wrap.targetHeight ? Math.max(parseInt(params.wrap.targetHeight, 10), 100) : undefined;
|
|
12036
|
+
|
|
12037
|
+
var preferredMeasuresPerLine = params.wrap.preferredMeasuresPerLine ? Math.max(parseInt(params.wrap.preferredMeasuresPerLine, 10), 0) : undefined;
|
|
12038
|
+
var accumulatedLineBreaks = [];
|
|
12039
|
+
var explanations = [];
|
|
12040
|
+
|
|
12041
|
+
for (var s = 0; s < widths.length; s++) {
|
|
12042
|
+
var section = widths[s];
|
|
12043
|
+
var usableWidth = params.staffwidth - section.left;
|
|
12044
|
+
var lineBreakPoint = usableWidth / minSpacing / scale;
|
|
12045
|
+
var minLineSize = usableWidth / maxSpacing / scale;
|
|
12046
|
+
var allowableVariance = usableWidth / minSpacingLimit / scale;
|
|
12047
|
+
var explanation = {
|
|
12048
|
+
widths: section,
|
|
12049
|
+
lineBreakPoint: lineBreakPoint,
|
|
12050
|
+
minLineSize: minLineSize,
|
|
12051
|
+
attempts: [],
|
|
12052
|
+
staffWidth: params.staffwidth,
|
|
12053
|
+
minWidth: Math.round(allowableVariance)
|
|
12054
|
+
}; // If there is a preferred number of measures per line, test that first. If none of the lines is too long, then we're finished.
|
|
12055
|
+
|
|
12056
|
+
var lineBreaks = null;
|
|
12057
|
+
|
|
12058
|
+
if (preferredMeasuresPerLine) {
|
|
12059
|
+
var f = fixedMeasureLineBreaks(section.measureWidths, lineBreakPoint, preferredMeasuresPerLine);
|
|
12060
|
+
explanation.attempts.push({
|
|
12061
|
+
type: "Fixed Measures Per Line",
|
|
12062
|
+
preferredMeasuresPerLine: preferredMeasuresPerLine,
|
|
12063
|
+
lineBreaks: f.lineBreaks,
|
|
12064
|
+
failed: f.failed,
|
|
12065
|
+
totals: f.totals
|
|
12066
|
+
});
|
|
12067
|
+
if (!f.failed) lineBreaks = f.lineBreaks;
|
|
12068
|
+
} // If we don't have lineBreaks yet, use the free form method of line breaks.
|
|
12069
|
+
// This will be called either if Preferred Measures is not used, or if the music is just weird - like a single measure is way too crowded.
|
|
12070
|
+
|
|
12071
|
+
|
|
12072
|
+
if (!lineBreaks) {
|
|
12073
|
+
var ff = freeFormLineBreaks(section.measureWidths, lineBreakPoint);
|
|
12074
|
+
explanation.attempts.push({
|
|
12075
|
+
type: "Free Form",
|
|
12076
|
+
lineBreaks: ff.lineBreaks,
|
|
12077
|
+
totals: ff.totals
|
|
12078
|
+
});
|
|
12079
|
+
lineBreaks = ff.lineBreaks; // We now have an acceptable number of lines, but the measures may not be optimally distributed. See if there is a better distribution.
|
|
12080
|
+
|
|
12081
|
+
if (lineBreaks.length > 0 && section.measureWidths.length < 25) {
|
|
12082
|
+
// Only do this if everything doesn't fit on one line.
|
|
12083
|
+
// This is an intensive operation and it is optional so just do it for shorter music.
|
|
12084
|
+
ff = optimizeLineWidths(section, lineBreakPoint, lineBreaks, explanation);
|
|
12085
|
+
explanation.attempts.push({
|
|
12086
|
+
type: "Optimize",
|
|
12087
|
+
failed: ff.failed,
|
|
12088
|
+
reason: ff.reason,
|
|
12089
|
+
lineBreaks: ff.lineBreaks,
|
|
12090
|
+
totals: ff.totals
|
|
12091
|
+
});
|
|
12092
|
+
if (!ff.failed) lineBreaks = ff.lineBreaks;
|
|
12093
|
+
}
|
|
12094
|
+
}
|
|
12095
|
+
|
|
12096
|
+
accumulatedLineBreaks.push(lineBreaks);
|
|
12097
|
+
explanations.push(explanation);
|
|
12098
|
+
} // If the vertical space exceeds targetHeight, remove a line and try again. If that is too crowded, then don't use it.
|
|
12099
|
+
|
|
12100
|
+
|
|
12101
|
+
var staffWidth = params.staffwidth;
|
|
12102
|
+
var ret = getRevisedTuneParams(accumulatedLineBreaks, staffWidth, params);
|
|
12103
|
+
ret.explanation = explanations;
|
|
12104
|
+
ret.reParse = true;
|
|
12105
|
+
return ret;
|
|
12106
|
+
}
|
|
12107
|
+
|
|
12108
|
+
module.exports = {
|
|
12109
|
+
wrapLines: wrapLines,
|
|
12110
|
+
calcLineWraps: calcLineWraps
|
|
12111
|
+
};
|
|
12112
|
+
|
|
12113
|
+
/***/ }),
|
|
12114
|
+
|
|
12115
|
+
/***/ "./src/str/output.js":
|
|
12116
|
+
/*!***************************!*\
|
|
12117
|
+
!*** ./src/str/output.js ***!
|
|
12118
|
+
\***************************/
|
|
12119
|
+
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
12120
|
+
|
|
12121
|
+
var keyAccidentals = __webpack_require__(/*! ../const/key-accidentals */ "./src/const/key-accidentals.js");
|
|
12122
|
+
|
|
12123
|
+
var _require = __webpack_require__(/*! ../const/relative-major */ "./src/const/relative-major.js"),
|
|
12124
|
+
relativeMajor = _require.relativeMajor,
|
|
12125
|
+
transposeKey = _require.transposeKey,
|
|
12126
|
+
relativeMode = _require.relativeMode;
|
|
12127
|
+
|
|
12128
|
+
var transposeChordName = __webpack_require__(/*! ../parse/transpose-chord */ "./src/parse/transpose-chord.js");
|
|
12129
|
+
|
|
12130
|
+
var strTranspose;
|
|
12131
|
+
|
|
12132
|
+
(function () {
|
|
12133
|
+
"use strict";
|
|
12134
|
+
|
|
12135
|
+
strTranspose = function strTranspose(abc, abcTune, steps) {
|
|
12136
|
+
if (abcTune === "TEST") // Backdoor way to get entry points for unit tests
|
|
12137
|
+
return {
|
|
12138
|
+
keyAccidentals: keyAccidentals,
|
|
12139
|
+
relativeMajor: relativeMajor,
|
|
12140
|
+
transposeKey: transposeKey,
|
|
12141
|
+
relativeMode: relativeMode,
|
|
12142
|
+
transposeChordName: transposeChordName
|
|
12143
|
+
};
|
|
12144
|
+
steps = parseInt(steps, 10);
|
|
12145
|
+
var changes = [];
|
|
12146
|
+
var i;
|
|
12147
|
+
|
|
12148
|
+
for (i = 0; i < abcTune.length; i++) {
|
|
12149
|
+
changes = changes.concat(transposeOneTune(abc, abcTune[i], steps));
|
|
12150
|
+
} // Reverse sort so that we are replacing strings from the end to the beginning so that the indexes aren't invalidated as we go.
|
|
12151
|
+
// (Because voices can be written in different ways we can't count on the notes being encountered in the order they appear in the string.)
|
|
12152
|
+
|
|
12153
|
+
|
|
12154
|
+
changes = changes.sort(function (a, b) {
|
|
12155
|
+
return b.start - a.start;
|
|
12156
|
+
});
|
|
12157
|
+
var output = abc.split('');
|
|
12158
|
+
|
|
12159
|
+
for (i = 0; i < changes.length; i++) {
|
|
12160
|
+
var ch = changes[i];
|
|
12161
|
+
output.splice(ch.start, ch.end - ch.start, ch.note);
|
|
12162
|
+
}
|
|
12163
|
+
|
|
12164
|
+
return output.join('');
|
|
12165
|
+
};
|
|
12166
|
+
|
|
12167
|
+
function transposeOneTune(abc, abcTune, steps) {
|
|
12168
|
+
var changes = []; // Don't transpose bagpipe music - that is a special case and is always a particular key
|
|
12169
|
+
|
|
12170
|
+
var key = abcTune.getKeySignature();
|
|
12171
|
+
if (key.root === 'Hp' || key.root === "HP") return changes;
|
|
12172
|
+
changes = changes.concat(changeAllKeySigs(abc, steps));
|
|
12173
|
+
|
|
12174
|
+
for (var i = 0; i < abcTune.lines.length; i++) {
|
|
12175
|
+
var staves = abcTune.lines[i].staff;
|
|
12176
|
+
|
|
12177
|
+
if (staves) {
|
|
12178
|
+
for (var j = 0; j < staves.length; j++) {
|
|
12179
|
+
var staff = staves[j];
|
|
12180
|
+
if (staff.clef.type !== "perc") changes = changes.concat(transposeVoices(abc, staff.voices, staff.key, steps));
|
|
12181
|
+
}
|
|
12182
|
+
}
|
|
12183
|
+
}
|
|
12184
|
+
|
|
12185
|
+
return changes;
|
|
12186
|
+
}
|
|
12187
|
+
|
|
12188
|
+
function changeAllKeySigs(abc, steps) {
|
|
12189
|
+
var changes = [];
|
|
12190
|
+
var arr = abc.split("K:"); // now each line except the first one will start with whatever is right after "K:"
|
|
12191
|
+
|
|
12192
|
+
var count = arr[0].length;
|
|
12193
|
+
|
|
12194
|
+
for (var i = 1; i < arr.length; i++) {
|
|
12195
|
+
var segment = arr[i];
|
|
12196
|
+
var match = segment.match(/^( *)([A-G])([#b]?)(\w*)/);
|
|
12197
|
+
|
|
12198
|
+
if (match) {
|
|
12199
|
+
var start = count + 2 + match[1].length; // move past the 'K:' and optional white space
|
|
12200
|
+
|
|
12201
|
+
var key = match[2] + match[3] + match[4]; // key name, accidental, and mode
|
|
12202
|
+
|
|
12203
|
+
var destinationKey = newKey({
|
|
12204
|
+
root: match[2],
|
|
12205
|
+
acc: match[3],
|
|
12206
|
+
mode: match[4]
|
|
12207
|
+
}, steps);
|
|
12208
|
+
var dest = destinationKey.root + destinationKey.acc + destinationKey.mode;
|
|
12209
|
+
changes.push({
|
|
12210
|
+
start: start,
|
|
12211
|
+
end: start + key.length,
|
|
12212
|
+
note: dest
|
|
12213
|
+
});
|
|
12214
|
+
}
|
|
12215
|
+
|
|
12216
|
+
count += segment.length + 2;
|
|
12217
|
+
}
|
|
12218
|
+
|
|
12219
|
+
return changes;
|
|
12220
|
+
}
|
|
12221
|
+
|
|
12222
|
+
function transposeVoices(abc, voices, key, steps) {
|
|
12223
|
+
var changes = [];
|
|
12224
|
+
var destinationKey = newKey(key, steps);
|
|
12225
|
+
|
|
12226
|
+
for (var i = 0; i < voices.length; i++) {
|
|
12227
|
+
changes = changes.concat(transposeVoice(abc, voices[i], key.root, createKeyAccidentals(key), destinationKey, steps));
|
|
12228
|
+
}
|
|
12229
|
+
|
|
12230
|
+
return changes;
|
|
12231
|
+
}
|
|
12232
|
+
|
|
12233
|
+
function createKeyAccidentals(key) {
|
|
12234
|
+
var ret = {};
|
|
12235
|
+
|
|
12236
|
+
for (var i = 0; i < key.accidentals.length; i++) {
|
|
12237
|
+
var acc = key.accidentals[i];
|
|
12238
|
+
if (acc.acc === 'flat') ret[acc.note.toUpperCase()] = '_';else if (acc.acc === 'sharp') ret[acc.note.toUpperCase()] = '^';
|
|
12239
|
+
}
|
|
12240
|
+
|
|
12241
|
+
return ret;
|
|
12242
|
+
}
|
|
12243
|
+
|
|
12244
|
+
function setLetterDistance(destinationKey, keyRoot, steps) {
|
|
12245
|
+
var letterDistance = letters.indexOf(destinationKey.root) - letters.indexOf(keyRoot);
|
|
12246
|
+
if (keyRoot === "none") letterDistance = letters.indexOf(destinationKey.root);
|
|
12247
|
+
|
|
12248
|
+
if (letterDistance === 0) {
|
|
12249
|
+
// This could either be a half step (like Eb => E) or almost an octave (like E => Eb)
|
|
12250
|
+
if (steps > 2) // If it is a large leap, then we are going up an octave
|
|
12251
|
+
letterDistance += 7;else if (steps === -12) // If it is a large leap, then we are going down an octave
|
|
12252
|
+
letterDistance -= 7;
|
|
12253
|
+
} else if (steps > 0 && letterDistance < 0) letterDistance += 7;else if (steps < 0 && letterDistance > 0) letterDistance -= 7;
|
|
12254
|
+
|
|
12255
|
+
if (steps > 12) letterDistance += 7;else if (steps < -12) letterDistance -= 7;
|
|
12256
|
+
return letterDistance;
|
|
12257
|
+
}
|
|
12258
|
+
|
|
12259
|
+
function transposeVoice(abc, voice, keyRoot, keyAccidentals, destinationKey, steps) {
|
|
12260
|
+
var changes = [];
|
|
12261
|
+
var letterDistance = setLetterDistance(destinationKey, keyRoot, steps);
|
|
12262
|
+
var measureAccidentals = {};
|
|
12263
|
+
var transposedMeasureAccidentals = {};
|
|
12264
|
+
|
|
12265
|
+
for (var i = 0; i < voice.length; i++) {
|
|
12266
|
+
var el = voice[i];
|
|
12267
|
+
|
|
12268
|
+
if (el.chord) {
|
|
12269
|
+
for (var c = 0; c < el.chord.length; c++) {
|
|
12270
|
+
var ch = el.chord[c];
|
|
12271
|
+
|
|
12272
|
+
if (ch.position === 'default') {
|
|
12273
|
+
var prefersFlats = destinationKey.accidentals.length && destinationKey.accidentals[0].acc === 'flat';
|
|
12274
|
+
var newChord = transposeChordName(ch.name, steps, prefersFlats, true);
|
|
12275
|
+
newChord = newChord.replace(/♭/g, "b").replace(/♯/g, "#");
|
|
12276
|
+
if (newChord !== ch.name) // If we didn't recognize the chord the input is returned unchanged and there is nothing to replace
|
|
12277
|
+
changes.push(replaceChord(abc, el.startChar, el.endChar, newChord));
|
|
12278
|
+
}
|
|
12279
|
+
}
|
|
12280
|
+
}
|
|
12281
|
+
|
|
12282
|
+
if (el.el_type === 'note' && el.pitches) {
|
|
12283
|
+
for (var j = 0; j < el.pitches.length; j++) {
|
|
12284
|
+
var note = parseNote(el.pitches[j].name, keyRoot, keyAccidentals, measureAccidentals);
|
|
12285
|
+
if (note.acc) measureAccidentals[note.name.toUpperCase()] = note.acc;
|
|
12286
|
+
var newPitch = transposePitch(note, destinationKey, letterDistance, transposedMeasureAccidentals);
|
|
12287
|
+
if (newPitch.acc) transposedMeasureAccidentals[newPitch.upper] = newPitch.acc;
|
|
12288
|
+
changes.push(replaceNote(abc, el.startChar, el.endChar, newPitch.acc + newPitch.name, j));
|
|
12289
|
+
}
|
|
12290
|
+
|
|
12291
|
+
if (el.gracenotes) {
|
|
12292
|
+
for (var g = 0; g < el.gracenotes.length; g++) {
|
|
12293
|
+
var grace = parseNote(el.gracenotes[g].name, keyRoot, keyAccidentals, measureAccidentals);
|
|
12294
|
+
if (grace.acc) measureAccidentals[grace.name.toUpperCase()] = grace.acc;
|
|
12295
|
+
var newGrace = transposePitch(grace, destinationKey, letterDistance, measureAccidentals);
|
|
12296
|
+
if (newGrace.acc) transposedMeasureAccidentals[newGrace.upper] = newGrace.acc;
|
|
12297
|
+
changes.push(replaceGrace(abc, el.startChar, el.endChar, newGrace.acc + newGrace.name, g));
|
|
12298
|
+
}
|
|
12299
|
+
}
|
|
12300
|
+
} else if (el.el_type === "bar") {
|
|
12301
|
+
measureAccidentals = {};
|
|
12302
|
+
transposedMeasureAccidentals = {};
|
|
12303
|
+
} else if (el.el_type === "keySignature") {
|
|
12304
|
+
keyRoot = el.root;
|
|
12305
|
+
keyAccidentals = createKeyAccidentals(el);
|
|
12306
|
+
destinationKey = newKey(el, steps);
|
|
12307
|
+
letterDistance = setLetterDistance(destinationKey, keyRoot, steps);
|
|
12308
|
+
}
|
|
12309
|
+
}
|
|
12310
|
+
|
|
12311
|
+
return changes;
|
|
12312
|
+
}
|
|
12313
|
+
|
|
12314
|
+
var letters = "CDEFGAB";
|
|
12315
|
+
var octaves = [",,,,", ",,,", ",,", ",", "", "'", "''", "'''", "''''"];
|
|
12316
|
+
|
|
12317
|
+
function newKey(key, steps) {
|
|
12318
|
+
if (key.root === "none") {
|
|
12319
|
+
return {
|
|
12320
|
+
root: transposeKey("C", steps),
|
|
12321
|
+
mode: "",
|
|
12322
|
+
acc: "",
|
|
12323
|
+
accidentals: []
|
|
12324
|
+
};
|
|
12325
|
+
}
|
|
12326
|
+
|
|
12327
|
+
var major = relativeMajor(key.root + key.acc + key.mode);
|
|
12328
|
+
var newMajor = transposeKey(major, steps);
|
|
12329
|
+
var newMode = relativeMode(newMajor, key.mode);
|
|
12330
|
+
var acc = keyAccidentals(newMajor);
|
|
12331
|
+
return {
|
|
12332
|
+
root: newMode[0],
|
|
12333
|
+
mode: key.mode,
|
|
12334
|
+
acc: newMode.length > 1 ? newMode[1] : '',
|
|
12335
|
+
accidentals: acc
|
|
12336
|
+
};
|
|
12337
|
+
}
|
|
12338
|
+
|
|
12339
|
+
function transposePitch(note, key, letterDistance, measureAccidentals) {
|
|
12340
|
+
// Depending on what the current note and new note are, the octave might have changed
|
|
12341
|
+
// The letterDistance is how far the change is to see if we passed "C" when transposing.
|
|
12342
|
+
var pitch = note.pitch;
|
|
12343
|
+
var origDistFromC = letters.indexOf(note.name);
|
|
12344
|
+
var root = letters.indexOf(key.root);
|
|
12345
|
+
var index = (root + pitch) % 7; // if the note crosses "c" then the octave changes, so that is true of "B" when going up one step, "A" and "B" when going up two steps, etc., and reverse when going down.
|
|
12346
|
+
|
|
12347
|
+
var newDistFromC = origDistFromC + letterDistance;
|
|
12348
|
+
var oct = note.oct;
|
|
12349
|
+
|
|
12350
|
+
while (newDistFromC > 6) {
|
|
12351
|
+
oct++;
|
|
12352
|
+
newDistFromC -= 7;
|
|
12353
|
+
}
|
|
12354
|
+
|
|
12355
|
+
while (newDistFromC < 0) {
|
|
12356
|
+
oct--;
|
|
12357
|
+
newDistFromC += 7;
|
|
12358
|
+
}
|
|
12359
|
+
|
|
12360
|
+
var name = letters[index];
|
|
12361
|
+
var acc = '';
|
|
12362
|
+
var adj = note.adj; // the amount of adjustment depends on the key - if there is a sharp in the key sig, then -1 is a natural, if there isn't, then -1 is a flat.
|
|
12363
|
+
|
|
12364
|
+
var keyAcc = '=';
|
|
12365
|
+
|
|
12366
|
+
for (var i = 0; i < key.accidentals.length; i++) {
|
|
12367
|
+
if (key.accidentals[i].note.toLowerCase() === name.toLowerCase()) {
|
|
12368
|
+
adj = adj + (key.accidentals[i].acc === 'flat' ? -1 : 1);
|
|
12369
|
+
keyAcc = key.accidentals[i].acc === 'flat' ? '_' : '^';
|
|
12370
|
+
break;
|
|
12371
|
+
}
|
|
12372
|
+
}
|
|
12373
|
+
|
|
12374
|
+
switch (adj) {
|
|
12375
|
+
case -2:
|
|
12376
|
+
acc = "__";
|
|
12377
|
+
break;
|
|
12378
|
+
|
|
12379
|
+
case -1:
|
|
12380
|
+
acc = "_";
|
|
12381
|
+
break;
|
|
12382
|
+
|
|
12383
|
+
case 0:
|
|
12384
|
+
acc = "=";
|
|
12385
|
+
break;
|
|
12386
|
+
|
|
12387
|
+
case 1:
|
|
12388
|
+
acc = "^";
|
|
12389
|
+
break;
|
|
12390
|
+
|
|
12391
|
+
case 2:
|
|
12392
|
+
acc = "^^";
|
|
12393
|
+
break;
|
|
12394
|
+
|
|
12395
|
+
case -3:
|
|
12396
|
+
// This requires a triple flat, so bump down the pitch and try again
|
|
12397
|
+
var newNote = {};
|
|
12398
|
+
newNote.pitch = note.pitch - 1;
|
|
12399
|
+
newNote.oct = note.oct;
|
|
12400
|
+
newNote.name = letters[letters.indexOf(note.name) - 1];
|
|
12401
|
+
|
|
12402
|
+
if (!newNote.name) {
|
|
12403
|
+
newNote.name = "B";
|
|
12404
|
+
newNote.oct--;
|
|
12405
|
+
}
|
|
12406
|
+
|
|
12407
|
+
if (newNote.name === "B" || newNote.name === "E") newNote.adj = note.adj + 1;else newNote.adj = note.adj + 2;
|
|
12408
|
+
return transposePitch(newNote, key, letterDistance + 1, measureAccidentals);
|
|
12409
|
+
|
|
12410
|
+
case 3:
|
|
12411
|
+
// This requires a triple sharp, so bump up the pitch and try again
|
|
12412
|
+
var newNote = {};
|
|
12413
|
+
newNote.pitch = note.pitch + 1;
|
|
12414
|
+
newNote.oct = note.oct;
|
|
12415
|
+
newNote.name = letters[letters.indexOf(note.name) + 1];
|
|
12416
|
+
|
|
12417
|
+
if (!newNote.name) {
|
|
12418
|
+
newNote.name = "C";
|
|
12419
|
+
newNote.oct++;
|
|
12420
|
+
}
|
|
12421
|
+
|
|
12422
|
+
if (newNote.name === "C" || newNote.name === "F") newNote.adj = note.adj - 1;else newNote.adj = note.adj - 2;
|
|
12423
|
+
return transposePitch(newNote, key, letterDistance + 1, measureAccidentals);
|
|
12424
|
+
}
|
|
12425
|
+
|
|
12426
|
+
if ((measureAccidentals[name] === acc || !measureAccidentals[name] && acc === keyAcc) && !note.courtesy) acc = "";
|
|
12427
|
+
|
|
12428
|
+
switch (oct) {
|
|
12429
|
+
case 0:
|
|
12430
|
+
name = name + ",,,";
|
|
12431
|
+
break;
|
|
12432
|
+
|
|
12433
|
+
case 1:
|
|
12434
|
+
name = name + ",,";
|
|
12435
|
+
break;
|
|
12436
|
+
|
|
12437
|
+
case 2:
|
|
12438
|
+
name = name + ",";
|
|
12439
|
+
break;
|
|
12440
|
+
// case 3: it is already correct
|
|
12441
|
+
|
|
12442
|
+
case 4:
|
|
12443
|
+
name = name.toLowerCase();
|
|
12444
|
+
break;
|
|
12445
|
+
|
|
12446
|
+
case 5:
|
|
12447
|
+
name = name.toLowerCase() + "'";
|
|
12448
|
+
break;
|
|
12449
|
+
|
|
12450
|
+
case 6:
|
|
12451
|
+
name = name.toLowerCase() + "''";
|
|
12452
|
+
break;
|
|
12453
|
+
|
|
12454
|
+
case 7:
|
|
12455
|
+
name = name.toLowerCase() + "'''";
|
|
12456
|
+
break;
|
|
12457
|
+
|
|
12458
|
+
case 8:
|
|
12459
|
+
name = name.toLowerCase() + "''''";
|
|
12460
|
+
break;
|
|
12461
|
+
}
|
|
12462
|
+
|
|
12463
|
+
if (oct > 4) name = name.toLowerCase();
|
|
12464
|
+
return {
|
|
12465
|
+
acc: acc,
|
|
12466
|
+
name: name,
|
|
12467
|
+
upper: name.toUpperCase()
|
|
12468
|
+
};
|
|
12469
|
+
}
|
|
12470
|
+
|
|
12471
|
+
var regPitch = /([_^=]*)([A-Ga-g])([,']*)/;
|
|
12472
|
+
var regNote = /([_^=]*[A-Ga-g][,']*)(\d*\/*\d*)([\>\<\-\)\.\s\\]*)/;
|
|
12473
|
+
var regOptionalNote = /([_^=]*[A-Ga-g][,']*)?(\d*\/*\d*)?([\>\<\-\)]*)?/;
|
|
12474
|
+
var regSpace = /(\s*)$/; // This the relationship of the note to the tonic and an octave. So what is returned is a distance in steps from the tonic and the amount of adjustment from
|
|
12475
|
+
// a normal scale. That is - in the key of D an F# is two steps from the tonic and no adjustment. A G# is three steps from the tonic and one half-step higher.
|
|
12476
|
+
// I don't think there is any adjustment needed for minor keys since the adjustment is based on the key signature and the accidentals.
|
|
12477
|
+
|
|
12478
|
+
function parseNote(note, keyRoot, keyAccidentals, measureAccidentals) {
|
|
12479
|
+
var root = keyRoot === "none" ? 0 : letters.indexOf(keyRoot);
|
|
12480
|
+
var reg = note.match(regPitch); // reg[1] : "__", "_", "", "=", "^", or "^^"
|
|
12481
|
+
// reg[2] : A-G a-g
|
|
12482
|
+
// reg[3] : commas or apostrophes
|
|
12483
|
+
|
|
12484
|
+
var name = reg[2].toUpperCase();
|
|
12485
|
+
var pos = letters.indexOf(name) - root;
|
|
12486
|
+
if (pos < 0) pos += 7;
|
|
12487
|
+
var oct = octaves.indexOf(reg[3]);
|
|
12488
|
+
if (name === reg[2]) // See if it is a capital letter and subtract an octave if so.
|
|
12489
|
+
oct--;
|
|
12490
|
+
var currentAcc = measureAccidentals[name] || keyAccidentals[name] || "="; // use the key accidentals if they exist, but override with the measure accidentals, and if neither of them exist, use a natural.
|
|
12491
|
+
|
|
12492
|
+
return {
|
|
12493
|
+
acc: reg[1],
|
|
12494
|
+
name: name,
|
|
12495
|
+
pitch: pos,
|
|
12496
|
+
oct: oct,
|
|
12497
|
+
adj: calcAdjustment(reg[1], keyAccidentals[name], measureAccidentals[name]),
|
|
12498
|
+
courtesy: reg[1] === currentAcc
|
|
12499
|
+
};
|
|
12500
|
+
}
|
|
12501
|
+
|
|
12502
|
+
function replaceNote(abc, start, end, newPitch, index) {
|
|
12503
|
+
// There may be more than just the note between the start and end - there could be spaces, there could be a chord symbol, there could be a decoration.
|
|
12504
|
+
// This could also be a part of a chord. If so, then the particular note needs to be teased out.
|
|
12505
|
+
var note = abc.substring(start, end);
|
|
12506
|
+
var match = note.match(new RegExp(regNote.source + regSpace.source), '');
|
|
12507
|
+
|
|
12508
|
+
if (match) {
|
|
12509
|
+
// This will match a single note
|
|
12510
|
+
var noteLen = match[1].length;
|
|
12511
|
+
var trailingLen = match[2].length + match[3].length + match[4].length;
|
|
12512
|
+
var leadingLen = end - start - noteLen - trailingLen;
|
|
12513
|
+
start += leadingLen;
|
|
12514
|
+
end -= trailingLen;
|
|
12515
|
+
} else {
|
|
12516
|
+
// I don't know how to capture more than one note, so I'm separating them. There is a limit of the number of notes in a chord depending on the repeats I have here, but it is unlikely to happen in real music.
|
|
12517
|
+
var regPreBracket = /([^\[]*)/;
|
|
12518
|
+
var regOpenBracket = /\[/;
|
|
12519
|
+
var regCloseBracket = /\-?](\d*\/*\d*)?([\>\<\-\)]*)/;
|
|
12520
|
+
match = note.match(new RegExp(regPreBracket.source + regOpenBracket.source + regOptionalNote.source + regOptionalNote.source + regOptionalNote.source + regOptionalNote.source + regOptionalNote.source + regOptionalNote.source + regOptionalNote.source + regOptionalNote.source + regCloseBracket.source + regSpace.source));
|
|
12521
|
+
|
|
12522
|
+
if (match) {
|
|
12523
|
+
// This will match a chord
|
|
12524
|
+
// Get the number of chars used by the previous notes in this chord
|
|
12525
|
+
var count = 1 + match[1].length; // one character for the open bracket
|
|
12526
|
+
|
|
12527
|
+
for (var i = 0; i < index; i++) {
|
|
12528
|
+
// index is the iteration through the chord. This function gets called for each one.
|
|
12529
|
+
if (match[i * 3 + 2]) count += match[i * 3 + 2].length;
|
|
12530
|
+
if (match[i * 3 + 3]) count += match[i * 3 + 3].length;
|
|
12531
|
+
if (match[i * 3 + 4]) count += match[i * 3 + 4].length;
|
|
12532
|
+
}
|
|
12533
|
+
|
|
12534
|
+
start += count;
|
|
12535
|
+
var endLen = match[index * 3 + 2] ? match[index * 3 + 2].length : 0; // endLen += match[index * 3 + 3] ? match[index * 3 + 3].length : 0
|
|
12536
|
+
// endLen += match[index * 3 + 4] ? match[index * 3 + 4].length : 0
|
|
11809
12537
|
|
|
11810
|
-
|
|
11811
|
-
|
|
12538
|
+
end = start + endLen;
|
|
12539
|
+
}
|
|
11812
12540
|
}
|
|
11813
12541
|
|
|
11814
|
-
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
}
|
|
12542
|
+
return {
|
|
12543
|
+
start: start,
|
|
12544
|
+
end: end,
|
|
12545
|
+
note: newPitch
|
|
12546
|
+
};
|
|
11820
12547
|
}
|
|
11821
12548
|
|
|
11822
|
-
|
|
11823
|
-
|
|
11824
|
-
totals: totals,
|
|
11825
|
-
lineBreaks: lineBreaks
|
|
11826
|
-
};
|
|
11827
|
-
}
|
|
12549
|
+
function replaceGrace(abc, start, end, newGrace, index) {
|
|
12550
|
+
var note = abc.substring(start, end); // I don't know how to capture more than one note, so I'm separating them. There is a limit of the number of notes in a chord depending on the repeats I have here, but it is unlikely to happen in real music.
|
|
11828
12551
|
|
|
11829
|
-
|
|
11830
|
-
|
|
11831
|
-
|
|
11832
|
-
|
|
11833
|
-
|
|
12552
|
+
var regOpenBrace = /\{/;
|
|
12553
|
+
var regCloseBrace = /\}/;
|
|
12554
|
+
var regPreBrace = /([^\{]*)/;
|
|
12555
|
+
var regPreNote = /(\/*)/;
|
|
12556
|
+
var match = note.match(new RegExp(regPreBrace.source + regOpenBrace.source + regPreNote.source + regOptionalNote.source + regPreNote.source + regOptionalNote.source + regPreNote.source + regOptionalNote.source + regPreNote.source + regOptionalNote.source + regPreNote.source + regOptionalNote.source + regPreNote.source + regOptionalNote.source + regPreNote.source + regOptionalNote.source + regPreNote.source + regOptionalNote.source + regCloseBrace.source));
|
|
11834
12557
|
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
12558
|
+
if (match) {
|
|
12559
|
+
// This will match all notes inside a grace symbol
|
|
12560
|
+
// Get the number of chars used by the previous graces
|
|
12561
|
+
var count = 1 + match[1].length; // one character for the open brace, and whatever comes before the brace
|
|
12562
|
+
|
|
12563
|
+
for (var i = 0; i < index; i++) {
|
|
12564
|
+
// index is the iteration through the chord. This function gets called for each one.
|
|
12565
|
+
if (match[i * 3 + 2]) count += match[i * 3 + 2].length;
|
|
12566
|
+
if (match[i * 3 + 3]) count += match[i * 3 + 3].length;
|
|
12567
|
+
if (match[i * 3 + 4]) count += match[i * 3 + 4].length;
|
|
12568
|
+
if (match[i * 3 + 5]) count += match[i * 3 + 5].length;
|
|
12569
|
+
}
|
|
12570
|
+
|
|
12571
|
+
if (match[index * 3 + 2]) count += match[i * 3 + 2].length;
|
|
12572
|
+
start += count;
|
|
12573
|
+
var endLen = match[index * 3 + 3] ? match[index * 3 + 3].length : 0;
|
|
12574
|
+
endLen += match[index * 3 + 4] ? match[index * 3 + 4].length : 0;
|
|
12575
|
+
endLen += match[index * 3 + 5] ? match[index * 3 + 5].length : 0;
|
|
12576
|
+
end = start + endLen;
|
|
11838
12577
|
}
|
|
12578
|
+
|
|
12579
|
+
return {
|
|
12580
|
+
start: start,
|
|
12581
|
+
end: end,
|
|
12582
|
+
note: newGrace
|
|
12583
|
+
};
|
|
11839
12584
|
}
|
|
11840
12585
|
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
12586
|
+
function replaceChord(abc, start, end, newChord) {
|
|
12587
|
+
// Isolate the chord and just replace that
|
|
12588
|
+
var match = abc.substring(start, end).match(/([^"]+)?(".+")+/);
|
|
12589
|
+
if (match[1]) start += match[1].length;
|
|
12590
|
+
end = start + match[2].length; // leave the quote in, so skip one more
|
|
11845
12591
|
|
|
11846
|
-
function calcLineWraps(tune, widths, params) {
|
|
11847
|
-
// For calculating how much can go on the line, it depends on the width of the line. It is a convenience to just divide it here
|
|
11848
|
-
// by the minimum spacing instead of multiplying the min spacing later.
|
|
11849
|
-
// The scaling works differently: this is done by changing the scaling of the outer SVG, so the scaling needs to be compensated
|
|
11850
|
-
// for here, because the actual width will be different from the calculated numbers.
|
|
11851
|
-
// If the desired width is less than the margin, just punt and return the original tune
|
|
11852
|
-
//console.log(widths)
|
|
11853
|
-
if (widths.length === 0 || params.staffwidth < widths[0].left) {
|
|
11854
12592
|
return {
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
12593
|
+
start: start + 1,
|
|
12594
|
+
end: end - 1,
|
|
12595
|
+
note: newChord
|
|
11858
12596
|
};
|
|
11859
12597
|
}
|
|
11860
12598
|
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
12599
|
+
function calcAdjustment(thisAccidental, keyAccidental, measureAccidental) {
|
|
12600
|
+
if (!thisAccidental && measureAccidental) {
|
|
12601
|
+
// There was no accidental on this note, but there was earlier in the measure, so we'll use that
|
|
12602
|
+
thisAccidental = measureAccidental;
|
|
12603
|
+
}
|
|
11866
12604
|
|
|
11867
|
-
|
|
11868
|
-
var accumulatedLineBreaks = [];
|
|
11869
|
-
var explanations = [];
|
|
12605
|
+
if (!thisAccidental) return 0; // there is no deviation from the key.
|
|
11870
12606
|
|
|
11871
|
-
|
|
11872
|
-
|
|
11873
|
-
|
|
11874
|
-
|
|
11875
|
-
|
|
11876
|
-
var allowableVariance = usableWidth / minSpacingLimit / scale;
|
|
11877
|
-
var explanation = {
|
|
11878
|
-
widths: section,
|
|
11879
|
-
lineBreakPoint: lineBreakPoint,
|
|
11880
|
-
minLineSize: minLineSize,
|
|
11881
|
-
attempts: [],
|
|
11882
|
-
staffWidth: params.staffwidth,
|
|
11883
|
-
minWidth: Math.round(allowableVariance)
|
|
11884
|
-
}; // If there is a preferred number of measures per line, test that first. If none of the lines is too long, then we're finished.
|
|
12607
|
+
switch (keyAccidental) {
|
|
12608
|
+
case undefined:
|
|
12609
|
+
switch (thisAccidental) {
|
|
12610
|
+
case '__':
|
|
12611
|
+
return -2;
|
|
11885
12612
|
|
|
11886
|
-
|
|
12613
|
+
case '_':
|
|
12614
|
+
return -1;
|
|
11887
12615
|
|
|
11888
|
-
|
|
11889
|
-
|
|
11890
|
-
explanation.attempts.push({
|
|
11891
|
-
type: "Fixed Measures Per Line",
|
|
11892
|
-
preferredMeasuresPerLine: preferredMeasuresPerLine,
|
|
11893
|
-
lineBreaks: f.lineBreaks,
|
|
11894
|
-
failed: f.failed,
|
|
11895
|
-
totals: f.totals
|
|
11896
|
-
});
|
|
11897
|
-
if (!f.failed) lineBreaks = f.lineBreaks;
|
|
11898
|
-
} // If we don't have lineBreaks yet, use the free form method of line breaks.
|
|
11899
|
-
// This will be called either if Preferred Measures is not used, or if the music is just weird - like a single measure is way too crowded.
|
|
12616
|
+
case '=':
|
|
12617
|
+
return 0;
|
|
11900
12618
|
|
|
12619
|
+
case '^':
|
|
12620
|
+
return 1;
|
|
11901
12621
|
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
explanation.attempts.push({
|
|
11905
|
-
type: "Free Form",
|
|
11906
|
-
lineBreaks: ff.lineBreaks,
|
|
11907
|
-
totals: ff.totals
|
|
11908
|
-
});
|
|
11909
|
-
lineBreaks = ff.lineBreaks; // We now have an acceptable number of lines, but the measures may not be optimally distributed. See if there is a better distribution.
|
|
12622
|
+
case '^^':
|
|
12623
|
+
return 2;
|
|
11910
12624
|
|
|
11911
|
-
|
|
11912
|
-
|
|
11913
|
-
|
|
11914
|
-
|
|
11915
|
-
explanation.attempts.push({
|
|
11916
|
-
type: "Optimize",
|
|
11917
|
-
failed: ff.failed,
|
|
11918
|
-
reason: ff.reason,
|
|
11919
|
-
lineBreaks: ff.lineBreaks,
|
|
11920
|
-
totals: ff.totals
|
|
11921
|
-
});
|
|
11922
|
-
if (!ff.failed) lineBreaks = ff.lineBreaks;
|
|
11923
|
-
}
|
|
11924
|
-
}
|
|
12625
|
+
default:
|
|
12626
|
+
return 0;
|
|
12627
|
+
// this should never happen
|
|
12628
|
+
}
|
|
11925
12629
|
|
|
11926
|
-
|
|
11927
|
-
|
|
11928
|
-
|
|
12630
|
+
case '_':
|
|
12631
|
+
switch (thisAccidental) {
|
|
12632
|
+
case '__':
|
|
12633
|
+
return -1;
|
|
11929
12634
|
|
|
12635
|
+
case '_':
|
|
12636
|
+
return 0;
|
|
11930
12637
|
|
|
11931
|
-
|
|
11932
|
-
|
|
11933
|
-
ret.explanation = explanations;
|
|
11934
|
-
ret.reParse = true;
|
|
11935
|
-
return ret;
|
|
11936
|
-
}
|
|
12638
|
+
case '=':
|
|
12639
|
+
return 1;
|
|
11937
12640
|
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11941
|
-
|
|
12641
|
+
case '^':
|
|
12642
|
+
return 2;
|
|
12643
|
+
|
|
12644
|
+
case '^^':
|
|
12645
|
+
return 3;
|
|
12646
|
+
|
|
12647
|
+
default:
|
|
12648
|
+
return 0;
|
|
12649
|
+
// this should never happen
|
|
12650
|
+
}
|
|
12651
|
+
|
|
12652
|
+
case '^':
|
|
12653
|
+
switch (thisAccidental) {
|
|
12654
|
+
case '__':
|
|
12655
|
+
return -3;
|
|
12656
|
+
|
|
12657
|
+
case '_':
|
|
12658
|
+
return -2;
|
|
12659
|
+
|
|
12660
|
+
case '=':
|
|
12661
|
+
return -1;
|
|
12662
|
+
|
|
12663
|
+
case '^':
|
|
12664
|
+
return 0;
|
|
12665
|
+
|
|
12666
|
+
case '^^':
|
|
12667
|
+
return 1;
|
|
12668
|
+
|
|
12669
|
+
default:
|
|
12670
|
+
return 0;
|
|
12671
|
+
// this should never happen
|
|
12672
|
+
}
|
|
12673
|
+
|
|
12674
|
+
}
|
|
12675
|
+
|
|
12676
|
+
return 0; // this should never happen
|
|
12677
|
+
}
|
|
12678
|
+
})();
|
|
12679
|
+
|
|
12680
|
+
module.exports = strTranspose;
|
|
11942
12681
|
|
|
11943
12682
|
/***/ }),
|
|
11944
12683
|
|
|
@@ -12719,7 +13458,9 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
|
|
|
12719
13458
|
volume: velocity,
|
|
12720
13459
|
start: timeToRealTime(elem.time),
|
|
12721
13460
|
duration: durationRounded(note.duration),
|
|
12722
|
-
instrument: currentInstrument
|
|
13461
|
+
instrument: currentInstrument,
|
|
13462
|
+
startChar: elem.elem.startChar,
|
|
13463
|
+
endChar: elem.elem.endChar
|
|
12723
13464
|
};
|
|
12724
13465
|
p = adjustForMicroTone(p);
|
|
12725
13466
|
|
|
@@ -14792,6 +15533,8 @@ var createNoteMap = function createNoteMap(sequence) {
|
|
|
14792
15533
|
end: Math.round((ev.start + len - gap) * 1000000) / 1000000,
|
|
14793
15534
|
volume: ev.volume
|
|
14794
15535
|
};
|
|
15536
|
+
if (ev.startChar) obj.startChar = ev.startChar;
|
|
15537
|
+
if (ev.endChar) obj.endChar = ev.endChar;
|
|
14795
15538
|
if (ev.style) obj.style = ev.style;
|
|
14796
15539
|
if (ev.cents) obj.cents = ev.cents;
|
|
14797
15540
|
map[i].push(obj);
|
|
@@ -16138,8 +16881,8 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
|
|
|
16138
16881
|
var fnResolve;
|
|
16139
16882
|
|
|
16140
16883
|
offlineCtx.oncomplete = function (e) {
|
|
16141
|
-
if (e.renderedBuffer) {
|
|
16142
|
-
// If the system gets overloaded then this can start failing. Just drop the note if so.
|
|
16884
|
+
if (e.renderedBuffer && e.renderedBuffer.getChannelData) {
|
|
16885
|
+
// If the system gets overloaded or there are network problems then this can start failing. Just drop the note if so.
|
|
16143
16886
|
for (var i = 0; i < startArray.length; i++) {
|
|
16144
16887
|
//Math.floor(startArray[i] * sound.tempoMultiplier * sampleRate)
|
|
16145
16888
|
var start = startArray[i] * sound.tempoMultiplier;
|
|
@@ -19302,6 +20045,15 @@ AbstractEngraver.prototype.createBeam = function (isSingleLineStaff, voice, elem
|
|
|
19302
20045
|
if (hint) beamelem.setHint();
|
|
19303
20046
|
|
|
19304
20047
|
for (var i = 0; i < elems.length; i++) {
|
|
20048
|
+
// Do a first pass to figure out the stem direction before creating the notes, so that staccatos and other decorations can be placed correctly.
|
|
20049
|
+
beamelem.runningDirection(elems[i]);
|
|
20050
|
+
}
|
|
20051
|
+
|
|
20052
|
+
beamelem.setStemDirection();
|
|
20053
|
+
var tempStemDir = this.stemdir;
|
|
20054
|
+
this.stemdir = beamelem.stemsUp ? 'up' : 'down';
|
|
20055
|
+
|
|
20056
|
+
for (i = 0; i < elems.length; i++) {
|
|
19305
20057
|
var elem = elems[i];
|
|
19306
20058
|
var abselem = this.createNote(elem, true, isSingleLineStaff, voice);
|
|
19307
20059
|
abselemset.push(abselem);
|
|
@@ -19316,6 +20068,7 @@ AbstractEngraver.prototype.createBeam = function (isSingleLineStaff, voice, elem
|
|
|
19316
20068
|
|
|
19317
20069
|
beamelem.calcDir();
|
|
19318
20070
|
voice.addBeam(beamelem);
|
|
20071
|
+
this.stemdir = tempStemDir;
|
|
19319
20072
|
return abselemset;
|
|
19320
20073
|
};
|
|
19321
20074
|
|
|
@@ -19861,6 +20614,7 @@ AbstractEngraver.prototype.addSlursAndTies = function (abselem, pitchelem, noteh
|
|
|
19861
20614
|
for (var j = 0; j < this.ties.length; j++) {
|
|
19862
20615
|
if (this.ties[j].anchor1 && this.ties[j].anchor1.pitch === notehead.pitch) {
|
|
19863
20616
|
this.ties[j].setEndAnchor(notehead);
|
|
20617
|
+
voice.setRange(this.ties[j]);
|
|
19864
20618
|
this.ties.splice(j, 1);
|
|
19865
20619
|
found = true;
|
|
19866
20620
|
break;
|
|
@@ -19869,6 +20623,7 @@ AbstractEngraver.prototype.addSlursAndTies = function (abselem, pitchelem, noteh
|
|
|
19869
20623
|
|
|
19870
20624
|
if (!found) {
|
|
19871
20625
|
this.ties[0].setEndAnchor(notehead);
|
|
20626
|
+
voice.setRange(this.ties[0]);
|
|
19872
20627
|
this.ties.splice(0, 1);
|
|
19873
20628
|
}
|
|
19874
20629
|
}
|
|
@@ -19904,6 +20659,7 @@ AbstractEngraver.prototype.addSlursAndTies = function (abselem, pitchelem, noteh
|
|
|
19904
20659
|
if (this.slurs[slurid]) {
|
|
19905
20660
|
slur = this.slurs[slurid];
|
|
19906
20661
|
slur.setEndAnchor(notehead);
|
|
20662
|
+
voice.setRange(slur);
|
|
19907
20663
|
delete this.slurs[slurid];
|
|
19908
20664
|
} else {
|
|
19909
20665
|
slur = new TieElem({
|
|
@@ -20058,6 +20814,11 @@ AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff)
|
|
|
20058
20814
|
|
|
20059
20815
|
|
|
20060
20816
|
abselem.extraw -= 5;
|
|
20817
|
+
|
|
20818
|
+
if (elem.chord !== undefined) {
|
|
20819
|
+
var ret3 = addChord(this.getTextSize, abselem, elem, 0, 0, 0, false);
|
|
20820
|
+
}
|
|
20821
|
+
|
|
20061
20822
|
return abselem;
|
|
20062
20823
|
};
|
|
20063
20824
|
|
|
@@ -20116,6 +20877,15 @@ BeamElem.prototype.setHint = function () {
|
|
|
20116
20877
|
this.hint = true;
|
|
20117
20878
|
};
|
|
20118
20879
|
|
|
20880
|
+
BeamElem.prototype.runningDirection = function (abcelem) {
|
|
20881
|
+
var pitch = abcelem.averagepitch;
|
|
20882
|
+
if (pitch === undefined) return; // don't include elements like spacers in beams
|
|
20883
|
+
|
|
20884
|
+
this.total = Math.round(this.total + pitch);
|
|
20885
|
+
if (!this.count) this.count = 0;
|
|
20886
|
+
this.count++;
|
|
20887
|
+
};
|
|
20888
|
+
|
|
20119
20889
|
BeamElem.prototype.add = function (abselem) {
|
|
20120
20890
|
var pitch = abselem.abcelem.averagepitch;
|
|
20121
20891
|
if (pitch === undefined) return; // don't include elements like spacers in beams
|
|
@@ -20138,6 +20908,24 @@ BeamElem.prototype.addBeam = function (beam) {
|
|
|
20138
20908
|
this.beams.push(beam);
|
|
20139
20909
|
};
|
|
20140
20910
|
|
|
20911
|
+
BeamElem.prototype.setStemDirection = function () {
|
|
20912
|
+
// Have to figure this out before the notes are placed because placing the notes also places the decorations.
|
|
20913
|
+
this.average = calcAverage(this.total, this.count);
|
|
20914
|
+
|
|
20915
|
+
if (this.forceup) {
|
|
20916
|
+
this.stemsUp = true;
|
|
20917
|
+
} else if (this.forcedown) {
|
|
20918
|
+
this.stemsUp = false;
|
|
20919
|
+
} else {
|
|
20920
|
+
var middleLine = 6; // hardcoded 6 is B
|
|
20921
|
+
|
|
20922
|
+
this.stemsUp = this.average < middleLine; // true is up, false is down;
|
|
20923
|
+
}
|
|
20924
|
+
|
|
20925
|
+
delete this.count;
|
|
20926
|
+
this.total = 0;
|
|
20927
|
+
};
|
|
20928
|
+
|
|
20141
20929
|
BeamElem.prototype.calcDir = function () {
|
|
20142
20930
|
this.average = calcAverage(this.total, this.elems.length);
|
|
20143
20931
|
|
|
@@ -20706,6 +21494,8 @@ var DynamicDecoration = __webpack_require__(/*! ./abc_dynamic_decoration */ "./s
|
|
|
20706
21494
|
|
|
20707
21495
|
var CrescendoElem = __webpack_require__(/*! ./abc_crescendo_element */ "./src/write/abc_crescendo_element.js");
|
|
20708
21496
|
|
|
21497
|
+
var GlissandoElem = __webpack_require__(/*! ./abc_glissando_element */ "./src/write/abc_glissando_element.js");
|
|
21498
|
+
|
|
20709
21499
|
var glyphs = __webpack_require__(/*! ./abc_glyphs */ "./src/write/abc_glyphs.js");
|
|
20710
21500
|
|
|
20711
21501
|
var RelativeElement = __webpack_require__(/*! ./abc_relative_element */ "./src/write/abc_relative_element.js");
|
|
@@ -21022,6 +21812,7 @@ function leftDecoration(decoration, abselem, roomtaken) {
|
|
|
21022
21812
|
Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, positioning) {
|
|
21023
21813
|
var diminuendo;
|
|
21024
21814
|
var crescendo;
|
|
21815
|
+
var glissando;
|
|
21025
21816
|
|
|
21026
21817
|
for (var i = 0; i < decoration.length; i++) {
|
|
21027
21818
|
switch (decoration[i]) {
|
|
@@ -21050,6 +21841,19 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
|
|
|
21050
21841
|
};
|
|
21051
21842
|
this.startCrescendoX = undefined;
|
|
21052
21843
|
break;
|
|
21844
|
+
|
|
21845
|
+
case "glissando(":
|
|
21846
|
+
this.startGlissandoX = abselem;
|
|
21847
|
+
glissando = undefined;
|
|
21848
|
+
break;
|
|
21849
|
+
|
|
21850
|
+
case "glissando)":
|
|
21851
|
+
glissando = {
|
|
21852
|
+
start: this.startGlissandoX,
|
|
21853
|
+
stop: abselem
|
|
21854
|
+
};
|
|
21855
|
+
this.startGlissandoX = undefined;
|
|
21856
|
+
break;
|
|
21053
21857
|
}
|
|
21054
21858
|
}
|
|
21055
21859
|
|
|
@@ -21060,6 +21864,10 @@ Decoration.prototype.dynamicDecoration = function (voice, decoration, abselem, p
|
|
|
21060
21864
|
if (crescendo) {
|
|
21061
21865
|
voice.addOther(new CrescendoElem(crescendo.start, crescendo.stop, "<", positioning));
|
|
21062
21866
|
}
|
|
21867
|
+
|
|
21868
|
+
if (glissando) {
|
|
21869
|
+
voice.addOther(new GlissandoElem(glissando.start, glissando.stop));
|
|
21870
|
+
}
|
|
21063
21871
|
};
|
|
21064
21872
|
|
|
21065
21873
|
Decoration.prototype.createDecoration = function (voice, decoration, pitch, width, abselem, roomtaken, dir, minPitch, positioning, hasVocals) {
|
|
@@ -21426,6 +22234,23 @@ module.exports = EngraverController;
|
|
|
21426
22234
|
|
|
21427
22235
|
/***/ }),
|
|
21428
22236
|
|
|
22237
|
+
/***/ "./src/write/abc_glissando_element.js":
|
|
22238
|
+
/*!********************************************!*\
|
|
22239
|
+
!*** ./src/write/abc_glissando_element.js ***!
|
|
22240
|
+
\********************************************/
|
|
22241
|
+
/***/ (function(module) {
|
|
22242
|
+
|
|
22243
|
+
var GlissandoElem = function GlissandoElem(anchor1, anchor2) {
|
|
22244
|
+
this.type = "GlissandoElem";
|
|
22245
|
+
this.anchor1 = anchor1; // must have a .x and a .parent property or be null (means starts at the "beginning" of the line - after keysig)
|
|
22246
|
+
|
|
22247
|
+
this.anchor2 = anchor2; // must have a .x property or be null (means ends at the end of the line)
|
|
22248
|
+
};
|
|
22249
|
+
|
|
22250
|
+
module.exports = GlissandoElem;
|
|
22251
|
+
|
|
22252
|
+
/***/ }),
|
|
22253
|
+
|
|
21429
22254
|
/***/ "./src/write/abc_glyphs.js":
|
|
21430
22255
|
/*!*********************************!*\
|
|
21431
22256
|
!*** ./src/write/abc_glyphs.js ***!
|
|
@@ -22663,6 +23488,17 @@ TieElem.prototype.addInternalNote = function (note) {
|
|
|
22663
23488
|
TieElem.prototype.setEndAnchor = function (anchor2) {
|
|
22664
23489
|
// console.log("end", this.anchor1 ? this.anchor1.pitch : "N/A", anchor2 ? anchor2.pitch : "N/A", this.isTie, this.isGrace);
|
|
22665
23490
|
this.anchor2 = anchor2; // must have a .x and a .pitch property or be null (means ends at the end of the line)
|
|
23491
|
+
// we don't really have enough info to know what the vertical extent is yet and we won't until drawing. This will just give it enough
|
|
23492
|
+
// room on either side (we don't even know if the slur will be above yet). We need to set this so that we can make sure the voice has
|
|
23493
|
+
// at least enough room that the line doesn't get cut off if the tie or slur is the lowest thing.
|
|
23494
|
+
|
|
23495
|
+
if (this.anchor1) {
|
|
23496
|
+
this.top = Math.max(this.anchor1.pitch, this.anchor2.pitch) + 4;
|
|
23497
|
+
this.bottom = Math.min(this.anchor1.pitch, this.anchor2.pitch) - 4;
|
|
23498
|
+
} else {
|
|
23499
|
+
this.top = this.anchor2.pitch + 4;
|
|
23500
|
+
this.bottom = this.anchor2.pitch - 4;
|
|
23501
|
+
}
|
|
22666
23502
|
}; // If we encounter a repeat sign, then we don't want to extend either a tie or a slur past it, so these are called to be a limit.
|
|
22667
23503
|
|
|
22668
23504
|
|
|
@@ -23899,6 +24735,107 @@ module.exports = drawEnding;
|
|
|
23899
24735
|
|
|
23900
24736
|
/***/ }),
|
|
23901
24737
|
|
|
24738
|
+
/***/ "./src/write/draw/glissando.js":
|
|
24739
|
+
/*!*************************************!*\
|
|
24740
|
+
!*** ./src/write/draw/glissando.js ***!
|
|
24741
|
+
\*************************************/
|
|
24742
|
+
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
24743
|
+
|
|
24744
|
+
var sprintf = __webpack_require__(/*! ./sprintf */ "./src/write/draw/sprintf.js");
|
|
24745
|
+
|
|
24746
|
+
var printPath = __webpack_require__(/*! ./print-path */ "./src/write/draw/print-path.js");
|
|
24747
|
+
|
|
24748
|
+
var roundNumber = __webpack_require__(/*! ./round-number */ "./src/write/draw/round-number.js");
|
|
24749
|
+
|
|
24750
|
+
function drawGlissando(renderer, params, selectables) {
|
|
24751
|
+
if (!params.anchor1 || !params.anchor2 || !params.anchor1.heads || !params.anchor2.heads || params.anchor1.heads.length === 0 || params.anchor2.heads.length === 0) window.console.error("Glissando Element not set.");
|
|
24752
|
+
var margin = 4;
|
|
24753
|
+
var leftY = renderer.calcY(params.anchor1.heads[0].pitch);
|
|
24754
|
+
var rightY = renderer.calcY(params.anchor2.heads[0].pitch);
|
|
24755
|
+
var leftX = params.anchor1.x + params.anchor1.w / 2;
|
|
24756
|
+
var rightX = params.anchor2.x + params.anchor2.w / 2;
|
|
24757
|
+
var len = lineLength(leftX, leftY, rightX, rightY);
|
|
24758
|
+
var marginLeft = params.anchor1.w / 2 + margin;
|
|
24759
|
+
var marginRight = params.anchor2.w / 2 + margin;
|
|
24760
|
+
var s = slope(leftX, leftY, rightX, rightY);
|
|
24761
|
+
var leftYAdj = getY(leftY, s, marginLeft);
|
|
24762
|
+
var rightYAdj = getY(rightY, s, -marginRight);
|
|
24763
|
+
var num = numSquigglies(len - marginLeft - marginRight);
|
|
24764
|
+
var el = drawSquiggly(renderer, leftX + marginLeft, leftYAdj, num, s);
|
|
24765
|
+
selectables.wrapSvgEl({
|
|
24766
|
+
el_type: "glissando",
|
|
24767
|
+
startChar: -1,
|
|
24768
|
+
endChar: -1
|
|
24769
|
+
}, el);
|
|
24770
|
+
return [el];
|
|
24771
|
+
}
|
|
24772
|
+
|
|
24773
|
+
function lineLength(leftX, leftY, rightX, rightY) {
|
|
24774
|
+
// The length from notehead center to notehead center.
|
|
24775
|
+
var w = rightX - leftX;
|
|
24776
|
+
var h = rightY - leftY;
|
|
24777
|
+
return Math.sqrt(w * w + h * h);
|
|
24778
|
+
}
|
|
24779
|
+
|
|
24780
|
+
function slope(leftX, leftY, rightX, rightY) {
|
|
24781
|
+
return (rightY - leftY) / (rightX - leftX);
|
|
24782
|
+
}
|
|
24783
|
+
|
|
24784
|
+
function getY(y, slope, xOfs) {
|
|
24785
|
+
return roundNumber(y + xOfs * slope);
|
|
24786
|
+
}
|
|
24787
|
+
|
|
24788
|
+
function numSquigglies(length) {
|
|
24789
|
+
var endLen = 5; // The width of the end - that is, the non repeating part
|
|
24790
|
+
|
|
24791
|
+
return Math.max(2, Math.floor((length - endLen * 2) / 6));
|
|
24792
|
+
}
|
|
24793
|
+
|
|
24794
|
+
var leftStart = [[3.5, -4.8]];
|
|
24795
|
+
var right = [[1.5, -1], [.3, -.3], [-3.5, 3.8]];
|
|
24796
|
+
var leftEnd = [[-1.5, 2]];
|
|
24797
|
+
var top = [[3, 4], [3, -4]];
|
|
24798
|
+
var bottom = [[-3, 4], [-3, -4]];
|
|
24799
|
+
|
|
24800
|
+
function segment(arr, slope) {
|
|
24801
|
+
var ret = "";
|
|
24802
|
+
|
|
24803
|
+
for (var i = 0; i < arr.length; i++) {
|
|
24804
|
+
ret += 'l' + arr[i][0] + ' ' + getY(arr[i][1], slope, arr[i][0]);
|
|
24805
|
+
}
|
|
24806
|
+
|
|
24807
|
+
return ret;
|
|
24808
|
+
}
|
|
24809
|
+
|
|
24810
|
+
var drawSquiggly = function drawSquiggly(renderer, x, y, num, slope) {
|
|
24811
|
+
var p = sprintf("M %f %f", x, y);
|
|
24812
|
+
p += segment(leftStart, slope);
|
|
24813
|
+
var i;
|
|
24814
|
+
|
|
24815
|
+
for (i = 0; i < num; i++) {
|
|
24816
|
+
p += segment(top, slope);
|
|
24817
|
+
}
|
|
24818
|
+
|
|
24819
|
+
p += segment(right, slope);
|
|
24820
|
+
|
|
24821
|
+
for (i = 0; i < num; i++) {
|
|
24822
|
+
p += segment(bottom, slope);
|
|
24823
|
+
}
|
|
24824
|
+
|
|
24825
|
+
p += segment(leftEnd, slope) + 'z';
|
|
24826
|
+
return printPath(renderer, {
|
|
24827
|
+
path: p,
|
|
24828
|
+
highlight: "stroke",
|
|
24829
|
+
stroke: renderer.foregroundColor,
|
|
24830
|
+
'class': renderer.controller.classes.generate('decoration'),
|
|
24831
|
+
"data-name": "glissando"
|
|
24832
|
+
});
|
|
24833
|
+
};
|
|
24834
|
+
|
|
24835
|
+
module.exports = drawGlissando;
|
|
24836
|
+
|
|
24837
|
+
/***/ }),
|
|
24838
|
+
|
|
23902
24839
|
/***/ "./src/write/draw/group-elements.js":
|
|
23903
24840
|
/*!******************************************!*\
|
|
23904
24841
|
!*** ./src/write/draw/group-elements.js ***!
|
|
@@ -25436,6 +26373,8 @@ module.exports = drawTriplet;
|
|
|
25436
26373
|
\*********************************/
|
|
25437
26374
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
25438
26375
|
|
|
26376
|
+
var drawGlissando = __webpack_require__(/*! ./glissando */ "./src/write/draw/glissando.js");
|
|
26377
|
+
|
|
25439
26378
|
var drawCrescendo = __webpack_require__(/*! ./crescendo */ "./src/write/draw/crescendo.js");
|
|
25440
26379
|
|
|
25441
26380
|
var drawDynamics = __webpack_require__(/*! ./dynamics */ "./src/write/draw/dynamics.js");
|
|
@@ -25535,6 +26474,10 @@ function drawVoice(renderer, params, bartop, selectables, staffPos) {
|
|
|
25535
26474
|
renderer.controller.classes.incrMeasure();
|
|
25536
26475
|
} else {
|
|
25537
26476
|
switch (child.type) {
|
|
26477
|
+
case "GlissandoElem":
|
|
26478
|
+
child.elemset = drawGlissando(renderer, child, selectables);
|
|
26479
|
+
break;
|
|
26480
|
+
|
|
25538
26481
|
case "CrescendoElem":
|
|
25539
26482
|
child.elemset = drawCrescendo(renderer, child, selectables);
|
|
25540
26483
|
break;
|
|
@@ -25587,7 +26530,7 @@ function formatJazzChord(chordString) {
|
|
|
25587
26530
|
for (var i = 0; i < lines.length; i++) {
|
|
25588
26531
|
var chord = lines[i]; // If the chord isn't in a recognizable format then just skip the formatting.
|
|
25589
26532
|
|
|
25590
|
-
var reg = chord.match(/^([ABCDEFG][♯♭]?)?([^\/]+)?(\/[ABCDEFG][#b]?)?/);
|
|
26533
|
+
var reg = chord.match(/^([ABCDEFG][♯♭]?)?([^\/]+)?(\/[ABCDEFG][#b♯♭]?)?/);
|
|
25591
26534
|
if (reg) lines[i] = (reg[1] ? reg[1] : '') + "\x03" + (reg[2] ? reg[2] : '') + "\x03" + (reg[3] ? reg[3] : '');
|
|
25592
26535
|
}
|
|
25593
26536
|
|
|
@@ -28109,7 +29052,7 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
|
|
|
28109
29052
|
font: 'infofont',
|
|
28110
29053
|
klass: 'meta-top rhythm',
|
|
28111
29054
|
absElemType: "rhythm",
|
|
28112
|
-
noMove:
|
|
29055
|
+
noMove: noMove,
|
|
28113
29056
|
info: metaTextInfo.rhythm,
|
|
28114
29057
|
name: "rhythm"
|
|
28115
29058
|
}, getTextSize);
|
|
@@ -28187,7 +29130,7 @@ module.exports = unhighlight;
|
|
|
28187
29130
|
\********************/
|
|
28188
29131
|
/***/ (function(module) {
|
|
28189
29132
|
|
|
28190
|
-
var version = '6.0
|
|
29133
|
+
var version = '6.1.0';
|
|
28191
29134
|
module.exports = version;
|
|
28192
29135
|
|
|
28193
29136
|
/***/ })
|