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//MIDI.js-module to handle the%%MIDI parameters
5abc2svg.MIDI={do_midi:function(parm){function abc_b40(p){var pit,acc=0,i=0
6switch(p[0]){case'^':if(p[++i]=='^'){acc=2
7i++}else{acc=1}
8break
9case'=':i++
10break
11case'_':if(p[++i]=='_'){acc=-2
12i++}else{acc=-1}
13break}
14pit='CDEFGABcdefgab'.indexOf(p[i++])+16
15if(pit<16)
16return
17while(p[i]=="'"){pit+=7
18i++}
19while(p[i]==","){pit-=7
20i++}
21return abc2svg.pab40(pit,acc).toString()}
22function mid_pit(p){var b40,pit=p
23p=(pit/12)|0
24pit=pit%12;b40=p*40+abc2svg.isb40[pit]+2
25return{pit:abc2svg.b40p(b40),acc:abc2svg.b40a(b40)}}
26function tb40(qs){var i,n1=[2,25,8,31,14,37,20,3,26,9,32,15,38,21,4,27,10,33,16,39],n2=[0,19,36,13,30,7,24,1,18,35,12,29,6,23,0,17],da=21-3*qs
27b=new Float32Array(40)
28for(i=0;i<n1.length;i++)
29b[n1[i]]=(qs*i+da)%12
30for(i=1;i<=n2.length;i++)
31b[n2[i]]=12-(qs*i-da)%12
32return b}
33var n,v,s,maps,o,q,n,qs,a=parm.split(/\s+/),abc=this,cfmt=abc.cfmt(),curvoice=abc.get_curvoice()
34if(curvoice){if(curvoice.ignore)
35return
36if(curvoice.chn==undefined)
37curvoice.chn=curvoice.v<9?curvoice.v:curvoice.v+1}
38switch(a[1]){case"chordname":if(!cfmt.chord)
39cfmt.chord={}
40if(!cfmt.chord.names)
41cfmt.chord.names={}
42cfmt.chord.names[a[2]]=a.slice(3)
43break
44case"chordprog":if(!cfmt.chord)
45cfmt.chord={}
46cfmt.chord.prog=a[2]
47if(a[3]&&a[3].slice(0,7)=="octave=")
48cfmt.chord.trans=Number(a[3].slice(7))
49break
50case"chordvol":v=Number(a[2])
51if(isNaN(v)||v<0||v>127){abc.syntax(1,abc.errs.bad_val,"%%MIDI chordvol")
52break}
53if(!cfmt.chord)
54cfmt.chord={}
55cfmt.chord.vol=v/127
56break
57case"gchordon":case"gchordoff":if(!cfmt.chord)
58cfmt.chord={}
59if(abc.parse.state==2)
60abc.goto_tune()
61if(abc.get_curvoice()){s=abc.new_block("midigch")
62s.play=true
63s.on=a[1][7]=='n'}else{cfmt.chord.gchon=a[1][7]=='n'}
64break
65case"channel":v=parseInt(a[2])
66if(isNaN(v)||v<=0||v>16){abc.syntax(1,abc.errs.bad_val,"%%MIDI channel")
67break}
68if(--v!=9){if(abc.parse.state==3){s=abc.new_block("midichn");s.play=true
69s.chn=v}else{abc.set_v_param("channel",v)}
70break}
71abc2svg.MIDI.do_midi.call(abc,"MIDI control 0 1")
72abc2svg.MIDI.do_midi.call(abc,"MIDI control 32 0")
73break
74case"drummap":n=abc_b40(a[2])
75v=Number(a[3])
76if(!n||!v){abc.syntax(1,abc.errs.bad_val,"%%MIDI drummap")
77break}
78maps=abc.get_maps()
79if(!maps.MIDIdrum)
80maps.MIDIdrum={}
81if(!maps.MIDIdrum[n])
82maps.MIDIdrum[n]=[]
83maps.MIDIdrum[n][3]=mid_pit(v)
84abc.set_v_param("mididrum","MIDIdrum")
85break
86case"program":if(a[3]!=undefined){abc2svg.MIDI.do_midi.call(abc,"MIDI channel "+a[2])
87v=a[3]}else{v=a[2]}
88v=parseInt(v)
89if(isNaN(v)||v<0||v>127){abc.syntax(1,abc.errs.bad_val,"%%MIDI program")
90break}
91if(abc.parse.state==3){s=abc.new_block("midiprog");s.play=true
92s.instr=v}else{abc.set_v_param("instr",v)}
93break
94case"control":n=parseInt(a[2])
95if(isNaN(n)||n<0||n>127){abc.syntax(1,"Bad controller number in %%MIDI")
96break}
97v=parseInt(a[3])
98if(isNaN(v)||v<0||v>127){abc.syntax(1,"Bad controller value in %%MIDI")
99break}
100if(abc.parse.state==3){s=abc.new_block("midictl");s.play=true
101s.ctrl=n;s.val=v}else{abc.set_v_param("midictl",a[2]+' '+a[3])}
102break
103case"temperamentequal":n=parseInt(a[2])
104if(isNaN(n)||n<5||n>255){abc.syntax(1,abc.errs.bad_val,"%%MIDI "+a[1])
105return}
106if(n==53){s=abc.get_glyphs()
107s.acc12_53='<text id="acc12_53" x="-1">&#xe282;</text>'
108s.acc24_53='<text id="acc24_53" x="-1">&#xe282;\
109 <tspan x="0" y="-10" style="font-size:8px">2</tspan></text>'
110s.acc36_53='<text id="acc36_53" x="-1">&#xe262;\
111 <tspan x="0" y="-10" style="font-size:8px">3</tspan></text>'
112s.acc48_53='<text id="acc48_53" x="-1">&#xe262;</text>'
113s.acc60_53='<g id="acc60_53">\n\
114 <text style="font-size:1.2em" x="-1">&#xe282;</text>\n\
115 <path class="stroke" stroke-width="1.6" d="M-2 1.5l7 -3"/>\n\
116</g>'
117s["acc-60_53"]='<text id="acc-60_53" x="-1">&#xe260;</text>'
118s["acc-48_53"]='<g id="acc-48_53">\n\
119 <text x="-1">&#xe260;</text>\n\
120 <path class="stroke" stroke-width="1" d="M-3 -5.5l5 -2"/>\n\
121</g>'
122s["acc-36_53"]='<g id="acc-36_53">\n\
123 <text x="-1">&#xe260;\
124  <tspan x="0" y="-10" style="font-size:8px">3</tspan></text>\n\
125 <path class="stroke" stroke-width="1" d="M-3 -5.5l5 -2"/>\n\
126</g>'
127s["acc-24_53"]='<text id="acc-24_53" x="-2">&#xe280;\
128 <tspan x="0" y="-10" style="font-size:8px">2</tspan></text>'
129s["acc-12_53"]='<text id="acc-12_53" x="-2">&#xe280;</text>'}
130q=7.019550008653874,o=12
131cfmt.nedo=n
132qs=((n*q/o+.5)|0)*o/n
133if(qs<6.85||qs>7.2)
134abc.syntax(0,abc.errs.bad_val,"%%MIDI "+a[1])
135cfmt.temper=tb40(qs)
136break}},set_vp:function(of,a){var i,item,curvoice=this.get_curvoice()
137for(i=0;i<a.length;i++){switch(a[i]){case"channel=":curvoice.chn=a[++i]
138break
139case"instr=":curvoice.instr=a[++i]
140break
141case"midictl=":if(!curvoice.midictl)
142curvoice.midictl=[]
143item=a[++i].split(' ');curvoice.midictl[item[0]]=Number(item[1])
144break
145case"mididrum=":if(!curvoice.map)
146curvoice.map={}
147curvoice.map=a[++i]
148break}}
149of(a)},do_pscom:function(of,text){if(text.slice(0,5)=="MIDI ")
150abc2svg.MIDI.do_midi.call(this,text)
151else
152of(text)},set_hooks:function(abc){abc.do_pscom=abc2svg.MIDI.do_pscom.bind(abc,abc.do_pscom);abc.set_vp=abc2svg.MIDI.set_vp.bind(abc,abc.set_vp)}}
153abc2svg.modules.hooks.push(abc2svg.MIDI.set_hooks);abc2svg.modules.MIDI.loaded=true
154