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"></text>' 108s.acc24_53='<text id="acc24_53" x="-1">\ 109 <tspan x="0" y="-10" style="font-size:8px">2</tspan></text>' 110s.acc36_53='<text id="acc36_53" x="-1">\ 111 <tspan x="0" y="-10" style="font-size:8px">3</tspan></text>' 112s.acc48_53='<text id="acc48_53" x="-1"></text>' 113s.acc60_53='<g id="acc60_53">\n\ 114 <text style="font-size:1.2em" x="-1"></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"></text>' 118s["acc-48_53"]='<g id="acc-48_53">\n\ 119 <text x="-1"></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">\ 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">\ 128 <tspan x="0" y="-10" style="font-size:8px">2</tspan></text>' 129s["acc-12_53"]='<text id="acc-12_53" x="-2"></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