@jpdutoit/squelchy 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -18,7 +18,7 @@ import { preload, Vco, Lfo, Delay, semitones, sec, hz } from '@jpdutoit/squelchy
18
18
  const ctx = new AudioContext();
19
19
  await preload(ctx); // registers the worklets of the modules you import
20
20
 
21
- const vco = Vco.create(ctx, { offset: semitones(57) }); // unpatched, offset is the note: 57 = A3
21
+ const vco = Vco.create(ctx, { offset: semitones(57) }); // nothing in voct = note 0 (C-1); 57 semitones up = A3
22
22
  const lfo = Lfo.create(ctx, { frequency: hz(5), amount: semitones(0.3) });
23
23
  const delay = Delay.create(ctx, { time: sec(0.3), feedback: 0.4, mix: 0.35 });
24
24
 
@@ -32,6 +32,8 @@ delay.params.mix.linearRampToValueAtTime(0.8, ctx.currentTime + 2);
32
32
 
33
33
  Browsers only start audio after a user gesture, so create or `resume()` the `AudioContext` inside a click handler.
34
34
 
35
+ Importing the package is safe on the server (SSR, Node tests): nothing touches Web Audio until you call `preload()` or `create()`, so a static `import` in shared code is fine.
36
+
35
37
  ## Patterns and time
36
38
 
37
39
  Musical positions are plain numbers in beats, and patterns are plain arrays.
@@ -11,7 +11,7 @@ var comb_filter_default = '(()=>{var V=Object.defineProperty;var X=(a,e,r)=>e in
11
11
  var env_follower_default = '(()=>{var d=Object.defineProperty;var h=(t,e,a)=>e in t?d(t,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[e]=a;var u=(t,e,a)=>h(t,typeof e!="symbol"?e+"":e,a);class V extends AudioWorkletProcessor{constructor(){super(...arguments);u(this,"envelope",0)}static get parameterDescriptors(){return[{name:"attack",defaultValue:.01,minValue:.001,maxValue:.5,automationRate:"k-rate"},{name:"release",defaultValue:.1,minValue:.001,maxValue:2,automationRate:"k-rate"}]}process(a,f,l){const s=a[0]?.[0],n=f[0]?.[0];if(!s||!n)return!0;const m=l.attack[0],p=l.release[0],k=Math.exp(-1/(m*sampleRate)),v=Math.exp(-1/(p*sampleRate));let o=this.envelope;for(let r=0;r<s.length;r++){const c=Math.abs(s[r]),i=c>o?k:v;o=i*o+(1-i)*c,n[r]=o}return this.envelope=o,!0}}registerProcessor("env-follower",V);})();\n';
12
12
 
13
13
  // src/lib-runtime/generated/worklet-src/fdn-reverb.ts
14
- var fdn_reverb_default = '(()=>{var nt=Object.defineProperty;var at=(u,c,n)=>c in u?nt(u,c,{enumerable:!0,configurable:!0,writable:!0,value:n}):u[c]=n;var a=(u,c,n)=>at(u,typeof c!="symbol"?c+"":c,n);const ot=[29.7,37.1,41.1,43.7],rt=[5,1.7],it=[4.3,2.3],B=.5,ct=1e-20,lt=500;function pt(u,c){const n=1-u,m=2*Math.PI*c/sampleRate;return u/Math.sqrt(1-2*n*Math.cos(m)+n*n)}class ut extends AudioWorkletProcessor{constructor(n){super();a(this,"combBuf",[]);a(this,"combLen",[]);a(this,"combIdx",[0,0,0,0]);a(this,"combDelaySec",[]);a(this,"lpState",[0,0,0,0]);a(this,"apBuf",[]);a(this,"apLen",[]);a(this,"apIdx",[0,0]);a(this,"sApBuf",[]);a(this,"sApLen",[]);a(this,"sApIdx",[0,0]);a(this,"ceiling");a(this,"g",[0,0,0,0]);a(this,"lpCoef",0);const m=n?.processorOptions?.size??1;this.ceiling=n?.processorOptions?.feedbackCeiling??.995;for(let r=0;r<4;r++){const i=ot[r]/1e3*m,l=Math.max(2,Math.round(i*sampleRate));this.combDelaySec.push(l/sampleRate),this.combLen.push(l),this.combBuf.push(new Float32Array(l))}for(let r=0;r<2;r++){const i=Math.max(2,Math.round(rt[r]/1e3*sampleRate));this.apLen.push(i),this.apBuf.push(new Float32Array(i));const l=Math.max(2,Math.round(it[r]/1e3*sampleRate));this.sApLen.push(l),this.sApBuf.push(new Float32Array(l))}}static get parameterDescriptors(){return[{name:"rt60",defaultValue:2,minValue:.05,maxValue:30,automationRate:"k-rate"},{name:"damping",defaultValue:.55,minValue:0,maxValue:1,automationRate:"k-rate"}]}targetGains(n,m){return this.combDelaySec.map(r=>Math.min(Math.pow(10,-3*r/Math.max(n,.05))/m,this.ceiling))}process(n,m,r){const i=m[0];if(!i||!i[0])return!0;const l=i[0],z=l.length,p=n[0],G=r.rt60[0],j=r.damping[0],N=800*Math.pow(20,Math.max(0,Math.min(1,j))),L=1-Math.exp(-2*Math.PI*N/sampleRate),q=this.targetGains(G,pt(L,lt)),_=.15;for(let t=0;t<4;t++)this.g[t]+=(q[t]-this.g[t])*_;this.lpCoef+=(L-this.lpCoef)*_;const[P,C,O,w]=this.combBuf,[H,W,Z,J]=this.combLen,A=this.g,x=this.lpCoef,o=this.lpState,e=this.combIdx,D=i.length>1?i[1]:null,K=!!(p&&p.length>1);for(let t=0;t<z;t++){let f=0,b=0;if(p&&p.length){for(let s=0;s<p.length;s++)f+=p[s][t];p.length>1&&(f/=p.length),K&&(b=.5*(p[0][t]-p[1][t]))}const Q=P[e[0]],U=C[e[1]],X=O[e[2]],Y=w[e[3]];o[0]+=(Q-o[0])*x,o[1]+=(U-o[1])*x,o[2]+=(X-o[2])*x,o[3]+=(Y-o[3])*x;const E=o[0],T=o[1],V=o[2],k=o[3],v=E*A[0],y=T*A[1],I=V*A[2],R=k*A[3],$=.5*(v+y+I+R),tt=.5*(v-y+I-R),et=.5*(v+y-I-R),st=.5*(v-y-I+R);P[e[0]]=f+b+$,C[e[1]]=f-b+tt,O[e[2]]=f+b+et,w[e[3]]=f-b+st,e[0]=e[0]+1===H?0:e[0]+1,e[1]=e[1]+1===W?0:e[1]+1,e[2]=e[2]+1===Z?0:e[2]+1,e[3]=e[3]+1===J?0:e[3]+1;let S=.5*(E+V),F=.5*(T+k);for(let s=0;s<2;s++){const g=this.apBuf[s],h=this.apIdx[s],d=g[h],M=S+d*B;g[h]=M,S=d-M*B,this.apIdx[s]=h+1===this.apLen[s]?0:h+1}for(let s=0;s<2;s++){const g=this.sApBuf[s],h=this.sApIdx[s],d=g[h],M=F+d*B;g[h]=M,F=d-M*B,this.sApIdx[s]=h+1===this.sApLen[s]?0:h+1}D?(l[t]=S,D[t]=F):l[t]=.5*(S+F)}for(let t=0;t<4;t++)Math.abs(o[t])<ct&&(o[t]=0);for(let t=2;t<i.length;t++)i[t].set(i[t&1]);return!0}}registerProcessor("fdn-reverb",ut);})();\n';
14
+ var fdn_reverb_default = '(()=>{var at=Object.defineProperty;var ot=(h,c,a)=>c in h?at(h,c,{enumerable:!0,configurable:!0,writable:!0,value:a}):h[c]=a;var n=(h,c,a)=>ot(h,typeof c!="symbol"?c+"":c,a);const rt=[29.7,37.1,41.1,43.7],it=[5,1.7],ct=[4.3,2.3],R=.5,lt=1e-20,pt=500;function ht(h,c){const a=1-h,m=2*Math.PI*c/sampleRate;return h/Math.sqrt(1-2*a*Math.cos(m)+a*a)}class ut extends AudioWorkletProcessor{constructor(a){super();n(this,"combBuf",[]);n(this,"combLen",[]);n(this,"combIdx",[0,0,0,0]);n(this,"combDelaySec",[]);n(this,"lpState",[0,0,0,0]);n(this,"apBuf",[]);n(this,"apLen",[]);n(this,"apIdx",[0,0]);n(this,"sApBuf",[]);n(this,"sApLen",[]);n(this,"sApIdx",[0,0]);n(this,"ceiling");n(this,"g",[0,0,0,0]);n(this,"lpCoef",0);n(this,"primed",!1);const m=a?.processorOptions?.size??1;this.ceiling=a?.processorOptions?.feedbackCeiling??.995;for(let r=0;r<4;r++){const i=rt[r]/1e3*m,l=Math.max(2,Math.round(i*sampleRate));this.combDelaySec.push(l/sampleRate),this.combLen.push(l),this.combBuf.push(new Float32Array(l))}for(let r=0;r<2;r++){const i=Math.max(2,Math.round(it[r]/1e3*sampleRate));this.apLen.push(i),this.apBuf.push(new Float32Array(i));const l=Math.max(2,Math.round(ct[r]/1e3*sampleRate));this.sApLen.push(l),this.sApBuf.push(new Float32Array(l))}}static get parameterDescriptors(){return[{name:"rt60",defaultValue:2,minValue:.05,maxValue:30,automationRate:"k-rate"},{name:"damping",defaultValue:.55,minValue:0,maxValue:1,automationRate:"k-rate"}]}targetGains(a,m){return this.combDelaySec.map(r=>Math.min(Math.pow(10,-3*r/Math.max(a,.05))/m,this.ceiling))}process(a,m,r){const i=m[0];if(!i||!i[0])return!0;const l=i[0],j=l.length,p=a[0],N=r.rt60[0],q=r.damping[0],H=800*Math.pow(20,Math.max(0,Math.min(1,q))),S=1-Math.exp(-2*Math.PI*H/sampleRate),F=this.targetGains(N,ht(S,pt));if(!this.primed){for(let t=0;t<4;t++)this.g[t]=F[t];this.lpCoef=S,this.primed=!0}const B=.15;for(let t=0;t<4;t++)this.g[t]+=(F[t]-this.g[t])*B;this.lpCoef+=(S-this.lpCoef)*B;const[L,_,C,P]=this.combBuf,[W,Z,J,K]=this.combLen,A=this.g,v=this.lpCoef,o=this.lpState,e=this.combIdx,O=i.length>1?i[1]:null,Q=!!(p&&p.length>1);for(let t=0;t<j;t++){let f=0,b=0;if(p&&p.length){for(let s=0;s<p.length;s++)f+=p[s][t];p.length>1&&(f/=p.length),Q&&(b=.5*(p[0][t]-p[1][t]))}const U=L[e[0]],X=_[e[1]],Y=C[e[2]],$=P[e[3]];o[0]+=(U-o[0])*v,o[1]+=(X-o[1])*v,o[2]+=(Y-o[2])*v,o[3]+=($-o[3])*v;const w=o[0],D=o[1],E=o[2],T=o[3],V=w*A[0],k=D*A[1],z=E*A[2],G=T*A[3],x=.5*(V+k+z+G),tt=x-k,et=x-V,st=x-z,nt=x-G;L[e[0]]=f+b+tt,_[e[1]]=f-b+et,C[e[2]]=f+b+st,P[e[3]]=f-b+nt,e[0]=e[0]+1===W?0:e[0]+1,e[1]=e[1]+1===Z?0:e[1]+1,e[2]=e[2]+1===J?0:e[2]+1,e[3]=e[3]+1===K?0:e[3]+1;let y=.5*(w+E),I=.5*(D+T);for(let s=0;s<2;s++){const d=this.apBuf[s],u=this.apIdx[s],g=d[u],M=y+g*R;d[u]=M,y=g-M*R,this.apIdx[s]=u+1===this.apLen[s]?0:u+1}for(let s=0;s<2;s++){const d=this.sApBuf[s],u=this.sApIdx[s],g=d[u],M=I+g*R;d[u]=M,I=g-M*R,this.sApIdx[s]=u+1===this.sApLen[s]?0:u+1}O?(l[t]=y,O[t]=I):l[t]=.5*(y+I)}for(let t=0;t<4;t++)Math.abs(o[t])<lt&&(o[t]=0);for(let t=2;t<i.length;t++)i[t].set(i[t&1]);return!0}}registerProcessor("fdn-reverb",ut);})();\n';
15
15
 
16
16
  // src/lib-runtime/generated/worklet-src/flanger.ts
