abcjs 6.2.3 → 6.3.0
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/README.md +4 -0
- package/RELEASE.md +40 -1
- package/dist/abcjs-basic-min.js +2 -2
- package/dist/abcjs-basic.js +751 -416
- package/dist/abcjs-basic.js.map +1 -1
- package/dist/abcjs-plugin-min.js +2 -2
- package/index.js +2 -0
- package/package.json +1 -1
- package/plugin.js +1 -1
- package/src/api/abc_tablatures.js +48 -13
- package/src/parse/abc_parse_directive.js +17 -16
- package/src/parse/abc_parse_header.js +22 -19
- package/src/parse/abc_tokenizer.js +72 -7
- package/src/parse/tune-builder.js +60 -1
- package/src/synth/synth-controller.js +6 -2
- package/src/tablatures/instruments/string-patterns.js +11 -0
- package/src/tablatures/instruments/{guitar/guitar-patterns.js → tab-string-patterns.js} +6 -6
- package/src/tablatures/instruments/{violin/tab-violin.js → tab-string.js} +13 -11
- package/src/tablatures/tab-absolute-elements.js +16 -7
- package/src/tablatures/tab-renderer.js +22 -9
- package/src/test/abc_parser_lint.js +13 -12
- package/src/write/creation/abstract-engraver.js +3 -2
- package/src/write/creation/add-chord.js +102 -82
- package/src/write/creation/add-text-if.js +2 -2
- package/src/write/creation/decoration.js +14 -8
- package/src/write/creation/elements/bottom-text.js +62 -47
- package/src/write/creation/elements/rich-text.js +51 -0
- package/src/write/creation/elements/top-text.js +37 -11
- package/src/write/creation/glyphs.js +1 -1
- package/src/write/draw/absolute.js +4 -1
- package/src/write/draw/draw.js +13 -4
- package/src/write/draw/non-music.js +3 -1
- package/src/write/draw/relative.js +1 -1
- package/src/write/draw/tempo.js +1 -1
- package/src/write/draw/text.js +10 -0
- package/src/write/engraver-controller.js +54 -13
- package/src/write/helpers/classes.js +1 -1
- package/src/write/helpers/get-font-and-attr.js +8 -1
- package/src/write/helpers/get-text-size.js +8 -1
- package/src/write/svg.js +30 -0
- package/temp.txt +50 -0
- package/types/index.d.ts +46 -6
- package/version.js +1 -1
- package/.github/workflows/tests.yml +0 -29
- package/src/tablatures/instruments/guitar/tab-guitar.js +0 -48
- package/src/tablatures/instruments/violin/violin-patterns.js +0 -23
package/index.js
CHANGED
|
@@ -57,6 +57,7 @@ var supportsAudio = require('./src/synth/supports-audio');
|
|
|
57
57
|
var playEvent = require('./src/synth/play-event');
|
|
58
58
|
var SynthController = require('./src/synth/synth-controller');
|
|
59
59
|
var getMidiFile = require('./src/synth/get-midi-file');
|
|
60
|
+
var midiRenderer = require('./src/synth/abc_midi_renderer');
|
|
60
61
|
|
|
61
62
|
abcjs.synth = {
|
|
62
63
|
CreateSynth: CreateSynth,
|
|
@@ -71,6 +72,7 @@ abcjs.synth = {
|
|
|
71
72
|
playEvent: playEvent,
|
|
72
73
|
getMidiFile: getMidiFile,
|
|
73
74
|
sequence: sequence,
|
|
75
|
+
midiRenderer: midiRenderer,
|
|
74
76
|
};
|
|
75
77
|
|
|
76
78
|
abcjs['Editor'] = require('./src/edit/abc_editor');
|
package/package.json
CHANGED
package/plugin.js
CHANGED
|
@@ -5,17 +5,17 @@
|
|
|
5
5
|
* where plugin represents a plugin instance
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
-
var
|
|
9
|
-
var GuitarTablature = require('../tablatures/instruments/guitar/tab-guitar');
|
|
8
|
+
var StringTablature = require('../tablatures/instruments/tab-string');
|
|
10
9
|
|
|
11
10
|
/* extend the table below when adding a new instrument plugin */
|
|
12
11
|
|
|
13
12
|
// Existing tab classes
|
|
14
13
|
var pluginTab = {
|
|
15
|
-
'violin': '
|
|
16
|
-
'fiddle': '
|
|
17
|
-
'mandolin': '
|
|
18
|
-
'guitar': '
|
|
14
|
+
'violin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0},
|
|
15
|
+
'fiddle': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0},
|
|
16
|
+
'mandolin': { name: 'StringTab', defaultTuning: ['G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: 0},
|
|
17
|
+
'guitar': { name: 'StringTab', defaultTuning: ['E,', 'A,', 'D', 'G' , 'B' , 'e'], isTabBig: true, tabSymbolOffset: 0},
|
|
18
|
+
'fiveString': { name: 'StringTab', defaultTuning: ['C,', 'G,', 'D', 'A', 'e'], isTabBig: false, tabSymbolOffset: -.95},
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
var abcTablatures = {
|
|
@@ -66,7 +66,7 @@ var abcTablatures = {
|
|
|
66
66
|
var tabName = pluginTab[instrument];
|
|
67
67
|
var plugin = null;
|
|
68
68
|
if (tabName) {
|
|
69
|
-
plugin = this.plugins[tabName];
|
|
69
|
+
plugin = this.plugins[tabName.name];
|
|
70
70
|
}
|
|
71
71
|
if (plugin) {
|
|
72
72
|
if (params.visualTranspose != 0) {
|
|
@@ -79,6 +79,7 @@ var abcTablatures = {
|
|
|
79
79
|
tuneNumber: tuneNumber,
|
|
80
80
|
params: args,
|
|
81
81
|
instance: null,
|
|
82
|
+
tabType: tabName,
|
|
82
83
|
};
|
|
83
84
|
// proceed with tab plugin init
|
|
84
85
|
// plugin.init(tune, tuneNumber, args, ii);
|
|
@@ -103,16 +104,50 @@ var abcTablatures = {
|
|
|
103
104
|
* @param {*} renderer
|
|
104
105
|
* @param {*} abcTune
|
|
105
106
|
*/
|
|
106
|
-
layoutTablatures: function (renderer, abcTune) {
|
|
107
|
+
layoutTablatures: function layoutTablatures(renderer, abcTune) {
|
|
107
108
|
var tabs = abcTune.tablatures;
|
|
109
|
+
|
|
108
110
|
// chack tabs request for each staffs
|
|
111
|
+
var staffLineCount = 0;
|
|
112
|
+
|
|
113
|
+
// Clear the suppression flag
|
|
114
|
+
if (tabs && (tabs.length > 0)){
|
|
115
|
+
var nTabs = tabs.length;
|
|
116
|
+
for (var kk=0;kk<nTabs;++kk){
|
|
117
|
+
if (tabs[kk] && tabs[kk].params.firstStaffOnly){
|
|
118
|
+
tabs[kk].params.suppress = false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
109
123
|
for (var ii = 0; ii < abcTune.lines.length; ii++) {
|
|
110
124
|
var line = abcTune.lines[ii];
|
|
125
|
+
|
|
126
|
+
if (line.staff){
|
|
127
|
+
staffLineCount++;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// MAE 27Nov2023
|
|
131
|
+
// If tab param "firstStaffOnly", remove the tab label after the first staff
|
|
132
|
+
if (staffLineCount > 1){
|
|
133
|
+
if (tabs && (tabs.length > 0)){
|
|
134
|
+
var nTabs = tabs.length;
|
|
135
|
+
for (var kk=0;kk<nTabs;++kk){
|
|
136
|
+
if (tabs[kk].params.firstStaffOnly){
|
|
137
|
+
// Set the staff draw suppression flag
|
|
138
|
+
tabs[kk].params.suppress = true;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
111
144
|
var curStaff = line.staff;
|
|
112
145
|
if (curStaff) {
|
|
146
|
+
var maxStaves = curStaff.length
|
|
113
147
|
for (var jj = 0; jj < curStaff.length; jj++) {
|
|
114
|
-
|
|
115
|
-
|
|
148
|
+
|
|
149
|
+
if (tabs[jj] && jj < maxStaves) {
|
|
150
|
+
// tablature requested for staff
|
|
116
151
|
var tabPlugin = tabs[jj];
|
|
117
152
|
if (tabPlugin.instance == null) {
|
|
118
153
|
tabPlugin.instance = new tabPlugin.classz();
|
|
@@ -121,7 +156,8 @@ var abcTablatures = {
|
|
|
121
156
|
tabPlugin.instance.init(abcTune,
|
|
122
157
|
tabPlugin.tuneNumber,
|
|
123
158
|
tabPlugin.params,
|
|
124
|
-
jj
|
|
159
|
+
jj,
|
|
160
|
+
tabPlugin.tabType
|
|
125
161
|
);
|
|
126
162
|
}
|
|
127
163
|
// render next
|
|
@@ -138,8 +174,7 @@ var abcTablatures = {
|
|
|
138
174
|
init: function () {
|
|
139
175
|
// just register plugin hosted by abcjs
|
|
140
176
|
if (!this.inited) {
|
|
141
|
-
this.register(new
|
|
142
|
-
this.register(new GuitarTablature());
|
|
177
|
+
this.register(new StringTablature());
|
|
143
178
|
this.inited = true;
|
|
144
179
|
}
|
|
145
180
|
}
|
|
@@ -684,27 +684,27 @@ var parseDirective = {};
|
|
|
684
684
|
};
|
|
685
685
|
|
|
686
686
|
parseDirective.parseFontChangeLine = function(textstr) {
|
|
687
|
+
// We don't want to match two dollar signs, so change those temporarily
|
|
688
|
+
textstr = textstr.replace(/\$\$/g,"\x03")
|
|
687
689
|
var textParts = textstr.split('$');
|
|
688
690
|
if (textParts.length > 1 && multilineVars.setfont) {
|
|
689
|
-
var textarr = [
|
|
691
|
+
var textarr = [ ];
|
|
692
|
+
if (textParts[0] !== '') // did the original string start with `$`?
|
|
693
|
+
textarr.push({ text: textParts[0] })
|
|
690
694
|
for (var i = 1; i < textParts.length; i++) {
|
|
691
695
|
if (textParts[i][0] === '0')
|
|
692
|
-
textarr.push({ text: textParts[i].substring(1) });
|
|
693
|
-
else
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
textarr.push({font: multilineVars.setfont[4], text: textParts[i].substring(1) });
|
|
701
|
-
else
|
|
702
|
-
textarr[textarr.length-1].text += '$' + textParts[i];
|
|
696
|
+
textarr.push({ text: textParts[i].substring(1).replace(/\x03/g,"$$") });
|
|
697
|
+
else {
|
|
698
|
+
var whichFont = parseInt(textParts[i][0],10)
|
|
699
|
+
if (multilineVars.setfont[whichFont])
|
|
700
|
+
textarr.push({font: multilineVars.setfont[whichFont], text: textParts[i].substring(1).replace(/\x03/g,"$$") });
|
|
701
|
+
else
|
|
702
|
+
textarr[textarr.length-1].text += '$' + textParts[i].replace(/\x03/g,"$$");
|
|
703
|
+
}
|
|
703
704
|
}
|
|
704
|
-
|
|
705
|
-
return textarr;
|
|
705
|
+
return textarr;
|
|
706
706
|
}
|
|
707
|
-
return textstr;
|
|
707
|
+
return textstr.replace(/\x03/g,"$$");
|
|
708
708
|
};
|
|
709
709
|
|
|
710
710
|
var positionChoices = [ 'auto', 'above', 'below', 'hidden' ];
|
|
@@ -748,6 +748,7 @@ var parseDirective = {};
|
|
|
748
748
|
case "bagpipes":tune.formatting.bagpipes = true;break;
|
|
749
749
|
case "flatbeams":tune.formatting.flatbeams = true;break;
|
|
750
750
|
case "jazzchords":tune.formatting.jazzchords = true;break;
|
|
751
|
+
case "accentAbove":tune.formatting.accentAbove = true;break;
|
|
751
752
|
case "germanAlphabet":tune.formatting.germanAlphabet = true;break;
|
|
752
753
|
case "landscape":multilineVars.landscape = true;break;
|
|
753
754
|
case "papersize":multilineVars.papersize = restOfString;break;
|
|
@@ -939,7 +940,7 @@ var parseDirective = {};
|
|
|
939
940
|
if (sfTokens.length >= 4) {
|
|
940
941
|
if (sfTokens[0].token === '-' && sfTokens[1].type === 'number') {
|
|
941
942
|
var sfNum = parseInt(sfTokens[1].token);
|
|
942
|
-
if (sfNum >= 1 && sfNum <=
|
|
943
|
+
if (sfNum >= 1 && sfNum <= 9) {
|
|
943
944
|
if (!multilineVars.setfont)
|
|
944
945
|
multilineVars.setfont = [];
|
|
945
946
|
sfTokens.shift();
|
|
@@ -11,15 +11,12 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
11
11
|
};
|
|
12
12
|
this.reset(tokenizer, warn, multilineVars, tune);
|
|
13
13
|
|
|
14
|
-
this.setTitle = function(title) {
|
|
14
|
+
this.setTitle = function(title, origSize) {
|
|
15
15
|
if (multilineVars.hasMainTitle)
|
|
16
|
-
tuneBuilder.addSubtitle(
|
|
16
|
+
tuneBuilder.addSubtitle(title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2}); // display secondary title
|
|
17
17
|
else
|
|
18
18
|
{
|
|
19
|
-
|
|
20
|
-
if (multilineVars.titlecaps)
|
|
21
|
-
titleStr = titleStr.toUpperCase();
|
|
22
|
-
tuneBuilder.addMetaText("title", titleStr, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+title.length+2});
|
|
19
|
+
tuneBuilder.addMetaText("title", title, { startChar: multilineVars.iChar, endChar: multilineVars.iChar+origSize+2});
|
|
23
20
|
multilineVars.hasMainTitle = true;
|
|
24
21
|
}
|
|
25
22
|
};
|
|
@@ -371,10 +368,11 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
371
368
|
tuneBuilder.appendStartingElement('key', startChar, endChar, parseKeyVoice.fixKey(multilineVars.clef, multilineVars.key));
|
|
372
369
|
return [ e-i+1+ws ];
|
|
373
370
|
case "[P:":
|
|
371
|
+
var part = parseDirective.parseFontChangeLine(line.substring(i+3, e))
|
|
374
372
|
if (startLine || tune.lines.length <= tune.lineNum)
|
|
375
|
-
multilineVars.partForNextLine = { title:
|
|
373
|
+
multilineVars.partForNextLine = { title: part, startChar: startChar, endChar: endChar };
|
|
376
374
|
else
|
|
377
|
-
tuneBuilder.appendElement('part', startChar, endChar, {title:
|
|
375
|
+
tuneBuilder.appendElement('part', startChar, endChar, {title: part});
|
|
378
376
|
return [ e-i+1+ws ];
|
|
379
377
|
case "[L:":
|
|
380
378
|
this.setDefaultLength(line, i+3, e);
|
|
@@ -477,23 +475,26 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
477
475
|
|
|
478
476
|
this.parseHeader = function(line) {
|
|
479
477
|
var field = metaTextHeaders[line[0]];
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
478
|
+
var origSize = line.length-2
|
|
479
|
+
var restOfLine = tokenizer.translateString(tokenizer.stripComment(line.substring(2)))
|
|
480
|
+
if (field === 'unalignedWords' || field === 'notes') {
|
|
481
|
+
// These fields can be multi-line
|
|
482
|
+
tuneBuilder.addMetaTextArray(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
483
|
+
} else if (field !== undefined) {
|
|
484
|
+
// these fields are single line
|
|
485
|
+
tuneBuilder.addMetaText(field, parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
486
486
|
} else {
|
|
487
487
|
var startChar = multilineVars.iChar;
|
|
488
488
|
var endChar = startChar + line.length;
|
|
489
489
|
switch(line[0])
|
|
490
490
|
{
|
|
491
491
|
case 'H':
|
|
492
|
-
|
|
492
|
+
// History is a little different because once it starts it continues until another header field is encountered
|
|
493
|
+
tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
493
494
|
line = tokenizer.peekLine()
|
|
494
495
|
while (line && line[1] !== ':') {
|
|
495
496
|
tokenizer.nextLine()
|
|
496
|
-
tuneBuilder.
|
|
497
|
+
tuneBuilder.addMetaTextArray("history", parseDirective.parseFontChangeLine(tokenizer.translateString(tokenizer.stripComment(line))), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
497
498
|
line = tokenizer.peekLine()
|
|
498
499
|
}
|
|
499
500
|
break;
|
|
@@ -518,9 +519,9 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
518
519
|
case 'P':
|
|
519
520
|
// TODO-PER: There is more to do with parts, but the writer doesn't care.
|
|
520
521
|
if (multilineVars.is_in_header)
|
|
521
|
-
tuneBuilder.addMetaText("partOrder",
|
|
522
|
+
tuneBuilder.addMetaText("partOrder", parseDirective.parseFontChangeLine(restOfLine), { startChar: multilineVars.iChar, endChar: multilineVars.iChar+line.length});
|
|
522
523
|
else
|
|
523
|
-
multilineVars.partForNextLine = { title:
|
|
524
|
+
multilineVars.partForNextLine = { title: restOfLine, startChar: startChar, endChar: endChar};
|
|
524
525
|
break;
|
|
525
526
|
case 'Q':
|
|
526
527
|
var tempo = this.setTempo(line, 2, line.length, multilineVars.iChar);
|
|
@@ -533,7 +534,9 @@ var ParseHeader = function(tokenizer, warn, multilineVars, tune, tuneBuilder) {
|
|
|
533
534
|
}
|
|
534
535
|
break;
|
|
535
536
|
case 'T':
|
|
536
|
-
|
|
537
|
+
if (multilineVars.titlecaps)
|
|
538
|
+
restOfLine = restOfLine.toUpperCase();
|
|
539
|
+
this.setTitle(parseDirective.parseFontChangeLine(tokenizer.theReverser(restOfLine)), origSize);
|
|
537
540
|
break;
|
|
538
541
|
case 'U':
|
|
539
542
|
this.addUserDefinition(line, 2, line.length);
|
|
@@ -639,13 +639,78 @@ var Tokenizer = function(lines, multilineVars) {
|
|
|
639
639
|
return {value: num/den, index: index};
|
|
640
640
|
};
|
|
641
641
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
642
|
+
//
|
|
643
|
+
// MAE 10 Jan 2023 - For better handling of tunes that have tune numbers in front of them.
|
|
644
|
+
//
|
|
645
|
+
// Previous version would take:
|
|
646
|
+
// 21. Woman of the House, The
|
|
647
|
+
// and return:
|
|
648
|
+
// The 21. Woman of the House
|
|
649
|
+
//
|
|
650
|
+
// This fix results in:
|
|
651
|
+
// 21. The Woman of the House
|
|
652
|
+
//
|
|
653
|
+
// Also added additional checks and handlers for lower case ", the" and ", a" since I found several tune collections with those tune name constructs
|
|
654
|
+
//
|
|
655
|
+
// Find an optional title number at the start of a tune title
|
|
656
|
+
function getTitleNumber(str){
|
|
657
|
+
|
|
658
|
+
const regex = /^(\d+)\./;
|
|
659
|
+
|
|
660
|
+
// Use the exec method to search for the pattern in the string
|
|
661
|
+
const match = regex.exec(str);
|
|
662
|
+
|
|
663
|
+
// Check if a match is found
|
|
664
|
+
if (match) {
|
|
665
|
+
|
|
666
|
+
// The matched number is captured in the first group (index 1)
|
|
667
|
+
const foundNumber = match[1];
|
|
668
|
+
return foundNumber;
|
|
669
|
+
|
|
670
|
+
} else {
|
|
671
|
+
|
|
672
|
+
// Return null if no match is found
|
|
673
|
+
return null;
|
|
674
|
+
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
var thePatterns = [
|
|
680
|
+
{ match: /,\s*[Tt]he$/, replace: "The " },
|
|
681
|
+
{ match: /,\s*[Aa]$/, replace: "A " },
|
|
682
|
+
{ match: /,\s*[Aa]n$/, replace: "An " },
|
|
683
|
+
]
|
|
684
|
+
|
|
685
|
+
this.theReverser = function (str) {
|
|
686
|
+
|
|
687
|
+
for (var i = 0; i < thePatterns.length; i++) {
|
|
688
|
+
var thisPattern = thePatterns[i]
|
|
689
|
+
var match = str.match(thisPattern.match)
|
|
690
|
+
if (match) {
|
|
691
|
+
var theTitleNumber = getTitleNumber(str);
|
|
692
|
+
if (theTitleNumber){
|
|
693
|
+
|
|
694
|
+
//console.log("theReverser The titlenumber:"+theTitleNumber);
|
|
695
|
+
|
|
696
|
+
str = str.replace(theTitleNumber+".","");
|
|
697
|
+
str = str.trim();
|
|
698
|
+
}
|
|
699
|
+
var len = match[0].length
|
|
700
|
+
var result = thisPattern.replace + str.substring(0, str.length - len);
|
|
701
|
+
|
|
702
|
+
if (theTitleNumber){
|
|
703
|
+
result = theTitleNumber+". "+result;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return result;
|
|
707
|
+
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
return str;
|
|
712
|
+
|
|
713
|
+
};
|
|
649
714
|
|
|
650
715
|
this.stripComment = function(str) {
|
|
651
716
|
var i = str.indexOf('%');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
var parseKeyVoice = require('../parse/abc_parse_key_voice');
|
|
2
2
|
var parseCommon = require('../parse/abc_common');
|
|
3
|
+
var parseDirective = require('./abc_parse_directive');
|
|
3
4
|
|
|
4
5
|
var TuneBuilder = function(tune) {
|
|
5
6
|
var self = this;
|
|
@@ -147,6 +148,9 @@ var TuneBuilder = function(tune) {
|
|
|
147
148
|
this.closeLine(); // Close the last line.
|
|
148
149
|
delete tune.runningFonts;
|
|
149
150
|
|
|
151
|
+
simplifyMetaText(tune)
|
|
152
|
+
//addRichTextToAnnotationsAndLyrics(tune)
|
|
153
|
+
|
|
150
154
|
// If the tempo was created with a string like "Allegro", then the duration of a beat needs to be set at the last moment, when it is most likely known.
|
|
151
155
|
if (tune.metaText.tempo && tune.metaText.tempo.bpm && !tune.metaText.tempo.duration)
|
|
152
156
|
tune.metaText.tempo.duration = [ tune.getBeatLength() ];
|
|
@@ -878,7 +882,15 @@ var TuneBuilder = function(tune) {
|
|
|
878
882
|
tune.metaText[key] = value;
|
|
879
883
|
tune.metaTextInfo[key] = info;
|
|
880
884
|
} else {
|
|
881
|
-
tune.metaText[key]
|
|
885
|
+
if (typeof tune.metaText[key] === 'string' && typeof value === 'string')
|
|
886
|
+
tune.metaText[key] += "\n" + value;
|
|
887
|
+
else {
|
|
888
|
+
if (tune.metaText[key] === 'string')
|
|
889
|
+
tune.metaText[key] = [{text: tune.metaText[key]}]
|
|
890
|
+
if (typeof value === 'string')
|
|
891
|
+
value = [{text: value}]
|
|
892
|
+
tune.metaText[key] =tune.metaText[key].concat(value)
|
|
893
|
+
}
|
|
882
894
|
tune.metaTextInfo[key].endChar = info.endChar;
|
|
883
895
|
}
|
|
884
896
|
};
|
|
@@ -898,4 +910,51 @@ var TuneBuilder = function(tune) {
|
|
|
898
910
|
};
|
|
899
911
|
};
|
|
900
912
|
|
|
913
|
+
function isArrayOfStrings(arr) {
|
|
914
|
+
if (!arr) return false
|
|
915
|
+
if (typeof arr === "string") return false
|
|
916
|
+
var str = ''
|
|
917
|
+
for (var i = 0; i < arr.length; i++) {
|
|
918
|
+
if (typeof arr[i] !== 'string')
|
|
919
|
+
return false
|
|
920
|
+
}
|
|
921
|
+
return true
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
function simplifyMetaText(tune) {
|
|
925
|
+
if (isArrayOfStrings(tune.metaText.notes))
|
|
926
|
+
tune.metaText.notes = tune.metaText.notes.join("\n")
|
|
927
|
+
if (isArrayOfStrings(tune.metaText.history))
|
|
928
|
+
tune.metaText.history = tune.metaText.history.join("\n")
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
function addRichTextToAnnotationsAndLyrics(tune) {
|
|
932
|
+
var lines = tune.lines
|
|
933
|
+
for (var i = 0; i < lines.length; i++) {
|
|
934
|
+
if (lines[i].staff !== undefined) {
|
|
935
|
+
for (var s = 0; s < lines[i].staff.length; s++) {
|
|
936
|
+
for (var v = 0; v < lines[i].staff[s].voices.length; v++) {
|
|
937
|
+
var voice = lines[i].staff[s].voices[v];
|
|
938
|
+
for (var n = 0; n < voice.length; n++) {
|
|
939
|
+
var element = voice[n]
|
|
940
|
+
if (element.chord) {
|
|
941
|
+
for (var c = 0; c < element.chord.length; c++) {
|
|
942
|
+
element.chord[c].name = parseDirective.parseFontChangeLine(element.chord[c].name)
|
|
943
|
+
console.log(element.chord[c].name)
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if (element.lyric) {
|
|
947
|
+
for (var l = 0; l < element.lyric.length; l++) {
|
|
948
|
+
element.lyric[l].syllable = parseDirective.parseFontChangeLine(element.lyric[l].syllable)
|
|
949
|
+
console.log(element.lyric[l].syllable)
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
}
|
|
959
|
+
|
|
901
960
|
module.exports = TuneBuilder;
|
|
@@ -21,6 +21,10 @@ function SynthController() {
|
|
|
21
21
|
self.load = function (selector, cursorControl, visualOptions) {
|
|
22
22
|
if (!visualOptions)
|
|
23
23
|
visualOptions = {};
|
|
24
|
+
if (visualOptions.displayPlay === undefined)
|
|
25
|
+
visualOptions.displayPlay = true
|
|
26
|
+
if (visualOptions.displayProgress === undefined)
|
|
27
|
+
visualOptions.displayProgress = true
|
|
24
28
|
self.control = new CreateSynthControl(selector, {
|
|
25
29
|
loopHandler: visualOptions.displayLoop ? self.toggleLoop : undefined,
|
|
26
30
|
restartHandler: visualOptions.displayRestart ? self.restart : undefined,
|
|
@@ -41,7 +45,7 @@ function SynthController() {
|
|
|
41
45
|
self.setTune = function(visualObj, userAction, audioParams) {
|
|
42
46
|
self.visualObj = visualObj;
|
|
43
47
|
self.disable(false);
|
|
44
|
-
self.options = audioParams;
|
|
48
|
+
self.options = audioParams ? audioParams : {};
|
|
45
49
|
|
|
46
50
|
if (self.control) {
|
|
47
51
|
self.pause();
|
|
@@ -195,7 +199,7 @@ function SynthController() {
|
|
|
195
199
|
|
|
196
200
|
self._randomAccess = function (ev) {
|
|
197
201
|
var background = (ev.target.classList.contains('abcjs-midi-progress-indicator')) ? ev.target.parentNode : ev.target;
|
|
198
|
-
var percent = (ev.x - background.
|
|
202
|
+
var percent = (ev.x - background.getBoundingClientRect().left) / background.offsetWidth;
|
|
199
203
|
if (percent < 0)
|
|
200
204
|
percent = 0;
|
|
201
205
|
if (percent > 1)
|
|
@@ -265,6 +265,17 @@ StringPatterns.prototype.tabInfos = function (plugin) {
|
|
|
265
265
|
return '';
|
|
266
266
|
};
|
|
267
267
|
|
|
268
|
+
// MAE 27 Nov 2023
|
|
269
|
+
StringPatterns.prototype.suppress = function (plugin) {
|
|
270
|
+
var _super = plugin._super;
|
|
271
|
+
var suppress = _super.params.suppress;
|
|
272
|
+
if (suppress){
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
return false;
|
|
276
|
+
};
|
|
277
|
+
// MAE 27 Nov 2023 End
|
|
278
|
+
|
|
268
279
|
/**
|
|
269
280
|
* Common patterns for all string instruments
|
|
270
281
|
* @param {} plugin
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
var StringPatterns = require('
|
|
1
|
+
var StringPatterns = require('./string-patterns');
|
|
2
2
|
|
|
3
|
-
function
|
|
3
|
+
function TabStringPatterns(plugin, defaultTuning) {
|
|
4
4
|
this.tuning = plugin._super.params.tuning;
|
|
5
5
|
if (!this.tuning) {
|
|
6
|
-
this.tuning =
|
|
6
|
+
this.tuning = defaultTuning;
|
|
7
7
|
}
|
|
8
8
|
plugin.tuning = this.tuning;
|
|
9
9
|
this.strings = new StringPatterns(plugin);
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
TabStringPatterns.prototype.notesToNumber = function (notes, graces) {
|
|
13
13
|
var converter = this.strings;
|
|
14
14
|
return converter.notesToNumber(notes, graces);
|
|
15
15
|
};
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
TabStringPatterns.prototype.stringToPitch = function (stringNumber) {
|
|
18
18
|
var converter = this.strings;
|
|
19
19
|
return converter.stringToPitch(stringNumber);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
module.exports =
|
|
23
|
+
module.exports = TabStringPatterns;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
|
-
var StringTablature = require('
|
|
3
|
-
var TabCommon = require('
|
|
4
|
-
var TabRenderer = require('
|
|
5
|
-
var
|
|
2
|
+
var StringTablature = require('./string-tablature');
|
|
3
|
+
var TabCommon = require('../tab-common');
|
|
4
|
+
var TabRenderer = require('../tab-renderer');
|
|
5
|
+
var TabStringPatterns = require('./tab-string-patterns');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -11,18 +11,20 @@ var ViolinPatterns = require('./violin-patterns');
|
|
|
11
11
|
* @param {*} tuneNumber the parsed tune AST tree
|
|
12
12
|
* @param {*} params complementary args provided to Tablature Plugin
|
|
13
13
|
*/
|
|
14
|
-
Plugin.prototype.init = function (abcTune, tuneNumber, params) {
|
|
14
|
+
Plugin.prototype.init = function (abcTune, tuneNumber, params, staffNumber, tabSettings) {
|
|
15
15
|
var _super = new TabCommon(abcTune, tuneNumber, params);
|
|
16
16
|
this.abcTune = abcTune;
|
|
17
17
|
this._super = _super;
|
|
18
18
|
this.linePitch = 3;
|
|
19
|
-
this.nbLines =
|
|
20
|
-
this.isTabBig =
|
|
19
|
+
this.nbLines = tabSettings.defaultTuning.length;
|
|
20
|
+
this.isTabBig = tabSettings.isTabBig;
|
|
21
|
+
this.tabSymbolOffset = tabSettings.tabSymbolOffset;
|
|
21
22
|
this.capo = params.capo;
|
|
22
23
|
this.transpose = params.visualTranspose;
|
|
24
|
+
this.hideTabSymbol = params.hideTabSymbol;
|
|
23
25
|
this.tablature = new StringTablature(this.nbLines,
|
|
24
26
|
this.linePitch);
|
|
25
|
-
var semantics = new
|
|
27
|
+
var semantics = new TabStringPatterns(this, tabSettings.defaultTuning);
|
|
26
28
|
this.semantics = semantics;
|
|
27
29
|
};
|
|
28
30
|
|
|
@@ -38,8 +40,8 @@ function Plugin() {}
|
|
|
38
40
|
//
|
|
39
41
|
// Tablature plugin definition
|
|
40
42
|
//
|
|
41
|
-
var
|
|
42
|
-
return { name: '
|
|
43
|
+
var AbcStringTab = function () {
|
|
44
|
+
return { name: 'StringTab', tablature: Plugin };
|
|
43
45
|
};
|
|
44
46
|
|
|
45
|
-
module.exports =
|
|
47
|
+
module.exports = AbcStringTab;
|
|
@@ -60,13 +60,22 @@ function buildTabAbsolute(plugin, absX, relX) {
|
|
|
60
60
|
icon: tabIcon,
|
|
61
61
|
Ypos: tabYPos
|
|
62
62
|
};
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
|
|
63
|
+
|
|
64
|
+
// Offset the TAB symbol position if specified in the tab description
|
|
65
|
+
tabYPos += plugin.tabSymbolOffset;
|
|
66
|
+
|
|
67
|
+
// For tablature like whistle tab where you want the TAB symbol hidden
|
|
68
|
+
if (!plugin.hideTabSymbol){
|
|
69
|
+
|
|
70
|
+
var tabAbsolute = new AbsoluteElement(element, 0, 0, "symbol", 0);
|
|
71
|
+
tabAbsolute.x = absX;
|
|
72
|
+
var tabRelative = new RelativeElement(tabIcon, 0, 0, 7.5, "tab");
|
|
73
|
+
tabRelative.x = relX;
|
|
74
|
+
tabAbsolute.children.push(tabRelative);
|
|
75
|
+
if (tabAbsolute.abcelem.el_type == 'tab') {
|
|
76
|
+
tabRelative.pitch = tabYPos;
|
|
77
|
+
}
|
|
78
|
+
|
|
70
79
|
}
|
|
71
80
|
return tabAbsolute;
|
|
72
81
|
}
|