UNPKG

crossbrowdy

Version:

A Multimedia JavaScript framework to create real cross-platform and hybrid game engines, games, emulators, multimedia libraries and apps.

1,647 lines (1,632 loc) 55.3 kB
// Web Audio API Simulator // Copyright (c) 2013 g200kg // http://www.g200kg.com/ // Released under the MIT-License // http://opensource.org/licenses/MIT // // Great thanks : // FFT algo for AnalyserNode and Convolver is based on Takuya OOURA's explanation. // http://www.kurims.kyoto-u.ac.jp/~ooura/fftman/index.html (function(window, document){ window.AudioContext = window.AudioContext||window.webkitAudioContext||window.mozAudioContext; if(typeof(waapisimLogEnable)==="undefined") var waapisimLogEnable=0; // Support Float32Array&Uint8Array if unavailable (for IE9) if(typeof(Float32Array)==="undefined") { Float32Array=function(n) { if(n instanceof Array) return n; var a=new Array(n); a.subarray=function(x,y) {return this.slice(x,y);}; a.set=function(x,off) {for(var i=0;i<x.length;++i) a[off+i]=x[i];}; return a; }; } if(typeof(Uint8Array)==="undefined") { Uint8Array=function(n) { if(n instanceof Array) return n; var a=new Array(n); a.subarray=function(x,y) {return this.slice(x,y);}; a.set=function(x,off) {for(var i=0;i<x.length;++i) a[off+i]=x[i];}; return a; }; } if(typeof(waapisimLogEnable)!=="undefined"&&waapisimLogEnable) waapisimDebug=function(a) {console.log(a);}; else waapisimDebug=function(){}; if(typeof(window.AudioContext)!=="undefined") { if(typeof(window.AudioContext.prototype.createGain)==="undefined") { window.AudioContext.prototype.createScriptProcessor=window.AudioContext.prototype.createJavaScriptNode; window.AudioContext.prototype.createGain=(function(){ var o=window.AudioContext.prototype.createGainNode.call(this); o._gain=o.gain; o.gain=o._gain; o.gain.setTargetAtTime=o._gain.setTargetValueAtTime; return o; }); window.AudioContext.prototype.createDelay=(function(){ var o=window.AudioContext.prototype.createDelayNode.call(this); o._delayTime=o.delayTime; o.delayTime=o._delayTime; o.delayTime.setTargetAtTime=o._delayTime.setTargetValueAtTime; return o; }); window.AudioContext.prototype._createOscillator=window.AudioContext.prototype.createOscillator; window.AudioContext.prototype.createOscillator=(function() { var o=window.AudioContext.prototype._createOscillator.call(this); o._frequency=o.frequency; o.frequency=o._frequency; o.frequency.setTargetAtTime=o._frequency.setTargetValueAtTime; o._detune=o.detune; o.detune=o._detune; o.detune.setTargetAtTime=o._detune.setTargetValueAtTime; o.start=o.noteOn; o.stop=o.noteOff; return o; }); window.AudioContext.prototype._createBufferSource=window.AudioContext.prototype.createBufferSource; window.AudioContext.prototype.createBufferSource=(function() { var o=window.AudioContext.prototype._createBufferSource.call(this); o._playbackRate=o.playbackRate; o.playbackRate=o._playbackRate; o.playbackRate.setTargetAtTime=o._playbackRate.setTargetValueAtTime; o.start=function(w,off,dur) { if(off===undefined) o.noteOn(w); else o.noteGrainOn(w,off,dur); }; o.stop=o.noteOff; return o; }); window.AudioContext.prototype._createBiquadFilter=window.AudioContext.prototype.createBiquadFilter; window.AudioContext.prototype.createBiquadFilter=(function() { var o=window.AudioContext.prototype._createBiquadFilter.call(this); o._frequency=o.frequency; o.frequency=o._frequency; o.frequency.setTargetAtTime=o._frequency.setTargetValueAtTime; o._Q=o.Q; o.Q=o._Q; o.Q.setTargetAtTime=o._Q.setTargetValueAtTime; o._gain=o.gain; o.gain=o._gain; o.gain.setTargetAtTime=o._gain.setTargetValueAtTime; return o; }); window.AudioContext.prototype._createDynamicsCompressor=window.AudioContext.prototype.createDynamicsCompressor; window.AudioContext.prototype.createDynamicsCompressor=(function() { var o=window.AudioContext.prototype._createDynamicsCompressor.call(this); o._threshold=o.threshold; o.threshold=o._threshold; o.threshold.setTargetAtTime=o._threshold.setTargetValueAtTime; o._knee=o.knee; o.knee=o._knee; o.knee.setTargetAtTime=o._knee.setTargetValueAtTime; o._ratio=o.ratio; o.ratio=o._ratio; o.ratio.setTargetAtTime=o._ratio.setTargetValueAtTime; o._attack=o.attack; o.attack=o._attack; o.attack.setTargetAtTime=o._attack.setTargetValueAtTime; return o; }); } } if((typeof(waapisimForceSim)!=="undefined"&&waapisimForceSim) ||(typeof(window.AudioContext)!=="undefined"&&typeof(window.AudioContext.prototype.createOscillator)==="undefined"&&(typeof(waapisimForceSimWhenLackOsc)==="undefined"||(typeof(waapisimForceSimWhenLackOsc)!=="undefined"&&waapisimForceSimWhenLackOsc))) ||(typeof(window.AudioContext)==="undefined")) { waapisimSampleRate=44100; waapisimAudioIf=0; waapisimBufSize=1024; waapisimFlashBufSize=1024*3; if(typeof(Audio)!=="undefined") { waapisimAudio=new Audio(); if(typeof(waapisimAudio.mozSetup)!=="undefined") waapisimAudioIf=1; } if(waapisimAudioIf===0) { waapisimOutBufSize=waapisimFlashBufSize; waapisimOutBuf=new Array(waapisimOutBufSize*2); } else { waapisimOutBufSize=waapisimBufSize; waapisimOutBuf=new Float32Array(waapisimOutBufSize*2); waapisimAudio.mozSetup(2,waapisimSampleRate); } for(var l=waapisimOutBuf.length,i=0;i<l;++i) waapisimOutBuf[i]=0; waapisimWrittenpos=0; waapisimNodeId=0; waapisimContexts=[]; waapisimAudioBuffer=function(ch,len,rate) { var i,j; if(typeof(ch)=="number") { len|=0; this.sampleRate=rate; this.length=len; this.duration=len/this.sampleRate; this.numberOfChannels=ch; this.buf=[]; for(i=0;i<2;++i) { this.buf[i]=new Float32Array(len); for(j=0;j<len;++j) this.buf[i][j]=0; } } else { var inbuf; this.sampleRate=44100; this.buf=[]; this.buf[0]=new Float32Array(0); this.buf[1]=new Float32Array(0); this.Get4BStr=function(b,n) { return String.fromCharCode(b[n],b[n+1],b[n+2],b[n+3]); }; this.GetDw=function(b,n) { return b[n]+(b[n+1]<<8)+(b[n+2]<<16)+(b[n+3]<<24); }; this.GetWd=function(b,n) { return b[n]+(b[n+1]<<8); }; inbuf=new Uint8Array(ch); var mixtomono=len; var riff=this.Get4BStr(inbuf,0); this.length=0; if(riff=="RIFF") { var filesize=this.GetDw(inbuf,4)+8; var wave=this.Get4BStr(inbuf,8); var fmtid=0; var wavch=1; var wavbits=16; if(wave=="WAVE") { var idx=12; while(idx<filesize) { var chunk=this.Get4BStr(inbuf,idx); var chunksz=this.GetDw(inbuf,idx+4); if(chunk=="fmt ") { fmtid=this.GetWd(inbuf,idx+8); wavch=this.GetWd(inbuf,idx+10); this.sampleRate=this.GetDw(inbuf,idx+12); wavbits=this.GetWd(inbuf,idx+22); } if(chunk=="data") { this.length=(chunksz/wavch/(wavbits/8))|0; this.buf[0]=new Float32Array(this.length); this.buf[1]=new Float32Array(this.length); this.numberOfChannels=wavch; this.duration=this.length/this.sampleRate; var v0,v1; for(i=0,j=0;i<this.length;++i) { if(wavbits==24) { if(wavch==2) { v0=inbuf[idx+j+9]+(inbuf[idx+j+10]<<8); v1=inbuf[idx+j+12]+(inbuf[idx+j+13]<<8); if(v0>=32768) v0=v0-65536; if(v1>=32768) v1=v1-65536; if(mixtomono===true) v0=v1=(v0+v1)*0.5; this.buf[0][i]=v0/32768; this.buf[1][i]=v1/32768; j+=6; } else { v=inbuf[idx+j+9]+(inbuf[idx+j+10]<<8); if(v>=32768) v=v-65536; this.buf[0][i]=this.buf[1][i]=v/32768; j+=3; } } else if(wavbits==16) { if(wavch==2) { v0=inbuf[idx+j+8]+(inbuf[idx+j+9]<<8); v1=inbuf[idx+j+10]+(inbuf[idx+j+11]<<8); if(v0>=32768) v0=v0-65536; if(v1>=32768) v1=v1-65536; if(mixtomono===true) v0=v1=(v0+v1)*0.5; this.buf[0][i]=v0/32768; this.buf[1][i]=v1/32768; j+=4; } else { v=inbuf[idx+j+8]+(inbuf[idx+j+9]<<8); if(v>=32768) v=v-65536; this.buf[0][i]=this.buf[1][i]=v/32768; j+=2; } } else { if(wavch==2) { v0=inbuf[idx+j+8]/128-1; v1=inbuf[idx+j+9]/128-1; if(mixtomono===true) v0=v1=(v0+v1)*0.5; this.buf[0][i]=v0; this.buf[1][i]=v1; j+=2; } else { this.buf[0][i]=this.buf[1][i]=inbuf[idx+j+8]/128-1; j++; } } } } idx+=(chunksz+8); } } } } this.getChannelData=function(i) { return this.buf[i]; }; }; waapisimDummybuf=new waapisimAudioBuffer(2,waapisimBufSize,waapisimSampleRate); waapisimSetupOutBuf=function(offset) { var numctx=waapisimContexts.length; var l,i,j,k,n,node; for(l=(offset+waapisimBufSize)*2,i=offset*2;i<l;i+=2) waapisimOutBuf[i]=waapisimOutBuf[i+1]=0; for(n=0;n<numctx;++n) { var ctx=waapisimContexts[n]; for(;;) { for(l=ctx._Nodes.length,i=0;i<l;++i) { node=ctx._Nodes[i]; if(node.playbackState==3) { node.disconnect(); ctx._UnregisterNode(node); break; } } if(i==l) break; } for(l=ctx._Nodes.length,i=0;i<l;++i) ctx._Nodes[i]._Process(); node=ctx.destination; if(node._nodein[0].from.length>0) { var buf=node._nodein[0].inbuf.buf; for(i=0;i<waapisimBufSize;++i) { waapisimOutBuf[(i+offset)*2]+=buf[0][i]; waapisimOutBuf[(i+offset)*2+1]+=buf[1][i]; } } node._nodein[0].NodeClear(); } }; waapisimUpdateCurrentTime=function(t) { for(var i=waapisimContexts.length;i--;) waapisimContexts[i].currentTime=t; }; waapisimInterval=function() { var curpos=waapisimAudio.mozCurrentSampleOffset(); var buffered=waapisimWrittenpos-curpos; var vl,vr; waapisimUpdateCurrentTime(curpos/(waapisimSampleRate*2)); if(buffered<16384) { waapisimSetupOutBuf(0); waapisimWrittenpos+=waapisimAudio.mozWriteAudio(waapisimOutBuf); } }; waapisimGetSwfPath=function() { var scr=document.getElementsByTagName("SCRIPT"); if(scr&&scr.length>0) { for(var i in scr) { if(scr[i].src){ var s=scr[i].src; if (s.match(/waapisim\.js$/)) { return s.substring(0,s.length-2)+"swf"; }else if (s.match(/waapisim\.min\.js$/)){ return s.substring(0,s.length-6)+"swf"; } } } } return ""; }; waapisimAddFlashObj=function() { var div = document.createElement('div'); var params = { movie: waapisimSwfPath, allowScriptAccess : 'always', quality: 'high', bgcolor: '#ffffff' }; div.id = 'WAAPISIMFLASHOBJ'; div.style.position = 'fixed'; div.style.right = 0; div.style.bottom = 0; div.style.background = '#ffffff'; document.body.appendChild(div); if (navigator.plugins && navigator.mimeTypes && navigator.mimeTypes.length) { var o = document.createElement('object'); o.id = 'waapisim_swf'; o.width = 150; o.height = 20; o.setAttribute('data', waapisimSwfPath); o.setAttribute('type', 'application/x-shockwave-flash'); for ( var i in params ) { var p = document.createElement('param'); p.setAttribute('name', i); p.setAttribute('value', params[i]); o.appendChild(p); } div.appendChild(o); } else { // IE div.innerHTML = '<object id="waapisim_swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="150" height="20">'; for ( var i in params ) { div.innerHTML += '<param name="' + i + '" value="' + params[i] + ' />'; } div.innerHTML += '</object>'; } if(typeof(document.getElementById("waapisim_swf").SetReturnValue)==="undefined") document.getElementById("waapisim_swf").SetReturnValue=function(v){document.getElementById("waapisim_swf").impl.SetReturnValue(v);}; }; waapisimFlashOffset=function(pos) { waapisimUpdateCurrentTime(pos/1000); }; waapisimFlashGetData=function() { var s=""; var l; for(l=waapisimOutBufSize/waapisimBufSize,i=0;i<l;++i) { waapisimSetupOutBuf(waapisimBufSize*i); } waapisimWrittenpos+=waapisimOutBufSize*2; for(l=waapisimOutBufSize*2,i=0;i<l;++i) { var v=(waapisimOutBuf[i]*16384+32768)|0; if(isNaN(v)) v=32768; v = Math.min(49152, Math.max(16384, v)); s+=String.fromCharCode(v); } return s; }; switch(waapisimAudioIf) { case 0: waapisimSwfPath=waapisimGetSwfPath(); window.addEventListener("load",waapisimAddFlashObj,false); break; case 1: setInterval(waapisimInterval,10); break; } window.AudioContext=function() { waapisimContexts.push(this); this._Nodes=[]; this.destination=new waapisimAudioDestinationNode(this); this.sampleRate=44100; this.currentTime=0; this.activeSourceCount=0; this.listener=new waapisimAudioListener(); this.createBuffer=function(ch,len,rate) { return new waapisimAudioBuffer(ch,len,rate); }; this.createBufferSource=function() { return new waapisimAudioBufferSource(this); }; this.createScriptProcessor=this.createJavaScriptNode=function(bufsize,inch,outch) { return new waapisimScriptProcessor(this,bufsize,inch,outch); }; this.createBiquadFilter=function() { return new waapisimBiquadFilter(this); }; this.createGain=this.createGainNode=function() { return new waapisimGain(this); }; this.createDelay=this.createDelayNode=function() { return new waapisimDelay(this); }; this.createOscillator=function() { return new waapisimOscillator(this); }; this.createAnalyser=function() { return new waapisimAnalyser(this); }; this.createConvolver=function() { return new waapisimConvolver(this); }; this.createDynamicsCompressor=function() { return new waapisimDynamicsCompressor(this); }; this.createPanner=function() { return new waapisimPanner(this); }; this.createChannelSplitter=function(ch) { return new waapisimChannelSplitter(this,ch); }; this.createChannelMerger=function(ch) { return new waapisimChannelMerger(this,ch); }; this.createWaveShaper=function() { return new waapisimWaveShaper(this); }; this.decodeAudioData=function(audioData,successCallback,errorCallback) { var buf=new waapisimAudioBuffer(audioData,false); if(buf.length > 0 && typeof successCallback === 'function'){ successCallback(buf); }else if (typeof errorCallback === 'function'){ errorCallback(); } }; this.createPeriodicWave=this.createWaveTable=function(real,imag) { return new waapisimPeriodicWave(real,imag); }; this._SortNode=function() { var i,j,k,n; for(i=0;i<this._Nodes.length;++i) { n=this._Nodes[i]; if(n._order>0) { for(j=0;j<n._nodein.length;++j) { for(k=0;k<n._nodein[j].from.length;++k) { var o=n._nodein[j].from[k].node._order; if(n._order<o+1) n._order=o+1; } } } } this._Nodes.sort(function(a,b){return b._order-a._order;}); } this._RegisterNode=function(node) { for(var i=this._Nodes.length;i--;) { if(this._Nodes[i]===node) { return false; } } this._Nodes.push(node); this._SortNode(); return true; }; this._UnregisterNode=function(node) { for(var i=this._Nodes.length;i--;) { if(this._Nodes[i]==node) { this._Nodes.splice(i,1); } } }; }; waapisimAudioListener=function() { this.px=0; this.py=0; this.pz=0; this.ox=0; this.oy=0; this.oz=-1; this.ux=0; this.uy=1; this.uz=0; this.dopplerFactor=1; this.speedOfSound=343.3; this.setPosition=function(x,y,z) {this.px=x;this.py=y;this.pz=z;}; this.setOrientation=function(x,y,z,ux,uy,uz) {this.ox=x;this.oy=y;this.oz=z;this.ux=ux;this.uy=uy;this.uz=uz;}; this.setVelocity=function(x,y,z) {}; }; waapisimPeriodicWave=function(real,imag) { var n=4096; var ar=new Array(n); var ai=new Array(n); this.buf=new Float32Array(n); var m, mh, i, j, k; var wr, wi, xr, xi; for(i=0;i<n;++i) ar[i]=ai[i]=0; i=j=0; do { ar[i]=real[j]; ai[i]=-imag[j]; for(var k=n>>1;k>(i^=k);k>>=1){} ; } while(++j<real.length); var theta=2*Math.PI; for(mh=1;(m=mh<<1)<=n;mh=m) { theta *= 0.5; for(i=0;i<mh;i++) { wr=Math.cos(theta*i); wi=Math.sin(theta*i); for(j=i;j<n;j+=m) { k=j+mh; xr=wr*ar[k]-wi*ai[k]; xi=wr*ai[k]+wi*ar[k]; ar[k]=ar[j]-xr; ai[k]=ai[j]-xi; ar[j]+=xr; ai[j]+=xi; } } } var max=0; for(i=0;i<n;++i) { var v=Math.abs(ar[i]); if(v>max) max=v; } if(max==0) { for(i=0;i<n;++i) this.buf[i]=0; } else { for(i=0;i<n;++i) this.buf[i]=ar[i]/max; } }; waapisimAudioNode=function(size,numin,numout) { this.numberOfInputs=numin; this.numberOfOutputs=numout; this._nodeId=waapisimNodeId; this._order=1; ++waapisimNodeId; this._targettype=1; this.context=null; this._nodein=[]; this._nodeout=[]; var i; for(i=0;i<numin;++i) this._nodein[i]=new waapisimAudioNodeIn(this,size); for(i=0;i<numout;++i) this._nodeout[i]=new waapisimAudioNodeOut(this,size); this.connect=function(next,output,input) { if(typeof(output)==="undefined") output=0; if(typeof(input)==="undefined") input=0; if(this._nodeout[output]) { if(next._targettype!==0) this._nodeout[output].connect(next._nodein[input]); else this._nodeout[output].connect(next); } }; this.disconnect=function(output) { if(typeof(this._nodeout[output])==="undefined") output=0; this._nodeout[output].disconnect(); }; }; waapisimAudioNodeIn=function(node,size) { this.node=node; this.from=[]; this.inbuf=new waapisimAudioBuffer(2,size,waapisimSampleRate); this.NodeClear=function() { for(var i=0;i<waapisimBufSize;++i) this.inbuf.buf[0][i]=this.inbuf.buf[1][i]=0; }; }; waapisimAudioNodeOut=function(node,size) { this.node=node; this.to=[]; this.connect=function(next) { waapisimDebug("connect "+this.node._nodetype+this.node._nodeId+"=>"+next.node._nodetype+next.node._nodeId); if(next===undefined) return; if(next.from.indexOf(this)!=-1) return; next.from.push(this); if(this.to.indexOf(next)==-1) this.to.push(next); if(next.node._targettype!==0) { if(this.node.context._RegisterNode(next.node)) { for(var i=0;i<next.node._nodeout.length;++i) { for(var ii=0;ii<next.node._nodeout[i].to.length;++ii) { next.node._nodeout[i].connect(next.node._nodeout[i].to[ii]); } } } } }; this.disconnectTemp=function() { var i,j,k,l,n,ii,jj,ll,node,node2; waapisimDebug("disconnect "+this.node._nodetype+this.node._nodeId); var nodes=this.node.context._Nodes; for(l=nodes.length,i=0;i<l;++i) { for(ll=nodes[i]._nodein.length,ii=0;ii<ll;++ii) { j=nodes[i]._nodein[ii].from.indexOf(this); if(j>=0) { waapisimDebug(" :"+this.node._nodeId+"=>"+nodes[i]._nodeId); nodes[i]._nodein[ii].from.splice(j,1); } } } for(i=0;i<nodes.length;++i) { node=nodes[i]; if(node._targettype==1) { n=0; for(ii=0;ii<node._nodein.length;++ii) n+=node._nodein[ii].from.length; if(n===0) { this.node.context._UnregisterNode(node); for(ii=0;ii<node._nodeout.length;++ii) node._nodeout[ii].disconnectTemp(); break; } } } }; this.disconnect=function() { this.disconnectTemp(); this.to.length=0; }; this.NodeEmit=function(idx,v1,v2) { for(var l=this.to.length,i=0;i<l;++i) { var buf=this.to[i].inbuf.buf; buf[0][idx]+=v1; buf[1][idx]+=v2; } }; this.NodeEmitBuf=function() { for(var l=this.to.length,i=0;i<l;++i) { var b0=this.to[i].inbuf.buf[0]; var b1=this.to[i].inbuf.buf[1]; for(var j=0;j<waapisimBufSize;++j) { b0[j]+=this.outbuf.buf[0][j]; b1[j]+=this.outbuf.buf[1][j]; } } }; this.outbuf=new waapisimAudioBuffer(2,size,waapisimSampleRate); }; waapisimAudioProcessingEvent=function() { }; waapisimAudioDestinationNode=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,0); this._nodetype="Destination"; waapisimDebug("create "+this._nodetype+this._nodeId); this._targettype=2; this.context=ctx; this.playbackState=0; this.maxNumberOfChannels=2; this.numberOfChannels=2; this._Process=function() {}; ctx._Nodes.push(this); }; waapisimAudioBufferSource=AudioBufferSourceNode=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,0,1); this._nodetype="BufSrc"; waapisimDebug("create "+this._nodetype+this._nodeId); this._targettype=3; this._order=0; this.context=ctx; this.playbackState=0; this.buffer=null; this.playbackRate=new waapisimAudioParam(ctx,this,0,10,1); this.gain=new waapisimAudioParam(ctx,this,0,1,1); // Undocumented this.loop=false; this.loopStart=0; this.loopEnd=0; this._bufferindex=0; this._whenstart=0; this._whenstop=Number.MAX_VALUE; this._endindex=0; this._actualLoopStart=0; this._actualLoopEnd=0; this.start=this.noteOn=this.noteGrainOn=function(w,off,dur) { if(this.buffer===null) return; this.playbackState=1; this._whenstart=w; if(off>0) this._bufferindex=off*waapisimSampleRate; this._endindex=this.buffer.length; if(dur>0) this._endindex=Math.min(this.buffer.length,(dur+off)*waapisimSampleRate); if(this.loop) { if((this.loopStart||this.loopEnd)&&this.loopStart>=0&&this.loopEnd>0&&this.loopStart<this.loopEnd) { this._actualLoopStart=this.loopStart; this._actualLoopEnd=Math.min(this.loopEnd,this.buffer.length); } else { this._actualLoopStart=0; this._actualLoopEnd=this.buffer.length; } } this.context._RegisterNode(this); }; this.stop=this.noteOff=function(w) { this._whenstop=w; }; this._Process=function() { this.playbackRate._Process(); if(this.buffer!==null && this._bufferindex>=this._endindex) { if(this.playbackState==2) --this.context.activeSourceCount; this.playbackState=3; } if(this.playbackState==1 && this.context.currentTime>=this._whenstart) { this.playbackState=2; ++this.context.activeSourceCount; } if(this.playbackState==2 && this.context.currentTime>=this._whenstop) { this.playbackState=3; --this.context.activeSourceCount; } if(this.playbackState!=2) return; var b0=this.buffer.getChannelData(0); var b1=this.buffer.getChannelData(1); var rate=this.buffer.sampleRate/44100; if(this._nodeout[0].to.length>0) { for(var i=0;i<waapisimBufSize;++i) { if(this._bufferindex<this._endindex) { var g=this.gain.Get(i); var idx=this._bufferindex|0; this._nodeout[0].outbuf.buf[0][i]=b0[idx]*g; this._nodeout[0].outbuf.buf[1][i]=b1[idx]*g; } this._bufferindex+=rate*this.playbackRate.Get(i); if(this.loop) { if(this._bufferindex>=this._actualLoopEnd) this._bufferindex=this._actualLoopStart; } } this._nodeout[0].NodeEmitBuf(); this.playbackRate.Clear(true); } }; }; waapisimAudioBufferSource.UNSCHEDULED_STATE=waapisimAudioBufferSource.prototype.UNSCHEDULED_STATE=0; waapisimAudioBufferSource.SCHEDULED_STATE=waapisimAudioBufferSource.prototype.SCHEDULED_STATE=1; waapisimAudioBufferSource.PLAYING_STATE=waapisimAudioBufferSource.prototype.PLAYING_STATE=2; waapisimAudioBufferSource.FINISHED_STATE=waapisimAudioBufferSource.prototype.FINISHED_STATE=3; waapisimScriptProcessor=function(ctx,bufsize,inch,outch) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="ScrProc"; waapisimDebug("create "+this._nodetype+this._nodeId); this._targettype=2; this.context=ctx; this.playbackState=0; if(typeof(bufsize)!=="number") throw(new TypeError("ScriptProcessor:bufferSize")); if(typeof(inch)==="undefined") inch=2; if(typeof(outch)==="undefined") outch=2; this.bufferSize=bufsize; this._scrinbuf=new waapisimAudioBuffer(inch,bufsize,waapisimSampleRate); this._scroutbuf=new waapisimAudioBuffer(outch,bufsize,waapisimSampleRate); this._index=bufsize; this.onaudioprocess=null; this._Process=function() { var inb=this._nodein[0].inbuf; if(inb===null) inb=waapisimDummybuf; for(var i=0;i<waapisimBufSize;++i) { if(this._index>=this.bufferSize) { if(this.onaudioprocess) { var ev=new waapisimAudioProcessingEvent(); ev.node=this; ev.inputBuffer=this._scrinbuf; ev.outputBuffer=this._scroutbuf; this.onaudioprocess(ev); } this._index=0; } this._scrinbuf.buf[0][this._index]=inb.buf[0][i]; if(this._scrinbuf.numberOfChannels>=2) this._scrinbuf.buf[1][this._index]=inb.buf[1][i]; if(this._scroutbuf.numberOfChannels>=2) this._nodeout[0].NodeEmit(i,this._scroutbuf.buf[0][this._index],this._scroutbuf.buf[1][this._index]); else this._nodeout[0].NodeEmit(i,this._scroutbuf.buf[0][this._index],this._scroutbuf.buf[0][this._index]); this._index++; } this._nodein[0].NodeClear(); }; ctx._RegisterNode(this); }; waapisimBiquadFilter=BiquadFilterNode=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="Filter"; waapisimDebug("create "+this._nodetype+this._nodeId); this.context=ctx; this.playbackState=0; this.type=0; this.frequency=new waapisimAudioParam(ctx,this,10,24000,350,0.5); this.detune=new waapisimAudioParam(ctx,this,-4800,4800,0,0.5); this.Q=new waapisimAudioParam(ctx,this,0.0001,1000,1,0.5); this.gain=new waapisimAudioParam(ctx,this,-40,40,0,0.5); this._a1=this._a2=0; this._b0=this._b1=this._b2=0; this._x1l=this._x1r=this._x2l=this._x2r=0; this._y1l=this._y1r=this._y2l=this._y2r=0; this._nodein[0].NodeClear(); this._Setup=function(fil) { var f=fil.frequency.Get(0)*Math.pow(2,fil.detune.Get(0)/1200); var q=Math.max(0.001,fil.Q.Get(0)); var alpha,ra0,g; var w0=2*Math.PI*f/fil.context.sampleRate; var cos=Math.cos(w0); switch(fil.type) { case "lowpass": case 0: q=Math.pow(10,q/20); alpha=Math.sin(w0)/(2*q); ra0=1/(1+alpha); fil._a1=-2*cos*ra0; fil._a2=(1-alpha)*ra0; fil._b0=fil._b2=(1-cos)/2*ra0; fil._b1=(1-cos)*ra0; break; case "highpass": case 1: q=Math.pow(10,q/20); alpha=Math.sin(w0)/(2*q); ra0=1/(1+alpha); fil._a1=-2*cos*ra0; fil._a2=(1-alpha)*ra0; fil._b0=fil._b2=(1+cos)/2*ra0; fil._b1=-(1+cos)*ra0; break; case "bandpass": case 2: alpha=Math.sin(w0)/(2*q); ra0=1/(1+alpha); fil._a1=-2*cos*ra0; fil._a2=(1-alpha)*ra0; fil._b0=alpha; fil._b1=0; fil._b2=-alpha; break; case "lowshelf": case 3: alpha=Math.sin(w0)/2*Math.sqrt(2); g=Math.pow(10,fil.gain.Get(0)/40); ra0=1/((g+1)+(g-1)*cos+2*Math.sqrt(g)*alpha); fil._a1=-2*((g-1)+(g+1)*cos)*ra0; fil._a2=((g+1)+(g-1)*cos-2*Math.sqrt(g)*alpha)*ra0; fil._b0=g*((g+1)-(g-1)*cos+2*Math.sqrt(g)*alpha)*ra0; fil._b1=2*g*((g-1)-(g+1)*cos)*ra0; fil._b2=g*((g+1)-(g-1)*cos-2*Math.sqrt(g)*alpha)*ra0; break; case "highshelf": case 4: alpha=Math.sin(w0)/2*Math.sqrt(2); g=Math.pow(10,fil.gain.Get(0)/40); ra0=1/((g+1)-(g-1)*cos+2*Math.sqrt(g)*alpha); fil._a1=2*((g-1)-(g+1)*cos)*ra0; fil._a2=((g+1)-(g-1)*cos-2*Math.sqrt(g)*alpha)*ra0; fil._b0=g*((g+1)+(g-1)*cos+2*Math.sqrt(g)*alpha)*ra0; fil._b1=-2*g*((g-1)+(g+1)*cos)*ra0; fil._b2=g*((g+1)+(g-1)*cos-2*Math.sqrt(g)*alpha)*ra0; break; case "peaking": case 5: alpha=Math.sin(w0)/(2*q); g=Math.pow(10,fil.gain.Get(0)/40); ra0=1/(1+alpha/g); fil._a1=-2*cos*ra0; fil._a2=(1-alpha/g)*ra0; fil._b0=(1+alpha*g)*ra0; fil._b1=-2*cos*ra0; fil._b2=(1-alpha*g)*ra0; break; case "notch": case 6: alpha=Math.sin(w0)/(2*q); ra0=1/(1+alpha); fil._a1=-2*cos*ra0; fil._a2=(1-alpha)*ra0; fil._b0=fil._b2=ra0; fil._b1=-2*cos*ra0; break; case "allpass": case 7: alpha=Math.sin(w0)/(2*q); ra0=1/(1+alpha); fil._a1=-2*cos*ra0; fil._a2=(1-alpha)*ra0; fil._b0=(1-alpha)*ra0; fil._b1=-2*cos*ra0; fil._b2=(1+alpha)*ra0; break; } }; this._Process=function() { var xl,xr,yl,yr; this.frequency._Process(); this.detune._Process(); this.Q._Process(); this.gain._Process(); this._Setup(this); var inbuf=this._nodein[0].inbuf.buf; var outbuf=this._nodeout[0].outbuf.buf; for(var i=0;i<waapisimBufSize;++i) { xl=inbuf[0][i]; xr=inbuf[1][i]; yl=this._b0*xl+this._b1*this._x1l+this._b2*this._x2l-this._a1*this._y1l-this._a2*this._y2l; yr=this._b0*xr+this._b1*this._x1r+this._b2*this._x2r-this._a1*this._y1r-this._a2*this._y2r; this._x2l=this._x1l; this._x2r=this._x1r; this._x1l=xl; this._x1r=xr; this._y2l=this._y1l; this._y2r=this._y1r; this._y1l=yl; this._y1r=yr; outbuf[0][i]=yl; outbuf[1][i]=yr; } this._nodeout[0].NodeEmitBuf(); this._nodein[0].NodeClear(); this.frequency.Clear(false); this.detune.Clear(false); this.Q.Clear(false); this.gain.Clear(false); }; this.getFrequencyResponse=function(f,m,p) { for(var l=f.length,i=0;i<l;++i) { var w=2*Math.PI*f[i]/this.context.sampleRate; var cw=Math.cos(w); var cw2=Math.cos(w*2); var sw=Math.sin(w); var sw2=Math.sin(w*2); var ca=1+this._a1*cw+this._a2*cw2; var sa=this._a1*sw+this._a2*sw2; var cb=this._b0+this._b1*cw+this._b2*cw2; var sb=this._b1*sw+this._b2*sw2; m[i]=Math.sqrt((cb*cb+sb*sb)/(ca*ca+sa*sa)); p[i]=Math.atan2(sa,ca)-Math.atan2(sb,cb); } } }; waapisimBiquadFilter.LOWPASS=waapisimBiquadFilter.prototype.LOWPASS=0; waapisimBiquadFilter.HIGHPASS=waapisimBiquadFilter.prototype.HIGHPASS=1; waapisimBiquadFilter.BANDPASS=waapisimBiquadFilter.prototype.BANDPASS=2; waapisimBiquadFilter.LOWSHELF=waapisimBiquadFilter.prototype.LOWSHELF=3; waapisimBiquadFilter.HIGHSHELF=waapisimBiquadFilter.prototype.HIGHSHELF=4; waapisimBiquadFilter.PEAKING=waapisimBiquadFilter.prototype.PEAKING=5; waapisimBiquadFilter.NOTCH=waapisimBiquadFilter.prototype.NOTCH=6; waapisimBiquadFilter.ALLPASS=waapisimBiquadFilter.prototype.ALLPASS=7; waapisimGain=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="Gain"; waapisimDebug("create "+this._nodetype+this._nodeId); this.context=ctx; this.playbackState=0; this.gain=new waapisimAudioParam(ctx,this,0,1,1); this._nodein[0].NodeClear(); this._curgain=1; this._Process=function() { var i; this.gain._Process(); var inbuf=this._nodein[0].inbuf.buf; switch(this._nodeout[0].to.length) { case 0: this._curgain=this.gain.Get(0); break; case 1: var b=this._nodeout[0].to[0].inbuf.buf; for(i=0;i<waapisimBufSize;++i) { var g=this.gain.Get(i); this._curgain+=(g-this._curgain)*0.01; b[0][i]+=inbuf[0][i]*this._curgain; b[1][i]+=inbuf[1][i]*this._curgain; } break; default: for(i=0;i<waapisimBufSize;++i) { var g=this.gain.Get(i); this._curgain+=(g-this._curgain)*0.01; this._nodeout[0].NodeEmit(i,inbuf[0][i]*this._curgain,inbuf[1][i]*this._curgain); } break; } this._nodein[0].NodeClear(); this.gain.Clear(true); }; }; waapisimDelay=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="Delay"; waapisimDebug("create "+this._nodetype+this._nodeId); this.context=ctx; this.playbackState=0; this.delayTime=new waapisimAudioParam(ctx,this,0,1,0); this._bufl=new Float32Array(waapisimSampleRate); this._bufr=new Float32Array(waapisimSampleRate); for(var i=0;i<waapisimSampleRate;++i) this._bufl[i]=this._bufr[i]=0; this._index=0; this._offscur=0; this._Process=function() { this.delayTime._Process(); var inbuf=this._nodein[0].inbuf.buf; var outbuf=this._nodeout[0].outbuf.buf; var offs=Math.floor(this.delayTime.Get(0)*this.context.sampleRate); if(offs<0) offs=0; if(offs>=this.context.sampleRate) offs=this.context.sampleRate-1; var deltaoff=(offs-this._offscur)/waapisimBufSize; for(var i=0;i<waapisimBufSize;++i) { var idxr=this._index-(this._offscur|0); if(idxr<0) idxr+=waapisimSampleRate; this._bufl[this._index]=inbuf[0][i]; this._bufr[this._index]=inbuf[1][i]; outbuf[0][i]=this._bufl[idxr]; outbuf[1][i]=this._bufr[idxr]; if(++this._index>=waapisimSampleRate) this._index=0; this._offscur+=deltaoff; } this._nodeout[0].NodeEmitBuf(); this._nodein[0].NodeClear(); this.delayTime.Clear(false); }; }; waapisimOscillator=OscillatorNode=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,0,1); this._nodetype="Osc"; waapisimDebug("create "+this._nodetype+this._nodeId); this._targettype=3; this._order=0; this.context=ctx; this.type=0; this._wavtable=null; this.frequency=new waapisimAudioParam(ctx,this,1,20000,440,0.9995); this.detune=new waapisimAudioParam(ctx,this,-4800,4800,0,0.9995); this.playbackState=0; this._phase=0.5; this._whenstart=0; this._whenstop=Number.MAX_VALUE; this._init=0; this.start=this.noteOn=function(w) { this._whenstart=w; this.playbackState=1; this.context._RegisterNode(this); }; this.stop=this.noteOff=function(w) { this._whenstop=w; }; this.setPeriodicWave=this.setWaveTable=function(tab) { this.type=4; this._wavtable=tab; }; this._Process=function() { var i; if(this._init==0) { this.frequency.Init(); this.detune.Init(); this._init=1; } this.frequency._Process(); this.detune._Process(); if(this.playbackState==1 && this.context.currentTime>=this._whenstart) this.playbackState=2; if(this.playbackState==2 && this.context.currentTime>=this._whenstop) this.playbackState=3; if(this.playbackState!=2) { for(i=0;i<waapisimBufSize;++i) this._nodeout[0].outbuf.buf[0][i]=this._nodeout[0].outbuf.buf[1][i]=0; return; } var t,x1,x2,y,z; var obuf=this._nodeout[0].outbuf.buf; var ph=this._phase; var r=1/this.context.sampleRate; var freq=this.frequency; var detu=this.detune; switch(this.type) { case "sine": case 0: x1=0.5; x2=1.5; y=2*Math.PI; z=1/6.78; break; case "square": case 1: x1=0.5; x2=1.5; y=100000; z=0; break; case "sawtooth": case 2: x1=0; x2=2; y=2; z=0; break; case "triangle": case 3: x1=0.5; x2=1.5; y=4; z=0; break; case "custom": case 4: for(i=0;i<waapisimBufSize;++i) { var f=freq.Get(i)*Math.pow(2,detu.Get(i)/1200); ph+=f*r; ph=ph-Math.floor(ph); var out=0; if(this._wavtable) out=this._wavtable.buf[(4096*ph)|0]; obuf[0][i]=obuf[1][i]=out; } this._phase=ph; this._nodeout[0].NodeEmitBuf(); this.frequency.Clear(true); this.detune.Clear(true); return; } for(i=0;i<waapisimBufSize;++i) { var f=freq.Get(i)*Math.pow(2,detu.Get(i)/1200); ph+=f*r; ph=ph-Math.floor(ph); t = ( Math.min( Math.max(ph ,x1 - ph), x2 - ph) - 0.5) * y; var out=t-t*t*t*z; if(out>1) out=1; if(out<-1) out=-1; obuf[0][i]=obuf[1][i]=out; } this._phase=ph; this._nodeout[0].NodeEmitBuf(); this.frequency.Clear(true); this.detune.Clear(true); }; }; waapisimOscillator.SINE=waapisimOscillator.prototype.SINE=0; waapisimOscillator.SQUARE=waapisimOscillator.prototype.SQUARE=1; waapisimOscillator.SAWTOOTH=waapisimOscillator.prototype.SAWTOOTH=2; waapisimOscillator.TRIANGLE=waapisimOscillator.prototype.TRIANGLE=3; waapisimOscillator.CUSTOM=waapisimOscillator.prototype.CUSTOM=4; waapisimOscillator.UNSCHEDULED_STATE=waapisimOscillator.prototype.UNSCHEDULED_STATE=0; waapisimOscillator.SCHEDULED_STATE=waapisimOscillator.prototype.SCHEDULED_STATE=1; waapisimOscillator.PLAYING_STATE=waapisimOscillator.prototype.PLAYING_STATE=2; waapisimOscillator.FINISHED_STATE=waapisimOscillator.prototype.FINISHED_STATE=3; waapisimAnalyser=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="Analyser"; waapisimDebug("create "+this._nodetype+this._nodeId); this.context=ctx; this.playbackState=0; this.fftSize=2048; this.frequencyBinCount=1024; this.minDecibels=-100; this.maxDecibels=-30; this.smoothingTimeConstant=0; this._fftInData=new Array(2048); this._fftOutData=new Array(2048); this._timeData=new Array(2048); this._fftIndex=0; this._fftCurrentSize=0; this._fftrev=new Array(256); this._fft=function(n,data,mag) { var nh=n>>1; var t=-2*Math.PI; var m,mh,mq,i,j,jr,ji,kr,ki,xr,xi; for(mh=1;(m=mh<<1)<=n;mh=m) { mq=mh>>1; t*=0.5; for(jr=0;jr<n;jr+=m) { kr=jr+mh; xr=data[kr]; data[kr]=data[jr]-xr; data[jr]+=xr; } for(i=1;i<mq;++i) { var wr=Math.cos(t*i); var wi=Math.sin(t*i); for(j=0;j<n;j+=m) { jr=j+i; ji=j+mh-i; kr=j+mh+i; ki=j+m-i; xr=wr*data[kr]+wi*data[ki]; xi=wr*data[ki]-wi*data[kr]; data[kr]=-data[ji]+xi; data[ki]=data[ji]+xi; data[ji]=data[jr]-xr; data[jr]=data[jr]+xr; } } } data[0]=Math.min(1e-100,Math.abs(data[0]/n)); var stc=Math.min(1,Math.max(0,this.smoothingTimeConstant)); mag[0]=mag[0]*stc+(1-stc)*data[0]; for(i=0;i<nh;++i) { var v=Math.sqrt(data[i]*data[i]+data[n-i]*data[n-i])/n; if(v<1e-100) v=1e-100; mag[i]=mag[i]*stc+(1-stc)*v; } }; this.getByteFrequencyData=function(array) { var range=this.maxDecibels-this.minDecibels; for(var l=Math.min(array.length,this.frequencyBinCount),i=0;i<l;++i) { var v=20*Math.LOG10E*Math.log(this._fftOutData[i]); array[i]=((Math.min(this.maxDecibels,Math.max(this.minDecibels,v))-this.minDecibels)*255/range)|0; } }; this.getFloatFrequencyData=function(array) { for(var l=Math.min(array.length,this.frequencyBinCount),i=0;i<l;++i) array[i]=20*Math.LOG10E*Math.log(this._fftOutData[i]); }; this.getByteTimeDomainData=function(array) { for(var l=Math.min(this.frequencyBinCount,array.length),i=0;i<l;++i) { var v=Math.min(1,Math.max(-1,this._timeData[i])); array[i]=v*127+128; } }; this._Process=function() { var i,j,k; var inbuf=this._nodein[0].inbuf.buf; if(this.fftSize!=this._fftCurrentSize) { var n=this.fftSize; for(i=0;i<n;++i) this._fftInData[i]=this._fftOutData[i]=0; this._fftCurrentSize=n; this.frequencyBinCount=n*0.5; this._fftIndex=0; this._fftrev[0]=0; this._fftrev[n-1]=n-1; for(i=0,j=1;j<n-1;++j) { for(k=n>>1;k>(i^=k);k>>=1){} ; this._fftrev[j]=i; } } for(i=0;i<waapisimBufSize;++i) { var xl=inbuf[0][i]; var xr=inbuf[1][i]; this._nodeout[0].NodeEmit(i,xl,xr); var v=this._timeData[this._fftIndex]=(xl+xr)*0.5; var t=2*Math.PI*this._fftIndex/this._fftCurrentSize; // this._fftInData[this._fftrev[this._fftIndex]]=v*(0.42-0.5*Math.cos(t)+0.08*Math.cos(t*2)); this._fftInData[this._fftrev[this._fftIndex]]=v*(0.5-0.5*Math.cos(t)); if(++this._fftIndex>=this._fftCurrentSize) { this._fftIndex=0; this._fft(this._fftCurrentSize,this._fftInData,this._fftOutData); } } this._nodein[0].NodeClear(); }; }; waapisimConvolver=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="Convolver"; waapisimDebug("create "+this._nodetype+this._nodeId); this.context=ctx; this.playbackState=0; this.buffer=null; this.normalize=true; this._scale=1; this._analyzed=null; this._dlybufsize=waapisimSampleRate*5; this._dlybuf=new waapisimAudioBuffer(2,this._dlybufsize,44100); this._dlyidx=0; this._tapsize=20; this._tap=[]; this._kernel=null; this._sum=[]; this._sum[0]=[]; this._sum[1]=[]; this._bitrev=[]; this._bitrev[0]=0; this._bitrev[waapisimBufSize-1]=waapisimBufSize-1; var i,j,k; for(i=0,j=1;j<waapisimBufSize-1;++j) { for(k=waapisimBufSize>>1;k>(i^=k);k>>=1){} ; this._bitrev[j]=i; } for(i=0;i<2;++i) for(j=0;j<2;++j) this._sum[i][j]=new Float32Array(waapisimSampleRate); this._Normalize=function(buffer) { var GainCalibration=0.00125; var GainCalibrationSampleRate=44100; var MinPower=0.000125; var numberOfChannels=2; var length=buffer.length; var power=0; for(var i=0;i<numberOfChannels;++i) { var sourceP=0; var channelPower=0; var n=length; while(n--) { var sample=buffer.buf[i][sourceP++]; channelPower+=sample*sample; } power+=channelPower; } power=Math.sqrt(power/(numberOfChannels*length)); if(isFinite(power)===false||isNaN(power)||power<MinPower) power=MinPower; var scale=1/power; scale*=GainCalibration; return scale; }; this._Fft=function(n,a) { var m,mh,mq,i,j,k,jr,ji,kr,ki; var theta, wr, wi, xr, xi; i=0; for(j=1;j<n-1;j++) { for(k=n>>1;k>(i^=k);k>>=1){} ; if(j<i) { xr=a[j]; a[j]=a[i]; a[i]=xr; } } theta=-2*Math.PI; for(mh=1;(m=mh<<1)<=n;mh=m) { mq=mh>>1; theta*=0.5; for(jr=0;jr<n;jr+=m) { kr=jr+mh; xr=a[kr]; a[kr]=a[jr]-xr; a[jr]+=xr; } for(i=1;i<mq;i++) { wr=Math.cos(theta*i); wi=Math.sin(theta*i); for(j=0;j<n;j+=m) { jr=j+i; ji=j+mh-i; kr=j+mh+i; ki=j+m-i; xr=wr*a[kr]+wi*a[ki]; xi=wr*a[ki]-wi*a[kr]; a[kr]=-a[ji]+xi; a[ki]=a[ji]+xi; a[ji]=a[jr]-xr; a[jr]=a[jr]+xr; } } } }; this._Fft2=function(n,ar,ai) { var m, mh, i, j, k; var wr, wi, xr, xi; var theta=2*Math.PI; i=0; for(j=1;j<n-1;j++) { for(k=n>>1;k>(i^=k);k>>=1){} ; if(j<i) { xr=ar[j]; xi=ai[j]; ar[j]=ar[i]; ai[j]=ai[i]; ar[i]=xr; ai[i]=xi; } } for(mh=1;(m=mh<<1)<=n;mh=m) { theta *= 0.5; for(i=0;i<mh;i++) { wr=Math.cos(theta*i); wi=Math.sin(theta*i); for(j=i;j<n;j+=m) { k=j+mh; xr=wr*ar[k]-wi*ai[k]; xi=wr*ai[k]+wi*ar[k]; ar[k]=ar[j]-xr; ai[k]=ai[j]-xi; ar[j]+=xr; ai[j]+=xi; } } } for(i=0;i<n;++i) ar[i]=ar[i]/n; }; this._Process=function() { var inbuf=this._nodein[0].inbuf.buf; var nh=(waapisimBufSize*0.5)|0; var i,j,k,l,px,v0,v1; if(this.buffer!==null) { if(this.buffer!=this._analyzed) { var kbuf=[]; for(i=0;i<4;++i) kbuf[i]=new waapisimAudioBuffer(2,waapisimBufSize,44100); this._scale=1; if(this.normalize) this._scale=this._Normalize(this.buffer); var len=this.buffer.length; for(i=len-1;i;--i) { if(Math.abs(this.buffer.buf[0][i])>1e-3) break; if(Math.abs(this.buffer.buf[1][i])>1e-3) break; } len=i+1; for(i=0,px=0;i<this._tapsize;++i) { var x=(i*len/this._tapsize)|0; var sz=x-px; v0=0; v1=0; if(sz>0) { while(px<x) { v0+=this.buffer.buf[0][px]*this.buffer.buf[0][px]; v1+=this.buffer.buf[1][px]*this.buffer.buf[1][px]; ++px; } v0=Math.sqrt(v0)*this._scale*0.5; v1=Math.sqrt(v1)*this._scale*0.5; } this._tap[i]=[x,v0,v1]; } this._kernel=new waapisimAudioBuffer(2,waapisimBufSize,44100); var p=0,maxp=0; for(l=Math.min(this.buffer.length,waapisimBufSize*4),i=0,j=0,k=0;i<l;++i) { v0=this.buffer.buf[0][i]; v1=this.buffer.buf[1][i]; kbuf[k].buf[0][j]=v0; kbuf[k].buf[1][j]=v1; p+=(v0*v0+v1*v1); if(++j>=waapisimBufSize) { if(p>maxp) { this._kernel=kbuf[k]; maxp=p; } j=0; p=0; ++k; } } if(p>maxp||this._kernel===null) this._kernel=kbuf[k]; this._Fft(waapisimBufSize,this._kernel.buf[0]); this._Fft(waapisimBufSize,this._kernel.buf[1]); this._analyzed=this.buffer; } this._Fft(waapisimBufSize,inbuf[0]); this._Fft(waapisimBufSize,inbuf[1]); this._sum[0][0][0]=this._sum[1][0][0]=this._sum[0][1][0]=this._sum[1][1][0]=0; for(i=1,j=waapisimBufSize-1;i<nh;++i,--j) { var real0=inbuf[0][i]*this._kernel.buf[0][i]-inbuf[0][j]*this._kernel.buf[0][j]; var imag0=inbuf[0][i]*this._kernel.buf[0][j]+inbuf[0][j]*this._kernel.buf[0][i]; this._sum[0][0][i]=real0; this._sum[0][0][j]=real0; this._sum[0][1][i]=-imag0; this._sum[0][1][j]=imag0; var real1=inbuf[1][i]*this._kernel.buf[1][i]-inbuf[1][j]*this._kernel.buf[1][j]; var imag1=inbuf[1][i]*this._kernel.buf[1][j]+inbuf[1][j]*this._kernel.buf[1][i]; this._sum[1][0][i]=real1; this._sum[1][0][j]=real1; this._sum[1][1][i]=-imag1; this._sum[1][1][j]=imag1; } this._Fft2(waapisimBufSize,this._sum[0][0],this._sum[0][1]); this._Fft2(waapisimBufSize,this._sum[1][0],this._sum[1][1]); for(i=0;i<waapisimBufSize;++i) { var v=(nh-Math.abs(i-nh))/nh; this._dlybuf.buf[0][this._dlyidx]=this._sum[0][0][i]*v; this._dlybuf.buf[1][this._dlyidx]=this._sum[1][0][i]*v; v0=0; v1=0; for(l=this._tap.length,j=0;j<l;++j) { var idx=this._dlyidx-this._tap[j][0]; while(idx<0) idx+=this._dlybufsize; v0+=this._dlybuf.buf[0][idx]*this._tap[j][1]; v1+=this._dlybuf.buf[1][idx]*this._tap[j][2]; } this._nodeout[0].NodeEmit(i,v0,v1); if(++this._dlyidx>=this._dlybufsize) this._dlyidx=0; } } this._nodein[0].NodeClear(); }; }; waapisimDynamicsCompressor=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="DynComp"; waapisimDebug("create "+this._nodetype+this._nodeId); this.context=ctx; this.playbackState=0; this.threshold=new waapisimAudioParam(ctx,this,-100,0,-24); this.knee=new waapisimAudioParam(ctx,this,0,40,30); this.ratio=new waapisimAudioParam(ctx,this,1,20,12); this.reduction=new waapisimAudioParam(ctx,this,-20,0,0);//ReadOnly this.attack=new waapisimAudioParam(ctx,this,0,1,0.003); this.release=new waapisimAudioParam(ctx,this,0,1,0.25); this._maxl=0; this._maxr=0; this._gain=1; this._Process=function() { this.threshold._Process(); this.knee._Process(); this.ratio._Process(); this.attack._Process(); this.release._Process(); var inbuf=this._nodein[0].inbuf.buf; var relratio=this.release.Get(0)*waapisimSampleRate; relratio=Math.pow(1/3.16,1/relratio); var atkratio=this.attack.Get(0)*waapisimSampleRate; atkratio=Math.pow(1/3.16,1/atkratio); var reduc=this.reduction.value; var thresh=Math.pow(10,this.threshold.Get(0)/20); var knee=Math.pow(10,this.knee.Get(0)/20*0.5); var makeup=1/Math.sqrt(thresh)/Math.pow(10,this.knee.Get(0)/80); var maxratio=0.99105; var ratio=this.ratio.Get(0); if(ratio<=1) ratio=1; for(var i=0;i<waapisimBufSize;++i) { this._maxl=maxratio*this._maxl+(1-maxratio)*inbuf[0][i]*inbuf[0][i]; this._maxr=maxratio*this._maxr+(1-maxratio)*inbuf[1][i]*inbuf[1][i]; var maxc=Math.sqrt(Math.max(this._maxl,this._maxr))*1.414; if(maxc>thresh) { var v=Math.pow(thresh*Math.min(knee,maxc/thresh)/maxc,1-1/ratio); this._gain=v+(this._gain-v)*atkratio; } else this._gain=1+(this._gain-1)*relratio; var g=this._gain*makeup; this._nodeout[0].NodeEmit(i,inbuf[0][i]*g,inbuf[1][i]*g); } this.reduction.value=this.reduction.computedValue=reduc; this._nodein[0].NodeClear(); this.threshold.Clear(false); this.knee.Clear(false); this.ratio.Clear(false); this.reduction.Clear(false); this.attack.Clear(false); this.release.Clear(false); }; }; waapisimPanner=AudioPannerNode=function(ctx) { waapisimAudioNode.call(this,waapisimBufSize,1,1); this._nodetype="Panner"; waapisimDebug("create "+this._nodetype+this._nodeId); this.context=ctx; this.playbackState=0; this.panningModel=0; this.distanceModel=1; this.refDistance=1; this.maxDistance=10000; this.rolloffFactor=1; this.coneInnerAngle=360; this.coneOuterAngle=360; this.coneOuterGain=0; this.px=0; this.py=0; this.pz=0; this.setPosition=function(x,y,z) {this.px=x;this.py=y;this.pz=z;}; this.setOrientation=function(x,y,z) {}; this.setVelocity=function(x,y,z) {}; this._Process=function() { var inbuf=this._nodein[0].inbuf.buf; var listener=this.context.listener; var dx=this.px-listener.px; var dy=this.py-listener.py; var dz=this.pz-listener.pz; var d=Math.max(1,Math.sqrt(dx*dx+dy*dy+dz*dz)); var dgain; switch(this.distanceModel) { case "linear": case 0: dgain=1-this.rolloffFactor*(d-this.refDistance)/(this.maxDistance-this.refDistance); break; case "inverse": case 1: dgain=this.refDistance/(this.refDistance+this.rolloffFactor*(d-this.refDistance)); break; case "exponential": case 2: dgain=Math.pow(d/this.refDistance,-this.rolloffFactor); break; } var rgain,lgain,tr; if(Math.abs(dz)<0.001) { lgain=rgain=1; } else { tr=Math.atan(dx/dz); if(dz<=0) { rgain=-tr+Math.PI*0.5; lgain=tr+Math.PI*0.5; } else { switch(this.panningModel) { case 0: case "equalpower": rgain=tr+Math.PI*0.5; lgain=-tr+Math.PI*0.5; break; default: if(dx>=0) { rgain=tr+Math.PI*0.5; lgain=-(-tr+Math.PI*0.5); } else { rgain=-(tr+Math.PI*0.5); lgain=-tr+Math.PI*0.5; } } } } var rl=Math.sqrt(rgain*rgain+lgain*lgain); rgain=rgain/rl; lgain=lgain/rl; var a=Math.sqrt(rgain*rgain+lgain*lgain); rgain=rgain/a*2*dgain; lgain=lgain/a*2*dgain; for(var i=0;i<waapisimBufSize;++i) this._nodeout[0].NodeEmit(i,inbuf[0][i]*lgain,inbuf[1][i]*rgain); this._nodein[0].NodeClear(); }; }; waapisimPanner.EQUALPOWER=waapisimPanner.prototype.EQUALPOWER=0; waapisimPanner.HRTF=waapisimPanner.prototype.HRTF=1; waapisimPanner.SOUNDFIELD=waapisimPanner.prototype.SOUNDFIELD=2; waapisimPanner.LINEAR_DISTANCE=waapisimPanner.prototype.LINEAR_DISTANCE=0; waapisimPanner.INVERSE_DISTANCE=waapisimPanner.prototype.INVERSE_DISTANCE=1; waapisimPanner.EXPONENTIAL_DISTANCE=waapisimPanner.prototype.EXPONENTIAL_DISTANCE=2; waapisimChannelSplitter=function(ctx,ch) { this._nodetype="ChSplit"; waapisimDebug("