/*
RMEQ {
/*
Dattoro
Effect Design
Part 1: Reverberator and Other Filters
JAES, vol 45, no 9, 1997

	Synth.fftScope({
		n = WhiteNoise.ar(0.1);
		f = MouseX.kr( 0.1, 24 );
		b = MouseY.kr( -12, 12 ) * 2;
		[
			RegaliaMitraEQ.ar( n, 5000, f.midiratio - 1, b),
			RBJPeakingEQ.ar( n, 5000, f.midiratio - 1, b )
		]
	})
	
	Synth.fftScope({RegaliaMitraEQ.ar( WhiteNoise.ar(-20.dbamp), MouseY.kr(100, 1000, \exponential), 12.midirq, MouseX.kr(-20, 20))})	
	scope({RegaliaMitraEQ.ar( WhiteNoise.ar(-60.dbamp), LFNoise2.kr(1, 50, 300), LFNoise2.kr( 5, 6, 15).midiratio - 1, LFNoise1.kr( 2.1, 12, 30))})	

*/
	*ar { arg in, freq=440, rq=0.1, dbgain=0;
		
		var wc, w2, w1, dw, q, beta, sr, y;
		var b0, b1, b2, a0, a1, a2, az, k;
		
		k = dbgain.dbamp;
				
		sr = 2pi / SampleRate.ir;
		wc = sr * freq;				// freq in radians
		dw = rq * wc;				// bandwidth in radians

		dw = (dw/2).tan;			// delta is only used to compute §
		beta = (1 - dw) / (1 + dw);	// §
		y = cos(wc).neg;			// lattice coefficient
		
		b0 = beta;
		b1 = y * (1 + beta);
		b2 = 1;
		
		a0 = 1;
		a1 = b1;	// y * (1 + beta);
		a2 = beta;
		
//		az = SOS.ar( in, b0/a0, b1/a0, b2/a0, a1/a0.neg, a2/a0.neg );
		az = SOS.ar( in, b0, b1, b2, a1.neg, a2.neg );
	
		^( k * (in - az) ) + (in + az) * 0.5
	}
}
*/

/*
Implementation of filters as described at:
<http://www.harmony-central.com/Computer/Programming/Audio-EQ-Cookbook.txt>
*/
/*
PeakingEQ {
	/*
		scope({RBJPeakingEQ.ar( WhiteNoise.ar(-60.dbamp), MouseY.kr(100, 1000, \exponential), 12.midiratio - 1, MouseX.kr(0, 45))})	
		scope({RBJPeakingEQ.ar( WhiteNoise.ar(-60.dbamp), LFNoise2.kr(1, 50, 300), LFNoise2.kr( 5, 6, 15).midiratio - 1, LFNoise1.kr( 2.1, 12, 30))})	
	*/

	*ar { arg in, freq=440, rq=0.1, dbgain=0, mul=1, add=0;
		var b0, b1, b2, a0, a1, a2;
		var a, omega, sin, cos, alpha, a0n;
		var aovera, atimesa;

		a = dbgain.dbamp;	
		omega = 2pi * freq/SampleRate.ir;
		sin = omega.sin;
		cos = omega.cos;
		alpha = sin * rq / 2;

		aovera = (alpha/a);
		atimesa = (alpha*a);
		
		a0 = 1 + aovera;
		a1 = -2 * cos;
		a2 = 1 - aovera;

		b0 = 1 + atimesa;
		b1 = a1;
		b2 = 1 - atimesa;
		
		a0n = a0.neg;

		^SOS.ar( in, b0/a0, b1/a0, b2/a0, a1/a0n, a2/a0n, mul, add )
	}

}
*/
Notch  {
	/*
		Synth.fftScope({RBJNotch.ar( WhiteNoise.ar(0.1), 4400, MouseX.kr(0.01, 2))})	
		Synth.fftScope({RBJNotch.ar( SinOsc.ar(LFTri.kr(0.1, 1000, 1100), 0, 0.1), 500, MouseX.kr(0.01, 2))})	
	*/

	*ar { arg in, freq=440, rq=0.1, mul=1, add=0;

		var b0, b1, b2, a0, a1, a2;
		var a, omega, sin, cos, alpha, beta, q;
		
		omega = 2pi * freq/SampleRate.ir;
		sin = omega.sin;
		cos = omega.cos;
		alpha = rq * sin/2;


		a0 = 1 + alpha;
		a1 = -2 * cos;
		a2 = 1 - alpha;

		b0 = 1;
		b1 = a1;	// -2 * cos;
		b2 = 1;

		^SOS.ar( in, b0/a0, b1/a0, b2/a0, a1/a0.neg, a2/a0.neg, mul, add )
	}
}

