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//grid3.js-module to insert a manual chords 5abc2svg.grid3={block_gen:function(of,s){if(s.subtype!="grid"){of(s) 6return} 7var abc=this,cfmt=abc.cfmt(),img=abc.get_img(),txt=s.text,font,font_cl,cls,w,ln,i,lines=[],cl=[],bars=[],cells=[],nr=0,nc=0,wc=0 8function build_grid(){var i,k,l,line,bl,bar,w,hr,x0,x,y,yl,cl,cell,lc='',path='<path class="stroke" stroke-width="1" d="M',sf='" style="font-size:'+(font.size*.72).toFixed(1)+'px' 9function build_ch(cl,x,y,n){return'<text class="'+cl+'" x="'+ 10x.toFixed(1)+'" y="'+y.toFixed(1)+'">'+ 11cell[n]+'</text>\n'} 12function build_cell(cell,x,y,yl,hr){var line 13if(cell.length>1){line=path+ 14(x-wc/2).toFixed(1)+' '+ 15yl.toFixed(1)+'l'+ 16wc.toFixed(1)+' -'+hr.toFixed(1)+'"/>\n' 17if(cell[1]){line+=path+ 18(x-wc/2).toFixed(1)+' '+ 19(yl-hr).toFixed(1)+'l'+ 20(wc/2).toFixed(1)+' '+(hr/2).toFixed(1)+'"/>\n'+ 21build_ch(cls+sf,x-wc/3,y,0)+ 22build_ch(cls+sf,x,y-hr*.32,1)}else{line+=build_ch(cls+sf,x-wc*.2,y-hr/4,0)} 23if(cell.length>=3){if(cell[3]){line+=path+ 24x.toFixed(1)+' '+ 25(yl-hr/2).toFixed(1)+'l'+ 26(wc/2).toFixed(1)+' '+(hr/2).toFixed(1)+'"/>\n'+ 27build_ch(cls+sf,x,y+hr*.3,2)+ 28build_ch(cls+sf,x+wc/3,y,3)}else{line+=build_ch(cls+sf,x+wc*.2,y+hr/4,2)}}}else{line=build_ch(cls,x,y,0)} 29return line} 30hr=font.size*2.1 31if(wc<hr*1.4) 32wc=hr*1.4 33w=wc*nc 34yl=3 35y=3-font.size*.7 36x0=(img.width/cfmt.scale-w)/2 37while(1){cl=cells.shift() 38if(!cl) 39break 40y+=hr 41yl+=hr 42x=x0+wc/2 43while(1){cell=cl.shift() 44if(!cell) 45break 46lc+=build_cell(cell,x,y,yl,hr) 47x+=wc}} 48line='<path class="stroke" d="\n' 49y=3 50for(i=0;i<=nr;i++){line+='M'+x0.toFixed(1)+' '+y.toFixed(1)+'h'+w.toFixed(1)+'\n' 51y+=hr} 52x=x0 53for(i=0;i<=nc;i++){line+='M'+x.toFixed(1)+' 3v'+(hr*nr).toFixed(1)+'\n' 54x+=wc} 55line+='"/>\n' 56line+=lc 57y=3-font.size*.7 58while(1){bl=bars.shift() 59if(!bl) 60break 61x=x0 62y+=hr 63while(1){bar=bl.shift() 64if(!bar) 65break 66if(bar[0]==':') 67line+='<text class="'+cls+'" x="'+ 68(x-5).toFixed(1)+'" y="'+y.toFixed(1)+'" style="font-weight:bold;font-size:'+ 69(font.size*1.6).toFixed(1)+'px">:</text>\n' 70if(bar.slice(-1)==':') 71line+='<text class="'+cls+'" x="'+ 72(x+5).toFixed(1)+'" y="'+y.toFixed(1)+'" style="font-weight:bold;font-size:'+ 73(font.size*1.6).toFixed(1)+'px">:</text>\n' 74x+=wc}} 75abc.out_svg(line) 76abc.vskip(hr*nr+6)} 77if(!cfmt.gridfont) 78abc.param_set_font("gridfont","serif 16") 79font=abc.get_font('grid') 80font_cl=abc.font_class(font) 81cls=font_cl+" mid" 82abc.add_style("\n.mid {text-anchor:middle}") 83abc.set_font('grid') 84txt=txt.split('\n') 85while(1){ln=txt.shift() 86if(!ln) 87break 88ln=ln.match(/[|:]+|[^|:\s]+/g) 89bars[nr]=[] 90cells[nr]=[] 91i=-1 92while(1){cl=ln.shift() 93if(!cl) 94break 95if(cl.match(/[:|]+/)){bars[nr][++i]=cl 96cells[nr][i]=[]}else{if(!cells[nr][i]){bars[nr][++i]='|' 97cells[nr][i]=[]} 98if(cl=='.'||cl=='-') 99cl='' 100cells[nr][i].push(cl)}} 101if(cells[nr][i].length) 102bars[nr][++i]='|' 103else 104cells[nr][i]=null 105if(i>nc) 106nc=i 107i=0 108while(1){cl=cells[nr][i++] 109if(!cl) 110break 111if(cl.length==2){cl[2]=cl[1] 112cl[1]=''} 113w=abc.strwh(cl.join(''))[0] 114if(w>wc) 115wc=w} 116nr++} 117wc+=abc.strwh(' ')[0] 118abc.blk_flush() 119build_grid() 120abc.blk_flush()},do_begin_end:function(of,type,opt,txt){var vt=this.get_voice_tb() 121if(type!="grid"){of(type,opt,txt) 122return} 123txt=txt.replace(/#|=|b/g,function(x){switch(x){case'#':return"\u266f" 124case'=':return"\u266e"} 125return"\u266d"}) 126if(opt.indexOf("chord-define")>=0) 127this.cfmt().csdef=txt 128if(opt.indexOf("noprint")<0){if(this.parse.state>=2){s=this.new_block(type) 129s.text=txt}else{abc2svg.grid3.block_gen.call(this,null,{subtype:type,text:txt})}}},output_music:function(of){var ln,i,dt,ss,ntim,p_vc,s3,C=abc2svg.C,abc=this,s=abc.get_tsfirst(),vt=abc.get_voice_tb(),t=abc.cfmt().csdef,cs=[] 130function add_cs(ss,ch){var s={type:C.REST,fname:ss.fname,istart:ss.istart,iend:ss.iend,v:p_vc.v,p_v:p_vc,time:ntim,st:0,dur:0,dur_orig:0,invis:true,seqst:true,nhd:0,notes:[{pit:18,dur:0}]} 131if(ch!='.'&&ch!='-'){abc.set_a_gch(s,[{type:'g',text:ch,otext:ch,istart:ss.istart,iend:ss.iend,font:abc.get_font("gchord")}])} 132if(!p_vc.last_sym){p_vc.sym=s}else{s.prev=p_vc.last_sym 133s.prev.next=s} 134p_vc.last_sym=s 135s.ts_next=ss 136s.ts_prev=ss.ts_prev 137s.ts_prev.ts_next=s 138ss.ts_prev=s 139if(s.time==ss.time) 140delete ss.seqst 141return s} 142if(t){p_vc={id:"grid3",v:vt.length,time:0,pos:{gst:0},scale:1,st:0,second:true,sls:[]} 143vt.push(p_vc) 144t=t.split('\n') 145while(1){ln=t.shift() 146if(!ln) 147break 148ln=ln.trimLeft() 149if(ln[0]=='|') 150ln=ln.slice(ln[1]==':'?2:1) 151if(ln[ln.length-1]!='|') 152ln=ln+'|' 153ln=ln.match(/[|:]+|[^|:\s]+/g) 154while(1){cl=ln.shift() 155if(!cl) 156break 157if(cl[0]=='|'||cl[0]==':'){while(s&&!s.dur) 158s=s.ts_next 159if(!s) 160break 161ss=s 162while(s&&!s.bar_type) 163s=s.ts_next 164if(!cs.length) 165cs=['.'] 166ntim=ss.time 167dt=(s.time-ntim)/cs.length 168s3=null 169for(i=0;i<cs.length;i++){if((cs[i]!='.'&&cs[i]!='-')||!s3){while(ss.time<ntim) 170ss=ss.ts_next 171s3=add_cs(ss,cs[i])} 172s3.dur+=dt 173s3.dur_orig=s3.notes[0].dur=s3.dur 174ntim+=dt} 175while(s&&s.type!=C.BAR) 176s=s.ts_next 177ss={type:C.BAR,bar_type:"|",fname:s.fname,istart:s.istart,iend:s.iend,v:p_vc.v,p_v:p_vc,st:0,time:s.time,dur:0,nhd:0,notes:[{pit:18}],next:s,ts_next:s,prev:s.prev,ts_prev:s.ts_prev} 178if(!s) 179break 180if(s.seqst){ss.seqst=true 181delete s.seqst} 182ss.prev.next=ss.ts_prev.ts_next=s.prev=s.ts_prev=ss 183cs=[]}else{cs.push(cl)}}}} 184of()},set_hooks:function(abc){abc.block_gen=abc2svg.grid3.block_gen.bind(abc,abc.block_gen) 185abc.do_begin_end=abc2svg.grid3.do_begin_end.bind(abc,abc.do_begin_end) 186abc.output_music=abc2svg.grid3.output_music.bind(abc,abc.output_music)}} 187abc2svg.modules.hooks.push(abc2svg.grid3.set_hooks) 188abc2svg.modules.begingrid.loaded=true 189