abcjs 6.4.1 → 6.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/RELEASE.md +34 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +1246 -1136
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/package.json +1 -1
- package/src/api/abc_tunebook.js +1 -2
- package/src/api/abc_tunebook_svg.js +0 -1
- package/src/midi/abc_midi_create.js +22 -7
- package/src/parse/abc_common.js +3 -11
- package/src/parse/abc_parse.js +1 -1
- package/src/parse/abc_parse_directive.js +44 -3
- package/src/parse/abc_parse_header.js +6 -4
- package/src/parse/abc_parse_key_voice.js +10 -6
- package/src/parse/abc_parse_music.js +22 -5
- package/src/parse/tune-builder.js +675 -643
- package/src/synth/abc_midi_flattener.js +3 -1
- package/src/synth/abc_midi_sequencer.js +18 -3
- package/src/synth/chord-track.js +81 -18
- package/src/synth/create-synth-control.js +1 -2
- package/src/tablatures/abc_tablatures.js +184 -0
- package/src/tablatures/instruments/string-patterns.js +266 -268
- package/src/tablatures/instruments/string-tablature.js +38 -35
- package/src/tablatures/instruments/tab-note.js +186 -181
- package/src/tablatures/instruments/tab-notes.js +30 -35
- package/src/tablatures/instruments/tab-string.js +43 -25
- package/src/tablatures/render/tab-absolute-elements.js +303 -0
- package/src/tablatures/render/tab-renderer.js +244 -0
- package/src/test/abc_parser_lint.js +2 -3
- package/src/write/creation/abstract-engraver.js +1 -1
- package/src/write/engraver-controller.js +1 -1
- package/temp.txt +12 -0
- package/types/index.d.ts +1 -1
- package/version.js +1 -1
- package/src/api/abc_tablatures.js +0 -184
- package/src/tablatures/instruments/tab-string-patterns.js +0 -23
- package/src/tablatures/tab-absolute-elements.js +0 -301
- package/src/tablatures/tab-common.js +0 -29
- package/src/tablatures/tab-renderer.js +0 -259
|
@@ -209,6 +209,7 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
209
209
|
case "chordprog":
|
|
210
210
|
case "bassvol":
|
|
211
211
|
case "chordvol":
|
|
212
|
+
case "gchordbars":
|
|
212
213
|
chordTrack.paramChange(element)
|
|
213
214
|
break
|
|
214
215
|
default:
|
|
@@ -347,7 +348,8 @@ var pitchesToPerc = require('./pitches-to-perc');
|
|
|
347
348
|
return 0;
|
|
348
349
|
|
|
349
350
|
var volume;
|
|
350
|
-
|
|
351
|
+
// MAE 21 Jun 2024 - This previously wasn't allowing zero volume to be applied
|
|
352
|
+
if (nextVolume != undefined) {
|
|
351
353
|
volume = nextVolume;
|
|
352
354
|
nextVolume = undefined;
|
|
353
355
|
} else if (!doBeatAccents) {
|
|
@@ -315,7 +315,7 @@ var parseCommon = require("../parse/abc_common");
|
|
|
315
315
|
if (!e) e = voices[voiceNumber].length; // If there wasn't a first ending marker, then we copy everything.
|
|
316
316
|
// duplicate each of the elements - this has to be a deep copy.
|
|
317
317
|
for (var z = s; z < e; z++) {
|
|
318
|
-
var item =
|
|
318
|
+
var item = Object.assign({},voices[voiceNumber][z]);
|
|
319
319
|
if (item.pitches)
|
|
320
320
|
item.pitches = parseCommon.cloneArray(item.pitches);
|
|
321
321
|
voices[voiceNumber].push(item);
|
|
@@ -389,12 +389,27 @@ var parseCommon = require("../parse/abc_common");
|
|
|
389
389
|
break;
|
|
390
390
|
case "swing":
|
|
391
391
|
case "gchord":
|
|
392
|
-
case "bassprog":
|
|
393
|
-
case "chordprog":
|
|
394
392
|
case "bassvol":
|
|
395
393
|
case "chordvol":
|
|
396
394
|
voices[voiceNumber].push({ el_type: elem.cmd, param: elem.params[0] });
|
|
397
395
|
break;
|
|
396
|
+
|
|
397
|
+
case "bassprog": // MAE 22 May 2024
|
|
398
|
+
case "chordprog": // MAE 22 May 2024
|
|
399
|
+
voices[voiceNumber].push({
|
|
400
|
+
el_type: elem.cmd,
|
|
401
|
+
value: elem.params[0],
|
|
402
|
+
octaveShift: elem.params[1]
|
|
403
|
+
});
|
|
404
|
+
break;
|
|
405
|
+
|
|
406
|
+
// MAE 23 Jun 2024
|
|
407
|
+
case "gchordbars":
|
|
408
|
+
voices[voiceNumber].push({
|
|
409
|
+
el_type: elem.cmd,
|
|
410
|
+
param: elem.params[0]
|
|
411
|
+
});
|
|
412
|
+
break;
|
|
398
413
|
default:
|
|
399
414
|
console.log("MIDI seq: midi cmd not handled: ", elem.cmd, elem);
|
|
400
415
|
}
|
package/src/synth/chord-track.js
CHANGED
|
@@ -17,8 +17,6 @@
|
|
|
17
17
|
//
|
|
18
18
|
// 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.
|
|
19
19
|
|
|
20
|
-
var parseCommon = require("../parse/abc_common");
|
|
21
|
-
|
|
22
20
|
var ChordTrack = function ChordTrack(numVoices, chordsOff, midiOptions, meter) {
|
|
23
21
|
this.chordTrack = [];
|
|
24
22
|
this.chordTrackFinished = false;
|
|
@@ -34,12 +32,24 @@ var ChordTrack = function ChordTrack(numVoices, chordsOff, midiOptions, meter) {
|
|
|
34
32
|
this.meter = meter;
|
|
35
33
|
this.tempoChangeFactor = 1;
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
this.
|
|
35
|
+
// MAE 17 Jun 2024 - To allow for bass and chord instrument octave shifts
|
|
36
|
+
this.bassInstrument = midiOptions.bassprog && midiOptions.bassprog.length >= 1 ? midiOptions.bassprog[0] : 0;
|
|
37
|
+
this.chordInstrument = midiOptions.chordprog && midiOptions.chordprog.length >= 1 ? midiOptions.chordprog[0] : 0;
|
|
38
|
+
|
|
39
|
+
// MAE For octave shifted bass and chords
|
|
40
|
+
this.bassOctaveShift = midiOptions.bassprog && midiOptions.bassprog.length === 2 ? midiOptions.bassprog[1] : 0;
|
|
41
|
+
this.chordOctaveShift = midiOptions.chordprog && midiOptions.chordprog.length === 2 ? midiOptions.chordprog[1] : 0;
|
|
42
|
+
|
|
39
43
|
this.boomVolume = midiOptions.bassvol && midiOptions.bassvol.length === 1 ? midiOptions.bassvol[0] : 64;
|
|
40
44
|
this.chickVolume = midiOptions.chordvol && midiOptions.chordvol.length === 1 ? midiOptions.chordvol[0] : 48;
|
|
41
45
|
|
|
42
|
-
|
|
46
|
+
// This allows for an initial %%MIDI gchord with no string
|
|
47
|
+
if (midiOptions.gchord && (midiOptions.gchord.length > 0)) {
|
|
48
|
+
this.overridePattern = parseGChord(midiOptions.gchord[0])
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
this.overridePattern = undefined;
|
|
52
|
+
}
|
|
43
53
|
};
|
|
44
54
|
|
|
45
55
|
ChordTrack.prototype.setMeter = function (meter) {
|
|
@@ -64,7 +74,7 @@ ChordTrack.prototype.setRhythmHead = function (isRhythmHead, elem) {
|
|
|
64
74
|
if (isRhythmHead) {
|
|
65
75
|
if (this.lastChord && this.lastChord.chick) {
|
|
66
76
|
for (var i2 = 0; i2 < this.lastChord.chick.length; i2++) {
|
|
67
|
-
var note2 =
|
|
77
|
+
var note2 = Object.assign({},elem.pitches[0]);
|
|
68
78
|
note2.actualPitch = this.lastChord.chick[i2];
|
|
69
79
|
ePitches.push(note2);
|
|
70
80
|
}
|
|
@@ -89,13 +99,32 @@ ChordTrack.prototype.gChordOn = function (element) {
|
|
|
89
99
|
ChordTrack.prototype.paramChange = function (element) {
|
|
90
100
|
switch (element.el_type) {
|
|
91
101
|
case "gchord":
|
|
92
|
-
|
|
102
|
+
// Skips gchord elements that don't have pattern strings
|
|
103
|
+
if (element.param && element.param.length > 0) {
|
|
104
|
+
this.overridePattern = parseGChord(element.param);
|
|
105
|
+
|
|
106
|
+
// Generate a default duration scale based on the pattern
|
|
107
|
+
//this.gchordduration = generateDefaultDurationScale(element.param);
|
|
108
|
+
} else
|
|
109
|
+
this.overridePattern = undefined;
|
|
93
110
|
break;
|
|
94
111
|
case "bassprog":
|
|
95
|
-
this.bassInstrument = element.
|
|
112
|
+
this.bassInstrument = element.value;
|
|
113
|
+
if ((element.octaveShift != undefined) && (element.octaveShift != null)) {
|
|
114
|
+
this.bassOctaveShift = element.octaveShift;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
this.bassOctaveShift = 0;
|
|
118
|
+
}
|
|
96
119
|
break;
|
|
97
120
|
case "chordprog":
|
|
98
|
-
this.chordInstrument = element.
|
|
121
|
+
this.chordInstrument = element.value;
|
|
122
|
+
if ((element.octaveShift != undefined) && (element.octaveShift != null)) {
|
|
123
|
+
this.chordOctaveShift = element.octaveShift;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
this.chordOctaveShift = 0;
|
|
127
|
+
}
|
|
99
128
|
break;
|
|
100
129
|
case "bassvol":
|
|
101
130
|
this.boomVolume = element.param;
|
|
@@ -169,6 +198,12 @@ ChordTrack.prototype.interpretChord = function (name) {
|
|
|
169
198
|
while (chordTranspose > 8)
|
|
170
199
|
chordTranspose -= 12;
|
|
171
200
|
bass += chordTranspose;
|
|
201
|
+
|
|
202
|
+
// MAE 17 Jun 2024 - Supporting octave shifted bass and chords
|
|
203
|
+
var unshiftedBass = bass;
|
|
204
|
+
|
|
205
|
+
bass += this.bassOctaveShift * 12;
|
|
206
|
+
|
|
172
207
|
var bass2 = bass - 5; // The alternating bass is a 4th below
|
|
173
208
|
var chick;
|
|
174
209
|
if (name.length === 1)
|
|
@@ -176,16 +211,18 @@ ChordTrack.prototype.interpretChord = function (name) {
|
|
|
176
211
|
var remaining = name.substring(1);
|
|
177
212
|
var acc = remaining.substring(0, 1);
|
|
178
213
|
if (acc === 'b' || acc === '♭') {
|
|
214
|
+
unshiftedBass--;
|
|
179
215
|
bass--;
|
|
180
216
|
bass2--;
|
|
181
217
|
remaining = remaining.substring(1);
|
|
182
218
|
} else if (acc === '#' || acc === '♯') {
|
|
219
|
+
unshiftedBass++;
|
|
183
220
|
bass++;
|
|
184
221
|
bass2++;
|
|
185
222
|
remaining = remaining.substring(1);
|
|
186
223
|
}
|
|
187
224
|
var arr = remaining.split('/');
|
|
188
|
-
chick = this.chordNotes(
|
|
225
|
+
chick = this.chordNotes(unshiftedBass, arr[0]);
|
|
189
226
|
// If the 5th is altered then the bass is altered. Normally the bass is 7 from the root, so adjust if it isn't.
|
|
190
227
|
if (chick.length >= 3) {
|
|
191
228
|
var fifth = chick[2] - chick[0];
|
|
@@ -198,6 +235,10 @@ ChordTrack.prototype.interpretChord = function (name) {
|
|
|
198
235
|
var bassAcc = arr[1].substring(1);
|
|
199
236
|
var bassShift = { '#': 1, '♯': 1, 'b': -1, '♭': -1 }[bassAcc] || 0;
|
|
200
237
|
bass = this.basses[arr[1].substring(0, 1)] + bassShift + chordTranspose;
|
|
238
|
+
|
|
239
|
+
// MAE 22 May 2024 - Supporting octave shifted bass and chords
|
|
240
|
+
bass += this.bassOctaveShift * 12;
|
|
241
|
+
|
|
201
242
|
bass2 = bass;
|
|
202
243
|
}
|
|
203
244
|
}
|
|
@@ -215,6 +256,10 @@ ChordTrack.prototype.chordNotes = function (bass, modifier) {
|
|
|
215
256
|
intervals = this.chordIntervals.M;
|
|
216
257
|
}
|
|
217
258
|
bass += 12; // the chord is an octave above the bass note.
|
|
259
|
+
|
|
260
|
+
// MAE 22 May 2024 - For chick octave shift
|
|
261
|
+
bass += (this.chordOctaveShift * 12);
|
|
262
|
+
|
|
218
263
|
var notes = [];
|
|
219
264
|
for (var i = 0; i < intervals.length; i++) {
|
|
220
265
|
notes.push(bass + intervals[i]);
|
|
@@ -338,25 +383,34 @@ function resolvePitch(currentChord, type, firstBoom, newBass) {
|
|
|
338
383
|
ret.push(firstBoom ? currentChord.boom : currentChord.boom2)
|
|
339
384
|
else if (newBass)
|
|
340
385
|
ret.push(currentChord.boom)
|
|
386
|
+
var numChordNotes = currentChord.chick.length
|
|
341
387
|
if (type.indexOf('chick') >= 0) {
|
|
342
|
-
for (var i = 0; i <
|
|
388
|
+
for (var i = 0; i < numChordNotes; i++)
|
|
343
389
|
ret.push(currentChord.chick[i])
|
|
344
390
|
}
|
|
345
391
|
switch (type) {
|
|
346
392
|
case 'DO': ret.push(currentChord.chick[0]); break;
|
|
347
393
|
case 'MI': ret.push(currentChord.chick[1]); break;
|
|
348
|
-
case 'SOL': ret.push(currentChord
|
|
349
|
-
case 'TI':
|
|
350
|
-
case 'TOP':
|
|
394
|
+
case 'SOL': ret.push(extractNote(currentChord,2)); break;
|
|
395
|
+
case 'TI': ret.push(extractNote(currentChord,3)); break;
|
|
396
|
+
case 'TOP': ret.push(extractNote(currentChord,4)); break;
|
|
351
397
|
case 'do': ret.push(currentChord.chick[0]+12); break;
|
|
352
398
|
case 'mi': ret.push(currentChord.chick[1]+12); break;
|
|
353
|
-
case 'sol': ret.push(currentChord
|
|
354
|
-
case 'ti':
|
|
355
|
-
case 'top':
|
|
399
|
+
case 'sol': ret.push(extractNote(currentChord,2)+12); break;
|
|
400
|
+
case 'ti': ret.push(extractNote(currentChord,3)+12); break;
|
|
401
|
+
case 'top': ret.push(extractNote(currentChord,4)+12); break;
|
|
356
402
|
}
|
|
357
403
|
return ret
|
|
358
404
|
}
|
|
359
405
|
|
|
406
|
+
function extractNote(chord, index) {
|
|
407
|
+
// 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
|
|
408
|
+
var octave = Math.floor(index / chord.chick.length)
|
|
409
|
+
var note = chord.chick[index % chord.chick.length]
|
|
410
|
+
//console.log(chord.chick, {index, octave, note}, index % chord.chick.length)
|
|
411
|
+
return note + octave * 12
|
|
412
|
+
}
|
|
413
|
+
|
|
360
414
|
function parseGChord(gchord) {
|
|
361
415
|
// 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.
|
|
362
416
|
var pattern = []
|
|
@@ -532,7 +586,12 @@ ChordTrack.prototype.chordIntervals = {
|
|
|
532
586
|
'maj7#5#11': [0, 4, 8, 11, 18],
|
|
533
587
|
'9(#5)': [0, 4, 8, 10, 14],
|
|
534
588
|
'13(#5)': [0, 4, 8, 10, 14, 21],
|
|
535
|
-
'13#5': [0, 4, 8, 10, 14, 21]
|
|
589
|
+
'13#5': [0, 4, 8, 10, 14, 21],
|
|
590
|
+
// MAE Power chords added 10 April 2024
|
|
591
|
+
'5': [0, 7],
|
|
592
|
+
'5(8)': [0, 7, 12],
|
|
593
|
+
'5add8': [0, 7, 12]
|
|
594
|
+
|
|
536
595
|
};
|
|
537
596
|
|
|
538
597
|
ChordTrack.prototype.rhythmPatterns = {
|
|
@@ -547,8 +606,12 @@ ChordTrack.prototype.rhythmPatterns = {
|
|
|
547
606
|
"6/4": ['boom', '', 'chick', '', 'boom', '', 'chick', '', 'boom', '', 'chick', ''],
|
|
548
607
|
|
|
549
608
|
"3/8": ['boom', '', 'chick'],
|
|
609
|
+
"5/8": ['boom', 'chick', 'chick', 'boom', 'chick'],
|
|
550
610
|
"6/8": ['boom', '', 'chick', 'boom', '', 'chick'],
|
|
611
|
+
"7/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
|
|
551
612
|
"9/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick'],
|
|
613
|
+
"10/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick'],
|
|
614
|
+
"11/8": ['boom', 'chick', 'chick', 'boom', 'chick', 'chick', 'boom', 'chick', 'boom', 'chick', 'chick'],
|
|
552
615
|
"12/8": ['boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick', 'boom', '', 'chick'],
|
|
553
616
|
};
|
|
554
617
|
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
var supportsAudio = require('./supports-audio');
|
|
2
2
|
var registerAudioContext = require('./register-audio-context');
|
|
3
3
|
var activeAudioContext = require('./active-audio-context');
|
|
4
|
-
var parseCommon = require('../parse/abc_common');
|
|
5
4
|
|
|
6
5
|
var loopImage = require('./images/loop.svg.js');
|
|
7
6
|
var playImage = require('./images/play.svg.js');
|
|
@@ -23,7 +22,7 @@ function CreateSynthControl(parent, options) {
|
|
|
23
22
|
self.parent = parent;
|
|
24
23
|
self.options = {};
|
|
25
24
|
if (options)
|
|
26
|
-
self.options =
|
|
25
|
+
self.options = Object.assign({},options);
|
|
27
26
|
|
|
28
27
|
// This can be called in the following cases:
|
|
29
28
|
// AC already registered and not suspended
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tablature Plugins
|
|
3
|
+
* tablature are defined dynamically and registered inside abcjs
|
|
4
|
+
* by calling abcTablatures.register(plugin)
|
|
5
|
+
* where plugin represents a plugin instance
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
// This is the only entry point to the tablatures. It is called both after parsing a tune and just before engraving
|
|
10
|
+
|
|
11
|
+
var TabString = require('./instruments/tab-string');
|
|
12
|
+
|
|
13
|
+
/* extend the table below when adding a new instrument plugin */
|
|
14
|
+
|
|
15
|
+
// Existing tab classes
|
|
16
|
+
var pluginTab = {
|
|
17
|
+
'violin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0 },
|
|
18
|
+
'fiddle': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0 },
|
|
19
|
+
'mandolin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0 },
|
|
20
|
+
'guitar': { name: 'StringTab', defaultTuning: ['E,', 'A,', 'D', 'G', 'B', 'e'], isTabBig: true, tabSymbolOffset: 0 },
|
|
21
|
+
'fiveString': { name: 'StringTab', defaultTuning: ['C,', 'G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: -.95 },
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
var abcTablatures = {
|
|
25
|
+
|
|
26
|
+
inited: false,
|
|
27
|
+
plugins: {},
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* to be called once per plugin for registration
|
|
32
|
+
* @param {*} plugin
|
|
33
|
+
*/
|
|
34
|
+
register: function (plugin) {
|
|
35
|
+
var name = plugin.name;
|
|
36
|
+
var tablature = plugin.tablature;
|
|
37
|
+
this.plugins[name] = tablature;
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
setError: function (tune, msg) {
|
|
41
|
+
if (tune.warnings) {
|
|
42
|
+
tune.warning.push(msg);
|
|
43
|
+
} else {
|
|
44
|
+
tune.warnings = [msg];
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* handle params for current processed score
|
|
50
|
+
* @param {*} tune current tune
|
|
51
|
+
* @param {*} tuneNumber number in tune list
|
|
52
|
+
* @param {*} params params to be processed for tablature
|
|
53
|
+
* @return prepared tablatures plugin instances for current tune
|
|
54
|
+
*/
|
|
55
|
+
preparePlugins: function (tune, tuneNumber, params) {
|
|
56
|
+
// Called after parsing a tune and before engraving it
|
|
57
|
+
if (!this.inited) {
|
|
58
|
+
// TODO-PER: I don't think this is needed - the plugin array can be hard coded, right?
|
|
59
|
+
this.register(new TabString());
|
|
60
|
+
this.inited = true;
|
|
61
|
+
}
|
|
62
|
+
var returned = null;
|
|
63
|
+
var nbPlugins = 0;
|
|
64
|
+
if (params.tablature) {
|
|
65
|
+
// validate requested plugins
|
|
66
|
+
var tabs = params.tablature;
|
|
67
|
+
returned = [];
|
|
68
|
+
for (var ii = 0; ii < tabs.length; ii++) {
|
|
69
|
+
var args = tabs[ii];
|
|
70
|
+
var instrument = args['instrument'];
|
|
71
|
+
if (instrument == null) {
|
|
72
|
+
this.setError(tune, "tablature 'instrument' is missing");
|
|
73
|
+
return returned;
|
|
74
|
+
}
|
|
75
|
+
var tabName = pluginTab[instrument];
|
|
76
|
+
var plugin = null;
|
|
77
|
+
if (tabName) {
|
|
78
|
+
plugin = this.plugins[tabName.name];
|
|
79
|
+
}
|
|
80
|
+
if (plugin) {
|
|
81
|
+
if (params.visualTranspose != 0) {
|
|
82
|
+
// populate transposition request to tabs
|
|
83
|
+
args.visualTranspose = params.visualTranspose;
|
|
84
|
+
}
|
|
85
|
+
args.abcSrc = params.tablature.abcSrc;
|
|
86
|
+
var pluginInstance = {
|
|
87
|
+
classz: plugin,
|
|
88
|
+
tuneNumber: tuneNumber,
|
|
89
|
+
params: args,
|
|
90
|
+
instance: null,
|
|
91
|
+
tabType: tabName,
|
|
92
|
+
};
|
|
93
|
+
// proceed with tab plugin init
|
|
94
|
+
// plugin.init(tune, tuneNumber, args, ii);
|
|
95
|
+
returned.push(pluginInstance);
|
|
96
|
+
nbPlugins++;
|
|
97
|
+
} else if (instrument === '') {
|
|
98
|
+
// create a placeholder - there is no tab for this staff
|
|
99
|
+
returned.push(null)
|
|
100
|
+
} else {
|
|
101
|
+
// unknown tab plugin
|
|
102
|
+
//this.emit_error('Undefined tablature plugin: ' + tabName)
|
|
103
|
+
this.setError(tune, 'Undefined tablature plugin: ' + instrument);
|
|
104
|
+
return returned;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return returned;
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Call requested plugin
|
|
113
|
+
* @param {*} renderer
|
|
114
|
+
* @param {*} abcTune
|
|
115
|
+
*/
|
|
116
|
+
layoutTablatures: function layoutTablatures(renderer, abcTune) {
|
|
117
|
+
var tabs = abcTune.tablatures;
|
|
118
|
+
|
|
119
|
+
// chack tabs request for each staffs
|
|
120
|
+
var staffLineCount = 0;
|
|
121
|
+
|
|
122
|
+
// Clear the suppression flag
|
|
123
|
+
if (tabs && (tabs.length > 0)) {
|
|
124
|
+
var nTabs = tabs.length;
|
|
125
|
+
for (var kk = 0; kk < nTabs; ++kk) {
|
|
126
|
+
if (tabs[kk] && tabs[kk].params.firstStaffOnly) {
|
|
127
|
+
tabs[kk].params.suppress = false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
for (var ii = 0; ii < abcTune.lines.length; ii++) {
|
|
133
|
+
var line = abcTune.lines[ii];
|
|
134
|
+
|
|
135
|
+
if (line.staff) {
|
|
136
|
+
staffLineCount++;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// MAE 27Nov2023
|
|
140
|
+
// If tab param "firstStaffOnly", remove the tab label after the first staff
|
|
141
|
+
if (staffLineCount > 1) {
|
|
142
|
+
if (tabs && (tabs.length > 0)) {
|
|
143
|
+
var nTabs = tabs.length;
|
|
144
|
+
for (var kk = 0; kk < nTabs; ++kk) {
|
|
145
|
+
if (tabs[kk].params.firstStaffOnly) {
|
|
146
|
+
// Set the staff draw suppression flag
|
|
147
|
+
tabs[kk].params.suppress = true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
var curStaff = line.staff;
|
|
154
|
+
if (curStaff) {
|
|
155
|
+
var maxStaves = curStaff.length
|
|
156
|
+
for (var jj = 0; jj < curStaff.length; jj++) {
|
|
157
|
+
|
|
158
|
+
if (tabs[jj] && jj < maxStaves) {
|
|
159
|
+
// tablature requested for staff
|
|
160
|
+
var tabPlugin = tabs[jj];
|
|
161
|
+
if (tabPlugin.instance == null) {
|
|
162
|
+
//console.log("★★★★ Tab Init line: " + ii + " staff: " + jj)
|
|
163
|
+
tabPlugin.instance = new tabPlugin.classz();
|
|
164
|
+
// plugin.init(tune, tuneNumber, args, ii);
|
|
165
|
+
// call initer first
|
|
166
|
+
tabPlugin.instance.init(abcTune,
|
|
167
|
+
tabPlugin.tuneNumber,
|
|
168
|
+
tabPlugin.params,
|
|
169
|
+
tabPlugin.tabType
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
// render next
|
|
173
|
+
//console.log("★★★★ Tab Render line: " + ii + " staff: " + jj)
|
|
174
|
+
tabPlugin.instance.render(renderer, line, jj);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
module.exports = abcTablatures;
|