//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]);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(){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 function ToAudio(){var C=abc2svg.C,a_e,p_time,abc_time,play_factor return{clear:function(){var a_pe=a_e;a_e=null return a_pe},add:function(start,voice_tb){var i,n,dt,d,v,rep_st_s,rep_en_s,rep_nx_s,rep_st_fac,instr=[],s=start function set_voices(){var v,p_v,s,mi a_e.push(new Float32Array([0,0,-1,121,0,1,0])) for(v=0;v=0){note=s.notes[i] if(note.b40==b40){note.ti2=true d+=s.dur/play_factor;return note.tie_ty?do_tie(s,b40,d):d}} return d} function gen_grace(s){var g,i,n,t,d,s2,next=s.next if(s.sappo){d=C.BLEN/16}else if((!next||next.type!=C.NOTE)&&s.prev&&s.prev.type==C.NOTE){d=s.prev.dur/2}else{next.ts_prev.ts_next=next.ts_next;next.ts_next.ts_prev=next.ts_prev;for(s2=next.ts_next;s2;s2=s2.ts_next){if(s2.time!=next.time){next.ts_next=s2 next.ts_prev=s2.ts_prev;next.ts_prev.ts_next=next;s2.ts_prev=next break}} d=next.dur/12 if(d&(d-1)==0) d=next.dur/2 else d=next.dur/3;next.time+=d;next.dur-=d} n=0 for(g=s.extra;g;g=g.next) if(g.type==C.NOTE) n++;d/=n*play_factor;t=p_time for(g=s.extra;g;g=g.next){if(g.type!=C.NOTE) continue gen_notes(g,t,d);t+=d}} function gen_notes(s,t,d){for(var i=0;i<=s.nhd;i++){var note=s.notes[i] if(note.ti2) continue a_e.push(new Float32Array([s.istart,t,instr[s.v],note.midi,note.tie_ty?do_tie(s,note.b40,d):d,1,s.v]))}} if(!a_e){a_e=[] abc_time=p_time=0;play_factor=C.BLEN/4*120/60}else if(s.time0){p_time+=dt/play_factor;abc_time=s.time} switch(s.type){case C.BAR:if(!s.seqst) break if(s==rep_en_s){s=rep_nx_s abc_time=s.time}else if(s.bar_type[0]==':'){rep_nx_s=s if(!rep_en_s) rep_en_s=s if(rep_st_s){s=rep_st_s play_factor=rep_st_fac}else{s=start;set_voices()} abc_time=s.time break} if(s.bar_type[s.bar_type.length-1]==':'){rep_st_s=s;rep_en_s=null rep_st_fac=play_factor}else if(s.text&&s.text[0]=='1'){rep_en_s=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_factor if(s.type==C.NOTE) gen_notes(s,p_time,d) else a_e.push(new Float32Array([s.istart,p_time,0,0,d,0,s.v])) break case C.BLOCK:switch(s.subtype){case"midictl":a_e.push(new Float32Array([s.istart,p_time,-1,s.ctrl,s.val,1,s.v])) break case"midiprog":instr[s.v]=s.instr break} break} s=s.ts_next}}}} if(typeof module=='object'&&typeof exports=='object') exports.ToAudio=ToAudio var abcsf2=[] function Audio5(i_conf){var conf=i_conf,onend=function(){},onnote=function(){},errmsg,ac,gain,params=[],rates=[],w_instr=0,evt_idx,iend,stime,timouts=[] function js_instr_load(instr,done,fail){abc2svg.loadjs(conf.sfu+'/'+instr+'.js',function(){done(b64dcod(abcsf2[instr]))},fail)} if(!conf.instr_load) conf.instr_load=js_instr_load var b64d=[] function init_b64d(){var b64l='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',l=b64l.length for(var 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,a_e){w_instr++;conf.instr_load(instr,function(sf2_bin){var parser=new sf2.Parser(sf2_bin);parser.parse();sf2_create(parser,instr);if(--w_instr==0) play_start(a_e)},function(){errmsg('could not find the instrument '+ ((instr/128)|0).toString()+'-'+ (instr%128).toString());if(--w_instr==0) play_start(a_e)})} function load_res(a_e){var i,e,instr,v,bk=[] for(i=evt_idx;i=iend){onend() return} if(conf.new_speed){stime=ac.currentTime- (ac.currentTime-stime)*conf.speed/conf.new_speed;conf.speed=conf.new_speed;conf.new_speed=0} timouts=[];t=e[1]/conf.speed;maxt=t+3 while(1){d=e[4]/conf.speed if(e[2]>=0){if(e[5]!=0) note_run(e,t+stime,d) var i=e[0];st=(t+stime-ac.currentTime)*1000;timouts.push(setTimeout(onnote,st,i,true));setTimeout(onnote,st+d*1000,i,false)} e=a_e[++evt_idx] if(!e||evt_idx>=iend){setTimeout(onend,(t+stime-ac.currentTime+d)*1000) return} t=e[1]/conf.speed if(t>maxt) break} timouts.push(setTimeout(play_next,(t+stime-ac.currentTime)*1000-300,a_e))} function play_start(a_e){if(iend==0){onend() return} if(w_instr!=0) return gain.connect(ac.destination);stime=ac.currentTime+.2 -a_e[evt_idx][1]*conf.speed;play_next(a_e)} init_b64d();if(!conf.sfu) conf.sfu="Scc1t2" return{get_outputs:function(){return(window.AudioContext||window.webkitAudioContext)?['sf2']:null},play:function(istart,i_iend,a_e){if(!a_e||istart>=a_e.length){onend() return} if(conf.onend) onend=conf.onend if(conf.onnote) onnote=conf.onnote 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} iend=i_iend;evt_idx=istart;load_res(a_e);play_start(a_e)},stop:function(){iend=0 timouts.forEach(function(id){clearTimeout(id)}) play_next() 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(sf2){"use strict";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.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;i=iend||!e){onend() return} if(conf.new_speed){stime=window-performance.now()- (window.performance.now()-stime)*conf.speed/conf.new_speed;conf.speed=conf.new_speed;conf.new_speed=0} timouts=[];t=e[1]/conf.speed*1000;maxt=t+3000 while(1){d=e[4]/conf.speed*1000 if(e[2]>=0){if(e[5]!=0) note_run(e,t+stime,d) st=t+stime-window.performance.now();timouts.push(setTimeout(onnote,st,e[0],true));setTimeout(onnote,st+d,e[0],false)}else{c=e[6]&0x0f op.send(new Uint8Array([0xb0+c,e[3],e[4]]),t+stime) if(bk[c]==undefined) bk[c]=0 switch(e[3]){case 0:bk[c]=(bk[c]&0x7f)|(e[4]<<7) break case 32:bk[c]=(bk[c]&0x3f80)|e[4] break case 121:bk=[] break}} e=a_e[++evt_idx] if(!e||evt_idx>=iend){setTimeout(onend,t+stime-window.performance.now()+d) return} t=e[1]/conf.speed*1000 if(t>maxt) break} timouts.push(setTimeout(play_next,(t+stime-window.performance.now()) -300,a_e))} function send_outputs(access){var o,os,out=[];Midi5.ma=access;if(access&&access.outputs.size>0){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(istart,i_iend,a_e){if(!a_e||istart>=a_e.length){onend() return} if(conf.onend) onend=conf.onend if(conf.onnote) onnote=conf.onnote;iend=i_iend;evt_idx=istart;if(0){op.send(new Uint8Array([0xf0,0x7f,0x7f,0x08,0x02,0x00,0x01,0x69,0x69,0x00,0,0xf7]),t)} v_i=[];stime=window.performance.now()+200 -a_e[evt_idx][1]*conf.speed*1000;play_next(a_e)},stop:function(){iend=0 timouts.forEach(function(id){clearTimeout(id)}) play_next() 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,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)}}}} (function(){var sty=document.createElement("style") sty.innerHTML=".abcr {fill: #d00000; fill-opacity: 0; z-index: 15}" document.head.appendChild(sty)})()