diff --git a/content/docs/webmodular/index.html b/content/docs/webmodular/index.html new file mode 100644 index 0000000..36206a5 --- /dev/null +++ b/content/docs/webmodular/index.html @@ -0,0 +1,78 @@ + + + + + + + + + +

WebModular

+ + +

+
+ +
+
+MML:
+ +
+ + +
+
+
+URL to this song:
+
+ +
+
+ +
+
+ + + + + + + + + +
12
C#3
3
D#3
45
F#3
6
G#3
7
A#3
89
C#4
0
D#4
Q
C3
W
D3
E
E3
R
F3
T
G3
Y
A3
U
B3
I
C4
O
D4
P
E4
AS
C#2
D
D#2
FG
F#2
H
G#2
J
A#2
KL
C#3
;
D#3
Z
C2
X
D2
C
E2
V
F2
B
G2
N
A2
M
B2
,
C3
.
D3
/
+
+
+
+
+
+
+
+
+
+
+ + + + diff --git a/content/docs/webmodular/keypress.png b/content/docs/webmodular/keypress.png new file mode 100644 index 0000000..4d5eeb6 Binary files /dev/null and b/content/docs/webmodular/keypress.png differ diff --git a/content/docs/webmodular/knob.png b/content/docs/webmodular/knob.png new file mode 100644 index 0000000..f74af19 Binary files /dev/null and b/content/docs/webmodular/knob.png differ diff --git a/content/docs/webmodular/knob2.png b/content/docs/webmodular/knob2.png new file mode 100644 index 0000000..b36da99 Binary files /dev/null and b/content/docs/webmodular/knob2.png differ diff --git a/content/docs/webmodular/knob3.png b/content/docs/webmodular/knob3.png new file mode 100644 index 0000000..8eb6470 Binary files /dev/null and b/content/docs/webmodular/knob3.png differ diff --git a/content/docs/webmodular/panel.png b/content/docs/webmodular/panel.png new file mode 100644 index 0000000..46792fb Binary files /dev/null and b/content/docs/webmodular/panel.png differ diff --git a/content/docs/webmodular/play.png b/content/docs/webmodular/play.png new file mode 100644 index 0000000..55d19c4 Binary files /dev/null and b/content/docs/webmodular/play.png differ diff --git a/content/docs/webmodular/sliderpos.png b/content/docs/webmodular/sliderpos.png new file mode 100644 index 0000000..30f7224 Binary files /dev/null and b/content/docs/webmodular/sliderpos.png differ diff --git a/content/docs/webmodular/stop.png b/content/docs/webmodular/stop.png new file mode 100644 index 0000000..270e6b5 Binary files /dev/null and b/content/docs/webmodular/stop.png differ diff --git a/content/docs/webmodular/sw2.png b/content/docs/webmodular/sw2.png new file mode 100644 index 0000000..7286dfa Binary files /dev/null and b/content/docs/webmodular/sw2.png differ diff --git a/content/docs/webmodular/sw3.png b/content/docs/webmodular/sw3.png new file mode 100644 index 0000000..1fb9c06 Binary files /dev/null and b/content/docs/webmodular/sw3.png differ diff --git a/content/docs/webmodular/sw5.png b/content/docs/webmodular/sw5.png new file mode 100644 index 0000000..7c56da2 Binary files /dev/null and b/content/docs/webmodular/sw5.png differ diff --git a/content/docs/webmodular/twitter-bird-light-bgs.png b/content/docs/webmodular/twitter-bird-light-bgs.png new file mode 100644 index 0000000..188597e Binary files /dev/null and b/content/docs/webmodular/twitter-bird-light-bgs.png differ diff --git a/static/waapisim.js b/static/waapisim.js new file mode 100644 index 0000000..acb3899 --- /dev/null +++ b/static/waapisim.js @@ -0,0 +1,1786 @@ +// 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 + +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=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;i0) { + var buf=node._nodein[0].inbuf.buf; + for(i=0;i0) { + for(var i in scr) { + if(scr[i].src && scr[i].src.match(/waapisim\.js$/)) { + var s=scr[i].src; + return s.substring(0,s.length-2)+"swf"; + } + } + } + return ""; + }; + waapisimAddFlashObj=function() { + var div=document.createElement("DIV"); + div.setAttribute("id","WAAPISIMFLASHOBJ"); + div.setAttribute("style","background:#ff00ff;position:static;"); + var body=document.getElementsByTagName("BODY"); + body[0].appendChild(div); + document.getElementById("WAAPISIMFLASHOBJ").innerHTML="
"; + 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;i0) + successCallback(buf); + else + errorCallback(); + }; + this.createPeriodicWave=this.createWaveTable=function(real,imag) { + return new waapisimPeriodicWave(real,imag); + }; + this._SortNode=function() { + var i,j,k,n; + for(i=0;i0) { + for(j=0;j>1;k>(i^=k);k>>=1) + ; + } while(++jmax) + max=v; + } + if(max==0) { + for(i=0;i"+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=0) { + waapisimDebug(" :"+this.node._nodeId+"=>"+nodes[i]._nodeId); + nodes[i]._nodein[ii].from.splice(j,1); + } + } + } + for(i=0;i0) + 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._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=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=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=webkitBiquadFilterNode=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=this.context.sampleRate) + offs=this.context.sampleRate-1; + var deltaoff=(offs-this._offscur)/waapisimBufSize; + for(var i=0;i=waapisimSampleRate) + this._index=0; + this._offscur+=deltaoff; + } + this._nodeout[0].NodeEmitBuf(); + this._nodein[0].NodeClear(); + this.delayTime.Clear(false); + }; + }; + waapisimOscillator=webkitOscillatorNode=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;i1) 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>1;k>(i^=k);k>>=1) + ; + this._fftrev[j]=i; + } + } + for(i=0;i=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>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>1;k>(i^=k);k>>=1) + ; + if(j>1; + theta*=0.5; + for(jr=0;jr>1;k>(i^=k);k>>=1) + ; + if(j1e-3) + break; + if(Math.abs(this.buffer.buf[1][i])>1e-3) + break; + } + len=i+1; + for(i=0,px=0;i0) { + while(px=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=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;ithresh) { + 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=webkitAudioPannerNode=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=0) { + for(i=0;it) + break; + } + this.automation.splice(i,0,ev); + }; + this.setValueAtTime=function(v,t) { + this.AddEvent([t,0,v]); + }; + this.linearRampToValueAtTime=function(v,t) { + this.AddEvent([t,1,v]); + }; + this.exponentialRampToValueAtTime=function(v,t) { + this.AddEvent([t,2,v]); + }; + this.setTargetAtTime=this.setTargetValueAtTime=function(v,t,c) { + this.AddEvent([t,3,v,c]); + }; + this.setValueCurveAtTime=function(values,t,d) { + this.AddEvent([t,4,values,d]); + }; + this.cancelScheduledValues=function(t) { + for(var l=this.automation.length,i=0;i=t) { + this.automation.length=i; + return; + } + } + }; + this._Process=function() { + this.value+=this.deltaAdd; + this.value=(this.value-this.deltaTarget)*this.deltaMul+this.deltaTarget; + if(this.currentEvent!==null) { + if(this.currentEvent[1]==4) { + var i=(this.currentEvent[2].length-1)*(this.context.currentTime-this.currentEvent[0])/this.currentEvent[3]; + this.value=this.currentEvent[2][Math.min(this.currentEvent[2].length-1,i)|0]; + } + } + if(this.automation.length>0) { + if(this.context.currentTime>=this.automation[0][0]) { + this.deltaAdd=0; + this.deltaMul=1; + this.deltaTarget=0; + this.currentEvent=this.automation.shift(); + switch(this.currentEvent[1]) { + case 0: + case 1: + case 2: + this.value=this.currentEvent[2]; + break; + case 3: + this.deltaMul=Math.pow(0.367879,1/(waapisimSampleRate/waapisimBufSize*this.currentEvent[3])); + this.deltaTarget=this.currentEvent[2]; + break; + } + if(this.automation.length>0) { + var n=waapisimSampleRate/waapisimBufSize*(this.automation[0][0]-this.context.currentTime); + switch(this.automation[0][1]) { + case 1: + this.deltaAdd=(this.automation[0][2]-this.value)/n; + break; + case 2: + this.deltaMul=Math.pow(this.automation[0][2]/this.value,1/n); + break; + } + } + } + } + }; + this.Init=function() { + this.computedValue=parseFloat(this.value); + } + this.Get=function(n) { + if(this.from.length>0) + this.computedValue=parseFloat(this.value)+(this.inbuf.buf[0][n]+this.inbuf.buf[1][n])*0.5; + else + this.computedValue=this.computedValue*this.timeconst+(1-this.timeconst)*parseFloat(this.value); + return this.computedValue; + }; + this.Clear=function(arate) { + if(arate) { + for(var i=0;i 0) + app.keyboard.key.NoteOn(parseInt(msg[2], 16), velo); + else + app.keyboard.key.NoteOff(parseInt(msg[2], 16)); + break; + case 0xb0: + if (parseInt(msg[2], 16) == 0x78) { + app.keyboard.key.AllOff(); + } + break; + } + break; + } +} +function LinkSend(win, s) { + win.postMessage(s, "*"); +} +function LinkReady() { + LinkSend(window.parent, "link,ready"); +} +function GetPatchString() { + return CmdSave(); +} +function SetPatchString(s) { + CmdLoad(s); +} +function getXY(e) { + var rc = e.target.getBoundingClientRect(); + mouseX = Math.floor(e.clientX - rc.left); + mouseY = Math.floor(e.clientY - rc.top); + if (mouseX < 0) mouseX = 0; + if (mouseY < 0) mouseY = 0; +} +function getXYTouch(e){ + var touch =e.changedTouches[0]; + var rc = touch.target.getBoundingClientRect() + mouseX = Math.floor(touch.clientX - rc.left); + mouseY = Math.floor(touch.clientY - rc.top); + if (mouseX < 0) mouseX = 0; + if (mouseY < 0) mouseY = 0; +} +function Rect(x, y, w, h) { + this.ty = 10000; + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.Draw = function() { + ctx.lineWidth = 1; + ctx.strokeStyle = "#000000"; + ctx.strokeRect(x, y, w, h); + } + this.MouseDown = function(x,y) { + } + this.MouseMove = function(x,y) { + } + this.MouseUp = function(x,y) { + } +} +function Jack(x, y, ty,col) { + this.ty = ty; + this.x = x; + this.y = y; + this.w = 16; + this.h = 16; + this.connect = null; + this.fanout = 0; + if (ty == 0) + this.pnum = jinum++; + else + this.pnum = jonum++; + this.col = cablecol[colnum]; + if (ty == 0) { + if (++colnum >= 18) + colnum = 0; + } + if (ty != 0) { + try { + this.buf = new Float32Array(128); + } catch (e) { + this.buf = new Array(128); + } + for (var i = 0; i < 128; ++i) + this.buf[i] = 0; + } + this.Draw = function() { + if (typeof (gadget) != "undefined") + return; + if (this.connect != null) { + this.Cable(this, this.connect.x + 8, this.connect.y + 12, this.col, 0); + } + } + this.FillBuf = function(v) { + var out = this.buf; + for (var i = 0; i < 128; ++i) + out[i] = v; + } + this.Connect = function(jck) { + var jIn = this; + var jOut = jck; + if (this.ty != 0) { + jIn = jck; + jOut = this; + } + if (jIn.connect != null) { + if (jIn.connect.fanout > 0) + --(jIn.connect.fanout); + } + jIn.connect = jOut; + if (jOut != null) + ++jOut.fanout; + } + this.Cable = function(j, x, y, col, f) { + var mx = (j.x + 8 + x) / 2; + var my = Math.max(j.y+12, y)+40; + ctx.beginPath(); + ctx.moveTo(j.x + 8, j.y+12); + ctx.bezierCurveTo(mx, my, mx, my, x, y); + + var r = (col >> 16) & 0xff; + var g = (col >> 8) & 0xff; + var b = col & 0xff; + for (var i = 3; i; --i) { + ctx.strokeStyle = "#" + ("000000" + ((r << 16) + (g << 8) + b).toString(16)).slice(-6); + if (r < 200) + r += Math.floor((200 - r) / 3); + if (g < 200) + g += Math.floor((200 - g) / 3); + if (b < 200) + b += Math.floor((200 - b) / 3); + ctx.lineWidth = i; + ctx.lineCap = "round"; + ctx.stroke(); + } + switch (f) { + case 1: + ctx.lineWidth = 2; + ctx.strokeStyle = "#00ff00"; + ctx.beginPath(); + ctx.arc(x, y, 8, 0, Math.PI * 2, true); + ctx.stroke(); + break; + case 2: + ctx.lineWidth = 2; + ctx.strokeStyle = "#ff0000"; + ctx.beginPath(); + ctx.moveTo(x - 8, y - 8); + ctx.lineTo(x + 8, y + 8); + ctx.moveTo(x + 8, y - 8); + ctx.lineTo(x - 8, y + 8); + ctx.stroke(); + break; + } + } + this.MouseDown = function(x,y) { + } + this.MouseMove = function(x,y) { + } + this.MouseUp = function(x,y) { + } +} +function Knob(x, y, w, h, img, step, def) { + this.ty = 100; + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.x0 = 0; + this.y0 = 0; + this.v0 = 0; + this.img = img; + this.step = step; + this.val = def; + this.Draw = function() { + if (typeof (gadget) != "undefined" || imgknobs[img] == undefined) + return; + var n = Math.floor(this.val * step); + if (this.val == 1) + --n; + ctx.drawImage(imgknobs[img], 0, n * h, w, h, this.x, this.y, w, h); + } + this.Set = function(v) { + if (v < 0) + v = 0; + if (v > 1) + v = 1; + if (this.step > 1) + v = Math.floor(v * (this.step - 1)) / (this.step - 1); + this.val = v; + } + this.MouseDown = function(x, y) { + this.x0 = x; + this.y0 = y; + this.v0 = this.val; + } + this.MouseMove = function(x, y) { + if (typeof (gadget) != "undefined") + return; + this.Set(this.v0 + (x - this.x0 - y + this.y0) * 0.01); + this.Draw(); + } + this.MouseUp = function(x, y) { + } +} +function Switch(x, y, w, h, img, step, def) { + this.ty = 102; + this.x = x; + this.y = y; + this.w = w; + this.h = h; + this.img = img; + this.step = step; + this.val = def; + this.Draw = function() { + if (typeof (gadget) != "undefined" || imgknobs[img] == undefined) + return; + var n = Math.floor(this.val * this.step); + if (this.val == 1) + --n; + ctx.drawImage(imgknobs[img], 0, n * this.h, this.w, this.h, this.x, this.y, this.w, this.h); + } + this.Set = function(v) { + if (v < 0) + v = 0; + if (v > 1) + v = 1; + this.val = v; + } + this.MouseDown = function(x, y) { + this.MouseMove(x, y); + } + this.MouseMove = function(x, y) { + if (typeof (gadget) != "undefined") + return; + this.Set(Math.floor((1 - (y - this.y) / this.h) * this.step) / (this.step - 1)); + this.Draw(); + } + this.MouseUp = function(x, y) { + } +} +function Slider(x, y,def) { + this.ty = 101; + this.x = x; + this.y = y; + this.w = 16; + this.h = 65; + this.val = def; + this.vala = (Math.pow(1000, this.val) - 1) * 0.0001; + this.v0 = 0; + this.x0 = 0; + this.y0 = 0; + this.Draw = function() { + if (typeof (gadget) != "undefined") + return; + ctx.drawImage(imgknobs["slider"], this.x, this.y + 50 - this.val * 50); + } + this.Set=function(v) { + if (v < 0) + v = 0; + if (v > 1) + v = 1; + this.val = v; + this.vala = (Math.pow(100, this.val) - 1) * 0.04; + } + this.MouseDown = function(x, y) { + this.x0 = x; + this.y0 = y; + this.v0 = this.val; + } + this.MouseMove = function(x, y) { + if (typeof (gadget) != "undefined") + return; + this.Set(this.v0 + (this.y0 - y) * 0.01); + this.Draw(); + } + this.MouseUp = function(x,y) { + } +} +var cnt = 0; +function Key(x, y) { + this.ty = 900; + this.x = x; + this.y = y; + if (typeof(gadget) == "undefined") + this.w = 448; + else + this.w = 272; + this.h = 64; + this.gate = 0; + this.cv = 0; + this.retrig = 0; + this.lastn = -1; + this.table = [ + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1, + 27, -1, 13, 15, -1, 18, 20, 22, -1, 25, -1, -1, -1, -1, -1, -1, + -1, -1, 7, 4, 3, 16, -1, 6, 8, 24, 10, -1, 13, 11, 9, 26, + 28, 12,17,1,19,23,5,14,2,21,0,-1,-1,-1,-1,-1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 15, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, -1, 14, -1, + ]; + this.press = new Array(); + this.Draw = function() { + } + this.KeyPosX = function(n) { + return Math.floor(n / 12) * 112 + [0, 12, 16, 28, 32, 48, 60, 64, 76, 80, 92, 96][n % 12]; + } + this.KeyPosY = function(n) { + return [40, 0, 40, 0, 40, 40, 0, 40, 0, 40, 0, 40][n % 12]; + } + this.DrawKey = function(n) { + // if (this.lastn != n) { + var nmax = 48; + if (typeof (gadget) != "undefined") + nmax = 29; + ctx.drawImage(imgpanel, this.x, this.y, this.w, this.h, this.x, this.y, this.w, this.h); + if (n >= 0 && n < nmax) { + var y = this.KeyPosY(n); + var w = (y != 0) ? 16 : 8; + var h = (y != 0) ? 24 : 40; + ctx.drawImage(imgknobs["keypress"], this.KeyPosX(n), y, w, h, this.x + this.KeyPosX(n), this.y + y, w, h); + } + this.lastn = n; + // } + } + this.MouseDown = function(x, y) { + this.gate = 1; + this.MouseMove(x, y); + } + this.MouseMove = function(x, y) { + var n; + x = (x - this.x); + if (y >= this.y + 40) { + x = Math.floor(x / 16); + if (x < 0) + x = 0; + if (x >= 28) + x = 27; + n = Math.floor(x / 7) * 12 + [0, 2, 4, 5, 7, 9, 11][x % 7]; + } + else { + var xx = x + 5; + if (xx % 16 < 10) { + var xxx = Math.floor(xx / 16) % 7; + if (xxx == 1 || xxx == 2 || xxx == 4 || xxx == 5 | xxx == 6) { + x = Math.floor(x / 16); + n = Math.floor(x / 7) * 12 + [0, 1, 3, 0, 6, 8, 10][xxx]; + this.cv = n / 12 * 0.2; + this.DrawKey(n); + return; + } + } + x = Math.floor(x / 16); + if (x < 0) + x = 0; + if (x >= 28) + x = 27; + } + n = Math.floor(x / 7) * 12 + [0, 2, 4, 5, 7, 9, 11][x % 7]; + this.cv = n / 12 * 0.2; + if (this.lastn >= 0 && n >= 0 && n != this.lastn) + this.retrig = 1; + this.DrawKey(n); + } + this.MouseUp = function(x, y) { + this.gate = 0; + this.DrawKey(-1); + } + this.AllOff = function() { + this.press.length = 0; + this.gate = 0; + this.DrawKey(-1); + } + this.NoteOn = function(n,v) { + for (var i = 0; i < this.press.length; ++i) { + if (this.press[i] == n) + break; + } + if (i == this.press.length) { + this.gate = 1; + this.retrig = 1; + n -= 36; + this.cv = n / 60; + this.DrawKey(n); + } + } + this.NoteOff = function(n) { + for (var i = 0; i < this.press.length; ++i) { + if (this.press[i] == n) { + this.press.splice(i, 1); + break; + } + } + if (this.press.length == 0) { + this.gate = 0; + this.DrawKey(-1); + } + else { + n = this.press[0] - 36; + this.cv = n / 60; + this.DrawKey(n); + } + } + this.KeyPress = function(c, f) { + if (f) { + if (c >= 0x20 && c <= 0xbf) { + var n = this.table[c - 0x20]; + if (n >= 0) { + for (var i = 0; i < this.press.length; ++i) { + if (this.press[i] == c) + break; + } + if (i == this.press.length) { + this.press.unshift(c); + this.gate = 1; + this.retrig = 1; + this.cv = n / 60; + this.DrawKey(n); + } + } + } + } + else { + for (var i = 0; i < this.press.length; ++i) { + if (this.press[i] == c) { + this.press.splice(i, 1); + break; + } + } + if (this.press.length == 0) { + this.gate = 0; + this.DrawKey(-1); + } + else { + var n = this.table[this.press[0] - 0x20]; + this.cv = n / 60; + this.DrawKey(n); + } + } + } +} +function Knobs() { + this.drag = null; + this.knobs = new Array(); + this.AddRect = function(name, x, y, w, h) { + this.knobs[name] = new Rect(x, y, w, h); + return this.knobs[name]; + } + this.AddJack = function(name, x, y,ty,col) { + this.knobs[name] = new Jack(x, y,ty,col); + return this.knobs[name]; + } + this.AddKnob = function(name, x, y, w,h,img, step,def) { + this.knobs[name] = new Knob(x, y, w,h,img,step,def); + return this.knobs[name]; + } + this.AddSwitch = function(name, x, y,w,h,img,step,def) { + this.knobs[name] = new Switch(x,y,w,h,img,step,def); + return this.knobs[name]; + } + this.AddSlider = function(name, x, y, def) { + this.knobs[name] = new Slider(x, y, def); + return this.knobs[name]; + } + this.AddKey = function(name, x, y) { + this.knobs[name] = new Key(x, y); + return this.knobs[name]; + } + this.MouseDown = function(x, y) { + this.drag = this.HitTest(x, y); + if (this.drag != null) + this.drag.MouseDown(x, y); + } + this.MouseMove = function(x, y) { + if (this.drag != null) { + app.Draw(); + this.drag.MouseMove(x, y); + } + } + this.MouseUp = function(x, y) { + var wd = this.HitTest(x, y); + if (this.drag != null) { + if (wd != null) { + if (wd.ty == 0 && (this.drag.ty == 1 || this.drag.ty == 2)) { + wd.Connect(this.drag); + } + if ((wd.ty == 1 || wd.ty == 2) && this.drag.ty == 0) { + this.drag.Connect(wd); + } + } + if (this.drag.ty == 0) { + if(wd==null || (wd.ty!=1 && wd.ty!=2)) + this.drag.Connect(null); + } + this.drag.MouseUp(x, y); + } + this.drag = null; + app.Draw(); + } + this.HitTest = function(x, y) { + var wd, r; + r = null; + for (var i in this.knobs) { + var wd = this.knobs[i]; + if (x >= wd.x && x < wd.x + wd.w && y >= wd.y && y < wd.y + wd.h) { + if (wd.ty < 1000) + r = wd; + } + } + return r; + } + this.Draw = function() { + for (var i in this.knobs) { + if (this.knobs[i].ty >= 100) + this.knobs[i].Draw(); + } + for (var i in this.knobs) { + if (this.knobs[i].ty < 100) + this.knobs[i].Draw(); + } + if (this.drag != null && this.drag.ty < 100) { + var wd = this.HitTest(mouseX, mouseY); + var f = 0; + if (wd != null && wd.ty < 100) { + if ((this.drag.ty == 0 && wd.ty != 0) || (this.drag.ty != 0 && wd.ty == 0)) + f = 1; + else + f = 2; + } + this.drag.Cable(this.drag, mouseX, mouseY, 0x808080, f); + } + } +} +function Keyboard(name, x, y) { + this.str = ""; + this.start = 0; + this.tempo = 120; + this.deflen = 8; + this.oct = 3; + this.index = 0; + this.dur = 0; + this.gt = 0; + this.cvcur = 0; + this.cvlog = 0; + this.jckCv = app.knobs.AddJack(name + ".cv", x + 24, y + 8, 2,0x600000); + this.jckGate = app.knobs.AddJack(name + ".g", x + 60, y + 8, 2, 0x700000); + this.knbGlide = app.knobs.AddKnob(name + ".gl", x + 484, y + 36, 32, 32, "knob", 51, 0); + if (typeof (gadget) != "undefined") + this.key = app.knobs.AddKey(name + ".k", x, y); + else + this.key = app.knobs.AddKey(name + ".k", x + 24, y + 48); + this.SetStr=function(s) { + this.str=s; + } + this.Start = function(v) { + this.jckGate.buf[0] = 0; + this.tempo = 120; + this.deflen = 8; + this.oct = 3; + this.index = 0; + this.start = v; + if (v == 0) + this.key.DrawKey(-1); + } + this.GetNum=function() { + var n = 0; + while (this.str[this.index] >= '0' && this.str[this.index] <= '9') { + n = n * 10 + parseInt(this.str[this.index]); + ++this.index; + } + return n; + } + this.Note = function(n) { + ++this.index; + var n2 = n; + while (1) { + switch (this.str[this.index]) { + case '+': + case '#': + ++n2; + ++this.index; + break; + case '-': + --n2; + ++this.index; + break; + default: + var len; + len = this.GetNum(); + if (len <= 0) + len = this.deflen; + var st = 240 / (this.tempo * len); + var st2 = st; + while(this.str[this.index] == '.'){ + ++this.index; + st += (st2/=2); + } + if (this.str[this.index] == '&'|| this.str[this.index] == '^') { + ++this.index; + this.gt = st; + } + else + this.gt = st * 0.8; + this.dur += st; + if (n >= 0) { + var nn = (this.oct - 2) * 12 + n2; + var v = n / 12 * 0.2; + if (v < 0) + v = 0; + if (v > 2) + v = 2; + this.cvlog=(nn / 12 * 0.2); + this.jckGate.FillBuf(1); + this.key.DrawKey(nn); + } + else { + this.jckGate.FillBuf(0); + this.gt = 0; + this.key.DrawKey(-1); + } + return; + } + } + } + this.OutCv = function() { + var diff = Math.abs(this.cvlog - this.cvcur); + var ratio = 1; + if (this.knbGlide.val != 0) { + ratio = Math.pow(100, this.knbGlide.val) * 0.000078125 * samplerate; + ratio = 1 - Math.exp(Math.log(0.01) / ratio); + } + if (diff < 1e-10) + this.cvcur = this.cvlog; + else + this.cvcur += (this.cvlog - this.cvcur) * ratio; + this.jckCv.FillBuf(this.cvcur); + } + this.Process = function() { + if (this.start == 0) { + if (this.key.gate != 0) { + if (this.key.retrig) + this.jckGate.FillBuf(0); + else + this.jckGate.FillBuf(1); + this.cvlog = this.key.cv; + } + else + this.jckGate.FillBuf(0); + this.OutCv(); + this.key.retrig = 0; + return; + } + this.key.retrig = 0; + if (this.dur > 0) { + this.dur -= 128 / samplerate; + } + if (this.gt > 0) { + if ((this.gt -= 128 / samplerate) <= 0) { + this.gt = 0; + this.jckGate.FillBuf(0); + } + } + while (this.dur <= 0) { + if (this.index >= this.str.length) + break; + switch (this.str[this.index]) { + case 'T': + case 't': + ++this.index; + this.tempo = this.GetNum(); + if (this.tempo <= 0) + this.tempo = 120; + break; + case 'V': + ++this.index; + this.GetNum(); + break; + case 'L': + case 'l': + ++this.index; + this.deflen = this.GetNum(); + break; + case '>': + ++this.index; + ++this.oct; + break; + case '<': + ++this.index; + --this.oct; + break; + case 'O': + case 'o': + ++this.index; + this.oct = this.GetNum(); + break; + case 'R': + case 'r': + this.Note(-1); + break; + case 'C': + case 'c': + this.Note(0); + break; + case 'D': + case 'd': + this.Note(2); + break; + case 'E': + case 'e': + this.Note(4); + break; + case 'F': + case 'f': + this.Note(5); + break; + case 'G': + case 'g': + this.Note(7); + break; + case 'A': + case 'a': + this.Note(9); + break; + case 'B': + case 'b': + this.Note(11); + break; + default: + ++this.index; + break; + } + } + this.OutCv(); + if (this.index >= this.str.length) { + this.tempo = 120; + this.deflen = 8; + this.oct = 3; + this.index = 0; + } + } +} +function Mix(name, x, y) { + try { + this.buf = new Float32Array(128); + } catch(e) { + this.buf=new Array(128); + } + this.jckIn1 = app.knobs.AddJack(name + ".i1", x + 8, y+52, 0,0x005000); + this.jckIn2 = app.knobs.AddJack(name + ".i2", x + 28, y+52, 0,0x006000); + this.jckIn3 = app.knobs.AddJack(name + ".i3", x + 48, y+52, 0,0x007000); + this.jckIn4 = app.knobs.AddJack(name + ".i4", x + 68, y+52, 0,0x008000); + this.sliIn1 = app.knobs.AddSlider(name + ".i1m", x + 8, y+72, 0.8); + this.sliIn2 = app.knobs.AddSlider(name + ".i2m", x + 28, y+72, 0.8); + this.sliIn3 = app.knobs.AddSlider(name + ".i3m", x + 48, y+72, 0); + this.sliIn4 = app.knobs.AddSlider(name + ".i4m", x + 68, y+72, 0); + this.Process = function() { + for (var i = 0; i < 128; ++i) { + this.buf[i] = 1e-100; + } + if (this.jckIn1.connect) { + var vala = this.sliIn1.vala; + for (var i = 0; i < 128; ++i) + this.buf[i] += this.jckIn1.connect.buf[i] * vala; + } + if (this.jckIn2.connect) { + var vala = this.sliIn2.vala; + for (var i = 0; i < 128; ++i) + this.buf[i] += this.jckIn2.connect.buf[i] * vala; + } + if (this.jckIn3.connect) { + var vala = this.sliIn3.vala; + for (var i = 0; i < 128; ++i) + this.buf[i] += this.jckIn3.connect.buf[i] * vala; + } + if (this.jckIn4.connect) { + var vala = this.sliIn4.vala; + for (var i = 0; i < 128; ++i) + this.buf[i] += this.jckIn4.connect.buf[i] * vala; + } + } +} +function Ring(name, x, y) { + this.jckIn1 = app.knobs.AddJack(name + ".i1", x+8, y + 0, 0,0x009000); + this.jckIn2 = app.knobs.AddJack(name + ".i2", x+32, y + 0, 0,0x00a000); + this.jckOut = app.knobs.AddJack(name + ".o", x + 68, y + 0, 1,0x800000); + this.Process = function() { + if (this.jckOut.fanout > 0) { + var out = this.jckOut.buf; + if (this.jckIn1.connect && this.jckIn2.connect) { + var in1 = this.jckIn1.connect.buf; + var in2 = this.jckIn2.connect.buf; + for (var i = 0; i < 128; ++i) + out[i] = in1[i] * in2[i]; + } + else { + for (var i = 0; i < 128; ++i) + out[i] = 0; + } + } + } +} +function Noise(name, x, y) { + this.jckOut = app.knobs.AddJack(name + ".o", x + 68, y + 0, 1,0x900000); + this.Process = function() { + if (this.jckOut.fanout > 0) { + var out = this.jckOut.buf; + for (var i = 0; i < 128; ++i) + out[i] = Math.random()*2 - 1; + } + } +} +function SH(name, x, y) { + this.hold = 0; + this.trlast = 0; + this.jckIn = app.knobs.AddJack(name + ".i", x + 8, y + 0, 0,0x009000); + this.jckTr = app.knobs.AddJack(name + ".tr", x + 32, y + 0, 0,0x00a000); + this.jckOut = app.knobs.AddJack(name + ".o", x + 68, y + 0, 1,0x990000); + this.Process = function() { + if (this.jckOut.fanout > 0) { + var out = this.jckOut.buf; + var hold = this.hold; + if (this.jckTr.connect != null) { + var tr = this.jckTr.connect.buf[0]; + if (tr > 0 && this.trlast <= 0) { + if (this.jckIn.connect != null) + this.hold = this.jckIn.connect.buf[0]; + else + this.hold = 0; + } + this.trlast = tr; + } + for (var i = 0; i < 128; ++i) + out[i] = hold; + } + } +} +function Env(name, x, y) { + this.jckOutP = app.knobs.AddJack(name + ".op", x + 68, y + 120, 2,0xb00000); + this.jckOutN = app.knobs.AddJack(name + ".on", x + 40, y + 120, 2,0xc00000); + this.jckTrig = app.knobs.AddJack(name + ".tr", x + 8, y + 120, 0,0); + this.sliA = app.knobs.AddSlider(name + ".a", x + 8, y + 28, 0); + this.sliD = app.knobs.AddSlider(name + ".d", x + 28, y + 28, 0); + this.sliS = app.knobs.AddSlider(name + ".s", x + 48, y + 28, 1); + this.sliR = app.knobs.AddSlider(name + ".r", x + 68, y + 28, 0); + this.phase = 0; + this.val = 0; + this.Process = function() { + if (this.jckTrig.connect == null) { + this.jckOutP.buf[0] = this.jckOutN.buf[0] = 0; + this.phase = this.val = 0; + return; + } + var n = 128 / samplerate; + var ratea = n / (Math.pow(1000, this.sliA.val) * 0.001); + var rated = Math.pow(10, -2 / ((Math.pow(1000, this.sliD.val) * 0.01) / n)); + var rater = Math.pow(10, -2 / ((Math.pow(1000, this.sliR.val) * 0.01) / n)); + switch (this.phase) { + case 0: + if (this.jckTrig.connect.buf[0] > 0) + this.phase = 1; + else { + if (this.val > this.sliS.val) { + this.val = this.sliS.val + (this.val - this.sliS.val) * rated; + } + this.val *= rater; + if (this.val < 0.00001) + this.val = 0; + } + break; + case 1: + if (this.jckTrig.connect.buf[0] > 0) { + if ((this.val += ratea) >= 1) { + this.val = 1; + this.phase = 2; + } + } + else { + this.phase = 0; + } + break; + case 2: + if (this.jckTrig.connect.buf[0] > 0) { + this.val = this.sliS.val + (this.val - this.sliS.val) * rated; + } + else + this.phase = 0; + break; + } + var xxp = this.val; + var xxn = -this.val; + for (var i = 0; i < 128; ++i) { + this.jckOutP.buf[i] = xxp; + this.jckOutN.buf[i] = xxn; + } + } +} +function Lfo(name, x, y) { + this.jckOut = app.knobs.AddJack(name + ".o", x + 68, y + 20, 2,0x880000); + this.jckOut10 = app.knobs.AddJack(name + ".o10", x + 40, y + 20, 2,0x990000); + this.knbForm = app.knobs.AddSwitch(name + ".form", x + 8, y + 64, 16, 40, "sw3", 3, 1); + this.knbFreq = app.knobs.AddKnob(name + ".f", x + 48, y + 68, 32, 32, "knob", 51, 0.5); + this.phase = 0; + this.Process = function() { + var f = Math.pow(1000, this.knbFreq.val) * 0.1; + this.phase += f * 128 / samplerate; + if (this.phase >= 1) + this.phase -= 1; + var x, mul0, mul1, add0, add1; + switch (this.knbForm.val) { + case 1: + mul0 = 4; + mul1 = -4; + add0 = -1; + add1 = 3; + break; + case 0.5: + mul0 = mul1 = 2; + add0 = add1 = -1; + break; + case 0: + mul0 = mul1 = 0; + add0 = -1; + add1 = 1; + break; + } + if (this.phase >= 0.5) + x = this.phase * mul1 + add1; + else + x = this.phase * mul0 + add0; + var xx = x; + var xx10 = x * 0.1; + for (var i = 0; i < 128; ++i) { + this.jckOut.buf[i] = xx; + this.jckOut10.buf[0] = xx10; + } + } +} +function Vco(name, x, y, oct, pit) { + this.jckPwm = app.knobs.AddJack(name + ".ipw", x + 8, y + 52, 0, 0x007700); + this.jckOut = app.knobs.AddJack(name + ".o", x + 48, y + 52, 1, 0xf00000); + this.sliPwm = app.knobs.AddSlider(name + ".pwm", x + 8, y + 72, 0); + this.sliPw = app.knobs.AddSlider(name + ".pw", x + 28, y + 72, 0); + this.knbOct = app.knobs.AddSwitch(name + ".oct", x + 8, y + 168, 16, 40, "sw5", 5, oct); + this.knbForm = app.knobs.AddSwitch(name + ".form", x + 40, y + 168, 16, 40, "sw3", 3, 0.5); + this.knbCoarse = app.knobs.AddKnob(name + ".co", x + 8, y + 236, 40, 40, "knob2", 25, 0.5); + this.knbPitch = app.knobs.AddKnob(name + ".pi", x + 16, y + 244, 24, 24, "knob3", 51, pit); + this.sliMod1 = app.knobs.AddSlider(name + ".m1m", x + 8, y + 280, 1); + this.sliMod2 = app.knobs.AddSlider(name + ".m2m", x + 28, y + 280, 0.1); + this.sliMod3 = app.knobs.AddSlider(name + ".m3m", x + 48, y + 280, 0); + this.jckMod1 = app.knobs.AddJack(name + ".m1", x + 8, y + 348, 0); + this.jckMod2 = app.knobs.AddJack(name + ".m2", x + 28, y + 348, 0); + this.jckMod3 = app.knobs.AddJack(name + ".m3", x + 48, y + 348, 0); + this.phase = 0; + this.freq = 0; + this.delta = 0; + this.cpw = 0; + this.rcpw = 1; + this.Process = function() { + if (this.jckOut.fanout <= 0) + return; + var cv; + cv = (this.knbOct.val - 0.5) * (this.knbOct.step - 1) * 0.2 + (this.knbCoarse.val - 0.5) * 0.4 + (this.knbPitch.val - 0.5) * 0.4 / 12; + if (this.jckMod1.connect) + cv += this.jckMod1.connect.buf[0] * this.sliMod1.val; + if (this.jckMod2.connect) + cv += this.jckMod2.connect.buf[0] * this.sliMod2.val; + if (this.jckMod3.connect) + cv += this.jckMod3.connect.buf[0] * this.sliMod3.val; + this.freq = 130.8127826502993 * Math.pow(2, cv * 5); + this.delta = this.freq / samplerate; + if (this.delta > 1) + this.delta = 1; + var cpw = this.sliPw.val; + if (this.jckPwm.connect) + cpw += this.jckPwm.connect.buf[0] * this.sliPwm.val; + if (cpw < 0) + cpw = -cpw; + if (cpw > 0.95) + cpw = 0.95; + var rcpw = 1 / (1 - cpw); + var mul0, mul1, add0, add1; + switch (this.knbForm.val) { + case 1: + mul0 = 4; + add0 = -1; + mul1 = -4; + add1 = 3; + break; + case 0.5: + mul0 = mul1 = 2; + add0 = add1 = -1; + break; + case 0: + mul0 = mul1 = 0; + add0 = -1; + add1 = 1; + break; + } + var x; + var out = this.jckOut.buf; + for (var i = 0; i < 128; ++i) { + if (this.phase > cpw) { + var ph2 = (this.phase - cpw) * rcpw; + if (ph2 >= 0.5) + x = ph2 * mul1 + add1; + else + x = ph2 * mul0 + add0; + } + else + x = 0; + this.phase += this.delta; + if (this.phase >= 1) + this.phase -= 1; + out[i] = x; + } + } +} +function Vcf(name, x, y) { + this.y1 = this.y2 = this.y3 = this.y4 = 0; + this.ox = 0; + this.k = this.r = this.p = 0; + this.gain = 0; + this.enable = false; + this.jckIn1 = app.knobs.AddJack(name + ".i1", x + 8, y + 52, 0); + this.jckIn2 = app.knobs.AddJack(name + ".i2", x + 28, y + 52, 0); + this.jckIn3 = app.knobs.AddJack(name + ".i3", x + 48, y + 52, 0); + this.sliIn1 = app.knobs.AddSlider(name + ".i1m", x + 8, y + 72, 0.8); + this.sliIn2 = app.knobs.AddSlider(name + ".i2m", x + 28, y + 72, 0.8); + this.sliIn3 = app.knobs.AddSlider(name + ".i3m", x + 48, y + 72, 0); + this.knbFreq = app.knobs.AddKnob(name + ".f", x + 12, y + 152, 32, 32, "knob", 50, 0.8); + this.knbReso = app.knobs.AddKnob(name + ".r", x + 12, y + 200, 32, 32, "knob", 50, 0.5); + this.jckOut = app.knobs.AddJack(name + ".o", x + 48, y + 252, 1); + this.sliMod1 = app.knobs.AddSlider(name + ".m1m", x + 8, y + 280, 1); + this.sliMod2 = app.knobs.AddSlider(name + ".m2m", x + 28, y + 280, 0.5); + this.sliMod3 = app.knobs.AddSlider(name + ".m3m", x + 48, y + 280, 0); + this.jckMod1 = app.knobs.AddJack(name + ".m1", x + 8, y + 348, 0); + this.jckMod2 = app.knobs.AddJack(name + ".m2", x + 28, y + 348, 0); + this.jckMod3 = app.knobs.AddJack(name + ".m3", x + 48, y + 348, 0); + this.SetFreq = function(f) { + f = Math.min(0.45, Math.max(0.001, f)); + this.p = f * (1.8 - 0.8 * f); + this.k = this.p * 2 - 1; + t = (1 - this.p) * 1.35; + t2 = 11 + t * t; + this.r = this.knbReso.val * (t2 + 6 * t) / (t2 - 6 * t) * 0.8; + } + this.SetFreq(1); + this.Process = function() { + if (this.jckOut.fanout <= 0) + return; + var cv; + cv = this.knbFreq.val; + if (this.jckMod1.connect) + cv += this.jckMod1.connect.buf[0] * this.sliMod1.val; + if (this.jckMod2.connect) + cv += this.jckMod2.connect.buf[0] * this.sliMod2.val; + if (this.jckMod3.connect) + cv += this.jckMod3.connect.buf[0] * this.sliMod3.val; + this.freq = 130.8127826502993 * Math.pow(2, cv * 5); + this.SetFreq(this.freq / samplerate); + var sliIn1 = this.sliIn1.val; + var sliIn2 = this.sliIn2.val; + var sliIn3 = this.sliIn3.val; + var enIn1 = (this.jckIn1.connect != null); + var enIn2 = (this.jckIn2.connect != null); + var enIn3 = (this.jckIn3.connect != null); + if (enIn1 || enIn2 || enIn3) { + var out = this.jckOut.buf; + var k = this.k; + var p = this.p; + this.enable = true; + for (var i = 0; i < 128; ++i) { + var x = 1e-100; + if (enIn1) + x += this.jckIn1.connect.buf[i] * sliIn1; + if (enIn2) + x += this.jckIn2.connect.buf[i] * sliIn2; + if (enIn3) + x += this.jckIn3.connect.buf[i] * sliIn3; + + x = x * .1 - this.r * this.y4; + y1 = this.y1; y2 = this.y2; y3 = this.y3; + this.y1 = (x + this.ox) * p - y1 * k; + this.y2 = (this.y1 + y1) * p - y2 * k; + this.y3 = (this.y2 + y2) * p - y3 * k; + y4 = (this.y3 + y3) * p - this.y4 * k; + this.y4 = y4 - y4 * y4 * y4 * 0.1666666666666667; + this.ox = x; + out[i] = this.y4 * 12; + } + } + else { + if (this.enable) + this.jckOut.FillBuf(0); + this.enable = false; + } + } +} +function Vca(name, x, y) { + this.gain = 0; + this.enable = false; + this.jckIn1 = app.knobs.AddJack(name + ".i1", x + 8, y + 52, 0); + this.jckIn2 = app.knobs.AddJack(name + ".i2", x + 28, y + 52, 0); + this.jckIn3 = app.knobs.AddJack(name + ".i3", x + 48, y + 52, 0); + this.sliIn1 = app.knobs.AddSlider(name + ".i1m", x + 8, y + 72, 0.8); + this.sliIn2 = app.knobs.AddSlider(name + ".i2m", x + 28, y + 72, 0); + this.sliIn3 = app.knobs.AddSlider(name + ".i3m", x + 48, y + 72, 0); + this.knbVol = app.knobs.AddKnob(name + ".vol", x + 12, y + 164, 32, 32, "knob", 50, 0.5); + this.jckOut = app.knobs.AddJack(name + ".o", x + 48, y + 224, 1); + this.sliMod1 = app.knobs.AddSlider(name + ".m1m", x + 8, y + 280, 1); + this.sliMod2 = app.knobs.AddSlider(name + ".m2m", x + 28, y + 280, 0); + this.sliMod3 = app.knobs.AddSlider(name + ".m3m", x + 48, y + 280, 0); + this.jckMod1 = app.knobs.AddJack(name + ".m1", x + 8, y + 348, 0); + this.jckMod2 = app.knobs.AddJack(name + ".m2", x + 28, y + 348, 0); + this.jckMod3 = app.knobs.AddJack(name + ".m3", x + 48, y + 348, 0); + this.Process = function() { + if (this.jckOut.fanout <= 0) + return; + var v; + var g = this.knbVol.val; + if (this.jckMod1.connect != null) + g += this.jckMod1.connect.buf[0] * this.sliMod1.val; + if (this.jckMod2.connect != null) + g += this.jckMod2.connect.buf[0] * this.sliMod2.val; + if (this.jckMod3.connect != null) + g += this.jckMod3.connect.buf[0] * this.sliMod3.val; + if (g < 0) + g = 0; + if (Math.abs(this.gain - g) < 1e-10) + this.gain = g; + var sli1 = this.sliIn1.val; + var sli2 = this.sliIn2.val; + var sli3 = this.sliIn3.val; + var enIn1 = (this.jckIn1.connect != null); + var enIn2 = (this.jckIn2.connect != null); + var enIn3 = (this.jckIn3.connect != null); + if (enIn1 || enIn2 || enIn3) { + this.enable = true; + var out = this.jckOut.buf; + for (var i = 0; i < 128; ++i) { + v = 1e-100; + if (enIn1) + v += this.jckIn1.connect.buf[i] * sli1; + if (enIn2) + v += this.jckIn2.connect.buf[i] * sli2; + if (enIn3) + v += this.jckIn3.connect.buf[i] * sli3; + out[i] = v * this.gain; + this.gain += (g - this.gain) * 0.02; +// this.gain = g; + } + } + else { + if (this.enable) + this.jckOut.FillBuf(0); + this.enable = false; + } + } +} +function App() { + this.Draw = function() { + if (!this.canvas || !this.canvas.getContext) { + return false; + } + ctx = this.canvas.getContext('2d'); + ctx.drawImage(imgpanel, 0, 0); + this.knobs.Draw(); + } + this.MouseDown = function(e) { + if(!this.ready){ + audioif.audio.resume(); + this.ready = true; + } + console.log("Press"); + document.getElementById("canvas").focus(); + getXY(e); + app.knobs.MouseDown(mouseX, mouseY); + return false; + } + this.MouseMove = function(e) { + getXY(e); + app.knobs.MouseMove(mouseX, mouseY); + } + this.MouseUp = function(e) { + getXY(e); + app.knobs.MouseUp(mouseX, mouseY); + } + this.TouchDown = function(e) { + if(!this.ready){ + audioif.audio.resume(); + this.ready = true; + } + e.preventDefault(); + document.getElementById("canvas").focus(); + getXYTouch(e); + app.knobs.MouseDown(mouseX, mouseY); + return false; + } + this.TouchMove = function(e) { + e.preventDefault(); + getXYTouch(e); + app.knobs.MouseMove(mouseX, mouseY); + } + this.TouchUp = function(e) { + e.preventDefault(); + getXYTouch(e); + app.knobs.MouseUp(mouseX, mouseY); + } + this.DblClick = function(e) { + } + this.KeyDown = function(e) { + if (document.activeElement == document.getElementById("canvas")) { + app.keyboard.key.KeyPress(e.keyCode, 1); + return false; + } + } + this.KeyUp = function(e) { + app.keyboard.key.KeyPress(e.keyCode, 0); + } + this.KeyPress = function(e) { + if (document.activeElement == document.getElementById("canvas")) + return false; + } + this.Init = function() { + samplerate = 44100; + this.ready = false; + this.canvas = document.getElementById('canvas'); + this.canvas.onmousedown = this.MouseDown; + this.canvas.onmousemove = this.MouseMove; + this.canvas.onmouseup = this.MouseUp; + this.canvas.ondblclick = this.DblClick; + this.canvas.ontouchstart = this.TouchDown; + this.canvas.ontouchmove = this.TouchMove; + this.canvas.ontouchend = this.TouchUp; + document.onkeydown = this.KeyDown; + document.onkeyup = this.KeyUp; + document.onkeypress = this.KeyPress; + this.knobs = new Knobs(); + this.vco1 = new Vco("vco1", 36, 78, 0.5, 0.5); + this.vco2 = new Vco("vco2", 108, 78, 0.25, 0.45); + this.vcf1 = new Vcf("vcf1", 180, 78); + this.vcf2 = new Vcf("vcf2", 252, 78); + this.vca1 = new Vca("vca1", 324, 78); + this.vca2 = new Vca("vca2", 396, 78); + this.env1 = new Env("env1", 468, 78); + this.env2 = new Env("env2", 468, 226); + this.lfo1 = new Lfo("lfo1", 468, 374); + this.lfo2 = new Lfo("lfo2", 564, 374); + this.mix = new Mix("mix", 564, 78); + this.ring = new Ring("ring", 564, 250); + this.noise = new Noise("noise", 564, 286); + this.sh = new SH("sh", 564, 346); + if (typeof(gadget) != "undefined") + this.keyboard = new Keyboard("kb", 24, 154); + else + this.keyboard = new Keyboard("kb", 48, 502); + try { + this.dummybuf = new Float32Array(128); + } catch (e) { + this.dummybuf = new Array(128); + } + for (var i = 0; i < 128; ++i) + this.dummybuf[i] = 0; + audioif = new AudioIf(); + audiomix = new AudioMix(); + imgpanel = document.getElementById("panel"); + imgknobs["knob"] = document.getElementById("knob"); + imgknobs["knob2"] = document.getElementById("knob2"); + imgknobs["knob3"] = document.getElementById("knob3"); + imgknobs["sw2"] = document.getElementById("sw2"); + imgknobs["sw3"] = document.getElementById("sw3"); + imgknobs["sw5"] = document.getElementById("sw5"); + imgknobs["slider"] = document.getElementById("slider"); + imgknobs["keypress"] = document.getElementById("keypress"); + Setup(); + this.Draw(); + var param = location.search; + if (param.length > 1) + CmdLoad(location.search.substring(1)); + } +} +function Interval() { +// if (typeof (document.hasFocus) != "undefined" && document.hasFocus() == false) +// return; + audiomix.Play(); + audioif.Write(); +} +function Init() { + app = new App(); + app.Init(); + if (audioif.enable == 0) { + return; + } + if (audioif.start == 0) { + audioif.Start(); + audiomix.Reset(); + playint = setInterval(Interval, 20); + } + LinkReady(); +} +function CmdPlay(v) { + if (v) { + if(!app.ready) + audioif.audio.resume(); + app.keyboard.SetStr(document.getElementById("mml").value); + app.keyboard.Start(1); + } + else { + app.keyboard.Start(0); + } +} +function CmdSave() { + var jstr = ""; + var kstr = ""; + var vals="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + for (var i in app.knobs.knobs) { + var w = app.knobs.knobs[i]; + switch(w.ty) { + case 0: + if (w.connect != null) { + jstr += vals[w.pnum]; + jstr += vals[w.connect.pnum]; + } + break; + case 100: + case 102: + kstr += vals[(w.val * (w.step-1)) | 0]; + break; + case 101: + kstr += vals[(w.val * 50) | 0]; + break; + } + } + var mstr = encodeURIComponent(document.getElementById("mml").value); + var url = document.URL.split("?")[0] + "?p=" + jstr + "_" + kstr+"&m="+mstr; + document.getElementById("url").value = url; + return url; +} +function GetJack(n, t) { + for (var i in app.knobs.knobs) { + var w = app.knobs.knobs[i]; + if (t == 0) { + if (w.ty == 0) { + if (w.pnum == n) + return w; + } + } + else { + if (w.ty != 0 && w.ty < 100) { + if (w.pnum == n) + return w; + } + } + } +} +function CmdLoad(str) { + if (str == null) { + str = document.getElementById("url").value; + } + n = str.indexOf("?"); + if (n >= 0) + str = str.substring(n + 1); + var param = str.split("&"); + var vals="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + for (var i = 0; i < param.length; ++i) { + if (param[i].search("p=") == 0) { + var s = param[i].substring(2); + for (var ii in app.knobs.knobs) { + var w = app.knobs.knobs[ii]; + if (w.ty == 0) + w.connect = null; + else if (w.ty < 100) + w.fanout = 0; + } + for (var j = 0; j < s.length; j += 2) { + if (s.charAt(j) == "_") + break; + var n = vals.indexOf(s.charAt(j)); + var v = vals.indexOf(s.charAt(j + 1)); + GetJack(n, 0).Connect(GetJack(v, 1)); + } + ++j; + for (var ii in app.knobs.knobs) { + var w = app.knobs.knobs[ii]; + switch (w.ty) { + case 100: + case 102: + w.Set(vals.indexOf(s.charAt(j)) / (w.step-1)); + ++j; + break; + case 101: + w.Set(vals.indexOf(s.charAt(j)) / 50); + ++j; + break; + } + } + } + else if (param[i].search("m=") == 0) { + var s; + try { + s=decodeURIComponent(param[i].substring(2)); + } catch (e) { + s = param[i].substring(2); + } + document.getElementById("mml").value = s; + } + } + app.Draw(); +} +function CmdTweet() { + CmdSave(); + var url = "https://twitter.com/intent/tweet?hashtags=WebModular&url=" + encodeURIComponent(document.getElementById("url").value); + var win = window.open(url, "", "toolbar=0, status=0, width=650, height=360"); + +} +function Message(s) { +} +var datbuf = new Array(4096); +for (var ii = 0; ii < 4096; ++ii) { + datbuf[ii] = 0; +} +function FlashGetEnable() { + if (audioif.enable == 3) + return 1; + else + return 0; +} +function FlashGetData() { + var b = audiomix.GetOutBuf(); + if (b < 0) { + return datbuf; + } + else { + audiomix.NextBuf(); + return audiomix.queout[b]; + } +} +function AudioIf() { + this.start = 0; + this.written = 0; + this.size = Math.floor(samplerate * 15 / 120) * 16; + this.buf = 0; + samplerate = 44100; + this.enable = 0; + this.totalwritten = 0; + this.count = 0; + if (typeof (webkitAudioContext) != "undefined") { + this.audio = new webkitAudioContext(); + samplerate = this.audio.sampleRate; + this.enable = 2; + outbufsize = 1024; + } + else if(typeof (AudioContext) != "undefined") { + this.audio = new AudioContext(); + samplerate = this.audio.sampleRate; + this.enable = 2; + outbufsize = 1024; + } + else if (typeof (Audio) != "function") { + this.audio = new Audio(); + if (typeof (this.audio.mozSetup) == "function") { + this.enable = 1; + outbufsize = 1024; + } + } + if (this.enable == 0) { + this.enable = 3; + outbufsize = 4096; + } + switch (this.enable) { + case 0: + Message("Audio Disabled: 'AudioDataAPI' or 'WebAudioAPI' is not supported in this browser."); + break; + case 1: + Message("Using Audio Data API"); + break; + case 2: + Message("Using Web Audio API"); + break; + case 3: + break; + } + if (this.enable > 0) { + try { + this.dummysample = new Float32Array(outbufsize); + } catch (e) { + this.dummysample = new Array(outbufsize); + } + for (var i = 0; i < outbufsize; ++i) + this.dummysample[i] = 0; + } + if (this.enable == 1) { + this.audio.mozSetup(stereo+1, samplerate); + } + if (this.enable == 2) { + this.dummyosc = this.audio.createOscillator(); + this.jsnode = this.audio.createScriptProcessor(outbufsize,2,2); +// this.jsnode = this.audio.createJavaScriptNode(outbufsize, 2, 2); + this.jsnode.onaudioprocess = function(e) { + var outl = e.outputBuffer.getChannelData(0); + var outr = e.outputBuffer.getChannelData(1); + var b = audiomix.GetOutBuf(); + if (b < 0) { + outl.set(audioif.dummysample); + outr.set(audioif.dummysample); + } + else { + outl.set(audiomix.queout[b]); + outr.set(audiomix.queout[b]); + audiomix.NextBuf(); + } + } + } + this.SetSamplerate = function(s) { + if (s != samplerate) { + samplerate = s; + audiomix.SetSamplerate(); + } + } + this.Write = function() { + if (this.enable == 1) { + if (audioif.start == 0) + return; + if (this.written >= outbufsize2) { + if (audiomix.NextBuf() < 0) + return; + this.written = 0; + } + if (this.totalwritten > this.audio.mozCurrentSampleOffset() + 16384) + return; + var b = audiomix.GetOutBuf(); + if (b >= 0) { + w = this.audio.mozWriteAudio(audiomix.queout[b].subarray(this.written)); + this.totalwritten += w; + this.written += w; + } + } + } + this.Start = function() { + this.start = 1; + switch (this.enable) { + case 1: + break; + case 2: + this.audio.resume(); + this.dummyosc.connect(this.audio.destination); + this.jsnode.connect(this.audio.destination); + break; + } + } + this.Stop = function() { + this.start = 0; + switch (this.enable) { + case 1: + break; + case 2: + this.jsnode.disconnect(0); + break; + } + } + this.SetSize = function(s) { + this.size = s; + } +} +function AudioMix() { + this.queout = new Array(outquenum); + this.queout2 = new Array(outquenum); + this.windex = 0; + this.rindex = 0; + this.pat = 0; + this.step = 0; + this.steplen = samplerate / 8; + this.tick = 0; + this.count = 0; + for (var i = 0; i < outquenum; ++i) { + if (audioif.enable == 1) { + this.queout[i] = new Float32Array(outbufsize2); + for (var ii = 0; ii < outbufsize2; ++ii) + this.queout[i][ii] = 0; + } + else if (audioif.enable == 2) { + this.queout[i] = new Float32Array(outbufsize); + this.queout2[i] = new Float32Array(outbufsize); + for (var ii = 0; ii < outbufsize; ++ii) { + this.queout[i][ii] = this.queout2[i][ii] = 0; + } + } + else { + this.queout[i] = new Array(outbufsize); + for (var ii = 0; ii < outbufsize2; ++ii) + this.queout[i][ii] = 0; + } + } + this.SetSamplerate = function() { + this.steplen = samplerate * 15 / tempo; + } + this.SetTempo = function(x) { + this.steplen = samplerate * 15 / x; + } + this.GetQueNum = function() { + if ((n = this.windex - this.rindex) < 0) + n += outquenum; + return n; + } + this.GetOutBuf = function() { + if (audiomix.rindex == audiomix.windex) + return -1; + return audiomix.rindex; + } + this.NextBuf = function() { + if (audiomix.rindex == audiomix.windex) + return -1; + if (++audiomix.rindex >= outquenum) + audiomix.rindex = 0; + return 1; + } + this.Reset = function() { + audiomix.tick = audiomix.steplen; + audiomix.rindex = audiomix.windex = 0; + audioif.written = 0; + } + this.Render = function(buf) { + } + this.DrawVu = function() { + } + this.Play = function() { + if (((audiomix.windex + 1) % outquenum) == audiomix.rindex) + return; + for (var ilp = 0; ilp < outbufsize; ilp += 128) { + app.keyboard.Process(); + app.noise.Process(); + app.vco1.Process(); + app.vco2.Process(); + app.vcf1.Process(); + app.vcf2.Process(); + app.vca1.Process(); + app.vca2.Process(); + app.lfo1.Process(); + app.lfo2.Process(); + app.env1.Process(); + app.env2.Process(); + app.ring.Process(); + app.sh.Process(); + app.mix.Process(); + switch (audioif.enable) { + case 1: + for (var j = 0; j < 128; ++j) { + audiomix.queout[audiomix.windex][(ilp + j) << 1] = app.mix.buf[j]; + audiomix.queout[audiomix.windex][((ilp + j) << 1) + 1] = app.mix.buf[j]; + } + break; + case 2: + for (var j = 0; j < 128; ++j) { + audiomix.queout[audiomix.windex][ilp + j] = app.mix.buf[j]; + audiomix.queout2[audiomix.windex][ilp + j] = app.mix.buf[j]; + } + break; + case 3: + for (var j = 0; j < 128; ++j) { + audiomix.queout[audiomix.windex][ilp + j] = app.mix.buf[j]; + } + break; + } + } + audiomix.windex = (audiomix.windex + 1) % outquenum; + } +} +function Setup() { + for (var i in app.knobs.knobs) { + var widget = app.knobs.knobs[i]; + if (widget.ty == 0) { + widget.Connect(null); + } + else if (widget.ty < 100) { + widget.fanout = 0; + } + if (widget.ty >= 100 && widget.ty < 200) + widget.Set(0); + } + app.knobs.knobs["vco1.oct"].Set(0.5); + app.knobs.knobs["vco1.form"].Set(0.5); + app.knobs.knobs["vco1.co"].Set(0.5); + app.knobs.knobs["vco1.pi"].Set(0.5); + app.knobs.knobs["vco1.m1m"].Set(1); + app.knobs.knobs["vco2.oct"].Set(0.5); + app.knobs.knobs["vco2.form"].Set(0.5); + app.knobs.knobs["vco2.co"].Set(0.5); + app.knobs.knobs["vco2.pi"].Set(0.48); + app.knobs.knobs["vco2.m1m"].Set(1); + app.knobs.knobs["vcf1.i1m"].Set(0.7); + app.knobs.knobs["vcf1.f"].Set(1); + app.knobs.knobs["vcf1.r"].Set(0.5); + app.knobs.knobs["vcf1.m1m"].Set(1); + app.knobs.knobs["vcf2.i1m"].Set(0.7); + app.knobs.knobs["vcf2.f"].Set(0.8); + app.knobs.knobs["vcf2.r"].Set(0.5); + app.knobs.knobs["vcf2.m1m"].Set(1); + app.knobs.knobs["vca1.i1m"].Set(0.7); + app.knobs.knobs["vca1.m1m"].Set(1); + app.knobs.knobs["vca2.i1m"].Set(0.7); + app.knobs.knobs["vca2.m1m"].Set(1); + app.knobs.knobs["env1.s"].Set(1); + app.knobs.knobs["env2.s"].Set(1); + app.knobs.knobs["lfo1.f"].Set(0.5); + app.knobs.knobs["lfo1.form"].Set(0.5); + app.knobs.knobs["lfo2.f"].Set(0.5); + app.knobs.knobs["lfo2.form"].Set(0.5); + app.knobs.knobs["mix.i1m"].Set(0.5); + app.knobs.knobs["mix.i2m"].Set(0.5); + var n = document.getElementById("patch").selectedIndex; + switch (n) { + case 0: + break; + case 1: + app.knobs.knobs["vco1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vca1.i1"].Connect(app.knobs.knobs["vco1.o"]); + app.knobs.knobs["mix.i1"].Connect(app.knobs.knobs["vca1.o"]); + app.knobs.knobs["vca1.m1"].Connect(app.knobs.knobs["kb.g"]); + break; + case 2: + app.knobs.knobs["vco1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vco2.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vcf1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["env1.tr"].Connect(app.knobs.knobs["kb.g"]); + app.knobs.knobs["vcf1.i1"].Connect(app.knobs.knobs["vco1.o"]); + app.knobs.knobs["vcf1.i2"].Connect(app.knobs.knobs["vco2.o"]); + app.knobs.knobs["vca1.i1"].Connect(app.knobs.knobs["vcf1.o"]); + app.knobs.knobs["mix.i1"].Connect(app.knobs.knobs["vca1.o"]); + app.knobs.knobs["vca1.m1"].Connect(app.knobs.knobs["env1.op"]); + app.knobs.knobs["vco2.oct"].Set(0); + app.knobs.knobs["vcf1.i2m"].Set(0.7); + break; + case 3: + app.knobs.knobs["vco1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vco2.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vcf1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vcf2.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["env1.tr"].Connect(app.knobs.knobs["kb.g"]); + app.knobs.knobs["env2.tr"].Connect(app.knobs.knobs["kb.g"]); + app.knobs.knobs["vcf1.i1"].Connect(app.knobs.knobs["vco1.o"]); + app.knobs.knobs["vcf2.i1"].Connect(app.knobs.knobs["vco2.o"]); + app.knobs.knobs["vca1.i1"].Connect(app.knobs.knobs["vcf1.o"]); + app.knobs.knobs["vca2.i1"].Connect(app.knobs.knobs["vcf2.o"]); + app.knobs.knobs["mix.i1"].Connect(app.knobs.knobs["vca1.o"]); + app.knobs.knobs["mix.i2"].Connect(app.knobs.knobs["vca2.o"]); + app.knobs.knobs["vca1.m1"].Connect(app.knobs.knobs["env1.op"]); + app.knobs.knobs["vca2.m1"].Connect(app.knobs.knobs["env2.op"]); + app.knobs.knobs["vcf1.f"].Set(0.6); + app.knobs.knobs["vcf1.r"].Set(0.6); + app.knobs.knobs["vcf2.f"].Set(0.7); + app.knobs.knobs["vcf2.r"].Set(1); + app.knobs.knobs["vco2.oct"].Set(0); + app.knobs.knobs["env1.d"].Set(0.8); + app.knobs.knobs["env1.s"].Set(0.1); + break; + case 4: + app.knobs.knobs["vco1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vco2.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vcf1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["env1.tr"].Connect(app.knobs.knobs["kb.g"]); + app.knobs.knobs["vcf1.i1"].Connect(app.knobs.knobs["vco1.o"]); + app.knobs.knobs["vcf1.i2"].Connect(app.knobs.knobs["vco2.o"]); + app.knobs.knobs["vca1.i1"].Connect(app.knobs.knobs["vcf1.o"]); + app.knobs.knobs["mix.i1"].Connect(app.knobs.knobs["vca1.o"]); + app.knobs.knobs["vca1.m1"].Connect(app.knobs.knobs["env1.op"]); + app.knobs.knobs["vco1.m2"].Connect(app.knobs.knobs["lfo1.o10"]); + app.knobs.knobs["vcf1.m2"].Connect(app.knobs.knobs["lfo1.o"]); + app.knobs.knobs["vcf1.i2m"].Set(0.8); + app.knobs.knobs["vco1.m2m"].Set(0.1); + app.knobs.knobs["vcf1.m2m"].Set(0.5); + app.knobs.knobs["lfo1.f"].Set(0.4); + app.knobs.knobs["lfo1.form"].Set(1); + break; + case 5: + app.knobs.knobs["vco1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vco2.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vcf1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["env1.tr"].Connect(app.knobs.knobs["kb.g"]); + app.knobs.knobs["vcf1.i1"].Connect(app.knobs.knobs["vco1.o"]); + app.knobs.knobs["vcf1.i2"].Connect(app.knobs.knobs["vco2.o"]); + app.knobs.knobs["vca1.i1"].Connect(app.knobs.knobs["vcf1.o"]); + app.knobs.knobs["mix.i1"].Connect(app.knobs.knobs["vca1.o"]); + app.knobs.knobs["vca1.m1"].Connect(app.knobs.knobs["env1.op"]); + app.knobs.knobs["vco1.m2"].Connect(app.knobs.knobs["lfo1.o10"]); + app.knobs.knobs["vcf1.m2"].Connect(app.knobs.knobs["lfo1.o"]); + app.knobs.knobs["vcf1.i3"].Connect(app.knobs.knobs["noise.o"]); + app.knobs.knobs["sh.i"].Connect(app.knobs.knobs["noise.o"]); + app.knobs.knobs["sh.tr"].Connect(app.knobs.knobs["lfo2.o"]); + app.knobs.knobs["vco1.m2"].Connect(app.knobs.knobs["sh.o"]); + app.knobs.knobs["vcf1.i2m"].Set(0.5); + app.knobs.knobs["vcf1.i3m"].Set(0.4); + app.knobs.knobs["vcf1.r"].Set(0.8); + app.knobs.knobs["vco1.m2m"].Set(0.2); + app.knobs.knobs["vcf1.m2m"].Set(0.5); + app.knobs.knobs["lfo1.f"].Set(0.4); + app.knobs.knobs["lfo1.form"].Set(1); + app.knobs.knobs["lfo2.f"].Set(0.7); + break; + case 6: + app.knobs.knobs["vco1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vco2.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vcf1.i1"].Connect(app.knobs.knobs["ring.o"]); + app.knobs.knobs["vcf1.i2"].Connect(app.knobs.knobs["vca2.o"]); + app.knobs.knobs["vcf1.m1"].Connect(app.knobs.knobs["kb.cv"]); + app.knobs.knobs["vca1.i1"].Connect(app.knobs.knobs["vcf1.o"]); + app.knobs.knobs["vca1.m1"].Connect(app.knobs.knobs["env1.op"]); + app.knobs.knobs["vca2.i1"].Connect(app.knobs.knobs["noise.o"]); + app.knobs.knobs["vca2.m1"].Connect(app.knobs.knobs["env2.op"]); + app.knobs.knobs["env1.tr"].Connect(app.knobs.knobs["kb.g"]); + app.knobs.knobs["env2.tr"].Connect(app.knobs.knobs["kb.g"]); + app.knobs.knobs["mix.i1"].Connect(app.knobs.knobs["vca1.o"]); + app.knobs.knobs["ring.i1"].Connect(app.knobs.knobs["vco1.o"]); + app.knobs.knobs["ring.i2"].Connect(app.knobs.knobs["vco2.o"]); + app.knobs.knobs["vco1.form"].Set(1); + app.knobs.knobs["vco2.form"].Set(1); + app.knobs.knobs["vco2.pi"].Set(0); + app.knobs.knobs["vco2.m1m"].Set(0.5); + app.knobs.knobs["vcf1.i2m"].Set(0.5); + app.knobs.knobs["vcf1.r"].Set(0.8); + app.knobs.knobs["vcf1.f"].Set(0.5); + app.knobs.knobs["env1.d"].Set(0.75); + app.knobs.knobs["env1.s"].Set(0); + app.knobs.knobs["env1.r"].Set(0.75); + app.knobs.knobs["env2.s"].Set(0); + app.knobs.knobs["env2.d"].Set(0.8); + app.knobs.knobs["env2.r"].Set(0.8); + app.knobs.knobs["mix.i1m"].Set(0.75); + break; + } + app.Draw(); +}