You are not recognized as the original poster of this topic.
let SAMPLE_RATE=32000,TAU=Math.PI*2;
class BiquadFilter{ //musicdsp.org/files/Audio-EQ-Cookbook.txt
constructor(type="lowpass",freq=1000,Q=1){
this.type=type;
this.Fs=SAMPLE_RATE;
this.f0=freq;this.Q=Q;
this.dBGain=0;this.S=1;
this.BW=undefined;
this.a0=1;this.a1=0;this.a2=0;
this.b0=1;this.b1=0;this.b2=0;
this.x1=0;this.x2=0;
this.y1=0;this.y2=0;
this.updateCoefficients();
}
setType(type){this.type=type;this.updateCoefficients();}
setFrequency(f0){this.f0=f0;this.updateCoefficients();}
setQ(Q){this.Q=Q;this.updateCoefficients();}
setGain(dB){this.dBGain=dB;this.updateCoefficients();}
setSlope(S){this.S=S;this.updateCoefficients();}
setBandwidth(BW){this.BW=BW;this.updateCoefficients();}
updateCoefficients(){
const{type,Fs,f0,Q,dBGain,S,BW}=this;
let A=1;
if(type==="peaking"||type==="lowshelf"||type==="highshelf")A=Math.pow(10,dBGain/40);
const w0=TAU*f0/Fs,cosw0=Math.cos(w0),sinw0=Math.sin(w0);
let alpha=0;
switch(type){
case"lowpass":case"highpass":case"bandpass":case"notch":case"allpass":case"peaking":
if(BW!==undefined&&(type==="bandpass"||type==="notch")){
const numerator=(Math.log(2)/2)*BW*w0;
alpha=sinw0*Math.sinh(numerator/sinw0);
}else{
alpha=sinw0/(2*Q);
}
break;
case"lowshelf":case"highshelf":
const sqrtTerm=Math.sqrt((A+1/A)*(1/S-1)+2);
alpha=(sinw0/2)*sqrtTerm;
break;
default:throw new Error(`Unsupported filter type: ${type}`);
}
switch(type){
case"lowpass":
this.b0=(1-cosw0)/2;this.b1=1-cosw0;this.b2=this.b0;
this.a0=1+alpha;this.a1=-2*cosw0;this.a2=1-alpha;
break;
case"highpass":
this.b0=(1+cosw0)/2;this.b1=-(1+cosw0);this.b2=this.b0;
this.a0=1+alpha;this.a1=-2*cosw0;this.a2=1-alpha;
break;
case"bandpass":
this.b0=sinw0/2;this.b1=0;this.b2=-this.b0;
this.a0=1+alpha;this.a1=-2*cosw0;this.a2=1-alpha;
break;
case"notch":
this.b0=1;this.b1=-2*cosw0;this.b2=1;
this.a0=1+alpha;this.a1=-2*cosw0;this.a2=1-alpha;
break;
case"allpass":
this.b0=1-alpha;this.b1=-2*cosw0;this.b2=1+alpha;
this.a0=1+alpha;this.a1=-2*cosw0;this.a2=1-alpha;
break;
case"peaking":
this.b0=1+alpha*A;this.b1=-2*cosw0;this.b2=1-alpha*A;
this.a0=1+alpha/A;this.a1=-2*cosw0;this.a2=1-alpha/A;
break;
case"lowshelf":{
const twoSqrtAlpha=2*Math.sqrt(A)*alpha;
this.b0=A*((A+1)-(A-1)*cosw0+twoSqrtAlpha);
this.b1=2*A*((A-1)-(A+1)*cosw0);
this.b2=A*((A+1)-(A-1)*cosw0-twoSqrtAlpha);
this.a0=(A+1)+(A-1)*cosw0+twoSqrtAlpha;
this.a1=-2*((A-1)+(A+1)*cosw0);
this.a2=(A+1)+(A-1)*cosw0-twoSqrtAlpha;
break;
}
case"highshelf":{
const twoSqrtAlpha=2*Math.sqrt(A)*alpha;
this.b0=A*((A+1)+(A-1)*cosw0+twoSqrtAlpha);
this.b1=-2*A*((A-1)+(A+1)*cosw0);
this.b2=A*((A+1)+(A-1)*cosw0-twoSqrtAlpha);
this.a0=(A+1)-(A-1)*cosw0+twoSqrtAlpha;
this.a1=2*((A-1)-(A+1)*cosw0);
this.a2=(A+1)-(A-1)*cosw0-twoSqrtAlpha;
break;
}
default:throw new Error(`Unsupported filter type: ${type}`);
}
const a0=this.a0;
this.b0/=a0;this.b1/=a0;this.b2/=a0;this.a1/=a0;this.a2/=a0;
}
process(sample){
const x=sample,
y=this.b0*x+this.b1*this.x1+this.b2*this.x2-this.a1*this.y1-this.a2*this.y2;
this.x2=this.x1;this.x1=x;this.y2=this.y1;this.y1=y;
return y;
}
}
//Example usage…
function noteHz(n){return 440*2**(n/12);}
const chord=[0,4,7,11,14],filters=chord.map(n=>new BiquadFilter(Math.random()<.5?"bandpass":"lowpass",noteHz(n),100));
return function DSP(time){
let o=0;
for(let i=0,f;i<filters.length;i++){
f=filters[i];
f.setFrequency(noteHz(chord[i]+[0,3,5,-2][floor(time/2%4)]+sin(time*10)*.1)*.56)
o+=f.process((Math.random()-.5)+.4*sin(1/((time%(.2+i*.1))**1.3+.001)));
}
return Math.tanh(o*.1);
}