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
+
+
+
+
+
+
+
+
+
+
+
+| 1 | 2 C#3 | 3 D#3 | 4 | 5 F#3 | 6 G#3 | 7 A#3 | 8 | 9 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 | 
+
+ | A | S C#2 | D D#2 | F | G F#2 | H G#2 | J A#2 | K | L 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();
+}