17
17
  var flanger_default = '(()=>{var D=Object.defineProperty;var P=(r,e,i)=>e in r?D(r,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):r[e]=i;var a=(r,e,i)=>P(r,typeof e!="symbol"?e+"":e,i);const M=.009000000000000001,p=class p extends AudioWorkletProcessor{constructor(){super(...arguments);a(this,"bufs",[]);a(this,"writeIdx",0);a(this,"phase",0);a(this,"dcX",[]);a(this,"dcY",[]);a(this,"dcR",1-2*Math.PI*5/sampleRate)}static get parameterDescriptors(){return[{name:"rate",defaultValue:.5,minValue:.05,maxValue:10,automationRate:"a-rate"},{name:"depth",defaultValue:.7,minValue:0,maxValue:1,automationRate:"a-rate"},{name:"feedback",defaultValue:.7,minValue:0,maxValue:.95,automationRate:"a-rate"}]}process(i,E,f){const x=i[0]??[],c=E[0]??[];if(!c.length)return!0;const V=c[0].length,m=f.rate,S=f.depth,A=f.feedback,n=p.LEN,R=c.length;for(;this.bufs.length<R;)this.bufs.push(new Float32Array(n)),this.dcX.push(0),this.dcY.push(0);for(let s=0;s<V;s++){const _=m.length>1?m[s]:m[0],w=S.length>1?S[s]:S[0],Y=A.length>1?A[s]:A[0];let h=(.005+w*.004*Math.sin(2*Math.PI*this.phase))*sampleRate;h<1?h=1:h>n-2&&(h=n-2);let l=this.writeIdx-h;l<0&&(l+=n);const o=l|0,v=l-o,L=o+1===n?0:o+1;for(let t=0;t<R;t++){const d=this.bufs[t],g=x[t]??x[0],b=d[o]+v*(d[L]-d[o]),y=b-this.dcX[t]+this.dcR*this.dcY[t];this.dcX[t]=b,this.dcY[t]=y;let u=(g?g[s]:0)+Y*y;u>-1e-20&&u<1e-20&&(u=0),d[this.writeIdx]=u,c[t][s]=b}this.writeIdx=this.writeIdx+1===n?0:this.writeIdx+1,this.phase+=_/sampleRate,this.phase>=1&&(this.phase-=1)}return!0}};a(p,"LEN",Math.ceil(M*sampleRate)+8);let I=p;registerProcessor("flanger",I);})();\n';
@@ -84,4 +84,4 @@ export {
84
84
  vca_default,
85
85
  waveshaper_default
86
86
  };
