// abc2svg - ABC to SVG translator // @source: https://chiselapp.com/user/moinejf/repository/abc2svg // Copyright (C) 2014-2020 Jean-Francois Moine - LGPL3+ //snd-1.js-file to include in html pages with abc2svg-1.js for playing // // changes from Anika Henke : // changed default conf.sfu to point to CDN due to licensing issues 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]);if(abc2svg.pwait){if(typeof abc2svg.pwait=="boolean"){abc2svg.pwait=function(){abcplay.play(init.istart,init.i_iend,init.a_e)}} return} abcplay.play(init.istart,init.i_iend,init.a_e)} conf.gain=0.7;conf.speed=1;(function get_param(){try{if(!localStorage) return}catch(e){return} var 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,c,s=first,rst=s,rst_fac,rsk,b_tim,b_typ,instr=[],chn=[] function build_parts(first){var i,j,c,n,v,s=first,p=s.parts,st=[],r="" 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.part=first break} s=s.ts_next if(s.type==C.PART){s.part=first v=s.text[0] for(i=0;i='1'&&d<='9') rsk[Number(d)]=s else if(d!=',') rsk.push(s)}} if(cfmt.chord){if(!abc2svg.chord){abc2svg.pwait=true abc2svg.loadjs("chord-1.js",function(){toaud.add(first,voice_tb,cfmt)},function(){cfmt.chord=null toaud.add(first,voice_tb,cfmt)}) return} abc2svg.chord(first,voice_tb,cfmt)} if(s.parts) build_parts(s) midi_start() 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 switch(s.type){case C.BAR:if(s.time!=b_tim){b_tim=s.time b_typ=0} if(s.text&&rsk&&s.text[0]!='1'){if(b_typ&1) break b_typ|=1 set_variant(rsk,s.text,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(rsk&&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(rsk,s.text,s) rst_fac=play_fac}}else if(s.rbstop){if(s.bar_type.slice(-1)==':'){if(b_typ&4) break b_typ|=4}else{if(b_typ&8) break b_typ|=8} rst=s rst_fac=play_fac} break case C.BLOCK:do_block(s) 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 c=chn[v] s.chn=c s.instr=instr[c] break case C.PART:rst=s rst_fac=play_fac break case C.TEMPO:if(s.tempo) play_fac=set_tempo(s) break} s=s.ts_next} if(abc2svg.pwait){i=abc2svg.pwait delete abc2svg.pwait if(typeof i=="function") i()}}}} abc2svg.play_next=function(po){function do_tie(s,midi,d){var i,note,C=abc2svg.C,v=s.v,end_time=s.time+s.dur while(1){s=s.ts_next if(!s) return d switch(s.type){case 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[po.repv+1]) return d s=s.rep_s[po.repv+1] end_time=s.time} while(s.ts_next&&!s.ts_next.dur) s=s.ts_next} if(s.time>end_time) return d if(s.type==C.NOTE&&s.v==v) break} i=s.notes.length while(--i>=0){note=s.notes[i] if(note.midi==midi){note.ti2=true d+=s.pdur/po.conf.speed return note.tie_ty?do_tie(s,midi,d):d}} return d} function set_ctrl(po,s2,t){var i,p_v=s2.p_v,tim=s2.time,s={subtype:"midictl",p_v:p_v,v:p_v.v,chn:p_v.chn} 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&&s.time<=tim;s=s.next){if(s.subtype=="midictl") po.midi_ctrl(po,s,t)} po.p_v[s2.v]=true} function play_cont(po){var d,i,st,m,note,g,s2,t,maxt,C=abc2svg.C,s=po.s_cur 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 if(po.conf.new_speed){d=po.get_time(po) po.stim=d-(d-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:if(s.rep_p){po.repv++ if(!po.repn&&(!s.rep_v||po.repvmaxt) break} po.s_cur=s po.timouts.push(setTimeout(play_cont,(t-po.get_time(po))*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.part 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=.4) parm.sustain=0.01 else parm.sustain=1-parm.sustain/.4 sample_cp(parm.buffer,sample) if(gen.sampleModes&&(gen.sampleModes.amount&1)){parm.loopStart=parser.sampleHeader[sid].startLoop/sampleRate parm.loopEnd=parser.sampleHeader[sid].endLoop/sampleRate} var scale=(gen.scaleTuning?gen.scaleTuning.amount:100)/100,tune=(gen.coarseTune?gen.coarseTune.amount:0)+ (gen.fineTune?gen.fineTune.amount:0)/100+ parser.sampleHeader[sid].pitchCorrection/100- (gen.overridingRootKey?gen.overridingRootKey.amount:parser.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++ conf.instr_load(instr,function(sf2_bin){sf2_create(sf2_bin,instr) 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 load_res(s){var i while(s){i=s.instr if(i!=undefined&&!params[i]){params[i]=[] load_instr(i)} s=s.ts_next}} function get_time(po){return po.ac.currentTime} function midi_ctrl(po,s,t){if(s.ctrl==7) s.p_v.vol=s.val/127} function note_run(po,s,key,t,d){var g,st,instr=s.instr,k=key|0 parm=po.params[instr][k],o=po.ac.createBufferSource(),v=s.p_v.vol==undefined?1:s.p_v.vol if(!v||!parm) return o.buffer=parm.buffer if(parm.loopStart){o.loop=true o.loopStart=parm.loopStart o.loopEnd=parm.loopEnd} if(o.detune){var dt=(key*100)%100 if(dt) o.detune.value=dt} o.playbackRate.value=po.rates[instr][k] g=po.ac.createGain() if(parm.hold<0.002){g.gain.setValueAtTime(v,t)}else{if(parm.attack<0.002){g.gain.setValueAtTime(v,t)}else{g.gain.setValueAtTime(0,t) g.gain.linearRampToValueAtTime(v,t+parm.attack)} g.gain.setValueAtTime(v,t+parm.hold)} g.gain.exponentialRampToValueAtTime(parm.sustain*v,t+parm.decay) o.connect(g) g.connect(po.gain) o.start(t) o.stop(t+d)} function play_start(){if(po.stop){po.onend(repv) return} gain.connect(ac.destination) abc2svg.play_next(po)} init_b64d() if(!conf.sfu) conf.sfu="https://cdn.jsdelivr.net/npm/abc2svg@1.20.16/Scc1t2" if(!conf.instr_load){conf.instr_load=function(instr,done,fail){abc2svg.loadjs(conf.sfu+'/'+instr+'.js',function(){done(b64dcod(abcsf2[instr]))},fail)}} return{get_outputs:function(){return(window.AudioContext||window.webkitAudioContext)?['sf2']:null},play:function(i_start,i_end,i_lvl){errmsg=conf.errmsg||alert function play_unlock(){var buf=ac.createBuffer(1,1,22050),src=ac.createBufferSource() src.buffer=buf src.connect(ac.destination) src.noteOn(0)} if(!gain){ac=conf.ac if(!ac){conf.ac=ac=new(window.AudioContext||window.webkitAudioContext) if(/iPad|iPhone|iPod/.test(navigator.userAgent)) play_unlock()} gain=ac.createGain() gain.gain.value=conf.gain} while(i_start.noplay) i_start=i_start.ts_next 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,note_run:note_run,ac:ac,gain:gain,params:params,rates:rates} w_instr++ load_res(i_start) if(--w_instr==0) play_start()},stop:function(){po.stop=true po.timouts.forEach(function(id){clearTimeout(id)}) abc2svg.play_next(po) if(gain){gain.disconnect() gain=null}},set_vol:function(v){if(gain) gain.gain.value=v}}} (function(root,factory){if(typeof exports==="object"){root.sf2=exports;factory(exports)}else if(typeof define==="function"&&define.amd){define(["exports"],function(exports){root.sf2=exports;return(root.sf2,factory(exports))})}else{root.sf2={};factory(root.sf2)}}(this,function(exports){"use strict";var sf2=exports;sf2.Parser=function(input,options){options=options||{};this.input=input;this.parserOptions=options.parserOptions};sf2.Parser.prototype.parse=function(){var parser=new sf2.Riff.Parser(this.input,this.parserOptions),chunk;parser.parse();if(parser.chunkList.length!==1) throw new Error('wrong chunk length');chunk=parser.getChunk(0);if(chunk===null) throw new Error('chunk not found');this.parseRiffChunk(chunk);this.input=null};sf2.Parser.prototype.parseRiffChunk=function(chunk){var parser,data=this.input,ip=chunk.offset,signature;if(chunk.type!=='RIFF') throw new Error('invalid chunk type:'+chunk.type);signature=String.fromCharCode(data[ip++],data[ip++],data[ip++],data[ip++]);if(signature!=='sfbk') throw new Error('invalid signature:'+signature);parser=new sf2.Riff.Parser(data,{'index':ip,'length':chunk.size-4});parser.parse();if(parser.getNumberOfChunks()!==3) throw new Error('invalid sfbk structure');this.parseInfoList(parser.getChunk(0));this.parseSdtaList(parser.getChunk(1));this.parsePdtaList(parser.getChunk(2))};sf2.Parser.prototype.parseInfoList=function(chunk){var parser,data=this.input,ip=chunk.offset,signature;if(chunk.type!=='LIST') throw new Error('invalid chunk type:'+chunk.type);signature=String.fromCharCode(data[ip++],data[ip++],data[ip++],data[ip++]);if(signature!=='INFO') throw new Error('invalid signature:'+signature);parser=new sf2.Riff.Parser(data,{'index':ip,'length':chunk.size-4});parser.parse()};sf2.Parser.prototype.parseSdtaList=function(chunk){var parser,data=this.input,ip=chunk.offset,signature;if(chunk.type!=='LIST') throw new Error('invalid chunk type:'+chunk.type);signature=String.fromCharCode(data[ip++],data[ip++],data[ip++],data[ip++]);if(signature!=='sdta') throw new Error('invalid signature:'+signature);parser=new sf2.Riff.Parser(data,{'index':ip,'length':chunk.size-4});parser.parse();if(parser.chunkList.length!==1) throw new Error('TODO');this.samplingData=parser.getChunk(0)};sf2.Parser.prototype.parsePdtaList=function(chunk){var parser,data=this.input,ip=chunk.offset,signature;if(chunk.type!=='LIST') throw new Error('invalid chunk type:'+chunk.type);signature=String.fromCharCode(data[ip++],data[ip++],data[ip++],data[ip++]);if(signature!=='pdta') throw new Error('invalid signature:'+signature);parser=new sf2.Riff.Parser(data,{'index':ip,'length':chunk.size-4});parser.parse();if(parser.getNumberOfChunks()!==9) throw new Error('invalid pdta chunk');this.parsePhdr((parser.getChunk(0)));this.parsePbag((parser.getChunk(1)));this.parsePmod((parser.getChunk(2)));this.parsePgen((parser.getChunk(3)));this.parseInst((parser.getChunk(4)));this.parseIbag((parser.getChunk(5)));this.parseImod((parser.getChunk(6)));this.parseIgen((parser.getChunk(7)));this.parseShdr((parser.getChunk(8)))};sf2.Parser.prototype.parsePhdr=function(chunk){var data=this.input,ip=chunk.offset,presetHeader=this.presetHeader=[],size=chunk.offset+chunk.size;if(chunk.type!=='phdr') throw new Error('invalid chunk type:'+chunk.type);while(ip>>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.getInstruments=function(){var instrument=this.instrument,zone=this.instrumentZone,output=[],bagIndex,bagIndexEnd,zoneInfo,instrumentGenerator,instrumentModulator,i,il,j,jl;for(i=0,il=instrument.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){var o,os if(!Midi5.ma) return 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,note_run:note_run,op:op,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 ref=[],keep_types={note:true,rest:true} user.anno_stop=function(type,start,stop,x,y,w,h){if(!keep_types[type]) return ref[start]=stop;abc.out_svg('\n')} playconf.onnote=function(i,on){var b,x,y,elts=document.getElementsByClassName('_'+i+'_') if(elts&&elts[0]){elts[0].style.fillOpacity=on?0.4:0 if(on&&!window.no_scroll){b=elts[0].getBoundingClientRect() if(b.top<0) y=window.scrollY+b.top- window.innerHeight/2 else if(b.bottom>window.innerHeight) y=window.scrollY+b.bottom+ window.innerHeight/2 if(b.left<0) x=window.scrollX+b.left- window.innerWidth/2 else if(b.right>window.innerWidth) x=window.scrollX+b.right+ window.innerWidth/2 if(x!=undefined||y!=undefined) window.scrollTo(x||0,y||0)}}} var sty=document.createElement("style");sty.innerHTML=".abcr {fill: #d00000; fill-opacity: 0; z-index: 15}";document.head.appendChild(sty)}