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//gamelan.js-module to output Gamelan(indonesian)music sheets
5abc2svg.gamelan={cde2fcg:new Int8Array([0,2,4,-1,1,3,5]),cgd2cde:new Int8Array([0,-4,-1,-5,-2,-6,-3,0,-4,-1,-5,-2,-6,-3,0]),acc2:new Int8Array([-2,-1,3,1,2]),do_pscom:function(of,p){switch(p.match(/\w+/)[0]){case'staves':case'score':p=p.replace(/\(|\)/g,'')
6break}
7of(p)},output_music:function(of){var C=abc2svg.C,abc=this,cur_sy=abc.get_cur_sy(),voice_tb=abc.get_voice_tb()
8if(!abc.cfmt().gamelan){of()
9return}
10function slice(s){var m,n,s2,s3,d,d_orig
11if(s.dur<=C.BLEN*3/8){if((s.dur_orig/9|0)*9!=s.dur_orig)
12return
13d=s.dur/3
14d_orig=s.dur_orig/3
15s.dur-=d
16s.dur_orig-=d_orig
17n=1}else{if(s.dur>=C.BLEN)
18n=3
19else if(s.dur==C.BLEN/2)
20n=1
21else
22n=2
23d=d_orig=C.BLEN/4
24s.dur=s.dur_orig=C.BLEN/4}
25for(m=0;m<=s.nhd;m++)
26s.notes[m].dur=s.dur
27s.beam_on=true
28while(--n>=0){s2={type:C.REST,v:s.v,p_v:s.p_v,st:s.st,dur:d,dur_orig:d_orig,stem:1,multi:0,nhd:0,notes:[{pit:s.notes[0].pit,jn:8}],xmx:0,beam_on:true,noplay:true,time:s.time+s.dur,prev:s,next:s.next}
29s.next=s2
30if(s2.next)
31s2.next.prev=s2
32if(!s.ts_next){s.ts_next=s2
33if(s.soln)
34s.soln=false
35s2.ts_prev=s
36s2.seqst=true}else{for(s3=s.ts_next;s3;s3=s3.ts_next){if(s3.time<s2.time)
37continue
38if(s3.time>s2.time){s2.seqst=true
39s3=s3.ts_prev}
40s2.ts_next=s3.ts_next
41s2.ts_prev=s3
42if(s2.ts_next)
43s2.ts_next.ts_prev=s2
44s3.ts_next=s2
45break}}
46s=s2}}
47function do_tie(s){var end_time=s.time+s.dur
48while(1){s=s.ts_next
49if(!s||s.time>end_time)
50return
51if(s.type==C.NOTE&&s.time==end_time)
52break}
53s.notes[0].jn=8
54s.notes[0].jo=2}
55function set_sym(p_v){var s,s2,note,pit,nn,p,a,m,i,sf=p_v.key.k_sf
56delta=abc2svg.gamelan.cgd2cde[sf+7]-2
57p_v.key.k_a_acc=[]
58p_v.clef.invis=true
59for(s=p_v.sym;s;s=s.next){s.st=p_v.st
60switch(s.type){case C.CLEF:s.invis=true
61default:continue
62case C.KEY:delta=abc2svg.gamelan.cgd2cde[s.k_sf+7]-2
63continue
64case C.REST:if(s.notes[0].jn)
65continue
66s.notes[0].jn=0
67s.notes[0].pit=21
68slice(s)
69continue
70case C.NOTE:break}
71s.stem=1
72s.stemless=true
73if(s.sls){for(i=0;i<s.sls.length;i++)
74s.sls[i].ty=C.SL_BELOW}
75for(m=0;m<=s.nhd;m++){note=s.notes[m]
76p=note.pit
77pit=p+delta
78if(note.jn==undefined){note.jn=((pit+77)%7)+1
79note.jo=(pit/7)|0}
80note.pit=21
81a=note.acc
82if(a){nn=abc2svg.gamelan.cde2fcg[(p+5+16*7)%7]-sf
83if(a!=3)
84nn+=a*7
85nn=((((nn+1+21)/7)|0)+2-3+32*5)%5
86note.acc=abc2svg.gamelan.acc2[nn]}
87if(note.tie_ty){do_tie(s)
88delete note.tie_ty}}
89slice(s)
90if(s.a_dd){for(i=0;i<s.a_dd.length;i++){if(s.a_dd[i].glyph=="stc"){abc.deco_cnv(["gstc"],s)
91s.a_dd[i]=s.a_dd.pop()}}}}}
92for(v=0;v<voice_tb.length;v++)
93set_sym(voice_tb[v])
94of()},draw_symbols:function(of,p_voice){var i,m,nl,note,s,s2,x,y,C=abc2svg.C,abc=this,dot="\ue1e7",staff_tb=abc.get_staff_tb(),out_svg=abc.out_svg,out_sxsy=abc.out_sxsy,xypath=abc.xypath
95if(!abc.cfmt().gamelan){of(p_voice)
96return}
97function draw_dur(s1,y,s2,n,nl){var s,s3
98xypath(s1.x-3,y+24)
99out_svg('h'+(s2.x-s1.x+8).toFixed(1)+'"/>\n')
100y-=2.5
101while(++n<=nl){s=s1
102while(1){if(s.nflags&&s.nflags>=n){s3=s
103while(s!=s2){if(s.next.beam_br1||(s.next.beam_br2&&n>2)||(s.next.nflags&&s.next.nflags<n))
104break
105s=s.next}
106draw_dur(s3,y,s,n,nl)}
107if(s==s2)
108break
109s=s.next}}}
110function out_mus(x,y,p){out_svg('<text x="')
111out_sxsy(x,'" y="',y)
112out_svg('">'+p+'</text>\n')}
113function out_txt(x,y,p){out_svg('<text class="bn" x="')
114out_sxsy(x,'" y="',y)
115out_svg('">'+p+'</text>\n')}
116function draw_hd(s,x,y){var m,note,ym
117for(m=0;m<=s.nhd;m++){note=s.notes[m]
118out_txt(x-3.5,y+8,"01234567."[note.jn])
119if(note.acc){out_svg('<path class="stroke" stroke-width="1.1" d="M')
120if(note.acc>0){out_sxsy(x-6,' ',y+10)
121out_svg("l12 -6")}else{out_sxsy(x-6,' ',y+16)
122out_svg("l12 6")}
123out_svg('"/>\n')}
124if(note.jo>2){out_mus(x-1,y+23,dot)
125if(note.jo>3){y+=3
126out_mus(x-1,y+23.4,dot)}}else if(note.jo<2){ym=y+4
127out_mus(x-1,ym,dot)}
128y+=20}}
129for(s=p_voice.sym;s;s=s.next){if(s.invis)
130continue
131switch(s.type){case C.NOTE:case C.REST:x=s.x
132y=staff_tb[s.st].y
133draw_hd(s,x,y)
134if(s.nflags>0){if(s.beam_st){nl=s.nflags
135s2=s
136while(1){if(s2.nflags&&s2.nflags>nl)
137nl=s2.nflags
138if(s2.beam_end)
139break
140if(!s2.next||!s2.next.nflags||s2.next.nflags<=0)
141break
142s2=s2.next}
143draw_dur(s,y+7,s2,1,nl)}}
144break}}},set_fmt:function(of,cmd,param){if(cmd=="gamelan"){var cfmt=this.cfmt()
145cfmt.gamelan=true
146cfmt.staffsep=20
147cfmt.sysstaffsep=14
148this.set_v_param("stafflines","...")
149cfmt.tuplets=[0,1,0,1]
150return}
151of(cmd,param)},set_pitch:function(of,last_s){of(last_s)
152if(!last_s||!this.cfmt().gamelan)
153return
154var C=abc2svg.C
155for(var s=this.get_tsfirst();s;s=s.ts_next){switch(s.type){case C.NOTE:s.ymx=20*s.nhd+(s.nflags>0?30:24)
156if(s.notes[s.nhd].jo>2){s.ymx+=3
157if(s.notes[s.nhd].jo>3)
158s.ymx+=2}
159break}}},set_width:function(of,s){of(s)
160if(!this.cfmt().gamelan)
161return
162var w,m,note,C=abc2svg.C
163switch(s.type){case C.CLEF:case C.KEY:case C.METER:s.wl=s.wr=0
164break}},set_hooks:function(abc){abc.do_pscom=abc2svg.gamelan.do_pscom.bind(abc,abc.do_pscom)
165abc.draw_symbols=abc2svg.gamelan.draw_symbols.bind(abc,abc.draw_symbols)
166abc.output_music=abc2svg.gamelan.output_music.bind(abc,abc.output_music)
167abc.set_format=abc2svg.gamelan.set_fmt.bind(abc,abc.set_format)
168abc.set_pitch=abc2svg.gamelan.set_pitch.bind(abc,abc.set_pitch)
169abc.set_width=abc2svg.gamelan.set_width.bind(abc,abc.set_width)
170abc.get_glyphs().gstc='<circle id="gstc" cx="0" cy="-3" r="2"/>'
171abc.get_decos().gstc="0 gstc 5 1 1"
172abc.add_style("\n.bn {font-family:sans-serif; font-size:16px}")}}
173abc2svg.modules.hooks.push(abc2svg.gamelan.set_hooks)
174abc2svg.modules.gamelan.loaded=true
175