abcjs 6.0.0-beta.35 → 6.0.0-beta.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -1
- package/README.md +15 -6
- package/RELEASE.md +74 -0
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic-min.js.LICENSE +2 -2
- package/dist/abcjs-basic.js +2599 -328
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/dist/abcjs-plugin-min.js.LICENSE +2 -2
- package/dist/report-basic.html +37 -0
- package/dist/report-before-glyph-compress.html +37 -0
- package/dist/report-brown-ts-target-es5.html +37 -0
- package/dist/report-dev-orig-no-babel.html +37 -0
- package/dist/report-synth.html +37 -0
- package/docker-build.sh +1 -0
- package/glyphs.json +1 -0
- package/index.js +23 -1
- package/license.js +1 -1
- package/package.json +2 -1
- package/plugin.js +23 -1
- package/src/api/abc_tablatures.js +144 -0
- package/src/api/abc_tunebook.js +10 -1
- package/src/api/abc_tunebook_svg.js +18 -6
- package/src/data/abc_tune.js +26 -24
- package/src/edit/abc_editor.js +29 -11
- package/src/parse/abc_parse.js +4 -2
- package/src/parse/abc_parse_directive.js +12 -6
- package/src/parse/tune-builder.js +1 -1
- package/src/synth/abc_midi_flattener.js +11 -2
- package/src/synth/abc_midi_sequencer.js +4 -1
- package/src/synth/create-synth.js +105 -34
- package/src/synth/load-note.js +34 -65
- package/src/synth/place-note.js +63 -59
- package/src/tablatures/instruments/guitar/guitar-fonts.js +19 -0
- package/src/tablatures/instruments/guitar/guitar-patterns.js +23 -0
- package/src/tablatures/instruments/guitar/tab-guitar.js +50 -0
- package/src/tablatures/instruments/string-patterns.js +277 -0
- package/src/tablatures/instruments/string-tablature.js +56 -0
- package/src/tablatures/instruments/tab-note.js +282 -0
- package/src/tablatures/instruments/tab-notes.js +41 -0
- package/src/tablatures/instruments/violin/tab-violin.js +47 -0
- package/src/tablatures/instruments/violin/violin-fonts.js +19 -0
- package/src/tablatures/instruments/violin/violin-patterns.js +23 -0
- package/src/tablatures/tab-absolute-elements.js +310 -0
- package/src/tablatures/tab-common.js +29 -0
- package/src/tablatures/tab-renderer.js +243 -0
- package/src/tablatures/transposer.js +110 -0
- package/src/test/abc_parser_lint.js +3 -0
- package/src/write/abc_absolute_element.js +2 -2
- package/src/write/abc_engraver_controller.js +19 -11
- package/src/write/abc_glyphs.js +2 -0
- package/src/write/abc_relative_element.js +5 -3
- package/src/write/abc_renderer.js +5 -1
- package/src/write/draw/absolute.js +5 -1
- package/src/write/draw/draw.js +5 -6
- package/src/write/draw/non-music.js +3 -1
- package/src/write/draw/print-line.js +24 -0
- package/src/write/draw/relative.js +14 -2
- package/src/write/draw/selectables.js +9 -6
- package/src/write/draw/staff-group.js +44 -8
- package/src/write/draw/staff-line.js +3 -19
- package/src/write/draw/staff.js +15 -2
- package/src/write/draw/tab-line.js +40 -0
- package/src/write/draw/text.js +3 -0
- package/src/write/draw/voice.js +9 -1
- package/src/write/format-jazz-chord.js +2 -2
- package/src/write/layout/staffGroup.js +23 -1
- package/src/write/layout/voice.js +2 -1
- package/src/write/svg.js +2 -1
- package/temp.txt +0 -0
- package/test.js +23 -0
- package/types/index.d.ts +73 -25
- package/version.js +1 -1
package/src/synth/place-note.js
CHANGED
|
@@ -17,74 +17,78 @@ function placeNote(outputAudioBuffer, sampleRate, sound, startArray, volumeMulti
|
|
|
17
17
|
len = 0.005; // Have some small audible length no matter how short the note is.
|
|
18
18
|
var offlineCtx = new OfflineAC(2,Math.floor((len+fadeTimeSec)*sampleRate),sampleRate);
|
|
19
19
|
var noteName = pitchToNoteName[sound.pitch];
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return;
|
|
20
|
+
var noteBufferPromise = soundsCache[sound.instrument][noteName];
|
|
21
|
+
|
|
22
|
+
if (!noteBufferPromise) {
|
|
23
|
+
// if the note isn't present then just skip it - it will leave a blank spot in the audio.
|
|
24
|
+
return Promise.resolve();
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
return noteBufferPromise
|
|
28
|
+
.then(function (response) {
|
|
29
|
+
// create audio buffer
|
|
30
|
+
var source = offlineCtx.createBufferSource();
|
|
31
|
+
source.buffer = response.audioBuffer;
|
|
30
32
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// add gain
|
|
34
|
+
// volume can be between 1 to 127. This translation to gain is just trial and error.
|
|
35
|
+
// The smaller the first number, the more dynamic range between the quietest to loudest.
|
|
36
|
+
// The larger the second number, the louder it will be in general.
|
|
37
|
+
var volume = (sound.volume / 96) * volumeMultiplier;
|
|
38
|
+
source.gainNode = offlineCtx.createGain();
|
|
37
39
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
40
|
+
// add pan if supported and present
|
|
41
|
+
if (sound.pan && offlineCtx.createStereoPanner) {
|
|
42
|
+
source.panNode = offlineCtx.createStereoPanner();
|
|
43
|
+
source.panNode.pan.setValueAtTime(sound.pan, 0);
|
|
44
|
+
}
|
|
45
|
+
source.gainNode.gain.value = volume; // Math.min(2, Math.max(0, volume));
|
|
46
|
+
source.gainNode.gain.linearRampToValueAtTime(source.gainNode.gain.value, len);
|
|
47
|
+
source.gainNode.gain.linearRampToValueAtTime(0.0, len + fadeTimeSec);
|
|
46
48
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
if (sound.cents) {
|
|
50
|
+
source.playbackRate.value = centsToFactor(sound.cents);
|
|
51
|
+
}
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
// connect all the nodes
|
|
54
|
+
if (source.panNode) {
|
|
55
|
+
source.panNode.connect(offlineCtx.destination);
|
|
56
|
+
source.gainNode.connect(source.panNode);
|
|
57
|
+
} else {
|
|
58
|
+
source.gainNode.connect(offlineCtx.destination);
|
|
59
|
+
}
|
|
60
|
+
source.connect(source.gainNode);
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
// Do the process of creating the sound and placing it in the buffer
|
|
63
|
+
source.start(0);
|
|
62
64
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
var fnResolve;
|
|
69
|
-
offlineCtx.oncomplete = function(e) {
|
|
70
|
-
if (e.renderedBuffer) { // If the system gets overloaded then this can start failing. Just drop the note if so.
|
|
71
|
-
for (var i = 0; i < startArray.length; i++) {
|
|
72
|
-
//Math.floor(startArray[i] * sound.tempoMultiplier * sampleRate)
|
|
73
|
-
var start = startArray[i] * sound.tempoMultiplier;
|
|
74
|
-
if (ofsMs)
|
|
75
|
-
start -=ofsMs/1000;
|
|
76
|
-
if (start < 0)
|
|
77
|
-
start = 0; // If the item that is moved back is at the very beginning of the buffer then don't move it back. To do that would be to push everything else forward. TODO-PER: this should probably be done at some point but then it would change timing in existing apps.
|
|
78
|
-
start = Math.floor(start*sampleRate);
|
|
79
|
-
copyToChannel(outputAudioBuffer, e.renderedBuffer, start);
|
|
65
|
+
if (source.noteOff) {
|
|
66
|
+
source.noteOff(len + fadeTimeSec);
|
|
67
|
+
} else {
|
|
68
|
+
source.stop(len + fadeTimeSec);
|
|
80
69
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
70
|
+
var fnResolve;
|
|
71
|
+
offlineCtx.oncomplete = function(e) {
|
|
72
|
+
if (e.renderedBuffer) { // If the system gets overloaded then this can start failing. Just drop the note if so.
|
|
73
|
+
for (var i = 0; i < startArray.length; i++) {
|
|
74
|
+
//Math.floor(startArray[i] * sound.tempoMultiplier * sampleRate)
|
|
75
|
+
var start = startArray[i] * sound.tempoMultiplier;
|
|
76
|
+
if (ofsMs)
|
|
77
|
+
start -=ofsMs/1000;
|
|
78
|
+
if (start < 0)
|
|
79
|
+
start = 0; // If the item that is moved back is at the very beginning of the buffer then don't move it back. To do that would be to push everything else forward. TODO-PER: this should probably be done at some point but then it would change timing in existing apps.
|
|
80
|
+
start = Math.floor(start*sampleRate);
|
|
81
|
+
copyToChannel(outputAudioBuffer, e.renderedBuffer, start);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
fnResolve();
|
|
85
|
+
};
|
|
86
|
+
offlineCtx.startRendering();
|
|
87
|
+
return new Promise(function(resolve) {
|
|
88
|
+
fnResolve = resolve;
|
|
89
|
+
});
|
|
90
|
+
})
|
|
91
|
+
.catch(function () {});
|
|
88
92
|
}
|
|
89
93
|
|
|
90
94
|
var copyToChannel = function(toBuffer, fromBuffer, start) {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Dedicated fonts for violin tabs
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Set here the fonts used by renderer/drawer
|
|
8
|
+
* for the violin plugin
|
|
9
|
+
* @param {} tune
|
|
10
|
+
*/
|
|
11
|
+
// eslint-disable-next-line no-unused-vars
|
|
12
|
+
function setGuitarFonts(tune) {
|
|
13
|
+
/* enhance or change instrument fonts here */
|
|
14
|
+
// tune.formatting.tabnumberfont = { face: "\"Times New Roman\"", size: 9, weight: "normal", style: "normal", decoration: "none" };
|
|
15
|
+
// tune.formatting.tabgracefont = { face: "\"Times New Roman\"", size: 7, weight: "normal", style: "normal", decoration: "none" };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = setGuitarFonts;
|
|
19
|
+
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
var StringPatterns = require('../string-patterns');
|
|
2
|
+
|
|
3
|
+
function GuitarPatterns(plugin) {
|
|
4
|
+
this.tuning = plugin._super.params.tuning;
|
|
5
|
+
if (!this.tuning) {
|
|
6
|
+
this.tuning = ['E,', 'A', 'D', 'G' , 'B' , 'e'];
|
|
7
|
+
}
|
|
8
|
+
plugin.tuning = this.tuning;
|
|
9
|
+
this.strings = new StringPatterns(plugin);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
GuitarPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
13
|
+
var converter = this.strings;
|
|
14
|
+
return converter.notesToNumber(notes, graces);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
GuitarPatterns.prototype.stringToPitch = function (stringNumber) {
|
|
18
|
+
var converter = this.strings;
|
|
19
|
+
return converter.stringToPitch(stringNumber);
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
module.exports = GuitarPatterns;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Emit tab for Guitar staff
|
|
3
|
+
*/
|
|
4
|
+
var StringTablature = require('../string-tablature');
|
|
5
|
+
var TabCommon = require('../../tab-common');
|
|
6
|
+
var TabRenderer = require('../../tab-renderer');
|
|
7
|
+
var GuitarPatterns = require('./guitar-patterns');
|
|
8
|
+
var setGuitarFonts = require('./guitar-fonts');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* upon init mainly store provided instances for later usage
|
|
12
|
+
* @param {*} abcTune the parsed tune AST tree
|
|
13
|
+
* @param {*} tuneNumber the parsed tune AST tree
|
|
14
|
+
* @param {*} params complementary args provided to Tablature Plugin
|
|
15
|
+
*/
|
|
16
|
+
Plugin.prototype.init = function (abcTune, tuneNumber, params) {
|
|
17
|
+
var _super = new TabCommon(abcTune, tuneNumber, params);
|
|
18
|
+
this._super = _super;
|
|
19
|
+
this.abcTune = abcTune;
|
|
20
|
+
this.linePitch = 3;
|
|
21
|
+
this.nbLines = 6;
|
|
22
|
+
this.isTabBig = true;
|
|
23
|
+
this.capo = params.capo;
|
|
24
|
+
this.transpose = params.visualTranspose;
|
|
25
|
+
this.tablature = new StringTablature(this.nbLines,
|
|
26
|
+
this.linePitch);
|
|
27
|
+
|
|
28
|
+
var semantics = new GuitarPatterns(this);
|
|
29
|
+
this.semantics = semantics;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
Plugin.prototype.render = function (renderer, line, staffIndex) {
|
|
33
|
+
if (this._super.inError) return;
|
|
34
|
+
if (this.tablature.bypass(line)) return;
|
|
35
|
+
setGuitarFonts(this.abcTune);
|
|
36
|
+
var rndrer = new TabRenderer(this, renderer, line, staffIndex);
|
|
37
|
+
rndrer.doLayout();
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function Plugin() {}
|
|
41
|
+
|
|
42
|
+
//
|
|
43
|
+
// Tablature plugin definition
|
|
44
|
+
//
|
|
45
|
+
var AbcGuitarTab = function () {
|
|
46
|
+
return { name: 'GuitarTab', tablature: Plugin };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
module.exports = AbcGuitarTab;
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
var TabNote = require('./tab-note');
|
|
2
|
+
var TabNotes = require('./tab-notes');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
function buildCapo(self) {
|
|
6
|
+
var capoTuning = null;
|
|
7
|
+
var tuning = self.tuning;
|
|
8
|
+
if (self.capo > 0) {
|
|
9
|
+
capoTuning = [];
|
|
10
|
+
for (var iii = 0; iii < tuning.length; iii++) {
|
|
11
|
+
var curNote = new TabNote.TabNote(tuning[iii]);
|
|
12
|
+
for (var jjj = 0; jjj < self.capo; jjj++) {
|
|
13
|
+
curNote = curNote.nextNote();
|
|
14
|
+
}
|
|
15
|
+
capoTuning[iii] = curNote.emit();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return capoTuning;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function buildPatterns(self) {
|
|
22
|
+
var strings = [];
|
|
23
|
+
var tuning = self.tuning;
|
|
24
|
+
if (self.capo > 0) {
|
|
25
|
+
tuning = self.capoTuning;
|
|
26
|
+
}
|
|
27
|
+
var pos = tuning.length - 1;
|
|
28
|
+
for (var iii = 0; iii < tuning.length; iii++) {
|
|
29
|
+
var nextNote = self.highestNote; // highest handled note
|
|
30
|
+
if (iii != tuning.length - 1) {
|
|
31
|
+
nextNote = tuning[iii + 1];
|
|
32
|
+
}
|
|
33
|
+
var tabNotes = new TabNotes(tuning[iii],nextNote);
|
|
34
|
+
var stringNotes = tabNotes.build();
|
|
35
|
+
if (stringNotes.error) {
|
|
36
|
+
return stringNotes;
|
|
37
|
+
}
|
|
38
|
+
strings[pos--] = stringNotes;
|
|
39
|
+
}
|
|
40
|
+
return strings;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
function buildSecond(first) {
|
|
45
|
+
var seconds = [];
|
|
46
|
+
seconds[0] = [];
|
|
47
|
+
var strings = first.strings;
|
|
48
|
+
for (var iii = 1; iii < strings.length; iii++) {
|
|
49
|
+
seconds[iii] = strings[iii - 1];
|
|
50
|
+
}
|
|
51
|
+
return seconds;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function sameString(self, chord) {
|
|
55
|
+
for (var jjjj = 0; jjjj < chord.length - 1; jjjj++) {
|
|
56
|
+
var curPos = chord[jjjj];
|
|
57
|
+
var nextPos = chord[jjjj + 1];
|
|
58
|
+
if (curPos.str == nextPos.str) {
|
|
59
|
+
// same String
|
|
60
|
+
// => change lower pos
|
|
61
|
+
if (curPos.str == self.strings.length - 1) {
|
|
62
|
+
// Invalid tab Chord position for instrument
|
|
63
|
+
curPos.num = "?";
|
|
64
|
+
nextPos.num = "?";
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// change lower pitch on lowest string
|
|
68
|
+
if (nextPos.num < curPos.num) {
|
|
69
|
+
nextPos.str++;
|
|
70
|
+
nextPos = noteToNumber(self,
|
|
71
|
+
nextPos.note,
|
|
72
|
+
nextPos.str,
|
|
73
|
+
self.secondPos,
|
|
74
|
+
self.strings[nextPos.str].length
|
|
75
|
+
);
|
|
76
|
+
} else {
|
|
77
|
+
curPos.str++;
|
|
78
|
+
curPos = noteToNumber(self,
|
|
79
|
+
curPos.note,
|
|
80
|
+
curPos.str,
|
|
81
|
+
self.secondPos,
|
|
82
|
+
self.strings[curPos.str].length
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
// update table
|
|
86
|
+
chord[jjjj] = curPos;
|
|
87
|
+
chord[jjjj + 1] = nextPos;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function handleChordNotes(self, notes) {
|
|
94
|
+
var retNotes = [];
|
|
95
|
+
for (var iiii = 0; iiii < notes.length; iiii++) {
|
|
96
|
+
var note = new TabNote.TabNote(notes[iiii].name);
|
|
97
|
+
var curPos = toNumber(self, note);
|
|
98
|
+
retNotes.push(curPos);
|
|
99
|
+
}
|
|
100
|
+
sameString(self, retNotes);
|
|
101
|
+
return retNotes;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function noteToNumber(self, note, stringNumber, secondPosition , firstSize) {
|
|
105
|
+
var strings = self.strings;
|
|
106
|
+
note.checkKeyAccidentals(self.accidentals) ;
|
|
107
|
+
if (secondPosition) {
|
|
108
|
+
strings = secondPosition;
|
|
109
|
+
}
|
|
110
|
+
var noteName = note.emitNoAccidentals();
|
|
111
|
+
var num = strings[stringNumber].indexOf(noteName);
|
|
112
|
+
var acc = note.acc;
|
|
113
|
+
if (num != -1) {
|
|
114
|
+
if (secondPosition) {
|
|
115
|
+
num += firstSize;
|
|
116
|
+
}
|
|
117
|
+
if ( (note.isFlat || note.acc == -1) && (num == 0)) {
|
|
118
|
+
// flat on 0 pos => previous string 7th position
|
|
119
|
+
var noteEquiv = note.getAccidentalEquiv();
|
|
120
|
+
stringNumber++;
|
|
121
|
+
num = strings[stringNumber].indexOf(noteEquiv.emit());
|
|
122
|
+
acc = 0;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
num: (num + acc),
|
|
126
|
+
str: stringNumber,
|
|
127
|
+
note: note
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function toNumber(self, note) {
|
|
134
|
+
var num = null;
|
|
135
|
+
var str = 0;
|
|
136
|
+
var lowestString = self.strings[self.strings.length - 1];
|
|
137
|
+
var lowestNote = new TabNote.TabNote(lowestString[0]);
|
|
138
|
+
if (note.isLowerThan(lowestNote) ) {
|
|
139
|
+
return {
|
|
140
|
+
num: "?",
|
|
141
|
+
str: self.strings.length - 1,
|
|
142
|
+
note: note,
|
|
143
|
+
error: note.emit() + ': unexpected note for instrument'
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
while (str < self.strings.length) {
|
|
147
|
+
num = noteToNumber(self, note, str);
|
|
148
|
+
if (num) {
|
|
149
|
+
return num;
|
|
150
|
+
}
|
|
151
|
+
str++;
|
|
152
|
+
}
|
|
153
|
+
return null; // not found
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
StringPatterns.prototype.stringToPitch = function (stringNumber) {
|
|
157
|
+
var startingPitch = 5.3;
|
|
158
|
+
var bottom = this.strings.length - 1;
|
|
159
|
+
return startingPitch + ((bottom - stringNumber) * this.linePitch);
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
function invalidNumber( retNotes , note ) {
|
|
163
|
+
var number = {
|
|
164
|
+
num: "?",
|
|
165
|
+
str: 0,
|
|
166
|
+
note: note
|
|
167
|
+
};
|
|
168
|
+
retNotes.push(number);
|
|
169
|
+
retNotes.error = note.emit() + ': unexpected note for instrument' ;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
StringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
173
|
+
var note;
|
|
174
|
+
var number;
|
|
175
|
+
var error = null;
|
|
176
|
+
var retNotes = null;
|
|
177
|
+
if (notes) {
|
|
178
|
+
retNotes = [];
|
|
179
|
+
if (notes.length > 1) {
|
|
180
|
+
retNotes = handleChordNotes(this, notes);
|
|
181
|
+
if (retNotes.error) {
|
|
182
|
+
error = retNotes.error;
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
note = new TabNote.TabNote(notes[0].name);
|
|
186
|
+
number = toNumber(this, note);
|
|
187
|
+
if (number) {
|
|
188
|
+
retNotes.push(number);
|
|
189
|
+
} else {
|
|
190
|
+
invalidNumber(retNotes, note);
|
|
191
|
+
error = retNotes.error;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (error) return retNotes;
|
|
196
|
+
var retGraces = null;
|
|
197
|
+
if (graces) {
|
|
198
|
+
retGraces = [];
|
|
199
|
+
for (var iiii = 0; iiii < graces.length; iiii++) {
|
|
200
|
+
note = new TabNote.TabNote(graces[iiii].name);
|
|
201
|
+
number = toNumber(this, note);
|
|
202
|
+
if (number) {
|
|
203
|
+
retGraces.push(number);
|
|
204
|
+
} else {
|
|
205
|
+
invalidNumber(retGraces, note);
|
|
206
|
+
error = retNotes.error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
notes: retNotes,
|
|
213
|
+
graces: retGraces,
|
|
214
|
+
error: error
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
StringPatterns.prototype.toString = function () {
|
|
219
|
+
return this.tuning.join('').replaceAll(',', '').toUpperCase();
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
StringPatterns.prototype.tabInfos = function (plugin) {
|
|
223
|
+
var _super = plugin._super;
|
|
224
|
+
var name = _super.params.label;
|
|
225
|
+
if (name) {
|
|
226
|
+
var tunePos = name.indexOf('%T');
|
|
227
|
+
var tuning = "";
|
|
228
|
+
if (tunePos != -1) {
|
|
229
|
+
tuning = this.toString();
|
|
230
|
+
if (plugin.capo > 0) {
|
|
231
|
+
tuning += ' capo:' + plugin.capo;
|
|
232
|
+
}
|
|
233
|
+
name = name.replace('%T', tuning);
|
|
234
|
+
}
|
|
235
|
+
return name;
|
|
236
|
+
}
|
|
237
|
+
return '';
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Common patterns for all string instruments
|
|
242
|
+
* @param {} plugin
|
|
243
|
+
* @param {} tuning
|
|
244
|
+
* @param {*} capo
|
|
245
|
+
* @param {*} highestNote
|
|
246
|
+
*/
|
|
247
|
+
function StringPatterns(plugin) {
|
|
248
|
+
var tuning = plugin.tuning;
|
|
249
|
+
var capo = plugin.capo;
|
|
250
|
+
var highestNote = plugin._super.params.highestNote;
|
|
251
|
+
this.linePitch = plugin.linePitch;
|
|
252
|
+
this.highestNote = "a'";
|
|
253
|
+
if (highestNote) {
|
|
254
|
+
// override default
|
|
255
|
+
this.highestNote = highestNote;
|
|
256
|
+
}
|
|
257
|
+
this.capo = 0;
|
|
258
|
+
if (capo) {
|
|
259
|
+
this.capo = capo;
|
|
260
|
+
}
|
|
261
|
+
this.tuning = tuning;
|
|
262
|
+
if (this.capo > 0) {
|
|
263
|
+
this.capoTuning = buildCapo(this);
|
|
264
|
+
}
|
|
265
|
+
this.strings = buildPatterns(this);
|
|
266
|
+
if (this.strings.error) {
|
|
267
|
+
plugin._super.setError(this.strings.error);
|
|
268
|
+
plugin.inError = true;
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
// second position pattern per string
|
|
272
|
+
this.secondPos = buildSecond(this);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
module.exports = StringPatterns;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* Layout tablature informations for draw
|
|
4
|
+
* @param {*} numLines
|
|
5
|
+
* @param {*} lineSpace
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
function StringTablature(numLines, lineSpace) {
|
|
9
|
+
this.numLines = numLines;
|
|
10
|
+
this.lineSpace = lineSpace;
|
|
11
|
+
this.verticalSize = this.numLines * this.lineSpace;
|
|
12
|
+
var pitch = 3;
|
|
13
|
+
this.bar = {
|
|
14
|
+
pitch: pitch,
|
|
15
|
+
pitch2: lineSpace * numLines,
|
|
16
|
+
height: 5,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* return true if current line should not produce a tab
|
|
22
|
+
* @param {} line
|
|
23
|
+
*/
|
|
24
|
+
StringTablature.prototype.bypass = function (line) {
|
|
25
|
+
var voices = line.staffGroup.voices;
|
|
26
|
+
if (voices.length > 0) {
|
|
27
|
+
if (voices[0].isPercussion) return true;
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
StringTablature.prototype.setRelative = function (child, relative, first) {
|
|
34
|
+
switch (child.type) {
|
|
35
|
+
case 'bar':
|
|
36
|
+
relative.pitch = this.bar.pitch;
|
|
37
|
+
relative.pitch2 = this.bar.pitch2;
|
|
38
|
+
relative.height = this.height;
|
|
39
|
+
break;
|
|
40
|
+
case 'symbol':
|
|
41
|
+
var top = this.bar.pitch2 / 2;
|
|
42
|
+
if (child.name == 'dots.dot') {
|
|
43
|
+
if (first) {
|
|
44
|
+
relative.pitch = top;
|
|
45
|
+
return false;
|
|
46
|
+
} else {
|
|
47
|
+
relative.pitch = top + this.lineSpace;
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
return first;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
module.exports = StringTablature;
|