// abc2svg - ABC to SVG translator // @source: https://chiselapp.com/user/moinejf/repository/abc2svg // Copyright (C) 2014-2023 Jean-Francois Moine - LGPL3+ //snd-1.js-file to include in html pages with abc2svg-1.js for playing function AbcPlay(i_conf){var conf=i_conf,init={},audio=ToAudio(),audio5,midi5,current,abcplay={clear:audio.clear,add:audio.add,set_sfu:function(v){if(v==undefined) return conf.sfu conf.sfu=v},set_speed:function(v){if(v==undefined) return conf.speed conf.new_speed=v},set_vol:function(v){if(v==undefined) return conf.gain;conf.gain=v if(current&¤t.set_vol) current.set_vol(v)},play:play,stop:vf} function vf(){} function play(istart,i_iend,a_e){init.istart=istart;init.i_iend=i_iend;init.a_e=a_e if(midi5) midi5.get_outputs(play2) else play2()} function play2(out){var o if(!out) out=[] o=audio5.get_outputs() if(o) Array.prototype.push.apply(out,o) if(out.length==0){if(conf.onend) conf.onend() return} if(out.length==1){o=0}else{o=-1 var pr="Use" for(var i=0;i=out.length) o=-1} if(!res||o<0){if(conf.onend) conf.onend() return}} current=out[o]=='sf2'?audio5:midi5;abcplay.play=current.play;abcplay.stop=current.stop if(current.set_output) current.set_output(out[o]);abcplay.play(init.istart,init.i_iend,init.a_e)} conf.gain=0.7;conf.speed=1;(function(){var v try{if(!localStorage) return}catch(e){return} if(!conf.sfu){v=localStorage.getItem("sfu") if(v) conf.sfu=v} v=localStorage.getItem("volume") if(v) conf.gain=Number(v)})() if(typeof Midi5=="function") midi5=Midi5(conf) if(typeof Audio5=="function") audio5=Audio5(conf);return abcplay} if(typeof module=='object'&&typeof exports=='object') exports.AbcPlay=AbcPlay if(!abc2svg) var abc2svg={} function ToAudio(){return{add:function(first,voice_tb,cfmt){var toaud=this,C=abc2svg.C,p_time=0,abc_time=0,play_fac=C.BLEN/4*120/60,i,n,dt,d,v,s=first,rst=s,rst_fac,rsk=[],b_tim,b_typ function get_beat(){var s=first.p_v.meter if(!s.a_meter[0]) return C.BLEN/4 if(!s.a_meter[0].bot) return(s.a_meter[1]&&s.a_meter[1].top=='|')?C.BLEN/2:C.BLEN/4 if(s.a_meter[0].bot=="8"&&s.a_meter[0].top%3==0) return C.BLEN/8*3 return C.BLEN/s.a_meter[0].bot|0} function def_beats(){var i,s2,s3,tim,last_d,beat=get_beat(),d=first.p_v.meter.wmeasure,nb=d/beat|0,v=voice_tb.length,p_v={id:"_beats",v:v,sym:{type:C.BLOCK,v:v,subtype:"midiprog",chn:9,instr:16384,ts_prev:first}},s={type:C.NOTE,v:v,p_v:p_v,dur:beat,nhd:0,notes:[{midi:37}]} for(s2=first;s2;s2=s2.ts_next){if(s2.bar_type&&s2.time){nb=(2*d-s2.time)/beat|0 last_d=beat-s2.time break}} s2=p_v.sym for(s3=first;s3&&!s3.time;s3=s3.ts_next){if(s3.type==C.TEMPO){s3=Object.create(s3) s3.v=v s3.p_v=p_v s3.prev=s3.ts_prev=s2 s2.next=s2.ts_next=s3 s2=s3 play_fac=set_tempo(s2) break}} voice_tb[v]=p_v p_v.sym.p_v=p_v tim=abc_time=-d first.time=s2.time=tim if(s3) p_v.sym.time=tim for(i=0;i='A'&&c<='Z'){j=r.length r+=c continue} n=Number(c) if(isNaN(n)) break v=r.slice(j) if(r.length+v.length*n>128) continue while(--n>0) r+=v} s.parts=r s.p_s=[] while(1){if(!s.ts_next){s.part1=first break} s=s.ts_next if(s.part){s.part1=first v=s.part.text[0] for(i=0;i='1'&&d<='9') rsk[Number(d)]=s else if(d!=',') rsk.push(s)}} if(cfmt.chord) abc2svg.chord(first,voice_tb,cfmt) if(cfmt.playbeats) def_beats() if(s.parts) build_parts(s) rst_fac=play_fac while(s){if(s.noplay){s=s.ts_next continue} dt=s.time-abc_time if(dt!=0){p_time+=dt/play_fac abc_time=s.time} s.ptim=p_time if(s.part){rst=s rst_fac=play_fac} switch(s.type){case C.BAR:if(s.time!=b_tim){b_tim=s.time b_typ=0} if(s.text&&rsk.length>1&&s.text[0]!='1'){if(b_typ&1) break b_typ|=1 set_variant(s) play_fac=rst_fac rst=rsk[0]} if(s.bar_type[0]==':'){if(b_typ&2) break b_typ|=2 s.rep_p=rst if(rst==rsk[0]) s.rep_v=rsk} if(s.text){if(s.text[0]=='1'){if(b_typ&1) break b_typ|=1 s.rep_s=rsk=[rst] if(rst.bar_type&&rst.bar_type.slice(-1)!=':') rst.bar_type+=':' set_variant(s) rst_fac=play_fac}}else if(s.bar_type.slice(-1)==':'){if(b_typ&4) break b_typ|=4 rst=s rst_fac=play_fac}else if(s.rbstop==2){if(b_typ&8) break b_typ|=8 rst=s rst_fac=play_fac} break case C.GRACE:if(s.time==0&&abc_time==0){dt=0 if(s.sappo) dt=C.BLEN/16 else if(!s.next||s.next.type!=C.NOTE) dt=d/2 abc_time-=dt} gen_grace(s) break case C.REST:case C.NOTE:d=s.dur if(s.next&&s.next.type==C.GRACE){dt=0 if(s.next.sappo) dt=C.BLEN/16 else if(!s.next.next||s.next.next.type!=C.NOTE) dt=d/2 s.next.time-=dt d-=dt} d/=play_fac s.pdur=d v=s.v break case C.TEMPO:if(s.tempo) play_fac=set_tempo(s) break} s=s.ts_next}}}} abc2svg.play_next=function(po){function do_tie(not_s,d){var i,s=not_s.s,C=abc2svg.C,v=s.v,end_time=s.time+s.dur,repv=po.repv while(1){s=s.ts_next if(!s||s.time>end_time) break if(s.type==C.BAR){if(s.rep_p){if(!po.repn){s=s.rep_p end_time=s.time}} if(s.rep_s){if(!s.rep_s[repv]) break s=s.rep_s[repv++] end_time=s.time} while(s.ts_next&&!s.ts_next.dur) s=s.ts_next continue} if(s.time=0){note=s.notes[i] if(note.tie_s==not_s){d+=s.pdur/po.conf.speed return note.tie_e?do_tie(note,d):d}}} return d} function set_ctrl(po,s2,t){var i,p_v=s2.p_v,s={subtype:"midictl",p_v:p_v,v:s2.v} for(i in p_v.midictl){s.ctrl=Number(i) s.val=p_v.midictl[i] po.midi_ctrl(po,s,t)} for(s=p_v.sym;s!=s2;s=s.next){if(s.subtype=="midictl") po.midi_ctrl(po,s,t) else if(s.subtype=='midiprog') po.midi_prog(po,s)} i=po.v_c[s2.v] if(i==undefined) po.v_c[s2.v]=i=s2.v<9?s2.v:s2.v+1 if(po.c_i[i]==undefined) po.c_i[i]=0 po.p_v[s2.v]=true} function play_cont(po){var d,i,st,m,note,g,s2,t,maxt,now,C=abc2svg.C,s=po.s_cur function var_end(s){var i,s2,s3,a=s.rep_v||s.rep_s ti=0 for(i=1;iti){ti=s2.time s3=s2}} for(s=s3;s!=po.s_end;s=s.ts_next){if(s.time==ti) continue if(s.rbstop==2) break} po.repv=1 return s} if(po.stop){if(po.onend) po.onend(po.repv) return} while(s.noplay){s=s.ts_next if(!s||s==po.s_end){if(po.onend) po.onend(po.repv) return}} t=po.stim+s.ptim/po.conf.speed now=po.get_time(po) if(po.conf.new_speed){po.stim=now-(now-po.stim)*po.conf.speed/po.conf.new_speed po.conf.speed=po.conf.new_speed po.conf.new_speed=0 t=po.stim+s.ptim/po.conf.speed} maxt=t+po.tgen po.timouts=[] while(1){if(!po.p_v[s.v]) set_ctrl(po,s,t) switch(s.type){case C.BAR:s2=null if(s.rep_p){po.repv++ if(!po.repn&&(!s.rep_v||po.repv<=s.rep_v.length)){s2=s.rep_p po.repn=true}else{if(s.rep_v) s2=var_end(s) po.repn=false}} if(s.rep_s){s2=s.rep_s[po.repv] if(s2){po.repn=false if(s2==s) s2=null}else{s2=var_end(s) if(s2==po.s_end) break}} if(s.bar_type.slice(-1)==':'&&s.bar_type[0]!=':') po.repv=1 if(s2){po.stim+=(s.ptim-s2.ptim)/po.conf.speed s=s2 while(s&&!s.dur) s=s.ts_next if(!s) break t=po.stim+s.ptim/po.conf.speed break} if(!s.part1){while(s.ts_next&&!s.ts_next.seqst){s=s.ts_next if(s.part1) break} if(!s.part1) break} default:if(s.part1&&po.i_p!=undefined){s2=s.part1.p_s[++po.i_p] if(s2){po.stim+=(s.ptim-s2.ptim)/po.conf.speed s=s2 t=po.stim+s.ptim/po.conf.speed}else{s=po.s_end} po.repv=1} break} if(s&&s!=po.s_end){switch(s.type){case C.BAR:break case C.BLOCK:if(s.subtype=="midictl") po.midi_ctrl(po,s,t) else if(s.subtype=='midiprog') po.midi_prog(po,s) break case C.GRACE:for(g=s.extra;g;g=g.next){d=g.pdur/po.conf.speed for(m=0;m<=g.nhd;m++){note=g.notes[m] if(!note.noplay) po.note_run(po,g,note.midi,t+g.ptim-s.ptim,d)}} break case C.NOTE:case C.REST:d=s.pdur/po.conf.speed if(s.type==C.NOTE){for(m=0;m<=s.nhd;m++){note=s.notes[m] if(note.tie_s||note.noplay) continue po.note_run(po,s,note.midi,t,note.tie_e?do_tie(note,d):d)}} if(po.onnote&&s.istart){i=s.istart st=(t-now)*1000 po.timouts.push(setTimeout(po.onnote,st,i,true)) if(d>2) d-=.1 setTimeout(po.onnote,st+d*1000,i,false)} break}} while(1){if(!s||s==po.s_end||!s.ts_next){if(po.onend) setTimeout(po.onend,(t-now+d)*1000,po.repv) po.s_cur=s return} s=s.ts_next if(!s.noplay) break} t=po.stim+s.ptim/po.conf.speed if(t>maxt) break} po.s_cur=s po.timouts.push(setTimeout(play_cont,(t-now)*1000 -300,po))} function get_part(po){var s,i,s_p for(s=po.s_cur;s;s=s.ts_prev){if(s.parts){po.i_p=-1 return} s_p=s.part1 if(!s_p||!s_p.p_s) continue for(i=0;i>16)&0xff a[j++]=(t>>8)&0xff a[j++]=t&0xff} if(l!=s.length){t=(b64d[s[i]]<<18)+ (b64d[s[i+1]]<<12)+ (b64d[s[i+2]]<<6)+ b64d[s[i+3]] a[j++]=(t>>16)&0xff if(j>8)&0xff} return a} function sample_cp(b,s){var i,n,a=b.getChannelData(0) for(i=0;i>7,p=instr%128,pr=sf2pre rates[instr]=[] for(i=0;i=.4) parm.sustain=0.01 else parm.sustain=1-parm.sustain/.4 sample_cp(parm.buffer,sample) if(parm.sm){parm.loopStart=sf2par.sampleHeader[sid].startLoop/sampleRate parm.loopEnd=sf2par.sampleHeader[sid].endLoop/sampleRate} scale=(gen.scaleTuning?gen.scaleTuning.amount:100)/100,tune=(gen.coarseTune?gen.coarseTune.amount:0)+ (gen.fineTune?gen.fineTune.amount:0)/100+ sf2par.sampleHeader[sid].pitchCorrection/100- (gen.overridingRootKey?gen.overridingRootKey.amount:sf2par.sampleHeader[sid].originalPitch) for(j=gen.keyRange.lo;j<=gen.keyRange.hi;j++){rates[instr][j]=Math.pow(Math.pow(2,1/12),(j+tune)*scale) params[instr][j]=parm}}}} function load_instr(instr){w_instr++ abc2svg.loadjs(conf.sfu+'/'+instr+'.js',function(){var sf2par=new sf2.Parser(b64dcod(abcsf2[instr])) sf2par.parse() var sf2pre=sf2par.getPresets() sf2_create(instr,sf2par,sf2pre) if(--w_instr==0) play_start()},function(){errmsg('could not find the instrument '+ ((instr/128)|0).toString()+'-'+ (instr%128).toString()) if(--w_instr==0) play_start()})} function def_instr(s,f,sf2par,sf2pre){var i,bk=[],nv=-1,vb=0 s=s.p_v.sym while(s.ts_prev) s=s.ts_prev for(;s;s=s.ts_next){if(s.v>nv){nv=s.v bk[nv]=0 if(s.p_v.midictl){if(s.p_v.midictl[0]) bk[s.v]=(bk[s.v]&~0x1fc000) +(s.p_v.midictl[0]<<14) if(s.p_v.midictl[32]) bk[s.v]=(bk[s.v]&~0x3f80) +(s.p_v.midictl[32]<<7)}} switch(s.subtype){case"midiprog":break case"midictl":if(s.ctrl!=0&&s.ctrl!=32) continue if(bk[s.v]==undefined) bk[s.v]=0 if(s.ctrl==0) bk[s.v]=(bk[s.v]&~0x1fc000) +(s.val<<14) else bk[s.v]=(bk[s.v]&~0x3f80) +(s.val<<7) default:continue} vb|=1<>>0,genre:(data[ip++]|(data[ip++]<<8)|(data[ip++]<<16)|(data[ip++]<<24))>>>0,morphology:(data[ip++]|(data[ip++]<<8)|(data[ip++]<<16)|(data[ip++]<<24))>>>0})}};sf2.Parser.prototype.parsePbag=function(chunk){var data=this.input,ip=chunk.offset,presetZone=this.presetZone=[],size=chunk.offset+chunk.size;if(chunk.type!=='pbag') throw new Error('invalid chunk type:'+chunk.type);while(ip>24;sampleLink=data[ip++]|(data[ip++]<<8);sampleType=data[ip++]|(data[ip++]<<8);var sample=new Int16Array(new Uint8Array(data.subarray(this.samplingData.offset+start*2,this.samplingData.offset+end*2)).buffer);startLoop-=start;endLoop-=start;if(sampleRate>0){var adjust=this.adjustSampleData(sample,sampleRate);sample=adjust.sample;sampleRate*=adjust.multiply;startLoop*=adjust.multiply;endLoop*=adjust.multiply} samples.push(sample);sampleHeader.push({sampleName:sampleName,startLoop:startLoop,endLoop:endLoop,sampleRate:sampleRate,originalPitch:originalPitch,pitchCorrection:pitchCorrection,sampleLink:sampleLink,sampleType:sampleType})}};sf2.Parser.prototype.adjustSampleData=function(sample,sampleRate){var newSample,i,il,j,multiply=1;while(sampleRate<22050){newSample=new Int16Array(sample.length*2);for(i=j=0,il=sample.length;i>16,lo:data[ip++],hi:data[ip++]}})}else{switch(key){case'keyRange':case'velRange':case'keynum':case'velocity':output.push({type:key,value:{lo:data[ip++],hi:data[ip++]}});break;default:output.push({type:key,value:{amount:data[ip++]|(data[ip++]<<8)<<16>>16}});break}} ip+=2;ip+=2} return output};sf2.Parser.prototype.parseGenerator=function(chunk){var data=this.input,ip=chunk.offset,size=chunk.offset+chunk.size,code,key,output=[];while(ip>16,lo:data[ip++],hi:data[ip++]}});continue} switch(key){case'keynum':case'keyRange':case'velRange':case'velocity':output.push({type:key,value:{lo:data[ip++],hi:data[ip++]}});break;default:output.push({type:key,value:{amount:data[ip++]|(data[ip++]<<8)<<16>>16}});break}} return output};sf2.Parser.prototype.getPresets=function(){var preset=this.presetHeader,zone=this.presetZone,output=[],bagIndex,bagIndexEnd,zoneInfo,presetGenerator,presetModulator,i,il,j,jl for(i=0,il=preset.length;i0){os=access.outputs.values() while(1){o=os.next() if(!o||o.done) break out.push(o.value.name)}} rf(out)} return{get_outputs:function(f){if(!navigator.requestMIDIAccess){f() return} rf=f navigator.requestMIDIAccess({sysex:true}).then(send_outputs,function(msg){navigator.requestMIDIAccess().then(send_outputs,function(msg){rf()})})},set_output:function(name){if(!Midi5.ma) return var o,os=Midi5.ma.outputs.values() while(1){o=os.next() if(!o||o.done) break if(o.value.name==name){op=o.value break}}},play:function(i_start,i_end,i_lvl){po={conf:conf,onend:conf.onend||empty,onnote:conf.onnote||empty,s_end:i_end,s_cur:i_start,repv:i_lvl||0,tgen:2,get_time:get_time,midi_ctrl:midi_ctrl,midi_prog:midi_prog,note_run:note_run,timouts:[],op:op,v_c:[],c_i:[]} if(0){op.send(new Uint8Array([0xf0,0x7f,0x7f,0x08,0x02,0x00,0x01,0x69,0x69,0x00,0,0xf7]),t)} abc2svg.play_next(po)},stop:function(){po.stop=true po.timouts.forEach(function(id){clearTimeout(id)}) abc2svg.play_next(po) if(op&&op.clear) op.clear()}}} function follow(abc,user,playconf){var keep_types={note:true,rest:true} user.anno_stop=function(type,start,stop,x,y,w,h){if(!keep_types[type]) return abc.out_svg('\n')} playconf.onnote=function(i,on){var b,i,e,elts,x=0,y=0 if(abc2svg.mu) elts=abc2svg.mu.d.getElementsByClassName('_'+i+'_') else elts=document.getElementsByClassName('_'+i+'_') if(!elts||!elts.length) return e=elts[0] e.style.fillOpacity=on?0.4:0 if(on&&!window.no_scroll){b=e.getBoundingClientRect() if(b.top<0||b.bottom>window.innerHeight*.8) y=b.top-window.innerHeight*.3 if(b.left<0||b.right>window.innerWidth*.8) x=b.left-window.innerWidth*.3 if(x||y) window.scrollBy({top:y,left:x,behavior:(x<0||y)?'instant':'smooth'})}}} (function(){var sty=document.createElement("style") sty.innerHTML=".abcr {fill: #d00000; fill-opacity: 0; z-index: 15}" document.head.appendChild(sty)})() abc2svg.ch_names={'':["C-E G C+","E-C G C+","G-C E G "],m:["C-e G C+","e-C G C+","G-C e G "],'7':["C-b-E G ","E-C G b ","G-E b C+","b-E G C+"],m7:["C-b-e G ","e-C G b ","G-e b C+","b-e G C+"],m7b5:["C-b-e g ","e-C g b ","g-e b C+","b-e g C+"],M7:["C-B-E G ","E-C G B ","G-E B C+","B-E G C+"],'6':["C-A-E G ","E-C A B ","A-E B C+","B-E A C+"],m6:["C-A-e G ","e-C A B ","A-e B C+","B-e A C+"],aug:["C-E a C+","E-C a C+","a-C E a "],aug7:["C-b-E a ","E-C a b ","a-E b C+","b-E a C+"],dim:["C-E g C+","E-C g C+","g-C E g "],dim7:["C-e g A ","e-C g A ","g-e A C+","A-C e G "],'9':["C-b-E G D+","E-C G b D+","G-E b C+D+","b-E G C+D+","D-G-C E b "],m9:["C-b-e G D+","e-C G b D+","G-e b C+D+","b-e G C+D+","D-G-C e b "],maj9:["C-B-E G D+","E-C G B D+","G-E B C+D+","B-E G C+D+","D-G-C E B "],M9:["C-B-E G D+","E-C G B D+","G-C E B D+","B-E G C+D+","D-G-C E B "],'11':["C-b-E G D+F+","E-C G b D+F+","G-E b C+D+F+","b-E G C+D+F+","D-G-C E b F+","F-D-G-C E b D+"],dim9:["C-A-e g d+","e-C g A d+","g-C e A d+","A-C e g d+","D-g-C e A "],sus4:["C-F G C+","F-C G C+","G-C F G "],sus9:["C-D G C+","D-C G C+","G-C D G "],'7sus4':["C-b-F G ","F-C G b ","G-F b C+","b-C F G "],'7sus9':["C-b-D G ","D-C G b ","G-D b C+","b-C D G "],'5':["C-G C+","G-G C+"]} abc2svg.midlet="CdDeEFgGaAbB" abc2svg.letmid={C:0,d:1,D:2,e:3,E:4,F:5,g:6,G:7,a:8,A:9,b:10,B:11} abc2svg.chord=function(first,voice_tb,cfmt){var chnm,i,k,vch,s,gchon,C=abc2svg.C,trans=48+(cfmt.chord.trans?cfmt.chord.trans*12:0) function chcr(b,ch){var i,v,r=[] b=abc2svg.midlet[b] i=ch.length while(--i>0){if(ch[i][0]==b) break} ch=ch[i] for(i=0;i=12)b=0;break case"b":case"♭":b--;if(b<0)b=11;break}}}} if(b==undefined) b=0 ch=chcr(b,ch) n=ch.length r+=trans if(sb.p_v.tr_snd) r+=sb.p_v.tr_snd for(m=0;m=12?"+":" ")} chnm[k]=[vch]}}else{chnm=abc2svg.ch_names} k=0 for(i=0;i