87
- //# sourceMappingURL=chunk-MEZE4P3U.js.map
87
+ //# sourceMappingURL=chunk-N7J25N5J.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/lib-runtime/generated/worklet-src/adsr-envelope.ts", "../src/lib-runtime/generated/worklet-src/bitcrusher.ts", "../src/lib-runtime/generated/worklet-src/comb-filter.ts", "../src/lib-runtime/generated/worklet-src/env-follower.ts", "../src/lib-runtime/generated/worklet-src/fdn-reverb.ts", "../src/lib-runtime/generated/worklet-src/flanger.ts", "../src/lib-runtime/generated/worklet-src/formant-table.ts", "../src/lib-runtime/generated/worklet-src/freq-divider.ts", "../src/lib-runtime/generated/worklet-src/freq-shifter.ts", "../src/lib-runtime/generated/worklet-src/glide.ts", "../src/lib-runtime/generated/worklet-src/ladder-filter.ts", "../src/lib-runtime/generated/worklet-src/map-res.ts", "../src/lib-runtime/generated/worklet-src/map-voct-to-freq.ts", "../src/lib-runtime/generated/worklet-src/map-voct-to-period.ts", "../src/lib-runtime/generated/worklet-src/ping-pong.ts", "../src/lib-runtime/generated/worklet-src/pitch-shifter.ts", "../src/lib-runtime/generated/worklet-src/spring-reverb.ts", "../src/lib-runtime/generated/worklet-src/tape-delay.ts", "../src/lib-runtime/generated/worklet-src/tape-stop.ts", "../src/lib-runtime/generated/worklet-src/vca.ts", "../src/lib-runtime/generated/worklet-src/waveshaper.ts"],
4
+ "sourcesContent": ["export default \"(()=>{var x=Object.defineProperty;var R=(a,t,r)=>t in a?x(a,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):a[t]=r;var e=(a,t,r)=>R(a,typeof t!=\\\"symbol\\\"?t+\\\"\\\":t,r);const L=Math.log(1e3);class D extends AudioWorkletProcessor{constructor(){super(...arguments);e(this,\\\"_stage\\\",0);e(this,\\\"_level\\\",0);e(this,\\\"_prevGate\\\",0);e(this,\\\"_hold\\\",0);e(this,\\\"_prevEff\\\",!1);e(this,\\\"_dFor\\\",-1);e(this,\\\"_kd\\\",0);e(this,\\\"_rFor\\\",-1);e(this,\\\"_kr\\\",0)}static get parameterDescriptors(){return[{name:\\\"attack\\\",defaultValue:.01,minValue:.001,maxValue:2},{name:\\\"decay\\\",defaultValue:.46,minValue:.001,maxValue:10},{name:\\\"sustain\\\",defaultValue:.7,minValue:0,maxValue:1},{name:\\\"release\\\",defaultValue:2.1,minValue:.001,maxValue:20}]}process(r,V,i){const f=r[0]?.[0],n=V[0]?.[0];if(!n)return!0;const l=sampleRate,c=i.attack,_=i.decay,v=i.sustain,u=i.release;for(let s=0;s<n.length;s++){const p=f?f[s]:0,g=p>.5,F=this._prevGate>.5,k=c.length>1?c[s]:c[0],o=_.length>1?_[s]:_[0],d=v.length>1?v[s]:v[0],E=u.length>1?u[s]:u[0];g&&!F?(this._hold=Math.ceil((k+o)*l)+1,this._stage=1):this._hold>0&&this._hold--;const A=g||this._hold>0,m=this._prevEff;switch(A&&!m?this._stage=1:!A&&m&&(this._stage=4),this._stage){case 1:{const h=1/Math.max(k*l,1);this._level+=h,this._level>=1&&(this._level=1,this._stage=2);break}case 2:{o!==this._dFor&&(this._dFor=o,this._kd=Math.exp(-L/Math.max(o*l,1)));const h=(this._level-d)*this._kd;this._level=Math.abs(h)<1e-7?d:d+h;break}case 4:{E!==this._rFor&&(this._rFor=E,this._kr=Math.exp(-L/Math.max(E*l,1))),this._level*=this._kr,this._level<=1e-5&&(this._level=0,this._stage=0);break}case 0:default:this._level=0;break}this._prevGate=p,this._prevEff=A,n[s]=this._level}return!0}}registerProcessor(\\\"adsr-envelope\\\",D);})();\\n\";\n", "export default \"(()=>{var _=Object.defineProperty;var g=(e,t,r)=>t in e?_(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r;var l=(e,t,r)=>g(e,typeof t!=\\\"symbol\\\"?t+\\\"\\\":t,r);class m extends AudioWorkletProcessor{constructor(){super(...arguments);l(this,\\\"_held\\\",0);l(this,\\\"_phase\\\",0)}static get parameterDescriptors(){return[{name:\\\"bits\\\",defaultValue:8,minValue:1,maxValue:16},{name:\\\"rate\\\",defaultValue:1,minValue:.01,maxValue:1}]}process(r,c,n){const u=r[0]?.[0],a=c[0]?.[0];if(!u||!a)return!0;const o=n.bits,i=n.rate;for(let s=0;s<a.length;s++){const p=o.length>1?o[s]:o[0],d=i.length>1?i[s]:i[0];if(this._phase+=d,this._phase>=1){this._phase-=1;const h=Math.pow(2,p);this._held=Math.round(u[s]*h)/h}a[s]=this._held}return!0}}registerProcessor(\\\"bitcrusher\\\",m);})();\\n\";\n", "export default \"(()=>{var V=Object.defineProperty;var X=(a,e,r)=>e in a?V(a,e,{enumerable:!0,configurable:!0,writable:!0,value:r}):a[e]=r;var o=(a,e,r)=>X(a,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,r);class w extends AudioWorkletProcessor{constructor(r){super();o(this,\\\"len\\\");o(this,\\\"bufs\\\",[]);o(this,\\\"dcX\\\",[]);o(this,\\\"dcY\\\",[]);o(this,\\\"writeIdx\\\",0);o(this,\\\"dcR\\\",1-2*Math.PI*5/sampleRate);const f=Math.min(5,r?.processorOptions?.maxPeriod??.1);this.len=Math.ceil(f*sampleRate)+4}static get parameterDescriptors(){return[{name:\\\"period\\\",defaultValue:.005,minValue:0,maxValue:5,automationRate:\\\"a-rate\\\"},{name:\\\"feedback\\\",defaultValue:.7,minValue:0,maxValue:.95,automationRate:\\\"a-rate\\\"}]}process(r,f,_){const g=r[0]??[],i=f[0];if(!i||!i.length)return!0;const h=_.period,I=_.feedback,s=this.len,A=i[0].length,E=this.writeIdx;for(let t=0;t<i.length;t++){const u=this.bufs[t]??(this.bufs[t]=new Float32Array(s));let P=this.dcX[t]??0,b=this.dcY[t]??0;const x=g[t],F=i[t];let c=E;for(let n=0;n<A;n++){const y=h.length>1?h[n]:h[0],O=I.length>1?I[n]:I[0];let l=y*sampleRate;l<1?l=1:l>s-2&&(l=s-2);let p=c-l;p<0&&(p+=s);const d=p|0,v=p-d,C=d+1===s?0:d+1,R=u[d]+v*(u[C]-u[d]),D=R-P+this.dcR*b;P=R,b=D;let m=(x?x[n]:0)+O*D;m>-1e-20&&m<1e-20&&(m=0),u[c]=m,c=c+1===s?0:c+1,F[n]=R}this.dcX[t]=P,this.dcY[t]=b}return this.writeIdx=(E+A)%s,!0}}registerProcessor(\\\"comb-filter\\\",w);})();\\n\";\n", "export default \"(()=>{var d=Object.defineProperty;var h=(t,e,a)=>e in t?d(t,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):t[e]=a;var u=(t,e,a)=>h(t,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,a);class V extends AudioWorkletProcessor{constructor(){super(...arguments);u(this,\\\"envelope\\\",0)}static get parameterDescriptors(){return[{name:\\\"attack\\\",defaultValue:.01,minValue:.001,maxValue:.5,automationRate:\\\"k-rate\\\"},{name:\\\"release\\\",defaultValue:.1,minValue:.001,maxValue:2,automationRate:\\\"k-rate\\\"}]}process(a,f,l){const s=a[0]?.[0],n=f[0]?.[0];if(!s||!n)return!0;const m=l.attack[0],p=l.release[0],k=Math.exp(-1/(m*sampleRate)),v=Math.exp(-1/(p*sampleRate));let o=this.envelope;for(let r=0;r<s.length;r++){const c=Math.abs(s[r]),i=c>o?k:v;o=i*o+(1-i)*c,n[r]=o}return this.envelope=o,!0}}registerProcessor(\\\"env-follower\\\",V);})();\\n\";\n", "export default \"(()=>{var at=Object.defineProperty;var ot=(h,c,a)=>c in h?at(h,c,{enumerable:!0,configurable:!0,writable:!0,value:a}):h[c]=a;var n=(h,c,a)=>ot(h,typeof c!=\\\"symbol\\\"?c+\\\"\\\":c,a);const rt=[29.7,37.1,41.1,43.7],it=[5,1.7],ct=[4.3,2.3],R=.5,lt=1e-20,pt=500;function ht(h,c){const a=1-h,m=2*Math.PI*c/sampleRate;return h/Math.sqrt(1-2*a*Math.cos(m)+a*a)}class ut extends AudioWorkletProcessor{constructor(a){super();n(this,\\\"combBuf\\\",[]);n(this,\\\"combLen\\\",[]);n(this,\\\"combIdx\\\",[0,0,0,0]);n(this,\\\"combDelaySec\\\",[]);n(this,\\\"lpState\\\",[0,0,0,0]);n(this,\\\"apBuf\\\",[]);n(this,\\\"apLen\\\",[]);n(this,\\\"apIdx\\\",[0,0]);n(this,\\\"sApBuf\\\",[]);n(this,\\\"sApLen\\\",[]);n(this,\\\"sApIdx\\\",[0,0]);n(this,\\\"ceiling\\\");n(this,\\\"g\\\",[0,0,0,0]);n(this,\\\"lpCoef\\\",0);n(this,\\\"primed\\\",!1);const m=a?.processorOptions?.size??1;this.ceiling=a?.processorOptions?.feedbackCeiling??.995;for(let r=0;r<4;r++){const i=rt[r]/1e3*m,l=Math.max(2,Math.round(i*sampleRate));this.combDelaySec.push(l/sampleRate),this.combLen.push(l),this.combBuf.push(new Float32Array(l))}for(let r=0;r<2;r++){const i=Math.max(2,Math.round(it[r]/1e3*sampleRate));this.apLen.push(i),this.apBuf.push(new Float32Array(i));const l=Math.max(2,Math.round(ct[r]/1e3*sampleRate));this.sApLen.push(l),this.sApBuf.push(new Float32Array(l))}}static get parameterDescriptors(){return[{name:\\\"rt60\\\",defaultValue:2,minValue:.05,maxValue:30,automationRate:\\\"k-rate\\\"},{name:\\\"damping\\\",defaultValue:.55,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"}]}targetGains(a,m){return this.combDelaySec.map(r=>Math.min(Math.pow(10,-3*r/Math.max(a,.05))/m,this.ceiling))}process(a,m,r){const i=m[0];if(!i||!i[0])return!0;const l=i[0],j=l.length,p=a[0],N=r.rt60[0],q=r.damping[0],H=800*Math.pow(20,Math.max(0,Math.min(1,q))),S=1-Math.exp(-2*Math.PI*H/sampleRate),F=this.targetGains(N,ht(S,pt));if(!this.primed){for(let t=0;t<4;t++)this.g[t]=F[t];this.lpCoef=S,this.primed=!0}const B=.15;for(let t=0;t<4;t++)this.g[t]+=(F[t]-this.g[t])*B;this.lpCoef+=(S-this.lpCoef)*B;const[L,_,C,P]=this.combBuf,[W,Z,J,K]=this.combLen,A=this.g,v=this.lpCoef,o=this.lpState,e=this.combIdx,O=i.length>1?i[1]:null,Q=!!(p&&p.length>1);for(let t=0;t<j;t++){let f=0,b=0;if(p&&p.length){for(let s=0;s<p.length;s++)f+=p[s][t];p.length>1&&(f/=p.length),Q&&(b=.5*(p[0][t]-p[1][t]))}const U=L[e[0]],X=_[e[1]],Y=C[e[2]],$=P[e[3]];o[0]+=(U-o[0])*v,o[1]+=(X-o[1])*v,o[2]+=(Y-o[2])*v,o[3]+=($-o[3])*v;const w=o[0],D=o[1],E=o[2],T=o[3],V=w*A[0],k=D*A[1],z=E*A[2],G=T*A[3],x=.5*(V+k+z+G),tt=x-k,et=x-V,st=x-z,nt=x-G;L[e[0]]=f+b+tt,_[e[1]]=f-b+et,C[e[2]]=f+b+st,P[e[3]]=f-b+nt,e[0]=e[0]+1===W?0:e[0]+1,e[1]=e[1]+1===Z?0:e[1]+1,e[2]=e[2]+1===J?0:e[2]+1,e[3]=e[3]+1===K?0:e[3]+1;let y=.5*(w+E),I=.5*(D+T);for(let s=0;s<2;s++){const d=this.apBuf[s],u=this.apIdx[s],g=d[u],M=y+g*R;d[u]=M,y=g-M*R,this.apIdx[s]=u+1===this.apLen[s]?0:u+1}for(let s=0;s<2;s++){const d=this.sApBuf[s],u=this.sApIdx[s],g=d[u],M=I+g*R;d[u]=M,I=g-M*R,this.sApIdx[s]=u+1===this.sApLen[s]?0:u+1}O?(l[t]=y,O[t]=I):l[t]=.5*(y+I)}for(let t=0;t<4;t++)Math.abs(o[t])<lt&&(o[t]=0);for(let t=2;t<i.length;t++)i[t].set(i[t&1]);return!0}}registerProcessor(\\\"fdn-reverb\\\",ut);})();\\n\";\n", "export default \"(()=>{var D=Object.defineProperty;var P=(r,e,i)=>e in r?D(r,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):r[e]=i;var a=(r,e,i)=>P(r,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,i);const M=.009000000000000001,p=class p extends AudioWorkletProcessor{constructor(){super(...arguments);a(this,\\\"bufs\\\",[]);a(this,\\\"writeIdx\\\",0);a(this,\\\"phase\\\",0);a(this,\\\"dcX\\\",[]);a(this,\\\"dcY\\\",[]);a(this,\\\"dcR\\\",1-2*Math.PI*5/sampleRate)}static get parameterDescriptors(){return[{name:\\\"rate\\\",defaultValue:.5,minValue:.05,maxValue:10,automationRate:\\\"a-rate\\\"},{name:\\\"depth\\\",defaultValue:.7,minValue:0,maxValue:1,automationRate:\\\"a-rate\\\"},{name:\\\"feedback\\\",defaultValue:.7,minValue:0,maxValue:.95,automationRate:\\\"a-rate\\\"}]}process(i,E,f){const x=i[0]??[],c=E[0]??[];if(!c.length)return!0;const V=c[0].length,m=f.rate,S=f.depth,A=f.feedback,n=p.LEN,R=c.length;for(;this.bufs.length<R;)this.bufs.push(new Float32Array(n)),this.dcX.push(0),this.dcY.push(0);for(let s=0;s<V;s++){const _=m.length>1?m[s]:m[0],w=S.length>1?S[s]:S[0],Y=A.length>1?A[s]:A[0];let h=(.005+w*.004*Math.sin(2*Math.PI*this.phase))*sampleRate;h<1?h=1:h>n-2&&(h=n-2);let l=this.writeIdx-h;l<0&&(l+=n);const o=l|0,v=l-o,L=o+1===n?0:o+1;for(let t=0;t<R;t++){const d=this.bufs[t],g=x[t]??x[0],b=d[o]+v*(d[L]-d[o]),y=b-this.dcX[t]+this.dcR*this.dcY[t];this.dcX[t]=b,this.dcY[t]=y;let u=(g?g[s]:0)+Y*y;u>-1e-20&&u<1e-20&&(u=0),d[this.writeIdx]=u,c[t][s]=b}this.writeIdx=this.writeIdx+1===n?0:this.writeIdx+1,this.phase+=_/sampleRate,this.phase>=1&&(this.phase-=1)}return!0}};a(p,\\\"LEN\\\",Math.ceil(M*sampleRate)+8);let I=p;registerProcessor(\\\"flanger\\\",I);})();\\n\";\n", "export default \"(()=>{const i=[[800,1200,2500,3300,3750],[400,2e3,2800,3500,4500],[300,2300,3e3,3500,4500],[500,900,2500,3300,3750],[350,700,2500,3300,3750]];class A extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:\\\"baseMorph\\\",defaultValue:0,automationRate:\\\"k-rate\\\"}]}process(m,h,b){const c=m[0],r=h[0],u=c.length>0?c[0]:null,O=b.baseMorph[0],s=r[0],d=r[1],g=r[2],l=r[3],f=r[4];if(!s)return!0;for(let o=0;o<s.length;o++){const F=u?u[o]:0,a=((O+F)%5+5)%5,p=Math.floor(a)%5,M=(p+1)%5,e=a-Math.floor(a),t=i[p],n=i[M];s[o]=t[0]+(n[0]-t[0])*e,d[o]=t[1]+(n[1]-t[1])*e,g[o]=t[2]+(n[2]-t[2])*e,l&&(l[o]=t[3]+(n[3]-t[3])*e),f&&(f[o]=t[4]+(n[4]-t[4])*e)}return!0}}registerProcessor(\\\"formant-table\\\",A);})();\\n\";\n", "export default \"(()=>{var F=Object.defineProperty;var b=(a,e,i)=>e in a?F(a,e,{enumerable:!0,configurable:!0,writable:!0,value:i}):a[e]=i;var t=(a,e,i)=>b(a,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,i);class w extends AudioWorkletProcessor{constructor(){super(...arguments);t(this,\\\"prevSample\\\",0);t(this,\\\"div1State\\\",!1);t(this,\\\"div2Count\\\",0);t(this,\\\"div2State\\\",!1);t(this,\\\"envelope\\\",0);t(this,\\\"smoothGate\\\",0);t(this,\\\"samplesSinceCross\\\",0);t(this,\\\"freqEstimate\\\",0)}static get parameterDescriptors(){return[{name:\\\"oct1Level\\\",defaultValue:.5,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"},{name:\\\"oct2Level\\\",defaultValue:.3,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"}]}process(i,o,h){const r=i[0]?.[0],v=o[0]?.[0],p=o[1],m=o[2]?.[0];if(!r)return!0;const g=h.oct1Level[0],q=h.oct2Level[0],G=.01,V=.01,R=5e-4,A=.02,E=.002,f=p?.[0],u=p?.[1];for(let s=0;s<r.length;s++){const n=r[s],l=Math.abs(n);if(l>this.envelope?this.envelope+=V*(l-this.envelope):this.envelope+=R*(l-this.envelope),this.samplesSinceCross++,this.prevSample<=0&&n>0){if(this.div1State=!this.div1State,this.div2Count++,this.div2Count>=2&&(this.div2State=!this.div2State,this.div2Count=0),this.samplesSinceCross>4&&this.samplesSinceCross<sampleRate){const k=sampleRate/this.samplesSinceCross;this.freqEstimate+=.05*(k-this.freqEstimate)}this.samplesSinceCross=0}this.prevSample=n;const d=this.envelope>G?1:0,L=d>this.smoothGate?A:E;this.smoothGate+=L*(d-this.smoothGate);const S=this.div1State?1:-1,C=this.div2State?1:-1,c=this.smoothGate*this.envelope;v&&(v[s]=(S*g+C*q)*c),f&&(f[s]=S*c),u&&(u[s]=C*c),m&&(m[s]=this.freqEstimate*this.smoothGate)}return!0}}registerProcessor(\\\"freq-divider\\\",w);})();\\n\";\n", "export default \"(()=>{var q=Object.defineProperty;var B=(r,t,s)=>t in r?q(r,t,{enumerable:!0,configurable:!0,writable:!0,value:s}):r[t]=s;var e=(r,t,s)=>B(r,typeof t!=\\\"symbol\\\"?t+\\\"\\\":t,s);const C=[.6923877778065,.9360654322959,.988229522686,.9987488452737],S=[.4021921162426,.856171088242,.9722909545651,.9952884791278];class m{constructor(t){e(this,\\\"a2\\\");e(this,\\\"x1\\\",0);e(this,\\\"x2\\\",0);e(this,\\\"y1\\\",0);e(this,\\\"y2\\\",0);this.a2=t}process(t){const s=this.a2*(t+this.y2)-this.x2;return this.x2=this.x1,this.x1=t,this.y2=this.y1,this.y1=s,s}}class w extends AudioWorkletProcessor{constructor(){super(...arguments);e(this,\\\"branchA\\\",C.map(s=>new m(s)));e(this,\\\"branchB\\\",S.map(s=>new m(s)));e(this,\\\"delayA\\\",0);e(this,\\\"phase\\\",0)}static get parameterDescriptors(){return[{name:\\\"shift\\\",defaultValue:0,minValue:-8e3,maxValue:8e3,automationRate:\\\"a-rate\\\"}]}process(s,y,A){const u=s[0]?.[0],n=y[0]?.[0];if(!n)return!0;if(!u)return n.fill(0),!0;const o=A.shift,c=2*Math.PI,b=c/sampleRate;for(let i=0;i<n.length;i++){const h=o.length>1?o[i]:o[0],v=h<0?-1:1,g=h<0?-h:h,f=u[i];let p=f;for(let a=0;a<this.branchA.length;a++)p=this.branchA[a].process(p);let l=f;for(let a=0;a<this.branchB.length;a++)l=this.branchB[a].process(l);const x=this.delayA,F=l;this.delayA=p,this.phase+=b*g,this.phase>=c&&(this.phase-=c);const d=Math.cos(this.phase),P=Math.sin(this.phase);n[i]=x*d+v*F*P}return!0}}registerProcessor(\\\"freq-shifter\\\",w);})();\\n\";\n", "export default \"(()=>{var m=Object.defineProperty;var v=(r,t,e)=>t in r?m(r,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[t]=e;var s=(r,t,e)=>v(r,typeof t!=\\\"symbol\\\"?t+\\\"\\\":t,e);class f extends AudioWorkletProcessor{constructor(){super(...arguments);s(this,\\\"y\\\",0);s(this,\\\"initialized\\\",!1);s(this,\\\"prevGate\\\",-1)}static get parameterDescriptors(){return[{name:\\\"time\\\",defaultValue:.1}]}process(e,p,u){const n=e[0]?.[0],l=e[1]?.[0],a=p[0]?.[0];if(!n||!a)return!0;const o=u.time;for(let i=0;i<a.length;i++){const c=n[i],d=o.length>1?o[i]:o[0],h=l?l[i]:-1,g=1-Math.exp(-3/(sampleRate*Math.max(d,1e-4))),y=h>0&&this.prevGate<=0;!this.initialized||y?(this.y=c,this.initialized=!0):this.y+=g*(c-this.y),this.prevGate=h,a[i]=this.y}return!0}}registerProcessor(\\\"glide\\\",f);})();\\n\";\n", "export default \"(()=>{var k=Object.defineProperty;var C=(a,e,n)=>e in a?k(a,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):a[e]=n;var y=(a,e,n)=>C(a,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,n);const V=Math.PI*2,W=()=>({y1:0,y2:0,y3:0,y4:0,dcIn:0,dcOut:0});class w extends AudioWorkletProcessor{constructor(){super(...arguments);y(this,\\\"states\\\",[]);y(this,\\\"noisePhase\\\",1)}static get parameterDescriptors(){return[{name:\\\"cutoff\\\",defaultValue:0,minValue:0,maxValue:24e3,automationRate:\\\"a-rate\\\"},{name:\\\"resonance\\\",defaultValue:.6,minValue:-2,maxValue:2,automationRate:\\\"a-rate\\\"},{name:\\\"drive\\\",defaultValue:.3,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"}]}process(n,M,f){const d=n[0]??[],c=M[0];if(!c||c.length===0)return!0;const i=f.cutoff,l=f.resonance,b=1+f.drive[0]*3,I=sampleRate*2,v=1-V*5/sampleRate,m=sampleRate*.45;for(let s=0;s<c.length;s++){const p=c[s],g=d[s]??d[0],t=this.states[s]??(this.states[s]=W());for(let o=0;o<p.length;o++){const O=g?g[o]:0,h=i.length>1?i[o]:i[0],A=h<8?8:h>m?m:h;let r=l.length>1?l[o]:l[0];r<0?r=0:r>1.15&&(r=1.15);const F=r*4,u=1-Math.exp(-V*A/I);this.noisePhase=this.noisePhase*1103515245+12345&2147483647;const L=(this.noisePhase/2147483647-.5)*2e-7;for(let R=0;R<2;R++){const S=Math.tanh(b*O-F*t.y4+L);t.y1+=u*(S-t.y1),t.y2+=u*(Math.tanh(t.y1)-t.y2),t.y3+=u*(Math.tanh(t.y2)-t.y3),t.y4+=u*(Math.tanh(t.y3)-t.y4)}const x=t.y4*(1+r),P=x-t.dcIn+v*t.dcOut;t.dcIn=x,t.dcOut=P,p[o]=P}Math.abs(t.y4)<1e-20&&(t.y1=t.y2=t.y3=t.y4=0)}return!0}}registerProcessor(\\\"ladder-filter\\\",w);})();\\n\";\n", "export default \"(()=>{class x extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:\\\"base\\\",defaultValue:1,minValue:.001,maxValue:1e3},{name:\\\"cvScale\\\",defaultValue:19.9,minValue:0,maxValue:1e3},{name:\\\"qMin\\\",defaultValue:.1,minValue:.001,maxValue:1e3},{name:\\\"qMax\\\",defaultValue:20,minValue:.001,maxValue:1e3},{name:\\\"dbOut\\\",defaultValue:1,minValue:0,maxValue:1}]}process(r,i,t){const s=r[0]?.[0],l=i[0]?.[0];if(!l)return!0;const n=t.base,u=t.cvScale,o=t.qMin[0],c=t.qMax[0],V=t.dbOut[0]>=.5;for(let e=0;e<l.length;e++){const m=n.length>1?n[e]:n[0],d=u.length>1?u[e]:u[0],f=s?s[e]:0;let a=m+f*d;a<o?a=o:a>c&&(a=c),l[e]=V?20*Math.log10(a):a}return!0}}registerProcessor(\\\"map-res\\\",x);})();\\n\";\n", "export default \"(()=>{class u extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:\\\"transpose\\\",defaultValue:0}]}process(s,a,n){const o=s[0]?.[0],r=a[0]?.[0];if(!r)return!0;const e=n.transpose;for(let t=0;t<r.length;t++){const c=e.length>1?e[t]:e[0],p=(o?o[t]:0)+c;r[t]=440*Math.pow(2,(p-69)/12)}return!0}}registerProcessor(\\\"map-voct-to-freq\\\",u);})();\\n\";\n", "export default \"(()=>{class i extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:\\\"transpose\\\",defaultValue:0}]}process(s,a,n){const e=s[0]?.[0],r=a[0]?.[0];if(!r)return!0;const o=n.transpose;for(let t=0;t<r.length;t++){const c=o.length>1?o[t]:o[0],p=(e?e[t]:0)+c,u=440*Math.pow(2,(p-69)/12);r[t]=1/u}return!0}}registerProcessor(\\\"map-voct-to-period\\\",i);})();\\n\";\n", "export default \"(()=>{var I=Object.defineProperty;var k=(s,e,n)=>e in s?I(s,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):s[e]=n;var r=(s,e,n)=>k(s,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,n);class x extends AudioWorkletProcessor{constructor(){super(...arguments);r(this,\\\"bufL\\\",new Float32Array(Math.ceil(2*sampleRate)+4));r(this,\\\"bufR\\\",new Float32Array(Math.ceil(2*2*sampleRate)+4));r(this,\\\"wL\\\",0);r(this,\\\"wR\\\",0);r(this,\\\"dcX\\\",0);r(this,\\\"dcY\\\",0);r(this,\\\"dcR\\\",1-2*Math.PI*5/sampleRate)}static get parameterDescriptors(){return[{name:\\\"time\\\",defaultValue:.3,minValue:.01,maxValue:2,automationRate:\\\"k-rate\\\"},{name:\\\"feedback\\\",defaultValue:.4,minValue:0,maxValue:.95,automationRate:\\\"a-rate\\\"}]}process(n,L,P){const X=n[0]?.[0],b=L[0]?.[0],_=L[1]?.[0];if(!b||!_)return!0;const v=P.time,M=P.feedback,g=this.bufL,A=this.bufR,f=g.length,R=A.length,F=this.dcR;let l=v[0]*sampleRate;l<1?l=1:l>f-3&&(l=f-3);let u=2*v[0]*sampleRate;u<1?u=1:u>R-3&&(u=R-3);let i=this.wL,o=this.wR,w=this.dcX,c=this.dcY;const y=(t,m,h,p)=>{let a=h-p;a<0&&(a+=m);const d=a|0,T=a-d,V=d+1===m?0:d+1;return t[d]+(t[V]-t[d])*T};for(let t=0;t<b.length;t++){const m=X?X[t]:0,h=M.length>1?M[t]:M[0],p=y(g,f,i,l),a=y(A,R,o,u);c=a-w+F*c,w=a,g[i]=m+h*c,A[o]=h*p,b[t]=p,_[t]=a,i++,i===f&&(i=0),o++,o===R&&(o=0)}return Math.abs(c)<1e-20&&(c=0),this.wL=i,this.wR=o,this.dcX=w,this.dcY=c,!0}}registerProcessor(\\\"ping-pong\\\",x);})();\\n\";\n", "export default \"(()=>{var R=Object.defineProperty;var y=(i,e,t)=>e in i?R(i,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[e]=t;var r=(i,e,t)=>y(i,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,t);class E extends AudioWorkletProcessor{constructor(t){super();r(this,\\\"ring\\\");r(this,\\\"ringLen\\\");r(this,\\\"writePos\\\",0);r(this,\\\"readPos\\\");r(this,\\\"grainPhase\\\");r(this,\\\"grainLen\\\");r(this,\\\"jitterLen\\\");r(this,\\\"rng\\\");this.rng=(t?.processorOptions?.seed??2654435769)>>>0||1,this.jitterLen=Math.round(sampleRate*.01),this.ringLen=Math.ceil(sampleRate*1),this.ring=new Float32Array(this.ringLen),this.grainLen=Math.floor(sampleRate*.08),this.readPos=new Float64Array([0,0]),this.grainPhase=new Float64Array([0,.5]),this.readPos[0]=this.readPos[1]=this.ringLen-this.grainLen}static get parameterDescriptors(){return[{name:\\\"semitones\\\",defaultValue:12,minValue:-24,maxValue:24,automationRate:\\\"k-rate\\\"}]}rand(){let t=this.rng;return t^=t<<13,t^=t>>>17,t^=t<<5,this.rng=t>>>0,this.rng/4294967296}process(t,P,p){const h=t[0]?.[0],o=P[0]?.[0];if(!o)return!0;const d=p.semitones[0],c=Math.pow(2,d/12),u=1/this.grainLen,L=2*Math.PI;for(let n=0;n<o.length;n++){const m=h?h[n]:0;this.ring[this.writePos]=m;let g=0;for(let s=0;s<2;s++){if(this.grainPhase[s]+=u,this.grainPhase[s]>=1){this.grainPhase[s]-=1;const f=Math.max(0,c-1)*this.grainLen+2+this.rand()*this.jitterLen;this.readPos[s]=(this.writePos-f+this.ringLen)%this.ringLen}else this.readPos[s]+=c,this.readPos[s]>=this.ringLen?this.readPos[s]-=this.ringLen:this.readPos[s]<0&&(this.readPos[s]+=this.ringLen);const l=this.readPos[s],a=l|0,A=l-a,S=(a+1)%this.ringLen,w=this.ring[a]+A*(this.ring[S]-this.ring[a]),N=.5-.5*Math.cos(L*this.grainPhase[s]);g+=w*N}o[n]=g,this.writePos=this.writePos+1===this.ringLen?0:this.writePos+1}return!0}}registerProcessor(\\\"pitch-shifter\\\",E);})();\\n\";\n", "export default \"(()=>{var $=Object.defineProperty;var tt=(n,o,e)=>o in n?$(n,o,{enumerable:!0,configurable:!0,writable:!0,value:e}):n[o]=e;var s=(n,o,e)=>tt(n,typeof o!=\\\"symbol\\\"?o+\\\"\\\":o,e);const c=[{stages:76,delayMs:37.9,chan:0},{stages:90,delayMs:41.7,chan:1},{stages:82,delayMs:51.3,chan:0},{stages:96,delayMs:47.9,chan:1}],b=c.length,st=.7,N=.95,et=2.4,at=4,nt=150,ot=15,it=.98,rt=1e-20,ct=500;function ht(n){if(n>3)return 1;if(n<-3)return-1;const o=n*n;return n*(27+o)/(27+9*o)}class pt extends AudioWorkletProcessor{constructor(){super();s(this,\\\"apX\\\",[]);s(this,\\\"apY\\\",[]);s(this,\\\"dBuf\\\",[]);s(this,\\\"dLen\\\",[]);s(this,\\\"dIdx\\\",[]);s(this,\\\"fb\\\",[]);s(this,\\\"lp\\\",[]);s(this,\\\"dc\\\",[]);s(this,\\\"g\\\",[]);s(this,\\\"inHpState\\\",0);s(this,\\\"inHpCoef\\\");s(this,\\\"dcCoef\\\");s(this,\\\"a\\\",.56);s(this,\\\"lpCoef\\\",.4);s(this,\\\"knockPos\\\",-1);s(this,\\\"knockLen\\\");s(this,\\\"prevTrig\\\",0);for(let e=0;e<b;e++){this.apX.push(new Float32Array(c[e].stages)),this.apY.push(new Float32Array(c[e].stages));const p=Math.max(2,Math.round(c[e].delayMs/1e3*sampleRate));this.dLen.push(p),this.dBuf.push(new Float32Array(p)),this.dIdx.push(0),this.fb.push(0),this.lp.push(0),this.dc.push(0),this.g.push(0)}this.inHpCoef=1-Math.exp(-2*Math.PI*nt/sampleRate),this.dcCoef=1-Math.exp(-2*Math.PI*ot/sampleRate),this.knockLen=Math.max(8,Math.round(at/1e3*sampleRate))}static get parameterDescriptors(){return[{name:\\\"decay\\\",defaultValue:1.5,minValue:.3,maxValue:4,automationRate:\\\"k-rate\\\"},{name:\\\"tone\\\",defaultValue:.6,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"},{name:\\\"drip\\\",defaultValue:.5,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"}]}process(e,p,m){const h=p[0];if(!h||!h[0])return!0;const x=h[0],w=h[1]??h[0],O=x.length,M=e[0]?.[0],E=e[0]?.[1]??M,I=e[1]?.[0],B=m.decay[0],D=Math.max(0,Math.min(1,m.tone[0])),K=.35+.42*Math.max(0,Math.min(1,m.drip[0]));this.a+=(K-this.a)*.1;const i=this.a,X=1100*Math.pow(6500/1100,D),g=1-Math.exp(-2*Math.PI*X/sampleRate);this.lpCoef+=(g-this.lpCoef)*.15;const Y=this.lpCoef,L=2*Math.PI*ct/sampleRate,k=Math.cos(L),Z=(1-i*i)/(1-2*i*k+i*i),v=1-g,G=g/Math.sqrt(1-2*v*k+v*v),A=1-this.dcCoef,y=1-A*k,C=A*Math.sin(L),H=y*y+C*C,q=1-this.dcCoef*y/H,z=this.dcCoef*C/H,J=G*Math.hypot(q,z);for(let a=0;a<b;a++){const l=(this.dLen[a]+c[a].stages*Z)/sampleRate,u=Math.min(Math.pow(10,-3*l/Math.max(B,.05))/J,it);this.g[a]+=(u-this.g[a])*.15}const U=this.inHpCoef,W=this.dcCoef;for(let a=0;a<O;a++){if(I){const t=I[a];t>.5&&this.prevTrig<=.5&&(this.knockPos=0),this.prevTrig=t}const l=M?(M[a]+E[a])*.5:0;this.inHpState+=U*(l-this.inHpState);let u=(l-this.inHpState)*st;this.knockPos>=0&&(u+=Math.sin(Math.PI*this.knockPos/this.knockLen)*et,++this.knockPos>=this.knockLen&&(this.knockPos=-1));let F=0,S=0;for(let t=0;t<b;t++){let d=u+this.fb[t]+rt;const R=this.apX[t],T=this.apY[t],j=R.length;for(let r=0;r<j;r++){const V=-i*d+R[r]+i*T[r];R[r]=d,T[r]=V,d=V}const _=this.dBuf[t],f=this.dIdx[t],Q=_[f];_[f]=d,this.dIdx[t]=f+1>=this.dLen[t]?0:f+1,this.lp[t]+=Y*(Q-this.lp[t]),this.dc[t]+=W*(this.lp[t]-this.dc[t]);const P=ht(this.lp[t]-this.dc[t]);this.fb[t]=P*this.g[t],c[t].chan===0?F+=P:S+=P}x[a]=F*N,w[a]=S*N}return!0}}registerProcessor(\\\"spring-reverb\\\",pt);})();\\n\";\n", "export default \"(()=>{var L=Object.defineProperty;var Z=(s,e,t)=>e in s?L(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var a=(s,e,t)=>Z(s,typeof e!=\\\"symbol\\\"?e+\\\"\\\":e,t);function E(s){let e=s>>>0;return()=>{e=e+1831565813>>>0;let t=e;return t=Math.imul(t^t>>>15,t|1),t^=t+Math.imul(t^t>>>7,t|61),((t^t>>>14)>>>0)/4294967296}}class O extends AudioWorkletProcessor{constructor(){super(...arguments);a(this,\\\"buf\\\",new Float32Array(Math.ceil(1.5*1.03*sampleRate)+4));a(this,\\\"writeIdx\\\",0);a(this,\\\"tSlew\\\",-1);a(this,\\\"slewA\\\",1-Math.exp(-1/(.08*sampleRate)));a(this,\\\"phaseWow\\\",0);a(this,\\\"phaseFlut\\\",0);a(this,\\\"wowInc\\\",2*Math.PI*.85/sampleRate);a(this,\\\"rand\\\",E(2057179700));a(this,\\\"wander\\\",0);a(this,\\\"wanderTarget\\\",0);a(this,\\\"wanderCountdown\\\",0);a(this,\\\"damp\\\",0);a(this,\\\"dampD\\\",Math.exp(-2*Math.PI*6e3/sampleRate));a(this,\\\"dcX\\\",0);a(this,\\\"dcY\\\",0);a(this,\\\"dcR\\\",1-2*Math.PI*5/sampleRate)}static get parameterDescriptors(){return[{name:\\\"time\\\",defaultValue:.375,minValue:.05,maxValue:1.5,automationRate:\\\"k-rate\\\"},{name:\\\"feedback\\\",defaultValue:.5,minValue:0,maxValue:.95,automationRate:\\\"a-rate\\\"},{name:\\\"saturation\\\",defaultValue:.4,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"},{name:\\\"flutter\\\",defaultValue:.3,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"}]}process(t,S,u){const R=t[0]?.[0],p=S[0]?.[0];if(!p)return!0;const b=u.time,f=u.feedback,A=u.saturation,F=u.flutter,o=this.buf,l=o.length,V=this.dampD,g=this.dcR,T=b[0];this.tSlew<0&&(this.tSlew=T);const W=1+A[0]*4,x=F[0];this.wanderCountdown<=0&&(this.wanderTarget=this.rand()*2-1,this.wanderCountdown=Math.round(.5*sampleRate)),this.wanderCountdown-=p.length,this.wander+=.02*(this.wanderTarget-this.wander);const y=2*Math.PI*6.3*(1+.12*this.wander)/sampleRate;let m=this.tSlew,M=this.phaseWow,_=this.phaseFlut,n=this.damp,P=this.dcX,i=this.dcY,r=this.writeIdx;for(let h=0;h<p.length;h++){const C=R?R[h]:0,k=f.length>1?f[h]:f[0];m+=this.slewA*(T-m);let I=0;x>0&&(M+=this.wowInc,_+=y,I=x*(.008*Math.sin(M)+.0015*Math.sin(_)));let c=m*(1+I)*sampleRate;c<1?c=1:c>l-3&&(c=l-3);let w=r-c;w<0&&(w+=l);const d=w|0,D=w-d,X=d+1===l?0:d+1,H=o[d]+(o[X]-o[d])*D;n+=(1-V)*(H-n);const v=(Math.tanh(W*n)+Math.tanh(W*n*.3)*.1)/1.1;i=v-P+g*i,P=v,o[r]=C+k*i,p[h]=v,r++,r===l&&(r=0)}return Math.abs(n)<1e-20&&(n=0),Math.abs(i)<1e-20&&(i=0),this.tSlew=m,this.phaseWow=M,this.phaseFlut=_,this.damp=n,this.dcX=P,this.dcY=i,this.writeIdx=r,!0}}registerProcessor(\\\"tape-delay\\\",O);})();\\n\";\n", "export default \"(()=>{var O=Object.defineProperty;var w=(r,a,e)=>a in r?O(r,a,{enumerable:!0,configurable:!0,writable:!0,value:e}):r[a]=e;var t=(r,a,e)=>w(r,typeof a!=\\\"symbol\\\"?a+\\\"\\\":a,e);class S extends AudioWorkletProcessor{constructor(){super();t(this,\\\"bufL\\\");t(this,\\\"bufR\\\");t(this,\\\"bufLen\\\");t(this,\\\"writePos\\\",0);t(this,\\\"readPos\\\",0);t(this,\\\"speed\\\",1);t(this,\\\"decayFactor\\\",1);t(this,\\\"ramping\\\",!1);t(this,\\\"prevTrig\\\",0);t(this,\\\"stopped\\\",!1);this.bufLen=Math.ceil(sampleRate*4),this.bufL=new Float32Array(this.bufLen),this.bufR=new Float32Array(this.bufLen)}static get parameterDescriptors(){return[{name:\\\"time\\\",defaultValue:.5,minValue:.005,maxValue:4},{name:\\\"mix\\\",defaultValue:1,minValue:0,maxValue:1}]}toggle(e){this.stopped=!this.stopped;const o=Math.max(1,Math.round(e*sampleRate));this.stopped?this.decayFactor=Math.pow(.001/Math.max(this.speed,.001),1/o):this.decayFactor=Math.pow(.001,1/o),this.ramping=!0,this.port.postMessage({type:\\\"state\\\",phase:\\\"ramping\\\"})}process(e,o,g){const L=e[0]?.[0],P=e[0]?.[1],F=e[1]?.[0],c=o[0]?.[0],b=o[0]?.[1];if(!c)return!0;const R=!!b,f=g.time,l=g.mix,E=c.length;for(let i=0;i<E;i++){const v=f.length>1?f[i]:f[0],h=l.length>1?l[i]:l[0];if(F){const s=F[i];s>.5&&this.prevTrig<=.5&&this.toggle(v),this.prevTrig=s}const n=L?L[i]:0,d=P?P[i]:R?n:0;if(this.bufL[this.writePos]=n,this.bufR[this.writePos]=d,this.ramping)if(this.stopped)this.speed*=this.decayFactor,this.speed<=.001&&(this.speed=0,this.ramping=!1,this.port.postMessage({type:\\\"state\\\",phase:\\\"stopped\\\"}));else{const p=(1-this.speed)*this.decayFactor;this.speed=1-p,p<=.001&&(this.speed=1,this.ramping=!1,this.port.postMessage({type:\\\"state\\\",phase:\\\"playing\\\"}))}let u=0,m=0;if(this.speed>=1&&!this.ramping)u=n,m=d,this.readPos=this.writePos;else if(this.speed>0){this.readPos=(this.readPos+this.speed)%this.bufLen;const s=Math.floor(this.readPos),p=this.readPos-s,y=(s+1)%this.bufLen;u=this.bufL[s]+p*(this.bufL[y]-this.bufL[s]),m=this.bufR[s]+p*(this.bufR[y]-this.bufR[s])}this.writePos=(this.writePos+1)%this.bufLen,c[i]=n*(1-h)+u*h,R&&(b[i]=d*(1-h)+m*h)}return!0}}registerProcessor(\\\"tape-stop\\\",S);})();\\n\";\n", "export default \"(()=>{class v extends AudioWorkletProcessor{static get parameterDescriptors(){return[{name:\\\"gain\\\",defaultValue:.5,minValue:0,maxValue:2,automationRate:\\\"a-rate\\\"},{name:\\\"cvAmount\\\",defaultValue:1,minValue:-1,maxValue:1,automationRate:\\\"a-rate\\\"},{name:\\\"cv\\\",defaultValue:0,minValue:-1e3,maxValue:1e3,automationRate:\\\"a-rate\\\"}]}process(i,m,o){const l=i[0],e=m[0];if(!e)return!0;const s=o.gain,c=o.cvAmount,r=o.cv,f=e.length,g=e[0]?.length??0;for(let t=0;t<g;t++){const V=s.length>1?s[t]:s[0],h=c.length>1?c[t]:c[0],d=r.length>1?r[t]:r[0];let a=V+h*d;a<0?a=0:a>2&&(a=2);for(let n=0;n<f;n++){const u=l?.[n]??l?.[0];e[n][t]=(u?u[t]:0)*a}}return!0}}registerProcessor(\\\"vca\\\",v);})();\\n\";\n", "export default \"(()=>{var J=Object.defineProperty;var X=(g,w,t)=>w in g?J(g,w,{enumerable:!0,configurable:!0,writable:!0,value:t}):g[w]=t;var r=(g,w,t)=>X(g,typeof w!=\\\"symbol\\\"?w+\\\"\\\":w,t);const F=new Float32Array([.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.109,.263,.453,.612,.701,.744,.773,.142,.333,.556,.731,.827,.873,.903,.188,.387,.59,.74,.821,.857,.882,.207,.422,.622,.756,.824,.855,.872,.217,.442,.642,.767,.827,.851,.868,.222,.452,.653,.774,.828,.852,.865,.224,.455,.657,.776,.829,.85,.862,.222,.452,.653,.774,.828,.852,.865,.217,.442,.642,.767,.827,.851,.868,.207,.422,.622,.756,.824,.855,.872,.187,.387,.59,.74,.821,.857,.882,.142,.333,.556,.731,.827,.873,.903,.152,.36,.61,.816,.935,.994,1.034,.27,.488,.689,.838,.924,.965,.994,.352,.592,.765,.874,.931,.958,.975,.401,.661,.819,.901,.939,.954,.966,.428,.7,.85,.917,.943,.954,.96,.437,.712,.861,.922,.945,.953,.957,.428,.7,.85,.917,.943,.954,.96,.401,.661,.819,.901,.939,.954,.966,.352,.592,.765,.874,.931,.958,.975,.27,.488,.689,.838,.924,.964,.995,.152,.36,.61,.816,.935,.994,1.034,.154,.369,.638,.876,1.028,1.108,1.165,.333,.551,.752,.912,1.012,1.063,1.103,.502,.721,.867,.967,1.025,1.053,1.074,.636,.849,.953,1.008,1.037,1.05,1.06,.724,.929,1.004,1.033,1.045,1.05,1.053,.754,.956,1.021,1.042,1.048,1.05,1.049,.724,.929,1.004,1.033,1.045,1.05,1.053,.636,.849,.953,1.008,1.037,1.05,1.06,.502,.721,.867,.967,1.025,1.053,1.073,.333,.551,.752,.912,1.012,1.063,1.103,.154,.369,.638,.876,1.028,1.108,1.165,.154,.372,.655,.923,1.11,1.216,1.296,.367,.586,.793,.969,1.09,1.154,1.208,.582,.79,.933,1.039,1.108,1.142,1.169,.77,.947,1.037,1.092,1.125,1.14,1.151,.901,1.047,1.1,1.124,1.135,1.14,1.144,.948,1.082,1.122,1.135,1.139,1.14,1.138,.901,1.047,1.1,1.124,1.135,1.14,1.144,.77,.947,1.037,1.092,1.125,1.14,1.151,.582,.79,.933,1.039,1.108,1.142,1.169,.367,.586,.793,.969,1.09,1.154,1.208,.154,.372,.655,.923,1.11,1.216,1.296,.154,.374,.668,.962,1.185,1.32,1.427,.377,.604,.821,1.016,1.159,1.24,1.31,.585,.811,.973,1.097,1.183,1.226,1.261,.753,.965,1.083,1.157,1.203,1.224,1.24,.862,1.061,1.15,1.194,1.216,1.225,1.232,.899,1.094,1.172,1.207,1.22,1.225,1.224,.862,1.061,1.15,1.194,1.216,1.225,1.232,.753,.965,1.083,1.157,1.203,1.224,1.24,.585,.811,.973,1.097,1.183,1.226,1.261,.377,.604,.821,1.016,1.159,1.24,1.31,.154,.374,.668,.962,1.185,1.32,1.427,.154,.372,.657,.934,1.137,1.257,1.35,.373,.594,.802,.985,1.116,1.188,1.249,.592,.801,.948,1.06,1.137,1.175,1.206,.781,.96,1.056,1.117,1.155,1.173,1.186,.911,1.06,1.121,1.152,1.167,1.173,1.178,.957,1.095,1.143,1.163,1.171,1.173,1.172,.911,1.06,1.121,1.152,1.167,1.173,1.178,.781,.96,1.056,1.117,1.155,1.173,1.186,.592,.801,.948,1.06,1.137,1.175,1.206,.373,.594,.802,.985,1.116,1.188,1.249,.154,.372,.657,.934,1.137,1.257,1.35,.154,.37,.647,.907,1.093,1.199,1.28,.367,.582,.784,.955,1.074,1.14,1.194,.592,.786,.922,1.025,1.093,1.128,1.155,.798,.946,1.026,1.077,1.11,1.125,1.137,.947,1.049,1.089,1.11,1.121,1.125,1.129,1.003,1.085,1.11,1.121,1.124,1.125,1.124,.947,1.049,1.089,1.11,1.121,1.125,1.129,.798,.946,1.026,1.077,1.11,1.125,1.137,.592,.786,.922,1.025,1.093,1.128,1.155,.367,.582,.784,.955,1.074,1.14,1.194,.154,.37,.647,.907,1.093,1.199,1.28,.153,.367,.636,.882,1.051,1.146,1.217,.358,.569,.764,.926,1.035,1.094,1.142,.583,.767,.896,.99,1.052,1.083,1.107,.799,.925,.994,1.039,1.067,1.081,1.091,.964,1.028,1.055,1.069,1.077,1.081,1.083,1.028,1.064,1.075,1.079,1.08,1.081,1.08,.964,1.028,1.055,1.069,1.077,1.081,1.084,.799,.925,.994,1.039,1.067,1.081,1.091,.583,.767,.896,.99,1.052,1.083,1.107,.358,.569,.764,.926,1.035,1.095,1.142,.153,.367,.636,.882,1.051,1.146,1.217,.153,.365,.625,.857,1.011,1.096,1.16,.348,.556,.745,.898,.999,1.052,1.095,.567,.746,.868,.957,1.014,1.042,1.064,.785,.899,.961,1.002,1.027,1.039,1.048,.958,1,1.018,1.029,1.036,1.039,1.041,1.027,1.035,1.038,1.039,1.039,1.039,1.038,.958,1,1.018,1.029,1.036,1.039,1.041,.785,.899,.961,1.002,1.027,1.039,1.048,.567,.746,.868,.957,1.014,1.042,1.064,.348,.556,.745,.898,.999,1.052,1.095,.153,.365,.625,.857,1.011,1.096,1.16,.153,.362,.615,.833,.975,1.051,1.107,.336,.541,.726,.871,.964,1.013,1.051,.546,.722,.841,.925,.977,1.003,1.023,.758,.869,.928,.966,.989,1.001,1.009,.931,.966,.982,.991,.997,1,1.002,1,1,1,1,1,1,1,.931,.966,.982,.991,.997,1,1.002,.758,.869,.928,.966,.989,1.001,1.009,.546,.722,.841,.925,.977,1.003,1.023,.336,.541,.726,.871,.964,1.013,1.051,.153,.362,.615,.833,.975,1.051,1.107]),K=11,D=11,T=7;const N=[5.7814,6.7814,7.7814,8.7814,9.7814,10.7814,11.7814],e=class e extends AudioWorkletProcessor{constructor(){super(...arguments);r(this,\\\"phase\\\",0);r(this,\\\"normGain\\\",1);r(this,\\\"normTarget\\\",1);r(this,\\\"osW1\\\",0);r(this,\\\"osW2\\\",0);r(this,\\\"stepPos\\\",new Float64Array(3));r(this,\\\"stepAmp\\\",new Float64Array(3));r(this,\\\"nSteps\\\",0)}static get parameterDescriptors(){return[{name:\\\"skew\\\",defaultValue:0,minValue:-34e37,maxValue:34e37,automationRate:\\\"a-rate\\\"},{name:\\\"shape\\\",defaultValue:0,minValue:-34e37,maxValue:34e37,automationRate:\\\"a-rate\\\"},{name:\\\"normalize\\\",defaultValue:0,minValue:0,maxValue:1,automationRate:\\\"k-rate\\\"}]}static awBilinear(t,o,n,a,i,s){const h=(y,c)=>(y*D+c)*T+i,u=h(t,n),A=h(t+1,n),S=h(t,n+1),E=h(t+1,n+1),f=F[u]*(1-s)+F[u+1]*s,b=F[A]*(1-s)+F[A+1]*s,m=F[S]*(1-s)+F[S+1]*s,d=F[E]*(1-s)+F[E+1]*s,l=f*(1-a)+m*a,p=b*(1-a)+d*a;return l*(1-o)+p*o}static awGainLookup(t,o,n){const a=Math.min(Math.max(t,0),1)*(K-1),i=Math.min(Math.max(o,0),1)*(D-1),h=(Math.log2(Math.max(n,20))-N[0])/(N[T-1]-N[0]),u=Math.min(Math.max(h*(T-1),0),T-1),A=Math.min(Math.floor(a),K-2),S=a-A,E=Math.min(Math.floor(i),D-2),f=i-E,b=Math.min(Math.floor(u),T-2),m=u-b,d=e.awBilinear(A,S,E,f,b,m),l=e.awBilinear(A,S,E,f,e.AW_REF_FI,0);return l<=1e-6?d:l*Math.pow(d/l,e.AW_TILT)}static shapeMap(t,o,n,a){let i;if(o<=.5){const s=Math.abs(t);i=(t>=0?1:-1)*Math.pow(s,n)}else{const s=(o-.5)*2,h=Math.sin(t*Math.PI*.5);i=t+(h-t)*s}return a>0&&(i=(1-a)*i+a*(t>=0?1:-1)),i}static blep(t){if(t>=0){if(t>=1)return 0;const n=t-1;return-.5*n*n}if(t<=-1)return 0;const o=t+1;return .5*o*o}static eval(t,o,n){const a=Math.min(Math.max(o,.001),.999);let i;t<a?i=t/a:i=1-(t-a)/(1-a);const s=2*i-1;if(n<=.5){const h=Math.max(n*2,.05),u=Math.abs(s);return(s>=0?1:-1)*Math.pow(u,h)}else{const h=(n-.5)*2,u=Math.sin(s*Math.PI*.5);return s+(u-s)*h}}cornerSample(t,o,n,a,i,s,h,u){let A;t<o?A=t/o:A=1-(t-o)/(1-o);let S=2*A-1;n>0&&(S=(1-n)*S+n*(a?2*t-1:1-2*t));let E=e.shapeMap(S,i,s,h);const f=u>=0?1:-1;for(let b=0;b<this.nSteps;b++){let m=t-this.stepPos[b];m-=Math.round(m);const d=m/u;d>-1&&d<1&&(E+=f*this.stepAmp[b]*e.blep(d))}return E}process(t,o,n){const a=t[0]?.[0],i=o[0]?.[0];if(!i)return!0;const s=n.skew,h=n.shape,u=n.normalize[0]>.5,A=1/sampleRate,S=e.SMOOTH_COEFF,E=e.UPDATE_INTERVAL,f=e.SKEW_EDGE,b=e.SHAPE_EDGE;for(let m=0;m<i.length;m++){const d=a&&a.length>m?a[m]:440;let l=s.length>1?s[m]:s[0],p=h.length>1?h[m]:h[0];l=(l+1)*.5,p=(p+1)*.5,l=1-Math.abs((l%2+2)%2-1),p=1-Math.abs((p%2+2)%2-1);const y=d*A*.5;let c=0,W=!1;l<f?c=1-l/f:l>1-f&&(c=1-(1-l)/f,W=!0);let v=0,R=1;if(p<=.5){const M=p*2;R=M>b?M:b,M<b&&(v=1-M/b)}let B,I;if(v===0&&c===0)this.phase+=y,this.phase>=1&&(this.phase-=1),this.phase<0&&(this.phase+=1),B=e.eval(this.phase,l,p),this.phase+=y,this.phase>=1&&(this.phase-=1),this.phase<0&&(this.phase+=1),I=e.eval(this.phase,l,p);else{const M=Math.min(Math.max(l,f),1-f),q=W?-1:1,C=W?2*M-1:1-2*M,j=W?1:-1,G=c>0?(1-c)*-1+c*q:-1,O=c>0?(1-c)*1+c*C:1,x=c>0?(1-c)*-1+c*j:-1;if(this.nSteps=0,c>0){const z=e.shapeMap(G,p,R,v)-e.shapeMap(x,p,R,v);z!==0&&(this.stepPos[this.nSteps]=0,this.stepAmp[this.nSteps++]=z)}v>0&&(G<0!=O<0&&(this.stepPos[this.nSteps]=M*(0-G)/(O-G),this.stepAmp[this.nSteps++]=O>G?2*v:-2*v),O<0!=x<0&&(this.stepPos[this.nSteps]=M+(1-M)*(0-O)/(x-O),this.stepAmp[this.nSteps++]=x>O?2*v:-2*v)),this.phase+=y,this.phase>=1&&(this.phase-=1),this.phase<0&&(this.phase+=1),B=this.cornerSample(this.phase,M,c,W,p,R,v,y),this.phase+=y,this.phase>=1&&(this.phase-=1),this.phase<0&&(this.phase+=1),I=this.cornerSample(this.phase,M,c,W,p,R,v,y)}const{OS_B0:P,OS_B1:Q,OS_B2:U,OS_A1:L,OS_A2:_}=e;let V=B-L*this.osW1-_*this.osW2;this.osW2=this.osW1,this.osW1=V,V=I-L*this.osW1-_*this.osW2;let H=P*V+Q*this.osW1+U*this.osW2;this.osW2=this.osW1,this.osW1=V,u&&((m&E-1)===0&&(this.normTarget=e.awGainLookup(p,l,d)),this.normGain+=S*(this.normTarget-this.normGain),H*=this.normGain),i[m]=H}return!0}};r(e,\\\"OS_B0\\\",.20657),r(e,\\\"OS_B1\\\",.41314),r(e,\\\"OS_B2\\\",.20657),r(e,\\\"OS_A1\\\",-.36953),r(e,\\\"OS_A2\\\",.19582),r(e,\\\"UPDATE_INTERVAL\\\",32),r(e,\\\"SMOOTH_COEFF\\\",1-Math.pow(.05,1/32)),r(e,\\\"AW_TILT\\\",.35),r(e,\\\"AW_REF_FI\\\",2),r(e,\\\"SKEW_EDGE\\\",.01),r(e,\\\"SHAPE_EDGE\\\",.05);let k=e;registerProcessor(\\\"waveshaper\\\",k);})();\\n\";\n"],
5
+ "mappings": ";AAAA,IAAO,wBAAQ;;;ACAf,IAAO,qBAAQ;;;ACAf,IAAO,sBAAQ;;;ACAf,IAAO,uBAAQ;;;ACAf,IAAO,qBAAQ;;;ACAf,IAAO,kBAAQ;;;ACAf,IAAO,wBAAQ;;;ACAf,IAAO,uBAAQ;;;ACAf,IAAO,uBAAQ;;;ACAf,IAAO,gBAAQ;;;ACAf,IAAO,wBAAQ;;;ACAf,IAAO,kBAAQ;;;ACAf,IAAO,2BAAQ;;;ACAf,IAAO,6BAAQ;;;ACAf,IAAO,oBAAQ;;;ACAf,IAAO,wBAAQ;;;ACAf,IAAO,wBAAQ;;;ACAf,IAAO,qBAAQ;;;ACAf,IAAO,oBAAQ;;;ACAf,IAAO,cAAQ;;;ACAf,IAAO,qBAAQ;",
6
+ "names": []
7
+ }
package/docs/GUIDE.md CHANGED
@@ -15,7 +15,7 @@ import { preload, Vco, Lfo, Vcf, semitones, hz, note } from '@jpdutoit/squelchy'
15
15
  const ctx = new AudioContext();
