1// abc2svg - ABC to SVG translator
2// @source: https://chiselapp.com/user/moinejf/repository/abc2svg
3// Copyright (C) 2014-2020 Jean-Francois Moine - LGPL3+
4//abc2svg-strtab.js-tablature for string instruments
5abc2svg.strtab={draw_symbols:function(of,p_v){var s,m,not,stb,x,y,C=abc2svg.C,abc=this
6if(!p_v.tab){of(p_v)
7return}
8m=abc.cfmt().bgcolor||"white"
9if(abc.bgt!=m){if(!abc.bgn)
10abc.bgn=1
11else
12abc.bgn++
13abc.bgt=m
14abc.defs_add('\
15<filter x="-0.1" y="0.2" width="1.2" height=".8" id="bg'+abc.bgn+'">\n\
16<feFlood flood-color="'+m+'"/>\n\
17<feComposite in="SourceGraphic" operator="over"/>\n\
18</filter>')
19abc.add_style('\n.bg'+abc.bgn+'{filter:url(#bg'+abc.bgn+')}')}
20for(s=p_v.sym;s;s=s.next){switch(s.type){case C.KEY:case C.METER:case C.REST:s.invis=true
21break
22case C.NOTE:if(!s.stemless)
23s.ys=-10
24break}}
25of(p_v)
26abc.glout()
27stb=abc.get_staff_tb()[p_v.st].y
28abc.out_svg('<g class="bn">\n')
29for(s=p_v.sym;s;s=s.next){if(s.type==C.NOTE){for(m=0;m<=s.nhd;m++){not=s.notes[m]
30x=s.x-3
31if(not.nb>=10)
32x-=3
33y=3*(not.pit-18)
34abc.out_svg('<text class="bg'+abc.bgn+'" x="')
35abc.out_sxsy(x,'" y="',stb+y-2.5)
36abc.out_svg('">'+not.nb+'</text>\n')}}}
37abc.out_svg('</g>\n')},set_fmt:function(of,cmd,parm){if(cmd=="strtab"){if(!parm)
38return
39this.set_v_param("clef","tab")
40if(parm.indexOf("diafret")>=0){this.set_v_param("diafret",true)
41parm=parm.replace(/\s*diafret\s*/,"")}
42this.set_v_param("strings",parm)
43return}
44of(cmd,parm)},set_width:function(of,s){var m,not,abc=this,C=abc2svg.C,o=s.stem<0?3.5:-2.5
45of(s)
46if(s.p_v&&s.p_v.tab&&s.type==C.NOTE&&!s.stemless){for(m=0;m<=s.nhd;m++)
47s.notes[m].shhd=o}},set_stems:function(of){var p_v,i,m,nt,n,bi,bn,strss,C=abc2svg.C,abc=this,s=abc.get_tsfirst(),strs=[],lstr=[]
48function set_pit(p_v,s,nt,i){var st=s.st,n=(p_v.diafret?nt.pit:nt.midi)-p_v.tab[i]
49if(p_v.diafret&&nt.acc)
50n+='+'
51nt.acc=0
52nt.invis=true
53nt.pit=i*2+18
54nt.nb=n
55strss[i]=s.time+s.dur
56if(s.nflags>=-1&&!s.stemless){if(!lstr[st])
57lstr[st]=[10]
58if(lstr[st][0]>i){lstr[st][0]=i
59lstr[st][1]=s}
60s.stemless=true}}
61function strnum(n){n=n.match(/^([1-9])s?$/)
62return n?p_v.tab.length-n[1]:-1}
63p_v=abc.get_voice_tb()
64for(n=0;n<p_v.length;n++){if(!p_v[n].tab)
65continue
66m=p_v[n].capo
67if(m){for(i=0;i<p_v[n].tab.length;i++)
68p_v[n].tab[i]+=m}}
69for(;s;s=s.ts_next){p_v=s.p_v
70if(!p_v.tab)
71continue
72strss=strs[s.st]
73if(!strss)
74strss=strs[s.st]=[]
75switch(s.type){case C.KEY:case C.REST:case C.TIME:s.invis=true
76default:continue
77case C.NOTE:break}
78if(!s.nhd&&s.a_dd){i=s.a_dd.length
79while(--i>=0){bi=strnum(s.a_dd[i].name)
80if(bi>=0){nt=s.notes[0]
81set_pit(p_v,s,nt,bi)
82break}}
83delete s.a_dd}
84ls:for(m=0;m<=s.nhd;m++){nt=s.notes[m]
85if(nt.nb!=undefined)
86continue
87if(nt.a_dcn){i=nt.a_dcn.length
88while(--i>=0){bi=strnum(nt.a_dcn[i])
89if(bi>=0){set_pit(p_v,s,nt,bi)
90delete nt.a_dcn
91continue ls}}
92delete nt.a_dcn}
93bn=100
94i=p_v.tab.length
95while(--i>=0){if(strss[i]&&strss[i]>s.time)
96continue
97n=(p_v.diafret?nt.pit:nt.midi)-
98p_v.tab[i]
99if(n>=0&&n<bn){bi=i
100bn=n}}
101set_pit(p_v,s,nt,bi)}
102if(!s.ts_next||s.ts_next.time!=s.time){for(i=0;i<lstr.length;i++){if(lstr[i]){delete lstr[i][1].stemless
103lstr[i]=null}}}}
104of()},set_vp:function(of,a){var i,e,g,tab,strs,ok,p_v=this.get_curvoice()
105function abc2tab(p){var i,c,t=[]
106if(p_v.diafret){for(i=0;i<p.length;i++){c=p[i]
107c="CDEFGABcdefgab".indexOf(c)
108if(c<0)
109return
110c+=16
111while(1){if(p[i+1]=="'"){c+=7
112i++}else if(p[i+1]==","){c-=7
113i++}else{break}}
114t.push(c)}}else{for(i=0;i<p.length;i++){c=p[i]
115c="CCDDEFFGGAABccddeffggaab".indexOf(c)
116if(c<0)
117return
118c+=60
119while(1){if(p[i+1]=="'"){c+=12
120i++}else if(p[i+1]==","){c-=12
121i++}else{break}}
122t.push(c)}}
123return t}
124function str2tab(a){var str,p,o,t=[]
125if(p_v.diafret){while(1){str=a.shift()
126if(!str)
127break
128p="CDEFGAB".indexOf(str[0])
129o=Number(str[1])
130if(p<0||isNaN(o))
131return
132t.push(o*7+p-12)}}else{while(1){str=a.shift()
133if(!str)
134break
135p="CCDDEFFGGAAB".indexOf(str[0])
136o=Number(str[1])
137if(p<0||isNaN(o))
138return
139t.push((o+1)*12+p)}}
140return t}
141for(i=0;i<a.length;i++){switch(a[i]){case"clef=":e=a[i+1]
142if(e!="tab")
143break
144a.splice(i,1)
145case"tab":a.splice(i,1)
146i--
147ok=true
148p_v.pos.stm=abc2svg.C.SL_BELOW
149break
150case"strings=":strs=a[++i]
151ok=true
152break
153case"nostems":p_v.pos.stm=abc2svg.C.SL_HIDDEN
154break
155case"capo=":p_v.capo=Number(a[++i])
156break
157case"diafret=":i++
158case"diafret":p_v.diafret=true
159break}}
160if(ok){if(strs){if(strs[1]>='1'&&strs[1]<='9')
161tab=str2tab(strs.split(','))
162else
163tab=abc2tab(strs)
164if(!tab){this.syntax(1,"Bad strings in tablature")
165ok=false}}else if(!p_v.tab){tab=p_v.diafret?[10,14,17]:[40,45,50,55,59,64]}}
166if(ok){if(p_v.capo){p_v.tab=[]
167for(i=0;i<tab.length;i++)
168p_v.tab.push(tab[i]+p_v.capo)}else{p_v.tab=tab}
169a.push("clef=")
170g=this.get_glyphs()
171if(tab.length==3){a.push('"tab3"')
172if(!g.tab3)
173g.tab3='<text id="tab3"\
174 x="-4,-4,-4" y="-4,3,10"\
175 style="font:bold 8px sans-serif">TAB</text>'}else if(tab.length==4){a.push('"tab4"')
176if(!g.tab4)
177g.tab4='<text id="tab4"\
178 x="-4,-4,-4" y="-8,1,10"\
179 style="font:bold 12px sans-serif">TAB</text>'}else if(tab.length==5){a.push('"tab5"')
180if(!g.tab5)
181g.tab5='<text id="tab5"\
182 x="-4,-4,-4" y="-11,-2,7"\
183 style="font:bold 12px sans-serif">TAB</text>'}else{a.push('"tab6"')
184if(!g.tab6)
185g.tab6='<text id="tab6"\
186 x="-4,-4,-4" y="-14.5,-4,5.5"\
187 style="font:bold 13px sans-serif">TAB</text>'}
188a.push("stafflines=")
189a.push("|||||||||".slice(0,tab.length))
190p_v.staffscale=1.6}
191of(a)},set_hooks:function(abc){abc.draw_symbols=abc2svg.strtab.draw_symbols.bind(abc,abc.draw_symbols)
192abc.set_format=abc2svg.strtab.set_fmt.bind(abc,abc.set_format);abc.set_stems=abc2svg.strtab.set_stems.bind(abc,abc.set_stems)
193abc.set_width=abc2svg.strtab.set_width.bind(abc,abc.set_width)
194abc.set_vp=abc2svg.strtab.set_vp.bind(abc,abc.set_vp)
195var decos=abc.get_decos()
196decos["1s"]="0 nul 0 0 0"
197decos["2s"]="0 nul 0 0 0"
198decos["3s"]="0 nul 0 0 0"
199decos["4s"]="0 nul 0 0 0"
200decos["5s"]="0 nul 0 0 0"
201decos["6s"]="0 nul 0 0 0"
202if(!user.nul)
203user.nul=function(){}
204abc.add_style("\n.bn{font:bold 8px sans-serif}")}}
205abc2svg.modules.hooks.push(abc2svg.strtab.set_hooks)
206abc2svg.modules.strtab.loaded=true
207