abcjs 6.4.1 → 6.4.2
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/RELEASE.md +34 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +1246 -1136
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/package.json +1 -1
- package/src/api/abc_tunebook.js +1 -2
- package/src/api/abc_tunebook_svg.js +0 -1
- 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 +22 -5
- 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 +81 -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/engraver-controller.js +1 -1
- package/temp.txt +12 -0
- package/types/index.d.ts +1 -1
- 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
|
@@ -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();
|
|
@@ -955,8 +755,6 @@ var Tune = __webpack_require__(/*! ../data/abc_tune */ "./src/data/abc_tune.js")
|
|
|
955
755
|
var EngraverController = __webpack_require__(/*! ../write/engraver-controller */ "./src/write/engraver-controller.js");
|
|
956
756
|
var Parse = __webpack_require__(/*! ../parse/abc_parse */ "./src/parse/abc_parse.js");
|
|
957
757
|
var wrap = __webpack_require__(/*! ../parse/wrap_lines */ "./src/parse/wrap_lines.js");
|
|
958
|
-
// var tablatures = require('./abc_tablatures');
|
|
959
|
-
|
|
960
758
|
var resizeDivs = {};
|
|
961
759
|
function resizeOuter() {
|
|
962
760
|
var width = window.innerWidth;
|
|
@@ -2630,9 +2428,21 @@ var create;
|
|
|
2630
2428
|
if (title && title.length > 128) title = title.substring(0, 124) + '...';
|
|
2631
2429
|
var key = abcTune.getKeySignature();
|
|
2632
2430
|
var time = abcTune.getMeterFraction();
|
|
2633
|
-
|
|
2431
|
+
|
|
2432
|
+
// MAE 7 July 2024 - Fix for */8 meter tempos
|
|
2433
|
+
var tempo = commands.tempo;
|
|
2434
|
+
var beatsPerSecond = tempo / 60;
|
|
2435
|
+
|
|
2436
|
+
// Fix tempo for */8 meters
|
|
2437
|
+
if (time.den == 8) {
|
|
2438
|
+
// Compute the tempo based on the actual milliseconds per measure, scaled by the number of eight notes and halved to get tempo in bpm.
|
|
2439
|
+
var msPerMeasure = abcTune.millisecondsPerMeasure();
|
|
2440
|
+
tempo = 60000 / (msPerMeasure / time.num) / 2;
|
|
2441
|
+
beatsPerSecond = tempo / 60;
|
|
2442
|
+
}
|
|
2443
|
+
|
|
2634
2444
|
//var beatLength = abcTune.getBeatLength();
|
|
2635
|
-
midi.setGlobalInfo(
|
|
2445
|
+
midi.setGlobalInfo(tempo, title, key, time);
|
|
2636
2446
|
for (var i = 0; i < commands.tracks.length; i++) {
|
|
2637
2447
|
midi.startTrack();
|
|
2638
2448
|
var notePlacement = {};
|
|
@@ -2718,27 +2528,20 @@ module.exports = create;
|
|
|
2718
2528
|
\*********************************/
|
|
2719
2529
|
/***/ (function(module) {
|
|
2720
2530
|
|
|
2721
|
-
//
|
|
2531
|
+
// abc_common.js: Some common utility functions.
|
|
2722
2532
|
|
|
2723
2533
|
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
2534
|
parseCommon.cloneArray = function (source) {
|
|
2732
2535
|
var destination = [];
|
|
2733
2536
|
for (var i = 0; i < source.length; i++) {
|
|
2734
|
-
destination.push(
|
|
2537
|
+
destination.push(Object.assign({}, source[i]));
|
|
2735
2538
|
}
|
|
2736
2539
|
return destination;
|
|
2737
2540
|
};
|
|
2738
2541
|
parseCommon.cloneHashOfHash = function (source) {
|
|
2739
2542
|
var destination = {};
|
|
2740
2543
|
for (var property in source) {
|
|
2741
|
-
if (source.hasOwnProperty(property)) destination[property] =
|
|
2544
|
+
if (source.hasOwnProperty(property)) destination[property] = Object.assign({}, source[property]);
|
|
2742
2545
|
}
|
|
2743
2546
|
return destination;
|
|
2744
2547
|
};
|
|
@@ -3230,7 +3033,7 @@ var Parse = function Parse() {
|
|
|
3230
3033
|
});
|
|
3231
3034
|
for (var i = 0; i < nextVoice.length; i++) {
|
|
3232
3035
|
var element = nextVoice[i];
|
|
3233
|
-
var hint =
|
|
3036
|
+
var hint = Object.assign({}, element);
|
|
3234
3037
|
voice.push(hint);
|
|
3235
3038
|
if (element.el_type === 'bar') return;
|
|
3236
3039
|
}
|
|
@@ -4157,7 +3960,7 @@ var parseDirective = {};
|
|
|
4157
3960
|
};
|
|
4158
3961
|
var midiCmdParam0 = ["nobarlines", "barlines", "beataccents", "nobeataccents", "droneon", "droneoff", "drumon", "drumoff", "fermatafixed", "fermataproportional", "gchordon", "gchordoff", "controlcombo", "temperamentnormal", "noportamento"];
|
|
4159
3962
|
var midiCmdParam1String = ["gchord", "ptstress", "beatstring"];
|
|
4160
|
-
var midiCmdParam1Integer = ["bassvol", "chordvol", "
|
|
3963
|
+
var midiCmdParam1Integer = ["bassvol", "chordvol", "c", "channel", "beatmod", "deltaloudness", "drumbars", "gracedivider", "makechordchannels", "randomchordattack", "chordattack", "stressmodel", "transpose", "rtranspose", "vol", "volinc", "gchordbars"];
|
|
4161
3964
|
var midiCmdParam1Integer1OptionalInteger = ["program"];
|
|
4162
3965
|
var midiCmdParam2Integer = ["ratio", "snt", "bendvelocity", "pitchbend", "control", "temperamentlinear"];
|
|
4163
3966
|
var midiCmdParam4Integer = ["beat"];
|
|
@@ -4165,6 +3968,7 @@ var parseDirective = {};
|
|
|
4165
3968
|
var midiCmdParam1String1Integer = ["portamento"];
|
|
4166
3969
|
var midiCmdParamFraction = ["expand", "grace", "trim"];
|
|
4167
3970
|
var midiCmdParam1StringVariableIntegers = ["drum", "chordname"];
|
|
3971
|
+
var midiCmdParam1Integer1OptionalString = ["bassprog", "chordprog"];
|
|
4168
3972
|
var parseMidiCommand = function parseMidiCommand(midi, tune, restOfString) {
|
|
4169
3973
|
var midi_cmd = midi.shift().token;
|
|
4170
3974
|
var midi_params = [];
|
|
@@ -4256,6 +4060,34 @@ var parseDirective = {};
|
|
|
4256
4060
|
midi_params.push(p.intt);
|
|
4257
4061
|
}
|
|
4258
4062
|
}
|
|
4063
|
+
} else if (midiCmdParam1Integer1OptionalString.indexOf(midi_cmd) >= 0) {
|
|
4064
|
+
// ONE INT PARAMETER, ONE OPTIONAL string
|
|
4065
|
+
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 {
|
|
4066
|
+
midi_params.push(midi[0].intt);
|
|
4067
|
+
|
|
4068
|
+
// Currently only bassprog and chordprog with optional octave shifts use this path
|
|
4069
|
+
if (midi.length === 2) {
|
|
4070
|
+
var cmd = midi[1].token;
|
|
4071
|
+
if (cmd.indexOf("octave=") != -1) {
|
|
4072
|
+
cmd = cmd.replace("octave=", "");
|
|
4073
|
+
cmd = parseInt(cmd);
|
|
4074
|
+
if (!isNaN(cmd)) {
|
|
4075
|
+
// Limit range from -1 to 3 octaves
|
|
4076
|
+
if (cmd < -1) {
|
|
4077
|
+
warn("Expected octave= in MIDI " + midi_cmd + ' to be >= -1 (recv:' + cmd + ')');
|
|
4078
|
+
cmd = -1;
|
|
4079
|
+
}
|
|
4080
|
+
if (cmd > 3) {
|
|
4081
|
+
warn("Expected octave= in MIDI " + midi_cmd + ' to be <= 3 (recv:' + cmd + ')');
|
|
4082
|
+
cmd = 3;
|
|
4083
|
+
}
|
|
4084
|
+
midi_params.push(cmd);
|
|
4085
|
+
} else warn("Expected octave value in MIDI" + midi_cmd);
|
|
4086
|
+
} else {
|
|
4087
|
+
warn("Expected octave= in MIDI" + midi_cmd);
|
|
4088
|
+
}
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4259
4091
|
}
|
|
4260
4092
|
if (tuneBuilder.hasBeginMusic()) tuneBuilder.appendElement('midi', -1, -1, {
|
|
4261
4093
|
cmd: midi_cmd,
|
|
@@ -5201,6 +5033,7 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5201
5033
|
}
|
|
5202
5034
|
};
|
|
5203
5035
|
this.letter_to_inline_header = function (line, i, startLine) {
|
|
5036
|
+
var needsNewLine = false;
|
|
5204
5037
|
var ws = tokenizer.eatWhiteSpace(line, i);
|
|
5205
5038
|
i += ws;
|
|
5206
5039
|
if (line.length >= i + 5 && line[i] === '[' && line[i + 2] === ':') {
|
|
@@ -5247,9 +5080,9 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5247
5080
|
break;
|
|
5248
5081
|
case "[V:":
|
|
5249
5082
|
if (e > 0) {
|
|
5250
|
-
parseKeyVoice.parseVoice(line, i + 3, e);
|
|
5083
|
+
needsNewLine = parseKeyVoice.parseVoice(line, i + 3, e);
|
|
5251
5084
|
//startNewLine();
|
|
5252
|
-
return [e - i + 1 + ws, line[i + 1], line.substring(i + 3, e)];
|
|
5085
|
+
return [e - i + 1 + ws, line[i + 1], line.substring(i + 3, e), needsNewLine];
|
|
5253
5086
|
}
|
|
5254
5087
|
break;
|
|
5255
5088
|
case "[r:":
|
|
@@ -5262,6 +5095,7 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5262
5095
|
return [0];
|
|
5263
5096
|
};
|
|
5264
5097
|
this.letter_to_body_header = function (line, i) {
|
|
5098
|
+
var needsNewLine = false;
|
|
5265
5099
|
if (line.length >= i + 3) {
|
|
5266
5100
|
switch (line.substring(i, i + 2)) {
|
|
5267
5101
|
case "I:":
|
|
@@ -5292,9 +5126,9 @@ var ParseHeader = function ParseHeader(tokenizer, warn, multilineVars, tune, tun
|
|
|
5292
5126
|
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
5127
|
return [e, line[i], parseCommon.strip(line.substring(i + 2))];
|
|
5294
5128
|
case "V:":
|
|
5295
|
-
parseKeyVoice.parseVoice(line, i + 2, line.length);
|
|
5129
|
+
needsNewLine = parseKeyVoice.parseVoice(line, i + 2, line.length);
|
|
5296
5130
|
// startNewLine();
|
|
5297
|
-
return [line.length, line[i], parseCommon.strip(line.substring(i + 2))];
|
|
5131
|
+
return [line.length, line[i], parseCommon.strip(line.substring(i + 2)), needsNewLine];
|
|
5298
5132
|
default:
|
|
5299
5133
|
// TODO: complain about unhandled header
|
|
5300
5134
|
}
|
|
@@ -5432,7 +5266,6 @@ module.exports = ParseHeader;
|
|
|
5432
5266
|
\******************************************/
|
|
5433
5267
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
5434
5268
|
|
|
5435
|
-
var parseCommon = __webpack_require__(/*! ./abc_common */ "./src/parse/abc_common.js");
|
|
5436
5269
|
var parseDirective = __webpack_require__(/*! ./abc_parse_directive */ "./src/parse/abc_parse_directive.js");
|
|
5437
5270
|
var transpose = __webpack_require__(/*! ./abc_transpose */ "./src/parse/abc_transpose.js");
|
|
5438
5271
|
var parseKeyVoice = {};
|
|
@@ -5683,7 +5516,7 @@ var parseKeyVoice = {};
|
|
|
5683
5516
|
mode: key.mode
|
|
5684
5517
|
};
|
|
5685
5518
|
key.accidentals.forEach(function (k) {
|
|
5686
|
-
ret.accidentals.push(
|
|
5519
|
+
ret.accidentals.push(Object.assign({}, k));
|
|
5687
5520
|
});
|
|
5688
5521
|
return ret;
|
|
5689
5522
|
};
|
|
@@ -5749,7 +5582,7 @@ var parseKeyVoice = {};
|
|
|
5749
5582
|
}
|
|
5750
5583
|
};
|
|
5751
5584
|
parseKeyVoice.fixKey = function (clef, key) {
|
|
5752
|
-
var fixedKey =
|
|
5585
|
+
var fixedKey = Object.assign({}, key);
|
|
5753
5586
|
parseKeyVoice.addPosToKey(clef, fixedKey);
|
|
5754
5587
|
return fixedKey;
|
|
5755
5588
|
};
|
|
@@ -6180,8 +6013,13 @@ var parseKeyVoice = {};
|
|
|
6180
6013
|
return ret;
|
|
6181
6014
|
};
|
|
6182
6015
|
var setCurrentVoice = function setCurrentVoice(id) {
|
|
6183
|
-
|
|
6184
|
-
|
|
6016
|
+
var currentVoice = multilineVars.voices[id];
|
|
6017
|
+
if (multilineVars.currentVoice) {
|
|
6018
|
+
if (multilineVars.currentVoice.index === currentVoice.index && multilineVars.currentVoice.staffNum === currentVoice.staffNum) return; // there was no change so don't reset it.
|
|
6019
|
+
}
|
|
6020
|
+
|
|
6021
|
+
multilineVars.currentVoice = currentVoice;
|
|
6022
|
+
return tuneBuilder.setCurrentVoice(currentVoice.staffNum, currentVoice.index, id);
|
|
6185
6023
|
};
|
|
6186
6024
|
parseKeyVoice.parseVoice = function (line, i, e) {
|
|
6187
6025
|
//First truncate the string to the first non-space character after V: through either the
|
|
@@ -6433,7 +6271,7 @@ var parseKeyVoice = {};
|
|
|
6433
6271
|
if (staffInfo.subname) {
|
|
6434
6272
|
if (s.subname) s.subname.push(staffInfo.subname);else s.subname = [staffInfo.subname];
|
|
6435
6273
|
}
|
|
6436
|
-
setCurrentVoice(id);
|
|
6274
|
+
return setCurrentVoice(id);
|
|
6437
6275
|
};
|
|
6438
6276
|
})();
|
|
6439
6277
|
module.exports = parseKeyVoice;
|
|
@@ -6446,7 +6284,6 @@ module.exports = parseKeyVoice;
|
|
|
6446
6284
|
\**************************************/
|
|
6447
6285
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
6448
6286
|
|
|
6449
|
-
var parseCommon = __webpack_require__(/*! ./abc_common */ "./src/parse/abc_common.js");
|
|
6450
6287
|
var parseKeyVoice = __webpack_require__(/*! ./abc_parse_key_voice */ "./src/parse/abc_parse_key_voice.js");
|
|
6451
6288
|
var transpose = __webpack_require__(/*! ./abc_transpose */ "./src/parse/abc_transpose.js");
|
|
6452
6289
|
var tokenizer;
|
|
@@ -6579,6 +6416,7 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
6579
6416
|
var retInlineHeader = header.letter_to_inline_header(line, i, delayStartNewLine);
|
|
6580
6417
|
if (retInlineHeader[0] > 0) {
|
|
6581
6418
|
i += retInlineHeader[0];
|
|
6419
|
+
//console.log("inline header", retInlineHeader)
|
|
6582
6420
|
if (retInlineHeader[1] === 'V') delayStartNewLine = true; // fixes bug on this: c[V:2]d
|
|
6583
6421
|
// TODO-PER: Handle inline headers
|
|
6584
6422
|
//multilineVars.start_new_line = false;
|
|
@@ -6858,6 +6696,9 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
6858
6696
|
if (ch === '-' || ch === ')' || ch === ' ' || ch === '<' || ch === '>') i--; // Subtracting one because one is automatically added below
|
|
6859
6697
|
else postChordDone = true;
|
|
6860
6698
|
break;
|
|
6699
|
+
case '0':
|
|
6700
|
+
chordDuration = 0;
|
|
6701
|
+
break;
|
|
6861
6702
|
default:
|
|
6862
6703
|
postChordDone = true;
|
|
6863
6704
|
break;
|
|
@@ -6947,7 +6788,11 @@ MusicParser.prototype.parseMusic = function (line) {
|
|
|
6947
6788
|
if (!el.rest || el.rest.type !== 'spacer') warn("Duration not representable: " + line.substring(startI, i), line, i);
|
|
6948
6789
|
}
|
|
6949
6790
|
multilineVars.addFormattingOptions(el, tune.formatting, 'note');
|
|
6950
|
-
tuneBuilder.appendElement('note', startOfLine + startI, startOfLine + i, el);
|
|
6791
|
+
var succeeded = tuneBuilder.appendElement('note', startOfLine + startI, startOfLine + i, el);
|
|
6792
|
+
if (!succeeded) {
|
|
6793
|
+
this.startNewLine();
|
|
6794
|
+
tuneBuilder.appendElement('note', startOfLine + startI, startOfLine + i, el);
|
|
6795
|
+
}
|
|
6951
6796
|
multilineVars.measureNotEmpty = true;
|
|
6952
6797
|
el = {};
|
|
6953
6798
|
}
|
|
@@ -7049,7 +6894,10 @@ var letter_to_grace = function letter_to_grace(line, i) {
|
|
|
7049
6894
|
// 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
6895
|
note.duration = note.duration / (multilineVars.default_length * 8);
|
|
7051
6896
|
if (acciaccatura) note.acciaccatura = true;
|
|
7052
|
-
|
|
6897
|
+
if (note.rest) {
|
|
6898
|
+
// don't allow rests inside gracenotes
|
|
6899
|
+
warn("Rests not allowed as grace notes '" + gra[1][ii] + "' while parsing grace note", line, i);
|
|
6900
|
+
} else gracenotes.push(note);
|
|
7053
6901
|
if (inTie) {
|
|
7054
6902
|
note.endTie = true;
|
|
7055
6903
|
inTie = false;
|
|
@@ -7280,7 +7128,7 @@ MusicParser.prototype.startNewLine = function () {
|
|
|
7280
7128
|
endChar: -1
|
|
7281
7129
|
};
|
|
7282
7130
|
if (multilineVars.partForNextLine.title) params.part = multilineVars.partForNextLine;
|
|
7283
|
-
params.clef = multilineVars.currentVoice && multilineVars.staves[multilineVars.currentVoice.staffNum].clef !== undefined ?
|
|
7131
|
+
params.clef = multilineVars.currentVoice && multilineVars.staves[multilineVars.currentVoice.staffNum].clef !== undefined ? Object.assign({}, multilineVars.staves[multilineVars.currentVoice.staffNum].clef) : Object.assign({}, multilineVars.clef);
|
|
7284
7132
|
var scoreTranspose = multilineVars.currentVoice ? multilineVars.currentVoice.scoreTranspose : 0;
|
|
7285
7133
|
params.key = parseKeyVoice.standardKey(multilineVars.key.root + multilineVars.key.acc + multilineVars.key.mode, multilineVars.key.root, multilineVars.key.acc, scoreTranspose);
|
|
7286
7134
|
params.key.mode = multilineVars.key.mode;
|
|
@@ -7334,6 +7182,11 @@ MusicParser.prototype.startNewLine = function () {
|
|
|
7334
7182
|
if (multilineVars.currentVoice.color) params.color = multilineVars.currentVoice.color;
|
|
7335
7183
|
if (multilineVars.currentVoice.style) params.style = multilineVars.currentVoice.style;
|
|
7336
7184
|
if (multilineVars.currentVoice.transpose) params.clef.transpose = multilineVars.currentVoice.transpose;
|
|
7185
|
+
params.currentVoice = multilineVars.currentVoice;
|
|
7186
|
+
var voices = Object.keys(multilineVars.voices);
|
|
7187
|
+
for (var mv = 0; mv < voices.length; mv++) {
|
|
7188
|
+
if (params.currentVoice.staffNum === multilineVars.voices[voices[mv]].staffNum && params.currentVoice.index === multilineVars.voices[voices[mv]].index) params.currentVoiceName = voices[mv];
|
|
7189
|
+
}
|
|
7337
7190
|
}
|
|
7338
7191
|
var isFirstVoice = multilineVars.currentVoice === undefined || multilineVars.currentVoice.staffNum === 0 && multilineVars.currentVoice.index === 0;
|
|
7339
7192
|
if (multilineVars.barNumbers === 0 && isFirstVoice && multilineVars.currBarNumber !== 1) params.barNumber = multilineVars.currBarNumber;
|
|
@@ -9321,166 +9174,19 @@ module.exports = transposeChordName;
|
|
|
9321
9174
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
9322
9175
|
|
|
9323
9176
|
var parseKeyVoice = __webpack_require__(/*! ../parse/abc_parse_key_voice */ "./src/parse/abc_parse_key_voice.js");
|
|
9324
|
-
var parseCommon =
|
|
9325
|
-
var parseDirective =
|
|
9177
|
+
//var parseCommon = require('../parse/abc_common');
|
|
9178
|
+
//var parseDirective = require('./abc_parse_directive');
|
|
9179
|
+
|
|
9326
9180
|
var TuneBuilder = function TuneBuilder(tune) {
|
|
9327
9181
|
var self = this;
|
|
9182
|
+
var voiceDefs = {};
|
|
9183
|
+
var currentVoiceName = '';
|
|
9184
|
+
tune.reset();
|
|
9328
9185
|
this.setVisualTranspose = function (visualTranspose) {
|
|
9329
9186
|
if (visualTranspose) tune.visualTranspose = visualTranspose;
|
|
9330
9187
|
};
|
|
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
9188
|
this.cleanUp = function (barsperstaff, staffnonote, currSlur) {
|
|
9483
|
-
|
|
9189
|
+
closeLine(tune); // Close the last line.
|
|
9484
9190
|
delete tune.runningFonts;
|
|
9485
9191
|
simplifyMetaText(tune);
|
|
9486
9192
|
//addRichTextToAnnotationsAndLyrics(tune)
|
|
@@ -9502,7 +9208,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9502
9208
|
} else {
|
|
9503
9209
|
for (v = 0; v < tune.lines[i].staff[s].voices.length; v++) {
|
|
9504
9210
|
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 (
|
|
9211
|
+
else if (containsNotes(tune.lines[i].staff[s].voices[v])) hasAny = true;
|
|
9506
9212
|
}
|
|
9507
9213
|
}
|
|
9508
9214
|
}
|
|
@@ -9538,7 +9244,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9538
9244
|
for (s = 0; s < tune.lines[i].staff.length; s++) {
|
|
9539
9245
|
var keepThis = false;
|
|
9540
9246
|
for (v = 0; v < tune.lines[i].staff[s].voices.length; v++) {
|
|
9541
|
-
if (
|
|
9247
|
+
if (containsNotesStrict(tune.lines[i].staff[s].voices[v])) {
|
|
9542
9248
|
keepThis = true;
|
|
9543
9249
|
}
|
|
9544
9250
|
}
|
|
@@ -9569,208 +9275,23 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9569
9275
|
}
|
|
9570
9276
|
|
|
9571
9277
|
// If there are overlays, create new voices for them.
|
|
9572
|
-
while (
|
|
9278
|
+
while (resolveOverlays(tune)) {
|
|
9573
9279
|
// keep resolving overlays as long as any are found.
|
|
9574
9280
|
}
|
|
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;
|
|
9281
|
+
for (var i = 0; i < tune.lines.length; i++) {
|
|
9282
|
+
var staff = tune.lines[i].staff;
|
|
9762
9283
|
if (staff) {
|
|
9763
9284
|
for (tune.staffNum = 0; tune.staffNum < staff.length; tune.staffNum++) {
|
|
9764
|
-
if (staff[tune.staffNum].clef)
|
|
9285
|
+
if (staff[tune.staffNum].clef) parseKeyVoice.fixClef(staff[tune.staffNum].clef);
|
|
9765
9286
|
for (tune.voiceNum = 0; tune.voiceNum < staff[tune.staffNum].voices.length; tune.voiceNum++) {
|
|
9766
9287
|
var voice = staff[tune.staffNum].voices[tune.voiceNum];
|
|
9767
|
-
cleanUpSlursInLine(voice, tune.staffNum, tune.voiceNum);
|
|
9288
|
+
cleanUpSlursInLine(voice, tune.staffNum, tune.voiceNum, currSlur);
|
|
9768
9289
|
for (var j = 0; j < voice.length; j++) {
|
|
9769
|
-
if (voice[j].el_type === 'clef')
|
|
9290
|
+
if (voice[j].el_type === 'clef') parseKeyVoice.fixClef(voice[j]);
|
|
9770
9291
|
}
|
|
9771
9292
|
if (voice.length > 0 && voice[voice.length - 1].barNumber) {
|
|
9772
9293
|
// Don't hang a bar number on the last bar line: it should go on the next line.
|
|
9773
|
-
var nextLine = getNextMusicLine(tune.lines,
|
|
9294
|
+
var nextLine = getNextMusicLine(tune.lines, i);
|
|
9774
9295
|
if (nextLine) nextLine.staff[0].barNumber = voice[voice.length - 1].barNumber;
|
|
9775
9296
|
delete voice[voice.length - 1].barNumber;
|
|
9776
9297
|
}
|
|
@@ -9788,21 +9309,9 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9788
9309
|
delete tune.vskipPending;
|
|
9789
9310
|
return currSlur;
|
|
9790
9311
|
};
|
|
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
9312
|
this.addTieToLastNote = function (dottedTie) {
|
|
9804
9313
|
// TODO-PER: if this is a chord, which note?
|
|
9805
|
-
var el =
|
|
9314
|
+
var el = getLastNote(tune);
|
|
9806
9315
|
if (el && el.pitches && el.pitches.length > 0) {
|
|
9807
9316
|
el.pitches[0].startTie = {};
|
|
9808
9317
|
if (dottedTie) el.pitches[0].startTie.style = 'dotted';
|
|
@@ -9810,59 +9319,10 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9810
9319
|
}
|
|
9811
9320
|
return false;
|
|
9812
9321
|
};
|
|
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
9322
|
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
9323
|
hashParams.el_type = type;
|
|
9849
9324
|
if (startChar !== null) hashParams.startChar = startChar;
|
|
9850
9325
|
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
9326
|
if (type === 'note') {
|
|
9867
9327
|
// && (hashParams.rest !== undefined || hashParams.end_beam === undefined)) {
|
|
9868
9328
|
// Now, add the startBeam and endBeam where it is needed.
|
|
@@ -9871,25 +9331,25 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9871
9331
|
// this.potentialEndBeam either points to null or the start beam.
|
|
9872
9332
|
// 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
9333
|
// reset the variables for the next notes.
|
|
9874
|
-
var dur =
|
|
9334
|
+
var dur = getDuration(hashParams);
|
|
9875
9335
|
if (dur >= 0.25) {
|
|
9876
9336
|
// 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 &&
|
|
9337
|
+
endBeamLast(tune);
|
|
9338
|
+
} else if (hashParams.force_end_beam_last && tune.potentialStartBeam !== undefined) {
|
|
9339
|
+
endBeamLast(tune);
|
|
9340
|
+
} else if (hashParams.end_beam && tune.potentialStartBeam !== undefined) {
|
|
9881
9341
|
// 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();
|
|
9342
|
+
if (hashParams.rest === undefined) endBeamHere(hashParams, tune);else endBeamLast(tune);
|
|
9883
9343
|
} else if (hashParams.rest === undefined) {
|
|
9884
9344
|
// this a short note and we aren't about to end the beam
|
|
9885
|
-
if (
|
|
9345
|
+
if (tune.potentialStartBeam === undefined) {
|
|
9886
9346
|
// We aren't collecting notes for a beam, so start here.
|
|
9887
9347
|
if (!hashParams.end_beam) {
|
|
9888
|
-
|
|
9889
|
-
delete
|
|
9348
|
+
tune.potentialStartBeam = hashParams;
|
|
9349
|
+
delete tune.potentialEndBeam;
|
|
9890
9350
|
}
|
|
9891
9351
|
} else {
|
|
9892
|
-
|
|
9352
|
+
tune.potentialEndBeam = hashParams; // Continue the beaming, look for the end next note.
|
|
9893
9353
|
}
|
|
9894
9354
|
}
|
|
9895
9355
|
|
|
@@ -9897,21 +9357,32 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9897
9357
|
// if (hashParams.rest !== undefined)
|
|
9898
9358
|
// {
|
|
9899
9359
|
// hashParams.end_beam = true;
|
|
9900
|
-
// var el2 =
|
|
9360
|
+
// var el2 = getLastNote(tune);
|
|
9901
9361
|
// if (el2) el2.end_beam = true;
|
|
9902
9362
|
// // TODO-PER: implement exception mentioned in the comment.
|
|
9903
9363
|
// }
|
|
9904
9364
|
} else {
|
|
9905
9365
|
// It's not a note, so there definitely isn't beaming after it.
|
|
9906
|
-
endBeamLast();
|
|
9366
|
+
endBeamLast(tune);
|
|
9907
9367
|
}
|
|
9908
9368
|
delete hashParams.end_beam; // We don't want this temporary variable hanging around.
|
|
9909
9369
|
delete hashParams.force_end_beam_last; // We don't want this temporary variable hanging around.
|
|
9910
|
-
|
|
9370
|
+
if (hashParams.rest && hashParams.rest.type === 'invisible') {
|
|
9371
|
+
delete hashParams.decoration; // the decorations on invisible rests should be invisible, too.
|
|
9372
|
+
}
|
|
9373
|
+
|
|
9374
|
+
if (tune.lines.length <= tune.lineNum || tune.lines[tune.lineNum].staff.length <= tune.staffNum) {
|
|
9375
|
+
//console.log("pushNote IGNORED", tune.lines[tune.lineNum])
|
|
9376
|
+
// 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.
|
|
9377
|
+
return false;
|
|
9378
|
+
}
|
|
9379
|
+
pushNote(self, tune, hashParams, voiceDefs, currentVoiceName);
|
|
9380
|
+
return true;
|
|
9911
9381
|
};
|
|
9912
9382
|
this.appendStartingElement = function (type, startChar, endChar, hashParams2) {
|
|
9383
|
+
//console.log('appendStartingElement', hashParams2)
|
|
9913
9384
|
// If we're in the middle of beaming, then end the beam.
|
|
9914
|
-
|
|
9385
|
+
closeLine(tune);
|
|
9915
9386
|
|
|
9916
9387
|
// We only ever want implied naturals the first time.
|
|
9917
9388
|
var impliedNaturals;
|
|
@@ -9922,58 +9393,54 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9922
9393
|
}
|
|
9923
9394
|
|
|
9924
9395
|
// 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
|
-
|
|
9396
|
+
var hashParams = Object.assign({}, hashParams2);
|
|
9397
|
+
|
|
9398
|
+
// be sure that we are on a music type line before doing the following.
|
|
9399
|
+
if (!tune.lines[tune.lineNum]) return;
|
|
9400
|
+
var staff = tune.lines[tune.lineNum].staff;
|
|
9401
|
+
if (!staff) return;
|
|
9402
|
+
|
|
9403
|
+
// If tune is the first item in tune staff, then we might have to initialize the staff, first.
|
|
9404
|
+
if (staff.length <= tune.staffNum) {
|
|
9405
|
+
staff[tune.staffNum] = {};
|
|
9406
|
+
staff[tune.staffNum].clef = Object.assign({}, staff[0].clef);
|
|
9407
|
+
staff[tune.staffNum].key = Object.assign({}, staff[0].key);
|
|
9408
|
+
if (staff[0].meter) staff[tune.staffNum].meter = Object.assign({}, staff[0].meter);
|
|
9409
|
+
staff[tune.staffNum].workingClef = Object.assign({}, staff[0].workingClef);
|
|
9410
|
+
staff[tune.staffNum].voices = [[]];
|
|
9411
|
+
}
|
|
9412
|
+
// If tune is a clef type, then we replace the working clef on the line. This is kept separate from
|
|
9413
|
+
// the clef in case there is an inline clef field. We need to know what the current position for
|
|
9414
|
+
// the note is.
|
|
9415
|
+
if (type === 'clef') {
|
|
9416
|
+
staff[tune.staffNum].workingClef = hashParams;
|
|
9417
|
+
}
|
|
9418
|
+
|
|
9419
|
+
// 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.
|
|
9420
|
+
var voice = staff[tune.staffNum].voices[tune.voiceNum];
|
|
9421
|
+
for (var i = 0; i < voice.length; i++) {
|
|
9422
|
+
if (voice[i].el_type === 'note' || voice[i].el_type === 'bar') {
|
|
9423
|
+
hashParams.el_type = type;
|
|
9424
|
+
hashParams.startChar = startChar;
|
|
9425
|
+
hashParams.endChar = endChar;
|
|
9426
|
+
if (impliedNaturals) hashParams.accidentals = impliedNaturals.concat(hashParams.accidentals);
|
|
9427
|
+
voice.push(hashParams);
|
|
9428
|
+
return;
|
|
9429
|
+
}
|
|
9430
|
+
if (voice[i].el_type === type) {
|
|
9431
|
+
hashParams.el_type = type;
|
|
9432
|
+
hashParams.startChar = startChar;
|
|
9433
|
+
hashParams.endChar = endChar;
|
|
9434
|
+
if (impliedNaturals) hashParams.accidentals = impliedNaturals.concat(hashParams.accidentals);
|
|
9435
|
+
voice[i] = hashParams;
|
|
9436
|
+
return;
|
|
9963
9437
|
}
|
|
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
9438
|
}
|
|
9973
|
-
|
|
9439
|
+
// We didn't see either that type or a note, so replace the element to the staff.
|
|
9440
|
+
staff[tune.staffNum][type] = hashParams2;
|
|
9974
9441
|
};
|
|
9975
9442
|
this.addSubtitle = function (str, info) {
|
|
9976
|
-
|
|
9443
|
+
pushLine(tune, {
|
|
9977
9444
|
subtitle: {
|
|
9978
9445
|
text: str,
|
|
9979
9446
|
startChar: info.startChar,
|
|
@@ -9985,12 +9452,12 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
9985
9452
|
tune.vskipPending = num;
|
|
9986
9453
|
};
|
|
9987
9454
|
this.addNewPage = function (num) {
|
|
9988
|
-
|
|
9455
|
+
pushLine(tune, {
|
|
9989
9456
|
newpage: num
|
|
9990
9457
|
});
|
|
9991
9458
|
};
|
|
9992
9459
|
this.addSeparator = function (spaceAbove, spaceBelow, lineLength, info) {
|
|
9993
|
-
|
|
9460
|
+
pushLine(tune, {
|
|
9994
9461
|
separator: {
|
|
9995
9462
|
spaceAbove: Math.round(spaceAbove),
|
|
9996
9463
|
spaceBelow: Math.round(spaceBelow),
|
|
@@ -10001,7 +9468,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10001
9468
|
});
|
|
10002
9469
|
};
|
|
10003
9470
|
this.addText = function (str, info) {
|
|
10004
|
-
|
|
9471
|
+
pushLine(tune, {
|
|
10005
9472
|
text: {
|
|
10006
9473
|
text: str,
|
|
10007
9474
|
startChar: info.startChar,
|
|
@@ -10010,29 +9477,17 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10010
9477
|
});
|
|
10011
9478
|
};
|
|
10012
9479
|
this.addCentered = function (str) {
|
|
10013
|
-
|
|
9480
|
+
pushLine(tune, {
|
|
10014
9481
|
text: [{
|
|
10015
9482
|
text: str,
|
|
10016
9483
|
center: true
|
|
10017
9484
|
}]
|
|
10018
9485
|
});
|
|
10019
9486
|
};
|
|
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
9487
|
|
|
10033
9488
|
// anyVoiceContainsNotes: function(line) {
|
|
10034
9489
|
// for (var i = 0; i < line.staff.voices.length; i++) {
|
|
10035
|
-
// if (
|
|
9490
|
+
// if (containsNotes(line.staff.voices[i]))
|
|
10036
9491
|
// return true;
|
|
10037
9492
|
// }
|
|
10038
9493
|
// return false;
|
|
@@ -10048,95 +9503,18 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10048
9503
|
});
|
|
10049
9504
|
};
|
|
10050
9505
|
this.startNewLine = function (params) {
|
|
9506
|
+
//console.log("startNewLine", tune.lineNum, params, voiceDefs)
|
|
10051
9507
|
// 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
9508
|
// 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) {
|
|
9509
|
+
closeLine(tune); // Close the previous line.
|
|
9510
|
+
if (params.currentVoiceName) {
|
|
9511
|
+
currentVoiceName = params.currentVoiceName;
|
|
9512
|
+
voiceDefs[params.currentVoiceName] = params;
|
|
9513
|
+
}
|
|
9514
|
+
if (tune.lines[tune.lineNum] === undefined) createLine(self, tune, params);else if (tune.lines[tune.lineNum].staff === undefined) {
|
|
10137
9515
|
tune.lineNum++;
|
|
10138
9516
|
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 (!
|
|
9517
|
+
} 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
9518
|
// We don't need a new line but we might need to update parts of it.
|
|
10141
9519
|
if (params.part) self.appendElement('part', params.part.startChar, params.part.endChar, {
|
|
10142
9520
|
title: params.part.title
|
|
@@ -10150,21 +9528,6 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10150
9528
|
// This is called at tune start to set the current default fonts so we know whether to record a change.
|
|
10151
9529
|
tune.runningFonts[type] = font;
|
|
10152
9530
|
};
|
|
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
9531
|
this.setBarNumberImmediate = function (barNumber) {
|
|
10169
9532
|
// If tune is called right at the beginning of a line, then correct the measure number that is already written.
|
|
10170
9533
|
// If tune is called at the beginning of a measure, then correct the measure number that was just created.
|
|
@@ -10194,24 +9557,31 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10194
9557
|
return true;
|
|
10195
9558
|
};
|
|
10196
9559
|
this.getCurrentVoice = function () {
|
|
9560
|
+
//console.log("getCurrentVoice", tune.lineNum)
|
|
10197
9561
|
var currLine = tune.lines[tune.lineNum];
|
|
10198
9562
|
if (!currLine) return null;
|
|
10199
9563
|
var currStaff = currLine.staff[tune.staffNum];
|
|
10200
9564
|
if (!currStaff) return null;
|
|
10201
9565
|
if (currStaff.voices[tune.voiceNum] !== undefined) return currStaff.voices[tune.voiceNum];else return null;
|
|
10202
9566
|
};
|
|
10203
|
-
this.setCurrentVoice = function (staffNum, voiceNum) {
|
|
9567
|
+
this.setCurrentVoice = function (staffNum, voiceNum, name) {
|
|
9568
|
+
//console.log("setCurrentVoice", tune.lineNum, staffNum, voiceNum, name, voiceDefs)
|
|
10204
9569
|
tune.staffNum = staffNum;
|
|
10205
9570
|
tune.voiceNum = voiceNum;
|
|
9571
|
+
currentVoiceName = name;
|
|
10206
9572
|
for (var i = 0; i < tune.lines.length; i++) {
|
|
10207
9573
|
if (tune.lines[i].staff) {
|
|
10208
|
-
if (tune.lines[i].staff[staffNum] === undefined || tune.lines[i].staff[staffNum].voices[voiceNum] === undefined || !
|
|
9574
|
+
if (tune.lines[i].staff[staffNum] === undefined || tune.lines[i].staff[staffNum].voices[voiceNum] === undefined || !containsNotes(tune.lines[i].staff[staffNum].voices[voiceNum])) {
|
|
9575
|
+
//console.log("cv2", i, tune.lines[i].staff[staffNum])
|
|
10209
9576
|
tune.lineNum = i;
|
|
10210
|
-
return;
|
|
9577
|
+
if (!tune.lines[i].staff[staffNum] || !!tune.lines[i].staff[staffNum].voices[voiceNum]) return true;
|
|
9578
|
+
return false;
|
|
10211
9579
|
}
|
|
10212
9580
|
}
|
|
10213
9581
|
}
|
|
9582
|
+
//console.log("cv3", i, tune.lineNum, tune.lines[tune.lineNum])
|
|
10214
9583
|
tune.lineNum = i;
|
|
9584
|
+
return false;
|
|
10215
9585
|
};
|
|
10216
9586
|
this.addMetaText = function (key, value, info) {
|
|
10217
9587
|
if (tune.metaText[key] === undefined) {
|
|
@@ -10247,7 +9617,7 @@ var TuneBuilder = function TuneBuilder(tune) {
|
|
|
10247
9617
|
function isArrayOfStrings(arr) {
|
|
10248
9618
|
if (!arr) return false;
|
|
10249
9619
|
if (typeof arr === "string") return false;
|
|
10250
|
-
var str = ''
|
|
9620
|
+
//var str = ''
|
|
10251
9621
|
for (var i = 0; i < arr.length; i++) {
|
|
10252
9622
|
if (typeof arr[i] !== 'string') return false;
|
|
10253
9623
|
}
|
|
@@ -10257,32 +9627,553 @@ function simplifyMetaText(tune) {
|
|
|
10257
9627
|
if (isArrayOfStrings(tune.metaText.notes)) tune.metaText.notes = tune.metaText.notes.join("\n");
|
|
10258
9628
|
if (isArrayOfStrings(tune.metaText.history)) tune.metaText.history = tune.metaText.history.join("\n");
|
|
10259
9629
|
}
|
|
10260
|
-
|
|
10261
|
-
|
|
9630
|
+
|
|
9631
|
+
// function addRichTextToAnnotationsAndLyrics(tune) {
|
|
9632
|
+
// var lines = tune.lines
|
|
9633
|
+
// for (var i = 0; i < lines.length; i++) {
|
|
9634
|
+
// if (lines[i].staff !== undefined) {
|
|
9635
|
+
// for (var s = 0; s < lines[i].staff.length; s++) {
|
|
9636
|
+
// for (var v = 0; v < lines[i].staff[s].voices.length; v++) {
|
|
9637
|
+
// var voice = lines[i].staff[s].voices[v];
|
|
9638
|
+
// for (var n = 0; n < voice.length; n++) {
|
|
9639
|
+
// var element = voice[n]
|
|
9640
|
+
// if (element.chord) {
|
|
9641
|
+
// for (var c = 0; c < element.chord.length; c++) {
|
|
9642
|
+
// element.chord[c].name = parseDirective.parseFontChangeLine(element.chord[c].name)
|
|
9643
|
+
// console.log(element.chord[c].name)
|
|
9644
|
+
// }
|
|
9645
|
+
// }
|
|
9646
|
+
// if (element.lyric) {
|
|
9647
|
+
// for (var l = 0; l < element.lyric.length; l++) {
|
|
9648
|
+
// element.lyric[l].syllable = parseDirective.parseFontChangeLine(element.lyric[l].syllable)
|
|
9649
|
+
// console.log(element.lyric[l].syllable)
|
|
9650
|
+
// }
|
|
9651
|
+
// }
|
|
9652
|
+
// }
|
|
9653
|
+
// }
|
|
9654
|
+
// }
|
|
9655
|
+
// }
|
|
9656
|
+
// }
|
|
9657
|
+
|
|
9658
|
+
// }
|
|
9659
|
+
|
|
9660
|
+
function resolveOverlays(tune) {
|
|
9661
|
+
var madeChanges = false;
|
|
9662
|
+
var durationsPerLines = [];
|
|
9663
|
+
for (var i = 0; i < tune.lines.length; i++) {
|
|
9664
|
+
var line = tune.lines[i];
|
|
9665
|
+
if (line.staff) {
|
|
9666
|
+
for (var j = 0; j < line.staff.length; j++) {
|
|
9667
|
+
var staff = line.staff[j];
|
|
9668
|
+
var overlayVoice = [];
|
|
9669
|
+
for (var k = 0; k < staff.voices.length; k++) {
|
|
9670
|
+
var voice = staff.voices[k];
|
|
9671
|
+
overlayVoice.push({
|
|
9672
|
+
hasOverlay: false,
|
|
9673
|
+
voice: [],
|
|
9674
|
+
snip: []
|
|
9675
|
+
});
|
|
9676
|
+
durationsPerLines[i] = 0;
|
|
9677
|
+
var durationThisBar = 0;
|
|
9678
|
+
var inOverlay = false;
|
|
9679
|
+
var overlayDuration = 0;
|
|
9680
|
+
var snipStart = -1;
|
|
9681
|
+
for (var kk = 0; kk < voice.length; kk++) {
|
|
9682
|
+
var event = voice[kk];
|
|
9683
|
+
if (event.el_type === "overlay" && !inOverlay) {
|
|
9684
|
+
madeChanges = true;
|
|
9685
|
+
inOverlay = true;
|
|
9686
|
+
snipStart = kk;
|
|
9687
|
+
overlayVoice[k].hasOverlay = true;
|
|
9688
|
+
if (overlayDuration === 0) overlayDuration = durationsPerLines[i];
|
|
9689
|
+
// If this isn't the first line, we also need invisible rests on the previous lines.
|
|
9690
|
+
// So, if the next voice doesn't appear in a previous line, create it
|
|
9691
|
+
for (var ii = 0; ii < i; ii++) {
|
|
9692
|
+
if (durationsPerLines[ii] && tune.lines[ii].staff && staff.voices.length >= tune.lines[ii].staff[0].voices.length) {
|
|
9693
|
+
tune.lines[ii].staff[0].voices.push([{
|
|
9694
|
+
el_type: "note",
|
|
9695
|
+
duration: durationsPerLines[ii],
|
|
9696
|
+
rest: {
|
|
9697
|
+
type: "invisible"
|
|
9698
|
+
},
|
|
9699
|
+
startChar: event.startChar,
|
|
9700
|
+
endChar: event.endChar
|
|
9701
|
+
}]);
|
|
9702
|
+
}
|
|
9703
|
+
}
|
|
9704
|
+
} else if (event.el_type === "bar") {
|
|
9705
|
+
if (inOverlay) {
|
|
9706
|
+
// delete the overlay events from this array without messing up this loop.
|
|
9707
|
+
inOverlay = false;
|
|
9708
|
+
overlayVoice[k].snip.push({
|
|
9709
|
+
start: snipStart,
|
|
9710
|
+
len: kk - snipStart
|
|
9711
|
+
});
|
|
9712
|
+
overlayVoice[k].voice.push(event); // Also end the overlay with the barline.
|
|
9713
|
+
} else {
|
|
9714
|
+
// This keeps the voices lined up: if the overlay isn't in the first measure then we need a bunch of invisible rests.
|
|
9715
|
+
if (durationThisBar > 0) overlayVoice[k].voice.push({
|
|
9716
|
+
el_type: "note",
|
|
9717
|
+
duration: durationThisBar,
|
|
9718
|
+
rest: {
|
|
9719
|
+
type: "invisible"
|
|
9720
|
+
},
|
|
9721
|
+
startChar: event.startChar,
|
|
9722
|
+
endChar: event.endChar
|
|
9723
|
+
});
|
|
9724
|
+
overlayVoice[k].voice.push(event);
|
|
9725
|
+
}
|
|
9726
|
+
durationThisBar = 0;
|
|
9727
|
+
} else if (event.el_type === "note") {
|
|
9728
|
+
if (inOverlay) {
|
|
9729
|
+
overlayVoice[k].voice.push(event);
|
|
9730
|
+
} else {
|
|
9731
|
+
durationThisBar += event.duration;
|
|
9732
|
+
durationsPerLines[i] += event.duration;
|
|
9733
|
+
}
|
|
9734
|
+
} 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") {
|
|
9735
|
+
// These types of events are duplicated on the overlay layer.
|
|
9736
|
+
overlayVoice[k].voice.push(event);
|
|
9737
|
+
}
|
|
9738
|
+
}
|
|
9739
|
+
if (overlayVoice[k].hasOverlay && overlayVoice[k].snip.length === 0) {
|
|
9740
|
+
// there was no closing bar, so we didn't set the snip amount.
|
|
9741
|
+
overlayVoice[k].snip.push({
|
|
9742
|
+
start: snipStart,
|
|
9743
|
+
len: voice.length - snipStart
|
|
9744
|
+
});
|
|
9745
|
+
}
|
|
9746
|
+
}
|
|
9747
|
+
for (k = 0; k < overlayVoice.length; k++) {
|
|
9748
|
+
var ov = overlayVoice[k];
|
|
9749
|
+
if (ov.hasOverlay) {
|
|
9750
|
+
ov.voice.splice(0, 0, {
|
|
9751
|
+
el_type: "stem",
|
|
9752
|
+
direction: "down"
|
|
9753
|
+
});
|
|
9754
|
+
staff.voices.push(ov.voice);
|
|
9755
|
+
for (var kkk = ov.snip.length - 1; kkk >= 0; kkk--) {
|
|
9756
|
+
var snip = ov.snip[kkk];
|
|
9757
|
+
staff.voices[k].splice(snip.start, snip.len);
|
|
9758
|
+
staff.voices[k].splice(snip.start + 1, 0, {
|
|
9759
|
+
el_type: "stem",
|
|
9760
|
+
direction: "auto"
|
|
9761
|
+
});
|
|
9762
|
+
var indexOfLastBar = findLastBar(staff.voices[k], snip.start);
|
|
9763
|
+
staff.voices[k].splice(indexOfLastBar, 0, {
|
|
9764
|
+
el_type: "stem",
|
|
9765
|
+
direction: "up"
|
|
9766
|
+
});
|
|
9767
|
+
}
|
|
9768
|
+
// remove ending marks from the overlay voice so they are not repeated
|
|
9769
|
+
for (kkk = 0; kkk < staff.voices[staff.voices.length - 1].length; kkk++) {
|
|
9770
|
+
staff.voices[staff.voices.length - 1][kkk] = Object.assign({}, staff.voices[staff.voices.length - 1][kkk]);
|
|
9771
|
+
var el = staff.voices[staff.voices.length - 1][kkk];
|
|
9772
|
+
if (el.el_type === 'bar' && el.startEnding) {
|
|
9773
|
+
delete el.startEnding;
|
|
9774
|
+
}
|
|
9775
|
+
if (el.el_type === 'bar' && el.endEnding) delete el.endEnding;
|
|
9776
|
+
}
|
|
9777
|
+
}
|
|
9778
|
+
}
|
|
9779
|
+
}
|
|
9780
|
+
}
|
|
9781
|
+
}
|
|
9782
|
+
return madeChanges;
|
|
9783
|
+
}
|
|
9784
|
+
;
|
|
9785
|
+
function findLastBar(voice, start) {
|
|
9786
|
+
for (var i = start - 1; i > 0 && voice[i].el_type !== "bar"; i--) {}
|
|
9787
|
+
return i;
|
|
9788
|
+
}
|
|
9789
|
+
function fixTitles(lines) {
|
|
9790
|
+
// We might have name and subname defined. We now know what line everything is on, so we can determine which to use.
|
|
9791
|
+
var firstMusicLine = true;
|
|
10262
9792
|
for (var i = 0; i < lines.length; i++) {
|
|
9793
|
+
var line = lines[i];
|
|
9794
|
+
if (line.staff) {
|
|
9795
|
+
for (var j = 0; j < line.staff.length; j++) {
|
|
9796
|
+
var staff = line.staff[j];
|
|
9797
|
+
if (staff.title) {
|
|
9798
|
+
var hasATitle = false;
|
|
9799
|
+
for (var k = 0; k < staff.title.length; k++) {
|
|
9800
|
+
if (staff.title[k]) {
|
|
9801
|
+
staff.title[k] = firstMusicLine ? staff.title[k].name : staff.title[k].subname;
|
|
9802
|
+
if (staff.title[k]) hasATitle = true;else staff.title[k] = '';
|
|
9803
|
+
} else staff.title[k] = '';
|
|
9804
|
+
}
|
|
9805
|
+
if (!hasATitle) delete staff.title;
|
|
9806
|
+
}
|
|
9807
|
+
}
|
|
9808
|
+
firstMusicLine = false;
|
|
9809
|
+
}
|
|
9810
|
+
}
|
|
9811
|
+
}
|
|
9812
|
+
function cleanUpSlursInLine(line, staffNum, voiceNum, currSlur) {
|
|
9813
|
+
if (!currSlur[staffNum]) currSlur[staffNum] = [];
|
|
9814
|
+
if (!currSlur[staffNum][voiceNum]) currSlur[staffNum][voiceNum] = [];
|
|
9815
|
+
var x;
|
|
9816
|
+
// var lyr = null; // TODO-PER: debugging.
|
|
9817
|
+
|
|
9818
|
+
var addEndSlur = function addEndSlur(obj, num, chordPos) {
|
|
9819
|
+
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9820
|
+
// There isn't an exact match for note position, but we'll take any other open slur.
|
|
9821
|
+
for (x = 0; x < currSlur[staffNum][voiceNum].length; x++) {
|
|
9822
|
+
if (currSlur[staffNum][voiceNum][x] !== undefined) {
|
|
9823
|
+
chordPos = x;
|
|
9824
|
+
break;
|
|
9825
|
+
}
|
|
9826
|
+
}
|
|
9827
|
+
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9828
|
+
var offNum = chordPos * 100 + 1;
|
|
9829
|
+
obj.endSlur.forEach(function (x) {
|
|
9830
|
+
if (offNum === x) --offNum;
|
|
9831
|
+
});
|
|
9832
|
+
currSlur[staffNum][voiceNum][chordPos] = [offNum];
|
|
9833
|
+
}
|
|
9834
|
+
}
|
|
9835
|
+
var slurNum;
|
|
9836
|
+
for (var i = 0; i < num; i++) {
|
|
9837
|
+
slurNum = currSlur[staffNum][voiceNum][chordPos].pop();
|
|
9838
|
+
obj.endSlur.push(slurNum);
|
|
9839
|
+
// lyr.syllable += '<' + slurNum; // TODO-PER: debugging
|
|
9840
|
+
}
|
|
9841
|
+
|
|
9842
|
+
if (currSlur[staffNum][voiceNum][chordPos].length === 0) delete currSlur[staffNum][voiceNum][chordPos];
|
|
9843
|
+
return slurNum;
|
|
9844
|
+
};
|
|
9845
|
+
var addStartSlur = function addStartSlur(obj, num, chordPos, usedNums) {
|
|
9846
|
+
obj.startSlur = [];
|
|
9847
|
+
if (currSlur[staffNum][voiceNum][chordPos] === undefined) {
|
|
9848
|
+
currSlur[staffNum][voiceNum][chordPos] = [];
|
|
9849
|
+
}
|
|
9850
|
+
var nextNum = chordPos * 100 + 1;
|
|
9851
|
+
for (var i = 0; i < num; i++) {
|
|
9852
|
+
if (usedNums) {
|
|
9853
|
+
usedNums.forEach(function (x) {
|
|
9854
|
+
if (nextNum === x) ++nextNum;
|
|
9855
|
+
});
|
|
9856
|
+
usedNums.forEach(function (x) {
|
|
9857
|
+
if (nextNum === x) ++nextNum;
|
|
9858
|
+
});
|
|
9859
|
+
usedNums.forEach(function (x) {
|
|
9860
|
+
if (nextNum === x) ++nextNum;
|
|
9861
|
+
});
|
|
9862
|
+
}
|
|
9863
|
+
currSlur[staffNum][voiceNum][chordPos].forEach(function (x) {
|
|
9864
|
+
if (nextNum === x) ++nextNum;
|
|
9865
|
+
});
|
|
9866
|
+
currSlur[staffNum][voiceNum][chordPos].forEach(function (x) {
|
|
9867
|
+
if (nextNum === x) ++nextNum;
|
|
9868
|
+
});
|
|
9869
|
+
currSlur[staffNum][voiceNum][chordPos].push(nextNum);
|
|
9870
|
+
obj.startSlur.push({
|
|
9871
|
+
label: nextNum
|
|
9872
|
+
});
|
|
9873
|
+
if (obj.dottedSlur) {
|
|
9874
|
+
obj.startSlur[obj.startSlur.length - 1].style = 'dotted';
|
|
9875
|
+
delete obj.dottedSlur;
|
|
9876
|
+
}
|
|
9877
|
+
// lyr.syllable += ' ' + nextNum + '>'; // TODO-PER:debugging
|
|
9878
|
+
nextNum++;
|
|
9879
|
+
}
|
|
9880
|
+
};
|
|
9881
|
+
for (var i = 0; i < line.length; i++) {
|
|
9882
|
+
var el = line[i];
|
|
9883
|
+
// if (el.lyric === undefined) // TODO-PER: debugging
|
|
9884
|
+
// el.lyric = [{ divider: '-' }]; // TODO-PER: debugging
|
|
9885
|
+
// lyr = el.lyric[0]; // TODO-PER: debugging
|
|
9886
|
+
// lyr.syllable = ''; // TODO-PER: debugging
|
|
9887
|
+
if (el.el_type === 'note') {
|
|
9888
|
+
if (el.gracenotes) {
|
|
9889
|
+
for (var g = 0; g < el.gracenotes.length; g++) {
|
|
9890
|
+
if (el.gracenotes[g].endSlur) {
|
|
9891
|
+
var gg = el.gracenotes[g].endSlur;
|
|
9892
|
+
el.gracenotes[g].endSlur = [];
|
|
9893
|
+
for (var ggg = 0; ggg < gg; ggg++) {
|
|
9894
|
+
addEndSlur(el.gracenotes[g], 1, 20);
|
|
9895
|
+
}
|
|
9896
|
+
}
|
|
9897
|
+
if (el.gracenotes[g].startSlur) {
|
|
9898
|
+
x = el.gracenotes[g].startSlur;
|
|
9899
|
+
addStartSlur(el.gracenotes[g], x, 20);
|
|
9900
|
+
}
|
|
9901
|
+
}
|
|
9902
|
+
}
|
|
9903
|
+
if (el.endSlur) {
|
|
9904
|
+
x = el.endSlur;
|
|
9905
|
+
el.endSlur = [];
|
|
9906
|
+
addEndSlur(el, x, 0);
|
|
9907
|
+
}
|
|
9908
|
+
if (el.startSlur) {
|
|
9909
|
+
x = el.startSlur;
|
|
9910
|
+
addStartSlur(el, x, 0);
|
|
9911
|
+
}
|
|
9912
|
+
if (el.pitches) {
|
|
9913
|
+
var usedNums = [];
|
|
9914
|
+
for (var p = 0; p < el.pitches.length; p++) {
|
|
9915
|
+
if (el.pitches[p].endSlur) {
|
|
9916
|
+
var k = el.pitches[p].endSlur;
|
|
9917
|
+
el.pitches[p].endSlur = [];
|
|
9918
|
+
for (var j = 0; j < k; j++) {
|
|
9919
|
+
var slurNum = addEndSlur(el.pitches[p], 1, p + 1);
|
|
9920
|
+
usedNums.push(slurNum);
|
|
9921
|
+
}
|
|
9922
|
+
}
|
|
9923
|
+
}
|
|
9924
|
+
for (p = 0; p < el.pitches.length; p++) {
|
|
9925
|
+
if (el.pitches[p].startSlur) {
|
|
9926
|
+
x = el.pitches[p].startSlur;
|
|
9927
|
+
addStartSlur(el.pitches[p], x, p + 1, usedNums);
|
|
9928
|
+
}
|
|
9929
|
+
}
|
|
9930
|
+
// Correct for the weird gracenote case where ({g}a) should match.
|
|
9931
|
+
// The end slur was already assigned to the note, and needs to be moved to the first note of the graces.
|
|
9932
|
+
if (el.gracenotes && el.pitches[0].endSlur && el.pitches[0].endSlur[0] === 100 && el.pitches[0].startSlur) {
|
|
9933
|
+
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];
|
|
9934
|
+
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();
|
|
9935
|
+
if (currSlur[staffNum][voiceNum][1].length === 1) delete currSlur[staffNum][voiceNum][1];else currSlur[staffNum][voiceNum][1].pop();
|
|
9936
|
+
}
|
|
9937
|
+
}
|
|
9938
|
+
}
|
|
9939
|
+
}
|
|
9940
|
+
}
|
|
9941
|
+
function wrapMusicLines(lines, barsperstaff) {
|
|
9942
|
+
for (i = 0; i < lines.length; i++) {
|
|
10263
9943
|
if (lines[i].staff !== undefined) {
|
|
10264
|
-
for (
|
|
10265
|
-
|
|
9944
|
+
for (s = 0; s < lines[i].staff.length; s++) {
|
|
9945
|
+
var permanentItems = [];
|
|
9946
|
+
for (v = 0; v < lines[i].staff[s].voices.length; v++) {
|
|
10266
9947
|
var voice = lines[i].staff[s].voices[v];
|
|
9948
|
+
var barNumThisLine = 0;
|
|
10267
9949
|
for (var n = 0; n < voice.length; n++) {
|
|
10268
|
-
|
|
10269
|
-
|
|
10270
|
-
|
|
10271
|
-
|
|
10272
|
-
|
|
10273
|
-
|
|
10274
|
-
|
|
10275
|
-
|
|
10276
|
-
|
|
10277
|
-
|
|
10278
|
-
|
|
9950
|
+
if (voice[n].el_type === 'bar') {
|
|
9951
|
+
barNumThisLine++;
|
|
9952
|
+
if (barNumThisLine >= barsperstaff) {
|
|
9953
|
+
// push everything else to the next line, if there is anything else,
|
|
9954
|
+
// and there is a next line. If there isn't a next line, create one.
|
|
9955
|
+
if (n < voice.length - 1) {
|
|
9956
|
+
var nextLine = getNextMusicLine(lines, i);
|
|
9957
|
+
if (!nextLine) {
|
|
9958
|
+
var cp = JSON.parse(JSON.stringify(lines[i]));
|
|
9959
|
+
lines.push(Object.assign({}, cp));
|
|
9960
|
+
nextLine = lines[lines.length - 1];
|
|
9961
|
+
for (var ss = 0; ss < nextLine.staff.length; ss++) {
|
|
9962
|
+
for (var vv = 0; vv < nextLine.staff[ss].voices.length; vv++) {
|
|
9963
|
+
nextLine.staff[ss].voices[vv] = [];
|
|
9964
|
+
}
|
|
9965
|
+
}
|
|
9966
|
+
}
|
|
9967
|
+
var startElement = n + 1;
|
|
9968
|
+
var section = lines[i].staff[s].voices[v].slice(startElement);
|
|
9969
|
+
lines[i].staff[s].voices[v] = lines[i].staff[s].voices[v].slice(0, startElement);
|
|
9970
|
+
nextLine.staff[s].voices[v] = permanentItems.concat(section.concat(nextLine.staff[s].voices[v]));
|
|
9971
|
+
return true;
|
|
9972
|
+
}
|
|
10279
9973
|
}
|
|
9974
|
+
} else if (!voice[n].duration) {
|
|
9975
|
+
permanentItems.push(voice[n]);
|
|
10280
9976
|
}
|
|
10281
9977
|
}
|
|
10282
9978
|
}
|
|
10283
9979
|
}
|
|
10284
9980
|
}
|
|
10285
9981
|
}
|
|
9982
|
+
return false;
|
|
9983
|
+
}
|
|
9984
|
+
function getNextMusicLine(lines, currentLine) {
|
|
9985
|
+
currentLine++;
|
|
9986
|
+
while (lines.length > currentLine) {
|
|
9987
|
+
if (lines[currentLine].staff) return lines[currentLine];
|
|
9988
|
+
currentLine++;
|
|
9989
|
+
}
|
|
9990
|
+
return null;
|
|
9991
|
+
}
|
|
9992
|
+
function getLastNote(tune) {
|
|
9993
|
+
if (!tune.lines[tune.lineNum]) return null;
|
|
9994
|
+
if (!tune.lines[tune.lineNum].staff) return null;
|
|
9995
|
+
if (!tune.lines[tune.lineNum].staff[tune.staffNum]) return null;
|
|
9996
|
+
var voice = tune.lines[tune.lineNum].staff[tune.staffNum].voices[tune.voiceNum];
|
|
9997
|
+
if (!voice) return null;
|
|
9998
|
+
for (var i = voice.length - 1; i >= 0; i--) {
|
|
9999
|
+
var el = voice[i];
|
|
10000
|
+
if (el.el_type === 'note') {
|
|
10001
|
+
return el;
|
|
10002
|
+
}
|
|
10003
|
+
}
|
|
10004
|
+
return null;
|
|
10005
|
+
}
|
|
10006
|
+
;
|
|
10007
|
+
function getDuration(el) {
|
|
10008
|
+
if (el.duration) return el.duration;
|
|
10009
|
+
return 0;
|
|
10010
|
+
}
|
|
10011
|
+
;
|
|
10012
|
+
function closeLine(tune) {
|
|
10013
|
+
if (tune.potentialStartBeam && tune.potentialEndBeam) {
|
|
10014
|
+
tune.potentialStartBeam.startBeam = true;
|
|
10015
|
+
tune.potentialEndBeam.endBeam = true;
|
|
10016
|
+
}
|
|
10017
|
+
delete tune.potentialStartBeam;
|
|
10018
|
+
delete tune.potentialEndBeam;
|
|
10019
|
+
}
|
|
10020
|
+
;
|
|
10021
|
+
function containsNotes(voice) {
|
|
10022
|
+
for (var i = 0; i < voice.length; i++) {
|
|
10023
|
+
if (voice[i].el_type === 'note' || voice[i].el_type === 'bar') return true;
|
|
10024
|
+
}
|
|
10025
|
+
return false;
|
|
10026
|
+
}
|
|
10027
|
+
;
|
|
10028
|
+
function containsNotesStrict(voice) {
|
|
10029
|
+
for (var i = 0; i < voice.length; i++) {
|
|
10030
|
+
if (voice[i].el_type === 'note' && (voice[i].rest === undefined || voice[i].chord !== undefined)) return true;
|
|
10031
|
+
}
|
|
10032
|
+
return false;
|
|
10033
|
+
}
|
|
10034
|
+
;
|
|
10035
|
+
function pushLine(tune, hash) {
|
|
10036
|
+
if (tune.vskipPending) {
|
|
10037
|
+
hash.vskip = tune.vskipPending;
|
|
10038
|
+
delete tune.vskipPending;
|
|
10039
|
+
}
|
|
10040
|
+
tune.lines.push(hash);
|
|
10041
|
+
}
|
|
10042
|
+
;
|
|
10043
|
+
function pushNote(self, tune, hp, voiceDefs, currentVoiceName) {
|
|
10044
|
+
//console.log("pushNote", tune.lineNum, tune.staffNum, hp.pitches ? JSON.stringify(hp.pitches) : hp.pitches)
|
|
10045
|
+
var currStaff = tune.lines[tune.lineNum].staff[tune.staffNum];
|
|
10046
|
+
if (hp.pitches !== undefined) {
|
|
10047
|
+
var mid = currStaff.workingClef.verticalPos;
|
|
10048
|
+
hp.pitches.forEach(function (p) {
|
|
10049
|
+
p.verticalPos = p.pitch - mid;
|
|
10050
|
+
});
|
|
10051
|
+
}
|
|
10052
|
+
if (hp.gracenotes !== undefined) {
|
|
10053
|
+
var mid2 = currStaff.workingClef.verticalPos;
|
|
10054
|
+
hp.gracenotes.forEach(function (p) {
|
|
10055
|
+
p.verticalPos = p.pitch - mid2;
|
|
10056
|
+
});
|
|
10057
|
+
}
|
|
10058
|
+
if (currStaff.voices.length <= tune.voiceNum) {
|
|
10059
|
+
//console.log("should create?", currentVoiceName, voiceDefs)
|
|
10060
|
+
if (!voiceDefs[currentVoiceName]) voiceDefs[currentVoiceName] = {};
|
|
10061
|
+
createVoice(self, tune, voiceDefs[currentVoiceName]);
|
|
10062
|
+
}
|
|
10063
|
+
currStaff.voices[tune.voiceNum].push(hp);
|
|
10064
|
+
}
|
|
10065
|
+
function endBeamHere(hashParams, tune) {
|
|
10066
|
+
tune.potentialStartBeam.startBeam = true;
|
|
10067
|
+
hashParams.endBeam = true;
|
|
10068
|
+
delete tune.potentialStartBeam;
|
|
10069
|
+
delete tune.potentialEndBeam;
|
|
10070
|
+
}
|
|
10071
|
+
function endBeamLast(tune) {
|
|
10072
|
+
if (tune.potentialStartBeam !== undefined && tune.potentialEndBeam !== undefined) {
|
|
10073
|
+
// Do we have a set of notes to beam?
|
|
10074
|
+
tune.potentialStartBeam.startBeam = true;
|
|
10075
|
+
tune.potentialEndBeam.endBeam = true;
|
|
10076
|
+
}
|
|
10077
|
+
delete tune.potentialStartBeam;
|
|
10078
|
+
delete tune.potentialEndBeam;
|
|
10079
|
+
}
|
|
10080
|
+
function setLineFont(tune, type, font) {
|
|
10081
|
+
// If we haven't encountered the font type yet then we are using the default font so it doesn't
|
|
10082
|
+
// need to be noted. If we have encountered it, then only record it if it is different from the last time.
|
|
10083
|
+
if (tune.runningFonts[type]) {
|
|
10084
|
+
var isDifferent = false;
|
|
10085
|
+
var keys = Object.keys(font);
|
|
10086
|
+
for (var i = 0; i < keys.length; i++) {
|
|
10087
|
+
if (tune.runningFonts[type][keys[i]] !== font[keys[i]]) isDifferent = true;
|
|
10088
|
+
}
|
|
10089
|
+
if (isDifferent) {
|
|
10090
|
+
tune.lines[tune.lineNum].staff[tune.staffNum][type] = font;
|
|
10091
|
+
}
|
|
10092
|
+
}
|
|
10093
|
+
tune.runningFonts[type] = font;
|
|
10094
|
+
}
|
|
10095
|
+
function createVoice(self, tune, params) {
|
|
10096
|
+
//console.log("createVoice", params)
|
|
10097
|
+
var thisStaff = tune.lines[tune.lineNum].staff[tune.staffNum];
|
|
10098
|
+
thisStaff.voices[tune.voiceNum] = [];
|
|
10099
|
+
if (!thisStaff.title) thisStaff.title = [];
|
|
10100
|
+
thisStaff.title[tune.voiceNum] = {
|
|
10101
|
+
name: params.name,
|
|
10102
|
+
subname: params.subname
|
|
10103
|
+
};
|
|
10104
|
+
if (params.style) self.appendElement('style', null, null, {
|
|
10105
|
+
head: params.style
|
|
10106
|
+
});
|
|
10107
|
+
if (params.stem) self.appendElement('stem', null, null, {
|
|
10108
|
+
direction: params.stem
|
|
10109
|
+
});else if (tune.voiceNum > 0) {
|
|
10110
|
+
if (thisStaff.voices[0] !== undefined) {
|
|
10111
|
+
var found = false;
|
|
10112
|
+
for (var i = 0; i < thisStaff.voices[0].length; i++) {
|
|
10113
|
+
if (thisStaff.voices[0].el_type === 'stem') found = true;
|
|
10114
|
+
}
|
|
10115
|
+
if (!found) {
|
|
10116
|
+
var stem = {
|
|
10117
|
+
el_type: 'stem',
|
|
10118
|
+
direction: 'up'
|
|
10119
|
+
};
|
|
10120
|
+
thisStaff.voices[0].splice(0, 0, stem);
|
|
10121
|
+
}
|
|
10122
|
+
}
|
|
10123
|
+
self.appendElement('stem', null, null, {
|
|
10124
|
+
direction: 'down'
|
|
10125
|
+
});
|
|
10126
|
+
}
|
|
10127
|
+
if (params.scale) self.appendElement('scale', null, null, {
|
|
10128
|
+
size: params.scale
|
|
10129
|
+
});
|
|
10130
|
+
if (params.color) self.appendElement('color', null, null, {
|
|
10131
|
+
color: params.color
|
|
10132
|
+
});
|
|
10133
|
+
}
|
|
10134
|
+
function createStaff(self, tune, params) {
|
|
10135
|
+
if (params.key && params.key.impliedNaturals) {
|
|
10136
|
+
params.key.accidentals = params.key.accidentals.concat(params.key.impliedNaturals);
|
|
10137
|
+
delete params.key.impliedNaturals;
|
|
10138
|
+
}
|
|
10139
|
+
tune.lines[tune.lineNum].staff[tune.staffNum] = {
|
|
10140
|
+
voices: [],
|
|
10141
|
+
clef: params.clef,
|
|
10142
|
+
key: params.key,
|
|
10143
|
+
workingClef: params.clef
|
|
10144
|
+
};
|
|
10145
|
+
var staff = tune.lines[tune.lineNum].staff[tune.staffNum];
|
|
10146
|
+
if (params.stafflines !== undefined) {
|
|
10147
|
+
staff.clef.stafflines = params.stafflines;
|
|
10148
|
+
staff.workingClef.stafflines = params.stafflines;
|
|
10149
|
+
}
|
|
10150
|
+
if (params.staffscale) {
|
|
10151
|
+
staff.staffscale = params.staffscale;
|
|
10152
|
+
}
|
|
10153
|
+
if (params.annotationfont) setLineFont(tune, "annotationfont", params.annotationfont);
|
|
10154
|
+
if (params.gchordfont) setLineFont(tune, "gchordfont", params.gchordfont);
|
|
10155
|
+
if (params.tripletfont) setLineFont(tune, "tripletfont", params.tripletfont);
|
|
10156
|
+
if (params.vocalfont) setLineFont(tune, "vocalfont", params.vocalfont);
|
|
10157
|
+
if (params.bracket) staff.bracket = params.bracket;
|
|
10158
|
+
if (params.brace) staff.brace = params.brace;
|
|
10159
|
+
if (params.connectBarLines) staff.connectBarLines = params.connectBarLines;
|
|
10160
|
+
if (params.barNumber) staff.barNumber = params.barNumber;
|
|
10161
|
+
createVoice(self, tune, params);
|
|
10162
|
+
// Some stuff just happens for the first voice
|
|
10163
|
+
if (params.part) self.appendElement('part', params.part.startChar, params.part.endChar, {
|
|
10164
|
+
title: params.part.title
|
|
10165
|
+
});
|
|
10166
|
+
if (params.meter !== undefined) staff.meter = params.meter;
|
|
10167
|
+
if (tune.vskipPending) {
|
|
10168
|
+
tune.lines[tune.lineNum].vskip = tune.vskipPending;
|
|
10169
|
+
delete tune.vskipPending;
|
|
10170
|
+
}
|
|
10171
|
+
}
|
|
10172
|
+
function createLine(self, tune, params) {
|
|
10173
|
+
tune.lines[tune.lineNum] = {
|
|
10174
|
+
staff: []
|
|
10175
|
+
};
|
|
10176
|
+
createStaff(self, tune, params);
|
|
10286
10177
|
}
|
|
10287
10178
|
module.exports = TuneBuilder;
|
|
10288
10179
|
|
|
@@ -11452,6 +11343,7 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
|
|
|
11452
11343
|
case "chordprog":
|
|
11453
11344
|
case "bassvol":
|
|
11454
11345
|
case "chordvol":
|
|
11346
|
+
case "gchordbars":
|
|
11455
11347
|
chordTrack.paramChange(element);
|
|
11456
11348
|
break;
|
|
11457
11349
|
default:
|
|
@@ -11581,7 +11473,8 @@ var pitchesToPerc = __webpack_require__(/*! ./pitches-to-perc */ "./src/synth/pi
|
|
|
11581
11473
|
function processVolume(beat, voiceOff) {
|
|
11582
11474
|
if (voiceOff) return 0;
|
|
11583
11475
|
var volume;
|
|
11584
|
-
|
|
11476
|
+
// MAE 21 Jun 2024 - This previously wasn't allowing zero volume to be applied
|
|
11477
|
+
if (nextVolume != undefined) {
|
|
11585
11478
|
volume = nextVolume;
|
|
11586
11479
|
nextVolume = undefined;
|
|
11587
11480
|
} else if (!doBeatAccents) {
|
|
@@ -12914,7 +12807,7 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
|
|
|
12914
12807
|
if (!e) e = voices[voiceNumber].length; // If there wasn't a first ending marker, then we copy everything.
|
|
12915
12808
|
// duplicate each of the elements - this has to be a deep copy.
|
|
12916
12809
|
for (var z = s; z < e; z++) {
|
|
12917
|
-
var item =
|
|
12810
|
+
var item = Object.assign({}, voices[voiceNumber][z]);
|
|
12918
12811
|
if (item.pitches) item.pitches = parseCommon.cloneArray(item.pitches);
|
|
12919
12812
|
voices[voiceNumber].push(item);
|
|
12920
12813
|
}
|
|
@@ -13023,8 +12916,6 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
|
|
|
13023
12916
|
break;
|
|
13024
12917
|
case "swing":
|
|
13025
12918
|
case "gchord":
|
|
13026
|
-
case "bassprog":
|
|
13027
|
-
case "chordprog":
|
|
13028
12919
|
case "bassvol":
|
|
13029
12920
|
case "chordvol":
|
|
13030
12921
|
voices[voiceNumber].push({
|
|
@@ -13032,6 +12923,23 @@ var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/ab
|
|
|
13032
12923
|
param: elem.params[0]
|
|
13033
12924
|
});
|
|
13034
12925
|
break;
|
|
12926
|
+
case "bassprog": // MAE 22 May 2024
|
|
12927
|
+
case "chordprog":
|
|
12928
|
+
// MAE 22 May 2024
|
|
12929
|
+
voices[voiceNumber].push({
|
|
12930
|
+
el_type: elem.cmd,
|
|
12931
|
+
value: elem.params[0],
|
|
12932
|
+
octaveShift: elem.params[1]
|
|
12933
|
+
});
|
|
12934
|
+
break;
|
|
12935
|
+
|
|
12936
|
+
// MAE 23 Jun 2024
|
|
12937
|
+
case "gchordbars":
|
|
12938
|
+
voices[voiceNumber].push({
|
|
12939
|
+
el_type: elem.cmd,
|
|
12940
|
+
param: elem.params[0]
|
|
12941
|
+
});
|
|
12942
|
+
break;
|
|
13035
12943
|
default:
|
|
13036
12944
|
console.log("MIDI seq: midi cmd not handled: ", elem.cmd, elem);
|
|
13037
12945
|
}
|
|
@@ -13304,7 +13212,7 @@ module.exports = centsToFactor;
|
|
|
13304
13212
|
/*!**********************************!*\
|
|
13305
13213
|
!*** ./src/synth/chord-track.js ***!
|
|
13306
13214
|
\**********************************/
|
|
13307
|
-
/***/ (function(module
|
|
13215
|
+
/***/ (function(module) {
|
|
13308
13216
|
|
|
13309
13217
|
//
|
|
13310
13218
|
// The algorithm for chords is:
|
|
@@ -13325,7 +13233,6 @@ module.exports = centsToFactor;
|
|
|
13325
13233
|
//
|
|
13326
13234
|
// 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
13235
|
|
|
13328
|
-
var parseCommon = __webpack_require__(/*! ../parse/abc_common */ "./src/parse/abc_common.js");
|
|
13329
13236
|
var ChordTrack = function ChordTrack(numVoices, chordsOff, midiOptions, meter) {
|
|
13330
13237
|
this.chordTrack = [];
|
|
13331
13238
|
this.chordTrackFinished = false;
|
|
@@ -13340,11 +13247,23 @@ var ChordTrack = function ChordTrack(numVoices, chordsOff, midiOptions, meter) {
|
|
|
13340
13247
|
this.lastBarTime = 0;
|
|
13341
13248
|
this.meter = meter;
|
|
13342
13249
|
this.tempoChangeFactor = 1;
|
|
13343
|
-
|
|
13344
|
-
|
|
13250
|
+
|
|
13251
|
+
// MAE 17 Jun 2024 - To allow for bass and chord instrument octave shifts
|
|
13252
|
+
this.bassInstrument = midiOptions.bassprog && midiOptions.bassprog.length >= 1 ? midiOptions.bassprog[0] : 0;
|
|
13253
|
+
this.chordInstrument = midiOptions.chordprog && midiOptions.chordprog.length >= 1 ? midiOptions.chordprog[0] : 0;
|
|
13254
|
+
|
|
13255
|
+
// MAE For octave shifted bass and chords
|
|
13256
|
+
this.bassOctaveShift = midiOptions.bassprog && midiOptions.bassprog.length === 2 ? midiOptions.bassprog[1] : 0;
|
|
13257
|
+
this.chordOctaveShift = midiOptions.chordprog && midiOptions.chordprog.length === 2 ? midiOptions.chordprog[1] : 0;
|
|
13345
13258
|
this.boomVolume = midiOptions.bassvol && midiOptions.bassvol.length === 1 ? midiOptions.bassvol[0] : 64;
|
|
13346
13259
|
this.chickVolume = midiOptions.chordvol && midiOptions.chordvol.length === 1 ? midiOptions.chordvol[0] : 48;
|
|
13347
|
-
|
|
13260
|
+
|
|
13261
|
+
// This allows for an initial %%MIDI gchord with no string
|
|
13262
|
+
if (midiOptions.gchord && midiOptions.gchord.length > 0) {
|
|
13263
|
+
this.overridePattern = parseGChord(midiOptions.gchord[0]);
|
|
13264
|
+
} else {
|
|
13265
|
+
this.overridePattern = undefined;
|
|
13266
|
+
}
|
|
13348
13267
|
};
|
|
13349
13268
|
ChordTrack.prototype.setMeter = function (meter) {
|
|
13350
13269
|
this.meter = meter;
|
|
@@ -13364,7 +13283,7 @@ ChordTrack.prototype.setRhythmHead = function (isRhythmHead, elem) {
|
|
|
13364
13283
|
if (isRhythmHead) {
|
|
13365
13284
|
if (this.lastChord && this.lastChord.chick) {
|
|
13366
13285
|
for (var i2 = 0; i2 < this.lastChord.chick.length; i2++) {
|
|
13367
|
-
var note2 =
|
|
13286
|
+
var note2 = Object.assign({}, elem.pitches[0]);
|
|
13368
13287
|
note2.actualPitch = this.lastChord.chick[i2];
|
|
13369
13288
|
ePitches.push(note2);
|
|
13370
13289
|
}
|
|
@@ -13385,13 +13304,29 @@ ChordTrack.prototype.gChordOn = function (element) {
|
|
|
13385
13304
|
ChordTrack.prototype.paramChange = function (element) {
|
|
13386
13305
|
switch (element.el_type) {
|
|
13387
13306
|
case "gchord":
|
|
13388
|
-
|
|
13307
|
+
// Skips gchord elements that don't have pattern strings
|
|
13308
|
+
if (element.param && element.param.length > 0) {
|
|
13309
|
+
this.overridePattern = parseGChord(element.param);
|
|
13310
|
+
|
|
13311
|
+
// Generate a default duration scale based on the pattern
|
|
13312
|
+
//this.gchordduration = generateDefaultDurationScale(element.param);
|
|
13313
|
+
} else this.overridePattern = undefined;
|
|
13389
13314
|
break;
|
|
13390
13315
|
case "bassprog":
|
|
13391
|
-
this.bassInstrument = element.
|
|
13316
|
+
this.bassInstrument = element.value;
|
|
13317
|
+
if (element.octaveShift != undefined && element.octaveShift != null) {
|
|
13318
|
+
this.bassOctaveShift = element.octaveShift;
|
|
13319
|
+
} else {
|
|
13320
|
+
this.bassOctaveShift = 0;
|
|
13321
|
+
}
|
|
13392
13322
|
break;
|
|
13393
13323
|
case "chordprog":
|
|
13394
|
-
this.chordInstrument = element.
|
|
13324
|
+
this.chordInstrument = element.value;
|
|
13325
|
+
if (element.octaveShift != undefined && element.octaveShift != null) {
|
|
13326
|
+
this.chordOctaveShift = element.octaveShift;
|
|
13327
|
+
} else {
|
|
13328
|
+
this.chordOctaveShift = 0;
|
|
13329
|
+
}
|
|
13395
13330
|
break;
|
|
13396
13331
|
case "bassvol":
|
|
13397
13332
|
this.boomVolume = element.param;
|
|
@@ -13459,22 +13394,28 @@ ChordTrack.prototype.interpretChord = function (name) {
|
|
|
13459
13394
|
chordTranspose -= 12;
|
|
13460
13395
|
}
|
|
13461
13396
|
bass += chordTranspose;
|
|
13397
|
+
|
|
13398
|
+
// MAE 17 Jun 2024 - Supporting octave shifted bass and chords
|
|
13399
|
+
var unshiftedBass = bass;
|
|
13400
|
+
bass += this.bassOctaveShift * 12;
|
|
13462
13401
|
var bass2 = bass - 5; // The alternating bass is a 4th below
|
|
13463
13402
|
var chick;
|
|
13464
13403
|
if (name.length === 1) chick = this.chordNotes(bass, '');
|
|
13465
13404
|
var remaining = name.substring(1);
|
|
13466
13405
|
var acc = remaining.substring(0, 1);
|
|
13467
13406
|
if (acc === 'b' || acc === '♭') {
|
|
13407
|
+
unshiftedBass--;
|
|
13468
13408
|
bass--;
|
|
13469
13409
|
bass2--;
|
|
13470
13410
|
remaining = remaining.substring(1);
|
|
13471
13411
|
} else if (acc === '#' || acc === '♯') {
|
|
13412
|
+
unshiftedBass++;
|
|
13472
13413
|
bass++;
|
|
13473
13414
|
bass2++;
|
|
13474
13415
|
remaining = remaining.substring(1);
|
|
13475
13416
|
}
|
|
13476
13417
|
var arr = remaining.split('/');
|
|
13477
|
-
chick = this.chordNotes(
|
|
13418
|
+
chick = this.chordNotes(unshiftedBass, arr[0]);
|
|
13478
13419
|
// 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
13420
|
if (chick.length >= 3) {
|
|
13480
13421
|
var fifth = chick[2] - chick[0];
|
|
@@ -13491,6 +13432,9 @@ ChordTrack.prototype.interpretChord = function (name) {
|
|
|
13491
13432
|
'♭': -1
|
|
13492
13433
|
}[bassAcc] || 0;
|
|
13493
13434
|
bass = this.basses[arr[1].substring(0, 1)] + bassShift + chordTranspose;
|
|
13435
|
+
|
|
13436
|
+
// MAE 22 May 2024 - Supporting octave shifted bass and chords
|
|
13437
|
+
bass += this.bassOctaveShift * 12;
|
|
13494
13438
|
bass2 = bass;
|
|
13495
13439
|
}
|
|
13496
13440
|
}
|
|
@@ -13506,6 +13450,9 @@ ChordTrack.prototype.chordNotes = function (bass, modifier) {
|
|
|
13506
13450
|
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
13451
|
}
|
|
13508
13452
|
bass += 12; // the chord is an octave above the bass note.
|
|
13453
|
+
|
|
13454
|
+
// MAE 22 May 2024 - For chick octave shift
|
|
13455
|
+
bass += this.chordOctaveShift * 12;
|
|
13509
13456
|
var notes = [];
|
|
13510
13457
|
for (var i = 0; i < intervals.length; i++) {
|
|
13511
13458
|
notes.push(bass + intervals[i]);
|
|
@@ -13619,8 +13566,9 @@ function resolvePitch(currentChord, type, firstBoom, newBass) {
|
|
|
13619
13566
|
var ret = [];
|
|
13620
13567
|
if (!currentChord) return ret;
|
|
13621
13568
|
if (type.indexOf('boom') >= 0) ret.push(firstBoom ? currentChord.boom : currentChord.boom2);else if (newBass) ret.push(currentChord.boom);
|
|
13569
|
+
var numChordNotes = currentChord.chick.length;
|
|
13622
13570
|
if (type.indexOf('chick') >= 0) {
|
|
13623
|
-
for (var i = 0; i <
|
|
13571
|
+
for (var i = 0; i < numChordNotes; i++) {
|
|
13624
13572
|
ret.push(currentChord.chick[i]);
|
|
13625
13573
|
}
|
|
13626
13574
|
}
|
|
@@ -13632,13 +13580,13 @@ function resolvePitch(currentChord, type, firstBoom, newBass) {
|
|
|
13632
13580
|
ret.push(currentChord.chick[1]);
|
|
13633
13581
|
break;
|
|
13634
13582
|
case 'SOL':
|
|
13635
|
-
ret.push(currentChord
|
|
13583
|
+
ret.push(extractNote(currentChord, 2));
|
|
13636
13584
|
break;
|
|
13637
13585
|
case 'TI':
|
|
13638
|
-
|
|
13586
|
+
ret.push(extractNote(currentChord, 3));
|
|
13639
13587
|
break;
|
|
13640
13588
|
case 'TOP':
|
|
13641
|
-
|
|
13589
|
+
ret.push(extractNote(currentChord, 4));
|
|
13642
13590
|
break;
|
|
13643
13591
|
case 'do':
|
|
13644
13592
|
ret.push(currentChord.chick[0] + 12);
|
|
@@ -13647,17 +13595,24 @@ function resolvePitch(currentChord, type, firstBoom, newBass) {
|
|
|
13647
13595
|
ret.push(currentChord.chick[1] + 12);
|
|
13648
13596
|
break;
|
|
13649
13597
|
case 'sol':
|
|
13650
|
-
ret.push(currentChord
|
|
13598
|
+
ret.push(extractNote(currentChord, 2) + 12);
|
|
13651
13599
|
break;
|
|
13652
13600
|
case 'ti':
|
|
13653
|
-
|
|
13601
|
+
ret.push(extractNote(currentChord, 3) + 12);
|
|
13654
13602
|
break;
|
|
13655
13603
|
case 'top':
|
|
13656
|
-
|
|
13604
|
+
ret.push(extractNote(currentChord, 4) + 12);
|
|
13657
13605
|
break;
|
|
13658
13606
|
}
|
|
13659
13607
|
return ret;
|
|
13660
13608
|
}
|
|
13609
|
+
function extractNote(chord, index) {
|
|
13610
|
+
// 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
|
|
13611
|
+
var octave = Math.floor(index / chord.chick.length);
|
|
13612
|
+
var note = chord.chick[index % chord.chick.length];
|
|
13613
|
+
//console.log(chord.chick, {index, octave, note}, index % chord.chick.length)
|
|
13614
|
+
return note + octave * 12;
|
|
13615
|
+
}
|
|
13661
13616
|
function parseGChord(gchord) {
|
|
13662
13617
|
// 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
13618
|
var pattern = [];
|
|
@@ -13854,7 +13809,11 @@ ChordTrack.prototype.chordIntervals = {
|
|
|
13854
13809
|
'maj7#5#11': [0, 4, 8, 11, 18],
|
|
13855
13810
|
'9(#5)': [0, 4, 8, 10, 14],
|
|
13856
13811
|
'13(#5)': [0, 4, 8, 10, 14, 21],
|
|
13857
|
-
'13#5': [0, 4, 8, 10, 14, 21]
|
|
13812
|
+
'13#5': [0, 4, 8, 10, 14, 21],
|
|
13813
|
+
// MAE Power chords added 10 April 2024
|
|
13814
|
+
'5': [0, 7],
|
|
13815
|
+
'5(8)': [0, 7, 12],
|
|
13816
|
+
'5add8': [0, 7, 12]
|
|
13858
13817
|
};
|
|
13859
13818
|
ChordTrack.prototype.rhythmPatterns = {
|
|
13860
13819
|
"2/2": ['boom', '', '', '', 'chick', '', '', ''],
|
|
@@ -13866,8 +13825,12 @@ ChordTrack.prototype.rhythmPatterns = {
|
|
|
13866
13825
|
"5/4": ['boom', '', 'chick', '', 'chick', '', 'boom', '', 'chick', ''],
|
|
13867
13826
|
"6/4": ['boom', '', 'chick', '', 'boom', '', 'chick', '', 'boom', '', 'chick', ''],
|
|
13868
13827
|
"3/8": ['boom', '', 'chick'],
|
|
13828
|
+
"5/8": ['boom', 'chick', 'chick', 'boom', 'chick'],
|
|
13869
13829
|
"6/8": ['boom', '', 'chick', 'boom', '', 'chick'],
|
|
13830
|
+
"7/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
|
|
13870
13831
|
"9/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick'],
|
|
13832
|
+
"10/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
|
|
13833
|
+
"11/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick', 'chick'],
|
|
13871
13834
|
"12/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick']
|
|
13872
13835
|
};
|
|
13873
13836
|
|
|
@@ -13955,7 +13918,6 @@ module.exports = createNoteMap;
|
|
|
13955
13918
|
var supportsAudio = __webpack_require__(/*! ./supports-audio */ "./src/synth/supports-audio.js");
|
|
13956
13919
|
var registerAudioContext = __webpack_require__(/*! ./register-audio-context */ "./src/synth/register-audio-context.js");
|
|
13957
13920
|
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
13921
|
var loopImage = __webpack_require__(/*! ./images/loop.svg.js */ "./src/synth/images/loop.svg.js");
|
|
13960
13922
|
var playImage = __webpack_require__(/*! ./images/play.svg.js */ "./src/synth/images/play.svg.js");
|
|
13961
13923
|
var pauseImage = __webpack_require__(/*! ./images/pause.svg.js */ "./src/synth/images/pause.svg.js");
|
|
@@ -13971,7 +13933,7 @@ function CreateSynthControl(parent, options) {
|
|
|
13971
13933
|
} else if (!(parent instanceof HTMLElement)) throw new Error("The first parameter must be a valid element or selector in the DOM.");
|
|
13972
13934
|
self.parent = parent;
|
|
13973
13935
|
self.options = {};
|
|
13974
|
-
if (options) self.options =
|
|
13936
|
+
if (options) self.options = Object.assign({}, options);
|
|
13975
13937
|
|
|
13976
13938
|
// This can be called in the following cases:
|
|
13977
13939
|
// AC already registered and not suspended
|
|
@@ -15642,115 +15604,315 @@ function SynthController() {
|
|
|
15642
15604
|
return Promise.resolve();
|
|
15643
15605
|
});
|
|
15644
15606
|
}
|
|
15645
|
-
self.seek(startPercent);
|
|
15646
|
-
return Promise.resolve();
|
|
15647
|
-
});
|
|
15648
|
-
}
|
|
15649
|
-
return Promise.resolve();
|
|
15650
|
-
};
|
|
15651
|
-
self.onWarp = function (ev) {
|
|
15652
|
-
var newWarp = ev.target.value;
|
|
15653
|
-
return self.setWarp(newWarp);
|
|
15654
|
-
};
|
|
15655
|
-
self.setProgress = function (percent, totalTime) {
|
|
15656
|
-
self.percent = percent;
|
|
15657
|
-
if (self.control) self.control.setProgress(percent, totalTime);
|
|
15658
|
-
};
|
|
15659
|
-
self.finished = function () {
|
|
15660
|
-
self.timer.reset();
|
|
15661
|
-
if (self.isLooping) {
|
|
15662
|
-
self.timer.start(0);
|
|
15663
|
-
self.midiBuffer.finished();
|
|
15664
|
-
self.midiBuffer.start();
|
|
15665
|
-
return "continue";
|
|
15666
|
-
} else {
|
|
15667
|
-
self.timer.stop();
|
|
15668
|
-
if (self.isStarted) {
|
|
15669
|
-
if (self.control) self.control.pushPlay(false);
|
|
15670
|
-
self.isStarted = false;
|
|
15671
|
-
self.midiBuffer.finished();
|
|
15672
|
-
if (self.cursorControl && self.cursorControl.onFinished && typeof self.cursorControl.onFinished === 'function') self.cursorControl.onFinished();
|
|
15673
|
-
self.setProgress(0, 1);
|
|
15607
|
+
self.seek(startPercent);
|
|
15608
|
+
return Promise.resolve();
|
|
15609
|
+
});
|
|
15610
|
+
}
|
|
15611
|
+
return Promise.resolve();
|
|
15612
|
+
};
|
|
15613
|
+
self.onWarp = function (ev) {
|
|
15614
|
+
var newWarp = ev.target.value;
|
|
15615
|
+
return self.setWarp(newWarp);
|
|
15616
|
+
};
|
|
15617
|
+
self.setProgress = function (percent, totalTime) {
|
|
15618
|
+
self.percent = percent;
|
|
15619
|
+
if (self.control) self.control.setProgress(percent, totalTime);
|
|
15620
|
+
};
|
|
15621
|
+
self.finished = function () {
|
|
15622
|
+
self.timer.reset();
|
|
15623
|
+
if (self.isLooping) {
|
|
15624
|
+
self.timer.start(0);
|
|
15625
|
+
self.midiBuffer.finished();
|
|
15626
|
+
self.midiBuffer.start();
|
|
15627
|
+
return "continue";
|
|
15628
|
+
} else {
|
|
15629
|
+
self.timer.stop();
|
|
15630
|
+
if (self.isStarted) {
|
|
15631
|
+
if (self.control) self.control.pushPlay(false);
|
|
15632
|
+
self.isStarted = false;
|
|
15633
|
+
self.midiBuffer.finished();
|
|
15634
|
+
if (self.cursorControl && self.cursorControl.onFinished && typeof self.cursorControl.onFinished === 'function') self.cursorControl.onFinished();
|
|
15635
|
+
self.setProgress(0, 1);
|
|
15636
|
+
}
|
|
15637
|
+
}
|
|
15638
|
+
};
|
|
15639
|
+
self.beatCallback = function (beatNumber, totalBeats, totalTime, position) {
|
|
15640
|
+
var percent = beatNumber / totalBeats;
|
|
15641
|
+
self.setProgress(percent, totalTime);
|
|
15642
|
+
if (self.cursorControl && self.cursorControl.onBeat && typeof self.cursorControl.onBeat === 'function') self.cursorControl.onBeat(beatNumber, totalBeats, totalTime, position);
|
|
15643
|
+
};
|
|
15644
|
+
self.eventCallback = function (event) {
|
|
15645
|
+
if (event) {
|
|
15646
|
+
if (self.cursorControl && self.cursorControl.onEvent && typeof self.cursorControl.onEvent === 'function') self.cursorControl.onEvent(event);
|
|
15647
|
+
} else {
|
|
15648
|
+
return self.finished();
|
|
15649
|
+
}
|
|
15650
|
+
};
|
|
15651
|
+
self.lineEndCallback = function (lineEvent, leftEvent) {
|
|
15652
|
+
if (self.cursorControl && self.cursorControl.onLineEnd && typeof self.cursorControl.onLineEnd === 'function') self.cursorControl.onLineEnd(lineEvent, leftEvent);
|
|
15653
|
+
};
|
|
15654
|
+
self.getUrl = function () {
|
|
15655
|
+
return self.midiBuffer.download();
|
|
15656
|
+
};
|
|
15657
|
+
self.download = function (fileName) {
|
|
15658
|
+
var url = self.getUrl();
|
|
15659
|
+
var link = document.createElement('a');
|
|
15660
|
+
document.body.appendChild(link);
|
|
15661
|
+
link.setAttribute("style", "display: none;");
|
|
15662
|
+
link.href = url;
|
|
15663
|
+
link.download = fileName ? fileName : 'output.wav';
|
|
15664
|
+
link.click();
|
|
15665
|
+
window.URL.revokeObjectURL(url);
|
|
15666
|
+
document.body.removeChild(link);
|
|
15667
|
+
};
|
|
15668
|
+
}
|
|
15669
|
+
module.exports = SynthController;
|
|
15670
|
+
|
|
15671
|
+
/***/ }),
|
|
15672
|
+
|
|
15673
|
+
/***/ "./src/synth/synth-sequence.js":
|
|
15674
|
+
/*!*************************************!*\
|
|
15675
|
+
!*** ./src/synth/synth-sequence.js ***!
|
|
15676
|
+
\*************************************/
|
|
15677
|
+
/***/ (function(module) {
|
|
15678
|
+
|
|
15679
|
+
var SynthSequence = function SynthSequence() {
|
|
15680
|
+
var self = this;
|
|
15681
|
+
self.tracks = [];
|
|
15682
|
+
self.totalDuration = 0;
|
|
15683
|
+
self.currentInstrument = [];
|
|
15684
|
+
self.starts = [];
|
|
15685
|
+
self.addTrack = function () {
|
|
15686
|
+
self.tracks.push([]);
|
|
15687
|
+
self.currentInstrument.push(0);
|
|
15688
|
+
self.starts.push(0);
|
|
15689
|
+
return self.tracks.length - 1;
|
|
15690
|
+
};
|
|
15691
|
+
self.setInstrument = function (trackNumber, instrumentNumber) {
|
|
15692
|
+
self.tracks[trackNumber].push({
|
|
15693
|
+
channel: 0,
|
|
15694
|
+
cmd: "program",
|
|
15695
|
+
instrument: instrumentNumber
|
|
15696
|
+
});
|
|
15697
|
+
self.currentInstrument[trackNumber] = instrumentNumber;
|
|
15698
|
+
};
|
|
15699
|
+
self.appendNote = function (trackNumber, pitch, durationInMeasures, volume, cents) {
|
|
15700
|
+
var note = {
|
|
15701
|
+
cmd: "note",
|
|
15702
|
+
duration: durationInMeasures,
|
|
15703
|
+
gap: 0,
|
|
15704
|
+
instrument: self.currentInstrument[trackNumber],
|
|
15705
|
+
pitch: pitch,
|
|
15706
|
+
start: self.starts[trackNumber],
|
|
15707
|
+
volume: volume
|
|
15708
|
+
};
|
|
15709
|
+
if (cents) note.cents = cents;
|
|
15710
|
+
self.tracks[trackNumber].push(note);
|
|
15711
|
+
self.starts[trackNumber] += durationInMeasures;
|
|
15712
|
+
self.totalDuration = Math.max(self.totalDuration, self.starts[trackNumber]);
|
|
15713
|
+
};
|
|
15714
|
+
};
|
|
15715
|
+
module.exports = SynthSequence;
|
|
15716
|
+
|
|
15717
|
+
/***/ }),
|
|
15718
|
+
|
|
15719
|
+
/***/ "./src/tablatures/abc_tablatures.js":
|
|
15720
|
+
/*!******************************************!*\
|
|
15721
|
+
!*** ./src/tablatures/abc_tablatures.js ***!
|
|
15722
|
+
\******************************************/
|
|
15723
|
+
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
15724
|
+
|
|
15725
|
+
/*
|
|
15726
|
+
* Tablature Plugins
|
|
15727
|
+
* tablature are defined dynamically and registered inside abcjs
|
|
15728
|
+
* by calling abcTablatures.register(plugin)
|
|
15729
|
+
* where plugin represents a plugin instance
|
|
15730
|
+
*
|
|
15731
|
+
*/
|
|
15732
|
+
|
|
15733
|
+
// This is the only entry point to the tablatures. It is called both after parsing a tune and just before engraving
|
|
15734
|
+
|
|
15735
|
+
var TabString = __webpack_require__(/*! ./instruments/tab-string */ "./src/tablatures/instruments/tab-string.js");
|
|
15736
|
+
|
|
15737
|
+
/* extend the table below when adding a new instrument plugin */
|
|
15738
|
+
|
|
15739
|
+
// Existing tab classes
|
|
15740
|
+
var pluginTab = {
|
|
15741
|
+
'violin': {
|
|
15742
|
+
name: 'StringTab',
|
|
15743
|
+
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
15744
|
+
isTabBig: false,
|
|
15745
|
+
tabSymbolOffset: 0
|
|
15746
|
+
},
|
|
15747
|
+
'fiddle': {
|
|
15748
|
+
name: 'StringTab',
|
|
15749
|
+
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
15750
|
+
isTabBig: false,
|
|
15751
|
+
tabSymbolOffset: 0
|
|
15752
|
+
},
|
|
15753
|
+
'mandolin': {
|
|
15754
|
+
name: 'StringTab',
|
|
15755
|
+
defaultTuning: ['G,', 'D', 'A', 'e'],
|
|
15756
|
+
isTabBig: false,
|
|
15757
|
+
tabSymbolOffset: 0
|
|
15758
|
+
},
|
|
15759
|
+
'guitar': {
|
|
15760
|
+
name: 'StringTab',
|
|
15761
|
+
defaultTuning: ['E,', 'A,', 'D', 'G', 'B', 'e'],
|
|
15762
|
+
isTabBig: true,
|
|
15763
|
+
tabSymbolOffset: 0
|
|
15764
|
+
},
|
|
15765
|
+
'fiveString': {
|
|
15766
|
+
name: 'StringTab',
|
|
15767
|
+
defaultTuning: ['C,', 'G,', 'D', 'A', 'e'],
|
|
15768
|
+
isTabBig: false,
|
|
15769
|
+
tabSymbolOffset: -.95
|
|
15770
|
+
}
|
|
15771
|
+
};
|
|
15772
|
+
var abcTablatures = {
|
|
15773
|
+
inited: false,
|
|
15774
|
+
plugins: {},
|
|
15775
|
+
/**
|
|
15776
|
+
* to be called once per plugin for registration
|
|
15777
|
+
* @param {*} plugin
|
|
15778
|
+
*/
|
|
15779
|
+
register: function register(plugin) {
|
|
15780
|
+
var name = plugin.name;
|
|
15781
|
+
var tablature = plugin.tablature;
|
|
15782
|
+
this.plugins[name] = tablature;
|
|
15783
|
+
},
|
|
15784
|
+
setError: function setError(tune, msg) {
|
|
15785
|
+
if (tune.warnings) {
|
|
15786
|
+
tune.warning.push(msg);
|
|
15787
|
+
} else {
|
|
15788
|
+
tune.warnings = [msg];
|
|
15789
|
+
}
|
|
15790
|
+
},
|
|
15791
|
+
/**
|
|
15792
|
+
* handle params for current processed score
|
|
15793
|
+
* @param {*} tune current tune
|
|
15794
|
+
* @param {*} tuneNumber number in tune list
|
|
15795
|
+
* @param {*} params params to be processed for tablature
|
|
15796
|
+
* @return prepared tablatures plugin instances for current tune
|
|
15797
|
+
*/
|
|
15798
|
+
preparePlugins: function preparePlugins(tune, tuneNumber, params) {
|
|
15799
|
+
// Called after parsing a tune and before engraving it
|
|
15800
|
+
if (!this.inited) {
|
|
15801
|
+
// TODO-PER: I don't think this is needed - the plugin array can be hard coded, right?
|
|
15802
|
+
this.register(new TabString());
|
|
15803
|
+
this.inited = true;
|
|
15804
|
+
}
|
|
15805
|
+
var returned = null;
|
|
15806
|
+
var nbPlugins = 0;
|
|
15807
|
+
if (params.tablature) {
|
|
15808
|
+
// validate requested plugins
|
|
15809
|
+
var tabs = params.tablature;
|
|
15810
|
+
returned = [];
|
|
15811
|
+
for (var ii = 0; ii < tabs.length; ii++) {
|
|
15812
|
+
var args = tabs[ii];
|
|
15813
|
+
var instrument = args['instrument'];
|
|
15814
|
+
if (instrument == null) {
|
|
15815
|
+
this.setError(tune, "tablature 'instrument' is missing");
|
|
15816
|
+
return returned;
|
|
15817
|
+
}
|
|
15818
|
+
var tabName = pluginTab[instrument];
|
|
15819
|
+
var plugin = null;
|
|
15820
|
+
if (tabName) {
|
|
15821
|
+
plugin = this.plugins[tabName.name];
|
|
15822
|
+
}
|
|
15823
|
+
if (plugin) {
|
|
15824
|
+
if (params.visualTranspose != 0) {
|
|
15825
|
+
// populate transposition request to tabs
|
|
15826
|
+
args.visualTranspose = params.visualTranspose;
|
|
15827
|
+
}
|
|
15828
|
+
args.abcSrc = params.tablature.abcSrc;
|
|
15829
|
+
var pluginInstance = {
|
|
15830
|
+
classz: plugin,
|
|
15831
|
+
tuneNumber: tuneNumber,
|
|
15832
|
+
params: args,
|
|
15833
|
+
instance: null,
|
|
15834
|
+
tabType: tabName
|
|
15835
|
+
};
|
|
15836
|
+
// proceed with tab plugin init
|
|
15837
|
+
// plugin.init(tune, tuneNumber, args, ii);
|
|
15838
|
+
returned.push(pluginInstance);
|
|
15839
|
+
nbPlugins++;
|
|
15840
|
+
} else if (instrument === '') {
|
|
15841
|
+
// create a placeholder - there is no tab for this staff
|
|
15842
|
+
returned.push(null);
|
|
15843
|
+
} else {
|
|
15844
|
+
// unknown tab plugin
|
|
15845
|
+
//this.emit_error('Undefined tablature plugin: ' + tabName)
|
|
15846
|
+
this.setError(tune, 'Undefined tablature plugin: ' + instrument);
|
|
15847
|
+
return returned;
|
|
15848
|
+
}
|
|
15674
15849
|
}
|
|
15675
15850
|
}
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
|
|
15683
|
-
|
|
15684
|
-
|
|
15685
|
-
} else {
|
|
15686
|
-
return self.finished();
|
|
15687
|
-
}
|
|
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;
|
|
15851
|
+
return returned;
|
|
15852
|
+
},
|
|
15853
|
+
/**
|
|
15854
|
+
* Call requested plugin
|
|
15855
|
+
* @param {*} renderer
|
|
15856
|
+
* @param {*} abcTune
|
|
15857
|
+
*/
|
|
15858
|
+
layoutTablatures: function layoutTablatures(renderer, abcTune) {
|
|
15859
|
+
var tabs = abcTune.tablatures;
|
|
15708
15860
|
|
|
15709
|
-
|
|
15861
|
+
// chack tabs request for each staffs
|
|
15862
|
+
var staffLineCount = 0;
|
|
15710
15863
|
|
|
15711
|
-
|
|
15712
|
-
|
|
15713
|
-
|
|
15714
|
-
|
|
15715
|
-
|
|
15864
|
+
// Clear the suppression flag
|
|
15865
|
+
if (tabs && tabs.length > 0) {
|
|
15866
|
+
var nTabs = tabs.length;
|
|
15867
|
+
for (var kk = 0; kk < nTabs; ++kk) {
|
|
15868
|
+
if (tabs[kk] && tabs[kk].params.firstStaffOnly) {
|
|
15869
|
+
tabs[kk].params.suppress = false;
|
|
15870
|
+
}
|
|
15871
|
+
}
|
|
15872
|
+
}
|
|
15873
|
+
for (var ii = 0; ii < abcTune.lines.length; ii++) {
|
|
15874
|
+
var line = abcTune.lines[ii];
|
|
15875
|
+
if (line.staff) {
|
|
15876
|
+
staffLineCount++;
|
|
15877
|
+
}
|
|
15716
15878
|
|
|
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
|
-
}
|
|
15879
|
+
// MAE 27Nov2023
|
|
15880
|
+
// If tab param "firstStaffOnly", remove the tab label after the first staff
|
|
15881
|
+
if (staffLineCount > 1) {
|
|
15882
|
+
if (tabs && tabs.length > 0) {
|
|
15883
|
+
var nTabs = tabs.length;
|
|
15884
|
+
for (var kk = 0; kk < nTabs; ++kk) {
|
|
15885
|
+
if (tabs[kk].params.firstStaffOnly) {
|
|
15886
|
+
// Set the staff draw suppression flag
|
|
15887
|
+
tabs[kk].params.suppress = true;
|
|
15888
|
+
}
|
|
15889
|
+
}
|
|
15890
|
+
}
|
|
15891
|
+
}
|
|
15892
|
+
var curStaff = line.staff;
|
|
15893
|
+
if (curStaff) {
|
|
15894
|
+
var maxStaves = curStaff.length;
|
|
15895
|
+
for (var jj = 0; jj < curStaff.length; jj++) {
|
|
15896
|
+
if (tabs[jj] && jj < maxStaves) {
|
|
15897
|
+
// tablature requested for staff
|
|
15898
|
+
var tabPlugin = tabs[jj];
|
|
15899
|
+
if (tabPlugin.instance == null) {
|
|
15900
|
+
//console.log("★★★★ Tab Init line: " + ii + " staff: " + jj)
|
|
15901
|
+
tabPlugin.instance = new tabPlugin.classz();
|
|
15902
|
+
// plugin.init(tune, tuneNumber, args, ii);
|
|
15903
|
+
// call initer first
|
|
15904
|
+
tabPlugin.instance.init(abcTune, tabPlugin.tuneNumber, tabPlugin.params, tabPlugin.tabType);
|
|
15905
|
+
}
|
|
15906
|
+
// render next
|
|
15907
|
+
//console.log("★★★★ Tab Render line: " + ii + " staff: " + jj)
|
|
15908
|
+
tabPlugin.instance.render(renderer, line, jj);
|
|
15909
|
+
}
|
|
15910
|
+
}
|
|
15911
|
+
}
|
|
15912
|
+
}
|
|
15913
|
+
}
|
|
15752
15914
|
};
|
|
15753
|
-
module.exports =
|
|
15915
|
+
module.exports = abcTablatures;
|
|
15754
15916
|
|
|
15755
15917
|
/***/ }),
|
|
15756
15918
|
|
|
@@ -15763,14 +15925,14 @@ module.exports = SynthSequence;
|
|
|
15763
15925
|
var _require = __webpack_require__(/*! ../../synth/note-to-midi */ "./src/synth/note-to-midi.js"),
|
|
15764
15926
|
noteToMidi = _require.noteToMidi;
|
|
15765
15927
|
var TabNote = __webpack_require__(/*! ./tab-note */ "./src/tablatures/instruments/tab-note.js");
|
|
15766
|
-
var
|
|
15928
|
+
var tabNotes = __webpack_require__(/*! ./tab-notes */ "./src/tablatures/instruments/tab-notes.js");
|
|
15767
15929
|
function buildCapo(self) {
|
|
15768
15930
|
var capoTuning = null;
|
|
15769
15931
|
var tuning = self.tuning;
|
|
15770
15932
|
if (self.capo > 0) {
|
|
15771
15933
|
capoTuning = [];
|
|
15772
15934
|
for (var iii = 0; iii < tuning.length; iii++) {
|
|
15773
|
-
var curNote = new TabNote
|
|
15935
|
+
var curNote = new TabNote(tuning[iii]);
|
|
15774
15936
|
for (var jjj = 0; jjj < self.capo; jjj++) {
|
|
15775
15937
|
curNote = curNote.nextNote();
|
|
15776
15938
|
}
|
|
@@ -15791,8 +15953,7 @@ function buildPatterns(self) {
|
|
|
15791
15953
|
if (iii != tuning.length - 1) {
|
|
15792
15954
|
nextNote = tuning[iii + 1];
|
|
15793
15955
|
}
|
|
15794
|
-
var
|
|
15795
|
-
var stringNotes = tabNotes.build();
|
|
15956
|
+
var stringNotes = tabNotes(tuning[iii], nextNote);
|
|
15796
15957
|
if (stringNotes.error) {
|
|
15797
15958
|
return stringNotes;
|
|
15798
15959
|
}
|
|
@@ -15841,7 +16002,7 @@ function handleChordNotes(self, notes) {
|
|
|
15841
16002
|
var retNotes = [];
|
|
15842
16003
|
for (var iiii = 0; iiii < notes.length; iiii++) {
|
|
15843
16004
|
if (notes[iiii].endTie) continue;
|
|
15844
|
-
var note = new TabNote
|
|
16005
|
+
var note = new TabNote(notes[iiii].name, self.clefTranspose);
|
|
15845
16006
|
note.checkKeyAccidentals(self.accidentals, self.measureAccidentals);
|
|
15846
16007
|
var curPos = toNumber(self, note);
|
|
15847
16008
|
retNotes.push(curPos);
|
|
@@ -15933,7 +16094,7 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
15933
16094
|
}
|
|
15934
16095
|
} else {
|
|
15935
16096
|
if (!notes[0].endTie) {
|
|
15936
|
-
note = new TabNote
|
|
16097
|
+
note = new TabNote(notes[0].name, this.clefTranspose);
|
|
15937
16098
|
note.checkKeyAccidentals(this.accidentals, this.measureAccidentals);
|
|
15938
16099
|
number = toNumber(this, note);
|
|
15939
16100
|
if (number) {
|
|
@@ -15950,7 +16111,7 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
15950
16111
|
if (graces) {
|
|
15951
16112
|
retGraces = [];
|
|
15952
16113
|
for (var iiii = 0; iiii < graces.length; iiii++) {
|
|
15953
|
-
note = new TabNote
|
|
16114
|
+
note = new TabNote(graces[iiii].name, this.clefTranspose);
|
|
15954
16115
|
note.checkKeyAccidentals(this.accidentals, this.measureAccidentals);
|
|
15955
16116
|
number = toNumber(this, note);
|
|
15956
16117
|
if (number) {
|
|
@@ -15977,8 +16138,7 @@ StringPatterns.prototype.toString = function () {
|
|
|
15977
16138
|
return arr.join('');
|
|
15978
16139
|
};
|
|
15979
16140
|
StringPatterns.prototype.tabInfos = function (plugin) {
|
|
15980
|
-
var
|
|
15981
|
-
var name = _super.params.label;
|
|
16141
|
+
var name = plugin.params.label;
|
|
15982
16142
|
if (name) {
|
|
15983
16143
|
var tunePos = name.indexOf('%T');
|
|
15984
16144
|
var tuning = "";
|
|
@@ -15996,8 +16156,7 @@ StringPatterns.prototype.tabInfos = function (plugin) {
|
|
|
15996
16156
|
|
|
15997
16157
|
// MAE 27 Nov 2023
|
|
15998
16158
|
StringPatterns.prototype.suppress = function (plugin) {
|
|
15999
|
-
var
|
|
16000
|
-
var suppress = _super.params.suppress;
|
|
16159
|
+
var suppress = plugin.params.suppress;
|
|
16001
16160
|
if (suppress) {
|
|
16002
16161
|
return true;
|
|
16003
16162
|
}
|
|
@@ -16013,9 +16172,10 @@ StringPatterns.prototype.suppress = function (plugin) {
|
|
|
16013
16172
|
* @param {*} highestNote
|
|
16014
16173
|
*/
|
|
16015
16174
|
function StringPatterns(plugin) {
|
|
16175
|
+
//console.log("INIT StringPatterns constructor")
|
|
16016
16176
|
var tuning = plugin.tuning;
|
|
16017
16177
|
var capo = plugin.capo;
|
|
16018
|
-
var highestNote = plugin.
|
|
16178
|
+
var highestNote = plugin.params.highestNote;
|
|
16019
16179
|
this.linePitch = plugin.linePitch;
|
|
16020
16180
|
this.highestNote = "a'";
|
|
16021
16181
|
if (highestNote) {
|
|
@@ -16039,7 +16199,7 @@ function StringPatterns(plugin) {
|
|
|
16039
16199
|
}
|
|
16040
16200
|
this.strings = buildPatterns(this);
|
|
16041
16201
|
if (this.strings.error) {
|
|
16042
|
-
plugin.
|
|
16202
|
+
plugin.setError(this.strings.error);
|
|
16043
16203
|
plugin.inError = true;
|
|
16044
16204
|
return;
|
|
16045
16205
|
}
|
|
@@ -16063,6 +16223,7 @@ module.exports = StringPatterns;
|
|
|
16063
16223
|
*/
|
|
16064
16224
|
|
|
16065
16225
|
function StringTablature(numLines, lineSpace) {
|
|
16226
|
+
//console.log("INIT StringTablature constructor")
|
|
16066
16227
|
this.numLines = numLines;
|
|
16067
16228
|
this.lineSpace = lineSpace;
|
|
16068
16229
|
this.verticalSize = this.numLines * this.lineSpace;
|
|
@@ -16079,6 +16240,7 @@ function StringTablature(numLines, lineSpace) {
|
|
|
16079
16240
|
* @param {} line
|
|
16080
16241
|
*/
|
|
16081
16242
|
StringTablature.prototype.bypass = function (line) {
|
|
16243
|
+
//console.log("RENDER StringTablature bypass")
|
|
16082
16244
|
var voices = line.staffGroup.voices;
|
|
16083
16245
|
if (voices.length > 0) {
|
|
16084
16246
|
if (voices[0].isPercussion) return true;
|
|
@@ -16086,6 +16248,7 @@ StringTablature.prototype.bypass = function (line) {
|
|
|
16086
16248
|
return false;
|
|
16087
16249
|
};
|
|
16088
16250
|
StringTablature.prototype.setRelative = function (child, relative, first) {
|
|
16251
|
+
//console.log("RENDER StringTablature setRelative")
|
|
16089
16252
|
switch (child.type) {
|
|
16090
16253
|
case 'bar':
|
|
16091
16254
|
relative.pitch = this.bar.pitch;
|
|
@@ -16126,8 +16289,9 @@ var _require = __webpack_require__(/*! ../../synth/note-to-midi */ "./src/synth/
|
|
|
16126
16289
|
* Note structure for Tabs
|
|
16127
16290
|
*
|
|
16128
16291
|
*/
|
|
16129
|
-
|
|
16292
|
+
|
|
16130
16293
|
function TabNote(note, clefTranspose) {
|
|
16294
|
+
//console.log("INIT/RENDER TabNote constructor")
|
|
16131
16295
|
var pitch = noteToMidi(note);
|
|
16132
16296
|
if (clefTranspose) pitch += clefTranspose;
|
|
16133
16297
|
var newNote = midiToNote(pitch);
|
|
@@ -16209,12 +16373,15 @@ function cloneNote(self) {
|
|
|
16209
16373
|
return newTabNote;
|
|
16210
16374
|
}
|
|
16211
16375
|
TabNote.prototype.sameNoteAs = function (note) {
|
|
16376
|
+
//console.log("INIT TabNote sameNoteAs")
|
|
16212
16377
|
return note.pitch === this.pitch;
|
|
16213
16378
|
};
|
|
16214
16379
|
TabNote.prototype.isLowerThan = function (note) {
|
|
16380
|
+
//console.log("INIT TabNote isLowerThan")
|
|
16215
16381
|
return note.pitch > this.pitch;
|
|
16216
16382
|
};
|
|
16217
16383
|
TabNote.prototype.checkKeyAccidentals = function (accidentals, measureAccidentals) {
|
|
16384
|
+
//console.log("RENDER TabNote checkKeyAccidentals")
|
|
16218
16385
|
if (this.isAltered || this.natural) return;
|
|
16219
16386
|
if (measureAccidentals[this.name.toUpperCase()]) {
|
|
16220
16387
|
switch (measureAccidentals[this.name.toUpperCase()]) {
|
|
@@ -16259,6 +16426,7 @@ TabNote.prototype.checkKeyAccidentals = function (accidentals, measureAccidental
|
|
|
16259
16426
|
}
|
|
16260
16427
|
};
|
|
16261
16428
|
TabNote.prototype.getAccidentalEquiv = function () {
|
|
16429
|
+
//console.log("TabNote getAccidentalEquiv")
|
|
16262
16430
|
var cloned = cloneNote(this);
|
|
16263
16431
|
if (cloned.isSharp || cloned.isKeySharp) {
|
|
16264
16432
|
cloned = cloned.nextNote();
|
|
@@ -16274,14 +16442,17 @@ TabNote.prototype.getAccidentalEquiv = function () {
|
|
|
16274
16442
|
return cloned;
|
|
16275
16443
|
};
|
|
16276
16444
|
TabNote.prototype.nextNote = function () {
|
|
16445
|
+
//console.log("INIT TabNote nextNote")
|
|
16277
16446
|
var note = midiToNote(this.pitch + 1 + this.pitchAltered);
|
|
16278
16447
|
return new TabNote(note);
|
|
16279
16448
|
};
|
|
16280
16449
|
TabNote.prototype.prevNote = function () {
|
|
16450
|
+
//console.log("TabNote prevNote")
|
|
16281
16451
|
var note = midiToNote(this.pitch - 1 + this.pitchAltered);
|
|
16282
16452
|
return new TabNote(note);
|
|
16283
16453
|
};
|
|
16284
16454
|
TabNote.prototype.emitNoAccidentals = function () {
|
|
16455
|
+
//console.log("TabNote emitNoAccidentals")
|
|
16285
16456
|
var returned = this.name;
|
|
16286
16457
|
if (this.isLower) {
|
|
16287
16458
|
returned = returned.toLowerCase();
|
|
@@ -16295,6 +16466,7 @@ TabNote.prototype.emitNoAccidentals = function () {
|
|
|
16295
16466
|
return returned;
|
|
16296
16467
|
};
|
|
16297
16468
|
TabNote.prototype.emit = function () {
|
|
16469
|
+
//console.log("INIT/RENDER TabNote emit")
|
|
16298
16470
|
var returned = this.name;
|
|
16299
16471
|
if (this.isSharp || this.isKeySharp) {
|
|
16300
16472
|
returned = '^' + returned;
|
|
@@ -16329,10 +16501,7 @@ TabNote.prototype.emit = function () {
|
|
|
16329
16501
|
}
|
|
16330
16502
|
return returned;
|
|
16331
16503
|
};
|
|
16332
|
-
module.exports =
|
|
16333
|
-
'TabNote': TabNote,
|
|
16334
|
-
'notes': notes
|
|
16335
|
-
};
|
|
16504
|
+
module.exports = TabNote;
|
|
16336
16505
|
|
|
16337
16506
|
/***/ }),
|
|
16338
16507
|
|
|
@@ -16343,14 +16512,11 @@ module.exports = {
|
|
|
16343
16512
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16344
16513
|
|
|
16345
16514
|
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;
|
|
16515
|
+
var notes = ['A', 'B', 'C', 'D', 'E', 'F', 'G'];
|
|
16516
|
+
function tabNotes(fromNote, toNote) {
|
|
16517
|
+
//console.log("INIT TabNotes")
|
|
16518
|
+
var fromN = new TabNote(fromNote);
|
|
16519
|
+
var toN = new TabNote(toNote);
|
|
16354
16520
|
// check that toN is not lower than fromN
|
|
16355
16521
|
if (toN.isLowerThan(fromN)) {
|
|
16356
16522
|
var from = fromN.emit();
|
|
@@ -16374,35 +16540,8 @@ TabNotes.prototype.build = function () {
|
|
|
16374
16540
|
}
|
|
16375
16541
|
}
|
|
16376
16542
|
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
16543
|
}
|
|
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;
|
|
16544
|
+
module.exports = tabNotes;
|
|
16406
16545
|
|
|
16407
16546
|
/***/ }),
|
|
16408
16547
|
|
|
@@ -16413,20 +16552,22 @@ module.exports = TabStringPatterns;
|
|
|
16413
16552
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16414
16553
|
|
|
16415
16554
|
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");
|
|
16555
|
+
var tabRenderer = __webpack_require__(/*! ../render/tab-renderer */ "./src/tablatures/render/tab-renderer.js");
|
|
16556
|
+
var StringPatterns = __webpack_require__(/*! ./string-patterns */ "./src/tablatures/instruments/string-patterns.js");
|
|
16419
16557
|
|
|
16420
16558
|
/**
|
|
16421
16559
|
* upon init mainly store provided instances for later usage
|
|
16422
16560
|
* @param {*} abcTune the parsed tune AST tree
|
|
16423
|
-
*
|
|
16561
|
+
* @param {*} tuneNumber the parsed tune AST tree
|
|
16424
16562
|
* @param {*} params complementary args provided to Tablature Plugin
|
|
16425
16563
|
*/
|
|
16426
|
-
Plugin.prototype.init = function (abcTune, tuneNumber, params,
|
|
16427
|
-
|
|
16564
|
+
Plugin.prototype.init = function (abcTune, tuneNumber, params, tabSettings) {
|
|
16565
|
+
//console.log("INIT AbcStringTab Plugin.init")
|
|
16566
|
+
this.tune = abcTune;
|
|
16567
|
+
this.params = params;
|
|
16568
|
+
this.tuneNumber = tuneNumber;
|
|
16569
|
+
this.inError = false;
|
|
16428
16570
|
this.abcTune = abcTune;
|
|
16429
|
-
this._super = _super;
|
|
16430
16571
|
this.linePitch = 3;
|
|
16431
16572
|
this.nbLines = tabSettings.defaultTuning.length;
|
|
16432
16573
|
this.isTabBig = tabSettings.isTabBig;
|
|
@@ -16435,14 +16576,30 @@ Plugin.prototype.init = function (abcTune, tuneNumber, params, staffNumber, tabS
|
|
|
16435
16576
|
this.transpose = params.visualTranspose;
|
|
16436
16577
|
this.hideTabSymbol = params.hideTabSymbol;
|
|
16437
16578
|
this.tablature = new StringTablature(this.nbLines, this.linePitch);
|
|
16438
|
-
var
|
|
16439
|
-
|
|
16579
|
+
var tuning = params.tuning;
|
|
16580
|
+
if (!tuning) {
|
|
16581
|
+
tuning = tabSettings.defaultTuning;
|
|
16582
|
+
}
|
|
16583
|
+
this.tuning = tuning;
|
|
16584
|
+
this.semantics = new StringPatterns(this);
|
|
16585
|
+
};
|
|
16586
|
+
Plugin.prototype.setError = function (error) {
|
|
16587
|
+
//console.log("Plugin setError")
|
|
16588
|
+
if (error) {
|
|
16589
|
+
this.error = error;
|
|
16590
|
+
this.inError = true;
|
|
16591
|
+
if (this.tune.warnings) {
|
|
16592
|
+
this.tune.warnings.push(error);
|
|
16593
|
+
} else {
|
|
16594
|
+
this.tune.warnings = [error];
|
|
16595
|
+
}
|
|
16596
|
+
}
|
|
16440
16597
|
};
|
|
16441
16598
|
Plugin.prototype.render = function (renderer, line, staffIndex) {
|
|
16442
|
-
|
|
16599
|
+
//console.log("RENDER AbcStringTab Plugin.render")
|
|
16600
|
+
if (this.inError) return;
|
|
16443
16601
|
if (this.tablature.bypass(line)) return;
|
|
16444
|
-
|
|
16445
|
-
rndrer.doLayout();
|
|
16602
|
+
tabRenderer(this, renderer, line, staffIndex);
|
|
16446
16603
|
};
|
|
16447
16604
|
function Plugin() {}
|
|
16448
16605
|
|
|
@@ -16459,17 +16616,17 @@ module.exports = AbcStringTab;
|
|
|
16459
16616
|
|
|
16460
16617
|
/***/ }),
|
|
16461
16618
|
|
|
16462
|
-
/***/ "./src/tablatures/tab-absolute-elements.js":
|
|
16463
|
-
|
|
16464
|
-
!*** ./src/tablatures/tab-absolute-elements.js ***!
|
|
16465
|
-
|
|
16619
|
+
/***/ "./src/tablatures/render/tab-absolute-elements.js":
|
|
16620
|
+
/*!********************************************************!*\
|
|
16621
|
+
!*** ./src/tablatures/render/tab-absolute-elements.js ***!
|
|
16622
|
+
\********************************************************/
|
|
16466
16623
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16467
16624
|
|
|
16468
16625
|
/**
|
|
16469
16626
|
* Tablature Absolute elements factory
|
|
16470
16627
|
*/
|
|
16471
|
-
var AbsoluteElement = __webpack_require__(/*!
|
|
16472
|
-
var RelativeElement = __webpack_require__(/*!
|
|
16628
|
+
var AbsoluteElement = __webpack_require__(/*! ../../write/creation/elements/absolute-element */ "./src/write/creation/elements/absolute-element.js");
|
|
16629
|
+
var RelativeElement = __webpack_require__(/*! ../../write/creation/elements/relative-element */ "./src/write/creation/elements/relative-element.js");
|
|
16473
16630
|
function isObject(a) {
|
|
16474
16631
|
return a != null && a.constructor === Object;
|
|
16475
16632
|
}
|
|
@@ -16556,6 +16713,7 @@ function lyricsDim(abs) {
|
|
|
16556
16713
|
return null;
|
|
16557
16714
|
}
|
|
16558
16715
|
function TabAbsoluteElements() {
|
|
16716
|
+
//console.log("RENDER TabAbsoluteElements constructor")
|
|
16559
16717
|
this.accidentals = null;
|
|
16560
16718
|
}
|
|
16561
16719
|
function getInitialStaffSize(staffGroup) {
|
|
@@ -16614,7 +16772,7 @@ function graceInRest(absElem) {
|
|
|
16614
16772
|
function convertToNumber(plugin, pitches, graceNotes) {
|
|
16615
16773
|
var tabPos = plugin.semantics.notesToNumber(pitches, graceNotes);
|
|
16616
16774
|
if (tabPos.error) {
|
|
16617
|
-
plugin.
|
|
16775
|
+
plugin.setError(tabPos.error);
|
|
16618
16776
|
return tabPos; // give up on error here
|
|
16619
16777
|
}
|
|
16620
16778
|
|
|
@@ -16647,6 +16805,7 @@ function buildGraceRelativesForRest(plugin, abs, absChild, graceNotes, tabVoice)
|
|
|
16647
16805
|
* @param {*} staffAbsolute
|
|
16648
16806
|
*/
|
|
16649
16807
|
TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice, voiceIndex, staffIndex, keySig, tabVoiceIndex) {
|
|
16808
|
+
//console.log("RENDER TabAbsoluteElements build")
|
|
16650
16809
|
var staffSize = getInitialStaffSize(staffAbsolute);
|
|
16651
16810
|
var source = staffAbsolute[staffIndex + voiceIndex];
|
|
16652
16811
|
var dest = staffAbsolute[tabVoiceIndex];
|
|
@@ -16667,17 +16826,17 @@ TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice,
|
|
|
16667
16826
|
// }
|
|
16668
16827
|
if (absChild.isClef) {
|
|
16669
16828
|
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.
|
|
16829
|
+
if (absChild.abcelem.type.indexOf('-8') >= 0) plugin.semantics.clefTranspose = -12;
|
|
16830
|
+
if (absChild.abcelem.type.indexOf('+8') >= 0) plugin.semantics.clefTranspose = 12;
|
|
16672
16831
|
}
|
|
16673
16832
|
switch (absChild.type) {
|
|
16674
16833
|
case 'staff-extra key-signature':
|
|
16675
16834
|
// refresh key accidentals
|
|
16676
16835
|
this.accidentals = absChild.abcelem.accidentals;
|
|
16677
|
-
plugin.semantics.
|
|
16836
|
+
plugin.semantics.accidentals = this.accidentals;
|
|
16678
16837
|
break;
|
|
16679
16838
|
case 'bar':
|
|
16680
|
-
plugin.semantics.
|
|
16839
|
+
plugin.semantics.measureAccidentals = {};
|
|
16681
16840
|
var lastBar = false;
|
|
16682
16841
|
if (ii === source.children.length - 1) {
|
|
16683
16842
|
// used for final line bar drawing
|
|
@@ -16777,50 +16936,16 @@ module.exports = TabAbsoluteElements;
|
|
|
16777
16936
|
|
|
16778
16937
|
/***/ }),
|
|
16779
16938
|
|
|
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
|
-
\****************************************/
|
|
16939
|
+
/***/ "./src/tablatures/render/tab-renderer.js":
|
|
16940
|
+
/*!***********************************************!*\
|
|
16941
|
+
!*** ./src/tablatures/render/tab-renderer.js ***!
|
|
16942
|
+
\***********************************************/
|
|
16818
16943
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16819
16944
|
|
|
16820
16945
|
/* 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__(/*!
|
|
16946
|
+
var VoiceElement = __webpack_require__(/*! ../../write/creation/elements/voice-element */ "./src/write/creation/elements/voice-element.js");
|
|
16947
|
+
var TabAbsoluteElements = __webpack_require__(/*! ./tab-absolute-elements */ "./src/tablatures/render/tab-absolute-elements.js");
|
|
16948
|
+
var spacing = __webpack_require__(/*! ../../write/helpers/spacing */ "./src/write/helpers/spacing.js");
|
|
16824
16949
|
function initSpecialY() {
|
|
16825
16950
|
return {
|
|
16826
16951
|
tempoHeightAbove: 0,
|
|
@@ -16849,12 +16974,11 @@ function getLyricHeight(voice) {
|
|
|
16849
16974
|
return maxLyricHeight; // add spacing
|
|
16850
16975
|
}
|
|
16851
16976
|
|
|
16852
|
-
function buildTabName(
|
|
16853
|
-
var stringSemantics =
|
|
16854
|
-
var
|
|
16855
|
-
var
|
|
16856
|
-
var
|
|
16857
|
-
var suppress = stringSemantics.suppress(self.plugin);
|
|
16977
|
+
function buildTabName(plugin, renderer, dest) {
|
|
16978
|
+
var stringSemantics = plugin.semantics;
|
|
16979
|
+
var textSize = renderer.controller.getTextSize;
|
|
16980
|
+
var tabName = stringSemantics.tabInfos(plugin);
|
|
16981
|
+
var suppress = stringSemantics.suppress(plugin);
|
|
16858
16982
|
var doDraw = true;
|
|
16859
16983
|
if (suppress) {
|
|
16860
16984
|
doDraw = false;
|
|
@@ -16872,27 +16996,6 @@ function buildTabName(self, dest) {
|
|
|
16872
16996
|
}
|
|
16873
16997
|
return 0;
|
|
16874
16998
|
}
|
|
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
16999
|
function islastTabInStaff(index, staffGroup) {
|
|
16897
17000
|
if (staffGroup[index].isTabStaff) {
|
|
16898
17001
|
if (index === staffGroup.length - 1) return true;
|
|
@@ -16938,8 +17041,7 @@ function isMultiVoiceSingleStaff(staffs, parent) {
|
|
|
16938
17041
|
}
|
|
16939
17042
|
return false;
|
|
16940
17043
|
}
|
|
16941
|
-
function getNextTabPos(
|
|
16942
|
-
var tabIndex = self.staffIndex;
|
|
17044
|
+
function getNextTabPos(tabIndex, staffGroup) {
|
|
16943
17045
|
var startIndex = 0;
|
|
16944
17046
|
var handledVoices = 0;
|
|
16945
17047
|
var inProgress = true;
|
|
@@ -16988,30 +17090,38 @@ function checkVoiceKeySig(voices, ii) {
|
|
|
16988
17090
|
}
|
|
16989
17091
|
return voices[ii - 1].children[0];
|
|
16990
17092
|
}
|
|
16991
|
-
|
|
16992
|
-
|
|
17093
|
+
function tabRenderer(plugin, renderer, line, staffIndex) {
|
|
17094
|
+
//console.log("RENDER tabRenderer")
|
|
17095
|
+
var absolutes = new TabAbsoluteElements();
|
|
17096
|
+
var tabStaff = {
|
|
17097
|
+
clef: {
|
|
17098
|
+
type: 'TAB'
|
|
17099
|
+
}
|
|
17100
|
+
};
|
|
17101
|
+
var tabSize = plugin.linePitch * plugin.nbLines;
|
|
17102
|
+
var staffs = line.staff;
|
|
16993
17103
|
if (staffs) {
|
|
16994
17104
|
// give up on staffline=0 in key
|
|
16995
17105
|
var firstStaff = staffs[0];
|
|
16996
17106
|
if (firstStaff) {
|
|
16997
17107
|
if (firstStaff.clef) {
|
|
16998
17108
|
if (firstStaff.clef.stafflines == 0) {
|
|
16999
|
-
|
|
17109
|
+
plugin.setError("No tablatures when stafflines=0");
|
|
17000
17110
|
return;
|
|
17001
17111
|
}
|
|
17002
17112
|
}
|
|
17003
17113
|
}
|
|
17004
|
-
staffs.splice(staffs.length, 0,
|
|
17114
|
+
staffs.splice(staffs.length, 0, tabStaff);
|
|
17005
17115
|
}
|
|
17006
|
-
var staffGroup =
|
|
17116
|
+
var staffGroup = line.staffGroup;
|
|
17007
17117
|
var voices = staffGroup.voices;
|
|
17008
17118
|
var firstVoice = voices[0];
|
|
17009
17119
|
// take lyrics into account if any
|
|
17010
17120
|
var lyricsHeight = getLyricHeight(firstVoice);
|
|
17011
17121
|
var padd = 3;
|
|
17012
|
-
var prevIndex =
|
|
17122
|
+
var prevIndex = staffIndex;
|
|
17013
17123
|
var previousStaff = staffGroup.staffs[prevIndex];
|
|
17014
|
-
var tabTop =
|
|
17124
|
+
var tabTop = tabSize + padd - previousStaff.bottom - lyricsHeight;
|
|
17015
17125
|
if (previousStaff.isTabStaff) {
|
|
17016
17126
|
tabTop = previousStaff.top;
|
|
17017
17127
|
}
|
|
@@ -17019,44 +17129,44 @@ TabRenderer.prototype.doLayout = function () {
|
|
|
17019
17129
|
bottom: -1,
|
|
17020
17130
|
isTabStaff: true,
|
|
17021
17131
|
specialY: initSpecialY(),
|
|
17022
|
-
lines:
|
|
17023
|
-
linePitch:
|
|
17132
|
+
lines: plugin.nbLines,
|
|
17133
|
+
linePitch: plugin.linePitch,
|
|
17024
17134
|
dy: 0.15,
|
|
17025
17135
|
top: tabTop
|
|
17026
17136
|
};
|
|
17027
|
-
var nextTabPos = getNextTabPos(
|
|
17137
|
+
var nextTabPos = getNextTabPos(staffIndex, staffGroup.staffs);
|
|
17028
17138
|
if (nextTabPos === -1) return;
|
|
17029
17139
|
staffGroupInfos.parentIndex = nextTabPos - 1;
|
|
17030
17140
|
staffGroup.staffs.splice(nextTabPos, 0, staffGroupInfos);
|
|
17031
17141
|
// staffGroup.staffs.push(staffGroupInfos);
|
|
17032
|
-
staffGroup.height +=
|
|
17142
|
+
staffGroup.height += tabSize + padd;
|
|
17033
17143
|
var parentStaff = getLastStaff(staffGroup.staffs, nextTabPos);
|
|
17034
17144
|
var nbVoices = 1;
|
|
17035
17145
|
if (isMultiVoiceSingleStaff(staffGroup.staffs, parentStaff)) {
|
|
17036
17146
|
nbVoices = parentStaff.voices.length;
|
|
17037
17147
|
}
|
|
17038
17148
|
// build from staff
|
|
17039
|
-
|
|
17149
|
+
tabStaff.voices = [];
|
|
17040
17150
|
for (var ii = 0; ii < nbVoices; ii++) {
|
|
17041
17151
|
var tabVoice = new VoiceElement(0, 0);
|
|
17042
17152
|
if (ii > 0) tabVoice.duplicate = true;
|
|
17043
|
-
var nameHeight = buildTabName(
|
|
17153
|
+
var nameHeight = buildTabName(plugin, renderer, tabVoice) / spacing.STEP;
|
|
17044
17154
|
nameHeight = Math.max(nameHeight, 1); // If there is no label for the tab line, then there needs to be a little padding
|
|
17045
17155
|
// This was pushing down the top staff by the tab label height
|
|
17046
|
-
//staffGroup.staffs[
|
|
17047
|
-
staffGroup.staffs[
|
|
17156
|
+
//staffGroup.staffs[staffIndex].top += nameHeight;
|
|
17157
|
+
staffGroup.staffs[staffIndex].top += 1;
|
|
17048
17158
|
staffGroup.height += nameHeight;
|
|
17049
17159
|
tabVoice.staff = staffGroupInfos;
|
|
17050
17160
|
var tabVoiceIndex = voices.length;
|
|
17051
17161
|
voices.splice(voices.length, 0, tabVoice);
|
|
17052
|
-
var keySig = checkVoiceKeySig(voices, ii +
|
|
17053
|
-
|
|
17054
|
-
|
|
17162
|
+
var keySig = checkVoiceKeySig(voices, ii + staffIndex);
|
|
17163
|
+
tabStaff.voices[ii] = [];
|
|
17164
|
+
absolutes.build(plugin, voices, tabStaff.voices[ii], ii, staffIndex, keySig, tabVoiceIndex);
|
|
17055
17165
|
}
|
|
17056
17166
|
linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
|
|
17057
|
-
}
|
|
17167
|
+
}
|
|
17058
17168
|
|
|
17059
|
-
module.exports =
|
|
17169
|
+
module.exports = tabRenderer;
|
|
17060
17170
|
|
|
17061
17171
|
/***/ }),
|
|
17062
17172
|
|
|
@@ -17990,7 +18100,7 @@ AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaf
|
|
|
17990
18100
|
if (elem.decoration) {
|
|
17991
18101
|
// 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
18102
|
// This should probably be combined with moveDecorations()
|
|
17993
|
-
var bottom = nostem ? Math.min(-3, abselem.bottom - 6) : abselem.bottom;
|
|
18103
|
+
var bottom = nostem && dir !== 'up' ? Math.min(-3, abselem.bottom - 6) : abselem.bottom;
|
|
17994
18104
|
this.decoration.createDecoration(voice, elem.decoration, abselem.top, notehead ? notehead.w : 0, abselem, roomtaken, dir, bottom, elem.positioning, this.hasVocals, this.accentAbove);
|
|
17995
18105
|
}
|
|
17996
18106
|
if (elem.barNumber) {
|
|
@@ -23519,7 +23629,7 @@ var Classes = __webpack_require__(/*! ./helpers/classes */ "./src/write/helpers/
|
|
|
23519
23629
|
var GetFontAndAttr = __webpack_require__(/*! ./helpers/get-font-and-attr */ "./src/write/helpers/get-font-and-attr.js");
|
|
23520
23630
|
var GetTextSize = __webpack_require__(/*! ./helpers/get-text-size */ "./src/write/helpers/get-text-size.js");
|
|
23521
23631
|
var draw = __webpack_require__(/*! ./draw/draw */ "./src/write/draw/draw.js");
|
|
23522
|
-
var tablatures = __webpack_require__(/*! ../
|
|
23632
|
+
var tablatures = __webpack_require__(/*! ../tablatures/abc_tablatures */ "./src/tablatures/abc_tablatures.js");
|
|
23523
23633
|
var findSelectableElement = __webpack_require__(/*! ./interactive/find-selectable-element */ "./src/write/interactive/find-selectable-element.js");
|
|
23524
23634
|
|
|
23525
23635
|
/**
|
|
@@ -26379,7 +26489,7 @@ module.exports = Svg;
|
|
|
26379
26489
|
\********************/
|
|
26380
26490
|
/***/ (function(module) {
|
|
26381
26491
|
|
|
26382
|
-
var version = '6.4.
|
|
26492
|
+
var version = '6.4.2';
|
|
26383
26493
|
module.exports = version;
|
|
26384
26494
|
|
|
26385
26495
|
/***/ })
|