16
16
  await preload(ctx); // once per context, before any create()
17
17
 
18
- const vco = Vco.create(ctx, { offset: semitones(45) }); // unpatched, offset is the note: 45 = A2
18
+ const vco = Vco.create(ctx, { offset: semitones(45) }); // nothing in voct = note 0 (C-1); 45 semitones up = A2
19
19
  const lfo = Lfo.create(ctx, { frequency: hz(0.2), amount: semitones(18) });
20
20
  const filter = Vcf.create(ctx, { note: note('C6'), resonance: 4 });
21
21
 
@@ -27,6 +27,8 @@ filter.out.connect(ctx.destination);
27
27
  lfo.output('out').connect(filter.input('modFreq'));
28
28
  ```
29
29
 
30
+ **Pitch is V/OCT plus `offset`.** A VCO plays the note on its `voct` input plus `offset` semitones, and it has no hidden "note" setting: Web Audio inputs can only add, so nothing can switch off when a cable arrives. With `voct` empty, the input is note 0 (C-1), so `offset` counts up from there: `semitones(69)` plays A4. To write the note by name, measure from note 0: `interval(note(0), note('A4'))`. With a sequencer or keyboard in `voct`, set `offset` to 0 to play the notes as written, or ±12 for an octave.
31
+
30
32
  ### Changing parameters: `set()` vs `params`
31
33
 
32
34
  - **`params.<key>`** is a native `AudioParam` for every parameter that drives the DSP 1:1. Use it for anything timed: ramps, curves and `setValueAtTime`.
@@ -49,6 +51,21 @@ filter.params.resonance;
49
51
  filter.dispose(); // disconnect and release when you're done
50
52
  ```
