abcjs 6.4.0 → 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 +42 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +1252 -1139
- 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 +86 -20
- package/src/synth/create-synth-control.js +1 -2
- package/src/synth/create-synth.js +1 -1
- 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 +9 -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]);
|
|
@@ -13577,8 +13524,8 @@ ChordTrack.prototype.resolveChords = function (startTime, endTime) {
|
|
|
13577
13524
|
if (p > 0 && currentChordsExpanded[p - 1] && currentChordsExpanded[p] && currentChordsExpanded[p - 1].boom !== currentChordsExpanded[p].boom) firstBoom = true;
|
|
13578
13525
|
var type = thisPattern[p];
|
|
13579
13526
|
var isBoom = type.indexOf('boom') >= 0;
|
|
13580
|
-
// If we changed chords at a time when we're not expecting a bass note, then add an extra bass note in.
|
|
13581
|
-
var newBass = !isBoom && p !== 0 && (!currentChordsExpanded[p - 1] || currentChordsExpanded[p - 1].boom !== currentChordsExpanded[p].boom);
|
|
13527
|
+
// If we changed chords at a time when we're not expecting a bass note, then add an extra bass note in if the first thing in the pattern is a bass note.
|
|
13528
|
+
var newBass = !isBoom && p !== 0 && thisPattern[0].indexOf('boom') >= 0 && (!currentChordsExpanded[p - 1] || currentChordsExpanded[p - 1].boom !== currentChordsExpanded[p].boom);
|
|
13582
13529
|
var pitches = resolvePitch(currentChordsExpanded[p], type, firstBoom, newBass);
|
|
13583
13530
|
if (isBoom) firstBoom = false;
|
|
13584
13531
|
for (var oo = 0; oo < pitches.length; oo++) {
|
|
@@ -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
|
|
@@ -14261,7 +14223,10 @@ function CreateSynth() {
|
|
|
14261
14223
|
self.sequenceCallback = params.sequenceCallback;
|
|
14262
14224
|
self.callbackContext = params.callbackContext;
|
|
14263
14225
|
self.onEnded = params.onEnded;
|
|
14264
|
-
self.meterFraction = options.visualObj.getMeterFraction()
|
|
14226
|
+
self.meterFraction = options.visualObj ? options.visualObj.getMeterFraction() : {
|
|
14227
|
+
den: 1
|
|
14228
|
+
}; // If we are given a sequence instead of a regular visual obj, then don't do the swing
|
|
14229
|
+
|
|
14265
14230
|
var allNotes = {};
|
|
14266
14231
|
var cached = [];
|
|
14267
14232
|
var errorNotes = [];
|
|
@@ -15639,115 +15604,315 @@ function SynthController() {
|
|
|
15639
15604
|
return Promise.resolve();
|
|
15640
15605
|
});
|
|
15641
15606
|
}
|
|
15642
|
-
self.seek(startPercent);
|
|
15643
|
-
return Promise.resolve();
|
|
15644
|
-
});
|
|
15645
|
-
}
|
|
15646
|
-
return Promise.resolve();
|
|
15647
|
-
};
|
|
15648
|
-
self.onWarp = function (ev) {
|
|
15649
|
-
var newWarp = ev.target.value;
|
|
15650
|
-
return self.setWarp(newWarp);
|
|
15651
|
-
};
|
|
15652
|
-
self.setProgress = function (percent, totalTime) {
|
|
15653
|
-
self.percent = percent;
|
|
15654
|
-
if (self.control) self.control.setProgress(percent, totalTime);
|
|
15655
|
-
};
|
|
15656
|
-
self.finished = function () {
|
|
15657
|
-
self.timer.reset();
|
|
15658
|
-
if (self.isLooping) {
|
|
15659
|
-
self.timer.start(0);
|
|
15660
|
-
self.midiBuffer.finished();
|
|
15661
|
-
self.midiBuffer.start();
|
|
15662
|
-
return "continue";
|
|
15663
|
-
} else {
|
|
15664
|
-
self.timer.stop();
|
|
15665
|
-
if (self.isStarted) {
|
|
15666
|
-
if (self.control) self.control.pushPlay(false);
|
|
15667
|
-
self.isStarted = false;
|
|
15668
|
-
self.midiBuffer.finished();
|
|
15669
|
-
if (self.cursorControl && self.cursorControl.onFinished && typeof self.cursorControl.onFinished === 'function') self.cursorControl.onFinished();
|
|
15670
|
-
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
|
+
}
|
|
15671
15849
|
}
|
|
15672
15850
|
}
|
|
15673
|
-
|
|
15674
|
-
|
|
15675
|
-
|
|
15676
|
-
|
|
15677
|
-
|
|
15678
|
-
|
|
15679
|
-
|
|
15680
|
-
|
|
15681
|
-
|
|
15682
|
-
} else {
|
|
15683
|
-
return self.finished();
|
|
15684
|
-
}
|
|
15685
|
-
};
|
|
15686
|
-
self.lineEndCallback = function (lineEvent, leftEvent) {
|
|
15687
|
-
if (self.cursorControl && self.cursorControl.onLineEnd && typeof self.cursorControl.onLineEnd === 'function') self.cursorControl.onLineEnd(lineEvent, leftEvent);
|
|
15688
|
-
};
|
|
15689
|
-
self.getUrl = function () {
|
|
15690
|
-
return self.midiBuffer.download();
|
|
15691
|
-
};
|
|
15692
|
-
self.download = function (fileName) {
|
|
15693
|
-
var url = self.getUrl();
|
|
15694
|
-
var link = document.createElement('a');
|
|
15695
|
-
document.body.appendChild(link);
|
|
15696
|
-
link.setAttribute("style", "display: none;");
|
|
15697
|
-
link.href = url;
|
|
15698
|
-
link.download = fileName ? fileName : 'output.wav';
|
|
15699
|
-
link.click();
|
|
15700
|
-
window.URL.revokeObjectURL(url);
|
|
15701
|
-
document.body.removeChild(link);
|
|
15702
|
-
};
|
|
15703
|
-
}
|
|
15704
|
-
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;
|
|
15705
15860
|
|
|
15706
|
-
|
|
15861
|
+
// chack tabs request for each staffs
|
|
15862
|
+
var staffLineCount = 0;
|
|
15707
15863
|
|
|
15708
|
-
|
|
15709
|
-
|
|
15710
|
-
|
|
15711
|
-
|
|
15712
|
-
|
|
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
|
+
}
|
|
15713
15878
|
|
|
15714
|
-
|
|
15715
|
-
|
|
15716
|
-
|
|
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
|
-
}
|
|
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
|
+
}
|
|
15749
15914
|
};
|
|
15750
|
-
module.exports =
|
|
15915
|
+
module.exports = abcTablatures;
|
|
15751
15916
|
|
|
15752
15917
|
/***/ }),
|
|
15753
15918
|
|
|
@@ -15760,14 +15925,14 @@ module.exports = SynthSequence;
|
|
|
15760
15925
|
var _require = __webpack_require__(/*! ../../synth/note-to-midi */ "./src/synth/note-to-midi.js"),
|
|
15761
15926
|
noteToMidi = _require.noteToMidi;
|
|
15762
15927
|
var TabNote = __webpack_require__(/*! ./tab-note */ "./src/tablatures/instruments/tab-note.js");
|
|
15763
|
-
var
|
|
15928
|
+
var tabNotes = __webpack_require__(/*! ./tab-notes */ "./src/tablatures/instruments/tab-notes.js");
|
|
15764
15929
|
function buildCapo(self) {
|
|
15765
15930
|
var capoTuning = null;
|
|
15766
15931
|
var tuning = self.tuning;
|
|
15767
15932
|
if (self.capo > 0) {
|
|
15768
15933
|
capoTuning = [];
|
|
15769
15934
|
for (var iii = 0; iii < tuning.length; iii++) {
|
|
15770
|
-
var curNote = new TabNote
|
|
15935
|
+
var curNote = new TabNote(tuning[iii]);
|
|
15771
15936
|
for (var jjj = 0; jjj < self.capo; jjj++) {
|
|
15772
15937
|
curNote = curNote.nextNote();
|
|
15773
15938
|
}
|
|
@@ -15788,8 +15953,7 @@ function buildPatterns(self) {
|
|
|
15788
15953
|
if (iii != tuning.length - 1) {
|
|
15789
15954
|
nextNote = tuning[iii + 1];
|
|
15790
15955
|
}
|
|
15791
|
-
var
|
|
15792
|
-
var stringNotes = tabNotes.build();
|
|
15956
|
+
var stringNotes = tabNotes(tuning[iii], nextNote);
|
|
15793
15957
|
if (stringNotes.error) {
|
|
15794
15958
|
return stringNotes;
|
|
15795
15959
|
}
|
|
@@ -15838,7 +16002,7 @@ function handleChordNotes(self, notes) {
|
|
|
15838
16002
|
var retNotes = [];
|
|
15839
16003
|
for (var iiii = 0; iiii < notes.length; iiii++) {
|
|
15840
16004
|
if (notes[iiii].endTie) continue;
|
|
15841
|
-
var note = new TabNote
|
|
16005
|
+
var note = new TabNote(notes[iiii].name, self.clefTranspose);
|
|
15842
16006
|
note.checkKeyAccidentals(self.accidentals, self.measureAccidentals);
|
|
15843
16007
|
var curPos = toNumber(self, note);
|
|
15844
16008
|
retNotes.push(curPos);
|
|
@@ -15930,7 +16094,7 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
15930
16094
|
}
|
|
15931
16095
|
} else {
|
|
15932
16096
|
if (!notes[0].endTie) {
|
|
15933
|
-
note = new TabNote
|
|
16097
|
+
note = new TabNote(notes[0].name, this.clefTranspose);
|
|
15934
16098
|
note.checkKeyAccidentals(this.accidentals, this.measureAccidentals);
|
|
15935
16099
|
number = toNumber(this, note);
|
|
15936
16100
|
if (number) {
|
|
@@ -15947,7 +16111,7 @@ StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
|
15947
16111
|
if (graces) {
|
|
15948
16112
|
retGraces = [];
|
|
15949
16113
|
for (var iiii = 0; iiii < graces.length; iiii++) {
|
|
15950
|
-
note = new TabNote
|
|
16114
|
+
note = new TabNote(graces[iiii].name, this.clefTranspose);
|
|
15951
16115
|
note.checkKeyAccidentals(this.accidentals, this.measureAccidentals);
|
|
15952
16116
|
number = toNumber(this, note);
|
|
15953
16117
|
if (number) {
|
|
@@ -15974,8 +16138,7 @@ StringPatterns.prototype.toString = function () {
|
|
|
15974
16138
|
return arr.join('');
|
|
15975
16139
|
};
|
|
15976
16140
|
StringPatterns.prototype.tabInfos = function (plugin) {
|
|
15977
|
-
var
|
|
15978
|
-
var name = _super.params.label;
|
|
16141
|
+
var name = plugin.params.label;
|
|
15979
16142
|
if (name) {
|
|
15980
16143
|
var tunePos = name.indexOf('%T');
|
|
15981
16144
|
var tuning = "";
|
|
@@ -15993,8 +16156,7 @@ StringPatterns.prototype.tabInfos = function (plugin) {
|
|
|
15993
16156
|
|
|
15994
16157
|
// MAE 27 Nov 2023
|
|
15995
16158
|
StringPatterns.prototype.suppress = function (plugin) {
|
|
15996
|
-
var
|
|
15997
|
-
var suppress = _super.params.suppress;
|
|
16159
|
+
var suppress = plugin.params.suppress;
|
|
15998
16160
|
if (suppress) {
|
|
15999
16161
|
return true;
|
|
16000
16162
|
}
|
|
@@ -16010,9 +16172,10 @@ StringPatterns.prototype.suppress = function (plugin) {
|
|
|
16010
16172
|
* @param {*} highestNote
|
|
16011
16173
|
*/
|
|
16012
16174
|
function StringPatterns(plugin) {
|
|
16175
|
+
//console.log("INIT StringPatterns constructor")
|
|
16013
16176
|
var tuning = plugin.tuning;
|
|
16014
16177
|
var capo = plugin.capo;
|
|
16015
|
-
var highestNote = plugin.
|
|
16178
|
+
var highestNote = plugin.params.highestNote;
|
|
16016
16179
|
this.linePitch = plugin.linePitch;
|
|
16017
16180
|
this.highestNote = "a'";
|
|
16018
16181
|
if (highestNote) {
|
|
@@ -16036,7 +16199,7 @@ function StringPatterns(plugin) {
|
|
|
16036
16199
|
}
|
|
16037
16200
|
this.strings = buildPatterns(this);
|
|
16038
16201
|
if (this.strings.error) {
|
|
16039
|
-
plugin.
|
|
16202
|
+
plugin.setError(this.strings.error);
|
|
16040
16203
|
plugin.inError = true;
|
|
16041
16204
|
return;
|
|
16042
16205
|
}
|
|
@@ -16060,6 +16223,7 @@ module.exports = StringPatterns;
|
|
|
16060
16223
|
*/
|
|
16061
16224
|
|
|
16062
16225
|
function StringTablature(numLines, lineSpace) {
|
|
16226
|
+
//console.log("INIT StringTablature constructor")
|
|
16063
16227
|
this.numLines = numLines;
|
|
16064
16228
|
this.lineSpace = lineSpace;
|
|
16065
16229
|
this.verticalSize = this.numLines * this.lineSpace;
|
|
@@ -16076,6 +16240,7 @@ function StringTablature(numLines, lineSpace) {
|
|
|
16076
16240
|
* @param {} line
|
|
16077
16241
|
*/
|
|
16078
16242
|
StringTablature.prototype.bypass = function (line) {
|
|
16243
|
+
//console.log("RENDER StringTablature bypass")
|
|
16079
16244
|
var voices = line.staffGroup.voices;
|
|
16080
16245
|
if (voices.length > 0) {
|
|
16081
16246
|
if (voices[0].isPercussion) return true;
|
|
@@ -16083,6 +16248,7 @@ StringTablature.prototype.bypass = function (line) {
|
|
|
16083
16248
|
return false;
|
|
16084
16249
|
};
|
|
16085
16250
|
StringTablature.prototype.setRelative = function (child, relative, first) {
|
|
16251
|
+
//console.log("RENDER StringTablature setRelative")
|
|
16086
16252
|
switch (child.type) {
|
|
16087
16253
|
case 'bar':
|
|
16088
16254
|
relative.pitch = this.bar.pitch;
|
|
@@ -16123,8 +16289,9 @@ var _require = __webpack_require__(/*! ../../synth/note-to-midi */ "./src/synth/
|
|
|
16123
16289
|
* Note structure for Tabs
|
|
16124
16290
|
*
|
|
16125
16291
|
*/
|
|
16126
|
-
|
|
16292
|
+
|
|
16127
16293
|
function TabNote(note, clefTranspose) {
|
|
16294
|
+
//console.log("INIT/RENDER TabNote constructor")
|
|
16128
16295
|
var pitch = noteToMidi(note);
|
|
16129
16296
|
if (clefTranspose) pitch += clefTranspose;
|
|
16130
16297
|
var newNote = midiToNote(pitch);
|
|
@@ -16206,12 +16373,15 @@ function cloneNote(self) {
|
|
|
16206
16373
|
return newTabNote;
|
|
16207
16374
|
}
|
|
16208
16375
|
TabNote.prototype.sameNoteAs = function (note) {
|
|
16376
|
+
//console.log("INIT TabNote sameNoteAs")
|
|
16209
16377
|
return note.pitch === this.pitch;
|
|
16210
16378
|
};
|
|
16211
16379
|
TabNote.prototype.isLowerThan = function (note) {
|
|
16380
|
+
//console.log("INIT TabNote isLowerThan")
|
|
16212
16381
|
return note.pitch > this.pitch;
|
|
16213
16382
|
};
|
|
16214
16383
|
TabNote.prototype.checkKeyAccidentals = function (accidentals, measureAccidentals) {
|
|
16384
|
+
//console.log("RENDER TabNote checkKeyAccidentals")
|
|
16215
16385
|
if (this.isAltered || this.natural) return;
|
|
16216
16386
|
if (measureAccidentals[this.name.toUpperCase()]) {
|
|
16217
16387
|
switch (measureAccidentals[this.name.toUpperCase()]) {
|
|
@@ -16256,6 +16426,7 @@ TabNote.prototype.checkKeyAccidentals = function (accidentals, measureAccidental
|
|
|
16256
16426
|
}
|
|
16257
16427
|
};
|
|
16258
16428
|
TabNote.prototype.getAccidentalEquiv = function () {
|
|
16429
|
+
//console.log("TabNote getAccidentalEquiv")
|
|
16259
16430
|
var cloned = cloneNote(this);
|
|
16260
16431
|
if (cloned.isSharp || cloned.isKeySharp) {
|
|
16261
16432
|
cloned = cloned.nextNote();
|
|
@@ -16271,14 +16442,17 @@ TabNote.prototype.getAccidentalEquiv = function () {
|
|
|
16271
16442
|
return cloned;
|
|
16272
16443
|
};
|
|
16273
16444
|
TabNote.prototype.nextNote = function () {
|
|
16445
|
+
//console.log("INIT TabNote nextNote")
|
|
16274
16446
|
var note = midiToNote(this.pitch + 1 + this.pitchAltered);
|
|
16275
16447
|
return new TabNote(note);
|
|
16276
16448
|
};
|
|
16277
16449
|
TabNote.prototype.prevNote = function () {
|
|
16450
|
+
//console.log("TabNote prevNote")
|
|
16278
16451
|
var note = midiToNote(this.pitch - 1 + this.pitchAltered);
|
|
16279
16452
|
return new TabNote(note);
|
|
16280
16453
|
};
|
|
16281
16454
|
TabNote.prototype.emitNoAccidentals = function () {
|
|
16455
|
+
//console.log("TabNote emitNoAccidentals")
|
|
16282
16456
|
var returned = this.name;
|
|
16283
16457
|
if (this.isLower) {
|
|
16284
16458
|
returned = returned.toLowerCase();
|
|
@@ -16292,6 +16466,7 @@ TabNote.prototype.emitNoAccidentals = function () {
|
|
|
16292
16466
|
return returned;
|
|
16293
16467
|
};
|
|
16294
16468
|
TabNote.prototype.emit = function () {
|
|
16469
|
+
//console.log("INIT/RENDER TabNote emit")
|
|
16295
16470
|
var returned = this.name;
|
|
16296
16471
|
if (this.isSharp || this.isKeySharp) {
|
|
16297
16472
|
returned = '^' + returned;
|
|
@@ -16326,10 +16501,7 @@ TabNote.prototype.emit = function () {
|
|
|
16326
16501
|
}
|
|
16327
16502
|
return returned;
|
|
16328
16503
|
};
|
|
16329
|
-
module.exports =
|
|
16330
|
-
'TabNote': TabNote,
|
|
16331
|
-
'notes': notes
|
|
16332
|
-
};
|
|
16504
|
+
module.exports = TabNote;
|
|
16333
16505
|
|
|
16334
16506
|
/***/ }),
|
|
16335
16507
|
|
|
@@ -16340,14 +16512,11 @@ module.exports = {
|
|
|
16340
16512
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16341
16513
|
|
|
16342
16514
|
var TabNote = __webpack_require__(/*! ./tab-note */ "./src/tablatures/instruments/tab-note.js");
|
|
16343
|
-
var notes =
|
|
16344
|
-
function
|
|
16345
|
-
|
|
16346
|
-
|
|
16347
|
-
|
|
16348
|
-
TabNotes.prototype.build = function () {
|
|
16349
|
-
var fromN = this.fromN;
|
|
16350
|
-
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);
|
|
16351
16520
|
// check that toN is not lower than fromN
|
|
16352
16521
|
if (toN.isLowerThan(fromN)) {
|
|
16353
16522
|
var from = fromN.emit();
|
|
@@ -16371,35 +16540,8 @@ TabNotes.prototype.build = function () {
|
|
|
16371
16540
|
}
|
|
16372
16541
|
}
|
|
16373
16542
|
return buildReturned;
|
|
16374
|
-
};
|
|
16375
|
-
module.exports = TabNotes;
|
|
16376
|
-
|
|
16377
|
-
/***/ }),
|
|
16378
|
-
|
|
16379
|
-
/***/ "./src/tablatures/instruments/tab-string-patterns.js":
|
|
16380
|
-
/*!***********************************************************!*\
|
|
16381
|
-
!*** ./src/tablatures/instruments/tab-string-patterns.js ***!
|
|
16382
|
-
\***********************************************************/
|
|
16383
|
-
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16384
|
-
|
|
16385
|
-
var StringPatterns = __webpack_require__(/*! ./string-patterns */ "./src/tablatures/instruments/string-patterns.js");
|
|
16386
|
-
function TabStringPatterns(plugin, defaultTuning) {
|
|
16387
|
-
this.tuning = plugin._super.params.tuning;
|
|
16388
|
-
if (!this.tuning) {
|
|
16389
|
-
this.tuning = defaultTuning;
|
|
16390
|
-
}
|
|
16391
|
-
plugin.tuning = this.tuning;
|
|
16392
|
-
this.strings = new StringPatterns(plugin);
|
|
16393
16543
|
}
|
|
16394
|
-
|
|
16395
|
-
var converter = this.strings;
|
|
16396
|
-
return converter.notesToNumber(notes, graces);
|
|
16397
|
-
};
|
|
16398
|
-
TabStringPatterns.prototype.stringToPitch = function (stringNumber) {
|
|
16399
|
-
var converter = this.strings;
|
|
16400
|
-
return converter.stringToPitch(stringNumber);
|
|
16401
|
-
};
|
|
16402
|
-
module.exports = TabStringPatterns;
|
|
16544
|
+
module.exports = tabNotes;
|
|
16403
16545
|
|
|
16404
16546
|
/***/ }),
|
|
16405
16547
|
|
|
@@ -16410,20 +16552,22 @@ module.exports = TabStringPatterns;
|
|
|
16410
16552
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16411
16553
|
|
|
16412
16554
|
var StringTablature = __webpack_require__(/*! ./string-tablature */ "./src/tablatures/instruments/string-tablature.js");
|
|
16413
|
-
var
|
|
16414
|
-
var
|
|
16415
|
-
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");
|
|
16416
16557
|
|
|
16417
16558
|
/**
|
|
16418
16559
|
* upon init mainly store provided instances for later usage
|
|
16419
16560
|
* @param {*} abcTune the parsed tune AST tree
|
|
16420
|
-
*
|
|
16561
|
+
* @param {*} tuneNumber the parsed tune AST tree
|
|
16421
16562
|
* @param {*} params complementary args provided to Tablature Plugin
|
|
16422
16563
|
*/
|
|
16423
|
-
Plugin.prototype.init = function (abcTune, tuneNumber, params,
|
|
16424
|
-
|
|
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;
|
|
16425
16570
|
this.abcTune = abcTune;
|
|
16426
|
-
this._super = _super;
|
|
16427
16571
|
this.linePitch = 3;
|
|
16428
16572
|
this.nbLines = tabSettings.defaultTuning.length;
|
|
16429
16573
|
this.isTabBig = tabSettings.isTabBig;
|
|
@@ -16432,14 +16576,30 @@ Plugin.prototype.init = function (abcTune, tuneNumber, params, staffNumber, tabS
|
|
|
16432
16576
|
this.transpose = params.visualTranspose;
|
|
16433
16577
|
this.hideTabSymbol = params.hideTabSymbol;
|
|
16434
16578
|
this.tablature = new StringTablature(this.nbLines, this.linePitch);
|
|
16435
|
-
var
|
|
16436
|
-
|
|
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
|
+
}
|
|
16437
16597
|
};
|
|
16438
16598
|
Plugin.prototype.render = function (renderer, line, staffIndex) {
|
|
16439
|
-
|
|
16599
|
+
//console.log("RENDER AbcStringTab Plugin.render")
|
|
16600
|
+
if (this.inError) return;
|
|
16440
16601
|
if (this.tablature.bypass(line)) return;
|
|
16441
|
-
|
|
16442
|
-
rndrer.doLayout();
|
|
16602
|
+
tabRenderer(this, renderer, line, staffIndex);
|
|
16443
16603
|
};
|
|
16444
16604
|
function Plugin() {}
|
|
16445
16605
|
|
|
@@ -16456,17 +16616,17 @@ module.exports = AbcStringTab;
|
|
|
16456
16616
|
|
|
16457
16617
|
/***/ }),
|
|
16458
16618
|
|
|
16459
|
-
/***/ "./src/tablatures/tab-absolute-elements.js":
|
|
16460
|
-
|
|
16461
|
-
!*** ./src/tablatures/tab-absolute-elements.js ***!
|
|
16462
|
-
|
|
16619
|
+
/***/ "./src/tablatures/render/tab-absolute-elements.js":
|
|
16620
|
+
/*!********************************************************!*\
|
|
16621
|
+
!*** ./src/tablatures/render/tab-absolute-elements.js ***!
|
|
16622
|
+
\********************************************************/
|
|
16463
16623
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16464
16624
|
|
|
16465
16625
|
/**
|
|
16466
16626
|
* Tablature Absolute elements factory
|
|
16467
16627
|
*/
|
|
16468
|
-
var AbsoluteElement = __webpack_require__(/*!
|
|
16469
|
-
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");
|
|
16470
16630
|
function isObject(a) {
|
|
16471
16631
|
return a != null && a.constructor === Object;
|
|
16472
16632
|
}
|
|
@@ -16553,6 +16713,7 @@ function lyricsDim(abs) {
|
|
|
16553
16713
|
return null;
|
|
16554
16714
|
}
|
|
16555
16715
|
function TabAbsoluteElements() {
|
|
16716
|
+
//console.log("RENDER TabAbsoluteElements constructor")
|
|
16556
16717
|
this.accidentals = null;
|
|
16557
16718
|
}
|
|
16558
16719
|
function getInitialStaffSize(staffGroup) {
|
|
@@ -16611,7 +16772,7 @@ function graceInRest(absElem) {
|
|
|
16611
16772
|
function convertToNumber(plugin, pitches, graceNotes) {
|
|
16612
16773
|
var tabPos = plugin.semantics.notesToNumber(pitches, graceNotes);
|
|
16613
16774
|
if (tabPos.error) {
|
|
16614
|
-
plugin.
|
|
16775
|
+
plugin.setError(tabPos.error);
|
|
16615
16776
|
return tabPos; // give up on error here
|
|
16616
16777
|
}
|
|
16617
16778
|
|
|
@@ -16644,6 +16805,7 @@ function buildGraceRelativesForRest(plugin, abs, absChild, graceNotes, tabVoice)
|
|
|
16644
16805
|
* @param {*} staffAbsolute
|
|
16645
16806
|
*/
|
|
16646
16807
|
TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice, voiceIndex, staffIndex, keySig, tabVoiceIndex) {
|
|
16808
|
+
//console.log("RENDER TabAbsoluteElements build")
|
|
16647
16809
|
var staffSize = getInitialStaffSize(staffAbsolute);
|
|
16648
16810
|
var source = staffAbsolute[staffIndex + voiceIndex];
|
|
16649
16811
|
var dest = staffAbsolute[tabVoiceIndex];
|
|
@@ -16664,17 +16826,17 @@ TabAbsoluteElements.prototype.build = function (plugin, staffAbsolute, tabVoice,
|
|
|
16664
16826
|
// }
|
|
16665
16827
|
if (absChild.isClef) {
|
|
16666
16828
|
dest.children.push(buildTabAbsolute(plugin, absX, relX));
|
|
16667
|
-
if (absChild.abcelem.type.indexOf('-8') >= 0) plugin.semantics.
|
|
16668
|
-
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;
|
|
16669
16831
|
}
|
|
16670
16832
|
switch (absChild.type) {
|
|
16671
16833
|
case 'staff-extra key-signature':
|
|
16672
16834
|
// refresh key accidentals
|
|
16673
16835
|
this.accidentals = absChild.abcelem.accidentals;
|
|
16674
|
-
plugin.semantics.
|
|
16836
|
+
plugin.semantics.accidentals = this.accidentals;
|
|
16675
16837
|
break;
|
|
16676
16838
|
case 'bar':
|
|
16677
|
-
plugin.semantics.
|
|
16839
|
+
plugin.semantics.measureAccidentals = {};
|
|
16678
16840
|
var lastBar = false;
|
|
16679
16841
|
if (ii === source.children.length - 1) {
|
|
16680
16842
|
// used for final line bar drawing
|
|
@@ -16774,50 +16936,16 @@ module.exports = TabAbsoluteElements;
|
|
|
16774
16936
|
|
|
16775
16937
|
/***/ }),
|
|
16776
16938
|
|
|
16777
|
-
/***/ "./src/tablatures/tab-
|
|
16778
|
-
|
|
16779
|
-
!*** ./src/tablatures/tab-
|
|
16780
|
-
|
|
16781
|
-
/***/ (function(module) {
|
|
16782
|
-
|
|
16783
|
-
/**
|
|
16784
|
-
*
|
|
16785
|
-
* Common Class/Method available for all instruments
|
|
16786
|
-
*
|
|
16787
|
-
*/
|
|
16788
|
-
|
|
16789
|
-
function TabCommon(abcTune, tuneNumber, params) {
|
|
16790
|
-
this.tune = abcTune;
|
|
16791
|
-
this.params = params;
|
|
16792
|
-
this.tuneNumber = tuneNumber;
|
|
16793
|
-
this.inError = false;
|
|
16794
|
-
}
|
|
16795
|
-
TabCommon.prototype.setError = function (error) {
|
|
16796
|
-
var tune = this.tune;
|
|
16797
|
-
if (error) {
|
|
16798
|
-
this.error = error;
|
|
16799
|
-
this.inError = true;
|
|
16800
|
-
if (tune.warnings) {
|
|
16801
|
-
tune.warnings.push(error);
|
|
16802
|
-
} else {
|
|
16803
|
-
tune.warnings = [error];
|
|
16804
|
-
}
|
|
16805
|
-
}
|
|
16806
|
-
};
|
|
16807
|
-
module.exports = TabCommon;
|
|
16808
|
-
|
|
16809
|
-
/***/ }),
|
|
16810
|
-
|
|
16811
|
-
/***/ "./src/tablatures/tab-renderer.js":
|
|
16812
|
-
/*!****************************************!*\
|
|
16813
|
-
!*** ./src/tablatures/tab-renderer.js ***!
|
|
16814
|
-
\****************************************/
|
|
16939
|
+
/***/ "./src/tablatures/render/tab-renderer.js":
|
|
16940
|
+
/*!***********************************************!*\
|
|
16941
|
+
!*** ./src/tablatures/render/tab-renderer.js ***!
|
|
16942
|
+
\***********************************************/
|
|
16815
16943
|
/***/ (function(module, __unused_webpack_exports, __webpack_require__) {
|
|
16816
16944
|
|
|
16817
16945
|
/* eslint-disable no-debugger */
|
|
16818
|
-
var VoiceElement = __webpack_require__(/*!
|
|
16819
|
-
var TabAbsoluteElements = __webpack_require__(/*! ./tab-absolute-elements */ "./src/tablatures/tab-absolute-elements.js");
|
|
16820
|
-
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");
|
|
16821
16949
|
function initSpecialY() {
|
|
16822
16950
|
return {
|
|
16823
16951
|
tempoHeightAbove: 0,
|
|
@@ -16846,12 +16974,11 @@ function getLyricHeight(voice) {
|
|
|
16846
16974
|
return maxLyricHeight; // add spacing
|
|
16847
16975
|
}
|
|
16848
16976
|
|
|
16849
|
-
function buildTabName(
|
|
16850
|
-
var stringSemantics =
|
|
16851
|
-
var
|
|
16852
|
-
var
|
|
16853
|
-
var
|
|
16854
|
-
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);
|
|
16855
16982
|
var doDraw = true;
|
|
16856
16983
|
if (suppress) {
|
|
16857
16984
|
doDraw = false;
|
|
@@ -16869,27 +16996,6 @@ function buildTabName(self, dest) {
|
|
|
16869
16996
|
}
|
|
16870
16997
|
return 0;
|
|
16871
16998
|
}
|
|
16872
|
-
|
|
16873
|
-
/**
|
|
16874
|
-
* Laying out tabs
|
|
16875
|
-
* @param {*} renderer
|
|
16876
|
-
* @param {*} line
|
|
16877
|
-
* @param {*} staffIndex
|
|
16878
|
-
* @param {*} tablatureLayout
|
|
16879
|
-
*/
|
|
16880
|
-
function TabRenderer(plugin, renderer, line, staffIndex) {
|
|
16881
|
-
this.renderer = renderer;
|
|
16882
|
-
this.plugin = plugin;
|
|
16883
|
-
this.line = line;
|
|
16884
|
-
this.absolutes = new TabAbsoluteElements();
|
|
16885
|
-
this.staffIndex = staffIndex;
|
|
16886
|
-
this.tabStaff = {
|
|
16887
|
-
clef: {
|
|
16888
|
-
type: 'TAB'
|
|
16889
|
-
}
|
|
16890
|
-
};
|
|
16891
|
-
this.tabSize = plugin.linePitch * plugin.nbLines;
|
|
16892
|
-
}
|
|
16893
16999
|
function islastTabInStaff(index, staffGroup) {
|
|
16894
17000
|
if (staffGroup[index].isTabStaff) {
|
|
16895
17001
|
if (index === staffGroup.length - 1) return true;
|
|
@@ -16935,8 +17041,7 @@ function isMultiVoiceSingleStaff(staffs, parent) {
|
|
|
16935
17041
|
}
|
|
16936
17042
|
return false;
|
|
16937
17043
|
}
|
|
16938
|
-
function getNextTabPos(
|
|
16939
|
-
var tabIndex = self.staffIndex;
|
|
17044
|
+
function getNextTabPos(tabIndex, staffGroup) {
|
|
16940
17045
|
var startIndex = 0;
|
|
16941
17046
|
var handledVoices = 0;
|
|
16942
17047
|
var inProgress = true;
|
|
@@ -16985,30 +17090,38 @@ function checkVoiceKeySig(voices, ii) {
|
|
|
16985
17090
|
}
|
|
16986
17091
|
return voices[ii - 1].children[0];
|
|
16987
17092
|
}
|
|
16988
|
-
|
|
16989
|
-
|
|
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;
|
|
16990
17103
|
if (staffs) {
|
|
16991
17104
|
// give up on staffline=0 in key
|
|
16992
17105
|
var firstStaff = staffs[0];
|
|
16993
17106
|
if (firstStaff) {
|
|
16994
17107
|
if (firstStaff.clef) {
|
|
16995
17108
|
if (firstStaff.clef.stafflines == 0) {
|
|
16996
|
-
|
|
17109
|
+
plugin.setError("No tablatures when stafflines=0");
|
|
16997
17110
|
return;
|
|
16998
17111
|
}
|
|
16999
17112
|
}
|
|
17000
17113
|
}
|
|
17001
|
-
staffs.splice(staffs.length, 0,
|
|
17114
|
+
staffs.splice(staffs.length, 0, tabStaff);
|
|
17002
17115
|
}
|
|
17003
|
-
var staffGroup =
|
|
17116
|
+
var staffGroup = line.staffGroup;
|
|
17004
17117
|
var voices = staffGroup.voices;
|
|
17005
17118
|
var firstVoice = voices[0];
|
|
17006
17119
|
// take lyrics into account if any
|
|
17007
17120
|
var lyricsHeight = getLyricHeight(firstVoice);
|
|
17008
17121
|
var padd = 3;
|
|
17009
|
-
var prevIndex =
|
|
17122
|
+
var prevIndex = staffIndex;
|
|
17010
17123
|
var previousStaff = staffGroup.staffs[prevIndex];
|
|
17011
|
-
var tabTop =
|
|
17124
|
+
var tabTop = tabSize + padd - previousStaff.bottom - lyricsHeight;
|
|
17012
17125
|
if (previousStaff.isTabStaff) {
|
|
17013
17126
|
tabTop = previousStaff.top;
|
|
17014
17127
|
}
|
|
@@ -17016,44 +17129,44 @@ TabRenderer.prototype.doLayout = function () {
|
|
|
17016
17129
|
bottom: -1,
|
|
17017
17130
|
isTabStaff: true,
|
|
17018
17131
|
specialY: initSpecialY(),
|
|
17019
|
-
lines:
|
|
17020
|
-
linePitch:
|
|
17132
|
+
lines: plugin.nbLines,
|
|
17133
|
+
linePitch: plugin.linePitch,
|
|
17021
17134
|
dy: 0.15,
|
|
17022
17135
|
top: tabTop
|
|
17023
17136
|
};
|
|
17024
|
-
var nextTabPos = getNextTabPos(
|
|
17137
|
+
var nextTabPos = getNextTabPos(staffIndex, staffGroup.staffs);
|
|
17025
17138
|
if (nextTabPos === -1) return;
|
|
17026
17139
|
staffGroupInfos.parentIndex = nextTabPos - 1;
|
|
17027
17140
|
staffGroup.staffs.splice(nextTabPos, 0, staffGroupInfos);
|
|
17028
17141
|
// staffGroup.staffs.push(staffGroupInfos);
|
|
17029
|
-
staffGroup.height +=
|
|
17142
|
+
staffGroup.height += tabSize + padd;
|
|
17030
17143
|
var parentStaff = getLastStaff(staffGroup.staffs, nextTabPos);
|
|
17031
17144
|
var nbVoices = 1;
|
|
17032
17145
|
if (isMultiVoiceSingleStaff(staffGroup.staffs, parentStaff)) {
|
|
17033
17146
|
nbVoices = parentStaff.voices.length;
|
|
17034
17147
|
}
|
|
17035
17148
|
// build from staff
|
|
17036
|
-
|
|
17149
|
+
tabStaff.voices = [];
|
|
17037
17150
|
for (var ii = 0; ii < nbVoices; ii++) {
|
|
17038
17151
|
var tabVoice = new VoiceElement(0, 0);
|
|
17039
17152
|
if (ii > 0) tabVoice.duplicate = true;
|
|
17040
|
-
var nameHeight = buildTabName(
|
|
17153
|
+
var nameHeight = buildTabName(plugin, renderer, tabVoice) / spacing.STEP;
|
|
17041
17154
|
nameHeight = Math.max(nameHeight, 1); // If there is no label for the tab line, then there needs to be a little padding
|
|
17042
17155
|
// This was pushing down the top staff by the tab label height
|
|
17043
|
-
//staffGroup.staffs[
|
|
17044
|
-
staffGroup.staffs[
|
|
17156
|
+
//staffGroup.staffs[staffIndex].top += nameHeight;
|
|
17157
|
+
staffGroup.staffs[staffIndex].top += 1;
|
|
17045
17158
|
staffGroup.height += nameHeight;
|
|
17046
17159
|
tabVoice.staff = staffGroupInfos;
|
|
17047
17160
|
var tabVoiceIndex = voices.length;
|
|
17048
17161
|
voices.splice(voices.length, 0, tabVoice);
|
|
17049
|
-
var keySig = checkVoiceKeySig(voices, ii +
|
|
17050
|
-
|
|
17051
|
-
|
|
17162
|
+
var keySig = checkVoiceKeySig(voices, ii + staffIndex);
|
|
17163
|
+
tabStaff.voices[ii] = [];
|
|
17164
|
+
absolutes.build(plugin, voices, tabStaff.voices[ii], ii, staffIndex, keySig, tabVoiceIndex);
|
|
17052
17165
|
}
|
|
17053
17166
|
linkStaffAndTabs(staffGroup.staffs); // crossreference tabs and staff
|
|
17054
|
-
}
|
|
17167
|
+
}
|
|
17055
17168
|
|
|
17056
|
-
module.exports =
|
|
17169
|
+
module.exports = tabRenderer;
|
|
17057
17170
|
|
|
17058
17171
|
/***/ }),
|
|
17059
17172
|
|
|
@@ -17987,7 +18100,7 @@ AbstractEngraver.prototype.createNote = function (elem, nostem, isSingleLineStaf
|
|
|
17987
18100
|
if (elem.decoration) {
|
|
17988
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.
|
|
17989
18102
|
// This should probably be combined with moveDecorations()
|
|
17990
|
-
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;
|
|
17991
18104
|
this.decoration.createDecoration(voice, elem.decoration, abselem.top, notehead ? notehead.w : 0, abselem, roomtaken, dir, bottom, elem.positioning, this.hasVocals, this.accentAbove);
|
|
17992
18105
|
}
|
|
17993
18106
|
if (elem.barNumber) {
|
|
@@ -23516,7 +23629,7 @@ var Classes = __webpack_require__(/*! ./helpers/classes */ "./src/write/helpers/
|
|
|
23516
23629
|
var GetFontAndAttr = __webpack_require__(/*! ./helpers/get-font-and-attr */ "./src/write/helpers/get-font-and-attr.js");
|
|
23517
23630
|
var GetTextSize = __webpack_require__(/*! ./helpers/get-text-size */ "./src/write/helpers/get-text-size.js");
|
|
23518
23631
|
var draw = __webpack_require__(/*! ./draw/draw */ "./src/write/draw/draw.js");
|
|
23519
|
-
var tablatures = __webpack_require__(/*! ../
|
|
23632
|
+
var tablatures = __webpack_require__(/*! ../tablatures/abc_tablatures */ "./src/tablatures/abc_tablatures.js");
|
|
23520
23633
|
var findSelectableElement = __webpack_require__(/*! ./interactive/find-selectable-element */ "./src/write/interactive/find-selectable-element.js");
|
|
23521
23634
|
|
|
23522
23635
|
/**
|
|
@@ -26376,7 +26489,7 @@ module.exports = Svg;
|
|
|
26376
26489
|
\********************/
|
|
26377
26490
|
/***/ (function(module) {
|
|
26378
26491
|
|
|
26379
|
-
var version = '6.4.
|
|
26492
|
+
var version = '6.4.2';
|
|
26380
26493
|
module.exports = version;
|
|
26381
26494
|
|
|
26382
26495
|
/***/ })
|