2851 lines
96 KiB
JavaScript
2851 lines
96 KiB
JavaScript
/* parser generated by jison 0.4.15 */
|
|
/*
|
|
Returns a Parser object of the following structure:
|
|
|
|
Parser: {
|
|
yy: {}
|
|
}
|
|
|
|
Parser.prototype: {
|
|
yy: {},
|
|
trace: function(),
|
|
symbols_: {associative list: name ==> number},
|
|
terminals_: {associative list: number ==> name},
|
|
productions_: [...],
|
|
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate, $$, _$),
|
|
table: [...],
|
|
defaultActions: {...},
|
|
parseError: function(str, hash),
|
|
parse: function(input),
|
|
|
|
lexer: {
|
|
EOF: 1,
|
|
parseError: function(str, hash),
|
|
setInput: function(input),
|
|
input: function(),
|
|
unput: function(str),
|
|
more: function(),
|
|
less: function(n),
|
|
pastInput: function(),
|
|
upcomingInput: function(),
|
|
showPosition: function(),
|
|
test_match: function(regex_match_array, rule_index),
|
|
next: function(),
|
|
lex: function(),
|
|
begin: function(condition),
|
|
popState: function(),
|
|
_currentRules: function(),
|
|
topState: function(),
|
|
pushState: function(condition),
|
|
|
|
options: {
|
|
ranges: boolean (optional: true ==> token location info will include a .range[] member)
|
|
flex: boolean (optional: true ==> flex-like lexing behaviour where the rules are tested exhaustively to find the longest match)
|
|
backtrack_lexer: boolean (optional: true ==> lexer regexes are tested in order and for each matching regex the action code is invoked; the lexer terminates the scan when a token is returned by the action code)
|
|
},
|
|
|
|
performAction: function(yy, yy_, $avoiding_name_collisions, YY_START),
|
|
rules: [...],
|
|
conditions: {associative list: name ==> set},
|
|
}
|
|
}
|
|
|
|
|
|
token location info (@$, _$, etc.): {
|
|
first_line: n,
|
|
last_line: n,
|
|
first_column: n,
|
|
last_column: n,
|
|
range: [start_number, end_number] (where the numbers are indexes into the input string, regular zero-based)
|
|
}
|
|
|
|
|
|
the parseError function receives a 'hash' object with these members for lexer and parser errors: {
|
|
text: (matched text)
|
|
token: (the produced terminal token, if any)
|
|
line: (yylineno)
|
|
}
|
|
while parser (grammar) errors will also provide these members, i.e. parser errors deliver a superset of attributes: {
|
|
loc: (yylloc)
|
|
expected: (string describing the set of expected tokens)
|
|
recoverable: (boolean: TRUE when the parser has a error recovery rule available for this particular error)
|
|
}
|
|
*/
|
|
var parser = (function(){
|
|
var o=function(k,v,o,l){for(o=o||{},l=k.length;l--;o[k[l]]=v);return o},$V0=[1,6],$V1=[1,7],$V2=[1,8],$V3=[1,9],$V4=[5,11,13,14,15],$V5=[5,11,13,14,15,17,19,21],$V6=[2,17],$V7=[1,14],$V8=[5,11,13,14,15,17,19,21,22],$V9=[1,18],$Va=[1,19],$Vb=[1,20],$Vc=[1,21],$Vd=[1,43],$Ve=[1,32],$Vf=[1,33],$Vg=[1,42],$Vh=[1,41],$Vi=[1,39],$Vj=[1,48],$Vk=[1,55],$Vl=[1,50],$Vm=[1,51],$Vn=[1,52],$Vo=[1,53],$Vp=[1,54],$Vq=[1,56],$Vr=[1,44],$Vs=[1,45],$Vt=[1,46],$Vu=[1,47],$Vv=[1,57],$Vw=[5,11,13,14,15,17,19,21,25],$Vx=[5,11,13,14,15,17,19,21,23,31,32,37,38,45,48,57,61,62,63,64,65,66,70,71,73,75,76],$Vy=[2,79],$Vz=[1,67],$VA=[1,64],$VB=[1,65],$VC=[1,66],$VD=[1,73],$VE=[1,74],$VF=[1,78],$VG=[1,79],$VH=[1,80],$VI=[1,81],$VJ=[41,57,59,61,62,63,64,65,66,67,68,69],$VK=[38,45,48,76],$VL=[41,48,57,59,61,62,63,64,65,66,67,68,69,81],$VM=[5,11,13,14,15,17,19,21,23,31,32,37,38,41,45,48,57,61,62,63,64,65,66,70,71,73,75,76],$VN=[1,101],$VO=[44,46],$VP=[2,63],$VQ=[1,106],$VR=[5,11,13,14,15,17,19,21,23,31,32,37,38,45,48,57,59,61,62,63,64,65,66,70,71,73,75,76],$VS=[5,11,13,14,15,17,19,21,23,31,32,37,38,45,48,57,59,60,61,62,63,64,65,66,70,71,73,75,76],$VT=[25,71],$VU=[41,48,57,59,61,62,63,64,65,66,67,68,69],$VV=[5,11,13,14,15,17,19,21,23,31,32,37,38,44,45,46,48,57,61,62,63,64,65,66,70,71,73,75,76];
|
|
var parser = {trace: function trace() { },
|
|
yy: {},
|
|
symbols_: {"error":2,"e":3,"maybe_vextab":4,"EOF":5,"vextab":6,"stave":7,"voice":8,"maybe_options":9,"stave_data":10,"OPTIONS":11,"options":12,"TABSTAVE":13,"STAVE":14,"VOICE":15,"stave_additions":16,"TEXT":17,"text":18,"NOTES":19,"notes":20,"SLUR":21,"WORD":22,"=":23,"STR":24,",":25,"lingo":26,"line":27,"chord":28,"time":29,"bar":30,"[":31,"]":32,"tuplets":33,"annotations":34,"command":35,"rest":36,"|":37,":":38,"frets":39,"maybe_decorator":40,"/":41,"string":42,"chord_line":43,".":44,"(":45,")":46,"articulation":47,"NUMBER":48,"abc":49,"_":50,"timed_fret":51,"time_values":52,"maybe_dot":53,"time_unit":54,"maybe_slash":55,"w":56,"h":57,"q":58,"d":59,"S":60,"-":61,"s":62,"t":63,"T":64,"b":65,"p":66,"v":67,"V":68,"u":69,"^":70,"$":71,"annotation_words":72,"!":73,"COMMAND":74,"#":75,"ABC":76,"abc_accidental":77,"accidental_type":78,"@":79,"n":80,"~":81,"$accept":0,"$end":1},
|
|
terminals_: {2:"error",5:"EOF",11:"OPTIONS",13:"TABSTAVE",14:"STAVE",15:"VOICE",17:"TEXT",19:"NOTES",21:"SLUR",22:"WORD",23:"=",24:"STR",25:",",31:"[",32:"]",37:"|",38:":",41:"/",44:".",45:"(",46:")",48:"NUMBER",50:"_",56:"w",57:"h",58:"q",59:"d",60:"S",61:"-",62:"s",63:"t",64:"T",65:"b",66:"p",67:"v",68:"V",69:"u",70:"^",71:"$",73:"!",74:"COMMAND",75:"#",76:"ABC",79:"@",80:"n",81:"~"},
|
|
productions_: [0,[3,2],[4,0],[4,1],[6,1],[6,2],[7,3],[7,2],[7,2],[8,1],[8,1],[8,1],[10,1],[10,2],[16,2],[16,2],[16,2],[9,0],[9,1],[12,3],[12,4],[18,1],[18,3],[20,1],[20,2],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[26,1],[30,1],[30,3],[30,3],[30,3],[30,3],[30,3],[27,4],[43,1],[43,3],[28,4],[28,5],[39,1],[39,1],[39,4],[39,2],[39,4],[51,5],[51,1],[51,5],[51,8],[51,1],[51,4],[29,3],[52,2],[54,1],[54,1],[54,1],[54,1],[53,0],[53,1],[55,0],[55,1],[42,1],[47,1],[47,1],[47,1],[47,1],[47,1],[47,1],[47,1],[40,1],[40,1],[40,1],[40,1],[40,0],[33,3],[33,5],[34,3],[72,1],[72,3],[35,3],[36,2],[36,3],[36,4],[49,3],[77,1],[77,2],[77,1],[77,2],[77,1],[77,0],[78,0],[78,1]],
|
|
performAction: function anonymous(yytext, yyleng, yylineno, yy, yystate /* action[1] */, $$ /* vstack */, _$ /* lstack */) {
|
|
/* this == yyval */
|
|
|
|
var $0 = $$.length - 1;
|
|
switch (yystate) {
|
|
case 1:
|
|
|
|
if (Vex.Flow.VexTab.DEBUG && $$[$0-1]) {
|
|
console.log($$[$0-1]);
|
|
console.log(JSON.stringify($$[$0-1], null, " "));
|
|
}
|
|
return $$[$0-1];
|
|
|
|
break;
|
|
case 2: case 17: case 79:
|
|
this.$ = null
|
|
break;
|
|
case 3: case 12: case 18: case 23: case 25: case 26: case 27: case 42: case 59: case 60: case 61: case 62: case 67:
|
|
this.$ = $$[$0]
|
|
break;
|
|
case 4: case 83:
|
|
this.$ = [$$[$0]]
|
|
break;
|
|
case 5:
|
|
this.$ = [].concat($$[$0-1], $$[$0])
|
|
break;
|
|
case 6:
|
|
this.$ = {
|
|
element: $$[$0-2],
|
|
options: $$[$0-1],
|
|
notes: $$[$0].notes,
|
|
text: $$[$0].text,
|
|
_l: _$[$0-2].first_line,
|
|
_c: _$[$0-2].first_column
|
|
}
|
|
|
|
break;
|
|
case 7:
|
|
this.$ = {
|
|
element: $$[$0-1],
|
|
options: $$[$0],
|
|
_l: _$[$0-1].first_line,
|
|
_c: _$[$0-1].first_column
|
|
}
|
|
|
|
break;
|
|
case 8:
|
|
|
|
this.$ = {
|
|
element: "options",
|
|
params: $$[$0],
|
|
_l: _$[$0-1].first_line,
|
|
_c: _$[$0-1].first_column
|
|
}
|
|
|
|
break;
|
|
case 13:
|
|
|
|
var text = [].concat($$[$0-1].text, $$[$0].text);
|
|
var notes = [].concat($$[$0-1].notes, $$[$0].notes);
|
|
var slurs = [].concat($$[$0-1].slurs, $$[$0].slurs)
|
|
this.$ = {text: text, notes: notes, slurs: slurs};
|
|
|
|
break;
|
|
case 14:
|
|
this.$ = {text: $$[$0], notes: [], slurs: []}
|
|
break;
|
|
case 15:
|
|
this.$ = {notes: $$[$0], text: [], slurs: []}
|
|
break;
|
|
case 16:
|
|
this.$ = {slurs: $$[$0], notes: [], text: []}
|
|
break;
|
|
case 19:
|
|
this.$ = [{
|
|
key: $$[$0-2],
|
|
value: $$[$0],
|
|
_l: _$[$0-2].first_line,
|
|
_c: _$[$0-2].first_column
|
|
}]
|
|
|
|
break;
|
|
case 20:
|
|
this.$ = [].concat($$[$0-3], [{
|
|
key: $$[$0-2],
|
|
value: $$[$0],
|
|
_l: _$[$0-2].first_line,
|
|
_c: _$[$0-2].first_column
|
|
}])
|
|
|
|
break;
|
|
case 21:
|
|
this.$ = [{text: $$[$0], _l: _$[$0].first_line, _c: _$[$0].first_column}]
|
|
break;
|
|
case 22:
|
|
this.$ = [].concat($$[$0-2], {text: $$[$0], _l: _$[$0].first_line, _c: _$[$0].first_column})
|
|
break;
|
|
case 24:
|
|
this.$ = [].concat($$[$0-1], $$[$0])
|
|
break;
|
|
case 28:
|
|
this.$ = [{
|
|
command: "bar",
|
|
type: $$[$0],
|
|
_l: _$[$0].first_line,
|
|
_c: _$[$0].first_column
|
|
}]
|
|
|
|
break;
|
|
case 29:
|
|
this.$ = [{
|
|
command: "open_beam",
|
|
_l: _$[$0].first_line,
|
|
_c: _$[$0].first_column
|
|
}]
|
|
|
|
break;
|
|
case 30:
|
|
this.$ = [{
|
|
command: "close_beam",
|
|
_l: _$[$0].first_line,
|
|
_c: _$[$0].first_column
|
|
}]
|
|
|
|
break;
|
|
case 31:
|
|
this.$ = [{
|
|
command: "tuplet",
|
|
params: $$[$0],
|
|
_l: _$[$0].first_line,
|
|
_c: _$[$0].first_column
|
|
}]
|
|
|
|
break;
|
|
case 32:
|
|
this.$ = [{
|
|
command: "annotations",
|
|
params: $$[$0],
|
|
_l: _$[$0].first_line,
|
|
_c: _$[$0].first_column
|
|
}]
|
|
|
|
break;
|
|
case 33:
|
|
this.$ = [{
|
|
command: "command",
|
|
params: $$[$0],
|
|
_l: _$[$0].first_line,
|
|
_c: _$[$0].first_column
|
|
}]
|
|
|
|
break;
|
|
case 34:
|
|
|
|
this.$ = [{
|
|
command: "rest",
|
|
params: $$[$0]
|
|
}]
|
|
|
|
break;
|
|
case 35:
|
|
this.$ = 'single'
|
|
break;
|
|
case 36:
|
|
this.$ = 'double'
|
|
break;
|
|
case 37:
|
|
this.$ = 'end'
|
|
break;
|
|
case 38:
|
|
this.$ = 'repeat-end'
|
|
break;
|
|
case 39:
|
|
this.$ = 'repeat-begin'
|
|
break;
|
|
case 40:
|
|
this.$ = 'repeat-both'
|
|
break;
|
|
case 41:
|
|
|
|
_.extend(_.last($$[$0-3]), {decorator: $$[$0-2]})
|
|
_.each($$[$0-3], function(fret) { fret['string'] = $$[$0] })
|
|
this.$ = $$[$0-3]
|
|
|
|
break;
|
|
case 43: case 84:
|
|
this.$ = [].concat($$[$0-2], $$[$0])
|
|
break;
|
|
case 44:
|
|
this.$ = [{chord: $$[$0-2], decorator: $$[$0]}]
|
|
break;
|
|
case 45:
|
|
this.$ = [{chord: $$[$0-2], articulation: $$[$0-4], decorator: $$[$0]}]
|
|
break;
|
|
case 46:
|
|
this.$ = [{
|
|
fret: $$[$0],
|
|
_l: _$[$0].first_line,
|
|
_c: _$[$0].first_column}]
|
|
|
|
break;
|
|
case 47:
|
|
this.$ = [{abc: $$[$0], _l: _$[$0].first_line, _c: _$[$0].first_column}]
|
|
break;
|
|
case 48:
|
|
this.$ = [{abc: $$[$0-3], octave: $$[$0-2],
|
|
fret: $$[$0], _l: _$[$0-3].first_line, _c: _$[$0-3].first_column}]
|
|
break;
|
|
case 49:
|
|
this.$ = [_.extend($$[$0], {articulation: $$[$0-1]})]
|
|
break;
|
|
case 50:
|
|
|
|
_.extend(_.last($$[$0-3]), {decorator: $$[$0-2]})
|
|
_.extend($$[$0], {articulation: $$[$0-1]})
|
|
$$[$0-3].push($$[$0])
|
|
this.$ = $$[$0-3]
|
|
|
|
break;
|
|
case 51:
|
|
this.$ = {
|
|
time: $$[$0-3], dot: $$[$0-2], fret: $$[$0],
|
|
_l: _$[$0-4].first_line, _c: _$[$0-4].first_column}
|
|
break;
|
|
case 52:
|
|
this.$ = {fret: $$[$0], _l: _$[$0].first_line, _c: _$[$0].first_column}
|
|
break;
|
|
case 53:
|
|
this.$ = {time: $$[$0-3], dot: $$[$0-2], abc: $$[$0]}
|
|
break;
|
|
case 54:
|
|
this.$ = {time: $$[$0-6], dot: $$[$0-5], abc: $$[$0-3], octave: $$[$0-2], fret: $$[$0]}
|
|
break;
|
|
case 55:
|
|
this.$ = {abc: $$[$0], _l: _$[$0].first_line, _c: _$[$0].first_column}
|
|
break;
|
|
case 56:
|
|
this.$ = {abc: $$[$0-3], octave: $$[$0-2],
|
|
fret: $$[$0], _l: _$[$0-3].first_line, _c: _$[$0-3].first_column}
|
|
break;
|
|
case 57:
|
|
this.$ = {time: $$[$0-1], dot: $$[$0]}
|
|
break;
|
|
case 58:
|
|
this.$ = $$[$0-1] + $$[$0]
|
|
break;
|
|
case 63:
|
|
this.$ = false
|
|
break;
|
|
case 64:
|
|
this.$ = true
|
|
break;
|
|
case 65:
|
|
this.$ = ''
|
|
break;
|
|
case 66: case 69:
|
|
this.$ = 's'
|
|
break;
|
|
case 68:
|
|
this.$ = '-'
|
|
break;
|
|
case 70:
|
|
this.$ = 't'
|
|
break;
|
|
case 71:
|
|
this.$ = 'T'
|
|
break;
|
|
case 72:
|
|
this.$ = 'b'
|
|
break;
|
|
case 73:
|
|
this.$ = 'h'
|
|
break;
|
|
case 74:
|
|
this.$ = 'p'
|
|
break;
|
|
case 75:
|
|
this.$ = 'v'
|
|
break;
|
|
case 76:
|
|
this.$ = 'V'
|
|
break;
|
|
case 77:
|
|
this.$ = 'u'
|
|
break;
|
|
case 78:
|
|
this.$ = 'd'
|
|
break;
|
|
case 80:
|
|
this.$ = {tuplet: $$[$0-1]}
|
|
break;
|
|
case 81:
|
|
this.$ = {tuplet: $$[$0-3], notes: $$[$0-1]}
|
|
break;
|
|
case 82: case 85:
|
|
this.$ = $$[$0-1]
|
|
break;
|
|
case 86:
|
|
this.$ = {position: 0}
|
|
break;
|
|
case 87:
|
|
this.$ = {position: $$[$0-1]}
|
|
break;
|
|
case 88:
|
|
this.$ = {position: $$[$0-1] * -1}
|
|
break;
|
|
case 89:
|
|
this.$ = {key: $$[$0-2], accidental: $$[$0-1], accidental_type: $$[$0]}
|
|
break;
|
|
case 90:
|
|
this.$ = "#"
|
|
break;
|
|
case 91:
|
|
this.$ = "##"
|
|
break;
|
|
case 92:
|
|
this.$ = "b"
|
|
break;
|
|
case 93:
|
|
this.$ = "bb"
|
|
break;
|
|
case 94:
|
|
this.$ = "n"
|
|
break;
|
|
case 96:
|
|
this.$ = null;
|
|
break;
|
|
case 97:
|
|
this.$ = "c"
|
|
break;
|
|
}
|
|
},
|
|
table: [{3:1,4:2,5:[2,2],6:3,7:4,8:5,11:$V0,13:$V1,14:$V2,15:$V3},{1:[3]},{5:[1,10]},{5:[2,3],7:11,8:5,11:$V0,13:$V1,14:$V2,15:$V3},o($V4,[2,4]),o($V5,$V6,{9:12,12:13,22:$V7}),{12:15,22:$V7},o($V8,[2,9]),o($V8,[2,10]),o($V8,[2,11]),{1:[2,1]},o($V4,[2,5]),o($V4,[2,7],{10:16,16:17,17:$V9,19:$Va,21:$Vb}),o($V5,[2,18],{22:$Vc}),{23:[1,22]},o($V4,[2,8],{22:$Vc}),o($V4,[2,6],{16:23,17:$V9,19:$Va,21:$Vb}),o($V5,[2,12]),{18:24,24:[1,25]},{20:26,23:$Vd,26:27,27:28,28:29,29:30,30:31,31:$Ve,32:$Vf,33:34,34:35,35:36,36:37,37:$Vg,38:$Vh,39:38,45:$Vi,47:40,48:$Vj,49:49,57:$Vk,61:$Vl,62:$Vm,63:$Vn,64:$Vo,65:$Vp,66:$Vq,70:$Vr,71:$Vs,73:$Vt,75:$Vu,76:$Vv},o($V5,$V6,{12:13,9:58,22:$V7}),{23:[1,59]},{22:[1,60]},o($V5,[2,13]),o($V5,[2,14],{25:[1,61]}),o($Vw,[2,21]),o($V5,[2,15],{27:28,28:29,29:30,30:31,33:34,34:35,35:36,36:37,39:38,47:40,49:49,26:62,23:$Vd,31:$Ve,32:$Vf,37:$Vg,38:$Vh,45:$Vi,48:$Vj,57:$Vk,61:$Vl,62:$Vm,63:$Vn,64:$Vo,65:$Vp,66:$Vq,70:$Vr,71:$Vs,73:$Vt,75:$Vu,76:$Vv}),o($Vx,[2,23]),o($Vx,[2,25]),o($Vx,[2,26]),o($Vx,[2,27]),o($Vx,[2,28]),o($Vx,[2,29]),o($Vx,[2,30]),o($Vx,[2,31]),o($Vx,[2,32]),o($Vx,[2,33]),o($Vx,[2,34]),o([41,57,61,62,63,64,65,66],$Vy,{40:63,59:$Vz,67:$VA,68:$VB,69:$VC}),{27:69,39:38,43:68,47:70,48:$Vj,49:49,57:$Vk,61:$Vl,62:$Vm,63:$Vn,64:$Vo,65:$Vp,66:$Vq,76:$Vv},{38:$VD,45:[1,71],48:$VE,49:75,51:72,76:$Vv},{48:$VF,52:76,54:77,56:$VG,57:$VH,58:$VI},o($Vx,[2,35]),{37:[1,82],38:[1,83]},{48:[1,84]},{22:[1,86],72:85},{74:[1,87]},{48:[1,89],61:[1,90],75:[1,88]},o($VJ,[2,46]),o($VJ,[2,47],{48:[1,91]}),o($VK,[2,68]),o($VK,[2,69]),o($VK,[2,70]),o($VK,[2,71]),o($VK,[2,72]),o($VK,[2,73]),o($VK,[2,74]),o($VL,[2,95],{77:92,75:[1,93],79:[1,94],80:[1,95]}),o($V5,[2,16]),{22:[1,96]},o($V8,[2,19]),{24:[1,97]},o($Vx,[2,24]),{41:[1,98],47:99,57:$Vk,61:$Vl,62:$Vm,63:$Vn,64:$Vo,65:$Vp,66:$Vq},o($VM,[2,75]),o($VM,[2,76]),o($VM,[2,77]),o($VM,[2,78]),{44:$VN,46:[1,100]},o($VO,[2,42]),{38:$VD,48:$VE,49:75,51:72,76:$Vv},{27:69,39:38,43:102,47:70,48:$Vj,49:49,57:$Vk,61:$Vl,62:$Vm,63:$Vn,64:$Vo,65:$Vp,66:$Vq,76:$Vv},o($VJ,[2,49]),{48:$VF,52:103,54:77,56:$VG,57:$VH,58:$VI},o($VJ,[2,52]),o($VJ,[2,55],{48:[1,104]}),o($Vx,$VP,{53:105,59:$VQ}),o($VR,[2,65],{55:107,60:[1,108]}),o($VS,[2,59]),o($VS,[2,60]),o($VS,[2,61]),o($VS,[2,62]),{23:[1,110],37:[1,109],38:[1,111]},{37:[1,112],38:[1,113]},{25:[1,115],70:[1,114]},{25:[1,117],71:[1,116]},o($VT,[2,83]),{73:[1,118]},o($Vx,[2,86]),{75:[1,119]},{48:[1,120]},{50:[1,121]},o($VU,[2,96],{78:122,81:[1,123]}),o($VL,[2,90],{75:[1,124]}),o($VL,[2,92],{79:[1,125]}),o($VL,[2,94]),o($V8,[2,20]),o($Vw,[2,22]),{42:126,48:[1,127]},{38:$VD,48:$VE,49:75,51:128,76:$Vv},o($Vx,$Vy,{40:129,59:$Vz,67:$VA,68:$VB,69:$VC}),{27:130,39:38,47:70,48:$Vj,49:49,57:$Vk,61:$Vl,62:$Vm,63:$Vn,64:$Vo,65:$Vp,66:$Vq,76:$Vv},{44:$VN,46:[1,131]},{38:$VP,53:132,59:$VQ},{50:[1,133]},o($Vx,[2,57]),o($Vx,[2,64]),o($VR,[2,58]),o($VR,[2,66]),o($Vx,[2,36]),o($Vx,[2,37]),o($Vx,[2,39]),o($Vx,[2,38]),o($Vx,[2,40]),o($Vx,[2,80]),{48:[1,134]},o($Vx,[2,82]),{22:[1,135]},o($Vx,[2,85]),o($Vx,[2,87]),{75:[1,136]},{48:[1,137]},o($VU,[2,89]),o($VU,[2,97]),o($VL,[2,91]),o($VL,[2,93]),o($VV,[2,41]),o($VV,[2,67]),o($VJ,[2,50]),o($Vx,[2,44]),o($VO,[2,43]),o($Vx,$Vy,{40:138,59:$Vz,67:$VA,68:$VB,69:$VC}),{38:[1,139]},{48:[1,140]},{70:[1,141]},o($VT,[2,84]),o($Vx,[2,88]),o($VJ,[2,48]),o($Vx,[2,45]),{48:[1,142],49:143,76:$Vv},o($VJ,[2,56]),o($Vx,[2,81]),o($VJ,[2,51]),o($VJ,[2,53],{48:[1,144]}),{50:[1,145]},{48:[1,146]},o($VJ,[2,54])],
|
|
defaultActions: {10:[2,1]},
|
|
parseError: function parseError(str, hash) {
|
|
if (hash.recoverable) {
|
|
this.trace(str);
|
|
} else {
|
|
throw new Error(str);
|
|
}
|
|
},
|
|
parse: function parse(input) {
|
|
var self = this, stack = [0], tstack = [], vstack = [null], lstack = [], table = this.table, yytext = '', yylineno = 0, yyleng = 0, recovering = 0, TERROR = 2, EOF = 1;
|
|
var args = lstack.slice.call(arguments, 1);
|
|
var lexer = Object.create(this.lexer);
|
|
var sharedState = { yy: {} };
|
|
for (var k in this.yy) {
|
|
if (Object.prototype.hasOwnProperty.call(this.yy, k)) {
|
|
sharedState.yy[k] = this.yy[k];
|
|
}
|
|
}
|
|
lexer.setInput(input, sharedState.yy);
|
|
sharedState.yy.lexer = lexer;
|
|
sharedState.yy.parser = this;
|
|
if (typeof lexer.yylloc == 'undefined') {
|
|
lexer.yylloc = {};
|
|
}
|
|
var yyloc = lexer.yylloc;
|
|
lstack.push(yyloc);
|
|
var ranges = lexer.options && lexer.options.ranges;
|
|
if (typeof sharedState.yy.parseError === 'function') {
|
|
this.parseError = sharedState.yy.parseError;
|
|
} else {
|
|
this.parseError = Object.getPrototypeOf(this).parseError;
|
|
}
|
|
function popStack(n) {
|
|
stack.length = stack.length - 2 * n;
|
|
vstack.length = vstack.length - n;
|
|
lstack.length = lstack.length - n;
|
|
}
|
|
_token_stack:
|
|
function lex() {
|
|
var token;
|
|
token = lexer.lex() || EOF;
|
|
if (typeof token !== 'number') {
|
|
token = self.symbols_[token] || token;
|
|
}
|
|
return token;
|
|
}
|
|
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected;
|
|
while (true) {
|
|
state = stack[stack.length - 1];
|
|
if (this.defaultActions[state]) {
|
|
action = this.defaultActions[state];
|
|
} else {
|
|
if (symbol === null || typeof symbol == 'undefined') {
|
|
symbol = lex();
|
|
}
|
|
action = table[state] && table[state][symbol];
|
|
}
|
|
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
|
var errStr = '';
|
|
expected = [];
|
|
for (p in table[state]) {
|
|
if (this.terminals_[p] && p > TERROR) {
|
|
expected.push('\'' + this.terminals_[p] + '\'');
|
|
}
|
|
}
|
|
if (lexer.showPosition) {
|
|
errStr = 'Parse error on line ' + (yylineno + 1) + ':\n' + lexer.showPosition() + '\nExpecting ' + expected.join(', ') + ', got \'' + (this.terminals_[symbol] || symbol) + '\'';
|
|
} else {
|
|
errStr = 'Parse error on line ' + (yylineno + 1) + ': Unexpected ' + (symbol == EOF ? 'end of input' : '\'' + (this.terminals_[symbol] || symbol) + '\'');
|
|
}
|
|
this.parseError(errStr, {
|
|
text: lexer.match,
|
|
token: this.terminals_[symbol] || symbol,
|
|
line: lexer.yylineno,
|
|
loc: yyloc,
|
|
expected: expected
|
|
});
|
|
}
|
|
if (action[0] instanceof Array && action.length > 1) {
|
|
throw new Error('Parse Error: multiple actions possible at state: ' + state + ', token: ' + symbol);
|
|
}
|
|
switch (action[0]) {
|
|
case 1:
|
|
stack.push(symbol);
|
|
vstack.push(lexer.yytext);
|
|
lstack.push(lexer.yylloc);
|
|
stack.push(action[1]);
|
|
symbol = null;
|
|
if (!preErrorSymbol) {
|
|
yyleng = lexer.yyleng;
|
|
yytext = lexer.yytext;
|
|
yylineno = lexer.yylineno;
|
|
yyloc = lexer.yylloc;
|
|
if (recovering > 0) {
|
|
recovering--;
|
|
}
|
|
} else {
|
|
symbol = preErrorSymbol;
|
|
preErrorSymbol = null;
|
|
}
|
|
break;
|
|
case 2:
|
|
len = this.productions_[action[1]][1];
|
|
yyval.$ = vstack[vstack.length - len];
|
|
yyval._$ = {
|
|
first_line: lstack[lstack.length - (len || 1)].first_line,
|
|
last_line: lstack[lstack.length - 1].last_line,
|
|
first_column: lstack[lstack.length - (len || 1)].first_column,
|
|
last_column: lstack[lstack.length - 1].last_column
|
|
};
|
|
if (ranges) {
|
|
yyval._$.range = [
|
|
lstack[lstack.length - (len || 1)].range[0],
|
|
lstack[lstack.length - 1].range[1]
|
|
];
|
|
}
|
|
r = this.performAction.apply(yyval, [
|
|
yytext,
|
|
yyleng,
|
|
yylineno,
|
|
sharedState.yy,
|
|
action[1],
|
|
vstack,
|
|
lstack
|
|
].concat(args));
|
|
if (typeof r !== 'undefined') {
|
|
return r;
|
|
}
|
|
if (len) {
|
|
stack = stack.slice(0, -1 * len * 2);
|
|
vstack = vstack.slice(0, -1 * len);
|
|
lstack = lstack.slice(0, -1 * len);
|
|
}
|
|
stack.push(this.productions_[action[1]][0]);
|
|
vstack.push(yyval.$);
|
|
lstack.push(yyval._$);
|
|
newState = table[stack[stack.length - 2]][stack[stack.length - 1]];
|
|
stack.push(newState);
|
|
break;
|
|
case 3:
|
|
return true;
|
|
}
|
|
}
|
|
return true;
|
|
}};
|
|
|
|
Vex.L("Starting parser.");
|
|
/* generated by jison-lex 0.3.4 */
|
|
var lexer = (function(){
|
|
var lexer = ({
|
|
|
|
EOF:1,
|
|
|
|
parseError:function parseError(str, hash) {
|
|
if (this.yy.parser) {
|
|
this.yy.parser.parseError(str, hash);
|
|
} else {
|
|
throw new Error(str);
|
|
}
|
|
},
|
|
|
|
// resets the lexer, sets new input
|
|
setInput:function (input, yy) {
|
|
this.yy = yy || this.yy || {};
|
|
this._input = input;
|
|
this._more = this._backtrack = this.done = false;
|
|
this.yylineno = this.yyleng = 0;
|
|
this.yytext = this.matched = this.match = '';
|
|
this.conditionStack = ['INITIAL'];
|
|
this.yylloc = {
|
|
first_line: 1,
|
|
first_column: 0,
|
|
last_line: 1,
|
|
last_column: 0
|
|
};
|
|
if (this.options.ranges) {
|
|
this.yylloc.range = [0,0];
|
|
}
|
|
this.offset = 0;
|
|
return this;
|
|
},
|
|
|
|
// consumes and returns one char from the input
|
|
input:function () {
|
|
var ch = this._input[0];
|
|
this.yytext += ch;
|
|
this.yyleng++;
|
|
this.offset++;
|
|
this.match += ch;
|
|
this.matched += ch;
|
|
var lines = ch.match(/(?:\r\n?|\n).*/g);
|
|
if (lines) {
|
|
this.yylineno++;
|
|
this.yylloc.last_line++;
|
|
} else {
|
|
this.yylloc.last_column++;
|
|
}
|
|
if (this.options.ranges) {
|
|
this.yylloc.range[1]++;
|
|
}
|
|
|
|
this._input = this._input.slice(1);
|
|
return ch;
|
|
},
|
|
|
|
// unshifts one char (or a string) into the input
|
|
unput:function (ch) {
|
|
var len = ch.length;
|
|
var lines = ch.split(/(?:\r\n?|\n)/g);
|
|
|
|
this._input = ch + this._input;
|
|
this.yytext = this.yytext.substr(0, this.yytext.length - len);
|
|
//this.yyleng -= len;
|
|
this.offset -= len;
|
|
var oldLines = this.match.split(/(?:\r\n?|\n)/g);
|
|
this.match = this.match.substr(0, this.match.length - 1);
|
|
this.matched = this.matched.substr(0, this.matched.length - 1);
|
|
|
|
if (lines.length - 1) {
|
|
this.yylineno -= lines.length - 1;
|
|
}
|
|
var r = this.yylloc.range;
|
|
|
|
this.yylloc = {
|
|
first_line: this.yylloc.first_line,
|
|
last_line: this.yylineno + 1,
|
|
first_column: this.yylloc.first_column,
|
|
last_column: lines ?
|
|
(lines.length === oldLines.length ? this.yylloc.first_column : 0)
|
|
+ oldLines[oldLines.length - lines.length].length - lines[0].length :
|
|
this.yylloc.first_column - len
|
|
};
|
|
|
|
if (this.options.ranges) {
|
|
this.yylloc.range = [r[0], r[0] + this.yyleng - len];
|
|
}
|
|
this.yyleng = this.yytext.length;
|
|
return this;
|
|
},
|
|
|
|
// When called from action, caches matched text and appends it on next action
|
|
more:function () {
|
|
this._more = true;
|
|
return this;
|
|
},
|
|
|
|
// When called from action, signals the lexer that this rule fails to match the input, so the next matching rule (regex) should be tested instead.
|
|
reject:function () {
|
|
if (this.options.backtrack_lexer) {
|
|
this._backtrack = true;
|
|
} else {
|
|
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n' + this.showPosition(), {
|
|
text: "",
|
|
token: null,
|
|
line: this.yylineno
|
|
});
|
|
|
|
}
|
|
return this;
|
|
},
|
|
|
|
// retain first n characters of the match
|
|
less:function (n) {
|
|
this.unput(this.match.slice(n));
|
|
},
|
|
|
|
// displays already matched input, i.e. for error messages
|
|
pastInput:function () {
|
|
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
|
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
|
},
|
|
|
|
// displays upcoming input, i.e. for error messages
|
|
upcomingInput:function () {
|
|
var next = this.match;
|
|
if (next.length < 20) {
|
|
next += this._input.substr(0, 20-next.length);
|
|
}
|
|
return (next.substr(0,20) + (next.length > 20 ? '...' : '')).replace(/\n/g, "");
|
|
},
|
|
|
|
// displays the character position where the lexing error occurred, i.e. for error messages
|
|
showPosition:function () {
|
|
var pre = this.pastInput();
|
|
var c = new Array(pre.length + 1).join("-");
|
|
return pre + this.upcomingInput() + "\n" + c + "^";
|
|
},
|
|
|
|
// test the lexed token: return FALSE when not a match, otherwise return token
|
|
test_match:function (match, indexed_rule) {
|
|
var token,
|
|
lines,
|
|
backup;
|
|
|
|
if (this.options.backtrack_lexer) {
|
|
// save context
|
|
backup = {
|
|
yylineno: this.yylineno,
|
|
yylloc: {
|
|
first_line: this.yylloc.first_line,
|
|
last_line: this.last_line,
|
|
first_column: this.yylloc.first_column,
|
|
last_column: this.yylloc.last_column
|
|
},
|
|
yytext: this.yytext,
|
|
match: this.match,
|
|
matches: this.matches,
|
|
matched: this.matched,
|
|
yyleng: this.yyleng,
|
|
offset: this.offset,
|
|
_more: this._more,
|
|
_input: this._input,
|
|
yy: this.yy,
|
|
conditionStack: this.conditionStack.slice(0),
|
|
done: this.done
|
|
};
|
|
if (this.options.ranges) {
|
|
backup.yylloc.range = this.yylloc.range.slice(0);
|
|
}
|
|
}
|
|
|
|
lines = match[0].match(/(?:\r\n?|\n).*/g);
|
|
if (lines) {
|
|
this.yylineno += lines.length;
|
|
}
|
|
this.yylloc = {
|
|
first_line: this.yylloc.last_line,
|
|
last_line: this.yylineno + 1,
|
|
first_column: this.yylloc.last_column,
|
|
last_column: lines ?
|
|
lines[lines.length - 1].length - lines[lines.length - 1].match(/\r?\n?/)[0].length :
|
|
this.yylloc.last_column + match[0].length
|
|
};
|
|
this.yytext += match[0];
|
|
this.match += match[0];
|
|
this.matches = match;
|
|
this.yyleng = this.yytext.length;
|
|
if (this.options.ranges) {
|
|
this.yylloc.range = [this.offset, this.offset += this.yyleng];
|
|
}
|
|
this._more = false;
|
|
this._backtrack = false;
|
|
this._input = this._input.slice(match[0].length);
|
|
this.matched += match[0];
|
|
token = this.performAction.call(this, this.yy, this, indexed_rule, this.conditionStack[this.conditionStack.length - 1]);
|
|
if (this.done && this._input) {
|
|
this.done = false;
|
|
}
|
|
if (token) {
|
|
return token;
|
|
} else if (this._backtrack) {
|
|
// recover context
|
|
for (var k in backup) {
|
|
this[k] = backup[k];
|
|
}
|
|
return false; // rule action called reject() implying the next rule should be tested instead.
|
|
}
|
|
return false;
|
|
},
|
|
|
|
// return next match in input
|
|
next:function () {
|
|
if (this.done) {
|
|
return this.EOF;
|
|
}
|
|
if (!this._input) {
|
|
this.done = true;
|
|
}
|
|
|
|
var token,
|
|
match,
|
|
tempMatch,
|
|
index;
|
|
if (!this._more) {
|
|
this.yytext = '';
|
|
this.match = '';
|
|
}
|
|
var rules = this._currentRules();
|
|
for (var i = 0; i < rules.length; i++) {
|
|
tempMatch = this._input.match(this.rules[rules[i]]);
|
|
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
|
match = tempMatch;
|
|
index = i;
|
|
if (this.options.backtrack_lexer) {
|
|
token = this.test_match(tempMatch, rules[i]);
|
|
if (token !== false) {
|
|
return token;
|
|
} else if (this._backtrack) {
|
|
match = false;
|
|
continue; // rule action called reject() implying a rule MISmatch.
|
|
} else {
|
|
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
|
|
return false;
|
|
}
|
|
} else if (!this.options.flex) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (match) {
|
|
token = this.test_match(match, rules[index]);
|
|
if (token !== false) {
|
|
return token;
|
|
}
|
|
// else: this is a lexer rule which consumes input without producing a token (e.g. whitespace)
|
|
return false;
|
|
}
|
|
if (this._input === "") {
|
|
return this.EOF;
|
|
} else {
|
|
return this.parseError('Lexical error on line ' + (this.yylineno + 1) + '. Unrecognized text.\n' + this.showPosition(), {
|
|
text: "",
|
|
token: null,
|
|
line: this.yylineno
|
|
});
|
|
}
|
|
},
|
|
|
|
// return next match that has a token
|
|
lex:function lex() {
|
|
var r = this.next();
|
|
if (r) {
|
|
return r;
|
|
} else {
|
|
return this.lex();
|
|
}
|
|
},
|
|
|
|
// activates a new lexer condition state (pushes the new lexer condition state onto the condition stack)
|
|
begin:function begin(condition) {
|
|
this.conditionStack.push(condition);
|
|
},
|
|
|
|
// pop the previously active lexer condition state off the condition stack
|
|
popState:function popState() {
|
|
var n = this.conditionStack.length - 1;
|
|
if (n > 0) {
|
|
return this.conditionStack.pop();
|
|
} else {
|
|
return this.conditionStack[0];
|
|
}
|
|
},
|
|
|
|
// produce the lexer rule set which is active for the currently active lexer condition state
|
|
_currentRules:function _currentRules() {
|
|
if (this.conditionStack.length && this.conditionStack[this.conditionStack.length - 1]) {
|
|
return this.conditions[this.conditionStack[this.conditionStack.length - 1]].rules;
|
|
} else {
|
|
return this.conditions["INITIAL"].rules;
|
|
}
|
|
},
|
|
|
|
// return the currently active lexer condition state; when an index argument is provided it produces the N-th previous condition state, if available
|
|
topState:function topState(n) {
|
|
n = this.conditionStack.length - 1 - Math.abs(n || 0);
|
|
if (n >= 0) {
|
|
return this.conditionStack[n];
|
|
} else {
|
|
return "INITIAL";
|
|
}
|
|
},
|
|
|
|
// alias for begin(condition)
|
|
pushState:function pushState(condition) {
|
|
this.begin(condition);
|
|
},
|
|
|
|
// return the number of states currently on the stack
|
|
stateStackSize:function stateStackSize() {
|
|
return this.conditionStack.length;
|
|
},
|
|
options: {},
|
|
performAction: function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
|
var YYSTATE=YY_START;
|
|
switch($avoiding_name_collisions) {
|
|
case 0: this.begin('notes'); return 19;
|
|
break;
|
|
case 1: this.begin('options'); return 13;
|
|
break;
|
|
case 2: this.begin('options'); return 14;
|
|
break;
|
|
case 3: this.begin('options'); return 15;
|
|
break;
|
|
case 4: this.begin('options'); return 11;
|
|
break;
|
|
case 5: this.begin('text'); return 17;
|
|
break;
|
|
case 6: this.begin('options'); return 21;
|
|
break;
|
|
case 7:return 22
|
|
break;
|
|
case 8: this.begin('annotations'); return "$"
|
|
break;
|
|
case 9: this.begin('notes'); return "$"
|
|
break;
|
|
case 10:return 22
|
|
break;
|
|
case 11: this.begin('command'); return "!"
|
|
break;
|
|
case 12: this.begin('notes'); return "!"
|
|
break;
|
|
case 13:return 74
|
|
break;
|
|
case 14:return 24
|
|
break;
|
|
case 15:return 41
|
|
break;
|
|
case 16:return '+'
|
|
break;
|
|
case 17:return 38
|
|
break;
|
|
case 18:return 23
|
|
break;
|
|
case 19:return 45
|
|
break;
|
|
case 20:return 46
|
|
break;
|
|
case 21:return 31
|
|
break;
|
|
case 22:return 32
|
|
break;
|
|
case 23:return 70
|
|
break;
|
|
case 24:return 25
|
|
break;
|
|
case 25:return 37
|
|
break;
|
|
case 26:return 44
|
|
break;
|
|
case 27:return 75
|
|
break;
|
|
case 28:return 79
|
|
break;
|
|
case 29:return 65
|
|
break;
|
|
case 30:return 62
|
|
break;
|
|
case 31:return 57
|
|
break;
|
|
case 32:return 66
|
|
break;
|
|
case 33:return 63
|
|
break;
|
|
case 34:return 64
|
|
break;
|
|
case 35:return 61
|
|
break;
|
|
case 36:return 50
|
|
break;
|
|
case 37:return 67
|
|
break;
|
|
case 38:return 68
|
|
break;
|
|
case 39:return 69
|
|
break;
|
|
case 40:return 59
|
|
break;
|
|
case 41:return 48
|
|
break;
|
|
case 42:return 58
|
|
break;
|
|
case 43:return 56
|
|
break;
|
|
case 44:return 57
|
|
break;
|
|
case 45:return 59
|
|
break;
|
|
case 46:return 60
|
|
break;
|
|
case 47:return 76
|
|
break;
|
|
case 48:return 80
|
|
break;
|
|
case 49:return 81
|
|
break;
|
|
case 50: this.begin('INITIAL');
|
|
break;
|
|
case 51:/* skip whitespace */
|
|
break;
|
|
case 52:return 5
|
|
break;
|
|
case 53:return 'INVALID'
|
|
break;
|
|
}
|
|
},
|
|
rules: [/^(?:notes\b)/,/^(?:tabstave\b)/,/^(?:stave\b)/,/^(?:voice\b)/,/^(?:options\b)/,/^(?:text\b)/,/^(?:slur\b)/,/^(?:[^\s=]+)/,/^(?:[$])/,/^(?:[$])/,/^(?:[^,$]+)/,/^(?:[!])/,/^(?:[!])/,/^(?:[^!]+)/,/^(?:[^,\r\n]+)/,/^(?:\/)/,/^(?:\+)/,/^(?::)/,/^(?:=)/,/^(?:\()/,/^(?:\))/,/^(?:\[)/,/^(?:\])/,/^(?:\^)/,/^(?:,)/,/^(?:\|)/,/^(?:\.)/,/^(?:#)/,/^(?:@)/,/^(?:[b])/,/^(?:[s])/,/^(?:[h])/,/^(?:[p])/,/^(?:[t])/,/^(?:[T])/,/^(?:[-])/,/^(?:[_])/,/^(?:[v])/,/^(?:[V])/,/^(?:[u])/,/^(?:[d])/,/^(?:[0-9]+)/,/^(?:[q])/,/^(?:[w])/,/^(?:[h])/,/^(?:[d])/,/^(?:[S])/,/^(?:[A-GXLR])/,/^(?:[n])/,/^(?:[~])/,/^(?:[\r\n]+)/,/^(?:\s+)/,/^(?:$)/,/^(?:.)/],
|
|
conditions: {"notes":{"rules":[8,11,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53],"inclusive":true},"text":{"rules":[14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,41,42,43,44,45,50,51,52,53],"inclusive":true},"slur":{"rules":[15,16,17,18,19,20,21,22,23,24,25,26,27,28,50,51,52,53],"inclusive":true},"annotations":{"rules":[9,10,15,16,17,18,19,20,21,22,23,24,25,26,27,28,50,51,52,53],"inclusive":true},"options":{"rules":[7,15,16,17,18,19,20,21,22,23,24,25,26,27,28,50,51,52,53],"inclusive":true},"command":{"rules":[12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,50,51,52,53],"inclusive":true},"INITIAL":{"rules":[0,1,2,3,4,5,6,7,15,16,17,18,19,20,21,22,23,24,25,26,27,28,50,51,52,53],"inclusive":true}}
|
|
});
|
|
return lexer;
|
|
})();
|
|
parser.lexer = lexer;
|
|
function Parser () {
|
|
this.yy = {};
|
|
}
|
|
Parser.prototype = parser;parser.Parser = Parser;
|
|
return new Parser;
|
|
})();
|
|
|
|
|
|
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
|
exports.parser = parser;
|
|
exports.Parser = parser.Parser;
|
|
exports.parse = function () { return parser.parse.apply(parser, arguments); };
|
|
exports.main = function commonjsMain(args) {
|
|
if (!args[1]) {
|
|
console.log('Usage: '+args[0]+' FILE');
|
|
process.exit(1);
|
|
}
|
|
var source = require('fs').readFileSync(require('path').normalize(args[1]), "utf8");
|
|
return exports.parser.parse(source);
|
|
};
|
|
if (typeof module !== 'undefined' && require.main === module) {
|
|
exports.main(process.argv.slice(1));
|
|
}
|
|
}/**
|
|
* VexFlow TabDiv
|
|
* Copyright Mohit Muthanna 2010 <mohit@muthanna.com>
|
|
*/
|
|
|
|
Vex.Flow.TabDiv = function(sel, options) {
|
|
if (arguments.length > 0) this.init(sel, options);
|
|
}
|
|
|
|
Vex.Flow.TabDiv.SEL = ".vex-tabdiv";
|
|
Vex.Flow.TabDiv.ERROR_NOCANVAS =
|
|
"<b>This browser does not support HTML5 Canvas</b><br/>" +
|
|
"Please use a modern browser such as <a href='http://google.com/chrome'>" +
|
|
"Google Chrome</a> or <a href='http://firefox.com'>Firefox</a>.";
|
|
|
|
Vex.Flow.TabDiv.prototype.init = function(sel, options) {
|
|
this.sel = sel;
|
|
|
|
// Grab code and clear tabdiv
|
|
this.code = $(sel).text();
|
|
$(sel).empty();
|
|
if ($(sel).css("position") == "static") {
|
|
$(sel).css("position", "relative");
|
|
}
|
|
|
|
// Get tabdiv properties
|
|
this.width = parseInt($(sel).attr("width")) || 400;
|
|
this.height = parseInt($(sel).attr("height")) || 200;
|
|
this.scale = parseFloat($(sel).attr("scale")) || 1.0;
|
|
|
|
// If the Raphael.js sources are included, then use Raphael, else
|
|
// resort to HTML5 Canvas.
|
|
if (typeof (Raphael) == "undefined") {
|
|
this.canvas = $('<canvas></canvas>').addClass("vex-canvas");
|
|
$(sel).append(this.canvas);
|
|
this.renderer = new Vex.Flow.Renderer(this.canvas[0],
|
|
Vex.Flow.Renderer.Backends.CANVAS);
|
|
} else {
|
|
this.canvas = $('<div></div>').addClass("vex-canvas");
|
|
$(sel).append(this.canvas);
|
|
this.renderer = new Vex.Flow.Renderer(this.canvas[0],
|
|
Vex.Flow.Renderer.Backends.RAPHAEL);
|
|
}
|
|
|
|
this.ctx_sel = $(sel).find(".vex-canvas");
|
|
this.renderer.resize(this.width, this.height);
|
|
this.ctx = this.renderer.getContext();
|
|
this.ctx.setBackgroundFillStyle(this.ctx_sel.css("background-color"));
|
|
this.ctx.scale(this.scale, this.scale);
|
|
|
|
// Grab editor properties
|
|
this.editor = $(sel).attr("editor") || "";
|
|
this.show_errors = $(sel).attr("show-errors") || "";
|
|
this.editor_width= $(sel).attr("editor_width") || this.width;
|
|
this.editor_height= $(sel).attr("editor_height") || 200;
|
|
|
|
var that = this;
|
|
if (this.editor == "true") {
|
|
this.text_area = $('<textarea></textarea>').addClass("editor").
|
|
val(this.code);
|
|
this.editor_error = $('<div></div>').addClass("editor-error");
|
|
$(sel).append($('<p/>')).append(this.editor_error);
|
|
$(sel).append($('<p/>')).append(this.text_area);
|
|
this.text_area.width(this.editor_width);
|
|
this.text_area.height(this.editor_height);
|
|
this.text_area.keyup(function() {
|
|
if (that.timeoutID) window.clearTimeout(that.timeoutID);
|
|
that.timeoutID =
|
|
window.setTimeout(function() {
|
|
// Draw only if code changed
|
|
if (that.code != that.text_area.val()) {
|
|
that.code = that.text_area.val();
|
|
that.redraw()
|
|
}
|
|
}, 250);
|
|
});
|
|
} if (this.show_errors == "true") {
|
|
this.editor_error = $('<div></div>').addClass("editor-error");
|
|
$(sel).append($('<p/>')).append(this.editor_error);
|
|
}
|
|
|
|
// Initialize parser.
|
|
this.artist = new Vex.Flow.Artist(10, 0, this.width, {scale: this.scale});
|
|
this.parser = new Vex.Flow.VexTab(this.artist);
|
|
|
|
if (Vex.Flow.Player) {
|
|
opts = {};
|
|
if (options) opts.soundfont_url = options.soundfont_url;
|
|
this.player = new Vex.Flow.Player(this.artist, opts);
|
|
}
|
|
|
|
this.redraw();
|
|
}
|
|
|
|
Vex.Flow.TabDiv.prototype.redraw = function() {
|
|
var that = this;
|
|
Vex.BM("Total render time: ", function() {
|
|
that.parse(); that.draw();});
|
|
|
|
return this;
|
|
}
|
|
|
|
Vex.Flow.TabDiv.prototype.drawInternal = function() {
|
|
if (!this.parser.isValid()) return this;
|
|
return this.artist.draw(this.renderer);
|
|
}
|
|
|
|
Vex.Flow.TabDiv.prototype.parseInternal = function() {
|
|
try {
|
|
this.artist.reset();
|
|
this.parser.reset();
|
|
this.parser.parse(this.code);
|
|
this.editor_error.empty();
|
|
} catch (e) {
|
|
if (this.editor_error) {
|
|
this.editor_error.empty();
|
|
this.editor_error.append(
|
|
$('<div></div>').addClass("text").html(
|
|
"Sucky VexTab: " + e.message));
|
|
}
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Vex.Flow.TabDiv.prototype.parse = function() {
|
|
var that = this;
|
|
Vex.BM("Parse time: ", function() { that.parseInternal(); });
|
|
return this;
|
|
}
|
|
|
|
Vex.Flow.TabDiv.prototype.draw = function() {
|
|
var that = this;
|
|
Vex.BM("Draw time: ", function() { that.drawInternal(); });
|
|
return this;
|
|
}
|
|
|
|
// Automatic initialization.
|
|
Vex.Flow.TabDiv.start = function() {
|
|
$(Vex.Flow.TabDiv.SEL).each(function(index) {
|
|
new Vex.Flow.TabDiv(this);
|
|
});
|
|
}
|
|
|
|
$(function() {if (Vex.Flow.TabDiv.SEL) { Vex.Flow.TabDiv.start() }});
|
|
// Generated by CoffeeScript 1.8.0
|
|
(function() {
|
|
var __slice = [].slice,
|
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
|
|
|
Vex.Flow.Artist = (function() {
|
|
var L, formatAndRender, getFingering, getScoreArticulationParts, getStrokeParts, makeBend, makeDuration, parseBool;
|
|
|
|
Artist.DEBUG = false;
|
|
|
|
L = function() {
|
|
var args;
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
if (Vex.Flow.Artist.DEBUG) {
|
|
return typeof console !== "undefined" && console !== null ? console.log.apply(console, ["(Vex.Flow.Artist)"].concat(__slice.call(args))) : void 0;
|
|
}
|
|
};
|
|
|
|
Artist.NOLOGO = false;
|
|
|
|
function Artist(x, y, width, options) {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.width = width;
|
|
this.options = {
|
|
font_face: "Arial",
|
|
font_size: 10,
|
|
font_style: null,
|
|
bottom_spacing: 20 + (Vex.Flow.Artist.NOLOGO ? 0 : 10),
|
|
tab_stave_lower_spacing: 10,
|
|
note_stave_lower_spacing: 0,
|
|
scale: 1.0
|
|
};
|
|
if (options != null) {
|
|
_.extend(this.options, options);
|
|
}
|
|
this.reset();
|
|
}
|
|
|
|
Artist.prototype.reset = function() {
|
|
this.tuning = new Vex.Flow.Tuning();
|
|
this.key_manager = new Vex.Flow.KeyManager("C");
|
|
this.music_api = new Vex.Flow.Music();
|
|
this.customizations = {
|
|
"font-size": this.options.font_size,
|
|
"font-face": this.options.font_face,
|
|
"font-style": this.options.font_style,
|
|
"annotation-position": "bottom",
|
|
"scale": this.options.scale,
|
|
"width": this.width,
|
|
"stave-distance": 0,
|
|
"space": 0,
|
|
"player": "false",
|
|
"tempo": 120,
|
|
"instrument": "acoustic_grand_piano",
|
|
"accidentals": "standard",
|
|
"tab-stems": "false",
|
|
"tab-stem-direction": "up",
|
|
"beam-rests": "true",
|
|
"beam-stemlets": "true",
|
|
"beam-middle-only": "false",
|
|
"connector-space": 0
|
|
};
|
|
this.staves = [];
|
|
this.tab_articulations = [];
|
|
this.stave_articulations = [];
|
|
this.player_voices = [];
|
|
this.last_y = this.y;
|
|
this.current_duration = "q";
|
|
this.current_clef = "treble";
|
|
this.current_bends = {};
|
|
this.current_octave_shift = 0;
|
|
this.bend_start_index = null;
|
|
this.bend_start_strings = null;
|
|
this.rendered = false;
|
|
return this.renderer_context = null;
|
|
};
|
|
|
|
Artist.prototype.attachPlayer = function(player) {
|
|
return this.player = player;
|
|
};
|
|
|
|
Artist.prototype.setOptions = function(options) {
|
|
var k, v, valid_options;
|
|
L("setOptions: ", options);
|
|
valid_options = _.keys(this.customizations);
|
|
for (k in options) {
|
|
v = options[k];
|
|
if (__indexOf.call(valid_options, k) >= 0) {
|
|
this.customizations[k] = v;
|
|
} else {
|
|
throw new Vex.RERR("ArtistError", "Invalid option '" + k + "'");
|
|
}
|
|
}
|
|
this.last_y += parseInt(this.customizations.space, 10);
|
|
if (this.customizations.player === "true") {
|
|
return this.last_y += 15;
|
|
}
|
|
};
|
|
|
|
Artist.prototype.getPlayerData = function() {
|
|
return {
|
|
voices: this.player_voices,
|
|
context: this.renderer_context,
|
|
scale: this.customizations.scale
|
|
};
|
|
};
|
|
|
|
parseBool = function(str) {
|
|
return str === "true";
|
|
};
|
|
|
|
formatAndRender = function(ctx, tab, score, text_notes, customizations, options) {
|
|
var align_rests, beam_config, beams, format_stave, format_voices, formatter, i, multi_voice, notes, score_stave, score_voices, stem_direction, tab_stave, tab_voices, text_stave, text_voices, voice, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
|
|
if (tab != null) {
|
|
tab_stave = tab.stave;
|
|
}
|
|
if (score != null) {
|
|
score_stave = score.stave;
|
|
}
|
|
tab_voices = [];
|
|
score_voices = [];
|
|
text_voices = [];
|
|
beams = [];
|
|
format_stave = null;
|
|
text_stave = null;
|
|
beam_config = {
|
|
beam_rests: parseBool(customizations["beam-rests"]),
|
|
show_stemlets: parseBool(customizations["beam-stemlets"]),
|
|
beam_middle_only: parseBool(customizations["beam-middle-only"]),
|
|
groups: options.beam_groups
|
|
};
|
|
if (tab != null) {
|
|
multi_voice = tab.voices.length > 1 ? true : false;
|
|
_ref = tab.voices;
|
|
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
|
notes = _ref[i];
|
|
if (_.isEmpty(notes)) {
|
|
continue;
|
|
}
|
|
_.each(notes, function(note) {
|
|
return note.setStave(tab_stave);
|
|
});
|
|
voice = new Vex.Flow.Voice(Vex.Flow.TIME4_4).setMode(Vex.Flow.Voice.Mode.SOFT);
|
|
voice.addTickables(notes);
|
|
tab_voices.push(voice);
|
|
if (customizations["tab-stems"] === "true") {
|
|
if (multi_voice) {
|
|
beam_config.stem_direction = i === 0 ? 1 : -1;
|
|
} else {
|
|
beam_config.stem_direction = customizations["tab-stem-direction"] === "down" ? -1 : 1;
|
|
}
|
|
beam_config.beam_rests = false;
|
|
beams = beams.concat(Vex.Flow.Beam.generateBeams(voice.getTickables(), beam_config));
|
|
}
|
|
}
|
|
format_stave = tab_stave;
|
|
text_stave = tab_stave;
|
|
}
|
|
beam_config.beam_rests = parseBool(customizations["beam-rests"]);
|
|
if (score != null) {
|
|
multi_voice = score.voices.length > 1 ? true : false;
|
|
_ref1 = score.voices;
|
|
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
|
|
notes = _ref1[i];
|
|
if (_.isEmpty(notes)) {
|
|
continue;
|
|
}
|
|
stem_direction = i === 0 ? 1 : -1;
|
|
_.each(notes, function(note) {
|
|
return note.setStave(score_stave);
|
|
});
|
|
voice = new Vex.Flow.Voice(Vex.Flow.TIME4_4).setMode(Vex.Flow.Voice.Mode.SOFT);
|
|
voice.addTickables(notes);
|
|
score_voices.push(voice);
|
|
if (multi_voice) {
|
|
beam_config.stem_direction = stem_direction;
|
|
beams = beams.concat(Vex.Flow.Beam.generateBeams(notes, beam_config));
|
|
} else {
|
|
beam_config.stem_direction = null;
|
|
beams = beams.concat(Vex.Flow.Beam.generateBeams(notes, beam_config));
|
|
}
|
|
}
|
|
format_stave = score_stave;
|
|
text_stave = score_stave;
|
|
}
|
|
for (_k = 0, _len2 = text_notes.length; _k < _len2; _k++) {
|
|
notes = text_notes[_k];
|
|
if (_.isEmpty(notes)) {
|
|
continue;
|
|
}
|
|
_.each(notes, function(voice) {
|
|
return voice.setStave(text_stave);
|
|
});
|
|
voice = new Vex.Flow.Voice(Vex.Flow.TIME4_4).setMode(Vex.Flow.Voice.Mode.SOFT);
|
|
voice.addTickables(notes);
|
|
text_voices.push(voice);
|
|
}
|
|
if (format_stave != null) {
|
|
format_voices = [];
|
|
formatter = new Vex.Flow.Formatter();
|
|
align_rests = false;
|
|
if (tab != null) {
|
|
if (!_.isEmpty(tab_voices)) {
|
|
formatter.joinVoices(tab_voices);
|
|
}
|
|
format_voices = tab_voices;
|
|
}
|
|
if (score != null) {
|
|
if (!_.isEmpty(score_voices)) {
|
|
formatter.joinVoices(score_voices);
|
|
}
|
|
format_voices = format_voices.concat(score_voices);
|
|
if (score_voices.length > 1) {
|
|
align_rests = true;
|
|
}
|
|
}
|
|
if (!_.isEmpty(text_notes) && !_.isEmpty(text_voices)) {
|
|
formatter.joinVoices(text_voices);
|
|
format_voices = format_voices.concat(text_voices);
|
|
}
|
|
if (!_.isEmpty(format_voices)) {
|
|
formatter.formatToStave(format_voices, format_stave, {
|
|
align_rests: align_rests
|
|
});
|
|
}
|
|
if (tab != null) {
|
|
_.each(tab_voices, function(voice) {
|
|
return voice.draw(ctx, tab_stave);
|
|
});
|
|
}
|
|
if (score != null) {
|
|
_.each(score_voices, function(voice) {
|
|
return voice.draw(ctx, score_stave);
|
|
});
|
|
}
|
|
_.each(beams, function(beam) {
|
|
return beam.setContext(ctx).draw();
|
|
});
|
|
if (!_.isEmpty(text_notes)) {
|
|
_.each(text_voices, function(voice) {
|
|
return voice.draw(ctx, text_stave);
|
|
});
|
|
}
|
|
if ((tab != null) && (score != null)) {
|
|
(new Vex.Flow.StaveConnector(score.stave, tab.stave)).setContext(ctx).draw();
|
|
}
|
|
if (score != null) {
|
|
return score_voices;
|
|
} else {
|
|
return tab_voices;
|
|
}
|
|
}
|
|
};
|
|
|
|
Artist.prototype.render = function(renderer) {
|
|
var LOGO, articulation, ctx, setBar, stave, voices, width, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
|
|
L("Render: ", this.options);
|
|
this.closeBends();
|
|
renderer.resize(this.customizations.width * this.customizations.scale, (this.last_y + this.options.bottom_spacing) * this.customizations.scale);
|
|
ctx = renderer.getContext();
|
|
ctx.scale(this.customizations.scale, this.customizations.scale);
|
|
ctx.clear();
|
|
ctx.setFont(this.options.font_face, this.options.font_size, "");
|
|
this.renderer_context = ctx;
|
|
setBar = function(stave, notes) {
|
|
var last_note;
|
|
last_note = _.last(notes);
|
|
if (last_note instanceof Vex.Flow.BarNote) {
|
|
notes.pop();
|
|
return stave.setEndBarType(last_note.getType());
|
|
}
|
|
};
|
|
_ref = this.staves;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
stave = _ref[_i];
|
|
L("Rendering staves.");
|
|
if (stave.tab != null) {
|
|
setBar(stave.tab, stave.tab_notes);
|
|
}
|
|
if (stave.note != null) {
|
|
setBar(stave.note, stave.note_notes);
|
|
}
|
|
if (stave.tab != null) {
|
|
stave.tab.setContext(ctx).draw();
|
|
}
|
|
if (stave.note != null) {
|
|
stave.note.setContext(ctx).draw();
|
|
}
|
|
stave.tab_voices.push(stave.tab_notes);
|
|
stave.note_voices.push(stave.note_notes);
|
|
voices = formatAndRender(ctx, stave.tab != null ? {
|
|
stave: stave.tab,
|
|
voices: stave.tab_voices
|
|
} : null, stave.note != null ? {
|
|
stave: stave.note,
|
|
voices: stave.note_voices
|
|
} : null, stave.text_voices, this.customizations, {
|
|
beam_groups: stave.beam_groups
|
|
});
|
|
this.player_voices.push(voices);
|
|
}
|
|
L("Rendering tab articulations.");
|
|
_ref1 = this.tab_articulations;
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
articulation = _ref1[_j];
|
|
articulation.setContext(ctx).draw();
|
|
}
|
|
L("Rendering note articulations.");
|
|
_ref2 = this.stave_articulations;
|
|
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
|
|
articulation = _ref2[_k];
|
|
articulation.setContext(ctx).draw();
|
|
}
|
|
if (this.player != null) {
|
|
if (this.customizations.player === "true") {
|
|
this.player.setTempo(parseInt(this.customizations.tempo, 10));
|
|
this.player.setInstrument(this.customizations.instrument);
|
|
this.player.render();
|
|
} else {
|
|
this.player.removeControls();
|
|
}
|
|
}
|
|
this.rendered = true;
|
|
if (!Vex.Flow.Artist.NOLOGO) {
|
|
LOGO = "vexflow.com";
|
|
width = ctx.measureText(LOGO).width;
|
|
ctx.save();
|
|
ctx.setFont("Times", 10, "italic");
|
|
ctx.fillText(LOGO, (this.customizations.width - width) / 2, this.last_y + 25);
|
|
return ctx.restore();
|
|
}
|
|
};
|
|
|
|
Artist.prototype.isRendered = function() {
|
|
return this.rendered;
|
|
};
|
|
|
|
Artist.prototype.draw = function(renderer) {
|
|
return this.render(renderer);
|
|
};
|
|
|
|
Artist.prototype.getNoteForFret = function(fret, string) {
|
|
var accidental, new_note, new_octave, new_root, old_root, selected_note, spec, spec_props;
|
|
spec = this.tuning.getNoteForFret(fret, string);
|
|
spec_props = Vex.Flow.keyProperties(spec);
|
|
selected_note = this.key_manager.selectNote(spec_props.key);
|
|
accidental = null;
|
|
switch (this.customizations.accidentals) {
|
|
case "standard":
|
|
if (selected_note.change) {
|
|
accidental = selected_note.accidental != null ? selected_note.accidental : "n";
|
|
}
|
|
break;
|
|
case "cautionary":
|
|
if (selected_note.change) {
|
|
accidental = selected_note.accidental != null ? selected_note.accidental : "n";
|
|
} else {
|
|
accidental = selected_note.accidental != null ? selected_note.accidental + "_c" : void 0;
|
|
}
|
|
break;
|
|
default:
|
|
throw new Vex.RERR("ArtistError", "Invalid value for option 'accidentals': " + this.customizations.accidentals);
|
|
}
|
|
new_note = selected_note.note;
|
|
new_octave = spec_props.octave;
|
|
old_root = this.music_api.getNoteParts(spec_props.key).root;
|
|
new_root = this.music_api.getNoteParts(selected_note.note).root;
|
|
if (new_root === "b" && old_root === "c") {
|
|
new_octave--;
|
|
} else if (new_root === "c" && old_root === "b") {
|
|
new_octave++;
|
|
}
|
|
return [new_note, new_octave, accidental];
|
|
};
|
|
|
|
Artist.prototype.getNoteForABC = function(abc, string) {
|
|
var accidental, key, octave;
|
|
key = abc.key;
|
|
octave = string;
|
|
accidental = abc.accidental;
|
|
if (abc.accidental_type != null) {
|
|
accidental += "_" + abc.accidental_type;
|
|
}
|
|
return [key, octave, accidental];
|
|
};
|
|
|
|
Artist.prototype.addStaveNote = function(note_params) {
|
|
var acc, index, new_accidental, params, parts, stave_note, stave_notes, _i, _len, _ref;
|
|
params = {
|
|
is_rest: false,
|
|
play_note: null
|
|
};
|
|
_.extend(params, note_params);
|
|
stave_notes = _.last(this.staves).note_notes;
|
|
stave_note = new Vex.Flow.StaveNote({
|
|
keys: params.spec,
|
|
duration: this.current_duration + (params.is_rest ? "r" : ""),
|
|
clef: params.is_rest ? "treble" : this.current_clef,
|
|
auto_stem: params.is_rest ? false : true
|
|
});
|
|
_ref = params.accidentals;
|
|
for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
|
|
acc = _ref[index];
|
|
if (acc != null) {
|
|
parts = acc.split("_");
|
|
new_accidental = new Vex.Flow.Accidental(parts[0]);
|
|
if (parts.length > 1 && parts[1] === "c") {
|
|
new_accidental.setAsCautionary();
|
|
}
|
|
stave_note.addAccidental(index, new_accidental);
|
|
}
|
|
}
|
|
if (this.current_duration[this.current_duration.length - 1] === "d") {
|
|
stave_note.addDotToAll();
|
|
}
|
|
if (params.play_note != null) {
|
|
stave_note.setPlayNote(params.play_note);
|
|
}
|
|
return stave_notes.push(stave_note);
|
|
};
|
|
|
|
Artist.prototype.addTabNote = function(spec, play_note) {
|
|
var new_tab_note, tab_notes;
|
|
if (play_note == null) {
|
|
play_note = null;
|
|
}
|
|
tab_notes = _.last(this.staves).tab_notes;
|
|
new_tab_note = new Vex.Flow.TabNote({
|
|
positions: spec,
|
|
duration: this.current_duration
|
|
}, this.customizations["tab-stems"] === "true");
|
|
if (play_note != null) {
|
|
new_tab_note.setPlayNote(play_note);
|
|
}
|
|
tab_notes.push(new_tab_note);
|
|
if (this.current_duration[this.current_duration.length - 1] === "d") {
|
|
return new_tab_note.addDot();
|
|
}
|
|
};
|
|
|
|
makeDuration = function(time, dot) {
|
|
return time + (dot ? "d" : "");
|
|
};
|
|
|
|
Artist.prototype.setDuration = function(time, dot) {
|
|
var t;
|
|
if (dot == null) {
|
|
dot = false;
|
|
}
|
|
t = time.split(/\s+/);
|
|
L("setDuration: ", t[0], dot);
|
|
return this.current_duration = makeDuration(t[0], dot);
|
|
};
|
|
|
|
Artist.prototype.addBar = function(type) {
|
|
var TYPE, bar_note, stave;
|
|
L("addBar: ", type);
|
|
this.closeBends();
|
|
this.key_manager.reset();
|
|
stave = _.last(this.staves);
|
|
TYPE = Vex.Flow.Barline.type;
|
|
type = (function() {
|
|
switch (type) {
|
|
case "single":
|
|
return TYPE.SINGLE;
|
|
case "double":
|
|
return TYPE.DOUBLE;
|
|
case "end":
|
|
return TYPE.END;
|
|
case "repeat-begin":
|
|
return TYPE.REPEAT_BEGIN;
|
|
case "repeat-end":
|
|
return TYPE.REPEAT_END;
|
|
case "repeat-both":
|
|
return TYPE.REPEAT_BOTH;
|
|
default:
|
|
return TYPE.SINGLE;
|
|
}
|
|
})();
|
|
bar_note = new Vex.Flow.BarNote().setType(type);
|
|
stave.tab_notes.push(bar_note);
|
|
if (stave.note != null) {
|
|
return stave.note_notes.push(bar_note);
|
|
}
|
|
};
|
|
|
|
makeBend = function(from_fret, to_fret) {
|
|
var direction, text;
|
|
direction = Vex.Flow.Bend.UP;
|
|
text = "";
|
|
if (parseInt(from_fret, 10) > parseInt(to_fret, 10)) {
|
|
direction = Vex.Flow.Bend.DOWN;
|
|
} else {
|
|
text = (function() {
|
|
switch (Math.abs(to_fret - from_fret)) {
|
|
case 1:
|
|
return "1/2";
|
|
case 2:
|
|
return "Full";
|
|
case 3:
|
|
return "1 1/2";
|
|
default:
|
|
return "Bend to " + to_fret;
|
|
}
|
|
})();
|
|
}
|
|
return {
|
|
type: direction,
|
|
text: text
|
|
};
|
|
};
|
|
|
|
Artist.prototype.openBends = function(first_note, last_note, first_indices, last_indices) {
|
|
var first_frets, from_fret, i, index, last_frets, last_index, start_indices, start_note, tab_notes, to_fret, _base, _i, _len, _results;
|
|
L("openBends", first_note, last_note, first_indices, last_indices);
|
|
tab_notes = _.last(this.staves).tab_notes;
|
|
start_note = first_note;
|
|
start_indices = first_indices;
|
|
if (_.isEmpty(this.current_bends)) {
|
|
this.bend_start_index = tab_notes.length - 2;
|
|
this.bend_start_strings = first_indices;
|
|
} else {
|
|
start_note = tab_notes[this.bend_start_index];
|
|
start_indices = this.bend_start_strings;
|
|
}
|
|
first_frets = start_note.getPositions();
|
|
last_frets = last_note.getPositions();
|
|
_results = [];
|
|
for (i = _i = 0, _len = start_indices.length; _i < _len; i = ++_i) {
|
|
index = start_indices[i];
|
|
last_index = last_indices[i];
|
|
from_fret = first_note.getPositions()[first_indices[i]];
|
|
to_fret = last_frets[last_index];
|
|
if ((_base = this.current_bends)[index] == null) {
|
|
_base[index] = [];
|
|
}
|
|
_results.push(this.current_bends[index].push(makeBend(from_fret.fret, to_fret.fret)));
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
Artist.prototype.closeBends = function(offset) {
|
|
var bend, k, phrase, tab_note, tab_notes, v, _i, _j, _len, _len1, _ref, _ref1;
|
|
if (offset == null) {
|
|
offset = 1;
|
|
}
|
|
if (this.bend_start_index == null) {
|
|
return;
|
|
}
|
|
L("closeBends(" + offset + ")");
|
|
tab_notes = _.last(this.staves).tab_notes;
|
|
_ref = this.current_bends;
|
|
for (k in _ref) {
|
|
v = _ref[k];
|
|
phrase = [];
|
|
for (_i = 0, _len = v.length; _i < _len; _i++) {
|
|
bend = v[_i];
|
|
phrase.push(bend);
|
|
}
|
|
tab_notes[this.bend_start_index].addModifier(new Vex.Flow.Bend(null, null, phrase), k);
|
|
}
|
|
_ref1 = tab_notes.slice(this.bend_start_index + 1, +((tab_notes.length - 2) + offset) + 1 || 9e9);
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
tab_note = _ref1[_j];
|
|
tab_note.setGhost(true);
|
|
}
|
|
this.current_bends = {};
|
|
return this.bend_start_index = null;
|
|
};
|
|
|
|
Artist.prototype.makeTuplets = function(tuplets, notes) {
|
|
var modifier, stave_notes, tab_modifier, tab_notes;
|
|
L("makeTuplets", tuplets, notes);
|
|
if (notes == null) {
|
|
notes = tuplets;
|
|
}
|
|
if (!_.last(this.staves).note) {
|
|
return;
|
|
}
|
|
stave_notes = _.last(this.staves).note_notes;
|
|
tab_notes = _.last(this.staves).tab_notes;
|
|
if (stave_notes.length < notes) {
|
|
throw new Vex.RERR("ArtistError", "Not enough notes for tuplet");
|
|
}
|
|
modifier = new Vex.Flow.Tuplet(stave_notes.slice(stave_notes.length - notes), {
|
|
num_notes: tuplets
|
|
});
|
|
this.stave_articulations.push(modifier);
|
|
tab_modifier = new Vex.Flow.Tuplet(tab_notes.slice(tab_notes.length - notes), {
|
|
num_notes: tuplets
|
|
});
|
|
if (this.customizations["tab-stems"] === "true") {
|
|
return this.tab_articulations.push(tab_modifier);
|
|
}
|
|
};
|
|
|
|
getFingering = function(text) {
|
|
return text.match(/^\.fingering\/([^.]+)\./);
|
|
};
|
|
|
|
Artist.prototype.makeFingering = function(text) {
|
|
var POS, badFingering, finger, fingering, fingers, modifier, note_number, number, p, parts, pieces, position, _i, _len;
|
|
parts = getFingering(text);
|
|
POS = Vex.Flow.Modifier.Position;
|
|
fingers = [];
|
|
fingering = [];
|
|
if (parts != null) {
|
|
fingers = (function() {
|
|
var _i, _len, _ref, _results;
|
|
_ref = parts[1].split(/-/);
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
p = _ref[_i];
|
|
_results.push(p.trim());
|
|
}
|
|
return _results;
|
|
})();
|
|
} else {
|
|
return null;
|
|
}
|
|
badFingering = function() {
|
|
return new Vex.RERR("ArtistError", "Bad fingering: " + parts[1]);
|
|
};
|
|
for (_i = 0, _len = fingers.length; _i < _len; _i++) {
|
|
finger = fingers[_i];
|
|
pieces = finger.match(/(\d+):([ablr]):([fs]):([^-.]+)/);
|
|
if (pieces == null) {
|
|
throw badFingering();
|
|
}
|
|
note_number = parseInt(pieces[1], 10) - 1;
|
|
position = POS.RIGHT;
|
|
switch (pieces[2]) {
|
|
case "l":
|
|
position = POS.LEFT;
|
|
break;
|
|
case "r":
|
|
position = POS.RIGHT;
|
|
break;
|
|
case "a":
|
|
position = POS.ABOVE;
|
|
break;
|
|
case "b":
|
|
position = POS.BELOW;
|
|
}
|
|
modifier = null;
|
|
number = pieces[4];
|
|
switch (pieces[3]) {
|
|
case "s":
|
|
modifier = new Vex.Flow.StringNumber(number).setPosition(position);
|
|
break;
|
|
case "f":
|
|
modifier = new Vex.Flow.FretHandFinger(number).setPosition(position);
|
|
}
|
|
fingering.push({
|
|
num: note_number,
|
|
modifier: modifier
|
|
});
|
|
}
|
|
return fingering;
|
|
};
|
|
|
|
getStrokeParts = function(text) {
|
|
return text.match(/^\.stroke\/([^.]+)\./);
|
|
};
|
|
|
|
Artist.prototype.makeStroke = function(text) {
|
|
var TYPE, parts, type;
|
|
parts = getStrokeParts(text);
|
|
TYPE = Vex.Flow.Stroke.Type;
|
|
type = null;
|
|
if (parts != null) {
|
|
switch (parts[1]) {
|
|
case "bu":
|
|
type = TYPE.BRUSH_UP;
|
|
break;
|
|
case "bd":
|
|
type = TYPE.BRUSH_DOWN;
|
|
break;
|
|
case "ru":
|
|
type = TYPE.ROLL_UP;
|
|
break;
|
|
case "rd":
|
|
type = TYPE.ROLL_DOWN;
|
|
break;
|
|
case "qu":
|
|
type = TYPE.RASQUEDO_UP;
|
|
break;
|
|
case "qd":
|
|
type = TYPE.RASQUEDO_DOWN;
|
|
break;
|
|
default:
|
|
throw new Vex.RERR("ArtistError", "Invalid stroke type: " + parts[1]);
|
|
}
|
|
return new Vex.Flow.Stroke(type);
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
getScoreArticulationParts = function(text) {
|
|
return text.match(/^\.(a[^\/]*)\/(t|b)[^.]*\./);
|
|
};
|
|
|
|
Artist.prototype.makeScoreArticulation = function(text) {
|
|
var POSTYPE, parts, pos, position, type;
|
|
parts = getScoreArticulationParts(text);
|
|
if (parts != null) {
|
|
type = parts[1];
|
|
position = parts[2];
|
|
POSTYPE = Vex.Flow.Modifier.Position;
|
|
pos = position === "t" ? POSTYPE.ABOVE : POSTYPE.BELOW;
|
|
return new Vex.Flow.Articulation(type).setPosition(pos);
|
|
} else {
|
|
return null;
|
|
}
|
|
};
|
|
|
|
Artist.prototype.makeAnnotation = function(text) {
|
|
var VJUST, aposition, default_vjust, font_face, font_size, font_style, just, makeIt, parts;
|
|
font_face = this.customizations["font-face"];
|
|
font_size = this.customizations["font-size"];
|
|
font_style = this.customizations["font-style"];
|
|
aposition = this.customizations["annotation-position"];
|
|
VJUST = Vex.Flow.Annotation.VerticalJustify;
|
|
default_vjust = aposition === "top" ? VJUST.TOP : VJUST.BOTTOM;
|
|
makeIt = function(text, just) {
|
|
if (just == null) {
|
|
just = default_vjust;
|
|
}
|
|
return new Vex.Flow.Annotation(text).setFont(font_face, font_size, font_style).setVerticalJustification(just);
|
|
};
|
|
parts = text.match(/^\.([^-]*)-([^-]*)-([^.]*)\.(.*)/);
|
|
if (parts != null) {
|
|
font_face = parts[1];
|
|
font_size = parts[2];
|
|
font_style = parts[3];
|
|
text = parts[4];
|
|
if (text) {
|
|
return makeIt(text);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
parts = text.match(/^\.([^.]*)\.(.*)/);
|
|
if (parts != null) {
|
|
just = default_vjust;
|
|
text = parts[2];
|
|
switch (parts[1]) {
|
|
case "big":
|
|
font_style = "bold";
|
|
font_size = "14";
|
|
break;
|
|
case "italic":
|
|
case "italics":
|
|
font_face = "Times";
|
|
font_style = "italic";
|
|
break;
|
|
case "medium":
|
|
font_size = "12";
|
|
break;
|
|
case "top":
|
|
just = VJUST.TOP;
|
|
this.customizations["annotation-position"] = "top";
|
|
break;
|
|
case "bottom":
|
|
just = VJUST.BOTTOM;
|
|
this.customizations["annotation-position"] = "bottom";
|
|
}
|
|
if (text) {
|
|
return makeIt(text, just);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
return makeIt(text);
|
|
};
|
|
|
|
Artist.prototype.addAnnotations = function(annotations) {
|
|
var annotation, e, fingering, fingerings, i, note, score_articulation, stave, stave_notes, stroke, tab_note, tab_notes, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results;
|
|
stave = _.last(this.staves);
|
|
stave_notes = stave.note_notes;
|
|
tab_notes = stave.tab_notes;
|
|
if (annotations.length > tab_notes.length) {
|
|
throw new Vex.RERR("ArtistError", "More annotations than note elements");
|
|
}
|
|
if (stave.tab) {
|
|
_ref = tab_notes.slice(tab_notes.length - annotations.length);
|
|
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
|
tab_note = _ref[i];
|
|
if (getScoreArticulationParts(annotations[i])) {
|
|
score_articulation = this.makeScoreArticulation(annotations[i]);
|
|
tab_note.addModifier(score_articulation, 0);
|
|
} else if (getStrokeParts(annotations[i])) {
|
|
stroke = this.makeStroke(annotations[i]);
|
|
tab_note.addModifier(stroke, 0);
|
|
} else {
|
|
annotation = this.makeAnnotation(annotations[i]);
|
|
if (annotation) {
|
|
tab_note.addModifier(this.makeAnnotation(annotations[i]), 0);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
_ref1 = stave_notes.slice(stave_notes.length - annotations.length);
|
|
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
|
|
note = _ref1[i];
|
|
if (!getScoreArticulationParts(annotations[i])) {
|
|
annotation = this.makeAnnotation(annotations[i]);
|
|
if (annotation) {
|
|
note.addAnnotation(0, this.makeAnnotation(annotations[i]));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (stave.note) {
|
|
_ref2 = stave_notes.slice(stave_notes.length - annotations.length);
|
|
_results = [];
|
|
for (i = _k = 0, _len2 = _ref2.length; _k < _len2; i = ++_k) {
|
|
note = _ref2[i];
|
|
score_articulation = this.makeScoreArticulation(annotations[i]);
|
|
if (score_articulation != null) {
|
|
note.addArticulation(0, score_articulation);
|
|
}
|
|
stroke = this.makeStroke(annotations[i]);
|
|
if (stroke != null) {
|
|
note.addStroke(0, stroke);
|
|
}
|
|
fingerings = this.makeFingering(annotations[i]);
|
|
if (fingerings != null) {
|
|
try {
|
|
_results.push((function() {
|
|
var _l, _len3, _results1;
|
|
_results1 = [];
|
|
for (_l = 0, _len3 = fingerings.length; _l < _len3; _l++) {
|
|
fingering = fingerings[_l];
|
|
_results1.push(note.addModifier(fingering.num, fingering.modifier));
|
|
}
|
|
return _results1;
|
|
})());
|
|
} catch (_error) {
|
|
e = _error;
|
|
throw new Vex.RERR("ArtistError", "Bad note number in fingering: " + annotations[i]);
|
|
}
|
|
} else {
|
|
_results.push(void 0);
|
|
}
|
|
}
|
|
return _results;
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addTabArticulation = function(type, first_note, last_note, first_indices, last_indices) {
|
|
var articulation;
|
|
L("addTabArticulations: ", type, first_note, last_note, first_indices, last_indices);
|
|
if (type === "t") {
|
|
last_note.addModifier(new Vex.Flow.Annotation("T").setVerticalJustification(Vex.Flow.Annotation.VerticalJustify.BOTTOM));
|
|
}
|
|
if (_.isEmpty(first_indices) && _.isEmpty(last_indices)) {
|
|
return;
|
|
}
|
|
articulation = null;
|
|
if (type === "s") {
|
|
articulation = new Vex.Flow.TabSlide({
|
|
first_note: first_note,
|
|
last_note: last_note,
|
|
first_indices: first_indices,
|
|
last_indices: last_indices
|
|
});
|
|
}
|
|
if (type === "h" || type === "p") {
|
|
articulation = new Vex.Flow.TabTie({
|
|
first_note: first_note,
|
|
last_note: last_note,
|
|
first_indices: first_indices,
|
|
last_indices: last_indices
|
|
}, type.toUpperCase());
|
|
}
|
|
if (type === "T" || type === "t") {
|
|
articulation = new Vex.Flow.TabTie({
|
|
first_note: first_note,
|
|
last_note: last_note,
|
|
first_indices: first_indices,
|
|
last_indices: last_indices
|
|
}, " ");
|
|
}
|
|
if (type === "b") {
|
|
this.openBends(first_note, last_note, first_indices, last_indices);
|
|
}
|
|
if (articulation != null) {
|
|
return this.tab_articulations.push(articulation);
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addStaveArticulation = function(type, first_note, last_note, first_indices, last_indices) {
|
|
var articulation;
|
|
L("addStaveArticulations: ", type, first_note, last_note, first_indices, last_indices);
|
|
articulation = null;
|
|
if (type === "b" || type === "s" || type === "h" || type === "p" || type === "t" || type === "T") {
|
|
articulation = new Vex.Flow.StaveTie({
|
|
first_note: first_note,
|
|
last_note: last_note,
|
|
first_indices: first_indices,
|
|
last_indices: last_indices
|
|
});
|
|
}
|
|
if (articulation != null) {
|
|
return this.stave_articulations.push(articulation);
|
|
}
|
|
};
|
|
|
|
Artist.prototype.getPreviousNoteIndex = function() {
|
|
var index, note, tab_notes;
|
|
tab_notes = _.last(this.staves).tab_notes;
|
|
index = 2;
|
|
while (index <= tab_notes.length) {
|
|
note = tab_notes[tab_notes.length - index];
|
|
if (note instanceof Vex.Flow.TabNote) {
|
|
return tab_notes.length - index;
|
|
}
|
|
index++;
|
|
}
|
|
return -1;
|
|
};
|
|
|
|
Artist.prototype.addDecorator = function(decorator) {
|
|
var modifier, score_modifier, score_notes, stave, tab_notes, _ref;
|
|
L("addDecorator: ", decorator);
|
|
if (decorator == null) {
|
|
return;
|
|
}
|
|
stave = _.last(this.staves);
|
|
tab_notes = stave.tab_notes;
|
|
score_notes = stave.note_notes;
|
|
modifier = null;
|
|
score_modifier = null;
|
|
if (decorator === "v") {
|
|
modifier = new Vex.Flow.Vibrato();
|
|
}
|
|
if (decorator === "V") {
|
|
modifier = new Vex.Flow.Vibrato().setHarsh(true);
|
|
}
|
|
if (decorator === "u") {
|
|
modifier = new Vex.Flow.Articulation("a|").setPosition(Vex.Flow.Modifier.Position.BOTTOM);
|
|
score_modifier = new Vex.Flow.Articulation("a|").setPosition(Vex.Flow.Modifier.Position.BOTTOM);
|
|
}
|
|
if (decorator === "d") {
|
|
modifier = new Vex.Flow.Articulation("am").setPosition(Vex.Flow.Modifier.Position.BOTTOM);
|
|
score_modifier = new Vex.Flow.Articulation("am").setPosition(Vex.Flow.Modifier.Position.BOTTOM);
|
|
}
|
|
if (modifier != null) {
|
|
_.last(tab_notes).addModifier(modifier, 0);
|
|
}
|
|
if (score_modifier != null) {
|
|
return (_ref = _.last(score_notes)) != null ? _ref.addArticulation(0, score_modifier) : void 0;
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addArticulations = function(articulations) {
|
|
var art, current_indices, current_tab_note, has_bends, i, indices, n, pos, prev_index, prev_indices, prev_tab_note, stave, stave_notes, tab_notes, this_strings, valid_articulation, valid_strings, _i, _len, _ref;
|
|
L("addArticulations: ", articulations);
|
|
stave = _.last(this.staves);
|
|
tab_notes = stave.tab_notes;
|
|
stave_notes = stave.note_notes;
|
|
if (_.isEmpty(tab_notes) || _.isEmpty(articulations)) {
|
|
this.closeBends(0);
|
|
return;
|
|
}
|
|
current_tab_note = _.last(tab_notes);
|
|
has_bends = false;
|
|
_ref = ["b", "s", "h", "p", "t", "T", "v", "V"];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
valid_articulation = _ref[_i];
|
|
indices = (function() {
|
|
var _j, _len1, _results;
|
|
_results = [];
|
|
for (i = _j = 0, _len1 = articulations.length; _j < _len1; i = ++_j) {
|
|
art = articulations[i];
|
|
if ((art != null) && art === valid_articulation) {
|
|
_results.push(i);
|
|
}
|
|
}
|
|
return _results;
|
|
})();
|
|
if (_.isEmpty(indices)) {
|
|
continue;
|
|
}
|
|
if (valid_articulation === "b") {
|
|
has_bends = true;
|
|
}
|
|
prev_index = this.getPreviousNoteIndex();
|
|
if (prev_index === -1) {
|
|
prev_tab_note = null;
|
|
prev_indices = null;
|
|
} else {
|
|
prev_tab_note = tab_notes[prev_index];
|
|
this_strings = (function() {
|
|
var _j, _len1, _ref1, _results;
|
|
_ref1 = current_tab_note.getPositions();
|
|
_results = [];
|
|
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
|
|
n = _ref1[i];
|
|
if (__indexOf.call(indices, i) >= 0) {
|
|
_results.push(n.str);
|
|
}
|
|
}
|
|
return _results;
|
|
})();
|
|
valid_strings = (function() {
|
|
var _j, _len1, _ref1, _ref2, _results;
|
|
_ref1 = prev_tab_note.getPositions();
|
|
_results = [];
|
|
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
|
|
pos = _ref1[i];
|
|
if (_ref2 = pos.str, __indexOf.call(this_strings, _ref2) >= 0) {
|
|
_results.push(pos.str);
|
|
}
|
|
}
|
|
return _results;
|
|
})();
|
|
prev_indices = (function() {
|
|
var _j, _len1, _ref1, _ref2, _results;
|
|
_ref1 = prev_tab_note.getPositions();
|
|
_results = [];
|
|
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
|
|
n = _ref1[i];
|
|
if (_ref2 = n.str, __indexOf.call(valid_strings, _ref2) >= 0) {
|
|
_results.push(i);
|
|
}
|
|
}
|
|
return _results;
|
|
})();
|
|
current_indices = (function() {
|
|
var _j, _len1, _ref1, _ref2, _results;
|
|
_ref1 = current_tab_note.getPositions();
|
|
_results = [];
|
|
for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) {
|
|
n = _ref1[i];
|
|
if (_ref2 = n.str, __indexOf.call(valid_strings, _ref2) >= 0) {
|
|
_results.push(i);
|
|
}
|
|
}
|
|
return _results;
|
|
})();
|
|
}
|
|
if (stave.tab != null) {
|
|
this.addTabArticulation(valid_articulation, prev_tab_note, current_tab_note, prev_indices, current_indices);
|
|
}
|
|
if (stave.note != null) {
|
|
this.addStaveArticulation(valid_articulation, stave_notes[prev_index], _.last(stave_notes), prev_indices, current_indices);
|
|
}
|
|
}
|
|
if (!has_bends) {
|
|
return this.closeBends(0);
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addRest = function(params) {
|
|
var position, tab_note, tab_notes;
|
|
L("addRest: ", params);
|
|
this.closeBends();
|
|
if (params["position"] === 0) {
|
|
this.addStaveNote({
|
|
spec: ["r/4"],
|
|
accidentals: [],
|
|
is_rest: true
|
|
});
|
|
} else {
|
|
position = this.tuning.getNoteForFret((parseInt(params["position"], 10) + 5) * 2, 6);
|
|
this.addStaveNote({
|
|
spec: [position],
|
|
accidentals: [],
|
|
is_rest: true
|
|
});
|
|
}
|
|
tab_notes = _.last(this.staves).tab_notes;
|
|
if (this.customizations["tab-stems"] === "true") {
|
|
tab_note = new Vex.Flow.StaveNote({
|
|
keys: [position || "r/4"],
|
|
duration: this.current_duration + "r",
|
|
clef: "treble",
|
|
auto_stem: false
|
|
});
|
|
if (this.current_duration[this.current_duration.length - 1] === "d") {
|
|
tab_note.addDot(0);
|
|
}
|
|
return tab_notes.push(tab_note);
|
|
} else {
|
|
return tab_notes.push(new Vex.Flow.GhostNote(this.current_duration));
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addChord = function(chord, chord_articulation, chord_decorator) {
|
|
var acc, accidental, accidentals, art, articulations, current_duration, current_position, current_string, decorators, durations, i, new_note, new_octave, note, num, num_notes, octave, play_note, play_notes, play_octave, saved_duration, spec, specs, stave, tab_specs, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2;
|
|
if (_.isEmpty(chord)) {
|
|
return;
|
|
}
|
|
L("addChord: ", chord);
|
|
stave = _.last(this.staves);
|
|
specs = [];
|
|
play_notes = [];
|
|
accidentals = [];
|
|
articulations = [];
|
|
decorators = [];
|
|
tab_specs = [];
|
|
durations = [];
|
|
num_notes = 0;
|
|
current_string = _.first(chord).string;
|
|
current_position = 0;
|
|
for (_i = 0, _len = chord.length; _i < _len; _i++) {
|
|
note = chord[_i];
|
|
num_notes++;
|
|
if ((note.abc != null) || note.string !== current_string) {
|
|
current_position = 0;
|
|
current_string = note.string;
|
|
}
|
|
if (specs[current_position] == null) {
|
|
specs[current_position] = [];
|
|
play_notes[current_position] = [];
|
|
accidentals[current_position] = [];
|
|
tab_specs[current_position] = [];
|
|
articulations[current_position] = [];
|
|
decorators[current_position] = [];
|
|
}
|
|
_ref = [null, null, null], new_note = _ref[0], new_octave = _ref[1], accidental = _ref[2];
|
|
play_note = null;
|
|
if (note.abc != null) {
|
|
octave = note.octave != null ? note.octave : note.string;
|
|
_ref1 = this.getNoteForABC(note.abc, octave), new_note = _ref1[0], new_octave = _ref1[1], accidental = _ref1[2];
|
|
if (accidental != null) {
|
|
acc = accidental.split("_")[0];
|
|
} else {
|
|
acc = "";
|
|
}
|
|
play_note = "" + new_note + acc;
|
|
if (note.fret == null) {
|
|
note.fret = 'X';
|
|
}
|
|
} else if (note.fret != null) {
|
|
_ref2 = this.getNoteForFret(note.fret, note.string), new_note = _ref2[0], new_octave = _ref2[1], accidental = _ref2[2];
|
|
play_note = this.tuning.getNoteForFret(note.fret, note.string).split("/")[0];
|
|
} else {
|
|
throw new Vex.RERR("ArtistError", "No note specified");
|
|
}
|
|
play_octave = parseInt(new_octave, 10) + this.current_octave_shift;
|
|
current_duration = note.time != null ? {
|
|
time: note.time,
|
|
dot: note.dot
|
|
} : null;
|
|
specs[current_position].push("" + new_note + "/" + new_octave);
|
|
play_notes[current_position].push("" + play_note + "/" + play_octave);
|
|
accidentals[current_position].push(accidental);
|
|
tab_specs[current_position].push({
|
|
fret: note.fret,
|
|
str: note.string
|
|
});
|
|
if (note.articulation != null) {
|
|
articulations[current_position].push(note.articulation);
|
|
}
|
|
durations[current_position] = current_duration;
|
|
if (note.decorator != null) {
|
|
decorators[current_position] = note.decorator;
|
|
}
|
|
current_position++;
|
|
}
|
|
for (i = _j = 0, _len1 = specs.length; _j < _len1; i = ++_j) {
|
|
spec = specs[i];
|
|
saved_duration = this.current_duration;
|
|
if (durations[i] != null) {
|
|
this.setDuration(durations[i].time, durations[i].dot);
|
|
}
|
|
this.addTabNote(tab_specs[i], play_notes[i]);
|
|
if (stave.note != null) {
|
|
this.addStaveNote({
|
|
spec: spec,
|
|
accidentals: accidentals[i],
|
|
play_note: play_notes[i]
|
|
});
|
|
}
|
|
this.addArticulations(articulations[i]);
|
|
if (decorators[i] != null) {
|
|
this.addDecorator(decorators[i]);
|
|
}
|
|
}
|
|
if (chord_articulation != null) {
|
|
art = [];
|
|
for (num = _k = 1; 1 <= num_notes ? _k <= num_notes : _k >= num_notes; num = 1 <= num_notes ? ++_k : --_k) {
|
|
art.push(chord_articulation);
|
|
}
|
|
this.addArticulations(art);
|
|
}
|
|
if (chord_decorator != null) {
|
|
return this.addDecorator(chord_decorator);
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addNote = function(note) {
|
|
return this.addChord([note]);
|
|
};
|
|
|
|
Artist.prototype.addTextVoice = function() {
|
|
return _.last(this.staves).text_voices.push([]);
|
|
};
|
|
|
|
Artist.prototype.setTextFont = function(font) {
|
|
var parts;
|
|
if (font != null) {
|
|
parts = font.match(/([^-]*)-([^-]*)-([^.]*)/);
|
|
if (parts != null) {
|
|
this.customizations["font-face"] = parts[1];
|
|
this.customizations["font-size"] = parseInt(parts[2], 10);
|
|
return this.customizations["font-style"] = parts[3];
|
|
}
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addTextNote = function(text, position, justification, smooth, ignore_ticks) {
|
|
var duration, font_face, font_size, font_style, just, note, struct, voices;
|
|
if (position == null) {
|
|
position = 0;
|
|
}
|
|
if (justification == null) {
|
|
justification = "center";
|
|
}
|
|
if (smooth == null) {
|
|
smooth = true;
|
|
}
|
|
if (ignore_ticks == null) {
|
|
ignore_ticks = false;
|
|
}
|
|
voices = _.last(this.staves).text_voices;
|
|
if (_.isEmpty(voices)) {
|
|
throw new Vex.RERR("ArtistError", "Can't add text note without text voice");
|
|
}
|
|
font_face = this.customizations["font-face"];
|
|
font_size = this.customizations["font-size"];
|
|
font_style = this.customizations["font-style"];
|
|
just = (function() {
|
|
switch (justification) {
|
|
case "center":
|
|
return Vex.Flow.TextNote.Justification.CENTER;
|
|
case "left":
|
|
return Vex.Flow.TextNote.Justification.LEFT;
|
|
case "right":
|
|
return Vex.Flow.TextNote.Justification.RIGHT;
|
|
default:
|
|
return Vex.Flow.TextNote.Justification.CENTER;
|
|
}
|
|
})();
|
|
duration = ignore_ticks ? "b" : this.current_duration;
|
|
struct = {
|
|
text: text,
|
|
duration: duration,
|
|
smooth: smooth,
|
|
ignore_ticks: ignore_ticks,
|
|
font: {
|
|
family: font_face,
|
|
size: font_size,
|
|
weight: font_style
|
|
}
|
|
};
|
|
if (text[0] === "#") {
|
|
struct.glyph = text.slice(1);
|
|
}
|
|
note = new Vex.Flow.TextNote(struct).setLine(position).setJustification(just);
|
|
return _.last(voices).push(note);
|
|
};
|
|
|
|
Artist.prototype.addVoice = function(options) {
|
|
var stave;
|
|
this.closeBends();
|
|
stave = _.last(this.staves);
|
|
if (stave == null) {
|
|
return this.addStave(options);
|
|
}
|
|
if (!_.isEmpty(stave.tab_notes)) {
|
|
stave.tab_voices.push(stave.tab_notes);
|
|
stave.tab_notes = [];
|
|
}
|
|
if (!_.isEmpty(stave.note_notes)) {
|
|
stave.note_voices.push(stave.note_notes);
|
|
return stave.note_notes = [];
|
|
}
|
|
};
|
|
|
|
Artist.prototype.addStave = function(element, options) {
|
|
var beam_groups, note_stave, opts, start_x, tab_stave, tabstave_start_x;
|
|
opts = {
|
|
tuning: "standard",
|
|
clef: "treble",
|
|
key: "C",
|
|
notation: element === "tabstave" ? "false" : "true",
|
|
tablature: element === "stave" ? "false" : "true",
|
|
strings: 6
|
|
};
|
|
_.extend(opts, options);
|
|
L("addStave: ", element, opts);
|
|
tab_stave = null;
|
|
note_stave = null;
|
|
start_x = this.x + this.customizations["connector-space"];
|
|
tabstave_start_x = 40;
|
|
if (opts.notation === "true") {
|
|
note_stave = new Vex.Flow.Stave(start_x, this.last_y, this.customizations.width - 20).addClef(opts.clef).addKeySignature(opts.key);
|
|
if (opts.time != null) {
|
|
note_stave.addTimeSignature(opts.time);
|
|
}
|
|
this.last_y += note_stave.getHeight() + this.options.note_stave_lower_spacing + parseInt(this.customizations["stave-distance"], 10);
|
|
tabstave_start_x = note_stave.getNoteStartX();
|
|
this.current_clef = opts.clef;
|
|
}
|
|
if (opts.tablature === "true") {
|
|
tab_stave = new Vex.Flow.TabStave(start_x, this.last_y, this.customizations.width - 20).setNumLines(opts.strings).addTabGlyph().setNoteStartX(tabstave_start_x);
|
|
this.last_y += tab_stave.getHeight() + this.options.tab_stave_lower_spacing;
|
|
}
|
|
this.closeBends();
|
|
beam_groups = Vex.Flow.Beam.getDefaultBeamGroups(opts.time);
|
|
this.staves.push({
|
|
tab: tab_stave,
|
|
note: note_stave,
|
|
tab_voices: [],
|
|
note_voices: [],
|
|
tab_notes: [],
|
|
note_notes: [],
|
|
text_voices: [],
|
|
beam_groups: beam_groups
|
|
});
|
|
this.tuning.setTuning(opts.tuning);
|
|
this.key_manager.setKey(opts.key);
|
|
};
|
|
|
|
Artist.prototype.runCommand = function(line, _l, _c) {
|
|
var words;
|
|
if (_l == null) {
|
|
_l = 0;
|
|
}
|
|
if (_c == null) {
|
|
_c = 0;
|
|
}
|
|
L("runCommand: ", line);
|
|
words = line.split(/\s+/);
|
|
switch (words[0]) {
|
|
case "octave-shift":
|
|
this.current_octave_shift = parseInt(words[1], 10);
|
|
return L("Octave shift: ", this.current_octave_shift);
|
|
default:
|
|
throw new Vex.RERR("ArtistError", "Invalid command '" + words[0] + "' at line " + _l + " column " + _c);
|
|
}
|
|
};
|
|
|
|
return Artist;
|
|
|
|
})();
|
|
|
|
}).call(this);
|
|
// Generated by CoffeeScript 1.8.0
|
|
(function() {
|
|
var __slice = [].slice,
|
|
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
|
|
|
Vex.Flow.VexTab = (function() {
|
|
var L, newError;
|
|
|
|
VexTab.DEBUG = false;
|
|
|
|
L = function() {
|
|
var args;
|
|
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
|
|
if (Vex.Flow.VexTab.DEBUG) {
|
|
return typeof console !== "undefined" && console !== null ? console.log.apply(console, ["(Vex.Flow.VexTab)"].concat(__slice.call(args))) : void 0;
|
|
}
|
|
};
|
|
|
|
newError = function(object, msg) {
|
|
return new Vex.RERR("ParseError", "" + msg + " in line " + object._l + " column " + object._c);
|
|
};
|
|
|
|
function VexTab(artist) {
|
|
this.artist = artist;
|
|
this.reset();
|
|
}
|
|
|
|
VexTab.prototype.reset = function() {
|
|
this.valid = false;
|
|
return this.elements = false;
|
|
};
|
|
|
|
VexTab.prototype.isValid = function() {
|
|
return this.valid;
|
|
};
|
|
|
|
VexTab.prototype.getArtist = function() {
|
|
return this.artist;
|
|
};
|
|
|
|
VexTab.prototype.parseStaveOptions = function(options) {
|
|
var clefs, e, error, notation_option, num_strings, option, params, voices, _i, _len, _ref, _ref1, _ref2;
|
|
params = {};
|
|
if (options == null) {
|
|
return params;
|
|
}
|
|
notation_option = null;
|
|
for (_i = 0, _len = options.length; _i < _len; _i++) {
|
|
option = options[_i];
|
|
error = function(msg) {
|
|
return newError(option, msg);
|
|
};
|
|
params[option.key] = option.value;
|
|
switch (option.key) {
|
|
case "notation":
|
|
case "tablature":
|
|
notation_option = option;
|
|
if ((_ref = option.value) !== "true" && _ref !== "false") {
|
|
throw error("'" + option.key + "' must be 'true' or 'false'");
|
|
}
|
|
break;
|
|
case "key":
|
|
if (!_.has(Vex.Flow.keySignature.keySpecs, option.value)) {
|
|
throw error("Invalid key signature '" + option.value + "'");
|
|
}
|
|
break;
|
|
case "clef":
|
|
clefs = ["treble", "bass", "tenor", "alto", "percussion", "none"];
|
|
if (_ref1 = option.value, __indexOf.call(clefs, _ref1) < 0) {
|
|
throw error("'clef' must be one of " + (clefs.join(', ')));
|
|
}
|
|
break;
|
|
case "voice":
|
|
voices = ["top", "bottom", "new"];
|
|
if (_ref2 = option.value, __indexOf.call(voices, _ref2) < 0) {
|
|
throw error("'voice' must be one of " + (voices.join(', ')));
|
|
}
|
|
break;
|
|
case "time":
|
|
try {
|
|
new Vex.Flow.TimeSignature(option.value);
|
|
} catch (_error) {
|
|
e = _error;
|
|
throw error("Invalid time signature: '" + option.value + "'");
|
|
}
|
|
break;
|
|
case "tuning":
|
|
try {
|
|
new Vex.Flow.Tuning(option.value);
|
|
} catch (_error) {
|
|
e = _error;
|
|
throw error("Invalid tuning: '" + option.value + "'");
|
|
}
|
|
break;
|
|
case "strings":
|
|
num_strings = parseInt(option.value);
|
|
if (num_strings < 4 || num_strings > 8) {
|
|
throw error("Invalid number of strings: " + num_strings);
|
|
}
|
|
break;
|
|
default:
|
|
throw error("Invalid option '" + option.key + "'");
|
|
}
|
|
}
|
|
if (params.notation === "false" && params.tablature === "false") {
|
|
throw newError(notation_option, "Both 'notation' and 'tablature' can't be invisible");
|
|
}
|
|
return params;
|
|
};
|
|
|
|
VexTab.prototype.parseCommand = function(element) {
|
|
if (element.command === "bar") {
|
|
this.artist.addBar(element.type);
|
|
}
|
|
if (element.command === "tuplet") {
|
|
this.artist.makeTuplets(element.params.tuplet, element.params.notes);
|
|
}
|
|
if (element.command === "annotations") {
|
|
this.artist.addAnnotations(element.params);
|
|
}
|
|
if (element.command === "rest") {
|
|
this.artist.addRest(element.params);
|
|
}
|
|
if (element.command === "command") {
|
|
return this.artist.runCommand(element.params, element._l, element._c);
|
|
}
|
|
};
|
|
|
|
VexTab.prototype.parseChord = function(element) {
|
|
L("parseChord:", element);
|
|
return this.artist.addChord(_.map(element.chord, function(note) {
|
|
return _.pick(note, 'time', 'dot', 'fret', 'abc', 'octave', 'string', 'articulation', 'decorator');
|
|
}), element.articulation, element.decorator);
|
|
};
|
|
|
|
VexTab.prototype.parseFret = function(note) {
|
|
return this.artist.addNote(_.pick(note, 'time', 'dot', 'fret', 'string', 'articulation', 'decorator'));
|
|
};
|
|
|
|
VexTab.prototype.parseABC = function(note) {
|
|
return this.artist.addNote(_.pick(note, 'time', 'dot', 'fret', 'abc', 'octave', 'string', 'articulation', 'decorator'));
|
|
};
|
|
|
|
VexTab.prototype.parseStaveElements = function(notes) {
|
|
var element, _i, _len, _results;
|
|
L("parseStaveElements:", notes);
|
|
_results = [];
|
|
for (_i = 0, _len = notes.length; _i < _len; _i++) {
|
|
element = notes[_i];
|
|
if (element.time) {
|
|
this.artist.setDuration(element.time, element.dot);
|
|
}
|
|
if (element.command) {
|
|
this.parseCommand(element);
|
|
}
|
|
if (element.chord) {
|
|
this.parseChord(element);
|
|
}
|
|
if (element.abc) {
|
|
_results.push(this.parseABC(element));
|
|
} else if (element.fret) {
|
|
_results.push(this.parseFret(element));
|
|
} else {
|
|
_results.push(void 0);
|
|
}
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
VexTab.prototype.parseStaveText = function(text_line) {
|
|
var bartext, command, createNote, font, justification, position, smooth, str, text, _i, _len, _results;
|
|
if (!_.isEmpty(text_line)) {
|
|
this.artist.addTextVoice();
|
|
}
|
|
position = 0;
|
|
justification = "center";
|
|
smooth = true;
|
|
font = null;
|
|
bartext = (function(_this) {
|
|
return function() {
|
|
return _this.artist.addTextNote("", 0, justification, false, true);
|
|
};
|
|
})(this);
|
|
createNote = (function(_this) {
|
|
return function(text) {
|
|
var e, ignore_ticks;
|
|
ignore_ticks = false;
|
|
if (text[0] === "|") {
|
|
ignore_ticks = true;
|
|
text = text.slice(1);
|
|
}
|
|
try {
|
|
return _this.artist.addTextNote(text, position, justification, smooth, ignore_ticks);
|
|
} catch (_error) {
|
|
e = _error;
|
|
throw newError(str, "Bad text or duration. Did you forget a comma?" + e);
|
|
}
|
|
};
|
|
})(this);
|
|
_results = [];
|
|
for (_i = 0, _len = text_line.length; _i < _len; _i++) {
|
|
str = text_line[_i];
|
|
text = str.text.trim();
|
|
if (text.match(/\.font=.*/)) {
|
|
font = text.slice(6);
|
|
_results.push(this.artist.setTextFont(font));
|
|
} else if (text[0] === ":") {
|
|
_results.push(this.artist.setDuration(text));
|
|
} else if (text[0] === ".") {
|
|
command = text.slice(1);
|
|
switch (command) {
|
|
case "center":
|
|
case "left":
|
|
case "right":
|
|
_results.push(justification = command);
|
|
break;
|
|
case "strict":
|
|
_results.push(smooth = false);
|
|
break;
|
|
case "smooth":
|
|
_results.push(smooth = true);
|
|
break;
|
|
case "bar":
|
|
case "|":
|
|
_results.push(bartext());
|
|
break;
|
|
default:
|
|
_results.push(position = parseInt(text.slice(1), 10));
|
|
}
|
|
} else if (text === "|") {
|
|
_results.push(bartext());
|
|
} else if (text.slice(0, 2) === "++") {
|
|
_results.push(this.artist.addTextVoice());
|
|
} else {
|
|
_results.push(createNote(text));
|
|
}
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
VexTab.prototype.generate = function() {
|
|
var e, option, options, stave, _i, _j, _len, _len1, _ref, _ref1, _results;
|
|
_ref = this.elements;
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
stave = _ref[_i];
|
|
switch (stave.element) {
|
|
case "stave":
|
|
case "tabstave":
|
|
this.artist.addStave(stave.element, this.parseStaveOptions(stave.options));
|
|
if (stave.notes != null) {
|
|
this.parseStaveElements(stave.notes);
|
|
}
|
|
if (stave.text != null) {
|
|
_results.push(this.parseStaveText(stave.text));
|
|
} else {
|
|
_results.push(void 0);
|
|
}
|
|
break;
|
|
case "voice":
|
|
this.artist.addVoice(this.parseStaveOptions(stave.options));
|
|
if (stave.notes != null) {
|
|
this.parseStaveElements(stave.notes);
|
|
}
|
|
if (stave.text != null) {
|
|
_results.push(this.parseStaveText(stave.text));
|
|
} else {
|
|
_results.push(void 0);
|
|
}
|
|
break;
|
|
case "options":
|
|
options = {};
|
|
_ref1 = stave.params;
|
|
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
|
option = _ref1[_j];
|
|
options[option.key] = option.value;
|
|
}
|
|
try {
|
|
_results.push(this.artist.setOptions(options));
|
|
} catch (_error) {
|
|
e = _error;
|
|
throw newError(stave, e.message);
|
|
}
|
|
break;
|
|
default:
|
|
throw newError(stave, "Invalid keyword '" + stave.element + "'");
|
|
}
|
|
}
|
|
return _results;
|
|
};
|
|
|
|
VexTab.prototype.parse = function(code) {
|
|
var line, stripped_code;
|
|
vextab_parser.parseError = function(message, hash) {
|
|
L("VexTab parse error: ", message, hash);
|
|
message = "Unexpected text '" + hash.text + "' at line " + hash.loc.first_line + " column " + hash.loc.first_column + ".";
|
|
throw new Vex.RERR("ParseError", message);
|
|
};
|
|
if (code == null) {
|
|
throw new Vex.RERR("ParseError", "No code");
|
|
}
|
|
L("Parsing:\n" + code);
|
|
stripped_code = (function() {
|
|
var _i, _len, _ref, _results;
|
|
_ref = code.split(/\r\n|\r|\n/);
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
line = _ref[_i];
|
|
_results.push(line.trim());
|
|
}
|
|
return _results;
|
|
})();
|
|
this.elements = vextab_parser.parse(stripped_code.join("\n"));
|
|
if (this.elements) {
|
|
this.generate();
|
|
this.valid = true;
|
|
}
|
|
return this.elements;
|
|
};
|
|
|
|
return VexTab;
|
|
|
|
})();
|
|
|
|
}).call(this);
|