51
53
 
54
+ **Ramping pitch and cutoff.** Pitch and cutoff parameters are notes or semitones (a VCO's `offset`, filter cutoffs), so they are already logarithmic: every 12 is an octave. A `linearRampToValueAtTime` between two values sweeps evenly in pitch, which is usually what you want. `exponentialRampToValueAtTime` is the Hz habit: on a note parameter it curves the sweep a second time, so it crawls through the low end and rushes the top.
55
+
56
+ ```ts
57
+ import { preload, Vcf, note } from '@jpdutoit/squelchy';
58
+
59
+ const ctx = new AudioContext();
60
+ await preload(ctx);
61
+ const filter = Vcf.create(ctx, { filterType: 'bandpass', note: note('C4') });
62
+ const t = ctx.currentTime;
63
+
64
+ // A riser: 5 octaves, evenly in pitch over 4 seconds.
65
+ filter.params.note.setValueAtTime(note('C4'), t);
66
+ filter.params.note.linearRampToValueAtTime(note('C9'), t + 4);
67
+ ```
68
+
52
69
  ## Units
53
70
 
54
71
  Notes, semitones, Hz, seconds and beats are distinct types, so passing seconds where a note is expected won't compile. At runtime they are plain numbers with zero overhead. Dimensionless values (mix, feedback, drive) are plain `number`.
@@ -103,7 +120,7 @@ playOn(asPitch(lfo.out)); // deliberate: you said so
103
120
 
104
121
  Musical positions are plain numbers in **beats** (quarter notes): bar 2 of a 4/4 song starts at beat 4, and a 16th note is 0.25. Audio times are `ctx.currentTime` seconds, as everywhere in Web Audio. Events are written ahead of time with exact start times, so timing doesn't depend on the main thread.
105
122
 
106
- Bars and beats count from 0, as on a timeline: `{ bar: 0 }` is the first bar and `{ bar: 1 }` starts at beat 4.
123
+ Bars and beats count from 0, as on a timeline: `{ bar: 0 }` is the first bar, `{ bar: 1 }` starts at beat 4, and `{ bar: 1, beat: beats(2) }` is the third beat of the second bar (beat 6).
107
124
 
108
125
  A **pattern** is a plain array, one element per step. A **voice** is anything with `trigger(time, hit)`, or a plain function `(time, hit) => void`.
109
126
 
@@ -122,7 +139,7 @@ transport.play(steps('..x. ..x. ..x. ..x.'), hat, {
122
139
  every: beats(0.25), // step length in beats (default: 16ths)
123
140
  swing: 0.3, // 0..1, delays every odd step
124
141
  gate: 0.5, // note length as a fraction of a step
125
- start: 'bar', // 'now' | 'beat' | 'bar' | { bar: n } | { beat: n }; default 'bar'
142
+ start: 'bar', // 'now' | 'beat' | 'bar' | { bar: n } | { bar: n, beat: n } | { beat: n }; default 'bar'
126
143
  loop: true, // true = forever, false = once, n = n times
127
144
  });
128
145
  transport.start();
@@ -130,9 +147,26 @@ transport.start();
130
147
 
131
148
  ### Pattern steps
132
149
 
133
- - **Hits:** any value. `true` from `steps()`, a `Note` from `notes()`, or whatever your voice understands.
134
- - **Rests:** `null`, `undefined`, `false`, `0`, `'.'` and `'-'`.
135
- - **Per-step velocity and length:** `{ value, velocity, length }`, where `length` is in steps.
150
+ - **Hits:** any other value, `0` included. A `Note` from `notes()`, `true`, or whatever your voice understands.
151
+ - **Rests:** `null`, `undefined` (and array holes like `[60, , 64]`) and `false`. Inside the `steps()` and `notes()` strings, `'.'` and `'-'` become rests.
152
+ - **Per-step velocity and length:** `{ value, velocity, length }`, where `length` is in steps. Velocity defaults to 1.
153
+
154
+ A step's value means whatever the voice makes of it. Drums ignore it, and `NoteCv` and `SampleVoice` play it as a note. Loudness is always `velocity`, never the value, so `[1, 0, 0, 1]` is four equal hits, not a drum grid.
155
+
156
+ **Drum grids with accents.** In `steps()`, `X` is an accent, `x` a normal hit and `o` a ghost note. All three are velocities: 1, 0.75 and 0.4 by default, and you can change them. Any other character throws, so a typo can't quietly become a rest.
157
+
158
+ ```ts
159
+ import { createTransport, steps, Snare } from '@jpdutoit/squelchy';
160
+
161
+ const ctx = new AudioContext();
162
+ const transport = createTransport(ctx);
163
+ const snare = Snare.create(ctx);
164
+ snare.connect(ctx.destination);
165
+
166
+ transport.play(steps('....X..o .o..X..o'), snare); // backbeat with ghost notes
167
+ transport.play(steps('x.x.x.x.', { normal: 0.5, accent: 1, ghost: 0.2 }), snare); // your own levels
168
+ transport.start();
169
+ ```
136
170
 
137
171
  ```ts
138
172
  import { createTransport, notes, note, beats, NoteCv, type Step, type Note } from '@jpdutoit/squelchy';
@@ -197,6 +231,8 @@ transport.stop(); // stop everything
197
231
 
198
232
  `transport.at(position, fn)` calls `fn(time)` just ahead of that musical position, with its exact audio time, so you can schedule any `AudioParam` in musical time. It returns a cancel function.
199
233
 
234
+ `fn` runs a lookahead early, so it's the wrong place for UI. Pass `onAudible` for that: it fires when the position is actually heard, output latency included, just like `onHit`. Cancelling cancels both.
235
+
200
236
  ```ts
201
237
  import { createTransport, preload, Vcf, note, sec } from '@jpdutoit/squelchy';
202
238
 
@@ -208,11 +244,12 @@ filter.out.connect(ctx.destination);
208
244
 
209
245
  const bar = sec((transport.beatsPerBar * 60) / transport.bpm);
210
246
 
211
- // Open the filter over two bars, starting at bar 3.
247
+ // Open the filter over two bars, starting at bar 3; tell the UI when the sweep is heard.
248
+ const showDrop = () => { /* update the screen */ };
212
249
  const cancel = transport.at({ bar: 2 }, (t) => {
213
250
  filter.params.note.setValueAtTime(note('C4'), t);
214
251
  filter.params.note.linearRampToValueAtTime(note('C7'), t + 2 * bar);
215
- });
252
+ }, { onAudible: showDrop });
216
253
  transport.start();