LowShelf  {
	/*
		Synth.fftScope({RBJLowShelf.ar( WhiteNoise.ar(0.1), 400, 1, MouseX.kr(-24, 24))})	
	*/

	*ar { arg in, freq=440, shelfslope=1, dbgain=0, mul=1, add=0;
		var am1, ap1, bs, am1cos, ap1cos, q;

		var b0, b1, b2, a0, a1, a2;
		var a, omega, sin, cos, alpha, beta;
		
		a = dbgain.dbamp;	
		omega = 2pi * freq/SampleRate.ir;
		sin = omega.sin;
		cos = omega.cos;

		beta = a.sqrt * ((a+a.reciprocal) * (shelfslope.reciprocal - 1) + 2).sqrt;
//		beta = (((a.squared + 1) / shelfslope) - (a - 1).squared).sqrt;
//		q = ((a + a.reciprocal) * (shelfslope.reciprocal - 1) + 2).sqrt.reciprocal;
//		q.postln;
//		beta = a.sqrt / q;

		am1 = a-1;
		ap1 = a+1;
		am1cos = am1 * cos;
		ap1cos = ap1 * cos;
		bs = beta * sin;
		
		a0 = ap1 + am1cos + bs;
		a1 = -2 * ( am1 + ap1cos );
		a2 = ap1 + am1cos - bs;

		b0 = a * ( ap1 - am1cos + bs );
		b1 = 2 * a * ( am1 - ap1cos );
		b2 = a * ( ap1 - am1cos - bs );

		^SOS.ar( in, b0/a0, b1/a0, b2/a0, a1/a0.neg, a2/a0.neg, mul, add )
	}
}

HighShelf  {
	/*
		Synth.fftScope({RBJHighShelf.ar( WhiteNoise.ar(0.1), 11000, 1, MouseX.kr(-6, 6))})	
	*/

	*ar { arg in, freq=440, shelfslope=1, dbgain=0, mul=1, add=0;
		var am1, ap1, bs, am1cos, ap1cos;

		var b0, b1, b2, a0, a1, a2, a0n;
		var a, omega, sin, cos, alpha, beta, q;
		
		a = dbgain.dbamp;	
		omega = 2pi * freq/SampleRate.ir;
		sin = omega.sin;
		cos = omega.cos;

//		beta = (((a.squared + 1) / shelfslope) - (a - 1).squared).sqrt;
		beta = a.sqrt * ((a+a.reciprocal)*(shelfslope.reciprocal-1)+2).sqrt;
//		q = ((a + a.reciprocal) * (shelfslope.reciprocal - 1) + 2).sqrt.reciprocal;
//		beta = a.sqrt / q;

		am1 = a-1;
		ap1 = a+1;
		am1cos = am1 * cos;
		ap1cos = ap1 * cos;
		bs = beta * sin;
		
		a0 = ap1 - am1cos + bs;
		a1 = 2 * ( am1 - ap1cos );
		a2 = ap1 - am1cos - bs;

		b0 = a * ( ap1 + am1cos + bs );
		b1 = -2 * a * ( am1 + ap1cos );
		b2 = a * ( ap1 + am1cos - bs );
		
		a0n = a0.neg;

		^SOS.ar( in, b0/a0, b1/a0, b2/a0, a1/a0n, a2/a0n, mul, add )
	}
}

// old verbose names
RegaliaMitraEQ : RMEQ {}
//RBJPeakingEQ : PeakingEQ {}
RBJNotch : Notch {}
RBJHighShelf : HighShelf {}
RBJLowShelf : LowShelf {}
