abcjs 6.4.1 → 6.4.3
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/LICENSE.md +1 -1
- package/RELEASE.md +46 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic-min.js.LICENSE +1 -1
- package/dist/abcjs-basic.js +1271 -1179
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/dist/abcjs-plugin-min.js.LICENSE +1 -1
- package/index.js +1 -1
- package/license.js +1 -1
- package/package.json +1 -1
- package/plugin.js +1 -1
- package/src/api/abc_tunebook.js +1 -2
- package/src/api/abc_tunebook_svg.js +0 -1
- package/src/data/abc_tune.js +2 -0
- package/src/midi/abc_midi_create.js +22 -7
- package/src/parse/abc_common.js +3 -11
- package/src/parse/abc_parse.js +1 -1
- package/src/parse/abc_parse_directive.js +44 -3
- package/src/parse/abc_parse_header.js +6 -4
- package/src/parse/abc_parse_key_voice.js +10 -6
- package/src/parse/abc_parse_music.js +54 -22
- package/src/parse/tune-builder.js +675 -643
- package/src/synth/abc_midi_flattener.js +3 -1
- package/src/synth/abc_midi_sequencer.js +18 -3
- package/src/synth/chord-track.js +90 -18
- package/src/synth/create-synth-control.js +1 -2
- package/src/tablatures/abc_tablatures.js +184 -0
- package/src/tablatures/instruments/string-patterns.js +266 -268
- package/src/tablatures/instruments/string-tablature.js +38 -35
- package/src/tablatures/instruments/tab-note.js +186 -181
- package/src/tablatures/instruments/tab-notes.js +30 -35
- package/src/tablatures/instruments/tab-string.js +43 -25
- package/src/tablatures/render/tab-absolute-elements.js +303 -0
- package/src/tablatures/render/tab-renderer.js +244 -0
- package/src/test/abc_parser_lint.js +2 -3
- package/src/write/creation/abstract-engraver.js +1 -1
- package/src/write/creation/elements/tie-element.js +26 -0
- package/src/write/engraver-controller.js +1 -1
- package/src/write/layout/set-upper-and-lower-elements.js +8 -0
- package/test.js +1 -1
- package/types/index.d.ts +2 -2
- package/version.js +1 -1
- package/src/api/abc_tablatures.js +0 -184
- package/src/tablatures/instruments/tab-string-patterns.js +0 -23
- package/src/tablatures/tab-absolute-elements.js +0 -301
- package/src/tablatures/tab-common.js +0 -29
- package/src/tablatures/tab-renderer.js +0 -259
package/dist/abcjs-basic.js
CHANGED
|
@@ -18,7 +18,7 @@ return /******/ (function() { // webpackBootstrap
|
|
|
18
18
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
19
19
|
|
|
20
20
|
/**!
|
|
21
|
-
Copyright (c) 2009-
|
|
21
|
+
Copyright (c) 2009-2024 Paul Rosen and Gregory Dyke
|
|
22
22
|
|
|
23
23
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
24
24
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -193,205 +193,6 @@ module.exports = animation;
|
|
|
193
193
|
|
|
194
194
|
/***/ }),
|
|
195
195
|
|
|
196
|
-
/***/ "./src/api/abc_tablatures.js":
|
|
197
|
-
/*!***********************************!*\
|
|
198
|
-
!*** ./src/api/abc_tablatures.js ***!
|
|
199
|
-
\***********************************/
|
|
200
|
-
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
201
|
-
|
|
202
|
-
/*
|
|
203
|
-
* Tablature Plugins
|
|
204
|
-
* tablature are defined dynamically and registered inside abcjs
|
|
205
|
-
* by calling abcTablatures.register(plugin)
|
|
206
|
-
* where plugin represents a plugin instance
|
|
207
|
-
*
|
|
208
|
-
*/
|
|
209
|
-
var StringTablature = __webpack_require__(/*! ../tablatures/instruments/tab-string */ "./src/tablatures/instruments/tab-string.js");
|
|
210
|
-
|
|
211
|
-
/* extend the table below when adding a new instrument plugin */
|
|
212
|
-
|
|
213
|
-
// Existing tab classes
|
|
214
|
-
var pluginTab = {
|
|
215
|
-
'violin': {
|
|
216
|
-
name: 'StringTab',
|
|
217
|
-
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
218
|
-
isTabBig: false,
|
|
219
|
-
tabSymbolOffset: 0
|
|
220
|
-
},
|
|
221
|
-
'fiddle': {
|
|
222
|
-
name: 'StringTab',
|
|
223
|
-
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
224
|
-
isTabBig: false,
|
|
225
|
-
tabSymbolOffset: 0
|
|
226
|
-
},
|
|
227
|
-
'mandolin': {
|
|
228
|
-
name: 'StringTab',
|
|
229
|
-
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
230
|
-
isTabBig: false,
|
|
231
|
-
tabSymbolOffset: 0
|
|
232
|
-
},
|
|
233
|
-
'guitar': {
|
|
234
|
-
name: 'StringTab',
|
|
235
|
-
defaultTuning: ['E,', 'A,', 'D', 'G', 'B', 'e'],
|
|
236
|
-
isTabBig: true,
|
|
237
|
-
tabSymbolOffset: 0
|
|
238
|
-
},
|
|
239
|
-
'fiveString': {
|
|
240
|
-
name: 'StringTab',
|
|
241
|
-
defaultTuning: ['C,', 'G,', 'D', 'A', 'e'],
|
|
242
|
-
isTabBig: false,
|
|
243
|
-
tabSymbolOffset: -.95
|
|
244
|
-
}
|
|
245
|
-
};
|
|
246
|
-
var abcTablatures = {
|
|
247
|
-
inited: false,
|
|
248
|
-
plugins: {},
|
|
249
|
-
/**
|
|
250
|
-
* to be called once per plugin for registration
|
|
251
|
-
* @param {*} plugin
|
|
252
|
-
*/
|
|
253
|
-
register: function register(plugin) {
|
|
254
|
-
var name = plugin.name;
|
|
255
|
-
var tablature = plugin.tablature;
|
|
256
|
-
this.plugins[name] = tablature;
|
|
257
|
-
},
|
|
258
|
-
setError: function setError(tune, msg) {
|
|
259
|
-
if (tune.warnings) {
|
|
260
|
-
tune.warning.push(msg);
|
|
261
|
-
} else {
|
|
262
|
-
tune.warnings = [msg];
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
|
-
/**
|
|
266
|
-
* handle params for current processed score
|
|
267
|
-
* @param {*} tune current tune
|
|
268
|
-
* @param {*} tuneNumber number in tune list
|
|
269
|
-
* @param {*} params params to be processed for tablature
|
|
270
|
-
* @return prepared tablatures plugin instances for current tune
|
|
271
|
-
*/
|
|
272
|
-
preparePlugins: function preparePlugins(tune, tuneNumber, params) {
|
|
273
|
-
var returned = null;
|
|
274
|
-
var nbPlugins = 0;
|
|
275
|
-
if (params.tablature) {
|
|
276
|
-
// validate requested plugins
|
|
277
|
-
var tabs = params.tablature;
|
|
278
|
-
returned = [];
|
|
279
|
-
for (var ii = 0; ii < tabs.length; ii++) {
|
|
280
|
-
var args = tabs[ii];
|
|
281
|
-
var instrument = args['instrument'];
|
|
282
|
-
if (instrument == null) {
|
|
283
|
-
this.setError(tune, "tablature 'instrument' is missing");
|
|
284
|
-
return returned;
|
|
285
|
-
}
|
|
286
|
-
var tabName = pluginTab[instrument];
|
|
287
|
-
var plugin = null;
|
|
288
|
-
if (tabName) {
|
|
289
|
-
plugin = this.plugins[tabName.name];
|
|
290
|
-
}
|
|
291
|
-
if (plugin) {
|
|
292
|
-
if (params.visualTranspose != 0) {
|
|
293
|
-
// populate transposition request to tabs
|
|
294
|
-
args.visualTranspose = params.visualTranspose;
|
|
295
|
-
}
|
|
296
|
-
args.abcSrc = params.tablature.abcSrc;
|
|
297
|
-
var pluginInstance = {
|
|
298
|
-
classz: plugin,
|
|
299
|
-
tuneNumber: tuneNumber,
|
|
300
|
-
params: args,
|
|
301
|
-
instance: null,
|
|
302
|
-
tabType: tabName
|
|
303
|
-
};
|
|
304
|
-
// proceed with tab plugin init
|
|
305
|
-
// plugin.init(tune, tuneNumber, args, ii);
|
|
306
|
-
returned.push(pluginInstance);
|
|
307
|
-
nbPlugins++;
|
|
308
|
-
} else if (instrument === '') {
|
|
309
|
-
// create a placeholder - there is no tab for this staff
|
|
310
|
-
returned.push(null);
|
|
311
|
-
} else {
|
|
312
|
-
// unknown tab plugin
|
|
313
|
-
//this.emit_error('Undefined tablature plugin: ' + tabName)
|
|
314
|
-
this.setError(tune, 'Undefined tablature plugin: ' + instrument);
|
|
315
|
-
return returned;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
return returned;
|
|
320
|
-
},
|
|
321
|
-
/**
|
|
322
|
-
* Call requested plugin
|
|
323
|
-
* @param {*} renderer
|
|
324
|
-
* @param {*} abcTune
|
|
325
|
-
*/
|
|
326
|
-
layoutTablatures: function layoutTablatures(renderer, abcTune) {
|
|
327
|
-
var tabs = abcTune.tablatures;
|
|
328
|
-
|
|
329
|
-
// chack tabs request for each staffs
|
|
330
|
-
var staffLineCount = 0;
|
|
331
|
-
|
|
332
|
-
// Clear the suppression flag
|
|
333
|
-
if (tabs && tabs.length > 0) {
|
|
334
|
-
var nTabs = tabs.length;
|
|
335
|
-
for (var kk = 0; kk < nTabs; ++kk) {
|
|
336
|
-
if (tabs[kk] && tabs[kk].params.firstStaffOnly) {
|
|
337
|
-
tabs[kk].params.suppress = false;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
for (var ii = 0; ii < abcTune.lines.length; ii++) {
|
|
342
|
-
var line = abcTune.lines[ii];
|
|
343
|
-
if (line.staff) {
|
|
344
|
-
staffLineCount++;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// MAE 27Nov2023
|
|
348
|
-
// If tab param "firstStaffOnly", remove the tab label after the first staff
|
|
349
|
-
if (staffLineCount > 1) {
|
|
350
|
-
if (tabs && tabs.length > 0) {
|
|
351
|
-
var nTabs = tabs.length;
|
|
352
|
-
for (var kk = 0; kk < nTabs; ++kk) {
|
|
353
|
-
if (tabs[kk].params.firstStaffOnly) {
|
|
354
|
-
// Set the staff draw suppression flag
|
|
355
|
-
tabs[kk].params.suppress = true;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
var curStaff = line.staff;
|
|
361
|
-
if (curStaff) {
|
|
362
|
-
var maxStaves = curStaff.length;
|
|
363
|
-
for (var jj = 0; jj < curStaff.length; jj++) {
|
|
364
|
-
if (tabs[jj] && jj < maxStaves) {
|
|
365
|
-
// tablature requested for staff
|
|
366
|
-
var tabPlugin = tabs[jj];
|
|
367
|
-
if (tabPlugin.instance == null) {
|
|
368
|
-
tabPlugin.instance = new tabPlugin.classz();
|
|
369
|
-
// plugin.init(tune, tuneNumber, args, ii);
|
|
370
|
-
// call initer first
|
|
371
|
-
tabPlugin.instance.init(abcTune, tabPlugin.tuneNumber, tabPlugin.params, jj, tabPlugin.tabType);
|
|
372
|
-
}
|
|
373
|
-
// render next
|
|
374
|
-
tabPlugin.instance.render(renderer, line, jj);
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
},
|
|
380
|
-
/**
|
|
381
|
-
* called once internally to register internal plugins
|
|
382
|
-
*/
|
|
383
|
-
init: function init() {
|
|
384
|
-
// just register plugin hosted by abcjs
|
|
385
|
-
if (!this.inited) {
|
|
386
|
-
this.register(new StringTablature());
|
|
387
|
-
this.inited = true;
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
};
|
|
391
|
-
module.exports = abcTablatures;
|
|
392
|
-
|
|
393
|
-
/***/ }),
|
|
394
|
-
|
|
395
196
|
/***/ "./src/api/abc_timing_callbacks.js":
|
|
396
197
|
/*!*****************************************!*\
|
|
397
198
|
!*** ./src/api/abc_timing_callbacks.js ***!
|
|
@@ -714,7 +515,7 @@ function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" =
|
|
|
714
515
|
|
|
715
516
|
var Parse = __webpack_require__(/*! ../parse/abc_parse */ "./src/parse/abc_parse.js");
|
|
716
517
|
var bookParser = __webpack_require__(/*! ../parse/abc_parse_book */ "./src/parse/abc_parse_book.js");
|
|
717
|
-
var tablatures = __webpack_require__(/*!
|
|
518
|
+
var tablatures = __webpack_require__(/*! ../tablatures/abc_tablatures */ "./src/tablatures/abc_tablatures.js");
|
|
718
519
|
var tunebook = {};
|
|
719
520
|
(function () {
|
|
720
521
|
"use strict";
|
|
@@ -785,7 +586,6 @@ var tunebook = {};
|
|
|
785
586
|
// Init tablatures plugins
|
|
786
587
|
//
|
|
787
588
|
if (params.tablature) {
|
|
788
|
-
tablatures.init();
|
|
789
589
|
tune.tablatures = tablatures.preparePlugins(tune, currentTune, params);
|
|
790
590
|
}
|
|
791
591
|
var warnings = abcParser.getWarnings();
|
|
@@ -817,7 +617,6 @@ var tunebook = {};
|
|
|
817
617
|
}
|
|
818
618
|
}
|
|
819
619
|
}
|
|
820
|
-
|
|
821
620
|
return staves;
|
|
822
621
|
}
|
|
823
622
|
function measuresParser(staff, tune) {
|
|
@@ -955,8 +754,6 @@ var Tune = __webpack_require__(/*! ../data/abc_tune */ "./src/data/abc_tune.js")
|
|
|
955
754
|
var EngraverController = __webpack_require__(/*! ../write/engraver-controller */ "./src/write/engraver-controller.js");
|
|
956
755
|
var Parse = __webpack_require__(/*! ../parse/abc_parse */ "./src/parse/abc_parse.js");
|
|
957
756
|
var wrap = __webpack_require__(/*! ../parse/wrap_lines */ "./src/parse/wrap_lines.js");
|
|
958
|
-
// var tablatures = require('./abc_tablatures');
|
|
959
|
-
|
|
960
757
|
var resizeDivs = {};
|
|
961
758
|
function resizeOuter() {
|
|
962
759
|
var width = window.innerWidth;
|
|
@@ -1543,7 +1340,6 @@ var Tune = function Tune() {
|
|
|
1543
1340
|
};
|
|
1544
1341
|
return this.meter; // TODO-PER: is this saved value used anywhere? A get function shouldn't change state.
|
|
1545
1342
|
};
|
|
1546
|
-
|
|
1547
1343
|
this.getKeySignature = function () {
|
|
1548
1344
|
for (var i = 0; i < this.lines.length; i++) {
|
|
1549
1345
|
var line = this.lines[i];
|
|
@@ -1698,7 +1494,6 @@ var Tune = function Tune() {
|
|
|
1698
1494
|
// isTiedState = voiceTimeMilliseconds;
|
|
1699
1495
|
}
|
|
1700
1496
|
}
|
|
1701
|
-
|
|
1702
1497
|
return {
|
|
1703
1498
|
isTiedState: isTiedState,
|
|
1704
1499
|
duration: realDuration / timeDivider,
|
|
@@ -1869,6 +1664,7 @@ var Tune = function Tune() {
|
|
|
1869
1664
|
}
|
|
1870
1665
|
this.getBpm = function (tempo) {
|
|
1871
1666
|
var bpm;
|
|
1667
|
+
if (!tempo) tempo = this.metaText ? this.metaText.tempo : null;
|
|
1872
1668
|
if (tempo) {
|
|
1873
1669
|
bpm = tempo.bpm;
|
|
1874
1670
|
var beatLength = this.getBeatLength();
|
|
@@ -2630,9 +2426,21 @@ var create;
|
|
|
2630
2426
|
if (title && title.length > 128) title = title.substring(0, 124) + '...';
|
|
2631
2427
|
var key = abcTune.getKeySignature();
|
|
2632
2428
|
var time = abcTune.getMeterFraction();
|
|
2633
|
-
|
|
2429
|
+
|
|
2430
|
+
// MAE 7 July 2024 - Fix for */8 meter tempos
|
|
2431
|
+
var tempo = commands.tempo;
|
|
2432
|
+
var beatsPerSecond = tempo / 60;
|
|
2433
|
+
|
|
2434
|
+
// Fix tempo for */8 meters
|
|
2435
|
+
if (time.den == 8) {
|
|
2436
|
+
// Compute the tempo based on the actual milliseconds per measure, scaled by the number of eight notes and halved to get tempo in bpm.
|
|
2437
|
+
var msPerMeasure = abcTune.millisecondsPerMeasure();
|
|
2438
|
+
tempo = 60000 / (msPerMeasure / time.num) / 2;
|
|
2439
|
+
beatsPerSecond = tempo / 60;
|
|
2440
|
+
}
|
|
2441
|
+
|
|
2634
2442
|
//var beatLength = abcTune.getBeatLength();
|
|
2635
|
-
midi.setGlobalInfo(
|
|
2443
|
+
midi.setGlobalInfo(tempo, title, key, time);
|
|
2636
2444
|
for (var i = 0; i < commands.tracks.length; i++) {
|
|
2637
2445
|
midi.startTrack();
|
|
2638
2446
|
var notePlacement = {};
|
|
@@ -2718,27 +2526,20 @@ module.exports = create;
|
|
|
2718
2526
|
\*********************************/
|
|
2719
2527
|
/***/ (function(module) {
|
|
2720
2528
|
|
|
2721
|
-
//
|
|
2529
|
+
// abc_common.js: Some common utility functions.
|
|
2722
2530
|
|
|
2723
2531
|
var parseCommon = {};
|
|
2724
|
-
parseCommon.clone = function (source) {
|
|
2725
|
-
var destination = {};
|
|
2726
|
-
for (var property in source) {
|
|
2727
|
-
if (source.hasOwnProperty(property)) destination[property] = source[property];
|
|
2728
|
-
}
|
|
2729
|
-
return destination;
|
|
2730
|
-
};
|
|
2731
2532
|
parseCommon.cloneArray = function (source) {
|
|
2732
2533
|
var destination = [];
|
|
2733
2534
|
for (var i = 0; i < source.length; i++) {
|
|
2734
|
-
destination.push(
|
|
2535
|
+
destination.push(Object.assign({}, source[i]));
|
|
2735
2536
|
}
|
|
2736
2537
|
return destination;
|
|
2737
2538
|
};
|
|
2738
2539
|
parseCommon.cloneHashOfHash = function (source) {
|
|
2739
2540
|
var destination = {};
|
|
2740
2541
|
for (var property in source) {
|
|
2741
|
-
if (source.hasOwnProperty(property)) destination[property] =
|
|
2542
|
+
if (source.hasOwnProperty(property)) destination[property] = Object.assign({}, source[property]);
|
|
2742
2543
|
}
|
|
2743
2544
|
return destination;
|
|
2744
2545
|
};
|
|
@@ -3230,7 +3031,7 @@ var Parse = function Parse() {
|
|
|
3230
3031
|
});
|
|
3231
3032
|
for (var i = 0; i < nextVoice.length; i++) {
|
|
3232
3033
|
var element = nextVoice[i];
|
|
3233
|
-
var hint =
|
|
3034
|
+
var hint = Object.assign({}, element);
|
|
3234
3035
|
voice.push(hint);
|
|
3235
3036
|
if (element.el_type === 'bar') return;
|
|
3236
3037
|
}
|
|
@@ -3318,7 +3119,6 @@ var Parse = function Parse() {
|
|
|
3318
3119
|
multilineVars.lineBreaks = switches.lineBreaks;
|
|
3319
3120
|
//multilineVars.continueall = true;
|
|
3320
3121
|
}
|
|
3321
|
-
|
|
3322
3122
|
header.reset(tokenizer, warn, multilineVars, tune);
|
|
3323
3123
|
try {
|
|
3324
3124
|
if (switches.format) {
|
|
@@ -3408,7 +3208,6 @@ var bookParser = function bookParser(book) {
|
|
|
3408
3208
|
});
|
|
3409
3209
|
pos += tune.length + 1; // We also lost a newline when splitting, so count that.
|
|
3410
3210
|
});
|
|
3411
|
-
|
|
3412
3211
|
if (tunes.length > 1 && !parseCommon.startsWith(tunes[0].abc, 'X:')) {
|
|
3413
3212
|
// If there is only one tune, the X: might be missing, otherwise assume the top of the file is "intertune"
|
|
3414
3213
|
// There could be file-wide directives in this, if so, we need to insert it into each tune. We can probably get away with
|
|
@@ -4157,7 +3956,7 @@ var parseDirective = {};
|
|
|
4157
3956
|
};
|
|
4158
3957
|
var midiCmdParam0 = ["nobarlines", "barlines", "beataccents", "nobeataccents", "droneon", "droneoff", "drumon", "drumoff", "fermatafixed", "fermataproportional", "gchordon", "gchordoff", "controlcombo", "temperamentnormal", "noportamento"];
|
|
4159
3958
|
var midiCmdParam1String = ["gchord", "ptstress", "beatstring"];
|
|
4160
|
-
var midiCmdParam1Integer = ["bassvol", "chordvol", "
|
|
3959
|
+
var midiCmdParam1Integer = ["bassvol", "chordvol", "c", "channel", "beatmod", "deltaloudness", "drumbars", "gracedivider", "makechordchannels", "randomchordattack", "chordattack", "stressmodel", "transpose", "rtranspose", "vol", "volinc", "gchordbars"];
|
|
4161
3960
|
var midiCmdParam1Integer1OptionalInteger = ["program"];
|
|
4162
3961
|
var midiCmdParam2Integer = ["ratio", "snt", "bendvelocity", "pitchbend", "control", "temperamentlinear"];
|
|
4163
3962
|
var midiCmdParam4Integer = ["beat"];
|
|
@@ -4165,6 +3964,7 @@ var parseDirective = {};
|
|
|
4165
3964
|
var midiCmdParam1String1Integer = ["portamento"];
|
|
4166
3965
|
var midiCmdParamFraction = ["expand", "grace", "trim"];
|
|
4167
3966
|
var midiCmdParam1StringVariableIntegers = ["drum", "chordname"];
|
|
3967
|
+
var midiCmdParam1Integer1OptionalString = ["bassprog", "chordprog"];
|
|
4168
3968
|
var parseMidiCommand = function parseMidiCommand(midi, tune, restOfString) {
|
|
4169
3969
|
var midi_cmd = midi.shift().token;
|
|
4170
3970
|
var midi_params = [];
|
|
@@ -4256,6 +4056,34 @@ var parseDirective = {};
|
|
|
4256
4056
|
midi_params.push(p.intt);
|
|
4257
4057
|
}
|
|
4258
4058
|
}
|
|
4059
|
+
} else if (midiCmdParam1Integer1OptionalString.indexOf(midi_cmd) >= 0) {
|
|
4060
|
+
// ONE INT PARAMETER, ONE OPTIONAL string
|
|
4061
|
+
if (midi.length !== 1 && midi.length !== 2) warn("Expected one or two parameters in MIDI " + midi_cmd, restOfString, 0);else if (midi[0].type !== "number") warn("Expected integer parameter in MIDI " + midi_cmd, restOfString, 0);else if (midi.length === 2 && midi[1].type !== "alpha") warn("Expected alpha parameter in MIDI " + midi_cmd, restOfString, 0);else {
|
|
4062
|
+
midi_params.push(midi[0].intt);
|
|
4063
|
+
|
|
4064
|
+
// Currently only bassprog and chordprog with optional octave shifts use this path
|
|
4065
|
+
if (midi.length === 2) {
|
|
4066
|
+
var cmd = midi[1].token;
|
|
4067
|
+
if (cmd.indexOf("octave=") != -1) {
|
|
4068
|
+
cmd = cmd.replace("octave=", "");
|
|
4069
|
+
cmd = parseInt(cmd);
|
|
4070
|
+
if (!isNaN(cmd)) {
|
|
4071
|
+
// Limit range from -1 to 3 octaves
|
|
4072
|
+
if (cmd < -1) {
|
|
4073
|
+
warn("Expected octave= in MIDI " + midi_cmd + ' to be >= -1 (recv:' + cmd + ')');
|
|
4074
|
+
cmd = -1;
|
|
4075
|
+
}
|
|
4076
|
+
if (cmd > 3) {
|
|
4077
|
+
warn("Expected octave= in MIDI " + midi_cmd + ' to be <= 3 (recv:' + cmd + ')');
|
|
4078
|
+
cmd = 3;
|
|
4079
|
+
}
|
|
4080
|
+
midi_params.push(cmd);
|
|
4081
|
+
} else warn("Expected octave value in MIDI" + midi_cmd);
|
|
4082
|
+
} else {
|
|
4083
|
+
warn("Expected octave= in MIDI" + midi_cmd);
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4259
4087
|
}
|
|
4260
4088
|
if (tuneBuilder.hasBeginMusic()) tuneBuilder.appendElement('midi', -1, -1, {
|
|
4261
4089
|
cmd: midi_cmd,
|
|
@@ -4952,7 +4780,6 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
4952
4780
|
}
|
|
4953
4781
|
return ret; // just to suppress warning
|
|
4954
4782
|
};
|
|
4955
|
-
|
|
4956
4783
|
var parseFraction = function parseFraction() {
|
|
4957
4784
|
// handles this much: parseNum slash decimal
|
|
4958
4785
|
var ret = parseNum();
|
|
@@ -4983,7 +4810,6 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
4983
4810
|
//var tok = tokens.shift();
|
|
4984
4811
|
//if (tok.token !== '+') throw "Extra characters in M: line";
|
|
4985
4812
|
}
|
|
4986
|
-
|
|
4987
4813
|
if (multilineVars.havent_set_length === true) {
|
|
4988
4814
|
multilineVars.default_length = totalLength < 0.75 ? 0.0625 : 0.125;
|
|
4989
4815
|
multilineVars.havent_set_length = false;
|
|
@@ -5201,6 +5027,7 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5201
5027
|
}
|
|
5202
5028
|
};
|
|
5203
5029
|
this.letter_to_inline_header = function (line, i, startLine) {
|
|
5030
|
+
var needsNewLine = false;
|
|
5204
5031
|
var ws = tokenizer.eatWhiteSpace(line, i);
|
|
5205
5032
|
i += ws;
|
|
5206
5033
|
if (line.length >= i + 5 && line[i] === '[' && line[i + 2] === ':') {
|
|
@@ -5247,9 +5074,9 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5247
5074
|
break;
|
|
5248
5075
|
case "[V:":
|
|
5249
5076
|
if (e > 0) {
|
|
5250
|
-
parseKeyVoice.parseVoice(line, i + 3, e);
|
|
5077
|
+
needsNewLine = parseKeyVoice.parseVoice(line, i + 3, e);
|
|
5251
5078
|
//startNewLine();
|
|
5252
|
-
return [e - i + 1 + ws, line[i + 1], line.substring(i + 3, e)];
|
|
5079
|
+
return [e - i + 1 + ws, line[i + 1], line.substring(i + 3, e), needsNewLine];
|
|
5253
5080
|
}
|
|
5254
5081
|
break;
|
|
5255
5082
|
case "[r:":
|
|
@@ -5258,10 +5085,10 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5258
5085
|
// TODO: complain about unhandled header
|
|
5259
5086
|
}
|
|
5260
5087
|
}
|
|
5261
|
-
|
|
5262
5088
|
return [0];
|
|
5263
5089
|
};
|
|
5264
5090
|
this.letter_to_body_header = function (line, i) {
|
|
5091
|
+
var needsNewLine = false;
|
|
5265
5092
|
if (line.length >= i + 3) {
|
|
5266
5093
|
switch (line.substring(i, i + 2)) {
|
|
5267
5094
|
case "I:":
|
|
@@ -5292,14 +5119,13 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5292
5119
|
if (tempo.type === 'delaySet') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, this.calcTempo(tempo.tempo));else if (tempo.type === 'immediate') tuneBuilder.appendElement('tempo', multilineVars.iChar + i, multilineVars.iChar + line.length, tempo.tempo);
|
|
5293
5120
|
return [e, line[i], parseCommon.strip(line.substring(i + 2))];
|
|
5294
5121
|
case "V:":
|
|
5295
|
-
parseKeyVoice.parseVoice(line, i + 2, line.length);
|
|
5122
|
+
needsNewLine = parseKeyVoice.parseVoice(line, i + 2, line.length);
|
|
5296
5123
|
// startNewLine();
|
|
5297
|
-
return [line.length, line[i], parseCommon.strip(line.substring(i + 2))];
|
|
5124
|
+
return [line.length, line[i], parseCommon.strip(line.substring(i + 2)), needsNewLine];
|
|
5298
5125
|
default:
|
|
5299
5126
|
// TODO: complain about unhandled header
|
|
5300
5127
|
}
|
|
5301
5128
|
}
|
|
5302
|
-
|
|
5303
5129
|
return [0];
|
|
5304
5130
|
};
|
|
5305
5131
|
var metaTextHeaders = {
|
|
@@ -5432,7 +5258,6 @@ module.exports = ParseHeader;
|
|
|
5432
5258
|
\******************************************/
|
|
5433
5259
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
5434
5260
|
|
|
5435
|
-
var parseCommon = __webpack_require__(/*! ./abc_common */ "./src/parse/abc_common.js");
|
|
5436
5261
|
var parseDirective = __webpack_require__(/*! ./abc_parse_directive */ "./src/parse/abc_parse_directive.js");
|
|
5437
5262
|
var transpose = __webpack_require__(/*! ./abc_transpose */ "./src/parse/abc_transpose.js");
|
|
5438
5263
|
var parseKeyVoice = {};
|
|
@@ -5683,7 +5508,7 @@ var parseKeyVoice = {};
|
|
|
5683
5508
|
mode: key.mode
|
|
5684
5509
|
};
|
|
5685
5510
|
key.accidentals.forEach(function (k) {
|
|
5686
|
-
ret.accidentals.push(
|
|
5511
|
+
ret.accidentals.push(Object.assign({}, k));
|
|
5687
5512
|
});
|
|
5688
5513
|
return ret;
|
|
5689
5514
|
};
|
|
@@ -5749,7 +5574,7 @@ var parseKeyVoice = {};
|
|
|
5749
5574
|
}
|
|
5750
5575
|
};
|
|
5751
5576
|
parseKeyVoice.fixKey = function (clef, key) {
|
|
5752
|
-
var fixedKey =
|
|
5577
|
+
var fixedKey = Object.assign({}, key);
|
|
5753
5578
|
parseKeyVoice.addPosToKey(clef, fixedKey);
|
|
5754
5579
|
return fixedKey;
|
|
5755
5580
|
};
|
|
@@ -5767,7 +5592,6 @@ var parseKeyVoice = {};
|
|
|
5767
5592
|
str: str.substring(i)
|
|
5768
5593
|
}; // We get the note in the middle of the staff. We want the note that appears as the first ledger line below the staff.
|
|
5769
5594
|
};
|
|
5770
|
-
|
|
5771
5595
|
var normalizeAccidentals = function normalizeAccidentals(accs) {
|
|
5772
5596
|
for (var i = 0; i < accs.length; i++) {
|
|
5773
5597
|
if (accs[i].note === 'b') accs[i].note = 'B';else if (accs[i].note === 'a') accs[i].note = 'A';else if (accs[i].note === 'F') accs[i].note = 'f';else if (accs[i].note === 'E') accs[i].note = 'e';else if (accs[i].note === 'D') accs[i].note = 'd';else if (accs[i].note === 'C') accs[i].note = 'c';else if (accs[i].note === 'G' && accs[i].acc === 'sharp') accs[i].note = 'g';else if (accs[i].note === 'g' && accs[i].acc === 'flat') accs[i].note = 'G';
|
|
@@ -6180,8 +6004,12 @@ var parseKeyVoice = {};
|
|
|
6180
6004
|
return ret;
|
|
6181
6005
|
};
|
|
6182
6006
|
var setCurrentVoice = function setCurrentVoice(id) {
|
|
6183
|
-
|
|
6184
|
-
|
|
6007
|
+
var currentVoice = multilineVars.voices[id];
|
|
6008
|
+
if (multilineVars.currentVoice) {
|
|
6009
|
+
if (multilineVars.currentVoice.index === currentVoice.index && multilineVars.currentVoice.staffNum === currentVoice.staffNum) return; // there was no change so don't reset it.
|
|
6010
|
+
}
|
|
6011
|
+
multilineVars.currentVoice = currentVoice;
|
|
6012
|
+
return tuneBuilder.setCurrentVoice(currentVoice.staffNum, currentVoice.index, id);
|
|
6185
6013
|
};
|
|
6186
6014
|
parseKeyVoice.parseVoice = function (line, i, e) {
|
|
6187
6015
|
//First truncate the string to the first non-space character after V: through either the
|
|
@@ -6395,7 +6223,6 @@ var parseKeyVoice = {};
|
|
|
6395
6223
|
// console.log("parse voice", token, tune.metaText.title);
|
|
6396
6224
|
}
|
|
6397
6225
|
}
|
|
6398
|
-
|
|
6399
6226
|
start += tokenizer.eatWhiteSpace(line, start);
|
|
6400
6227
|
}
|
|
6401
6228
|
|
|
@@ -6433,7 +6260,7 @@ var parseKeyVoice = {};
|
|
|
6433
6260
|
if (staffInfo.subname) {
|
|
6434
6261
|
if (s.subname) s.subname.push(staffInfo.subname);else s.subname = [staffInfo.subname];
|
|
6435
6262
|
}
|
|
6436
|
-
setCurrentVoice(id);
|
|
6263
|
+
return setCurrentVoice(id);
|
|
6437
6264
|
};
|
|
6438
6265
|
})();
|
|
6439
6266
|
module.exports = parseKeyVoice;
|
|
@@ -6446,7 +6273,6 @@ module.exports = parseKeyVoice;
|
|
|
6446
6273
|
\**************************************/
|
|
6447
6274
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
6448
6275
|
|
|
6449
|
-
var parseCommon = __webpack_require__(/*! ./abc_common */ "./src/parse/abc_common.js");
|
|
6450
6276
|
var parseKeyVoice = __webpack_require__(/*! ./abc_parse_key_voice */ "./src/parse/abc_parse_key_voice.js");
|
|
6451
6277
|
var transpose = __webpack_require__(/*! ./abc_transpose */ "./src/parse/abc_transpose.js");
|
|
6452
6278
|
var tokenizer;
|
|
@@ -6571,7 +6397,6 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
6571
6397
|
// delayStartNewLine = true;
|
|
6572
6398
|
// TODO-PER: Handle inline headers
|
|
6573
6399
|
}
|
|
6574
|
-
|
|
6575
6400
|
var overlayLevel = 0;
|
|
6576
6401
|
while (i < line.length) {
|
|
6577
6402
|
var startI = i;
|
|
@@ -6579,6 +6404,7 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
6579
6404
|
var retInlineHeader = header.letter_to_inline_header(line, i, delayStartNewLine);
|
|
6580
6405
|
if (retInlineHeader[0] > 0) {
|
|
6581
6406
|
i += retInlineHeader[0];
|
|
6407
|
+
//console.log("inline header", retInlineHeader)
|
|
6582
6408
|
if (retInlineHeader[1] === 'V') delayStartNewLine = true; // fixes bug on this: c[V:2]d
|
|
6583
6409
|
// TODO-PER: Handle inline headers
|
|
6584
6410
|
//multilineVars.start_new_line = false;
|
|
@@ -6858,6 +6684,9 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
6858
6684
|
if (ch === '-' || ch === ')' || ch === ' ' || ch === '<' || ch === '>') i--; // Subtracting one because one is automatically added below
|
|
6859
6685
|
else postChordDone = true;
|
|
6860
6686
|
break;
|
|
6687
|
+
case '0':
|
|
6688
|
+
chordDuration = 0;
|
|
6689
|
+
break;
|
|
6861
6690
|
default:
|
|
6862
6691
|
postChordDone = true;
|
|
6863
6692
|
break;
|
|
@@ -6947,7 +6776,11 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
6947
6776
|
if (!el.rest || el.rest.type !== 'spacer') warn("Duration not representable: " + line.substring(startI, i), line, i);
|
|
6948
6777
|
}
|
|
6949
6778
|
multilineVars.addFormattingOptions(el, tune.formatting, 'note');
|
|
6950
|
-
tuneBuilder.appendElement('note', startOfLine + startI, startOfLine + i, el);
|
|
6779
|
+
var succeeded = tuneBuilder.appendElement('note', startOfLine + startI, startOfLine + i, el);
|
|
6780
|
+
if (!succeeded) {
|
|
6781
|
+
this.startNewLine();
|
|
6782
|
+
tuneBuilder.appendElement('note', startOfLine + startI, startOfLine + i, el);
|
|
6783
|
+
}
|
|
6951
6784
|
multilineVars.measureNotEmpty = true;
|
|
6952
6785
|
el = {};
|
|
6953
6786
|
}
|
|
@@ -6991,15 +6824,30 @@ var letter_to_chord = function letter_to_chord(line, i) {
|
|
|
6991
6824
|
chord[1] = chord[1].substring(1);
|
|
6992
6825
|
chord[2] = 'right';
|
|
6993
6826
|
} else if (chord[0] > 0 && chord[1].length > 0 && chord[1][0] === '@') {
|
|
6994
|
-
// @-15,5.7
|
|
6827
|
+
// @-15,5.7
|
|
6995
6828
|
chord[1] = chord[1].substring(1);
|
|
6996
6829
|
var x = tokenizer.getFloat(chord[1]);
|
|
6997
|
-
if (x.digits === 0)
|
|
6830
|
+
if (x.digits === 0) {
|
|
6831
|
+
warn("Missing first position in absolutely positioned annotation.", line, i);
|
|
6832
|
+
chord[1] = chord[1].replace("@", "");
|
|
6833
|
+
chord[2] = 'above';
|
|
6834
|
+
return chord;
|
|
6835
|
+
}
|
|
6998
6836
|
chord[1] = chord[1].substring(x.digits);
|
|
6999
|
-
if (chord[1][0] !== ',')
|
|
6837
|
+
if (chord[1][0] !== ',') {
|
|
6838
|
+
warn("Missing comma absolutely positioned annotation.", line, i);
|
|
6839
|
+
chord[1] = chord[1].replace("@", "");
|
|
6840
|
+
chord[2] = 'above';
|
|
6841
|
+
return chord;
|
|
6842
|
+
}
|
|
7000
6843
|
chord[1] = chord[1].substring(1);
|
|
7001
6844
|
var y = tokenizer.getFloat(chord[1]);
|
|
7002
|
-
if (y.digits === 0)
|
|
6845
|
+
if (y.digits === 0) {
|
|
6846
|
+
warn("Missing second position in absolutely positioned annotation.", line, i);
|
|
6847
|
+
chord[1] = chord[1].replace("@", "");
|
|
6848
|
+
chord[2] = 'above';
|
|
6849
|
+
return chord;
|
|
6850
|
+
}
|
|
7003
6851
|
chord[1] = chord[1].substring(y.digits);
|
|
7004
6852
|
var ws = tokenizer.skipWhiteSpace(chord[1]);
|
|
7005
6853
|
chord[1] = chord[1].substring(ws);
|
|
@@ -7049,7 +6897,10 @@ var letter_to_grace = function letter_to_grace(line, i) {
|
|
|
7049
6897
|
// The grace note durations should not be affected by the default length: they should be based on 1/16, so if that isn't the default, then multiply here.
|
|
7050
6898
|
note.duration = note.duration / (multilineVars.default_length * 8);
|
|
7051
6899
|
if (acciaccatura) note.acciaccatura = true;
|
|
7052
|
-
|
|
6900
|
+
if (note.rest) {
|
|
6901
|
+
// don't allow rests inside gracenotes
|
|
6902
|
+
warn("Rests not allowed as grace notes '" + gra[1][ii] + "' while parsing grace note", line, i);
|
|
6903
|
+
} else gracenotes.push(note);
|
|
7053
6904
|
if (inTie) {
|
|
7054
6905
|
note.endTie = true;
|
|
7055
6906
|
inTie = false;
|
|
@@ -7280,7 +7131,7 @@ MusicParser.prototype.startNewLine = function () {
|
|
|
7280
7131
|
endChar: -1
|
|
7281
7132
|
};
|
|
7282
7133
|
if (multilineVars.partForNextLine.title) params.part = multilineVars.partForNextLine;
|
|
7283
|
-
params.clef = multilineVars.currentVoice && multilineVars.staves[multilineVars.currentVoice.staffNum].clef !== undefined ?
|
|
7134
|
+
params.clef = multilineVars.currentVoice && multilineVars.staves[multilineVars.currentVoice.staffNum].clef !== undefined ? Object.assign({}, multilineVars.staves[multilineVars.currentVoice.staffNum].clef) : Object.assign({}, multilineVars.clef);
|
|
7284
7135
|
var scoreTranspose = multilineVars.currentVoice ? multilineVars.currentVoice.scoreTranspose : 0;
|
|
7285
7136
|
params.key = parseKeyVoice.standardKey(multilineVars.key.root + multilineVars.key.acc + multilineVars.key.mode, multilineVars.key.root, multilineVars.key.acc, scoreTranspose);
|
|
7286
7137
|
params.key.mode = multilineVars.key.mode;
|
|
@@ -7334,6 +7185,11 @@ MusicParser.prototype.startNewLine = function () {
|
|
|
7334
7185
|
if (multilineVars.currentVoice.color) params.color = multilineVars.currentVoice.color;
|
|
7335
7186
|
if (multilineVars.currentVoice.style) params.style = multilineVars.currentVoice.style;
|
|
7336
7187
|
if (multilineVars.currentVoice.transpose) params.clef.transpose = multilineVars.currentVoice.transpose;
|
|
7188
|
+
params.currentVoice = multilineVars.currentVoice;
|
|
7189
|
+
var voices = Object.keys(multilineVars.voices);
|
|
7190
|
+
for (var mv = 0; mv < voices.length; mv++) {
|
|
7191
|
+
if (params.currentVoice.staffNum === multilineVars.voices[voices[mv]].staffNum && params.currentVoice.index === multilineVars.voices[voices[mv]].index) params.currentVoiceName = voices[mv];
|
|
7192
|
+
}
|
|
7337
7193
|
}
|
|
7338
7194
|
var isFirstVoice = multilineVars.currentVoice === undefined || multilineVars.currentVoice.staffNum === 0 && multilineVars.currentVoice.index === 0;
|
|
7339
7195
|
if (multilineVars.barNumbers === 0 && isFirstVoice && multilineVars.currBarNumber !== 1) params.barNumber = multilineVars.currBarNumber;
|
|
@@ -7721,7 +7577,6 @@ var Tokenizer = function Tokenizer(lines, multilineVars) {
|
|
|
7721
7577
|
}
|
|
7722
7578
|
return str.length; // It must have been all white space
|
|
7723
7579
|
};
|
|
7724
|
-
|
|
7725
7580
|
var finished = function finished(str, i) {
|
|
7726
7581
|
return i >= str.length;
|
|
7727
7582
|
};
|
|
@@ -7782,7 +7637,6 @@ var Tokenizer = function Tokenizer(lines, multilineVars) {
|
|
|
7782
7637
|
// case 'f':return {len: i+1, token: 'F'};
|
|
7783
7638
|
// case 'g':return {len: i+1, token: 'G'};
|
|
7784
7639
|
}
|
|
7785
|
-
|
|
7786
7640
|
return {
|
|
7787
7641
|
len: 0
|
|
7788
7642
|
};
|
|
@@ -8614,7 +8468,6 @@ var Tokenizer = function Tokenizer(lines, multilineVars) {
|
|
|
8614
8468
|
|
|
8615
8469
|
// More chars: IJ ij Ď ď Đ đ Ĝ ĝ Ğ ğ Ġ ġ Ģ ģ Ĥ ĥ Ħ ħ Ĵ ĵ Ķ ķ ĸ Ĺ ĺ Ļ ļ Ľ ľ Ŀ ŀ Ł ł Ń ń Ņ ņ Ň ň ʼn Ŋ ŋ Ŕ ŕ Ŗ ŗ Ř ř Ś ś Ŝ ŝ Ş ş Š Ţ ţ Ť ť Ŧ ŧ Ŵ ŵ Ź ź Ż ż Ž
|
|
8616
8470
|
};
|
|
8617
|
-
|
|
8618
8471
|
var charMap1 = {
|
|
8619
8472
|
"#": "♯",
|
|
8620
8473
|
"b": "♭",
|
|
@@ -9306,7 +9159,6 @@ function transposeChordName(chord, steps, preferFlats, freeGCchord) {
|
|
|
9306
9159
|
}
|
|
9307
9160
|
} else chord += bass; // Don't know what to do so do nothing
|
|
9308
9161
|
}
|
|
9309
|
-
|
|
9310
9162
|
if (extra2) chord += extra2;
|
|
9311
9163
|
return chord;
|
|
9312
9164
|
}
|
|
@@ -9321,166 +9173,19 @@ module.exports = transposeChordName;
|
|
|
9321
9173
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
9322
9174
|
|
|
9323
9175
|
var parseKeyVoice = __webpack_require__(/*! ../parse/abc_parse_key_voice */ "./src/parse/abc_parse_key_voice.js");
|
|
9324
|
-
var parseCommon =
|
|
9325
|
-
var parseDirective =
|
|
9176
|
+
//var parseCommon = require('../parse/abc_common');
|
|
9177
|
+
//var parseDirective = require('./abc_parse_directive');
|
|
9178
|
+
|
|
9326
9179
|
var TuneBuilder = function TuneBuilder(tune) {
|
|
9327
9180
|
var self = this;
|
|
9181
|
+
var voiceDefs = {};
|
|
9182
|
+
var currentVoiceName = '';
|
|
9183
|
+
tune.reset();
|
|
9328
9184
|
this.setVisualTranspose = function (visualTranspose) {
|
|
9329
9185
|
if (visualTranspose) tune.visualTranspose = visualTranspose;
|
|
9330
9186
|
};
|
|
9331
|
-
this.resolveOverlays = function () {
|
|
9332
|
-
var madeChanges = false;
|
|
9333
|
-
var durationsPerLines = [];
|
|
9334
|
-
for (var i = 0; i < tune.lines.length; i++) {
|
|
9335
|
-
var line = tune.lines[i];
|
|
9336
|
-
if (line.staff) {
|
|
9337
|
-
for (var j = 0; j < line.staff.length; j++) {
|
|
9338
|
-
var staff = line.staff[j];
|
|
9339
|
-
var overlayVoice = [];
|
|
9340
|
-
for (var k = 0; k < staff.voices.length; k++) {
|
|
9341
|
-
var voice = staff.voices[k];
|
|
9342
|
-
overlayVoice.push({
|
|
9343
|
-
hasOverlay: false,
|
|
9344
|
-
voice: [],
|
|
9345
|
-
snip: []
|
|
9346
|
-
});
|
|
9347
|
-
durationsPerLines[i] = 0;
|
|
9348
|
-
var durationThisBar = 0;
|
|
9349
|
-
var inOverlay = false;
|
|
9350
|
-
var overlayDuration = 0;
|
|
9351
|
-
var snipStart = -1;
|
|
9352
|
-
for (var kk = 0; kk < voice.length; kk++) {
|
|
9353
|
-
var event = voice[kk];
|
|
9354
|
-
if (event.el_type === "overlay" && !inOverlay) {
|
|
9355
|
-
madeChanges = true;
|
|
9356
|
-
inOverlay = true;
|
|
9357
|
-
snipStart = kk;
|
|
9358
|
-
overlayVoice[k].hasOverlay = true;
|
|
9359
|
-
if (overlayDuration === 0) overlayDuration = durationsPerLines[i];
|
|
9360
|
-
// If this isn't the first line, we also need invisible rests on the previous lines.
|
|
9361
|
-
// So, if the next voice doesn't appear in a previous line, create it
|
|
9362
|
-
for (var ii = 0; ii < i; ii++) {
|
|
9363
|
-
if (durationsPerLines[ii] && tune.lines[ii].staff && staff.voices.length >= tune.lines[ii].staff[0].voices.length) {
|
|
9364
|
-
tune.lines[ii].staff[0].voices.push([{
|
|
9365
|
-
el_type: "note",
|
|
9366
|
-
duration: durationsPerLines[ii],
|
|
9367
|
-
rest: {
|
|
9368
|
-
type: "invisible"
|
|
9369
|
-
},
|
|
9370
|
-
startChar: event.startChar,
|
|
9371
|
-
endChar: event.endChar
|
|
9372
|
-
}]);
|
|
9373
|
-
}
|
|
9374
|
-
}
|
|
9375
|
-
} else if (event.el_type === "bar") {
|
|
9376
|
-
if (inOverlay) {
|
|
9377
|
-
// delete the overlay events from this array without messing up this loop.
|
|
9378
|
-
inOverlay = false;
|
|
9379
|
-
overlayVoice[k].snip.push({
|
|
9380
|
-
start: snipStart,
|
|
9381
|
-
len: kk - snipStart
|
|
9382
|
-
});
|
|
9383
|
-
overlayVoice[k].voice.push(event); // Also end the overlay with the barline.
|
|
9384
|
-
} else {
|
|
9385
|
-
// This keeps the voices lined up: if the overlay isn't in the first measure then we need a bunch of invisible rests.
|
|
9386
|
-
if (durationThisBar > 0) overlayVoice[k].voice.push({
|
|
9387
|
-
el_type: "note",
|
|
9388
|
-
duration: durationThisBar,
|
|
9389
|
-
rest: {
|
|
9390
|
-
type: "invisible"
|
|
9391
|
-
},
|
|
9392
|
-
startChar: event.startChar,
|
|
9393
|
-
endChar: event.endChar
|
|
9394
|
-
});
|
|
9395
|
-
overlayVoice[k].voice.push(event);
|
|
9396
|
-
}
|
|
9397
|
-
durationThisBar = 0;
|
|
9398
|
-
} else if (event.el_type === "note") {
|
|
9399
|
-
if (inOverlay) {
|
|
9400
|
-
overlayVoice[k].voice.push(event);
|
|
9401
|
-
} else {
|
|
9402
|
-
durationThisBar += event.duration;
|
|
9403
|
-
durationsPerLines[i] += event.duration;
|
|
9404
|
-
}
|
|
9405
|
-
} else if (event.el_type === "scale" || event.el_type === "stem" || event.el_type === "overlay" || event.el_type === "style" || event.el_type === "transpose" || event.el_type === "color") {
|
|
9406
|
-
// These types of events are duplicated on the overlay layer.
|
|
9407
|
-
overlayVoice[k].voice.push(event);
|
|
9408
|
-
}
|
|
9409
|
-
}
|
|
9410
|
-
if (overlayVoice[k].hasOverlay && overlayVoice[k].snip.length === 0) {
|
|
9411
|
-
// there was no closing bar, so we didn't set the snip amount.
|
|
9412
|
-
overlayVoice[k].snip.push({
|
|
9413
|
-
start: snipStart,
|
|
9414
|
-
len: voice.length - snipStart
|
|
9415
|
-
});
|
|
9416
|
-
}
|
|
9417
|
-
}
|
|
9418
|
-
for (k = 0; k < overlayVoice.length; k++) {
|
|
9419
|
-
var ov = overlayVoice[k];
|
|
9420
|
-
if (ov.hasOverlay) {
|
|
9421
|
-
ov.voice.splice(0, 0, {
|
|
9422
|
-
el_type: "stem",
|
|
9423
|
-
direction: "down"
|
|
9424
|
-
});
|
|
9425
|
-
staff.voices.push(ov.voice);
|
|
9426
|
-
for (var kkk = ov.snip.length - 1; kkk >= 0; kkk--) {
|
|
9427
|
-
var snip = ov.snip[kkk];
|
|
9428
|
-
staff.voices[k].splice(snip.start, snip.len);
|
|
9429
|
-
staff.voices[k].splice(snip.start + 1, 0, {
|
|
9430
|
-
el_type: "stem",
|
|
9431
|
-
direction: "auto"
|
|
9432
|
-
});
|
|
9433
|
-
var indexOfLastBar = findLastBar(staff.voices[k], snip.start);
|
|
9434
|
-
staff.voices[k].splice(indexOfLastBar, 0, {
|
|
9435
|
-
el_type: "stem",
|
|
9436
|
-
direction: "up"
|
|
9437
|
-
});
|
|
9438
|
-
}
|
|
9439
|
-
// remove ending marks from the overlay voice so they are not repeated
|
|
9440
|
-
for (kkk = 0; kkk < staff.voices[staff.voices.length - 1].length; kkk++) {
|
|
9441
|
-
staff.voices[staff.voices.length - 1][kkk] = parseCommon.clone(staff.voices[staff.voices.length - 1][kkk]);
|
|
9442
|
-
var el = staff.voices[staff.voices.length - 1][kkk];
|
|
9443
|
-
if (el.el_type === 'bar' && el.startEnding) {
|
|
9444
|
-
delete el.startEnding;
|
|
9445
|
-
}
|
|
9446
|
-
if (el.el_type === 'bar' && el.endEnding) delete el.endEnding;
|
|
9447
|
-
}
|
|
9448
|
-
}
|
|
9449
|
-
}
|
|
9450
|
-
}
|
|
9451
|
-
}
|
|
9452
|
-
}
|
|
9453
|
-
return madeChanges;
|
|
9454
|
-
};
|
|
9455
|
-
function findLastBar(voice, start) {
|
|
9456
|
-
for (var i = start - 1; i > 0 && voice[i].el_type !== "bar"; i--) {}
|
|
9457
|
-
return i;
|
|
9458
|
-
}
|
|
9459
|
-
function fixTitles(lines) {
|
|
9460
|
-
// We might have name and subname defined. We now know what line everything is on, so we can determine which to use.
|
|
9461
|
-
var firstMusicLine = true;
|
|
9462
|
-
for (var i = 0; i < lines.length; i++) {
|
|
9463
|
-
var line = lines[i];
|
|
9464
|
-
if (line.staff) {
|
|
9465
|
-
for (var j = 0; j < line.staff.length; j++) {
|
|
9466
|
-
var staff = line.staff[j];
|
|
9467
|
-
if (staff.title) {
|
|
9468
|
-
var hasATitle = false;
|
|
9469
|
-
for (var k = 0; k < staff.title.length; k++) {
|
|
9470
|
-
if (staff.title[k]) {
|
|
9471
|
-
staff.title[k] = firstMusicLine ? staff.title[k].name : staff.title[k].subname;
|
|
9472
|
-
if (staff.title[k]) hasATitle = true;else staff.title[k] = '';
|
|
9473
|
-
} else staff.title[k] = '';
|
|
9474
|
-
}
|
|
9475
|
-
if (!hasATitle) delete staff.title;
|
|
9476
|
-
}
|
|
9477
|
-
}
|
|
9478
|
-
firstMusicLine = false;
|
|
9479
|
-
}
|
|
9480
|
-
}
|
|
9481
|
-
}
|
|
9482
9187
|
this.cleanUp = function (barsperstaff, staffnonote, currSlur) {
|
|
9483
|
-
|
|
9188
|
+
closeLine(tune); // Close the last line.
|
|
9484
9189
|
delete tune.runningFonts;
|
|
9485
9190
|
simplifyMetaText(tune);
|
|
9486
9191
|
//addRichTextToAnnotationsAndLyrics(tune)
|
|
@@ -9502,7 +9207,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9502
9207
|
} else {
|
|
9503
9208
|
for (v = 0; v < tune.lines[i].staff[s].voices.length; v++) {
|
|
9504
9209
|
if (tune.lines[i].staff[s].voices[v] === undefined) tune.lines[i].staff[s].voices[v] = []; // TODO-PER: There was a part missing in the abc music. How should we recover?
|
|
9505
|
-
else if (
|
|
9210
|
+
else if (containsNotes(tune.lines[i].staff[s].voices[v])) hasAny = true;
|
|
9506
9211
|
}
|
|
9507
9212
|
}
|
|
9508
9213
|
}
|
|
@@ -9538,7 +9243,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9538
9243
|
for (s = 0; s < tune.lines[i].staff.length; s++) {
|
|
9539
9244
|
var keepThis = false;
|
|
9540
9245
|
for (v = 0; v < tune.lines[i].staff[s].voices.length; v++) {
|
|
9541
|
-
if (
|
|
9246
|
+
if (containsNotesStrict(tune.lines[i].staff[s].voices[v])) {
|
|
9542
9247
|
keepThis = true;
|
|
9543
9248
|
}
|
|
9544
9249
|
}
|
|
@@ -9569,208 +9274,23 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9569
9274
|
}
|
|
9570
9275
|
|
|
9571
9276
|
// If there are overlays, create new voices for them.
|
|
9572
|
-
while (
|
|
9277
|
+
while (resolveOverlays(tune)) {
|
|
9573
9278
|
// keep resolving overlays as long as any are found.
|
|
9574
9279
|
}
|
|
9575
|
-
|
|
9576
|
-
|
|
9577
|
-
if (!currSlur[staffNum][voiceNum]) currSlur[staffNum][voiceNum] = [];
|
|
9578
|
-
var x;
|
|
9579
|
-
// var lyr = null; // TODO-PER: debugging.
|
|
9580
|
-
|
|
9581
|
-
var addEndSlur = function addEndSlur(obj, num, chordPos) {
|
|
9582
|
-
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9583
|
-
// There isn't an exact match for note position, but we'll take any other open slur.
|
|
9584
|
-
for (x = 0; x < currSlur[staffNum][voiceNum].length; x++) {
|
|
9585
|
-
if (currSlur[staffNum][voiceNum][x] !== undefined) {
|
|
9586
|
-
chordPos = x;
|
|
9587
|
-
break;
|
|
9588
|
-
}
|
|
9589
|
-
}
|
|
9590
|
-
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9591
|
-
var offNum = chordPos * 100 + 1;
|
|
9592
|
-
obj.endSlur.forEach(function (x) {
|
|
9593
|
-
if (offNum === x) --offNum;
|
|
9594
|
-
});
|
|
9595
|
-
currSlur[staffNum][voiceNum][chordPos] = [offNum];
|
|
9596
|
-
}
|
|
9597
|
-
}
|
|
9598
|
-
var slurNum;
|
|
9599
|
-
for (var i = 0; i < num; i++) {
|
|
9600
|
-
slurNum = currSlur[staffNum][voiceNum][chordPos].pop();
|
|
9601
|
-
obj.endSlur.push(slurNum);
|
|
9602
|
-
// lyr.syllable += '<' + slurNum; // TODO-PER: debugging
|
|
9603
|
-
}
|
|
9604
|
-
|
|
9605
|
-
if (currSlur[staffNum][voiceNum][chordPos].length === 0) delete currSlur[staffNum][voiceNum][chordPos];
|
|
9606
|
-
return slurNum;
|
|
9607
|
-
};
|
|
9608
|
-
var addStartSlur = function addStartSlur(obj, num, chordPos, usedNums) {
|
|
9609
|
-
obj.startSlur = [];
|
|
9610
|
-
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9611
|
-
currSlur[staffNum][voiceNum][chordPos] = [];
|
|
9612
|
-
}
|
|
9613
|
-
var nextNum = chordPos * 100 + 1;
|
|
9614
|
-
for (var i = 0; i < num; i++) {
|
|
9615
|
-
if (usedNums) {
|
|
9616
|
-
usedNums.forEach(function (x) {
|
|
9617
|
-
if (nextNum === x) ++nextNum;
|
|
9618
|
-
});
|
|
9619
|
-
usedNums.forEach(function (x) {
|
|
9620
|
-
if (nextNum === x) ++nextNum;
|
|
9621
|
-
});
|
|
9622
|
-
usedNums.forEach(function (x) {
|
|
9623
|
-
if (nextNum === x) ++nextNum;
|
|
9624
|
-
});
|
|
9625
|
-
}
|
|
9626
|
-
currSlur[staffNum][voiceNum][chordPos].forEach(function (x) {
|
|
9627
|
-
if (nextNum === x) ++nextNum;
|
|
9628
|
-
});
|
|
9629
|
-
currSlur[staffNum][voiceNum][chordPos].forEach(function (x) {
|
|
9630
|
-
if (nextNum === x) ++nextNum;
|
|
9631
|
-
});
|
|
9632
|
-
currSlur[staffNum][voiceNum][chordPos].push(nextNum);
|
|
9633
|
-
obj.startSlur.push({
|
|
9634
|
-
label: nextNum
|
|
9635
|
-
});
|
|
9636
|
-
if (obj.dottedSlur) {
|
|
9637
|
-
obj.startSlur[obj.startSlur.length - 1].style = 'dotted';
|
|
9638
|
-
delete obj.dottedSlur;
|
|
9639
|
-
}
|
|
9640
|
-
// lyr.syllable += ' ' + nextNum + '>'; // TODO-PER:debugging
|
|
9641
|
-
nextNum++;
|
|
9642
|
-
}
|
|
9643
|
-
};
|
|
9644
|
-
for (var i = 0; i < line.length; i++) {
|
|
9645
|
-
var el = line[i];
|
|
9646
|
-
// if (el.lyric === undefined) // TODO-PER: debugging
|
|
9647
|
-
// el.lyric = [{ divider: '-' }]; // TODO-PER: debugging
|
|
9648
|
-
// lyr = el.lyric[0]; // TODO-PER: debugging
|
|
9649
|
-
// lyr.syllable = ''; // TODO-PER: debugging
|
|
9650
|
-
if (el.el_type === 'note') {
|
|
9651
|
-
if (el.gracenotes) {
|
|
9652
|
-
for (var g = 0; g < el.gracenotes.length; g++) {
|
|
9653
|
-
if (el.gracenotes[g].endSlur) {
|
|
9654
|
-
var gg = el.gracenotes[g].endSlur;
|
|
9655
|
-
el.gracenotes[g].endSlur = [];
|
|
9656
|
-
for (var ggg = 0; ggg < gg; ggg++) {
|
|
9657
|
-
addEndSlur(el.gracenotes[g], 1, 20);
|
|
9658
|
-
}
|
|
9659
|
-
}
|
|
9660
|
-
if (el.gracenotes[g].startSlur) {
|
|
9661
|
-
x = el.gracenotes[g].startSlur;
|
|
9662
|
-
addStartSlur(el.gracenotes[g], x, 20);
|
|
9663
|
-
}
|
|
9664
|
-
}
|
|
9665
|
-
}
|
|
9666
|
-
if (el.endSlur) {
|
|
9667
|
-
x = el.endSlur;
|
|
9668
|
-
el.endSlur = [];
|
|
9669
|
-
addEndSlur(el, x, 0);
|
|
9670
|
-
}
|
|
9671
|
-
if (el.startSlur) {
|
|
9672
|
-
x = el.startSlur;
|
|
9673
|
-
addStartSlur(el, x, 0);
|
|
9674
|
-
}
|
|
9675
|
-
if (el.pitches) {
|
|
9676
|
-
var usedNums = [];
|
|
9677
|
-
for (var p = 0; p < el.pitches.length; p++) {
|
|
9678
|
-
if (el.pitches[p].endSlur) {
|
|
9679
|
-
var k = el.pitches[p].endSlur;
|
|
9680
|
-
el.pitches[p].endSlur = [];
|
|
9681
|
-
for (var j = 0; j < k; j++) {
|
|
9682
|
-
var slurNum = addEndSlur(el.pitches[p], 1, p + 1);
|
|
9683
|
-
usedNums.push(slurNum);
|
|
9684
|
-
}
|
|
9685
|
-
}
|
|
9686
|
-
}
|
|
9687
|
-
for (p = 0; p < el.pitches.length; p++) {
|
|
9688
|
-
if (el.pitches[p].startSlur) {
|
|
9689
|
-
x = el.pitches[p].startSlur;
|
|
9690
|
-
addStartSlur(el.pitches[p], x, p + 1, usedNums);
|
|
9691
|
-
}
|
|
9692
|
-
}
|
|
9693
|
-
// Correct for the weird gracenote case where ({g}a) should match.
|
|
9694
|
-
// The end slur was already assigned to the note, and needs to be moved to the first note of the graces.
|
|
9695
|
-
if (el.gracenotes && el.pitches[0].endSlur && el.pitches[0].endSlur[0] === 100 && el.pitches[0].startSlur) {
|
|
9696
|
-
if (el.gracenotes[0].endSlur) el.gracenotes[0].endSlur.push(el.pitches[0].startSlur[0].label);else el.gracenotes[0].endSlur = [el.pitches[0].startSlur[0].label];
|
|
9697
|
-
if (el.pitches[0].endSlur.length === 1) delete el.pitches[0].endSlur;else if (el.pitches[0].endSlur[0] === 100) el.pitches[0].endSlur.shift();else if (el.pitches[0].endSlur[el.pitches[0].endSlur.length - 1] === 100) el.pitches[0].endSlur.pop();
|
|
9698
|
-
if (currSlur[staffNum][voiceNum][1].length === 1) delete currSlur[staffNum][voiceNum][1];else currSlur[staffNum][voiceNum][1].pop();
|
|
9699
|
-
}
|
|
9700
|
-
}
|
|
9701
|
-
}
|
|
9702
|
-
}
|
|
9703
|
-
}
|
|
9704
|
-
|
|
9705
|
-
// TODO-PER: This could be done faster as we go instead of as the last step.
|
|
9706
|
-
function fixClefPlacement(el) {
|
|
9707
|
-
parseKeyVoice.fixClef(el);
|
|
9708
|
-
}
|
|
9709
|
-
function wrapMusicLines(lines, barsperstaff) {
|
|
9710
|
-
for (i = 0; i < lines.length; i++) {
|
|
9711
|
-
if (lines[i].staff !== undefined) {
|
|
9712
|
-
for (s = 0; s < lines[i].staff.length; s++) {
|
|
9713
|
-
var permanentItems = [];
|
|
9714
|
-
for (v = 0; v < lines[i].staff[s].voices.length; v++) {
|
|
9715
|
-
var voice = lines[i].staff[s].voices[v];
|
|
9716
|
-
var barNumThisLine = 0;
|
|
9717
|
-
for (var n = 0; n < voice.length; n++) {
|
|
9718
|
-
if (voice[n].el_type === 'bar') {
|
|
9719
|
-
barNumThisLine++;
|
|
9720
|
-
if (barNumThisLine >= barsperstaff) {
|
|
9721
|
-
// push everything else to the next line, if there is anything else,
|
|
9722
|
-
// and there is a next line. If there isn't a next line, create one.
|
|
9723
|
-
if (n < voice.length - 1) {
|
|
9724
|
-
var nextLine = getNextMusicLine(lines, i);
|
|
9725
|
-
if (!nextLine) {
|
|
9726
|
-
var cp = JSON.parse(JSON.stringify(lines[i]));
|
|
9727
|
-
lines.push(parseCommon.clone(cp));
|
|
9728
|
-
nextLine = lines[lines.length - 1];
|
|
9729
|
-
for (var ss = 0; ss < nextLine.staff.length; ss++) {
|
|
9730
|
-
for (var vv = 0; vv < nextLine.staff[ss].voices.length; vv++) {
|
|
9731
|
-
nextLine.staff[ss].voices[vv] = [];
|
|
9732
|
-
}
|
|
9733
|
-
}
|
|
9734
|
-
}
|
|
9735
|
-
var startElement = n + 1;
|
|
9736
|
-
var section = lines[i].staff[s].voices[v].slice(startElement);
|
|
9737
|
-
lines[i].staff[s].voices[v] = lines[i].staff[s].voices[v].slice(0, startElement);
|
|
9738
|
-
nextLine.staff[s].voices[v] = permanentItems.concat(section.concat(nextLine.staff[s].voices[v]));
|
|
9739
|
-
return true;
|
|
9740
|
-
}
|
|
9741
|
-
}
|
|
9742
|
-
} else if (!voice[n].duration) {
|
|
9743
|
-
permanentItems.push(voice[n]);
|
|
9744
|
-
}
|
|
9745
|
-
}
|
|
9746
|
-
}
|
|
9747
|
-
}
|
|
9748
|
-
}
|
|
9749
|
-
}
|
|
9750
|
-
return false;
|
|
9751
|
-
}
|
|
9752
|
-
function getNextMusicLine(lines, currentLine) {
|
|
9753
|
-
currentLine++;
|
|
9754
|
-
while (lines.length > currentLine) {
|
|
9755
|
-
if (lines[currentLine].staff) return lines[currentLine];
|
|
9756
|
-
currentLine++;
|
|
9757
|
-
}
|
|
9758
|
-
return null;
|
|
9759
|
-
}
|
|
9760
|
-
for (tune.lineNum = 0; tune.lineNum < tune.lines.length; tune.lineNum++) {
|
|
9761
|
-
var staff = tune.lines[tune.lineNum].staff;
|
|
9280
|
+
for (var i = 0; i < tune.lines.length; i++) {
|
|
9281
|
+
var staff = tune.lines[i].staff;
|
|
9762
9282
|
if (staff) {
|
|
9763
9283
|
for (tune.staffNum = 0; tune.staffNum < staff.length; tune.staffNum++) {
|
|
9764
|
-
if (staff[tune.staffNum].clef)
|
|
9284
|
+
if (staff[tune.staffNum].clef) parseKeyVoice.fixClef(staff[tune.staffNum].clef);
|
|
9765
9285
|
for (tune.voiceNum = 0; tune.voiceNum < staff[tune.staffNum].voices.length; tune.voiceNum++) {
|
|
9766
9286
|
var voice = staff[tune.staffNum].voices[tune.voiceNum];
|
|
9767
|
-
cleanUpSlursInLine(voice, tune.staffNum, tune.voiceNum);
|
|
9287
|
+
cleanUpSlursInLine(voice, tune.staffNum, tune.voiceNum, currSlur);
|
|
9768
9288
|
for (var j = 0; j < voice.length; j++) {
|
|
9769
|
-
if (voice[j].el_type === 'clef')
|
|
9289
|
+
if (voice[j].el_type === 'clef') parseKeyVoice.fixClef(voice[j]);
|
|
9770
9290
|
}
|
|
9771
9291
|
if (voice.length > 0 && voice[voice.length - 1].barNumber) {
|
|
9772
9292
|
// Don't hang a bar number on the last bar line: it should go on the next line.
|
|
9773
|
-
var nextLine = getNextMusicLine(tune.lines,
|
|
9293
|
+
var nextLine = getNextMusicLine(tune.lines, i);
|
|
9774
9294
|
if (nextLine) nextLine.staff[0].barNumber = voice[voice.length - 1].barNumber;
|
|
9775
9295
|
delete voice[voice.length - 1].barNumber;
|
|
9776
9296
|
}
|
|
@@ -9788,21 +9308,9 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9788
9308
|
delete tune.vskipPending;
|
|
9789
9309
|
return currSlur;
|
|
9790
9310
|
};
|
|
9791
|
-
tune.reset();
|
|
9792
|
-
this.getLastNote = function () {
|
|
9793
|
-
if (tune.lines[tune.lineNum] && tune.lines[tune.lineNum].staff && tune.lines[tune.lineNum].staff[tune.staffNum] && tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum]) {
|
|
9794
|
-
for (var i = tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum].length - 1; i >= 0; i--) {
|
|
9795
|
-
var el = tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum][i];
|
|
9796
|
-
if (el.el_type === 'note') {
|
|
9797
|
-
return el;
|
|
9798
|
-
}
|
|
9799
|
-
}
|
|
9800
|
-
}
|
|
9801
|
-
return null;
|
|
9802
|
-
};
|
|
9803
9311
|
this.addTieToLastNote = function (dottedTie) {
|
|
9804
9312
|
// TODO-PER: if this is a chord, which note?
|
|
9805
|
-
var el =
|
|
9313
|
+
var el = getLastNote(tune);
|
|
9806
9314
|
if (el && el.pitches && el.pitches.length > 0) {
|
|
9807
9315
|
el.pitches[0].startTie = {};
|
|
9808
9316
|
if (dottedTie) el.pitches[0].startTie.style = 'dotted';
|
|
@@ -9810,59 +9318,10 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9810
9318
|
}
|
|
9811
9319
|
return false;
|
|
9812
9320
|
};
|
|
9813
|
-
this.getDuration = function (el) {
|
|
9814
|
-
if (el.duration) return el.duration;
|
|
9815
|
-
//if (el.pitches && el.pitches.length > 0) return el.pitches[0].duration;
|
|
9816
|
-
return 0;
|
|
9817
|
-
};
|
|
9818
|
-
this.closeLine = function () {
|
|
9819
|
-
if (tune.potentialStartBeam && tune.potentialEndBeam) {
|
|
9820
|
-
tune.potentialStartBeam.startBeam = true;
|
|
9821
|
-
tune.potentialEndBeam.endBeam = true;
|
|
9822
|
-
}
|
|
9823
|
-
delete tune.potentialStartBeam;
|
|
9824
|
-
delete tune.potentialEndBeam;
|
|
9825
|
-
};
|
|
9826
9321
|
this.appendElement = function (type, startChar, endChar, hashParams) {
|
|
9827
|
-
var This = tune;
|
|
9828
|
-
var pushNote = function pushNote(hp) {
|
|
9829
|
-
var currStaff = This.lines[This.lineNum].staff[This.staffNum];
|
|
9830
|
-
if (!currStaff) {
|
|
9831
|
-
// TODO-PER: This prevents a crash, but it drops the element. Need to figure out how to start a new line, or delay adding this.
|
|
9832
|
-
return;
|
|
9833
|
-
}
|
|
9834
|
-
if (hp.pitches !== undefined) {
|
|
9835
|
-
var mid = currStaff.workingClef.verticalPos;
|
|
9836
|
-
hp.pitches.forEach(function (p) {
|
|
9837
|
-
p.verticalPos = p.pitch - mid;
|
|
9838
|
-
});
|
|
9839
|
-
}
|
|
9840
|
-
if (hp.gracenotes !== undefined) {
|
|
9841
|
-
var mid2 = currStaff.workingClef.verticalPos;
|
|
9842
|
-
hp.gracenotes.forEach(function (p) {
|
|
9843
|
-
p.verticalPos = p.pitch - mid2;
|
|
9844
|
-
});
|
|
9845
|
-
}
|
|
9846
|
-
currStaff.voices[This.voiceNum].push(hp);
|
|
9847
|
-
};
|
|
9848
9322
|
hashParams.el_type = type;
|
|
9849
9323
|
if (startChar !== null) hashParams.startChar = startChar;
|
|
9850
9324
|
if (endChar !== null) hashParams.endChar = endChar;
|
|
9851
|
-
var endBeamHere = function endBeamHere() {
|
|
9852
|
-
This.potentialStartBeam.startBeam = true;
|
|
9853
|
-
hashParams.endBeam = true;
|
|
9854
|
-
delete This.potentialStartBeam;
|
|
9855
|
-
delete This.potentialEndBeam;
|
|
9856
|
-
};
|
|
9857
|
-
var endBeamLast = function endBeamLast() {
|
|
9858
|
-
if (This.potentialStartBeam !== undefined && This.potentialEndBeam !== undefined) {
|
|
9859
|
-
// Do we have a set of notes to beam?
|
|
9860
|
-
This.potentialStartBeam.startBeam = true;
|
|
9861
|
-
This.potentialEndBeam.endBeam = true;
|
|
9862
|
-
}
|
|
9863
|
-
delete This.potentialStartBeam;
|
|
9864
|
-
delete This.potentialEndBeam;
|
|
9865
|
-
};
|
|
9866
9325
|
if (type === 'note') {
|
|
9867
9326
|
// && (hashParams.rest !== undefined || hashParams.end_beam === undefined)) {
|
|
9868
9327
|
// Now, add the startBeam and endBeam where it is needed.
|
|
@@ -9871,25 +9330,25 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9871
9330
|
// this.potentialEndBeam either points to null or the start beam.
|
|
9872
9331
|
// If we have a beam break (note is longer than a quarter, or an end_beam is on this element), then set the beam if we have one.
|
|
9873
9332
|
// reset the variables for the next notes.
|
|
9874
|
-
var dur =
|
|
9333
|
+
var dur = getDuration(hashParams);
|
|
9875
9334
|
if (dur >= 0.25) {
|
|
9876
9335
|
// The beam ends on the note before this.
|
|
9877
|
-
endBeamLast();
|
|
9878
|
-
} else if (hashParams.force_end_beam_last &&
|
|
9879
|
-
endBeamLast();
|
|
9880
|
-
} else if (hashParams.end_beam &&
|
|
9336
|
+
endBeamLast(tune);
|
|
9337
|
+
} else if (hashParams.force_end_beam_last && tune.potentialStartBeam !== undefined) {
|
|
9338
|
+
endBeamLast(tune);
|
|
9339
|
+
} else if (hashParams.end_beam && tune.potentialStartBeam !== undefined) {
|
|
9881
9340
|
// the beam is forced to end on this note, probably because of a space in the ABC
|
|
9882
|
-
if (hashParams.rest === undefined) endBeamHere();else endBeamLast();
|
|
9341
|
+
if (hashParams.rest === undefined) endBeamHere(hashParams, tune);else endBeamLast(tune);
|
|
9883
9342
|
} else if (hashParams.rest === undefined) {
|
|
9884
9343
|
// this a short note and we aren't about to end the beam
|
|
9885
|
-
if (
|
|
9344
|
+
if (tune.potentialStartBeam === undefined) {
|
|
9886
9345
|
// We aren't collecting notes for a beam, so start here.
|
|
9887
9346
|
if (!hashParams.end_beam) {
|
|
9888
|
-
|
|
9889
|
-
delete
|
|
9347
|
+
tune.potentialStartBeam = hashParams;
|
|
9348
|
+
delete tune.potentialEndBeam;
|
|
9890
9349
|
}
|
|
9891
9350
|
} else {
|
|
9892
|
-
|
|
9351
|
+
tune.potentialEndBeam = hashParams; // Continue the beaming, look for the end next note.
|
|
9893
9352
|
}
|
|
9894
9353
|
}
|
|
9895
9354
|
|
|
@@ -9897,21 +9356,31 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9897
9356
|
// if (hashParams.rest !== undefined)
|
|
9898
9357
|
// {
|
|
9899
9358
|
// hashParams.end_beam = true;
|
|
9900
|
-
// var el2 =
|
|
9359
|
+
// var el2 = getLastNote(tune);
|
|
9901
9360
|
// if (el2) el2.end_beam = true;
|
|
9902
9361
|
// // TODO-PER: implement exception mentioned in the comment.
|
|
9903
9362
|
// }
|
|
9904
9363
|
} else {
|
|
9905
9364
|
// It's not a note, so there definitely isn't beaming after it.
|
|
9906
|
-
endBeamLast();
|
|
9365
|
+
endBeamLast(tune);
|
|
9907
9366
|
}
|
|
9908
9367
|
delete hashParams.end_beam; // We don't want this temporary variable hanging around.
|
|
9909
9368
|
delete hashParams.force_end_beam_last; // We don't want this temporary variable hanging around.
|
|
9910
|
-
|
|
9369
|
+
if (hashParams.rest && hashParams.rest.type === 'invisible') {
|
|
9370
|
+
delete hashParams.decoration; // the decorations on invisible rests should be invisible, too.
|
|
9371
|
+
}
|
|
9372
|
+
if (tune.lines.length <= tune.lineNum || tune.lines[tune.lineNum].staff.length <= tune.staffNum) {
|
|
9373
|
+
//console.log("pushNote IGNORED", tune.lines[tune.lineNum])
|
|
9374
|
+
// TODO-PER: This prevents a crash, but it drops the element. Need to figure out how to start a new line, or delay adding this.
|
|
9375
|
+
return false;
|
|
9376
|
+
}
|
|
9377
|
+
pushNote(self, tune, hashParams, voiceDefs, currentVoiceName);
|
|
9378
|
+
return true;
|
|
9911
9379
|
};
|
|
9912
9380
|
this.appendStartingElement = function (type, startChar, endChar, hashParams2) {
|
|
9381
|
+
//console.log('appendStartingElement', hashParams2)
|
|
9913
9382
|
// If we're in the middle of beaming, then end the beam.
|
|
9914
|
-
|
|
9383
|
+
closeLine(tune);
|
|
9915
9384
|
|
|
9916
9385
|
// We only ever want implied naturals the first time.
|
|
9917
9386
|
var impliedNaturals;
|
|
@@ -9922,58 +9391,54 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9922
9391
|
}
|
|
9923
9392
|
|
|
9924
9393
|
// Clone the object because it will be sticking around for the next line and we don't want the extra fields in it.
|
|
9925
|
-
var hashParams =
|
|
9926
|
-
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
|
|
9934
|
-
|
|
9935
|
-
|
|
9936
|
-
}
|
|
9937
|
-
|
|
9938
|
-
|
|
9939
|
-
|
|
9940
|
-
|
|
9941
|
-
|
|
9942
|
-
|
|
9943
|
-
|
|
9944
|
-
|
|
9945
|
-
|
|
9946
|
-
|
|
9947
|
-
|
|
9948
|
-
|
|
9949
|
-
|
|
9950
|
-
|
|
9951
|
-
|
|
9952
|
-
|
|
9953
|
-
|
|
9954
|
-
|
|
9955
|
-
if (
|
|
9956
|
-
|
|
9957
|
-
|
|
9958
|
-
|
|
9959
|
-
|
|
9960
|
-
|
|
9961
|
-
|
|
9962
|
-
|
|
9394
|
+
var hashParams = Object.assign({}, hashParams2);
|
|
9395
|
+
|
|
9396
|
+
// be sure that we are on a music type line before doing the following.
|
|
9397
|
+
if (!tune.lines[tune.lineNum]) return;
|
|
9398
|
+
var staff = tune.lines[tune.lineNum].staff;
|
|
9399
|
+
if (!staff) return;
|
|
9400
|
+
|
|
9401
|
+
// If tune is the first item in tune staff, then we might have to initialize the staff, first.
|
|
9402
|
+
if (staff.length <= tune.staffNum) {
|
|
9403
|
+
staff[tune.staffNum] = {};
|
|
9404
|
+
staff[tune.staffNum].clef = Object.assign({}, staff[0].clef);
|
|
9405
|
+
staff[tune.staffNum].key = Object.assign({}, staff[0].key);
|
|
9406
|
+
if (staff[0].meter) staff[tune.staffNum].meter = Object.assign({}, staff[0].meter);
|
|
9407
|
+
staff[tune.staffNum].workingClef = Object.assign({}, staff[0].workingClef);
|
|
9408
|
+
staff[tune.staffNum].voices = [[]];
|
|
9409
|
+
}
|
|
9410
|
+
// If tune is a clef type, then we replace the working clef on the line. This is kept separate from
|
|
9411
|
+
// the clef in case there is an inline clef field. We need to know what the current position for
|
|
9412
|
+
// the note is.
|
|
9413
|
+
if (type === 'clef') {
|
|
9414
|
+
staff[tune.staffNum].workingClef = hashParams;
|
|
9415
|
+
}
|
|
9416
|
+
|
|
9417
|
+
// These elements should not be added twice, so if the element exists on tune line without a note or bar before it, just replace the staff version.
|
|
9418
|
+
var voice = staff[tune.staffNum].voices[tune.voiceNum];
|
|
9419
|
+
for (var i = 0; i < voice.length; i++) {
|
|
9420
|
+
if (voice[i].el_type === 'note' || voice[i].el_type === 'bar') {
|
|
9421
|
+
hashParams.el_type = type;
|
|
9422
|
+
hashParams.startChar = startChar;
|
|
9423
|
+
hashParams.endChar = endChar;
|
|
9424
|
+
if (impliedNaturals) hashParams.accidentals = impliedNaturals.concat(hashParams.accidentals);
|
|
9425
|
+
voice.push(hashParams);
|
|
9426
|
+
return;
|
|
9427
|
+
}
|
|
9428
|
+
if (voice[i].el_type === type) {
|
|
9429
|
+
hashParams.el_type = type;
|
|
9430
|
+
hashParams.startChar = startChar;
|
|
9431
|
+
hashParams.endChar = endChar;
|
|
9432
|
+
if (impliedNaturals) hashParams.accidentals = impliedNaturals.concat(hashParams.accidentals);
|
|
9433
|
+
voice[i] = hashParams;
|
|
9434
|
+
return;
|
|
9963
9435
|
}
|
|
9964
|
-
// We didn't see either that type or a note, so replace the element to the staff.
|
|
9965
|
-
tune.lines[tune.lineNum].staff[tune.staffNum][type] = hashParams2;
|
|
9966
|
-
}
|
|
9967
|
-
};
|
|
9968
|
-
this.pushLine = function (hash) {
|
|
9969
|
-
if (tune.vskipPending) {
|
|
9970
|
-
hash.vskip = tune.vskipPending;
|
|
9971
|
-
delete tune.vskipPending;
|
|
9972
9436
|
}
|
|
9973
|
-
|
|
9437
|
+
// We didn't see either that type or a note, so replace the element to the staff.
|
|
9438
|
+
staff[tune.staffNum][type] = hashParams2;
|
|
9974
9439
|
};
|
|
9975
9440
|
this.addSubtitle = function (str, info) {
|
|
9976
|
-
|
|
9441
|
+
pushLine(tune, {
|
|
9977
9442
|
subtitle: {
|
|
9978
9443
|
text: str,
|
|
9979
9444
|
startChar: info.startChar,
|
|
@@ -9985,12 +9450,12 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9985
9450
|
tune.vskipPending = num;
|
|
9986
9451
|
};
|
|
9987
9452
|
this.addNewPage = function (num) {
|
|
9988
|
-
|
|
9453
|
+
pushLine(tune, {
|
|
9989
9454
|
newpage: num
|
|
9990
9455
|
});
|
|
9991
9456
|
};
|
|
9992
9457
|
this.addSeparator = function (spaceAbove, spaceBelow, lineLength, info) {
|
|
9993
|
-
|
|
9458
|
+
pushLine(tune, {
|
|
9994
9459
|
separator: {
|
|
9995
9460
|
spaceAbove: Math.round(spaceAbove),
|
|
9996
9461
|
spaceBelow: Math.round(spaceBelow),
|
|
@@ -10001,7 +9466,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10001
9466
|
});
|
|
10002
9467
|
};
|
|
10003
9468
|
this.addText = function (str, info) {
|
|
10004
|
-
|
|
9469
|
+
pushLine(tune, {
|
|
10005
9470
|
text: {
|
|
10006
9471
|
text: str,
|
|
10007
9472
|
startChar: info.startChar,
|
|
@@ -10010,29 +9475,17 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10010
9475
|
});
|
|
10011
9476
|
};
|
|
10012
9477
|
this.addCentered = function (str) {
|
|
10013
|
-
|
|
9478
|
+
pushLine(tune, {
|
|
10014
9479
|
text: [{
|
|
10015
9480
|
text: str,
|
|
10016
9481
|
center: true
|
|
10017
9482
|
}]
|
|
10018
9483
|
});
|
|
10019
9484
|
};
|
|
10020
|
-
this.containsNotes = function (voice) {
|
|
10021
|
-
for (var i = 0; i < voice.length; i++) {
|
|
10022
|
-
if (voice[i].el_type === 'note' || voice[i].el_type === 'bar') return true;
|
|
10023
|
-
}
|
|
10024
|
-
return false;
|
|
10025
|
-
};
|
|
10026
|
-
this.containsNotesStrict = function (voice) {
|
|
10027
|
-
for (var i = 0; i < voice.length; i++) {
|
|
10028
|
-
if (voice[i].el_type === 'note' && (voice[i].rest === undefined || voice[i].chord !== undefined)) return true;
|
|
10029
|
-
}
|
|
10030
|
-
return false;
|
|
10031
|
-
};
|
|
10032
9485
|
|
|
10033
9486
|
// anyVoiceContainsNotes: function(line) {
|
|
10034
9487
|
// for (var i = 0; i < line.staff.voices.length; i++) {
|
|
10035
|
-
// if (
|
|
9488
|
+
// if (containsNotes(line.staff.voices[i]))
|
|
10036
9489
|
// return true;
|
|
10037
9490
|
// }
|
|
10038
9491
|
// return false;
|
|
@@ -10048,95 +9501,18 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10048
9501
|
});
|
|
10049
9502
|
};
|
|
10050
9503
|
this.startNewLine = function (params) {
|
|
9504
|
+
//console.log("startNewLine", tune.lineNum, params, voiceDefs)
|
|
10051
9505
|
// If the pointed to line doesn't exist, just create that. If the line does exist, but doesn't have any music on it, just use it.
|
|
10052
9506
|
// If it does exist and has music, then increment the line number. If the new element doesn't exist, create it.
|
|
10053
|
-
|
|
10054
|
-
|
|
10055
|
-
|
|
10056
|
-
|
|
10057
|
-
|
|
10058
|
-
|
|
10059
|
-
thisStaff.title[This.voiceNum] = {
|
|
10060
|
-
name: params.name,
|
|
10061
|
-
subname: params.subname
|
|
10062
|
-
};
|
|
10063
|
-
if (params.style) self.appendElement('style', null, null, {
|
|
10064
|
-
head: params.style
|
|
10065
|
-
});
|
|
10066
|
-
if (params.stem) self.appendElement('stem', null, null, {
|
|
10067
|
-
direction: params.stem
|
|
10068
|
-
});else if (This.voiceNum > 0) {
|
|
10069
|
-
if (thisStaff.voices[0] !== undefined) {
|
|
10070
|
-
var found = false;
|
|
10071
|
-
for (var i = 0; i < thisStaff.voices[0].length; i++) {
|
|
10072
|
-
if (thisStaff.voices[0].el_type === 'stem') found = true;
|
|
10073
|
-
}
|
|
10074
|
-
if (!found) {
|
|
10075
|
-
var stem = {
|
|
10076
|
-
el_type: 'stem',
|
|
10077
|
-
direction: 'up'
|
|
10078
|
-
};
|
|
10079
|
-
thisStaff.voices[0].splice(0, 0, stem);
|
|
10080
|
-
}
|
|
10081
|
-
}
|
|
10082
|
-
self.appendElement('stem', null, null, {
|
|
10083
|
-
direction: 'down'
|
|
10084
|
-
});
|
|
10085
|
-
}
|
|
10086
|
-
if (params.scale) self.appendElement('scale', null, null, {
|
|
10087
|
-
size: params.scale
|
|
10088
|
-
});
|
|
10089
|
-
if (params.color) self.appendElement('color', null, null, {
|
|
10090
|
-
color: params.color
|
|
10091
|
-
});
|
|
10092
|
-
};
|
|
10093
|
-
var createStaff = function createStaff(params) {
|
|
10094
|
-
if (params.key && params.key.impliedNaturals) {
|
|
10095
|
-
params.key.accidentals = params.key.accidentals.concat(params.key.impliedNaturals);
|
|
10096
|
-
delete params.key.impliedNaturals;
|
|
10097
|
-
}
|
|
10098
|
-
This.lines[This.lineNum].staff[This.staffNum] = {
|
|
10099
|
-
voices: [],
|
|
10100
|
-
clef: params.clef,
|
|
10101
|
-
key: params.key,
|
|
10102
|
-
workingClef: params.clef
|
|
10103
|
-
};
|
|
10104
|
-
if (params.stafflines !== undefined) {
|
|
10105
|
-
This.lines[This.lineNum].staff[This.staffNum].clef.stafflines = params.stafflines;
|
|
10106
|
-
This.lines[This.lineNum].staff[This.staffNum].workingClef.stafflines = params.stafflines;
|
|
10107
|
-
}
|
|
10108
|
-
if (params.staffscale) {
|
|
10109
|
-
This.lines[This.lineNum].staff[This.staffNum].staffscale = params.staffscale;
|
|
10110
|
-
}
|
|
10111
|
-
if (params.annotationfont) self.setLineFont("annotationfont", params.annotationfont);
|
|
10112
|
-
if (params.gchordfont) self.setLineFont("gchordfont", params.gchordfont);
|
|
10113
|
-
if (params.tripletfont) self.setLineFont("tripletfont", params.tripletfont);
|
|
10114
|
-
if (params.vocalfont) self.setLineFont("vocalfont", params.vocalfont);
|
|
10115
|
-
if (params.bracket) This.lines[This.lineNum].staff[This.staffNum].bracket = params.bracket;
|
|
10116
|
-
if (params.brace) This.lines[This.lineNum].staff[This.staffNum].brace = params.brace;
|
|
10117
|
-
if (params.connectBarLines) This.lines[This.lineNum].staff[This.staffNum].connectBarLines = params.connectBarLines;
|
|
10118
|
-
if (params.barNumber) This.lines[This.lineNum].staff[This.staffNum].barNumber = params.barNumber;
|
|
10119
|
-
createVoice(params);
|
|
10120
|
-
// Some stuff just happens for the first voice
|
|
10121
|
-
if (params.part) self.appendElement('part', params.part.startChar, params.part.endChar, {
|
|
10122
|
-
title: params.part.title
|
|
10123
|
-
});
|
|
10124
|
-
if (params.meter !== undefined) This.lines[This.lineNum].staff[This.staffNum].meter = params.meter;
|
|
10125
|
-
if (This.vskipPending) {
|
|
10126
|
-
This.lines[This.lineNum].vskip = This.vskipPending;
|
|
10127
|
-
delete This.vskipPending;
|
|
10128
|
-
}
|
|
10129
|
-
};
|
|
10130
|
-
var createLine = function createLine(params) {
|
|
10131
|
-
This.lines[This.lineNum] = {
|
|
10132
|
-
staff: []
|
|
10133
|
-
};
|
|
10134
|
-
createStaff(params);
|
|
10135
|
-
};
|
|
10136
|
-
if (tune.lines[tune.lineNum] === undefined) createLine(params);else if (tune.lines[tune.lineNum].staff === undefined) {
|
|
9507
|
+
closeLine(tune); // Close the previous line.
|
|
9508
|
+
if (params.currentVoiceName) {
|
|
9509
|
+
currentVoiceName = params.currentVoiceName;
|
|
9510
|
+
voiceDefs[params.currentVoiceName] = params;
|
|
9511
|
+
}
|
|
9512
|
+
if (tune.lines[tune.lineNum] === undefined) createLine(self, tune, params);else if (tune.lines[tune.lineNum].staff === undefined) {
|
|
10137
9513
|
tune.lineNum++;
|
|
10138
9514
|
this.startNewLine(params);
|
|
10139
|
-
} else if (tune.lines[tune.lineNum].staff[tune.staffNum] === undefined) createStaff(params);else if (tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum] === undefined) createVoice(params);else if (!
|
|
9515
|
+
} else if (tune.lines[tune.lineNum].staff[tune.staffNum] === undefined) createStaff(self, tune, params);else if (tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum] === undefined) createVoice(self, tune, params);else if (!containsNotes(tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum])) {
|
|
10140
9516
|
// We don't need a new line but we might need to update parts of it.
|
|
10141
9517
|
if (params.part) self.appendElement('part', params.part.startChar, params.part.endChar, {
|
|
10142
9518
|
title: params.part.title
|
|
@@ -10150,21 +9526,6 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10150
9526
|
// This is called at tune start to set the current default fonts so we know whether to record a change.
|
|
10151
9527
|
tune.runningFonts[type] = font;
|
|
10152
9528
|
};
|
|
10153
|
-
this.setLineFont = function (type, font) {
|
|
10154
|
-
// If we haven't encountered the font type yet then we are using the default font so it doesn't
|
|
10155
|
-
// need to be noted. If we have encountered it, then only record it if it is different from the last time.
|
|
10156
|
-
if (tune.runningFonts[type]) {
|
|
10157
|
-
var isDifferent = false;
|
|
10158
|
-
var keys = Object.keys(font);
|
|
10159
|
-
for (var i = 0; i < keys.length; i++) {
|
|
10160
|
-
if (tune.runningFonts[type][keys[i]] !== font[keys[i]]) isDifferent = true;
|
|
10161
|
-
}
|
|
10162
|
-
if (isDifferent) {
|
|
10163
|
-
tune.lines[tune.lineNum].staff[tune.staffNum][type] = font;
|
|
10164
|
-
}
|
|
10165
|
-
}
|
|
10166
|
-
tune.runningFonts[type] = font;
|
|
10167
|
-
};
|
|
10168
9529
|
this.setBarNumberImmediate = function (barNumber) {
|
|
10169
9530
|
// If tune is called right at the beginning of a line, then correct the measure number that is already written.
|
|
10170
9531
|
// If tune is called at the beginning of a measure, then correct the measure number that was just created.
|
|
@@ -10194,24 +9555,31 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10194
9555
|
return true;
|
|
10195
9556
|
};
|
|
10196
9557
|
this.getCurrentVoice = function () {
|
|
9558
|
+
//console.log("getCurrentVoice", tune.lineNum)
|
|
10197
9559
|
var currLine = tune.lines[tune.lineNum];
|
|
10198
9560
|
if (!currLine) return null;
|
|
10199
9561
|
var currStaff = currLine.staff[tune.staffNum];
|
|
10200
9562
|
if (!currStaff) return null;
|
|
10201
9563
|
if (currStaff.voices[tune.voiceNum] !== undefined) return currStaff.voices[tune.voiceNum];else return null;
|
|
10202
9564
|
};
|
|
10203
|
-
this.setCurrentVoice = function (staffNum, voiceNum) {
|
|
9565
|
+
this.setCurrentVoice = function (staffNum, voiceNum, name) {
|
|
9566
|
+
//console.log("setCurrentVoice", tune.lineNum, staffNum, voiceNum, name, voiceDefs)
|
|
10204
9567
|
tune.staffNum = staffNum;
|
|
10205
9568
|
tune.voiceNum = voiceNum;
|
|
9569
|
+
currentVoiceName = name;
|
|
10206
9570
|
for (var i = 0; i < tune.lines.length; i++) {
|
|
10207
9571
|
if (tune.lines[i].staff) {
|
|
10208
|
-
if (tune.lines[i].staff[staffNum] === undefined || tune.lines[i].staff[staffNum].voices[voiceNum] === undefined || !
|
|
9572
|
+
if (tune.lines[i].staff[staffNum] === undefined || tune.lines[i].staff[staffNum].voices[voiceNum] === undefined || !containsNotes(tune.lines[i].staff[staffNum].voices[voiceNum])) {
|
|
9573
|
+
//console.log("cv2", i, tune.lines[i].staff[staffNum])
|
|
10209
9574
|
tune.lineNum = i;
|
|
10210
|
-
return;
|
|
9575
|
+
if (!tune.lines[i].staff[staffNum] || !!tune.lines[i].staff[staffNum].voices[voiceNum]) return true;
|
|
9576
|
+
return false;
|
|
10211
9577
|
}
|
|
10212
9578
|
}
|
|
10213
9579
|
}
|
|
9580
|
+
//console.log("cv3", i, tune.lineNum, tune.lines[tune.lineNum])
|
|
10214
9581
|
tune.lineNum = i;
|
|
9582
|
+
return false;
|
|
10215
9583
|
};
|
|
10216
9584
|
this.addMetaText = function (key, value, info) {
|
|
10217
9585
|
if (tune.metaText[key] === undefined) {
|
|
@@ -10247,7 +9615,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10247
9615
|
function isArrayOfStrings(arr) {
|
|
10248
9616
|
if (!arr) return false;
|
|
10249
9617
|
if (typeof arr === "string") return false;
|
|
10250
|
-
var str = ''
|
|
9618
|
+
//var str = ''
|
|
10251
9619
|
for (var i = 0; i < arr.length; i++) {
|
|
10252
9620
|
if (typeof arr[i] !== 'string') return false;
|
|
10253
9621
|
}
|
|
@@ -10257,33 +9625,553 @@ function simplifyMetaText(tune) {
|
|
|
10257
9625
|
if (isArrayOfStrings(tune.metaText.notes)) tune.metaText.notes = tune.metaText.notes.join("\n");
|
|
10258
9626
|
if (isArrayOfStrings(tune.metaText.history)) tune.metaText.history = tune.metaText.history.join("\n");
|
|
10259
9627
|
}
|
|
10260
|
-
|
|
10261
|
-
|
|
10262
|
-
|
|
10263
|
-
|
|
10264
|
-
|
|
10265
|
-
|
|
10266
|
-
|
|
10267
|
-
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
10279
|
-
|
|
10280
|
-
|
|
10281
|
-
|
|
10282
|
-
|
|
9628
|
+
|
|
9629
|
+
// function addRichTextToAnnotationsAndLyrics(tune) {
|
|
9630
|
+
// var lines = tune.lines
|
|
9631
|
+
// for (var i = 0; i < lines.length; i++) {
|
|
9632
|
+
// if (lines[i].staff !== undefined) {
|
|
9633
|
+
// for (var s = 0; s < lines[i].staff.length; s++) {
|
|
9634
|
+
// for (var v = 0; v < lines[i].staff[s].voices.length; v++) {
|
|
9635
|
+
// var voice = lines[i].staff[s].voices[v];
|
|
9636
|
+
// for (var n = 0; n < voice.length; n++) {
|
|
9637
|
+
// var element = voice[n]
|
|
9638
|
+
// if (element.chord) {
|
|
9639
|
+
// for (var c = 0; c < element.chord.length; c++) {
|
|
9640
|
+
// element.chord[c].name = parseDirective.parseFontChangeLine(element.chord[c].name)
|
|
9641
|
+
// console.log(element.chord[c].name)
|
|
9642
|
+
// }
|
|
9643
|
+
// }
|
|
9644
|
+
// if (element.lyric) {
|
|
9645
|
+
// for (var l = 0; l < element.lyric.length; l++) {
|
|
9646
|
+
// element.lyric[l].syllable = parseDirective.parseFontChangeLine(element.lyric[l].syllable)
|
|
9647
|
+
// console.log(element.lyric[l].syllable)
|
|
9648
|
+
// }
|
|
9649
|
+
// }
|
|
9650
|
+
// }
|
|
9651
|
+
// }
|
|
9652
|
+
// }
|
|
9653
|
+
// }
|
|
9654
|
+
// }
|
|
9655
|
+
|
|
9656
|
+
// }
|
|
9657
|
+
|
|
9658
|
+
function resolveOverlays(tune) {
|
|
9659
|
+
var madeChanges = false;
|
|
9660
|
+
var durationsPerLines = [];
|
|
9661
|
+
for (var i = 0; i < tune.lines.length; i++) {
|
|
9662
|
+
var line = tune.lines[i];
|
|
9663
|
+
if (line.staff) {
|
|
9664
|
+
for (var j = 0; j < line.staff.length; j++) {
|
|
9665
|
+
var staff = line.staff[j];
|
|
9666
|
+
var overlayVoice = [];
|
|
9667
|
+
for (var k = 0; k < staff.voices.length; k++) {
|
|
9668
|
+
var voice = staff.voices[k];
|
|
9669
|
+
overlayVoice.push({
|
|
9670
|
+
hasOverlay: false,
|
|
9671
|
+
voice: [],
|
|
9672
|
+
snip: []
|
|
9673
|
+
});
|
|
9674
|
+
durationsPerLines[i] = 0;
|
|
9675
|
+
var durationThisBar = 0;
|
|
9676
|
+
var inOverlay = false;
|
|
9677
|
+
var overlayDuration = 0;
|
|
9678
|
+
var snipStart = -1;
|
|
9679
|
+
for (var kk = 0; kk < voice.length; kk++) {
|
|
9680
|
+
var event = voice[kk];
|
|
9681
|
+
if (event.el_type === "overlay" && !inOverlay) {
|
|
9682
|
+
madeChanges = true;
|
|
9683
|
+
inOverlay = true;
|
|
9684
|
+
snipStart = kk;
|
|
9685
|
+
overlayVoice[k].hasOverlay = true;
|
|
9686
|
+
if (overlayDuration === 0) overlayDuration = durationsPerLines[i];
|
|
9687
|
+
// If this isn't the first line, we also need invisible rests on the previous lines.
|
|
9688
|
+
// So, if the next voice doesn't appear in a previous line, create it
|
|
9689
|
+
for (var ii = 0; ii < i; ii++) {
|
|
9690
|
+
if (durationsPerLines[ii] && tune.lines[ii].staff && staff.voices.length >= tune.lines[ii].staff[0].voices.length) {
|
|
9691
|
+
tune.lines[ii].staff[0].voices.push([{
|
|
9692
|
+
el_type: "note",
|
|
9693
|
+
duration: durationsPerLines[ii],
|
|
9694
|
+
rest: {
|
|
9695
|
+
type: "invisible"
|
|
9696
|
+
},
|
|
9697
|
+
startChar: event.startChar,
|
|
9698
|
+
endChar: event.endChar
|
|
9699
|
+
}]);
|
|
9700
|
+
}
|
|
9701
|
+
}
|
|
9702
|
+
} else if (event.el_type === "bar") {
|
|
9703
|
+
if (inOverlay) {
|
|
9704
|
+
// delete the overlay events from this array without messing up this loop.
|
|
9705
|
+
inOverlay = false;
|
|
9706
|
+
overlayVoice[k].snip.push({
|
|
9707
|
+
start: snipStart,
|
|
9708
|
+
len: kk - snipStart
|
|
9709
|
+
});
|
|
9710
|
+
overlayVoice[k].voice.push(event); // Also end the overlay with the barline.
|
|
9711
|
+
} else {
|
|
9712
|
+
// This keeps the voices lined up: if the overlay isn't in the first measure then we need a bunch of invisible rests.
|
|
9713
|
+
if (durationThisBar > 0) overlayVoice[k].voice.push({
|
|
9714
|
+
el_type: "note",
|
|
9715
|
+
duration: durationThisBar,
|
|
9716
|
+
rest: {
|
|
9717
|
+
type: "invisible"
|
|
9718
|
+
},
|
|
9719
|
+
startChar: event.startChar,
|
|
9720
|
+
endChar: event.endChar
|
|
9721
|
+
});
|
|
9722
|
+
overlayVoice[k].voice.push(event);
|
|
9723
|
+
}
|
|
9724
|
+
durationThisBar = 0;
|
|
9725
|
+
} else if (event.el_type === "note") {
|
|
9726
|
+
if (inOverlay) {
|
|
9727
|
+
overlayVoice[k].voice.push(event);
|
|
9728
|
+
} else {
|
|
9729
|
+
durationThisBar += event.duration;
|
|
9730
|
+
durationsPerLines[i] += event.duration;
|
|
9731
|
+
}
|
|
9732
|
+
} else if (event.el_type === "scale" || event.el_type === "stem" || event.el_type === "overlay" || event.el_type === "style" || event.el_type === "transpose" || event.el_type === "color") {
|
|
9733
|
+
// These types of events are duplicated on the overlay layer.
|
|
9734
|
+
overlayVoice[k].voice.push(event);
|
|
9735
|
+
}
|
|
9736
|
+
}
|
|
9737
|
+
if (overlayVoice[k].hasOverlay && overlayVoice[k].snip.length === 0) {
|
|
9738
|
+
// there was no closing bar, so we didn't set the snip amount.
|
|
9739
|
+
overlayVoice[k].snip.push({
|
|
9740
|
+
start: snipStart,
|
|
9741
|
+
len: voice.length - snipStart
|
|
9742
|
+
});
|
|
9743
|
+
}
|
|
9744
|
+
}
|
|
9745
|
+
for (k = 0; k < overlayVoice.length; k++) {
|
|
9746
|
+
var ov = overlayVoice[k];
|
|
9747
|
+
if (ov.hasOverlay) {
|
|
9748
|
+
ov.voice.splice(0, 0, {
|
|
9749
|
+
el_type: "stem",
|
|
9750
|
+
direction: "down"
|
|
9751
|
+
});
|
|
9752
|
+
staff.voices.push(ov.voice);
|
|
9753
|
+
for (var kkk = ov.snip.length - 1; kkk >= 0; kkk--) {
|
|
9754
|
+
var snip = ov.snip[kkk];
|
|
9755
|
+
staff.voices[k].splice(snip.start, snip.len);
|
|
9756
|
+
staff.voices[k].splice(snip.start + 1, 0, {
|
|
9757
|
+
el_type: "stem",
|
|
9758
|
+
direction: "auto"
|
|
9759
|
+
});
|
|
9760
|
+
var indexOfLastBar = findLastBar(staff.voices[k], snip.start);
|
|
9761
|
+
staff.voices[k].splice(indexOfLastBar, 0, {
|
|
9762
|
+
el_type: "stem",
|
|
9763
|
+
direction: "up"
|
|
9764
|
+
});
|
|
9765
|
+
}
|
|
9766
|
+
// remove ending marks from the overlay voice so they are not repeated
|
|
9767
|
+
for (kkk = 0; kkk < staff.voices[staff.voices.length - 1].length; kkk++) {
|
|
9768
|
+
staff.voices[staff.voices.length - 1][kkk] = Object.assign({}, staff.voices[staff.voices.length - 1][kkk]);
|
|
9769
|
+
var el = staff.voices[staff.voices.length - 1][kkk];
|
|
9770
|
+
if (el.el_type === 'bar' && el.startEnding) {
|
|
9771
|
+
delete el.startEnding;
|
|
9772
|
+
}
|
|
9773
|
+
if (el.el_type === 'bar' && el.endEnding) delete el.endEnding;
|
|
9774
|
+
}
|
|
9775
|
+
}
|
|
9776
|
+
}
|
|
9777
|
+
}
|
|
9778
|
+
}
|
|
9779
|
+
}
|
|
9780
|
+
return madeChanges;
|
|
9781
|
+
}
|
|
9782
|
+
;
|
|
9783
|
+
function findLastBar(voice, start) {
|
|
9784
|
+
for (var i = start - 1; i > 0 && voice[i].el_type !== "bar"; i--) {}
|
|
9785
|
+
return i;
|
|
9786
|
+
}
|
|
9787
|
+
function fixTitles(lines) {
|
|
9788
|
+
// We might have name and subname defined. We now know what line everything is on, so we can determine which to use.
|
|
9789
|
+
var firstMusicLine = true;
|
|
9790
|
+
for (var i = 0; i < lines.length; i++) {
|
|
9791
|
+
var line = lines[i];
|
|
9792
|
+
if (line.staff) {
|
|
9793
|
+
for (var j = 0; j < line.staff.length; j++) {
|
|
9794
|
+
var staff = line.staff[j];
|
|
9795
|
+
if (staff.title) {
|
|
9796
|
+
var hasATitle = false;
|
|
9797
|
+
for (var k = 0; k < staff.title.length; k++) {
|
|
9798
|
+
if (staff.title[k]) {
|
|
9799
|
+
staff.title[k] = firstMusicLine ? staff.title[k].name : staff.title[k].subname;
|
|
9800
|
+
if (staff.title[k]) hasATitle = true;else staff.title[k] = '';
|
|
9801
|
+
} else staff.title[k] = '';
|
|
9802
|
+
}
|
|
9803
|
+
if (!hasATitle) delete staff.title;
|
|
9804
|
+
}
|
|
9805
|
+
}
|
|
9806
|
+
firstMusicLine = false;
|
|
9807
|
+
}
|
|
9808
|
+
}
|
|
9809
|
+
}
|
|
9810
|
+
function cleanUpSlursInLine(line, staffNum, voiceNum, currSlur) {
|
|
9811
|
+
if (!currSlur[staffNum]) currSlur[staffNum] = [];
|
|
9812
|
+
if (!currSlur[staffNum][voiceNum]) currSlur[staffNum][voiceNum] = [];
|
|
9813
|
+
var x;
|
|
9814
|
+
// var lyr = null; // TODO-PER: debugging.
|
|
9815
|
+
|
|
9816
|
+
var addEndSlur = function addEndSlur(obj, num, chordPos) {
|
|
9817
|
+
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9818
|
+
// There isn't an exact match for note position, but we'll take any other open slur.
|
|
9819
|
+
for (x = 0; x < currSlur[staffNum][voiceNum].length; x++) {
|
|
9820
|
+
if (currSlur[staffNum][voiceNum][x] !== undefined) {
|
|
9821
|
+
chordPos = x;
|
|
9822
|
+
break;
|
|
9823
|
+
}
|
|
9824
|
+
}
|
|
9825
|
+
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9826
|
+
var offNum = chordPos * 100 + 1;
|
|
9827
|
+
obj.endSlur.forEach(function (x) {
|
|
9828
|
+
if (offNum === x) --offNum;
|
|
9829
|
+
});
|
|
9830
|
+
currSlur[staffNum][voiceNum][chordPos] = [offNum];
|
|
9831
|
+
}
|
|
9832
|
+
}
|
|
9833
|
+
var slurNum;
|
|
9834
|
+
for (var i = 0; i < num; i++) {
|
|
9835
|
+
slurNum = currSlur[staffNum][voiceNum][chordPos].pop();
|
|
9836
|
+
obj.endSlur.push(slurNum);
|
|
9837
|
+
// lyr.syllable += '<' + slurNum; // TODO-PER: debugging
|
|
9838
|
+
}
|
|
9839
|
+
if (currSlur[staffNum][voiceNum][chordPos].length === 0) delete currSlur[staffNum][voiceNum][chordPos];
|
|
9840
|
+
return slurNum;
|
|
9841
|
+
};
|
|
9842
|
+
var addStartSlur = function addStartSlur(obj, num, chordPos, usedNums) {
|
|
9843
|
+
obj.startSlur = [];
|
|
9844
|
+
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9845
|
+
currSlur[staffNum][voiceNum][chordPos] = [];
|
|
9846
|
+
}
|
|
9847
|
+
var nextNum = chordPos * 100 + 1;
|
|
9848
|
+
for (var i = 0; i < num; i++) {
|
|
9849
|
+
if (usedNums) {
|
|
9850
|
+
usedNums.forEach(function (x) {
|
|
9851
|
+
if (nextNum === x) ++nextNum;
|
|
9852
|
+
});
|
|
9853
|
+
usedNums.forEach(function (x) {
|
|
9854
|
+
if (nextNum === x) ++nextNum;
|
|
9855
|
+
});
|
|
9856
|
+
usedNums.forEach(function (x) {
|
|
9857
|
+
if (nextNum === x) ++nextNum;
|
|
9858
|
+
});
|
|
9859
|
+
}
|
|
9860
|
+
currSlur[staffNum][voiceNum][chordPos].forEach(function (x) {
|
|
9861
|
+
if (nextNum === x) ++nextNum;
|
|
9862
|
+
});
|
|
9863
|
+
currSlur[staffNum][voiceNum][chordPos].forEach(function (x) {
|
|
9864
|
+
if (nextNum === x) ++nextNum;
|
|
9865
|
+
});
|
|
9866
|
+
currSlur[staffNum][voiceNum][chordPos].push(nextNum);
|
|
9867
|
+
obj.startSlur.push({
|
|
9868
|
+
label: nextNum
|
|
9869
|
+
});
|
|
9870
|
+
if (obj.dottedSlur) {
|
|
9871
|
+
obj.startSlur[obj.startSlur.length - 1].style = 'dotted';
|
|
9872
|
+
delete obj.dottedSlur;
|
|
9873
|
+
}
|
|
9874
|
+
// lyr.syllable += ' ' + nextNum + '>'; // TODO-PER:debugging
|
|
9875
|
+
nextNum++;
|
|
9876
|
+
}
|
|
9877
|
+
};
|
|
9878
|
+
for (var i = 0; i < line.length; i++) {
|
|
9879
|
+
var el = line[i];
|
|
9880
|
+
// if (el.lyric === undefined) // TODO-PER: debugging
|
|
9881
|
+
// el.lyric = [{ divider: '-' }]; // TODO-PER: debugging
|
|
9882
|
+
// lyr = el.lyric[0]; // TODO-PER: debugging
|
|
9883
|
+
// lyr.syllable = ''; // TODO-PER: debugging
|
|
9884
|
+
if (el.el_type === 'note') {
|
|
9885
|
+
if (el.gracenotes) {
|
|
9886
|
+
for (var g = 0; g < el.gracenotes.length; g++) {
|
|
9887
|
+
if (el.gracenotes[g].endSlur) {
|
|
9888
|
+
var gg = el.gracenotes[g].endSlur;
|
|
9889
|
+
el.gracenotes[g].endSlur = [];
|
|
9890
|
+
for (var ggg = 0; ggg < gg; ggg++) {
|
|
9891
|
+
addEndSlur(el.gracenotes[g], 1, 20);
|
|
9892
|
+
}
|
|
9893
|
+
}
|
|
9894
|
+
if (el.gracenotes[g].startSlur) {
|
|
9895
|
+
x = el.gracenotes[g].startSlur;
|
|
9896
|
+
addStartSlur(el.gracenotes[g], x, 20);
|
|
9897
|
+
}
|
|
9898
|
+
}
|
|
9899
|
+
}
|
|
9900
|
+
if (el.endSlur) {
|
|
9901
|
+
x = el.endSlur;
|
|
9902
|
+
el.endSlur = [];
|
|
9903
|
+
addEndSlur(el, x, 0);
|
|
9904
|
+
}
|
|
9905
|
+
if (el.startSlur) {
|
|
9906
|
+
x = el.startSlur;
|
|
9907
|
+
addStartSlur(el, x, 0);
|
|
9908
|
+
}
|
|
9909
|
+
if (el.pitches) {
|
|
9910
|
+
var usedNums = [];
|
|
9911
|
+
for (var p = 0; p < el.pitches.length; p++) {
|
|
9912
|
+
if (el.pitches[p].endSlur) {
|
|
9913
|
+
var k = el.pitches[p].endSlur;
|
|
9914
|
+
el.pitches[p].endSlur = [];
|
|
9915
|
+
for (var j = 0; j < k; j++) {
|
|
9916
|
+
var slurNum = addEndSlur(el.pitches[p], 1, p + 1);
|
|
9917
|
+
usedNums.push(slurNum);
|
|
9918
|
+
}
|
|
9919
|
+
}
|
|
9920
|
+
}
|
|
9921
|
+
for (p = 0; p < el.pitches.length; p++) {
|
|
9922
|
+
if (el.pitches[p].startSlur) {
|
|
9923
|
+
x = el.pitches[p].startSlur;
|
|
9924
|
+
addStartSlur(el.pitches[p], x, p + 1, usedNums);
|
|
9925
|
+
}
|
|
9926
|
+
}
|
|
9927
|
+
// Correct for the weird gracenote case where ({g}a) should match.
|
|
9928
|
+
// The end slur was already assigned to the note, and needs to be moved to the first note of the graces.
|
|
9929
|
+
if (el.gracenotes && el.pitches[0].endSlur && el.pitches[0].endSlur[0] === 100 && el.pitches[0].startSlur) {
|
|
9930
|
+
if (el.gracenotes[0].endSlur) el.gracenotes[0].endSlur.push(el.pitches[0].startSlur[0].label);else el.gracenotes[0].endSlur = [el.pitches[0].startSlur[0].label];
|
|
9931
|
+
if (el.pitches[0].endSlur.length === 1) delete el.pitches[0].endSlur;else if (el.pitches[0].endSlur[0] === 100) el.pitches[0].endSlur.shift();else if (el.pitches[0].endSlur[el.pitches[0].endSlur.length - 1] === 100) el.pitches[0].endSlur.pop();
|
|
9932
|
+
if (currSlur[staffNum][voiceNum][1].length === 1) delete currSlur[staffNum][voiceNum][1];else currSlur[staffNum][voiceNum][1].pop();
|
|
9933
|
+
}
|
|
9934
|
+
}
|
|
9935
|
+
}
|
|
9936
|
+
}
|
|
9937
|
+
}
|
|
9938
|
+
function wrapMusicLines(lines, barsperstaff) {
|
|
9939
|
+
for (i = 0; i < lines.length; i++) {
|
|
9940
|
+
if (lines[i].staff !== undefined) {
|
|
9941
|
+
for (s = 0; s < lines[i].staff.length; s++) {
|
|
9942
|
+
var permanentItems = [];
|
|
9943
|
+
for (v = 0; v < lines[i].staff[s].voices.length; v++) {
|
|
9944
|
+
var voice = lines[i].staff[s].voices[v];
|
|
9945
|
+
var barNumThisLine = 0;
|
|
9946
|
+
for (var n = 0; n < voice.length; n++) {
|
|
9947
|
+
if (voice[n].el_type === 'bar') {
|
|
9948
|
+
barNumThisLine++;
|
|
9949
|
+
if (barNumThisLine >= barsperstaff) {
|
|
9950
|
+
// push everything else to the next line, if there is anything else,
|
|
9951
|
+
// and there is a next line. If there isn't a next line, create one.
|
|
9952
|
+
if (n < voice.length - 1) {
|
|
9953
|
+
var nextLine = getNextMusicLine(lines, i);
|
|
9954
|
+
if (!nextLine) {
|
|
9955
|
+
var cp = JSON.parse(JSON.stringify(lines[i]));
|
|
9956
|
+
lines.push(Object.assign({}, cp));
|
|
9957
|
+
nextLine = lines[lines.length - 1];
|
|
9958
|
+
for (var ss = 0; ss < nextLine.staff.length; ss++) {
|
|
9959
|
+
for (var vv = 0; vv < nextLine.staff[ss].voices.length; vv++) {
|
|
9960
|
+
nextLine.staff[ss].voices[vv] = [];
|
|
9961
|
+
}
|
|
9962
|
+
}
|
|
9963
|
+
}
|
|
9964
|
+
var startElement = n + 1;
|
|
9965
|
+
var section = lines[i].staff[s].voices[v].slice(startElement);
|
|
9966
|
+
lines[i].staff[s].voices[v] = lines[i].staff[s].voices[v].slice(0, startElement);
|
|
9967
|
+
nextLine.staff[s].voices[v] = permanentItems.concat(section.concat(nextLine.staff[s].voices[v]));
|
|
9968
|
+
return true;
|
|
9969
|
+
}
|
|
9970
|
+
}
|
|
9971
|
+
} else if (!voice[n].duration) {
|
|
9972
|
+
permanentItems.push(voice[n]);
|
|
9973
|
+
}
|
|
9974
|
+
}
|
|
9975
|
+
}
|
|
9976
|
+
}
|
|
9977
|
+
}
|
|
9978
|
+
}
|
|
9979
|
+
return false;
|
|
9980
|
+
}
|
|
9981
|
+
function getNextMusicLine(lines, currentLine) {
|
|
9982
|
+
currentLine++;
|
|
9983
|
+
while (lines.length > currentLine) {
|
|
9984
|
+
if (lines[currentLine].staff) return lines[currentLine];
|
|
9985
|
+
currentLine++;
|
|
9986
|
+
}
|
|
9987
|
+
return null;
|
|
9988
|
+
}
|
|
9989
|
+
function getLastNote(tune) {
|
|
9990
|
+
if (!tune.lines[tune.lineNum]) return null;
|
|
9991
|
+
if (!tune.lines[tune.lineNum].staff) return null;
|
|
9992
|
+
if (!tune.lines[tune.lineNum].staff[tune.staffNum]) return null;
|
|
9993
|
+
var voice = tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum];
|
|
9994
|
+
if (!voice) return null;
|
|
9995
|
+
for (var i = voice.length - 1; i >= 0; i--) {
|
|
9996
|
+
var el = voice[i];
|
|
9997
|
+
if (el.el_type === 'note') {
|
|
9998
|
+
return el;
|
|
9999
|
+
}
|
|
10000
|
+
}
|
|
10001
|
+
return null;
|
|
10002
|
+
}
|
|
10003
|
+
;
|
|
10004
|
+
function getDuration(el) {
|
|
10005
|
+
if (el.duration) return el.duration;
|
|
10006
|
+
return 0;
|
|
10007
|
+
}
|
|
10008
|
+
;
|
|
10009
|
+
function closeLine(tune) {
|
|
10010
|
+
if (tune.potentialStartBeam && tune.potentialEndBeam) {
|
|
10011
|
+
tune.potentialStartBeam.startBeam = true;
|
|
10012
|
+
tune.potentialEndBeam.endBeam = true;
|
|
10013
|
+
}
|
|
10014
|
+
delete tune.potentialStartBeam;
|
|
10015
|
+
delete tune.potentialEndBeam;
|
|
10016
|
+
}
|
|
10017
|
+
;
|
|
10018
|
+
function containsNotes(voice) {
|
|
10019
|
+
for (var i = 0; i < voice.length; i++) {
|
|
10020
|
+
if (voice[i].el_type === 'note' || voice[i].el_type === 'bar') return true;
|
|
10021
|
+
}
|
|
10022
|
+
return false;
|
|
10023
|
+
}
|
|
10024
|
+
;
|
|
10025
|
+
function containsNotesStrict(voice) {
|
|
10026
|
+
for (var i = 0; i < voice.length; i++) {
|
|
10027
|
+
if (voice[i].el_type === 'note' && (voice[i].rest === undefined || voice[i].chord !== undefined)) return true;
|
|
10028
|
+
}
|
|
10029
|
+
return false;
|
|
10030
|
+
}
|
|
10031
|
+
;
|
|
10032
|
+
function pushLine(tune, hash) {
|
|
10033
|
+
if (tune.vskipPending) {
|
|
10034
|
+
hash.vskip = tune.vskipPending;
|
|
10035
|
+
delete tune.vskipPending;
|
|
10036
|
+
}
|
|
10037
|
+
tune.lines.push(hash);
|
|
10038
|
+
}
|
|
10039
|
+
;
|
|
10040
|
+
function pushNote(self, tune, hp, voiceDefs, currentVoiceName) {
|
|
10041
|
+
//console.log("pushNote", tune.lineNum, tune.staffNum, hp.pitches ? JSON.stringify(hp.pitches) : hp.pitches)
|
|
10042
|
+
var currStaff = tune.lines[tune.lineNum].staff[tune.staffNum];
|
|
10043
|
+
if (hp.pitches !== undefined) {
|
|
10044
|
+
var mid = currStaff.workingClef.verticalPos;
|
|
10045
|
+
hp.pitches.forEach(function (p) {
|
|
10046
|
+
p.verticalPos = p.pitch - mid;
|
|
10047
|
+
});
|
|
10048
|
+
}
|
|
10049
|
+
if (hp.gracenotes !== undefined) {
|
|
10050
|
+
var mid2 = currStaff.workingClef.verticalPos;
|
|
10051
|
+
hp.gracenotes.forEach(function (p) {
|
|
10052
|
+
p.verticalPos = p.pitch - mid2;
|
|
10053
|
+
});
|
|
10054
|
+
}
|
|
10055
|
+
if (currStaff.voices.length <= tune.voiceNum) {
|
|
10056
|
+
//console.log("should create?", currentVoiceName, voiceDefs)
|
|
10057
|
+
if (!voiceDefs[currentVoiceName]) voiceDefs[currentVoiceName] = {};
|
|
10058
|
+
createVoice(self, tune, voiceDefs[currentVoiceName]);
|
|
10059
|
+
}
|
|
10060
|
+
currStaff.voices[tune.voiceNum].push(hp);
|
|
10061
|
+
}
|
|
10062
|
+
function endBeamHere(hashParams, tune) {
|
|
10063
|
+
tune.potentialStartBeam.startBeam = true;
|
|
10064
|
+
hashParams.endBeam = true;
|
|
10065
|
+
delete tune.potentialStartBeam;
|
|
10066
|
+
delete tune.potentialEndBeam;
|
|
10067
|
+
}
|
|
10068
|
+
function endBeamLast(tune) {
|
|
10069
|
+
if (tune.potentialStartBeam !== undefined && tune.potentialEndBeam !== undefined) {
|
|
10070
|
+
// Do we have a set of notes to beam?
|
|
10071
|
+
tune.potentialStartBeam.startBeam = true;
|
|
10072
|
+
tune.potentialEndBeam.endBeam = true;
|
|
10073
|
+
}
|
|
10074
|
+
delete tune.potentialStartBeam;
|
|
10075
|
+
delete tune.potentialEndBeam;
|
|
10076
|
+
}
|
|
10077
|
+
function setLineFont(tune, type, font) {
|
|
10078
|
+
// If we haven't encountered the font type yet then we are using the default font so it doesn't
|
|
10079
|
+
// need to be noted. If we have encountered it, then only record it if it is different from the last time.
|
|
10080
|
+
if (tune.runningFonts[type]) {
|
|
10081
|
+
var isDifferent = false;
|
|
10082
|
+
var keys = Object.keys(font);
|
|
10083
|
+
for (var i = 0; i < keys.length; i++) {
|
|
10084
|
+
if (tune.runningFonts[type][keys[i]] !== font[keys[i]]) isDifferent = true;
|
|
10085
|
+
}
|
|
10086
|
+
if (isDifferent) {
|
|
10087
|
+
tune.lines[tune.lineNum].staff[tune.staffNum][type] = font;
|
|
10088
|
+
}
|
|
10089
|
+
}
|
|
10090
|
+
tune.runningFonts[type] = font;
|
|
10091
|
+
}
|
|
10092
|
+
function createVoice(self, tune, params) {
|
|
10093
|
+
//console.log("createVoice", params)
|
|
10094
|
+
var thisStaff = tune.lines[tune.lineNum].staff[tune.staffNum];
|
|
10095
|
+
thisStaff.voices[tune.voiceNum] = [];
|
|
10096
|
+
if (!thisStaff.title) thisStaff.title = [];
|
|
10097
|
+
thisStaff.title[tune.voiceNum] = {
|
|
10098
|
+
name: params.name,
|
|
10099
|
+
subname: params.subname
|
|
10100
|
+
};
|
|
10101
|
+
if (params.style) self.appendElement('style', null, null, {
|
|
10102
|
+
head: params.style
|
|
10103
|
+
});
|
|
10104
|
+
if (params.stem) self.appendElement('stem', null, null, {
|
|
10105
|
+
direction: params.stem
|
|
10106
|
+
});else if (tune.voiceNum > 0) {
|
|
10107
|
+
if (thisStaff.voices[0] !== undefined) {
|
|
10108
|
+
var found = false;
|
|
10109
|
+
for (var i = 0; i < thisStaff.voices[0].length; i++) {
|
|
10110
|
+
if (thisStaff.voices[0].el_type === 'stem') found = true;
|
|
10111
|
+
}
|
|
10112
|
+
if (!found) {
|
|
10113
|
+
var stem = {
|
|
10114
|
+
el_type: 'stem',
|
|
10115
|
+
direction: 'up'
|
|
10116
|
+
};
|
|
10117
|
+
thisStaff.voices[0].splice(0, 0, stem);
|
|
10283
10118
|
}
|
|
10284
10119
|
}
|
|
10120
|
+
self.appendElement('stem', null, null, {
|
|
10121
|
+
direction: 'down'
|
|
10122
|
+
});
|
|
10123
|
+
}
|
|
10124
|
+
if (params.scale) self.appendElement('scale', null, null, {
|
|
10125
|
+
size: params.scale
|
|
10126
|
+
});
|
|
10127
|
+
if (params.color) self.appendElement('color', null, null, {
|
|
10128
|
+
color: params.color
|
|
10129
|
+
});
|
|
10130
|
+
}
|
|
10131
|
+
function createStaff(self, tune, params) {
|
|
10132
|
+
if (params.key && params.key.impliedNaturals) {
|
|
10133
|
+
params.key.accidentals = params.key.accidentals.concat(params.key.impliedNaturals);
|
|
10134
|
+
delete params.key.impliedNaturals;
|
|
10135
|
+
}
|
|
10136
|
+
tune.lines[tune.lineNum].staff[tune.staffNum] = {
|
|
10137
|
+
voices: [],
|
|
10138
|
+
clef: params.clef,
|
|
10139
|
+
key: params.key,
|
|
10140
|
+
workingClef: params.clef
|
|
10141
|
+
};
|
|
10142
|
+
var staff = tune.lines[tune.lineNum].staff[tune.staffNum];
|
|
10143
|
+
if (params.stafflines !== undefined) {
|
|
10144
|
+
staff.clef.stafflines = params.stafflines;
|
|
10145
|
+
staff.workingClef.stafflines = params.stafflines;
|
|
10146
|
+
}
|
|
10147
|
+
if (params.staffscale) {
|
|
10148
|
+
staff.staffscale = params.staffscale;
|
|
10149
|
+
}
|
|
10150
|
+
if (params.annotationfont) setLineFont(tune, "annotationfont", params.annotationfont);
|
|
10151
|
+
if (params.gchordfont) setLineFont(tune, "gchordfont", params.gchordfont);
|
|
10152
|
+
if (params.tripletfont) setLineFont(tune, "tripletfont", params.tripletfont);
|
|
10153
|
+
if (params.vocalfont) setLineFont(tune, "vocalfont", params.vocalfont);
|
|
10154
|
+
if (params.bracket) staff.bracket = params.bracket;
|
|
10155
|
+
if (params.brace) staff.brace = params.brace;
|
|
10156
|
+
if (params.connectBarLines) staff.connectBarLines = params.connectBarLines;
|
|
10157
|
+
if (params.barNumber) staff.barNumber = params.barNumber;
|
|
10158
|
+
createVoice(self, tune, params);
|
|
10159
|
+
// Some stuff just happens for the first voice
|
|
10160
|
+
if (params.part) self.appendElement('part', params.part.startChar, params.part.endChar, {
|
|
10161
|
+
title: params.part.title
|
|
10162
|
+
});
|
|
10163
|
+
if (params.meter !== undefined) staff.meter = params.meter;
|
|
10164
|
+
if (tune.vskipPending) {
|
|
10165
|
+
tune.lines[tune.lineNum].vskip = tune.vskipPending;
|
|
10166
|
+
delete tune.vskipPending;
|
|
10285
10167
|
}
|
|
10286
10168
|
}
|
|
10169
|
+
function createLine(self, tune, params) {
|
|
10170
|
+
tune.lines[tune.lineNum] = {
|
|
10171
|
+
staff: []
|
|
10172
|
+
};
|
|
10173
|
+
createStaff(self, tune, params);
|
|
10174
|
+
}
|
|
10287
10175
|
module.exports = TuneBuilder;
|
|
10288
10176
|
|
|
10289
10177
|
/***/ }),
|
|
@@ -11197,7 +11085,6 @@ var strTranspose;
|
|
|
11197
11085
|
return 0;
|
|
11198
11086
|
// this should never happen
|
|
11199
11087
|
}
|
|
11200
|
-
|
|
11201
11088
|
case '_':
|
|
11202
11089
|
switch (thisAccidental) {
|
|
11203
11090
|
case '__':
|
|
@@ -11214,7 +11101,6 @@ var strTranspose;
|
|
|
11214
11101
|
return 0;
|
|
11215
11102
|
// this should never happen
|
|
11216
11103
|
}
|
|
11217
|
-
|
|
11218
11104
|
case '^':
|
|
11219
11105
|
switch (thisAccidental) {
|
|
11220
11106
|
case '__':
|
|
@@ -11232,11 +11118,9 @@ var strTranspose;
|
|
|
11232
11118
|
// this should never happen
|
|
11233
11119
|
}
|
|
11234
11120
|
}
|
|
11235
|
-
|
|
11236
11121
|
return 0; // this should never happen
|
|
11237
11122
|
}
|
|
11238
11123
|
})();
|
|
11239
|
-
|
|
11240
11124
|
module.exports = strTranspose;
|
|
11241
11125
|
|
|
11242
11126
|
/***/ }),
|
|
@@ -11452,6 +11336,7 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
|
|
|
11452
11336
|
case "chordprog":
|
|
11453
11337
|
case "bassvol":
|
|
11454
11338
|
case "chordvol":
|
|
11339
|
+
case "gchordbars":
|
|
11455
11340
|
chordTrack.paramChange(element);
|
|
11456
11341
|
break;
|
|
11457
11342
|
default:
|
|
@@ -11560,7 +11445,6 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
|
|
|
11560
11445
|
// console.log(JSON.stringify(voices))
|
|
11561
11446
|
}
|
|
11562
11447
|
}
|
|
11563
|
-
|
|
11564
11448
|
function getBeatFraction(meter) {
|
|
11565
11449
|
switch (parseInt(meter.den, 10)) {
|
|
11566
11450
|
case 2:
|
|
@@ -11581,7 +11465,8 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
|
|
|
11581
11465
|
function processVolume(beat, voiceOff) {
|
|
11582
11466
|
if (voiceOff) return 0;
|
|
11583
11467
|
var volume;
|
|
11584
|
-
|
|
11468
|
+
// MAE 21 Jun 2024 - This previously wasn't allowing zero volume to be applied
|
|
11469
|
+
if (nextVolume != undefined) {
|
|
11585
11470
|
volume = nextVolume;
|
|
11586
11471
|
nextVolume = undefined;
|
|
11587
11472
|
} else if (!doBeatAccents) {
|
|
@@ -12335,7 +12220,6 @@ var rendererFactory;
|
|
|
12335
12220
|
this.track += this.noteOnAndChannel;
|
|
12336
12221
|
this.track += "%" + pitch.toString(16) + toHex(loudness, 2); //note
|
|
12337
12222
|
};
|
|
12338
|
-
|
|
12339
12223
|
Midi.prototype.endNote = function (pitch) {
|
|
12340
12224
|
this.track += toDurationHex(this.silencelength); // only need to shift by amount of silence (if there is any)
|
|
12341
12225
|
this.silencelength = 0;
|
|
@@ -12349,7 +12233,6 @@ var rendererFactory;
|
|
|
12349
12233
|
this.track += this.noteOffAndChannel;
|
|
12350
12234
|
this.track += "%" + pitch.toString(16) + "%00"; //end note
|
|
12351
12235
|
};
|
|
12352
|
-
|
|
12353
12236
|
Midi.prototype.addRest = function (length) {
|
|
12354
12237
|
this.silencelength += length;
|
|
12355
12238
|
if (this.silencelength < 0) this.silencelength = 0;
|
|
@@ -12386,7 +12269,6 @@ var rendererFactory;
|
|
|
12386
12269
|
}
|
|
12387
12270
|
return "%00%FF" + cmdType + toHex(nameArray.length / 3, 2) + nameArray; // Each byte is represented by three chars "%XX", so divide by 3 to get the length.
|
|
12388
12271
|
}
|
|
12389
|
-
|
|
12390
12272
|
function keySignature(key) {
|
|
12391
12273
|
//00 FF 5902 03 00 - key signature
|
|
12392
12274
|
if (!key || !key.accidentals) return "";
|
|
@@ -12914,7 +12796,7 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
|
|
|
12914
12796
|
if (!e) e = voices[voiceNumber].length; // If there wasn't a first ending marker, then we copy everything.
|
|
12915
12797
|
// duplicate each of the elements - this has to be a deep copy.
|
|
12916
12798
|
for (var z = s; z < e; z++) {
|
|
12917
|
-
var item =
|
|
12799
|
+
var item = Object.assign({}, voices[voiceNumber][z]);
|
|
12918
12800
|
if (item.pitches) item.pitches = parseCommon.cloneArray(item.pitches);
|
|
12919
12801
|
voices[voiceNumber].push(item);
|
|
12920
12802
|
}
|
|
@@ -13023,8 +12905,6 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
|
|
|
13023
12905
|
break;
|
|
13024
12906
|
case "swing":
|
|
13025
12907
|
case "gchord":
|
|
13026
|
-
case "bassprog":
|
|
13027
|
-
case "chordprog":
|
|
13028
12908
|
case "bassvol":
|
|
13029
12909
|
case "chordvol":
|
|
13030
12910
|
voices[voiceNumber].push({
|
|
@@ -13032,6 +12912,23 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
|
|
|
13032
12912
|
param: elem.params[0]
|
|
13033
12913
|
});
|
|
13034
12914
|
break;
|
|
12915
|
+
case "bassprog": // MAE 22 May 2024
|
|
12916
|
+
case "chordprog":
|
|
12917
|
+
// MAE 22 May 2024
|
|
12918
|
+
voices[voiceNumber].push({
|
|
12919
|
+
el_type: elem.cmd,
|
|
12920
|
+
value: elem.params[0],
|
|
12921
|
+
octaveShift: elem.params[1]
|
|
12922
|
+
});
|
|
12923
|
+
break;
|
|
12924
|
+
|
|
12925
|
+
// MAE 23 Jun 2024
|
|
12926
|
+
case "gchordbars":
|
|
12927
|
+
voices[voiceNumber].push({
|
|
12928
|
+
el_type: elem.cmd,
|
|
12929
|
+
param: elem.params[0]
|
|
12930
|
+
});
|
|
12931
|
+
break;
|
|
13035
12932
|
default:
|
|
13036
12933
|
console.log("MIDI seq: midi cmd not handled: ", elem.cmd, elem);
|
|
13037
12934
|
}
|
|
@@ -13161,7 +13058,6 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
|
|
|
13161
13058
|
}
|
|
13162
13059
|
}
|
|
13163
13060
|
}
|
|
13164
|
-
|
|
13165
13061
|
function chordVoiceOffThisBar(voices) {
|
|
13166
13062
|
for (var i = 0; i < voices.length; i++) {
|
|
13167
13063
|
var voice = voices[i];
|
|
@@ -13304,7 +13200,7 @@ module.exports = centsToFactor;
|
|
|
13304
13200
|
/*!**********************************!*\
|
|
13305
13201
|
!*** ./src/synth/chord-track.js ***!
|
|
13306
13202
|
\**********************************/
|
|
13307
|
-
/***/ (function(module
|
|
13203
|
+
/***/ (function(module) {
|
|
13308
13204
|
|
|
13309
13205
|
//
|
|
13310
13206
|
// The algorithm for chords is:
|
|
@@ -13325,7 +13221,6 @@ module.exports = centsToFactor;
|
|
|
13325
13221
|
//
|
|
13326
13222
|
// If there is any note in the melody that has a rhythm head, then assume the melody controls the rhythm, so there is no chord added for that entire measure.
|
|
13327
13223
|
|
|
13328
|
-
var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/abc_common.js");
|
|
13329
13224
|
var ChordTrack = function ChordTrack(numVoices, chordsOff, midiOptions, meter) {
|
|
13330
13225
|
this.chordTrack = [];
|
|
13331
13226
|
this.chordTrackFinished = false;
|
|
@@ -13340,11 +13235,23 @@ var ChordTrack = function ChordTrack(numVoices, chordsOff, midiOptions, meter) {
|
|
|
13340
13235
|
this.lastBarTime = 0;
|
|
13341
13236
|
this.meter = meter;
|
|
13342
13237
|
this.tempoChangeFactor = 1;
|
|
13343
|
-
|
|
13344
|
-
|
|
13238
|
+
|
|
13239
|
+
// MAE 17 Jun 2024 - To allow for bass and chord instrument octave shifts
|
|
13240
|
+
this.bassInstrument = midiOptions.bassprog && midiOptions.bassprog.length >= 1 ? midiOptions.bassprog[0] : 0;
|
|
13241
|
+
this.chordInstrument = midiOptions.chordprog && midiOptions.chordprog.length >= 1 ? midiOptions.chordprog[0] : 0;
|
|
13242
|
+
|
|
13243
|
+
// MAE For octave shifted bass and chords
|
|
13244
|
+
this.bassOctaveShift = midiOptions.bassprog && midiOptions.bassprog.length === 2 ? midiOptions.bassprog[1] : 0;
|
|
13245
|
+
this.chordOctaveShift = midiOptions.chordprog && midiOptions.chordprog.length === 2 ? midiOptions.chordprog[1] : 0;
|
|
13345
13246
|
this.boomVolume = midiOptions.bassvol && midiOptions.bassvol.length === 1 ? midiOptions.bassvol[0] : 64;
|
|
13346
13247
|
this.chickVolume = midiOptions.chordvol && midiOptions.chordvol.length === 1 ? midiOptions.chordvol[0] : 48;
|
|
13347
|
-
|
|
13248
|
+
|
|
13249
|
+
// This allows for an initial %%MIDI gchord with no string
|
|
13250
|
+
if (midiOptions.gchord && midiOptions.gchord.length > 0) {
|
|
13251
|
+
this.overridePattern = parseGChord(midiOptions.gchord[0]);
|
|
13252
|
+
} else {
|
|
13253
|
+
this.overridePattern = undefined;
|
|
13254
|
+
}
|
|
13348
13255
|
};
|
|
13349
13256
|
ChordTrack.prototype.setMeter = function (meter) {
|
|
13350
13257
|
this.meter = meter;
|
|
@@ -13364,7 +13271,7 @@ ChordTrack.prototype.setRhythmHead = function (isRhythmHead, elem) {
|
|
|
13364
13271
|
if (isRhythmHead) {
|
|
13365
13272
|
if (this.lastChord && this.lastChord.chick) {
|
|
13366
13273
|
for (var i2 = 0; i2 < this.lastChord.chick.length; i2++) {
|
|
13367
|
-
var note2 =
|
|
13274
|
+
var note2 = Object.assign({}, elem.pitches[0]);
|
|
13368
13275
|
note2.actualPitch = this.lastChord.chick[i2];
|
|
13369
13276
|
ePitches.push(note2);
|
|
13370
13277
|
}
|
|
@@ -13385,13 +13292,29 @@ ChordTrack.prototype.gChordOn = function (element) {
|
|
|
13385
13292
|
ChordTrack.prototype.paramChange = function (element) {
|
|
13386
13293
|
switch (element.el_type) {
|
|
13387
13294
|
case "gchord":
|
|
13388
|
-
|
|
13295
|
+
// Skips gchord elements that don't have pattern strings
|
|
13296
|
+
if (element.param && element.param.length > 0) {
|
|
13297
|
+
this.overridePattern = parseGChord(element.param);
|
|
13298
|
+
|
|
13299
|
+
// Generate a default duration scale based on the pattern
|
|
13300
|
+
//this.gchordduration = generateDefaultDurationScale(element.param);
|
|
13301
|
+
} else this.overridePattern = undefined;
|
|
13389
13302
|
break;
|
|
13390
13303
|
case "bassprog":
|
|
13391
|
-
this.bassInstrument = element.
|
|
13304
|
+
this.bassInstrument = element.value;
|
|
13305
|
+
if (element.octaveShift != undefined && element.octaveShift != null) {
|
|
13306
|
+
this.bassOctaveShift = element.octaveShift;
|
|
13307
|
+
} else {
|
|
13308
|
+
this.bassOctaveShift = 0;
|
|
13309
|
+
}
|
|
13392
13310
|
break;
|
|
13393
13311
|
case "chordprog":
|
|
13394
|
-
this.chordInstrument = element.
|
|
13312
|
+
this.chordInstrument = element.value;
|
|
13313
|
+
if (element.octaveShift != undefined && element.octaveShift != null) {
|
|
13314
|
+
this.chordOctaveShift = element.octaveShift;
|
|
13315
|
+
} else {
|
|
13316
|
+
this.chordOctaveShift = 0;
|
|
13317
|
+
}
|
|
13395
13318
|
break;
|
|
13396
13319
|
case "bassvol":
|
|
13397
13320
|
this.boomVolume = element.param;
|
|
@@ -13459,22 +13382,36 @@ ChordTrack.prototype.interpretChord = function (name) {
|
|
|
13459
13382
|
chordTranspose -= 12;
|
|
13460
13383
|
}
|
|
13461
13384
|
bass += chordTranspose;
|
|
13385
|
+
|
|
13386
|
+
// MAE 31 Aug 2024 - For visual transpose backup range issue
|
|
13387
|
+
// If transposed below A or above G, bring it back in the normal backup range
|
|
13388
|
+
if (bass < 33) {
|
|
13389
|
+
bass += 12;
|
|
13390
|
+
} else if (bass > 44) {
|
|
13391
|
+
bass -= 12;
|
|
13392
|
+
}
|
|
13393
|
+
|
|
13394
|
+
// MAE 17 Jun 2024 - Supporting octave shifted bass and chords
|
|
13395
|
+
var unshiftedBass = bass;
|
|
13396
|
+
bass += this.bassOctaveShift * 12;
|
|
13462
13397
|
var bass2 = bass - 5; // The alternating bass is a 4th below
|
|
13463
13398
|
var chick;
|
|
13464
13399
|
if (name.length === 1) chick = this.chordNotes(bass, '');
|
|
13465
13400
|
var remaining = name.substring(1);
|
|
13466
13401
|
var acc = remaining.substring(0, 1);
|
|
13467
13402
|
if (acc === 'b' || acc === '♭') {
|
|
13403
|
+
unshiftedBass--;
|
|
13468
13404
|
bass--;
|
|
13469
13405
|
bass2--;
|
|
13470
13406
|
remaining = remaining.substring(1);
|
|
13471
13407
|
} else if (acc === '#' || acc === '♯') {
|
|
13408
|
+
unshiftedBass++;
|
|
13472
13409
|
bass++;
|
|
13473
13410
|
bass2++;
|
|
13474
13411
|
remaining = remaining.substring(1);
|
|
13475
13412
|
}
|
|
13476
13413
|
var arr = remaining.split('/');
|
|
13477
|
-
chick = this.chordNotes(
|
|
13414
|
+
chick = this.chordNotes(unshiftedBass, arr[0]);
|
|
13478
13415
|
// If the 5th is altered then the bass is altered. Normally the bass is 7 from the root, so adjust if it isn't.
|
|
13479
13416
|
if (chick.length >= 3) {
|
|
13480
13417
|
var fifth = chick[2] - chick[0];
|
|
@@ -13491,6 +13428,9 @@ ChordTrack.prototype.interpretChord = function (name) {
|
|
|
13491
13428
|
'♭': -1
|
|
13492
13429
|
}[bassAcc] || 0;
|
|
13493
13430
|
bass = this.basses[arr[1].substring(0, 1)] + bassShift + chordTranspose;
|
|
13431
|
+
|
|
13432
|
+
// MAE 22 May 2024 - Supporting octave shifted bass and chords
|
|
13433
|
+
bass += this.bassOctaveShift * 12;
|
|
13494
13434
|
bass2 = bass;
|
|
13495
13435
|
}
|
|
13496
13436
|
}
|
|
@@ -13506,6 +13446,9 @@ ChordTrack.prototype.chordNotes = function (bass, modifier) {
|
|
|
13506
13446
|
if (modifier.slice(0, 2).toLowerCase() === 'ma' || modifier[0] === 'M') intervals = this.chordIntervals.M;else if (modifier[0] === 'm' || modifier[0] === '-') intervals = this.chordIntervals.m;else intervals = this.chordIntervals.M;
|
|
13507
13447
|
}
|
|
13508
13448
|
bass += 12; // the chord is an octave above the bass note.
|
|
13449
|
+
|
|
13450
|
+
// MAE 22 May 2024 - For chick octave shift
|
|
13451
|
+
bass += this.chordOctaveShift * 12;
|
|
13509
13452
|
var notes = [];
|
|
13510
13453
|
for (var i = 0; i < intervals.length; i++) {
|
|
13511
13454
|
notes.push(bass + intervals[i]);
|
|
@@ -13586,7 +13529,6 @@ ChordTrack.prototype.resolveChords = function (startTime, endTime) {
|
|
|
13586
13529
|
if (newBass) newBass = false;else isBoom = false; // only the first note in a chord is a bass note. This handles the case where bass and chord are played at the same time.
|
|
13587
13530
|
}
|
|
13588
13531
|
}
|
|
13589
|
-
|
|
13590
13532
|
return;
|
|
13591
13533
|
};
|
|
13592
13534
|
ChordTrack.prototype.processChord = function (elem) {
|
|
@@ -13619,8 +13561,9 @@ function resolvePitch(currentChord, type, firstBoom, newBass) {
|
|
|
13619
13561
|
var ret = [];
|
|
13620
13562
|
if (!currentChord) return ret;
|
|
13621
13563
|
if (type.indexOf('boom') >= 0) ret.push(firstBoom ? currentChord.boom : currentChord.boom2);else if (newBass) ret.push(currentChord.boom);
|
|
13564
|
+
var numChordNotes = currentChord.chick.length;
|
|
13622
13565
|
if (type.indexOf('chick') >= 0) {
|
|
13623
|
-
for (var i = 0; i <
|
|
13566
|
+
for (var i = 0; i < numChordNotes; i++) {
|
|
13624
13567
|
ret.push(currentChord.chick[i]);
|
|
13625
13568
|
}
|
|
13626
13569
|
}
|
|
@@ -13632,13 +13575,13 @@ function resolvePitch(currentChord, type, firstBoom, newBass) {
|
|
|
13632
13575
|
ret.push(currentChord.chick[1]);
|
|
13633
13576
|
break;
|
|
13634
13577
|
case 'SOL':
|
|
13635
|
-
ret.push(currentChord
|
|
13578
|
+
ret.push(extractNote(currentChord, 2));
|
|
13636
13579
|
break;
|
|
13637
13580
|
case 'TI':
|
|
13638
|
-
|
|
13581
|
+
ret.push(extractNote(currentChord, 3));
|
|
13639
13582
|
break;
|
|
13640
13583
|
case 'TOP':
|
|
13641
|
-
|
|
13584
|
+
ret.push(extractNote(currentChord, 4));
|
|
13642
13585
|
break;
|
|
13643
13586
|
case 'do':
|
|
13644
13587
|
ret.push(currentChord.chick[0] + 12);
|
|
@@ -13647,17 +13590,24 @@ function resolvePitch(currentChord, type, firstBoom, newBass) {
|
|
|
13647
13590
|
ret.push(currentChord.chick[1] + 12);
|
|
13648
13591
|
break;
|
|
13649
13592
|
case 'sol':
|
|
13650
|
-
ret.push(currentChord
|
|
13593
|
+
ret.push(extractNote(currentChord, 2) + 12);
|
|
13651
13594
|
break;
|
|
13652
13595
|
case 'ti':
|
|
13653
|
-
|
|
13596
|
+
ret.push(extractNote(currentChord, 3) + 12);
|
|
13654
13597
|
break;
|
|
13655
13598
|
case 'top':
|
|
13656
|
-
|
|
13599
|
+
ret.push(extractNote(currentChord, 4) + 12);
|
|
13657
13600
|
break;
|
|
13658
13601
|
}
|
|
13659
13602
|
return ret;
|
|
13660
13603
|
}
|
|
13604
|
+
function extractNote(chord, index) {
|
|
13605
|
+
// This creates an arpeggio note no matter how many notes are in the chord - if it runs out of notes it continues in the next octave
|
|
13606
|
+
var octave = Math.floor(index / chord.chick.length);
|
|
13607
|
+
var note = chord.chick[index % chord.chick.length];
|
|
13608
|
+
//console.log(chord.chick, {index, octave, note}, index % chord.chick.length)
|
|
13609
|
+
return note + octave * 12;
|
|
13610
|
+
}
|
|
13661
13611
|
function parseGChord(gchord) {
|
|
13662
13612
|
// TODO-PER: The spec is more complicated than this but for now this will not try to do anything with error cases like the wrong number of beats.
|
|
13663
13613
|
var pattern = [];
|
|
@@ -13854,7 +13804,11 @@ ChordTrack.prototype.chordIntervals = {
|
|
|
13854
13804
|
'maj7#5#11': [0, 4, 8, 11, 18],
|
|
13855
13805
|
'9(#5)': [0, 4, 8, 10, 14],
|
|
13856
13806
|
'13(#5)': [0, 4, 8, 10, 14, 21],
|
|
13857
|
-
'13#5': [0, 4, 8, 10, 14, 21]
|
|
13807
|
+
'13#5': [0, 4, 8, 10, 14, 21],
|
|
13808
|
+
// MAE Power chords added 10 April 2024
|
|
13809
|
+
'5': [0, 7],
|
|
13810
|
+
'5(8)': [0, 7, 12],
|
|
13811
|
+
'5add8': [0, 7, 12]
|
|
13858
13812
|
};
|
|
13859
13813
|
ChordTrack.prototype.rhythmPatterns = {
|
|
13860
13814
|
"2/2": ['boom', '', '', '', 'chick', '', '', ''],
|
|
@@ -13866,8 +13820,12 @@ ChordTrack.prototype.rhythmPatterns = {
|
|
|
13866
13820
|
"5/4": ['boom', '', 'chick', '', 'chick', '', 'boom', '', 'chick', ''],
|
|
13867
13821
|
"6/4": ['boom', '', 'chick', '', 'boom', '', 'chick', '', 'boom', '', 'chick', ''],
|
|
13868
13822
|
"3/8": ['boom', '', 'chick'],
|
|
13823
|
+
"5/8": ['boom', 'chick', 'chick', 'boom', 'chick'],
|
|
13869
13824
|
"6/8": ['boom', '', 'chick', 'boom', '', 'chick'],
|
|
13825
|
+
"7/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
|
|
13870
13826
|
"9/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick'],
|
|
13827
|
+
"10/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
|
|
13828
|
+
"11/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick', 'chick'],
|
|
13871
13829
|
"12/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick']
|
|
13872
13830
|
};
|
|
13873
13831
|
|
|
@@ -13955,7 +13913,6 @@ module.exports = createNoteMap;
|
|
|
13955
13913
|
var supportsAudio = __webpack_require__(/*! ./supports-audio */ "./src/synth/supports-audio.js");
|
|
13956
13914
|
var registerAudioContext = __webpack_require__(/*! ./register-audio-context */ "./src/synth/register-audio-context.js");
|
|
13957
13915
|
var activeAudioContext = __webpack_require__(/*! ./active-audio-context */ "./src/synth/active-audio-context.js");
|
|
13958
|
-
var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/abc_common.js");
|
|
13959
13916
|
var loopImage = __webpack_require__(/*! ./images/loop.svg.js */ "./src/synth/images/loop.svg.js");
|
|
13960
13917
|
var playImage = __webpack_require__(/*! ./images/play.svg.js */ "./src/synth/images/play.svg.js");
|
|
13961
13918
|
var pauseImage = __webpack_require__(/*! ./images/pause.svg.js */ "./src/synth/images/pause.svg.js");
|
|
@@ -13971,7 +13928,7 @@ function CreateSynthControl(parent, options) {
|
|
|
13971
13928
|
} else if (!(parent instanceof HTMLElement)) throw new Error("The first parameter must be a valid element or selector in the DOM.");
|
|
13972
13929
|
self.parent = parent;
|
|
13973
13930
|
self.options = {};
|
|
13974
|
-
if (options) self.options =
|
|
13931
|
+
if (options) self.options = Object.assign({}, options);
|
|
13975
13932
|
|
|
13976
13933
|
// This can be called in the following cases:
|
|
13977
13934
|
// AC already registered and not suspended
|
|
@@ -14627,7 +14584,6 @@ function CreateSynth() {
|
|
|
14627
14584
|
self.directSource[trackNum].buffer = audioBuffer; // tell the source which sound to play
|
|
14628
14585
|
self.directSource[trackNum].connect(activeAudioContext().destination); // connect the source to the context's destination (the speakers)
|
|
14629
14586
|
});
|
|
14630
|
-
|
|
14631
14587
|
self.directSource.forEach(function (source) {
|
|
14632
14588
|
source.start(0, seconds);
|
|
14633
14589
|
});
|
|
@@ -15685,72 +15641,272 @@ function SynthController() {
|
|
|
15685
15641
|
} else {
|
|
15686
15642
|
return self.finished();
|
|
15687
15643
|
}
|
|
15688
|
-
};
|
|
15689
|
-
self.lineEndCallback = function (lineEvent, leftEvent) {
|
|
15690
|
-
if (self.cursorControl && self.cursorControl.onLineEnd && typeof self.cursorControl.onLineEnd === 'function') self.cursorControl.onLineEnd(lineEvent, leftEvent);
|
|
15691
|
-
};
|
|
15692
|
-
self.getUrl = function () {
|
|
15693
|
-
return self.midiBuffer.download();
|
|
15694
|
-
};
|
|
15695
|
-
self.download = function (fileName) {
|
|
15696
|
-
var url = self.getUrl();
|
|
15697
|
-
var link = document.createElement('a');
|
|
15698
|
-
document.body.appendChild(link);
|
|
15699
|
-
link.setAttribute("style", "display: none;");
|
|
15700
|
-
link.href = url;
|
|
15701
|
-
link.download = fileName ? fileName : 'output.wav';
|
|
15702
|
-
link.click();
|
|
15703
|
-
window.URL.revokeObjectURL(url);
|
|
15704
|
-
document.body.removeChild(link);
|
|
15705
|
-
};
|
|
15706
|
-
}
|
|
15707
|
-
module.exports = SynthController;
|
|
15644
|
+
};
|
|
15645
|
+
self.lineEndCallback = function (lineEvent, leftEvent) {
|
|
15646
|
+
if (self.cursorControl && self.cursorControl.onLineEnd && typeof self.cursorControl.onLineEnd === 'function') self.cursorControl.onLineEnd(lineEvent, leftEvent);
|
|
15647
|
+
};
|
|
15648
|
+
self.getUrl = function () {
|
|
15649
|
+
return self.midiBuffer.download();
|
|
15650
|
+
};
|
|
15651
|
+
self.download = function (fileName) {
|
|
15652
|
+
var url = self.getUrl();
|
|
15653
|
+
var link = document.createElement('a');
|
|
15654
|
+
document.body.appendChild(link);
|
|
15655
|
+
link.setAttribute("style", "display: none;");
|
|
15656
|
+
link.href = url;
|
|
15657
|
+
link.download = fileName ? fileName : 'output.wav';
|
|
15658
|
+
link.click();
|
|
15659
|
+
window.URL.revokeObjectURL(url);
|
|
15660
|
+
document.body.removeChild(link);
|
|
15661
|
+
};
|
|
15662
|
+
}
|
|
15663
|
+
module.exports = SynthController;
|
|
15664
|
+
|
|
15665
|
+
/***/ }),
|
|
15666
|
+
|
|
15667
|
+
/***/ "./src/synth/synth-sequence.js":
|
|
15668
|
+
/*!*************************************!*\
|
|
15669
|
+
!*** ./src/synth/synth-sequence.js ***!
|
|
15670
|
+
\*************************************/
|
|
15671
|
+
/***/ (function(module) {
|
|
15672
|
+
|
|
15673
|
+
var SynthSequence = function SynthSequence() {
|
|
15674
|
+
var self = this;
|
|
15675
|
+
self.tracks = [];
|
|
15676
|
+
self.totalDuration = 0;
|
|
15677
|
+
self.currentInstrument = [];
|
|
15678
|
+
self.starts = [];
|
|
15679
|
+
self.addTrack = function () {
|
|
15680
|
+
self.tracks.push([]);
|
|
15681
|
+
self.currentInstrument.push(0);
|
|
15682
|
+
self.starts.push(0);
|
|
15683
|
+
return self.tracks.length - 1;
|
|
15684
|
+
};
|
|
15685
|
+
self.setInstrument = function (trackNumber, instrumentNumber) {
|
|
15686
|
+
self.tracks[trackNumber].push({
|
|
15687
|
+
channel: 0,
|
|
15688
|
+
cmd: "program",
|
|
15689
|
+
instrument: instrumentNumber
|
|
15690
|
+
});
|
|
15691
|
+
self.currentInstrument[trackNumber] = instrumentNumber;
|
|
15692
|
+
};
|
|
15693
|
+
self.appendNote = function (trackNumber, pitch, durationInMeasures, volume, cents) {
|
|
15694
|
+
var note = {
|
|
15695
|
+
cmd: "note",
|
|
15696
|
+
duration: durationInMeasures,
|
|
15697
|
+
gap: 0,
|
|
15698
|
+
instrument: self.currentInstrument[trackNumber],
|
|
15699
|
+
pitch: pitch,
|
|
15700
|
+
start: self.starts[trackNumber],
|
|
15701
|
+
volume: volume
|
|
15702
|
+
};
|
|
15703
|
+
if (cents) note.cents = cents;
|
|
15704
|
+
self.tracks[trackNumber].push(note);
|
|
15705
|
+
self.starts[trackNumber] += durationInMeasures;
|
|
15706
|
+
self.totalDuration = Math.max(self.totalDuration, self.starts[trackNumber]);
|
|
15707
|
+
};
|
|
15708
|
+
};
|
|
15709
|
+
module.exports = SynthSequence;
|
|
15710
|
+
|
|
15711
|
+
/***/ }),
|
|
15712
|
+
|
|
15713
|
+
/***/ "./src/tablatures/abc_tablatures.js":
|
|
15714
|
+
/*!******************************************!*\
|
|
15715
|
+
!*** ./src/tablatures/abc_tablatures.js ***!
|
|
15716
|
+
\******************************************/
|
|
15717
|
+
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
15718
|
+
|
|
15719
|
+
/*
|
|
15720
|
+
* Tablature Plugins
|
|
15721
|
+
* tablature are defined dynamically and registered inside abcjs
|
|
15722
|
+
* by calling abcTablatures.register(plugin)
|
|
15723
|
+
* where plugin represents a plugin instance
|
|
15724
|
+
*
|
|
15725
|
+
*/
|
|
15726
|
+
|
|
15727
|
+
// This is the only entry point to the tablatures. It is called both after parsing a tune and just before engraving
|
|
15728
|
+
|
|
15729
|
+
var TabString = __webpack_require__(/*! ./instruments/tab-string */ "./src/tablatures/instruments/tab-string.js");
|
|
15730
|
+
|
|
15731
|
+
/* extend the table below when adding a new instrument plugin */
|
|
15732
|
+
|
|
15733
|
+
// Existing tab classes
|
|
15734
|
+
var pluginTab = {
|
|
15735
|
+
'violin': {
|
|
15736
|
+
name: 'StringTab',
|
|
15737
|
+
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
15738
|
+
isTabBig: false,
|
|
15739
|
+
tabSymbolOffset: 0
|
|
15740
|
+
},
|
|
15741
|
+
'fiddle': {
|
|
15742
|
+
name: 'StringTab',
|
|
15743
|
+
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
15744
|
+
isTabBig: false,
|
|
15745
|
+
tabSymbolOffset: 0
|
|
15746
|
+
},
|
|
15747
|
+
'mandolin': {
|
|
15748
|
+
name: 'StringTab',
|
|
15749
|
+
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
15750
|
+
isTabBig: false,
|
|
15751
|
+
tabSymbolOffset: 0
|
|
15752
|
+
},
|
|
15753
|
+
'guitar': {
|
|
15754
|
+
name: 'StringTab',
|
|
15755
|
+
defaultTuning: ['E,', 'A,', 'D', 'G', 'B', 'e'],
|
|
15756
|
+
isTabBig: true,
|
|
15757
|
+
tabSymbolOffset: 0
|
|
15758
|
+
},
|
|
15759
|
+
'fiveString': {
|
|
15760
|
+
name: 'StringTab',
|
|
15761
|
+
defaultTuning: ['C,', 'G,', 'D', 'A', 'e'],
|
|
15762
|
+
isTabBig: false,
|
|
15763
|
+
tabSymbolOffset: -.95
|
|
15764
|
+
}
|
|
15765
|
+
};
|
|
15766
|
+
var abcTablatures = {
|
|
15767
|
+
inited: false,
|
|
15768
|
+
plugins: {},
|
|
15769
|
+
/**
|
|
15770
|
+
* to be called once per plugin for registration
|
|
15771
|
+
* @param {*} plugin
|
|
15772
|
+
*/
|
|
15773
|
+
register: function register(plugin) {
|
|
15774
|
+
var name = plugin.name;
|
|
15775
|
+
var tablature = plugin.tablature;
|
|
15776
|
+
this.plugins[name] = tablature;
|
|
15777
|
+
},
|
|
15778
|
+
setError: function setError(tune, msg) {
|
|
15779
|
+
if (tune.warnings) {
|
|
15780
|
+
tune.warning.push(msg);
|
|
15781
|
+
} else {
|
|
15782
|
+
tune.warnings = [msg];
|
|
15783
|
+
}
|
|
15784
|
+
},
|
|
15785
|
+
/**
|
|
15786
|
+
* handle params for current processed score
|
|
15787
|
+
* @param {*} tune current tune
|
|
15788
|
+
* @param {*} tuneNumber number in tune list
|
|
15789
|
+
* @param {*} params params to be processed for tablature
|
|
15790
|
+
* @return prepared tablatures plugin instances for current tune
|
|
15791
|
+
*/
|
|
15792
|
+
preparePlugins: function preparePlugins(tune, tuneNumber, params) {
|
|
15793
|
+
// Called after parsing a tune and before engraving it
|
|
15794
|
+
if (!this.inited) {
|
|
15795
|
+
// TODO-PER: I don't think this is needed - the plugin array can be hard coded, right?
|
|
15796
|
+
this.register(new TabString());
|
|
15797
|
+
this.inited = true;
|
|
15798
|
+
}
|
|
15799
|
+
var returned = null;
|
|
15800
|
+
var nbPlugins = 0;
|
|
15801
|
+
if (params.tablature) {
|
|
15802
|
+
// validate requested plugins
|
|
15803
|
+
var tabs = params.tablature;
|
|
15804
|
+
returned = [];
|
|
15805
|
+
for (var ii = 0; ii < tabs.length; ii++) {
|
|
15806
|
+
var args = tabs[ii];
|
|
15807
|
+
var instrument = args['instrument'];
|
|
15808
|
+
if (instrument == null) {
|
|
15809
|
+
this.setError(tune, "tablature 'instrument' is missing");
|
|
15810
|
+
return returned;
|
|
15811
|
+
}
|
|
15812
|
+
var tabName = pluginTab[instrument];
|
|
15813
|
+
var plugin = null;
|
|
15814
|
+
if (tabName) {
|
|
15815
|
+
plugin = this.plugins[tabName.name];
|
|
15816
|
+
}
|
|
15817
|
+
if (plugin) {
|
|
15818
|
+
if (params.visualTranspose != 0) {
|
|
15819
|
+
// populate transposition request to tabs
|
|
15820
|
+
args.visualTranspose = params.visualTranspose;
|
|
15821
|
+
}
|
|
15822
|
+
args.abcSrc = params.tablature.abcSrc;
|
|
15823
|
+
var pluginInstance = {
|
|
15824
|
+
classz: plugin,
|
|
15825
|
+
tuneNumber: tuneNumber,
|
|
15826
|
+
params: args,
|
|
15827
|
+
instance: null,
|
|
15828
|
+
tabType: tabName
|
|
15829
|
+
};
|
|
15830
|
+
// proceed with tab plugin init
|
|
15831
|
+
// plugin.init(tune, tuneNumber, args, ii);
|
|
15832
|
+
returned.push(pluginInstance);
|
|
15833
|
+
nbPlugins++;
|
|
15834
|
+
} else if (instrument === '') {
|
|
15835
|
+
// create a placeholder - there is no tab for this staff
|
|
15836
|
+
returned.push(null);
|
|
15837
|
+
} else {
|
|
15838
|
+
// unknown tab plugin
|
|
15839
|
+
//this.emit_error('Undefined tablature plugin: ' + tabName)
|
|
15840
|
+
this.setError(tune, 'Undefined tablature plugin: ' + instrument);
|
|
15841
|
+
return returned;
|
|
15842
|
+
}
|
|
15843
|
+
}
|
|
15844
|
+
}
|
|
15845
|
+
return returned;
|
|
15846
|
+
},
|
|
15847
|
+
/**
|
|
15848
|
+
* Call requested plugin
|
|
15849
|
+
* @param {*} renderer
|
|
15850
|
+
* @param {*} abcTune
|
|
15851
|
+
*/
|
|
15852
|
+
layoutTablatures: function layoutTablatures(renderer, abcTune) {
|
|
15853
|
+
var tabs = abcTune.tablatures;
|
|
15708
15854
|
|
|
15709
|
-
|
|
15855
|
+
// chack tabs request for each staffs
|
|
15856
|
+
var staffLineCount = 0;
|
|
15710
15857
|
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15858
|
+
// Clear the suppression flag
|
|
15859
|
+
if (tabs && tabs.length > 0) {
|
|
15860
|
+
var nTabs = tabs.length;
|
|
15861
|
+
for (var kk = 0; kk < nTabs; ++kk) {
|
|
15862
|
+
if (tabs[kk] && tabs[kk].params.firstStaffOnly) {
|
|
15863
|
+
tabs[kk].params.suppress = false;
|
|
15864
|
+
}
|
|
15865
|
+
}
|
|
15866
|
+
}
|
|
15867
|
+
for (var ii = 0; ii < abcTune.lines.length; ii++) {
|
|
15868
|
+
var line = abcTune.lines[ii];
|
|
15869
|
+
if (line.staff) {
|
|
15870
|
+
staffLineCount++;
|
|
15871
|
+
}
|
|
15716
15872
|
|
|
15717
|
-
|
|
15718
|
-
|
|
15719
|
-
|
|
15720
|
-
|
|
15721
|
-
|
|
15722
|
-
|
|
15723
|
-
|
|
15724
|
-
|
|
15725
|
-
|
|
15726
|
-
|
|
15727
|
-
|
|
15728
|
-
|
|
15729
|
-
|
|
15730
|
-
|
|
15731
|
-
|
|
15732
|
-
|
|
15733
|
-
|
|
15734
|
-
|
|
15735
|
-
|
|
15736
|
-
|
|
15737
|
-
|
|
15738
|
-
|
|
15739
|
-
|
|
15740
|
-
|
|
15741
|
-
|
|
15742
|
-
|
|
15743
|
-
|
|
15744
|
-
|
|
15745
|
-
|
|
15746
|
-
|
|
15747
|
-
|
|
15748
|
-
|
|
15749
|
-
|
|
15750
|
-
|
|
15751
|
-
}
|
|
15873
|
+
// MAE 27Nov2023
|
|
15874
|
+
// If tab param "firstStaffOnly", remove the tab label after the first staff
|
|
15875
|
+
if (staffLineCount > 1) {
|
|
15876
|
+
if (tabs && tabs.length > 0) {
|
|
15877
|
+
var nTabs = tabs.length;
|
|
15878
|
+
for (var kk = 0; kk < nTabs; ++kk) {
|
|
15879
|
+
if (tabs[kk].params.firstStaffOnly) {
|
|
15880
|
+
// Set the staff draw suppression flag
|
|
15881
|
+
tabs[kk].params.suppress = true;
|
|
15882
|
+
}
|
|
15883
|
+
}
|
|
15884
|
+
}
|
|
15885
|
+
}
|
|
15886
|
+
var curStaff = line.staff;
|
|
15887
|
+
if (curStaff) {
|
|
15888
|
+
var maxStaves = curStaff.length;
|
|
15889
|
+
for (var jj = 0; jj < curStaff.length; jj++) {
|
|
15890
|
+
if (tabs[jj] && jj < maxStaves) {
|
|
15891
|
+
// tablature requested for staff
|
|
15892
|
+
var tabPlugin = tabs[jj];
|
|
15893
|
+
if (tabPlugin.instance == null) {
|
|
15894
|
+
//console.log("★★★★ Tab Init line: " + ii + " staff: " + jj)
|
|
15895
|
+
tabPlugin.instance = new tabPlugin.classz();
|
|
15896
|
+
// plugin.init(tune, tuneNumber, args, ii);
|
|
15897
|
+
// call initer first
|
|
15898
|
+
tabPlugin.instance.init(abcTune, tabPlugin.tuneNumber, tabPlugin.params, tabPlugin.tabType);
|
|
15899
|
+
}
|
|
15900
|
+
// render next
|
|
15901
|
+
//console.log("★★★★ Tab Render line: " + ii + " staff: " + jj)
|
|
15902
|
+
tabPlugin.instance.render(renderer, line, jj);
|
|
15903
|
+
}
|
|
15904
|
+
}
|
|
15905
|
+
}
|
|
15906
|
+
}
|
|
15907
|
+
}
|
|
15752
15908
|
};
|
|
15753
|
-
module.exports =
|
|
15909
|
+
module.exports = abcTablatures;
|
|
15754
15910
|
|
|
15755
15911
|
/***/ }),
|
|
15756
15912
|
|
|
@@ -15763,14 +15919,14 @@ module.exports = SynthSequence;
|
|
|
15763
15919
|
var _require = __webpack_require__(/*! ../../synth/note-to-midi */ "./src/synth/note-to-midi.js"),
|
|
15764
15920
|
noteToMidi = _require.noteToMidi;
|
|
15765
15921
|
var TabNote = __webpack_require__(/*! ./tab-note */ "./src/tablatures/instruments/tab-note.js");
|
|
15766
|
-
var
|
|
15922
|
+
var tabNotes = __webpack_require__(/*! ./tab-notes */ "./src/tablatures/instruments/tab-notes.js");
|
|
15767
15923
|
function buildCapo(self) {
|
|
15768
15924
|
var capoTuning = null;
|
|
15769
15925
|
var tuning = self.tuning;
|
|
15770
15926
|
if (self.capo > 0) {
|
|
15771
15927
|
capoTuning = [];
|
|
15772
15928
|
for (var iii = 0; iii < tuning.length; iii++) {
|
|
15773
|
-
var curNote = new TabNote
|
|
15929
|
+
var curNote = new TabNote(tuning[iii]);
|
|
15774
15930
|
for (var jjj = 0; jjj < self.capo; jjj++) {
|
|
15775
15931
|
curNote = curNote.nextNote();
|
|
15776
15932
|
}
|
|
@@ -15791,8 +15947,7 @@ function buildPatterns(self) {
|
|
|
15791
15947
|
if (iii != tuning.length - 1) {
|
|
15792
15948
|
nextNote = tuning[iii + 1];
|
|
15793
15949
|
}
|
|
15794
|
-
var
|
|
15795
|
-
var stringNotes = tabNotes.build();
|
|
15950
|
+
var stringNotes = tabNotes(tuning[iii], nextNote);
|
|
15796
15951
|
if (stringNotes.error) {
|
|
15797
15952
|
return stringNotes;
|
|
15798
15953
|
}
|
|
@@ -15841,7 +15996,7 @@ function handleChordNotes(self, notes) {
|
|
|
15841
15996
|
var retNotes = [];
|
|
15842
15997
|
for (var iiii = 0; iiii < notes.length; iiii++) {
|
|
15843
15998
|
if (notes[iiii].endTie) continue;
|
|
15844
|
-
var note = new TabNote
|
|
15999
|
+
var note = new TabNote(notes[iiii].name, self.clefTranspose);
|
|
15845
16000
|
note.checkKeyAccidentals(self.accidentals, self.measureAccidentals);
|
|
15846
16001
|
var curPos = toNumber(self, note);
|
|
15847
16002
|
retNotes.push(curPos);
|
|
@@ -15933,7 +16088,7 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
15933
16088
|
}
|
|
15934
16089
|
} else {
|
|
15935
16090
|
if (!notes[0].endTie) {
|
|
15936
|
-
note = new TabNote
|
|
16091
|
+
note = new TabNote(notes[0].name, this.clefTranspose);
|
|
15937
16092
|
note.checkKeyAccidentals(this.accidentals, this.measureAccidentals);
|
|
15938
16093
|
number = toNumber(this, note);
|
|
15939
16094
|
if (number) {
|
|
@@ -15950,7 +16105,7 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
15950
16105
|
if (graces) {
|
|
15951
16106
|
retGraces = [];
|
|
15952
16107
|
for (var iiii = 0; iiii < graces.length; iiii++) {
|
|
15953
|
-
note = new TabNote
|
|
16108
|
+
note = new TabNote(graces[iiii].name, this.clefTranspose);
|
|
15954
16109
|
note.checkKeyAccidentals(this.accidentals, this.measureAccidentals);
|
|
15955
16110
|
number = toNumber(this, note);
|
|
15956
16111
|
if (number) {
|
|
@@ -15977,8 +16132,7 @@ StringPatterns.prototype.toString = function () {
|
|
|
15977
16132
|
return arr.join('');
|
|
15978
16133
|
};
|
|
15979
16134
|
StringPatterns.prototype.tabInfos = function (plugin) {
|
|
15980
|
-
var
|
|
15981
|
-
var name = _super.params.label;
|
|
16135
|
+
var name = plugin.params.label;
|
|
15982
16136
|
if (name) {
|
|
15983
16137
|
var tunePos = name.indexOf('%T');
|
|
15984
16138
|
var tuning = "";
|
|
@@ -15996,8 +16150,7 @@ StringPatterns.prototype.tabInfos = function (plugin) {
|
|
|
15996
16150
|
|
|
15997
16151
|
// MAE 27 Nov 2023
|
|
15998
16152
|
StringPatterns.prototype.suppress = function (plugin) {
|
|
15999
|
-
var
|
|
16000
|
-
var suppress = _super.params.suppress;
|
|
16153
|
+
var suppress = plugin.params.suppress;
|
|
16001
16154
|
if (suppress) {
|
|
16002
16155
|
return true;
|
|
16003
16156
|
}
|
|
@@ -16013,9 +16166,10 @@ StringPatterns.prototype.suppress = function (plugin) {
|
|
|
16013
16166
|
* @param {*} highestNote
|
|
16014
16167
|
*/
|
|
16015
16168
|
function StringPatterns(plugin) {
|
|
16169
|
+
//console.log("INIT StringPatterns constructor")
|
|
16016
16170
|
var tuning = plugin.tuning;
|
|
16017
16171
|
var capo = plugin.capo;
|
|
16018
|
-
var highestNote = plugin.
|
|
16172
|
+
var highestNote = plugin.params.highestNote;
|
|
16019
16173
|
this.linePitch = plugin.linePitch;
|
|
16020
16174
|
this.highestNote = "a'";
|
|
16021
16175
|
if (highestNote) {
|
|
@@ -16039,7 +16193,7 @@ function StringPatterns(plugin) {
|
|
|
16039
16193
|
}
|
|
16040
16194
|
this.strings = buildPatterns(this);
|
|
16041
16195
|
if (this.strings.error) {
|
|
16042
|
-
plugin.
|
|
16196
|
+
plugin.setError(this.strings.error);
|
|
16043
16197
|
plugin.inError = true;
|
|
16044
16198
|
return;
|
|
16045
16199
|
}
|
|
@@ -16063,6 +16217,7 @@ module.exports = StringPatterns;
|
|
|
16063
16217
|
*/
|
|
16064
16218
|
|
|
16065
16219
|
function StringTablature(numLines, lineSpace) {
|
|
16220
|
+
//console.log("INIT StringTablature constructor")
|
|
16066
16221
|
this.numLines = numLines;
|
|
16067
16222
|
this.lineSpace = lineSpace;
|
|
16068
16223
|
this.verticalSize = this.numLines * this.lineSpace;
|
|
@@ -16079,6 +16234,7 @@ function StringTablature(numLines, lineSpace) {
|
|
|
16079
16234
|
* @param {} line
|
|
16080
16235
|
*/
|
|
16081
16236
|
StringTablature.prototype.bypass = function (line) {
|
|
16237
|
+
//console.log("RENDER StringTablature bypass")
|
|
16082
16238
|
var voices = line.staffGroup.voices;
|
|
16083
16239
|
if (voices.length > 0) {
|
|
16084
16240
|
if (voices[0].isPercussion) return true;
|
|
@@ -16086,6 +16242,7 @@ StringTablature.prototype.bypass = function (line) {
|
|
|
16086
16242
|
return false;
|
|
16087
16243
|
};
|
|
16088
16244
|
StringTablature.prototype.setRelative = function (child, relative, first) {
|
|
16245
|
+
//console.log("RENDER StringTablature setRelative")
|
|
16089
16246
|
switch (child.type) {
|
|
16090
16247
|
case 'bar':
|
|
16091
16248
|
relative.pitch = this.bar.pitch;
|
|
@@ -16126,8 +16283,9 @@ var _require = __webpack_require__(/*! ../../synth/note-to-midi */ "./src/synth/
|
|
|
16126
16283
|
* Note structure for Tabs
|
|
16127
16284
|
*
|
|
16128
16285
|
*/
|
|
16129
|
-
|
|
16286
|
+
|
|
16130
16287
|
function TabNote(note, clefTranspose) {
|
|
16288
|
+
//console.log("INIT/RENDER TabNote constructor")
|
|
16131
16289
|
var pitch = noteToMidi(note);
|
|
16132
16290
|
if (clefTranspose) pitch += clefTranspose;
|
|
16133
16291
|
var newNote = midiToNote(pitch);
|
|
@@ -16209,12 +16367,15 @@ function cloneNote(self) {
|
|
|
16209
16367
|
return newTabNote;
|
|
16210
16368
|
}
|
|
16211
16369
|
TabNote.prototype.sameNoteAs = function (note) {
|
|
16370
|
+
//console.log("INIT TabNote sameNoteAs")
|
|
16212
16371
|
return note.pitch === this.pitch;
|
|
16213
16372
|
};
|
|
16214
16373
|
TabNote.prototype.isLowerThan = function (note) {
|
|
16374
|
+
//console.log("INIT TabNote isLowerThan")
|
|
16215
16375
|
return note.pitch > this.pitch;
|
|
16216
16376
|
};
|
|
16217
16377
|
TabNote.prototype.checkKeyAccidentals = function (accidentals, measureAccidentals) {
|
|
16378
|
+
//console.log("RENDER TabNote checkKeyAccidentals")
|
|
16218
16379
|
if (this.isAltered || this.natural) return;
|
|
16219
16380
|
if (measureAccidentals[this.name.toUpperCase()]) {
|
|
16220
16381
|
switch (measureAccidentals[this.name.toUpperCase()]) {
|
|
@@ -16259,6 +16420,7 @@ TabNote.prototype.checkKeyAccidentals = function (accidentals, measureAccidental
|
|
|
16259
16420
|
}
|
|
16260
16421
|
};
|
|
16261
16422
|
TabNote.prototype.getAccidentalEquiv = function () {
|
|
16423
|
+
//console.log("TabNote getAccidentalEquiv")
|
|
16262
16424
|
var cloned = cloneNote(this);
|
|
16263
16425
|
if (cloned.isSharp || cloned.isKeySharp) {
|
|
16264
16426
|
cloned = cloned.nextNote();
|
|
@@ -16274,14 +16436,17 @@ TabNote.prototype.getAccidentalEquiv = function () {
|
|
|
16274
16436
|
return cloned;
|
|
16275
16437
|
};
|
|
16276
16438
|
TabNote.prototype.nextNote = function () {
|
|
16439
|
+
//console.log("INIT TabNote nextNote")
|
|
16277
16440
|
var note = midiToNote(this.pitch + 1 + this.pitchAltered);
|
|
16278
16441
|
return new TabNote(note);
|
|
16279
16442
|
};
|
|
16280
16443
|
TabNote.prototype.prevNote = function () {
|
|
16444
|
+
//console.log("TabNote prevNote")
|
|
16281
16445
|
var note = midiToNote(this.pitch - 1 + this.pitchAltered);
|
|
16282
16446
|
return new TabNote(note);
|
|
16283
16447
|
};
|
|
16284
16448
|
TabNote.prototype.emitNoAccidentals = function () {
|
|
16449
|
+
//console.log("TabNote emitNoAccidentals")
|
|
16285
16450
|
var returned = this.name;
|
|
16286
16451
|
if (this.isLower) {
|
|
16287
16452
|
returned = returned.toLowerCase();
|
|
@@ -16295,6 +16460,7 @@ TabNote.prototype.emitNoAccidentals = function () {
|
|
|
16295
16460
|
return returned;
|
|
16296
16461
|
};
|
|
16297
16462
|
TabNote.prototype.emit = function () {
|
|
16463
|
+
//console.log("INIT/RENDER TabNote emit")
|
|
16298
16464
|
var returned = this.name;
|
|
16299
16465
|
if (this.isSharp || this.isKeySharp) {
|
|
16300
16466
|
returned = '^' + returned;
|
|
@@ -16329,10 +16495,7 @@ TabNote.prototype.emit = function () {
|
|
|
16329
16495
|
}
|
|
16330
16496
|
return returned;
|
|
16331
16497
|
};
|
|
16332
|
-
module.exports =
|
|
16333
|
-
'TabNote': TabNote,
|
|
16334
|
-
'notes': notes
|
|
16335
|
-
};
|
|
16498
|
+
module.exports = TabNote;
|
|
16336
16499
|
|
|
16337
16500
|
/***/ }),
|
|
16338
16501
|
|
|
@@ -16343,14 +16506,11 @@ module.exports = {
|
|
|
16343
16506
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16344
16507
|
|
|
16345
16508
|
var TabNote = __webpack_require__(/*! ./tab-note */ "./src/tablatures/instruments/tab-note.js");
|
|
16346
|
-
var notes =
|
|
16347
|
-
function
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
TabNotes.prototype.build = function () {
|
|
16352
|
-
var fromN = this.fromN;
|
|
16353
|
-
var toN = this.toN;
|
|
16509
|
+
var notes = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
|
|
16510
|
+
function tabNotes(fromNote, toNote) {
|
|
16511
|
+
//console.log("INIT TabNotes")
|
|
16512
|
+
var fromN = new TabNote(fromNote);
|
|
16513
|
+
var toN = new TabNote(toNote);
|
|
16354
16514
|
// check that toN is not lower than fromN
|
|
16355
16515
|
if (toN.isLowerThan(fromN)) {
|
|
16356
16516
|
var from = fromN.emit();
|
|
@@ -16374,35 +16534,8 @@ TabNotes.prototype.build = function () {
|
|
|
16374
16534
|
}
|
|
16375
16535
|
}
|
|
16376
16536
|
return buildReturned;
|
|
16377
|
-
};
|
|
16378
|
-
module.exports = TabNotes;
|
|
16379
|
-
|
|
16380
|
-
/***/ }),
|
|
16381
|
-
|
|
16382
|
-
/***/ "./src/tablatures/instruments/tab-string-patterns.js":
|
|
16383
|
-
/*!***********************************************************!*\
|
|
16384
|
-
!*** ./src/tablatures/instruments/tab-string-patterns.js ***!
|
|
16385
|
-
\***********************************************************/
|
|
16386
|
-
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16387
|
-
|
|
16388
|
-
var StringPatterns = __webpack_require__(/*! ./string-patterns */ "./src/tablatures/instruments/string-patterns.js");
|
|
16389
|
-
function TabStringPatterns(plugin, defaultTuning) {
|
|
16390
|
-
this.tuning = plugin._super.params.tuning;
|
|
16391
|
-
if (!this.tuning) {
|
|
16392
|
-
this.tuning = defaultTuning;
|
|
16393
|
-
}
|
|
16394
|
-
plugin.tuning = this.tuning;
|
|
16395
|
-
this.strings = new StringPatterns(plugin);
|
|
16396
16537
|
}
|
|
16397
|
-
|
|
16398
|
-
var converter = this.strings;
|
|
16399
|
-
return converter.notesToNumber(notes, graces);
|
|
16400
|
-
};
|
|
16401
|
-
TabStringPatterns.prototype.stringToPitch = function (stringNumber) {
|
|
16402
|
-
var converter = this.strings;
|
|
16403
|
-
return converter.stringToPitch(stringNumber);
|
|
16404
|
-
};
|
|
16405
|
-
module.exports = TabStringPatterns;
|
|
16538
|
+
module.exports = tabNotes;
|
|
16406
16539
|
|
|
16407
16540
|
/***/ }),
|
|
16408
16541
|
|
|
@@ -16413,20 +16546,22 @@ module.exports = TabStringPatterns;
|
|
|
16413
16546
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16414
16547
|
|
|
16415
16548
|
var StringTablature = __webpack_require__(/*! ./string-tablature */ "./src/tablatures/instruments/string-tablature.js");
|
|
16416
|
-
var
|
|
16417
|
-
var
|
|
16418
|
-
var TabStringPatterns = __webpack_require__(/*! ./tab-string-patterns */ "./src/tablatures/instruments/tab-string-patterns.js");
|
|
16549
|
+
var tabRenderer = __webpack_require__(/*! ../render/tab-renderer */ "./src/tablatures/render/tab-renderer.js");
|
|
16550
|
+
var StringPatterns = __webpack_require__(/*! ./string-patterns */ "./src/tablatures/instruments/string-patterns.js");
|
|
16419
16551
|
|
|
16420
16552
|
/**
|
|
16421
16553
|
* upon init mainly store provided instances for later usage
|
|
16422
16554
|
* @param {*} abcTune the parsed tune AST tree
|
|
16423
|
-
*
|
|
16555
|
+
* @param {*} tuneNumber the parsed tune AST tree
|
|
16424
16556
|
* @param {*} params complementary args provided to Tablature Plugin
|
|
16425
16557
|
*/
|
|
16426
|
-
Plugin.prototype.init = function (abcTune, tuneNumber, params,
|
|
16427
|
-
|
|
16558
|
+
Plugin.prototype.init = function (abcTune, tuneNumber, params, tabSettings) {
|
|
16559
|
+
//console.log("INIT AbcStringTab Plugin.init")
|
|
16560
|
+
this.tune = abcTune;
|
|
16561
|
+
this.params = params;
|
|
16562
|
+
this.tuneNumber = tuneNumber;
|
|
16563
|
+
this.inError = false;
|
|
16428
16564
|
this.abcTune = abcTune;
|
|
16429
|
-
this._super = _super;
|
|
16430
16565
|
this.linePitch = 3;
|
|
16431
16566
|
this.nbLines = tabSettings.defaultTuning.length;
|
|
16432
16567
|
this.isTabBig = tabSettings.isTabBig;
|
|
@@ -16435,14 +16570,30 @@ Plugin.prototype.init = function (abcTune, tuneNumber, params, staffNumber, tabS
|
|
|
16435
16570
|
this.transpose = params.visualTranspose;
|
|
16436
16571
|
this.hideTabSymbol = params.hideTabSymbol;
|
|
16437
16572
|
this.tablature = new StringTablature(this.nbLines, this.linePitch);
|
|
16438
|
-
var
|
|
16439
|
-
|
|
16573
|
+
var tuning = params.tuning;
|
|
16574
|
+
if (!tuning) {
|
|
16575
|
+
tuning = tabSettings.defaultTuning;
|
|
16576
|
+
}
|
|
16577
|
+
this.tuning = tuning;
|
|
16578
|
+
this.semantics = new StringPatterns(this);
|
|
16579
|
+
};
|
|
16580
|
+
Plugin.prototype.setError = function (error) {
|
|
16581
|
+
//console.log("Plugin setError")
|
|
16582
|
+
if (error) {
|
|
16583
|
+
this.error = error;
|
|
16584
|
+
this.inError = true;
|
|
16585
|
+
if (this.tune.warnings) {
|
|
16586
|
+
this.tune.warnings.push(error);
|
|
16587
|
+
} else {
|
|
16588
|
+
this.tune.warnings = [error];
|
|
16589
|
+
}
|
|
16590
|
+
}
|
|
16440
16591
|
};
|
|
16441
16592
|
Plugin.prototype.render = function (renderer, line, staffIndex) {
|
|
16442
|
-
|
|
16593
|
+
//console.log("RENDER AbcStringTab Plugin.render")
|
|
16594
|
+
if (this.inError) return;
|
|
16443
16595
|
if (this.tablature.bypass(line)) return;
|
|
16444
|
-
|
|
16445
|
-
rndrer.doLayout();
|
|
16596
|
+
tabRenderer(this, renderer, line, staffIndex);
|
|
16446
16597
|
};
|
|
16447
16598
|
function Plugin() {}
|
|
16448
16599
|
|
|
@@ -16459,17 +16610,17 @@ module.exports = AbcStringTab;
|
|
|
16459
16610
|
|
|
16460
16611
|
/***/ }),
|
|
16461
16612
|
|
|
16462
|
-
/***/ "./src/tablatures/tab-absolute-elements.js":
|
|
16463
|
-
|
|
16464
|
-
!*** ./src/tablatures/tab-absolute-elements.js ***!
|
|
16465
|
-
|
|
16613
|
+
/***/ "./src/tablatures/render/tab-absolute-elements.js":
|
|
16614
|
+
/*!********************************************************!*\
|
|
16615
|
+
!*** ./src/tablatures/render/tab-absolute-elements.js ***!
|
|
16616
|
+
\********************************************************/
|
|
16466
16617
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16467
16618
|
|
|
16468
16619
|
/**
|
|
16469
16620
|
* Tablature Absolute elements factory
|
|
16470
16621
|
*/
|
|
16471
|
-
var AbsoluteElement = __webpack_require__(/*!
|
|
16472
|
-
var RelativeElement = __webpack_require__(/*!
|
|
16622
|
+
var AbsoluteElement = __webpack_require__(/*! ../../write/creation/elements/absolute-element */ "./src/write/creation/elements/absolute-element.js");
|
|
16623
|
+
var RelativeElement = __webpack_require__(/*! ../../write/creation/elements/relative-element */ "./src/write/creation/elements/relative-element.js");
|
|
16473
16624
|
function isObject(a) {
|
|
16474
16625
|
return a != null && a.constructor === Object;
|
|
16475
16626
|
}
|
|
@@ -16556,6 +16707,7 @@ function lyricsDim(abs) {
|
|
|
16556
16707
|
return null;
|
|
16557
16708
|
}
|
|
16558
16709
|
function TabAbsoluteElements() {
|
|
16710
|
+
//console.log("RENDER TabAbsoluteElements constructor")
|
|
16559
16711
|
this.accidentals = null;
|
|
16560
16712
|
}
|
|
16561
16713
|
function getInitialStaffSize(staffGroup) {
|
|
@@ -16614,10 +16766,9 @@ function graceInRest(absElem) {
|
|
|
16614
16766
|
function convertToNumber(plugin, pitches, graceNotes) {
|
|
16615
16767
|
var tabPos = plugin.semantics.notesToNumber(pitches, graceNotes);
|
|
16616
16768
|
if (tabPos.error) {
|
|
16617
|
-
plugin.
|
|
16769
|
+
plugin.setError(tabPos.error);
|
|
16618
16770
|
return tabPos; // give up on error here
|
|
16619
16771
|
}
|
|
16620
|
-
|
|
16621
16772
|
if (tabPos.graces && tabPos.notes) {
|
|
16622
16773
|
// add graces to last note in notes
|
|
16623
16774
|
var posNote = tabPos.notes.length - 1;
|
|
@@ -16647,6 +16798,7 @@ function buildGraceRelativesForRest(plugin, abs, absChild, graceNotes, tabVoice)
|
|
|
16647
16798
|
* @param {*} staffAbsolute
|
|
16648
16799
|
*/
|
|
16649
16800
|
TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice, voiceIndex, staffIndex, keySig, tabVoiceIndex) {
|
|
16801
|
+
//console.log("RENDER TabAbsoluteElements build")
|
|
16650
16802
|
var staffSize = getInitialStaffSize(staffAbsolute);
|
|
16651
16803
|
var source = staffAbsolute[staffIndex + voiceIndex];
|
|
16652
16804
|
var dest = staffAbsolute[tabVoiceIndex];
|
|
@@ -16667,17 +16819,17 @@ TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice,
|
|
|
16667
16819
|
// }
|
|
16668
16820
|
if (absChild.isClef) {
|
|
16669
16821
|
dest.children.push(buildTabAbsolute(plugin, absX, relX));
|
|
16670
|
-
if (absChild.abcelem.type.indexOf('-8') >= 0) plugin.semantics.
|
|
16671
|
-
if (absChild.abcelem.type.indexOf('+8') >= 0) plugin.semantics.
|
|
16822
|
+
if (absChild.abcelem.type.indexOf('-8') >= 0) plugin.semantics.clefTranspose = -12;
|
|
16823
|
+
if (absChild.abcelem.type.indexOf('+8') >= 0) plugin.semantics.clefTranspose = 12;
|
|
16672
16824
|
}
|
|
16673
16825
|
switch (absChild.type) {
|
|
16674
16826
|
case 'staff-extra key-signature':
|
|
16675
16827
|
// refresh key accidentals
|
|
16676
16828
|
this.accidentals = absChild.abcelem.accidentals;
|
|
16677
|
-
plugin.semantics.
|
|
16829
|
+
plugin.semantics.accidentals = this.accidentals;
|
|
16678
16830
|
break;
|
|
16679
16831
|
case 'bar':
|
|
16680
|
-
plugin.semantics.
|
|
16832
|
+
plugin.semantics.measureAccidentals = {};
|
|
16681
16833
|
var lastBar = false;
|
|
16682
16834
|
if (ii === source.children.length - 1) {
|
|
16683
16835
|
// used for final line bar drawing
|
|
@@ -16777,50 +16929,16 @@ module.exports = TabAbsoluteElements;
|
|
|
16777
16929
|
|
|
16778
16930
|
/***/ }),
|
|
16779
16931
|
|
|
16780
|
-
/***/ "./src/tablatures/tab-
|
|
16781
|
-
|
|
16782
|
-
!*** ./src/tablatures/tab-
|
|
16783
|
-
|
|
16784
|
-
/***/ (function(module) {
|
|
16785
|
-
|
|
16786
|
-
/**
|
|
16787
|
-
*
|
|
16788
|
-
* Common Class/Method available for all instruments
|
|
16789
|
-
*
|
|
16790
|
-
*/
|
|
16791
|
-
|
|
16792
|
-
function TabCommon(abcTune, tuneNumber, params) {
|
|
16793
|
-
this.tune = abcTune;
|
|
16794
|
-
this.params = params;
|
|
16795
|
-
this.tuneNumber = tuneNumber;
|
|
16796
|
-
this.inError = false;
|
|
16797
|
-
}
|
|
16798
|
-
TabCommon.prototype.setError = function (error) {
|
|
16799
|
-
var tune = this.tune;
|
|
16800
|
-
if (error) {
|
|
16801
|
-
this.error = error;
|
|
16802
|
-
this.inError = true;
|
|
16803
|
-
if (tune.warnings) {
|
|
16804
|
-
tune.warnings.push(error);
|
|
16805
|
-
} else {
|
|
16806
|
-
tune.warnings = [error];
|
|
16807
|
-
}
|
|
16808
|
-
}
|
|
16809
|
-
};
|
|
16810
|
-
module.exports = TabCommon;
|
|
16811
|
-
|
|
16812
|
-
/***/ }),
|
|
16813
|
-
|
|
16814
|
-
/***/ "./src/tablatures/tab-renderer.js":
|
|
16815
|
-
/*!****************************************!*\
|
|
16816
|
-
!*** ./src/tablatures/tab-renderer.js ***!
|
|
16817
|
-
\****************************************/
|
|
16932
|
+
/***/ "./src/tablatures/render/tab-renderer.js":
|
|
16933
|
+
/*!***********************************************!*\
|
|
16934
|
+
!*** ./src/tablatures/render/tab-renderer.js ***!
|
|
16935
|
+
\***********************************************/
|
|
16818
16936
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16819
16937
|
|
|
16820
16938
|
/* eslint-disable no-debugger */
|
|
16821
|
-
var VoiceElement = __webpack_require__(/*!
|
|
16822
|
-
var TabAbsoluteElements = __webpack_require__(/*! ./tab-absolute-elements */ "./src/tablatures/tab-absolute-elements.js");
|
|
16823
|
-
var spacing = __webpack_require__(/*!
|
|
16939
|
+
var VoiceElement = __webpack_require__(/*! ../../write/creation/elements/voice-element */ "./src/write/creation/elements/voice-element.js");
|
|
16940
|
+
var TabAbsoluteElements = __webpack_require__(/*! ./tab-absolute-elements */ "./src/tablatures/render/tab-absolute-elements.js");
|
|
16941
|
+
var spacing = __webpack_require__(/*! ../../write/helpers/spacing */ "./src/write/helpers/spacing.js");
|
|
16824
16942
|
function initSpecialY() {
|
|
16825
16943
|
return {
|
|
16826
16944
|
tempoHeightAbove: 0,
|
|
@@ -16848,13 +16966,11 @@ function getLyricHeight(voice) {
|
|
|
16848
16966
|
}
|
|
16849
16967
|
return maxLyricHeight; // add spacing
|
|
16850
16968
|
}
|
|
16851
|
-
|
|
16852
|
-
|
|
16853
|
-
var
|
|
16854
|
-
var
|
|
16855
|
-
var
|
|
16856
|
-
var tabName = stringSemantics.tabInfos(self.plugin);
|
|
16857
|
-
var suppress = stringSemantics.suppress(self.plugin);
|
|
16969
|
+
function buildTabName(plugin, renderer, dest) {
|
|
16970
|
+
var stringSemantics = plugin.semantics;
|
|
16971
|
+
var textSize = renderer.controller.getTextSize;
|
|
16972
|
+
var tabName = stringSemantics.tabInfos(plugin);
|
|
16973
|
+
var suppress = stringSemantics.suppress(plugin);
|
|
16858
16974
|
var doDraw = true;
|
|
16859
16975
|
if (suppress) {
|
|
16860
16976
|
doDraw = false;
|
|
@@ -16872,27 +16988,6 @@ function buildTabName(self, dest) {
|
|
|
16872
16988
|
}
|
|
16873
16989
|
return 0;
|
|
16874
16990
|
}
|
|
16875
|
-
|
|
16876
|
-
/**
|
|
16877
|
-
* Laying out tabs
|
|
16878
|
-
* @param {*} renderer
|
|
16879
|
-
* @param {*} line
|
|
16880
|
-
* @param {*} staffIndex
|
|
16881
|
-
* @param {*} tablatureLayout
|
|
16882
|
-
*/
|
|
16883
|
-
function TabRenderer(plugin, renderer, line, staffIndex) {
|
|
16884
|
-
this.renderer = renderer;
|
|
16885
|
-
this.plugin = plugin;
|
|
16886
|
-
this.line = line;
|
|
16887
|
-
this.absolutes = new TabAbsoluteElements();
|
|
16888
|
-
this.staffIndex = staffIndex;
|
|
16889
|
-
this.tabStaff = {
|
|
16890
|
-
clef: {
|
|
16891
|
-
type: 'TAB'
|
|
16892
|
-
}
|
|
16893
|
-
};
|
|
16894
|
-
this.tabSize = plugin.linePitch * plugin.nbLines;
|
|
16895
|
-
}
|
|
16896
16991
|
function islastTabInStaff(index, staffGroup) {
|
|
16897
16992
|
if (staffGroup[index].isTabStaff) {
|
|
16898
16993
|
if (index === staffGroup.length - 1) return true;
|
|
@@ -16938,8 +17033,7 @@ function isMultiVoiceSingleStaff(staffs, parent) {
|
|
|
16938
17033
|
}
|
|
16939
17034
|
return false;
|
|
16940
17035
|
}
|
|
16941
|
-
function getNextTabPos(
|
|
16942
|
-
var tabIndex = self.staffIndex;
|
|
17036
|
+
function getNextTabPos(tabIndex, staffGroup) {
|
|
16943
17037
|
var startIndex = 0;
|
|
16944
17038
|
var handledVoices = 0;
|
|
16945
17039
|
var inProgress = true;
|
|
@@ -16950,7 +17044,6 @@ function getNextTabPos(self, staffGroup) {
|
|
|
16950
17044
|
if (!staffGroup[startIndex].isTabStaff) {
|
|
16951
17045
|
nbVoices = staffGroup[startIndex].voices.length; // get number of staff voices
|
|
16952
17046
|
}
|
|
16953
|
-
|
|
16954
17047
|
if (staffGroup[startIndex].isTabStaff) {
|
|
16955
17048
|
handledVoices++;
|
|
16956
17049
|
if (islastTabInStaff(startIndex, staffGroup)) {
|
|
@@ -16988,30 +17081,38 @@ function checkVoiceKeySig(voices, ii) {
|
|
|
16988
17081
|
}
|
|
16989
17082
|
return voices[ii - 1].children[0];
|
|
16990
17083
|
}
|
|
16991
|
-
|
|
16992
|
-
|
|
17084
|
+
function tabRenderer(plugin, renderer, line, staffIndex) {
|
|
17085
|
+
//console.log("RENDER tabRenderer")
|
|
17086
|
+
var absolutes = new TabAbsoluteElements();
|
|
17087
|
+
var tabStaff = {
|
|
17088
|
+
clef: {
|
|
17089
|
+
type: 'TAB'
|
|
17090
|
+
}
|
|
17091
|
+
};
|
|
17092
|
+
var tabSize = plugin.linePitch * plugin.nbLines;
|
|
17093
|
+
var staffs = line.staff;
|
|
16993
17094
|
if (staffs) {
|
|
16994
17095
|
// give up on staffline=0 in key
|
|
16995
17096
|
var firstStaff = staffs[0];
|
|
16996
17097
|
if (firstStaff) {
|
|
16997
17098
|
if (firstStaff.clef) {
|
|
16998
17099
|
if (firstStaff.clef.stafflines == 0) {
|
|
16999
|
-
|
|
17100
|
+
plugin.setError("No tablatures when stafflines=0");
|
|
17000
17101
|
return;
|
|
17001
17102
|
}
|
|
17002
17103
|
}
|
|
17003
17104
|
}
|
|
17004
|
-
staffs.splice(staffs.length, 0,
|
|
17105
|
+
staffs.splice(staffs.length, 0, tabStaff);
|
|
17005
17106
|
}
|
|
17006
|
-
var staffGroup =
|
|
17107
|
+
var staffGroup = line.staffGroup;
|
|
17007
17108
|
var voices = staffGroup.voices;
|
|
17008
17109
|
var firstVoice = voices[0];
|
|
17009
17110
|
// take lyrics into account if any
|
|
17010
17111
|
var lyricsHeight = getLyricHeight(firstVoice);
|
|
17011
17112
|
var padd = 3;
|
|
17012
|
-
var prevIndex =
|
|
17113
|
+
var prevIndex = staffIndex;
|
|
17013
17114
|
var previousStaff = staffGroup.staffs[prevIndex];
|
|
17014
|
-
var tabTop =
|
|
17115
|
+
var tabTop = tabSize + padd - previousStaff.bottom - lyricsHeight;
|
|
17015
17116
|
if (previousStaff.isTabStaff) {
|
|
17016
17117
|
tabTop = previousStaff.top;
|
|
17017
17118
|
}
|
|
@@ -17019,44 +17120,43 @@ TabRenderer.prototype.doLayout = function () {
|
|
|
17019
17120
|
bottom: -1,
|
|
17020
17121
|
isTabStaff: true,
|
|
17021
17122
|
specialY: initSpecialY(),
|
|
17022
|
-
lines:
|
|
17023
|
-
linePitch:
|
|
17123
|
+
lines: plugin.nbLines,
|
|
17124
|
+
linePitch: plugin.linePitch,
|
|
17024
17125
|
dy: 0.15,
|
|
17025
17126
|
top: tabTop
|
|
17026
17127
|
};
|
|
17027
|
-
var nextTabPos = getNextTabPos(
|
|
17128
|
+
var nextTabPos = getNextTabPos(staffIndex, staffGroup.staffs);
|
|
17028
17129
|
if (nextTabPos === -1) return;
|
|
17029
17130
|
staffGroupInfos.parentIndex = nextTabPos - 1;
|
|
17030
17131
|
staffGroup.staffs.splice(nextTabPos, 0, staffGroupInfos);
|
|
17031
17132
|
// staffGroup.staffs.push(staffGroupInfos);
|
|
17032
|
-
staffGroup.height +=
|
|
17133
|
+
staffGroup.height += tabSize + padd;
|
|
17033
17134
|
var parentStaff = getLastStaff(staffGroup.staffs, nextTabPos);
|
|
17034
17135
|
var nbVoices = 1;
|
|
17035
17136
|
if (isMultiVoiceSingleStaff(staffGroup.staffs, parentStaff)) {
|
|
17036
17137
|
nbVoices = parentStaff.voices.length;
|
|
17037
17138
|
}
|
|
17038
17139
|
// build from staff
|
|
17039
|
-
|
|
17140
|
+
tabStaff.voices = [];
|
|
17040
17141
|
for (var ii = 0; ii < nbVoices; ii++) {
|
|
17041
17142
|
var tabVoice = new VoiceElement(0, 0);
|
|
17042
17143
|
if (ii > 0) tabVoice.duplicate = true;
|
|
17043
|
-
var nameHeight = buildTabName(
|
|
17144
|
+
var nameHeight = buildTabName(plugin, renderer, tabVoice) / spacing.STEP;
|
|
17044
17145
|
nameHeight = Math.max(nameHeight, 1); // If there is no label for the tab line, then there needs to be a little padding
|
|
17045
17146
|
// This was pushing down the top staff by the tab label height
|
|
17046
|
-
//staffGroup.staffs[
|
|
17047
|
-
staffGroup.staffs[
|
|
17147
|
+
//staffGroup.staffs[staffIndex].top += nameHeight;
|
|
17148
|
+
staffGroup.staffs[staffIndex].top += 1;
|
|
17048
17149
|
staffGroup.height += nameHeight;
|
|
17049
17150
|
tabVoice.staff = staffGroupInfos;
|
|
17050
17151
|
var tabVoiceIndex = voices.length;
|
|
17051
17152
|
voices.splice(voices.length, 0, tabVoice);
|
|
17052
|
-
var keySig = checkVoiceKeySig(voices, ii +
|
|
17053
|
-
|
|
17054
|
-
|
|
17153
|
+
var keySig = checkVoiceKeySig(voices, ii + staffIndex);
|
|
17154
|
+
tabStaff.voices[ii] = [];
|
|
17155
|
+
absolutes.build(plugin, voices, tabStaff.voices[ii], ii, staffIndex, keySig, tabVoiceIndex);
|
|
17055
17156
|
}
|
|
17056
17157
|
linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
|
|
17057
|
-
}
|
|
17058
|
-
|
|
17059
|
-
module.exports = TabRenderer;
|
|
17158
|
+
}
|
|
17159
|
+
module.exports = tabRenderer;
|
|
17060
17160
|
|
|
17061
17161
|
/***/ }),
|
|
17062
17162
|
|
|
@@ -17275,7 +17375,6 @@ AbstractEngraver.prototype.createABCStaff = function (staffgroup, abcstaff, temp
|
|
|
17275
17375
|
} else {
|
|
17276
17376
|
voice.duplicate = true; // bar lines and other duplicate info need not be created
|
|
17277
17377
|
}
|
|
17278
|
-
|
|
17279
17378
|
if (abcstaff.title && abcstaff.title[v]) {
|
|
17280
17379
|
voice.header = abcstaff.title[v].replace(/\\n/g, "\n");
|
|
17281
17380
|
voice.headerPosition = 6 + staffgroup.getTextSize.baselineToCenter(voice.header, "voicefont", 'staff-extra voice-name', v, abcstaff.voices.length) / spacing.STEP;
|
|
@@ -17289,13 +17388,11 @@ AbstractEngraver.prototype.createABCStaff = function (staffgroup, abcstaff, temp
|
|
|
17289
17388
|
voice.addChild(clef);
|
|
17290
17389
|
this.startlimitelem = clef; // limit ties here
|
|
17291
17390
|
}
|
|
17292
|
-
|
|
17293
17391
|
var keySig = createKeySignature(abcstaff.key, this.tuneNumber);
|
|
17294
17392
|
if (keySig) {
|
|
17295
17393
|
voice.addChild(keySig);
|
|
17296
17394
|
this.startlimitelem = keySig; // limit ties here
|
|
17297
17395
|
}
|
|
17298
|
-
|
|
17299
17396
|
if (abcstaff.meter) {
|
|
17300
17397
|
if (abcstaff.meter.type === 'specified') {
|
|
17301
17398
|
this.measureLength = abcstaff.meter.value[0].num / abcstaff.meter.value[0].den;
|
|
@@ -17304,7 +17401,6 @@ AbstractEngraver.prototype.createABCStaff = function (staffgroup, abcstaff, temp
|
|
|
17304
17401
|
voice.addChild(ts);
|
|
17305
17402
|
this.startlimitelem = ts; // limit ties here
|
|
17306
17403
|
}
|
|
17307
|
-
|
|
17308
17404
|
if (voice.duplicate) voice.children = []; // we shouldn't reprint the above if we're reusing the same staff. We just created them to get the right spacing.
|
|
17309
17405
|
var staffLines = abcstaff.clef.stafflines || abcstaff.clef.stafflines === 0 ? abcstaff.clef.stafflines : 5;
|
|
17310
17406
|
staffgroup.addVoice(voice, s, staffLines);
|
|
@@ -17468,7 +17564,6 @@ AbstractEngraver.prototype.createABCElement = function (isFirstStaff, isSingleLi
|
|
|
17468
17564
|
elemset[0] = absKey;
|
|
17469
17565
|
this.startlimitelem = elemset[0]; // limit ties here
|
|
17470
17566
|
}
|
|
17471
|
-
|
|
17472
17567
|
if (voice.duplicate && elemset.length > 0) elemset[0].invisible = true;
|
|
17473
17568
|
break;
|
|
17474
17569
|
case "stem":
|
|
@@ -17602,7 +17697,6 @@ AbstractEngraver.prototype.addGraceNotes = function (elem, voice, abselem, noteh
|
|
|
17602
17697
|
if (hint) gracebeam.setHint();
|
|
17603
17698
|
gracebeam.mainNote = abselem; // this gives us a reference back to the note this is attached to so that the stems can be attached somewhere.
|
|
17604
17699
|
}
|
|
17605
|
-
|
|
17606
17700
|
var i;
|
|
17607
17701
|
var graceoffsets = [];
|
|
17608
17702
|
for (i = elem.gracenotes.length - 1; i >= 0; i--) {
|
|
@@ -17702,7 +17796,6 @@ function addRestToAbsElement(abselem, elem, duration, dot, isMultiVoice, stemdir
|
|
|
17702
17796
|
if (duration < 0.5) restpitch = 7;else if (duration < 1) restpitch = 7; // half rest
|
|
17703
17797
|
else restpitch = 5; // whole rest
|
|
17704
17798
|
}
|
|
17705
|
-
|
|
17706
17799
|
switch (elem.rest.type) {
|
|
17707
17800
|
case "whole":
|
|
17708
17801
|
c = chartable.rest[0];
|
|
@@ -17841,7 +17934,6 @@ AbstractEngraver.prototype.addNoteToAbcElement = function (abselem, elem, dot, s
|
|
|
17841
17934
|
elem.pitches[p].highestVert = elem.pitches[pp - 1].verticalPos;
|
|
17842
17935
|
if (getDuration(elem) < 1 && (stemdir === "up" || dir === "up")) elem.pitches[p].highestVert += 6; // If the stem is up, then compensate for the length of the stem
|
|
17843
17936
|
}
|
|
17844
|
-
|
|
17845
17937
|
if (elem.startSlur) {
|
|
17846
17938
|
if (!elem.pitches[p].startSlur) elem.pitches[p].startSlur = []; //TODO possibly redundant, provided array is not optional
|
|
17847
17939
|
for (i = 0; i < elem.startSlur.length; i++) {
|
|
@@ -17990,7 +18082,7 @@ AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaf
|
|
|
17990
18082
|
if (elem.decoration) {
|
|
17991
18083
|
// TODO-PER: nostem is true if this is beamed. In that case we don't know where to place the decoration yet so just make a guess. This should be refactored to not place decorations until after the beams are determined.
|
|
17992
18084
|
// This should probably be combined with moveDecorations()
|
|
17993
|
-
var bottom = nostem ? Math.min(-3, abselem.bottom - 6) : abselem.bottom;
|
|
18085
|
+
var bottom = nostem && dir !== 'up' ? Math.min(-3, abselem.bottom - 6) : abselem.bottom;
|
|
17994
18086
|
this.decoration.createDecoration(voice, elem.decoration, abselem.top, notehead ? notehead.w : 0, abselem, roomtaken, dir, bottom, elem.positioning, this.hasVocals, this.accentAbove);
|
|
17995
18087
|
}
|
|
17996
18088
|
if (elem.barNumber) {
|
|
@@ -18011,7 +18103,6 @@ AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaf
|
|
|
18011
18103
|
flatBeams: this.flatBeams
|
|
18012
18104
|
}); // above is opposite from case of slurs
|
|
18013
18105
|
}
|
|
18014
|
-
|
|
18015
18106
|
if (elem.endTriplet && this.triplet) {
|
|
18016
18107
|
this.triplet.setCloseAnchor(notehead);
|
|
18017
18108
|
}
|
|
@@ -18145,7 +18236,6 @@ AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff)
|
|
|
18145
18236
|
abselem.addRight(new RelativeElement("dots.dot", dx, 1, 5));
|
|
18146
18237
|
dx += 6; //2 hardcoded, twice;
|
|
18147
18238
|
}
|
|
18148
|
-
|
|
18149
18239
|
if (firstthin) {
|
|
18150
18240
|
anchor = new RelativeElement(null, dx, 1, 2, {
|
|
18151
18241
|
"type": "bar",
|
|
@@ -18194,7 +18284,6 @@ AbstractEngraver.prototype.createBarLine = function (voice, elem, isFirstStaff)
|
|
|
18194
18284
|
});
|
|
18195
18285
|
abselem.addRight(anchor); // 3 is hardcoded
|
|
18196
18286
|
}
|
|
18197
|
-
|
|
18198
18287
|
if (seconddots) {
|
|
18199
18288
|
dx += 3; //3 hardcoded;
|
|
18200
18289
|
abselem.addRight(new RelativeElement("dots.dot", dx, 1, 7));
|
|
@@ -18528,7 +18617,6 @@ var createClef = function createClef(elem, tuneNumber) {
|
|
|
18528
18617
|
//abselem.top += 2;
|
|
18529
18618
|
}
|
|
18530
18619
|
}
|
|
18531
|
-
|
|
18532
18620
|
return abselem;
|
|
18533
18621
|
};
|
|
18534
18622
|
function clefOffsets(clef) {
|
|
@@ -18720,7 +18808,6 @@ var createNoteHead = function createNoteHead(abselem, c, pitchelem, options) {
|
|
|
18720
18808
|
}));
|
|
18721
18809
|
extraLeft = glyphs.getSymbolWidth(symb) / 2; // TODO-PER: We need a little extra width if there is an accidental, but I'm not sure why it isn't the full width of the accidental.
|
|
18722
18810
|
}
|
|
18723
|
-
|
|
18724
18811
|
return {
|
|
18725
18812
|
notehead: notehead,
|
|
18726
18813
|
accidentalshiftx: accidentalshiftx,
|
|
@@ -19511,7 +19598,6 @@ BeamElem.prototype.setStemDirection = function () {
|
|
|
19511
19598
|
var middleLine = 6; // hardcoded 6 is B
|
|
19512
19599
|
this.stemsUp = this.average < middleLine; // true is up, false is down;
|
|
19513
19600
|
}
|
|
19514
|
-
|
|
19515
19601
|
delete this.count;
|
|
19516
19602
|
this.total = 0;
|
|
19517
19603
|
};
|
|
@@ -19525,7 +19611,6 @@ BeamElem.prototype.calcDir = function () {
|
|
|
19525
19611
|
var middleLine = 6; // hardcoded 6 is B
|
|
19526
19612
|
this.stemsUp = this.average < middleLine; // true is up, false is down;
|
|
19527
19613
|
}
|
|
19528
|
-
|
|
19529
19614
|
var dir = this.stemsUp ? 'up' : 'down';
|
|
19530
19615
|
for (var i = 0; i < this.elems.length; i++) {
|
|
19531
19616
|
for (var j = 0; j < this.elems[i].heads.length; j++) {
|
|
@@ -19715,7 +19800,6 @@ BraceElem.prototype.continuing = function (voice) {
|
|
|
19715
19800
|
BraceElem.prototype.getWidth = function () {
|
|
19716
19801
|
return 10; // TODO-PER: right now the drawing function doesn't vary the width at all. If it does in the future then this will change.
|
|
19717
19802
|
};
|
|
19718
|
-
|
|
19719
19803
|
BraceElem.prototype.isStartVoice = function (voice) {
|
|
19720
19804
|
if (this.startVoice && this.startVoice.staff && this.startVoice.staff.voices.length > 0 && this.startVoice.staff.voices[0] === voice) return true;
|
|
19721
19805
|
return false;
|
|
@@ -19740,7 +19824,6 @@ var CrescendoElem = function CrescendoElem(anchor1, anchor2, dir, positioning) {
|
|
|
19740
19824
|
if (positioning === 'above') this.dynamicHeightAbove = 6;else this.dynamicHeightBelow = 6;
|
|
19741
19825
|
this.pitch = undefined; // This will be set later
|
|
19742
19826
|
};
|
|
19743
|
-
|
|
19744
19827
|
module.exports = CrescendoElem;
|
|
19745
19828
|
|
|
19746
19829
|
/***/ }),
|
|
@@ -19760,7 +19843,6 @@ var DynamicDecoration = function DynamicDecoration(anchor, dec, position) {
|
|
|
19760
19843
|
if (position === 'below') this.volumeHeightBelow = 6;else this.volumeHeightAbove = 6;
|
|
19761
19844
|
this.pitch = undefined; // This will be set later
|
|
19762
19845
|
};
|
|
19763
|
-
|
|
19764
19846
|
module.exports = DynamicDecoration;
|
|
19765
19847
|
|
|
19766
19848
|
/***/ }),
|
|
@@ -19781,7 +19863,6 @@ var EndingElem = function EndingElem(text, anchor1, anchor2) {
|
|
|
19781
19863
|
this.endingHeightAbove = 5;
|
|
19782
19864
|
this.pitch = undefined; // This will be set later
|
|
19783
19865
|
};
|
|
19784
|
-
|
|
19785
19866
|
module.exports = EndingElem;
|
|
19786
19867
|
|
|
19787
19868
|
/***/ }),
|
|
@@ -19887,7 +19968,6 @@ var GlissandoElem = function GlissandoElem(anchor1, anchor2) {
|
|
|
19887
19968
|
this.anchor1 = anchor1; // must have a .x and a .parent property or be null (means starts at the "beginning" of the line - after keysig)
|
|
19888
19969
|
this.anchor2 = anchor2; // must have a .x property or be null (means ends at the end of the line)
|
|
19889
19970
|
};
|
|
19890
|
-
|
|
19891
19971
|
module.exports = GlissandoElem;
|
|
19892
19972
|
|
|
19893
19973
|
/***/ }),
|
|
@@ -20422,14 +20502,12 @@ TieElem.prototype.calcX = function (lineStartX, lineEndX) {
|
|
|
20422
20502
|
if (this.anchor2) this.startX = this.anchor2.x - 20; // There is no element and no repeat mark: make a small arc
|
|
20423
20503
|
else this.startX = lineStartX; // Don't have any guidance, so extend to beginning of line
|
|
20424
20504
|
}
|
|
20425
|
-
|
|
20426
20505
|
if (!this.anchor1 && this.dotted) this.startX -= 3; // The arc needs to be long enough to tell that it is dotted.
|
|
20427
20506
|
|
|
20428
20507
|
if (this.anchor2) this.endX = this.anchor2.x; // The normal case where there is a starting element to attach to.
|
|
20429
20508
|
else if (this.endLimitX) this.endX = this.endLimitX.x; // if there is no start element, but there is a repeat mark before the start of the line.
|
|
20430
20509
|
else this.endX = lineEndX; // There is no element and no repeat mark: extend to the beginning of the line.
|
|
20431
20510
|
};
|
|
20432
|
-
|
|
20433
20511
|
TieElem.prototype.calcTieY = function () {
|
|
20434
20512
|
// If the tie comes from another line, then one or both anchors will be missing.
|
|
20435
20513
|
if (this.anchor1) this.startY = this.anchor1.pitch;else if (this.anchor2) this.startY = this.anchor2.pitch;else this.startY = this.above ? 14 : 0;
|
|
@@ -20492,6 +20570,30 @@ TieElem.prototype.avoidCollisionAbove = function () {
|
|
|
20492
20570
|
if (maxInnerHeight > this.startY && maxInnerHeight > this.endY) this.startY = this.endY = maxInnerHeight - 1;
|
|
20493
20571
|
}
|
|
20494
20572
|
};
|
|
20573
|
+
TieElem.prototype.getYBounds = function () {
|
|
20574
|
+
var lineStartX = 10; // TODO-PER: I'm not sure where to get this number from but it probably doesn't matter much
|
|
20575
|
+
var lineEndX = 1000; // TODO-PER: I'm not sure where to get this number from but it probably doesn't matter much
|
|
20576
|
+
if (this.isTie) {
|
|
20577
|
+
this.calcTieDirection();
|
|
20578
|
+
this.calcX(lineStartX, lineEndX);
|
|
20579
|
+
this.calcTieY();
|
|
20580
|
+
} else {
|
|
20581
|
+
this.calcSlurDirection();
|
|
20582
|
+
this.calcX(lineStartX, lineEndX);
|
|
20583
|
+
this.calcSlurY();
|
|
20584
|
+
}
|
|
20585
|
+
var top;
|
|
20586
|
+
var bottom;
|
|
20587
|
+
// TODO-PER: It's hard to tell how far the arc is, so I'm just using 3 as the max
|
|
20588
|
+
if (this.above) {
|
|
20589
|
+
bottom = Math.min(this.startY, this.endY);
|
|
20590
|
+
top = bottom + 3;
|
|
20591
|
+
} else {
|
|
20592
|
+
top = Math.min(this.startY, this.endY);
|
|
20593
|
+
bottom = top - 3;
|
|
20594
|
+
}
|
|
20595
|
+
return [top, bottom];
|
|
20596
|
+
};
|
|
20495
20597
|
module.exports = TieElem;
|
|
20496
20598
|
|
|
20497
20599
|
/***/ }),
|
|
@@ -20542,7 +20644,6 @@ function TopText(metaText, metaTextInfo, formatting, lines, width, isPrint, padd
|
|
|
20542
20644
|
|
|
20543
20645
|
// TopText.prototype.addTextIf = function (marginLeft, text, font, klass, marginTop, marginBottom, anchor, getTextSize, absElemType, noMove) {
|
|
20544
20646
|
}
|
|
20545
|
-
|
|
20546
20647
|
if (isPrint) this.rows.push({
|
|
20547
20648
|
move: spacing.top
|
|
20548
20649
|
});
|
|
@@ -21614,7 +21715,6 @@ function straightPath(renderer, xLeft, yTop, yBottom, type) {
|
|
|
21614
21715
|
// right point
|
|
21615
21716
|
-wCurve * 0.1, -hCurve * 0.3, -wCurve, -hCurve - spacing.STEP // left bottom
|
|
21616
21717
|
);
|
|
21617
|
-
|
|
21618
21718
|
return renderer.paper.path({
|
|
21619
21719
|
path: pathString,
|
|
21620
21720
|
stroke: renderer.foregroundColor,
|
|
@@ -22893,7 +22993,6 @@ function drawStaffGroup(renderer, params, selectables, lineNumber) {
|
|
|
22893
22993
|
// renderer.moveY(spacing.STEP, -staff.bottom);
|
|
22894
22994
|
}
|
|
22895
22995
|
}
|
|
22896
|
-
|
|
22897
22996
|
renderer.controller.classes.newMeasure();
|
|
22898
22997
|
|
|
22899
22998
|
// connect all the staves together with a vertical line
|
|
@@ -23115,7 +23214,6 @@ function drawTempo(renderer, params) {
|
|
|
23115
23214
|
// });
|
|
23116
23215
|
//return [tempoGroup];
|
|
23117
23216
|
}
|
|
23118
|
-
|
|
23119
23217
|
module.exports = drawTempo;
|
|
23120
23218
|
|
|
23121
23219
|
/***/ }),
|
|
@@ -23452,7 +23550,6 @@ function drawVoice(renderer, params, bartop, selectables, staffPos) {
|
|
|
23452
23550
|
renderer.controller.classes.incrMeasure();
|
|
23453
23551
|
} else drawBeam(renderer, beam, selectables); // beams must be drawn first for proper printing of triplets, slurs and ties.
|
|
23454
23552
|
}
|
|
23455
|
-
|
|
23456
23553
|
renderer.controller.classes.startMeasure();
|
|
23457
23554
|
for (i = 0; i < params.otherchildren.length; i++) {
|
|
23458
23555
|
child = params.otherchildren[i];
|
|
@@ -23519,7 +23616,7 @@ var Classes = __webpack_require__(/*! ./helpers/classes */ "./src/write/helpers/
|
|
|
23519
23616
|
var GetFontAndAttr = __webpack_require__(/*! ./helpers/get-font-and-attr */ "./src/write/helpers/get-font-and-attr.js");
|
|
23520
23617
|
var GetTextSize = __webpack_require__(/*! ./helpers/get-text-size */ "./src/write/helpers/get-text-size.js");
|
|
23521
23618
|
var draw = __webpack_require__(/*! ./draw/draw */ "./src/write/draw/draw.js");
|
|
23522
|
-
var tablatures = __webpack_require__(/*! ../
|
|
23619
|
+
var tablatures = __webpack_require__(/*! ../tablatures/abc_tablatures */ "./src/tablatures/abc_tablatures.js");
|
|
23523
23620
|
var findSelectableElement = __webpack_require__(/*! ./interactive/find-selectable-element */ "./src/write/interactive/find-selectable-element.js");
|
|
23524
23621
|
|
|
23525
23622
|
/**
|
|
@@ -23561,7 +23658,6 @@ var EngraverController = function EngraverController(paper, params) {
|
|
|
23561
23658
|
this.staffwidthScreen = 740; // TODO-PER: Not sure where this number comes from, but this is how it's always been.
|
|
23562
23659
|
this.staffwidthPrint = 680; // The number of pixels in 8.5", after 1cm of margin has been removed.
|
|
23563
23660
|
}
|
|
23564
|
-
|
|
23565
23661
|
this.listeners = [];
|
|
23566
23662
|
if (params.clickListener) this.addSelectListener(params.clickListener);
|
|
23567
23663
|
this.renderer = new Renderer(paper);
|
|
@@ -24471,7 +24567,6 @@ function getMousePosition(self, ev) {
|
|
|
24471
24567
|
clickedOn = findElementByCoord(self, x, y);
|
|
24472
24568
|
//console.log("clicked near", clickedOn, x, y, printEl(ev.target));
|
|
24473
24569
|
}
|
|
24474
|
-
|
|
24475
24570
|
return {
|
|
24476
24571
|
x: x,
|
|
24477
24572
|
y: y,
|
|
@@ -24709,7 +24804,6 @@ function minStem(element, stemsUp, referencePitch, minStemHeight) {
|
|
|
24709
24804
|
var elem = element.children[i];
|
|
24710
24805
|
if (stemsUp && elem.top !== undefined && elem.c === "flags.ugrace") minStemHeight = Math.max(minStemHeight, elem.top - referencePitch);else if (!stemsUp && elem.bottom !== undefined && elem.c === "flags.ugrace") minStemHeight = Math.max(minStemHeight, referencePitch - elem.bottom + 7); // The extra 7 is because we are measuring the slash from the top.
|
|
24711
24806
|
}
|
|
24712
|
-
|
|
24713
24807
|
return minStemHeight;
|
|
24714
24808
|
}
|
|
24715
24809
|
function calcSlant(leftAveragePitch, rightAveragePitch, numStems, isFlat) {
|
|
@@ -25114,7 +25208,6 @@ function calcHorizontalSpacing(isLastLine, stretchLast, targetWidth, lineWidth,
|
|
|
25114
25208
|
if (!stretch) return null; // don't stretch last line too much
|
|
25115
25209
|
}
|
|
25116
25210
|
}
|
|
25117
|
-
|
|
25118
25211
|
if (Math.abs(targetWidth - lineWidth) < 2) return null; // if we are already near the target width, we're done.
|
|
25119
25212
|
var relSpace = spacingUnits * spacing;
|
|
25120
25213
|
var constSpace = lineWidth - relSpace;
|
|
@@ -25179,7 +25272,6 @@ var setUpperAndLowerElements = function setUpperAndLowerElements(renderer, staff
|
|
|
25179
25272
|
staff.originalTop = staff.top; // This is just being stored for debugging purposes.
|
|
25180
25273
|
staff.originalBottom = staff.bottom; // This is just being stored for debugging purposes.
|
|
25181
25274
|
}
|
|
25182
|
-
|
|
25183
25275
|
incTop(staff, positionY, 'lyricHeightAbove');
|
|
25184
25276
|
incTop(staff, positionY, 'chordHeightAbove', staff.specialY.chordLines.above);
|
|
25185
25277
|
if (staff.specialY.endingHeightAbove) {
|
|
@@ -25242,7 +25334,6 @@ var setUpperAndLowerElements = function setUpperAndLowerElements(renderer, staff
|
|
|
25242
25334
|
}
|
|
25243
25335
|
//console.log("Staff Height: ",heightInPitches,this.height);
|
|
25244
25336
|
};
|
|
25245
|
-
|
|
25246
25337
|
var margin = 1;
|
|
25247
25338
|
function incTop(staff, positionY, item, count) {
|
|
25248
25339
|
if (staff.specialY[item]) {
|
|
@@ -25271,6 +25362,14 @@ function setUpperAndLowerVoiceElements(positionY, voice, spacing) {
|
|
|
25271
25362
|
case 'EndingElem':
|
|
25272
25363
|
setUpperAndLowerEndingElements(positionY, abselem);
|
|
25273
25364
|
break;
|
|
25365
|
+
case 'TieElem':
|
|
25366
|
+
// If a tie element is the highest or lowest thing then space might need to make room for it.
|
|
25367
|
+
var yBounds = abselem.getYBounds();
|
|
25368
|
+
voice.staff.top = Math.max(voice.staff.top, yBounds[0]);
|
|
25369
|
+
voice.staff.top = Math.max(voice.staff.top, yBounds[1]);
|
|
25370
|
+
voice.staff.bottom = Math.min(voice.staff.bottom, yBounds[0]);
|
|
25371
|
+
voice.staff.bottom = Math.min(voice.staff.bottom, yBounds[1]);
|
|
25372
|
+
break;
|
|
25274
25373
|
}
|
|
25275
25374
|
}
|
|
25276
25375
|
}
|
|
@@ -25499,7 +25598,6 @@ function finished(voices) {
|
|
|
25499
25598
|
function getDurationIndex(element) {
|
|
25500
25599
|
return element.durationindex - (element.children[element.i] && element.children[element.i].duration > 0 ? 0 : 0.0000005); // if the ith element doesn't have a duration (is not a note), its duration index is fractionally before. This enables CLEF KEYSIG TIMESIG PART, etc. to be laid out before we get to the first note of other voices
|
|
25501
25600
|
}
|
|
25502
|
-
|
|
25503
25601
|
function isSameStaff(voice1, voice2) {
|
|
25504
25602
|
if (!voice1 || !voice1.staff || !voice1.staff.voices || voice1.staff.voices.length === 0) return false;
|
|
25505
25603
|
if (!voice2 || !voice2.staff || !voice2.staff.voices || voice2.staff.voices.length === 0) return false;
|
|
@@ -25597,7 +25695,6 @@ VoiceElement.beginLayout = function (startx, voice) {
|
|
|
25597
25695
|
voice.nextx = startx; // x position where the next element of this voice should be placed assuming no other voices and no fixed width constraints
|
|
25598
25696
|
voice.spacingduration = 0; // duration left to be laid out in current iteration (omitting additional spacing due to other aspects, such as bars, dots, sharps and flats)
|
|
25599
25697
|
};
|
|
25600
|
-
|
|
25601
25698
|
VoiceElement.layoutEnded = function (voice) {
|
|
25602
25699
|
return voice.i >= voice.children.length;
|
|
25603
25700
|
};
|
|
@@ -25663,7 +25760,6 @@ VoiceElement.layoutOneItem = function (x, spacing, voice, minPadding, firstVoice
|
|
|
25663
25760
|
|
|
25664
25761
|
return x; // where we end up having placed the child
|
|
25665
25762
|
};
|
|
25666
|
-
|
|
25667
25763
|
VoiceElement.shiftRight = function (dx, voice) {
|
|
25668
25764
|
var child = voice.children[voice.i];
|
|
25669
25765
|
if (!child) return;
|
|
@@ -25826,7 +25922,6 @@ function setLane(absElems, numLanesAbove, numLanesBelow) {
|
|
|
25826
25922
|
}
|
|
25827
25923
|
}
|
|
25828
25924
|
}
|
|
25829
|
-
|
|
25830
25925
|
function yAtNote(element, beam) {
|
|
25831
25926
|
beam = beam.beams[0];
|
|
25832
25927
|
return getBarYAt(beam.startX, beam.startY, beam.endX, beam.endY, element.x);
|
|
@@ -25985,7 +26080,6 @@ Renderer.prototype.initVerticalSpace = function () {
|
|
|
25985
26080
|
<float> range is 0.0 to 1.0.
|
|
25986
26081
|
*/
|
|
25987
26082
|
};
|
|
25988
|
-
|
|
25989
26083
|
Renderer.prototype.setVerticalSpace = function (formatting) {
|
|
25990
26084
|
// conversion from pts to px 4/3
|
|
25991
26085
|
if (formatting.staffsep !== undefined) this.spacing.staffSeparation = formatting.staffsep * 4 / 3;
|
|
@@ -26107,7 +26201,6 @@ Svg.prototype.insertStyles = function (styles) {
|
|
|
26107
26201
|
this.svg.insertBefore(el, this.svg.firstChild); // prepend is not available on older browsers.
|
|
26108
26202
|
// this.svg.prepend(el);
|
|
26109
26203
|
};
|
|
26110
|
-
|
|
26111
26204
|
Svg.prototype.setParentStyles = function (attr) {
|
|
26112
26205
|
// This is needed to get the size right when there is scaling involved.
|
|
26113
26206
|
for (var key in attr) {
|
|
@@ -26250,7 +26343,6 @@ Svg.prototype.guessWidth = function (text, attr) {
|
|
|
26250
26343
|
height: attr['font-size'] + 2
|
|
26251
26344
|
}; // Just a wild guess.
|
|
26252
26345
|
}
|
|
26253
|
-
|
|
26254
26346
|
svg.removeChild(el);
|
|
26255
26347
|
return size;
|
|
26256
26348
|
};
|
|
@@ -26379,7 +26471,7 @@ module.exports = Svg;
|
|
|
26379
26471
|
\********************/
|
|
26380
26472
|
/***/ (function(module) {
|
|
26381
26473
|
|
|
26382
|
-
var version = '6.4.
|
|
26474
|
+
var version = '6.4.3';
|
|
26383
26475
|
module.exports = version;
|
|
26384
26476
|
|
|
26385
26477
|
/***/ })
|