217
254
  // cancel(); // if you change your mind before it fires
218
255
  ```
@@ -232,6 +269,7 @@ const highlight = (step: number) => { /* light up step `step` */ };
232
269
 
233
270
  transport.play(steps('x...x...'), kick, { onHit: (hit) => highlight(hit.step) }); // one playback
234
271
  const unsubscribe = transport.onHit((hit) => console.log(hit.beat, hit.value)); // every playback
272
+ transport.at({ bar: 8 }, () => {}, { onAudible: () => highlight(-1) }); // a moment, not a hit
235
273
  transport.start();
236
274
  ```
237
275
 
@@ -262,10 +300,29 @@ transport.play(notes('C2 C2 . C3 . C2 Eb2 . G2 . C2 . Bb1 . C2 .'), cv, { gate:
262
300
  transport.start();
263
301
  ```
264
302
 
303
+ To change the notes on their way to the voice, wrap it in a function. `transpose()` keeps the result typed as a note:
304
+
305
+ ```ts
306
+ import { createTransport, notes, transpose, semitones, NoteCv, type Hit, type Note, type Seconds } from '@jpdutoit/squelchy';
307
+
308
+ const ctx = new AudioContext();
309
+ const transport = createTransport(ctx);
310
+ const cv = NoteCv.create(ctx);
311
+
312
+ let key = semitones(0);
313
+ const inKey = (time: Seconds, hit: Hit<Note>) => cv.trigger(time, { ...hit, value: transpose(hit.value, key) });
314
+ transport.play(notes('C2 . Eb2 G2'), inKey);
315
+ key = semitones(5); // later hits play a fourth up
316
+ ```
317
+
265
318
  ## One-shot actions with `pulse()`
266
319
 
267
320
  Actions like a tape stop or kicking the spring tank are **gate inputs**. They react to a rising edge, like a trigger cable on hardware. `pulse(input, time)` fires one at an exact time. It works the same whether it's called from a button, a pattern or `transport.at`, and it sums with anything else patched into that input.
268
321
 
322
+ **Timing.** A pulse lands exactly on the time you give it, as long as that time is still ahead when the call runs. Schedule timed actions ahead: `transport.at` and `transport.play` do this for you, a lookahead before the beat. A time that has already passed fires as soon as possible, so it's late. It's never dropped.
323
+
324
+ `pulse(input)` with no time is for buttons: it fires as soon as possible. A busy page can make it a few milliseconds late, but the press always registers. To land a button press on the beat, hand it to the transport so it fires on the next beat (or bar):
325
+
269
326
  ```ts
270
327
  import { preload, createTransport, steps, pulse, sec, TapeStop, SpringReverb, Kick } from '@jpdutoit/squelchy';
271
328
 
@@ -287,6 +344,8 @@ transport.at({ bar: 5 }, (t) => pulse(tape.trigger, t)); // …and back up a bar
287
344
 
288
345
  // From a button, right now:
289
346
  const onClick = () => pulse(tape.trigger);
347
+ // From a button, on the next beat ('bar' for the next bar line):
348
+ const onClickInTime = () => transport.at('beat', (t) => pulse(tape.trigger, t));
290
349
  transport.start();
291
350
  ```
292
351
 
@@ -309,7 +368,7 @@ Every kit is CC0 or public domain, and each one carries its own `license`. Each
309
368
  | `import { DeepAnalogue } from '@jpdutoit/squelchy/kits/deep-analogue'` | Deep Analogue | Acoustic | bd sd rim clap ch oh lt mt ht cym perc |
310
369
 
311
370
  ```ts
312
- import { createTransport, steps, loadSampleSet, SampleVoice, VOICE_KEYS } from '@jpdutoit/squelchy';
371
+ import { createTransport, steps, notes, note, loadSampleSet, SampleVoice, VOICE_KEYS } from '@jpdutoit/squelchy';
313
372
  import { Tr909 } from '@jpdutoit/squelchy/kits/tr-909';
314
373
 
315
374
  const ctx = new AudioContext();
@@ -319,17 +378,36 @@ const kit = await loadSampleSet(ctx, Tr909);
319
378
  console.log(VOICE_KEYS.filter((k) => !kit.buffers[k])); // voices this kit covers by fallback
320
379
 
321
380
  const bd = SampleVoice.create(ctx, kit, 'bd');
322
- const tom = SampleVoice.create(ctx, kit, 'lt');
381
+ const tom = SampleVoice.create(ctx, kit, 'lt', { root: note('C4') }); // C4 plays the sample as recorded (the default)
323
382
  bd.connect(ctx.destination);
324
383
  tom.connect(ctx.destination);
325
384
 
326
385
  const transport = createTransport(ctx);
327
386
  transport.play(steps('x...x...x...x...'), bd);
328
- transport.play([true, null, 3, null, 7, 12, null, null], tom); // numbers repitch in semitones
387
+ transport.play(notes('C4 . Eb4 . G4 C5 . .'), tom); // tom melody: notes, like NoteCv
329
388
  transport.start();
330
389
  ```
331
390
 
332
- A step value of `0` is a rest, so use `true` for an unshifted hit.
391
+ A sample voice is one-shot, like a drum machine: every hit plays the whole sample, whatever the step's gate length. Its step value is a note, so the same `notes()` melody plays on a sampler and on a synth voice.
392
+
393
+ **Swapping kits while playing.** `voice.setKit(kit)` plays later hits from another kit. Patterns, connections and sidechains stay as they are, and samples already ringing (or scheduled within the lookahead) finish on the old kit, so nothing gets cut off.
394
+
395
+ ```ts
396
+ import { createTransport, steps, loadSampleSet, SampleVoice } from '@jpdutoit/squelchy';
397
+ import { Tr909 } from '@jpdutoit/squelchy/kits/tr-909';
398
+ import { Roland808 } from '@jpdutoit/squelchy/kits/roland-808';
399
+
400
+ const ctx = new AudioContext();
401
+ const transport = createTransport(ctx);
402
+ const bd = SampleVoice.create(ctx, await loadSampleSet(ctx, Tr909), 'bd');
403
+ bd.connect(ctx.destination);
404
+ transport.play(steps('x...x...x...x...'), bd);
405
+ transport.start();
406
+
407
+ const tr808 = await loadSampleSet(ctx, Roland808);
408
+ bd.setKit(tr808); // hits scheduled from now on (about a lookahead ahead) play the 808
409
+ console.log(bd.kit.set.name);
410
+ ```
333
411
 
334
412
  **How the audio gets into your build.** A kit's voice URLs are written as `new URL('./tr-909/bd.flac', import.meta.url)`. Vite (8.3 or newer, in dev and build), webpack 5 and Parcel all recognise that pattern: they copy each file of the kits you import into your output with a content hash and rewrite the URL. Loading the package unbundled, e.g. from a CDN like jsDelivr, resolves the files next to the kit module.
335
413
 
package/docs/MODULES.md CHANGED
@@ -79,7 +79,7 @@ Categories: Filters · Worklets: adsr-envelope, map-voct-to-freq
79
79
  | `resonance` | `8` | 0 – 15 (sqrt) | **Resonance** — Resonance amount, 0–100% of travel. Creates the characteristic 303 "wow" at high settings. Like the hardware, there is no resonance CV input — the knob is the only control. `set()` only. |
80
80
  | `envMod` | `0.7` | 0 – 1 | **Envelope Mod** — How much the triggered envelope sweeps the filter cutoff. `set()` only. |
81
81
  | `accent` | `0.5` | 0 – 1 | **Accent** — Intensifies the envelope sweep for more aggressive acid sounds. `set()` only. |
82
- | `decay` | `0.2` | 0.05 – 1 s (log) | **Decay Time** — How quickly the filter envelope falls. Short = plucky, long = sustained. Automatable: `params.decay` is a native AudioParam. |
82
+ | `decay` | `0.92` | 0.2 – 5 s (log) | **Decay Time** — Time for the exponential filter sweep to fall 60 dB after each trigger. Short = plucky squelch, long = slow, singing sweeps. Automatable: `params.decay` is a native AudioParam. |
83
83
 
84
84
  ## PAN
85
85
 
@@ -929,7 +929,7 @@ Categories: Time · Worklets: pitch-shifter, fdn-reverb
929
929
  | `decay` | `3` | 0.5 – 10 s (log) | **Reverb Decay** — RT60 of the reverb tank in seconds — the time to fall 60 dB, measured at 500 Hz. Treble dies faster, like a real hall. `set()` only. |
930
930
  | `pitch` | `12` | -12 – 24 semitones | **Pitch Shift** — Transposition applied by the granular pitch shifter on every trip round the feedback loop (12 = one octave). +12 = octave up, +7 = fifth up, -12 = octave down. `set()` only. |
931
931
  | `mix` | `0.5` | 0 – 1 | **Dry/Wet Mix** — Equal-power balance between dry signal and shimmer output — independent of the regen amount. Automatable: `params.mix` is a native AudioParam. |
932
- | `shimmer` | `0.5` | 0 – 0.95 | **Shimmer Regen** — Gain once round the pitch-shifted feedback loop, measured at 500 Hz: 0.5 = each new octave 6 dB quieter than the last, 0.95 = an almost endless rising choir. Means the same at every DECAY setting. Automatable: `params.shimmer` is a native AudioParam. |
932
+ | `shimmer` | `0.5` | 0 – 0.95 | **Shimmer Regen** — Gain once round the pitch-shifted feedback loop, measured at 500 Hz: 0.5 = each new octave 6 dB quieter than the last, 0.95 = an almost endless rising choir. Means the same at every DECAY setting. At PITCH 0 the loop is plain reverb feedback and the regen is held under its self-oscillation edge, so 0.95 is a near-frozen, slowly breathing tail that always dies away. Automatable: `params.shimmer` is a native AudioParam. |
933
933
 
934
934
  ## LIMIT
935
935
 
@@ -1190,7 +1190,7 @@ Categories: Sources · Worklets: map-voct-to-freq, waveshaper
1190
1190
  |---|---|---|---|
1191
1191
  | `skew` | `1` | -1 – 1 | **Waveshape Skew** — Symmetry of the waveform: −1 reversed sawtooth, 0 symmetric, +1 sawtooth. Automatable: `params.skew` is a native AudioParam. |
1192
1192
  | `shape` | `0` | -1 – 1 | **Waveshape Curvature** — Curvature of the waveform: −1 square, 0 triangle, +1 sine. Automatable: `params.shape` is a native AudioParam. |
1193
- | `offset` | `69` | -48 – 108 semitones | **Pitch Offset** — Semitones added to the V/OCT input (12 = one octave). Unpatched the input is silent, so this is the note itself: 69 = A4. Driven by an absolute pitch CV (keyboard, sequencer), set 0 to play as-is or ±12 to shift an octave. Automatable: `params.offset` is a native AudioParam. |
1193
+ | `offset` | `69` | -48 – 108 semitones | **Pitch Offset** — Semitones added to the V/OCT input (12 = one octave). Unpatched, the input is silent (note 0, C−1), so the offset counts up from there: 69 semitones above C−1 = A4. Driven by an absolute pitch CV (keyboard, sequencer), set 0 to play as-is or ±12 to shift an octave. Automatable: `params.offset` is a native AudioParam. |
1194
1194
  | `detune` | `0` | -1 – 1 semitones | **Detune** — Fine pitch offset in semitones; ±1 = ±100 cents. Use for detuning oscillators against each other. Automatable: `params.detune` is a native AudioParam. |
1195
1195
  | `gain` | `0.5` | 0 – 1 | **Output Level** — Amplitude of the oscillator output signal. Automatable: `params.gain` is a native AudioParam. |
1196
1196
 
package/docs/modules.json CHANGED
@@ -80,12 +80,12 @@
80
80
  },
81
81
  "decay": {
82
82
  "name": "Decay Time",
83
- "description": "How quickly the filter envelope falls. Short = plucky, long = sustained.",
83
+ "description": "Time for the exponential filter sweep to fall 60 dB after each trigger. Short = plucky squelch, long = slow, singing sweeps.",
84
84
  "type": "Seconds",
85
85
  "unit": "s",
86
- "default": 0.2,
87
- "min": 0.05,
88
- "max": 1,
86
+ "default": 0.92,
87
+ "min": 0.2,
88
+ "max": 5,
89
89
  "scale": "log",
90
90
  "automatable": true
91
91
  }
@@ -2470,7 +2470,7 @@
2470
2470
  },
2471
2471
  "shimmer": {
2472
2472
  "name": "Shimmer Regen",
2473
- "description": "Gain once round the pitch-shifted feedback loop, measured at 500 Hz: 0.5 = each new octave 6 dB quieter than the last, 0.95 = an almost endless rising choir. Means the same at every DECAY setting.",
2473
+ "description": "Gain once round the pitch-shifted feedback loop, measured at 500 Hz: 0.5 = each new octave 6 dB quieter than the last, 0.95 = an almost endless rising choir. Means the same at every DECAY setting. At PITCH 0 the loop is plain reverb feedback and the regen is held under its self-oscillation edge, so 0.95 is a near-frozen, slowly breathing tail that always dies away.",
2474
2474
  "type": "number",
2475
2475
  "unit": "factor",
2476
2476
  "default": 0.5,
@@ -3164,7 +3164,7 @@
3164
3164
  },
3165
3165
  "offset": {
3166
3166
  "name": "Pitch Offset",
3167
- "description": "Semitones added to the V/OCT input (12 = one octave). Unpatched the input is silent, so this is the note itself: 69 = A4. Driven by an absolute pitch CV (keyboard, sequencer), set 0 to play as-is or ±12 to shift an octave.",
3167
+ "description": "Semitones added to the V/OCT input (12 = one octave). Unpatched, the input is silent (note 0, C−1), so the offset counts up from there: 69 semitones above C−1 = A4. Driven by an absolute pitch CV (keyboard, sequencer), set 0 to play as-is or ±12 to shift an octave.",
3168
3168
  "type": "Semitones",
3169
3169
  "unit": "semitone",
3170
3170
  "default": 69,
package/index.d.ts CHANGED
@@ -50,7 +50,7 @@ export declare function preload(ctx: BaseAudioContext, opts?: {
50
50
  export type ParamValue = number | string | boolean | number[] | boolean[][];
51
51
  /** Runtime metadata — only what code needs. Human-facing text (names,
52
52
  * descriptions, labels) is stripped from the bundle; it lives in the
53
- * generated docs/MODULES.md, meta.json and the .d.ts JSDoc instead. */
53
+ * generated docs/MODULES.md, docs/modules.json and the .d.ts JSDoc instead. */
54
54
  export interface ModuleMeta {
55
55
  type: string;
56
56
  ports: Record<string, Pick<PortDefinition, "type" | "signal">>;
@@ -125,12 +125,20 @@ export type Signal<Q> = AudioNode & {
125
125
  /** Reinterpret a node as a pitch signal — the greppable escape hatch for
126
126
  * deliberate cross-quantity patches. */
127
127
  export declare const asPitch: (n: AudioNode) => Signal<Note>;
128
- /** Where a playback starts. Default 'bar' = next bar line (beat 0 if stopped). */
128
+ /** A musical position. 'now' | 'beat' | 'bar' are the next of each from the
129
+ * current position (beat 0 if stopped). `{ bar: 3, beat: 2 }` is beat 2 of
130
+ * bar 3 (both count from 0); `{ beat: n }` is an absolute beat. */
129
131
  export type StartAt = "now" | "beat" | "bar" | {
130
132
  bar: number;
133
+ beat?: Beats;
131
134
  } | {
132
135
  beat: Beats;
133
136
  };
137
+ interface AtOptions {
138
+ /** Fires when the position is actually heard (output latency included),
139
+ * like `onHit`. Use it for UI; `fn` runs a lookahead early, for audio. */
140
+ onAudible?: (time: Seconds) => void;
141
+ }
134
142
  /** Rich step form, for when a plain value isn't enough. */
135
143
  export interface StepObject<V> {
136
144
  value: V;
@@ -139,7 +147,7 @@ export interface StepObject<V> {
139
147
  /** Gate length in steps, default = the playback's `gate`. */
140
148
  length?: number;
141
149
  }
142
- /** A pattern step: a value, a rest (null/undefined/false/0/'.'/'-'), or a StepObject. */
150
+ /** A pattern step: a value (0 included), a rest (null/undefined/false), or a StepObject. */
143
151
  export type Step<V> = V | StepObject<V> | null | undefined | false;
144
152
  /** What a voice receives per hit. */
145
153
  export interface Hit<V = unknown> {
@@ -151,7 +159,7 @@ export interface Hit<V = unknown> {
151
159
  step: number;
152
160
  /** Loop iteration, 0-based. */
153
161
  cycle: number;
154
- /** The step's value (true for `steps('x..x')`, a midi number for melodies, …). */
162
+ /** The step's value (true for `steps('x..x')`, a Note for melodies, …). */
155
163
  value: V;
156
164
  velocity: number;
157
165
  /** Gate length in seconds. */
@@ -211,18 +219,37 @@ export interface Transport {
211
219
  resolve(at: StartAt): Beats;
212
220
  /** Play a pattern array through a voice. */
213
221
  play<V>(pattern: readonly Step<V>[], voice: Voice<V>, opts?: PlayOptions<V>): Playback<V>;
214
- /** Run `fn(time)` once at a musical position — for automation, e.g. `vca.set('gain', 0, time)`. */
215
- at(when: StartAt | Beats, fn: (time: Seconds) => void): () => void;
222
+ /** Run `fn(time)` once, a lookahead before a musical position, with its exact
223
+ * audio time — for automation. `onAudible` fires when that moment is heard.
224
+ * Returns a cancel function (cancels both). */
225
+ at(when: StartAt | Beats, fn: (time: Seconds) => void, opts?: AtOptions): () => void;
216
226
  /** Global visual tap: every hit of every playback, fired when audible. Returns unsubscribe. */
217
227
  onHit(cb: (hit: Hit) => void): () => void;
218
228
  /** Schedule everything due inside the lookahead window. Auto-called in 'auto' mode. */
219
229
  tick(): void;
220
230
  dispose(): void;
221
231
  }
222
- export declare function isRest(v: unknown): boolean;
232
+ /** Rests are exactly the "nothing" values in `Step`: null, undefined (array
233
+ * holes) and false. `0` is a real value (root note, 0 semitones, CV 0);
234
+ * `'.'`/`'-'` are only rest syntax inside steps()/notes() strings. */
235
+ export declare function isRest(v: unknown): v is null | undefined | false;
223
236
  export declare function createTransport(ctx: BaseAudioContext, opts?: TransportOptions): Transport;
224
- /** `steps('x... x... x..x x...')` → boolean[]. x/X = hit, anything else = rest; spaces/| ignored. */
225
- export declare function steps(s: string): boolean[];
237
+ /** Velocities for the hit letters in `steps()`. */
238
+ export interface StepsLevels {
239
+ /** `X`. Default 1. */
240
+ accent?: number;
241
+ /** `x`. Default 0.75. */
242
+ normal?: number;
243
+ /** `o`. Default 0.4. */
244
+ ghost?: number;
245
+ }
246
+ /**
247
+ * `steps('X..x o.x. x... x..x')` → one step per character, value `true`:
248
+ * `X` = accent, `x` = normal hit, `o` = ghost note (as velocity, see
249
+ * StepsLevels), `.`/`-` = rest. Spaces and `|` are ignored; any other
250
+ * character throws, so a typo can't silently become a rest.
251
+ */
252
+ export declare function steps(s: string, levels?: StepsLevels): (StepObject<true> | null)[];
226
253
  /** 'A4' → 69, 'C4' → 60, 'F#2' → 42; a number passes through typed. Midi numbers are the pitch unit everywhere (V/Oct = semitones). */
227
254
  export declare function note(name: string | number): Note;
228
255
  /** `notes('C3 . E3 G3 - C4')` → (Note | null)[]. '.'/'-' = rest. */
@@ -301,11 +328,26 @@ export interface LoadedSampleSet {
301
328
  export declare function loadSampleSet(ctx: BaseAudioContext, set: SampleSetInfo, opts?: {
302
329
  fetch?: typeof fetch;
303
330
  }): Promise<LoadedSampleSet>;
304
- /** A one-sample voice. velocity 0..1 scales level; a number `value`
305
- * repitches in semitones, anything else (e.g. `true` from steps()) plays it
306
- * unshifted. */
331
+ export interface SampleVoiceOptions {
332
+ /** The note that plays the sample unshifted. Default 60 (C4). */
333
+ root?: Note;
334
+ }
335
+ /** A sample voice: a VoiceInstance whose kit can be swapped while playing. */
336
+ export interface SampleVoiceInstance extends VoiceInstance<Note | boolean> {
337
+ /** The kit hits are played from. */
338
+ readonly kit: LoadedSampleSet;
339
+ /** Play later hits from another kit (same voice key, same fallback chain).
340
+ * Hits already scheduled (up to the transport's lookahead) and samples
341
+ * still ringing keep the old kit, so the swap never cuts a tail. */
342
+ setKit(kit: LoadedSampleSet): void;
343
+ }
344
+ /** A one-shot sample voice, like a drum machine: every hit plays the whole
345
+ * sample, whatever the step's gate length. velocity 0..1 scales level. A
346
+ * `Note` value plays the sample at that note (`root` = unshifted), the same
347
+ * numbers `NoteCv` plays, so `notes()` melodies work on both; anything else
348
+ * (e.g. `true` from steps()) plays it unshifted. */
307
349
  export declare const SampleVoice: {
308
- create(ctx: BaseAudioContext, kit: LoadedSampleSet, key: VoiceKey): VoiceInstance<number | boolean>;
350
+ create(ctx: BaseAudioContext, kit: LoadedSampleSet, key: VoiceKey, opts?: SampleVoiceOptions): SampleVoiceInstance;
309
351
  };
310
352
  export interface AcidFilterParams {
311
353
  /** Cutoff Note. Base cutoff as a note (67 ≈ 400 Hz, 69 = 440 Hz) for the iconic squelchy acid sound. Drives the V/OCT worklet 1:1 — the panel knob shows the equivalent Hz. Range 15–135 notes. Default 67. */
@@ -316,7 +358,7 @@ export interface AcidFilterParams {
316
358
  envMod?: number;
317
359
  /** Accent. Intensifies the envelope sweep for more aggressive acid sounds. Range 0–1. Default 0.5. */
318
360
  accent?: number;
319
- /** Decay Time. How quickly the filter envelope falls. Short = plucky, long = sustained. Range 0.05–1 s (log). Default 0.2. */
361
+ /** Decay Time. Time for the exponential filter sweep to fall 60 dB after each trigger. Short = plucky squelch, long = slow, singing sweeps. Range 0.2–5 s (log). Default 0.92. */
320
362
  decay?: Seconds;
321
363
  }
322
364
  export type AcidFilterInputs = {
@@ -1335,7 +1377,7 @@ export interface ShimmerParams {
1335
1377
  pitch?: Semitones;
1336
1378
  /** Dry/Wet Mix. Equal-power balance between dry signal and shimmer output — independent of the regen amount. Range 0–1. Default 0.5. */
1337
1379
  mix?: number;
1338
- /** Shimmer Regen. Gain once round the pitch-shifted feedback loop, measured at 500 Hz: 0.5 = each new octave 6 dB quieter than the last, 0.95 = an almost endless rising choir. Means the same at every DECAY setting. Range 0–0.95. Default 0.5. */
1380
+ /** Shimmer Regen. Gain once round the pitch-shifted feedback loop, measured at 500 Hz: 0.5 = each new octave 6 dB quieter than the last, 0.95 = an almost endless rising choir. Means the same at every DECAY setting. At PITCH 0 the loop is plain reverb feedback and the regen is held under its self-oscillation edge, so 0.95 is a near-frozen, slowly breathing tail that always dies away. Range 0–0.95. Default 0.5. */
1339
1381
  shimmer?: number;
1340
1382
  }
1341
1383
  export type ShimmerInputs = {
@@ -1624,7 +1666,7 @@ export interface VcoParams {
1624
1666
  skew?: number;
1625
1667
  /** Waveshape Curvature. Curvature of the waveform: −1 square, 0 triangle, +1 sine. Range -1–1. Default 0. */
1626
1668
  shape?: number;
1627
- /** Pitch Offset. Semitones added to the V/OCT input (12 = one octave). Unpatched the input is silent, so this is the note itself: 69 = A4. Driven by an absolute pitch CV (keyboard, sequencer), set 0 to play as-is or ±12 to shift an octave. Range -48–108 semitones. Default 69. */
1669
+ /** Pitch Offset. Semitones added to the V/OCT input (12 = one octave). Unpatched, the input is silent (note 0, C−1), so the offset counts up from there: 69 semitones above C−1 = A4. Driven by an absolute pitch CV (keyboard, sequencer), set 0 to play as-is or ±12 to shift an octave. Range -48–108 semitones. Default 69. */
1628
1670
  offset?: Semitones;
1629
1671
  /** Detune. Fine pitch offset in semitones; ±1 = ±100 cents. Use for detuning oscillators against each other. Range -1–1 semitones. Default 0. */
1630
1672
  detune?: Semitones;