Modulating the center frequency of the Band Pass filter

Hi folks,

Is it possible to change the center frequency of a band pass filter, while keeping its bandwidth the same?

I’m trying to do this, using a low frequency SinOsc, whose output is shifted using the following function from Charles Dodge:

y = (( ( ymax - ymin ) / (xmax -xmin ) ) * ( x - xmin ) ) + ymin

(Parentheses are in keeping with SC’s proclivities.)

Here’s the code::

data = env * PlayBuf.ar(numChannels: 1, bufnum: a.bufnum, rate: 1.0, startPos: 0.0) ;

// the following is an attempt at implementing the scaling function:
// y = ( (ymax-ymin)/(xmax-xmin) ) * ( x - xmin ) + ymin ;
// as described in Charles Dodge’s book “Computer Music”
//
// the idea is to implement a band pass filter in which the center frequency oscillates
// between ymax and ymin, but the bandwidth remains the same.

cf = 800 ; // center frequency
bw = 500 ; // desired bandwith

xmax = 1.0 ; // xmax and xmin are the limits of the SinOsc()
xmin = -1.0 ;
ymax = cf + ( bw / 2 ) ; // these are the desired limits for the band pass filter
ymin = cf - ( bw / 2 ) ;

scale = ( ymax - ymin ) / ( xmax - xmin ) ;

cf2 = (scale * (SinOsc.ar(freq: 1) - xmin) ) + ymin ; // calculate current value of cf
rQ = cf2 / bw ; // recalculate value of rQ, given new value of cf

output = BPF.ar(data, cf2, rQ); /// pass data through BandPassFilter()
Out.ar(0, output)

Thanks for any help or advice.

Arun Chandra

Your code is pretty solid. Check out my code below. I rearrange some things for you and add .range for cf2 and clip the rQ so it doesn’t get too big or too small:

{
	var cf, bw, cf2, rQ, output;
	cf = 800 ; // center frequency
	bw = 500 ; // desired bandwith




	cf2 = SinOsc.ar(1).range(cf-200, cf+200);
	
	rQ = (cf2 / bw).clip(0.01, 2); // recalculate value of rQ, given new value of cf

	rQ.poll;
	
	output = BPF.ar(WhiteNoise.ar*0.1, cf2, rQ); /// pass data through BandPassFilter()
	Out.ar(0, output)
}.play

Thank. you!

This was very helpful.

Arun

Is there any advantage to having cf and cf2?

Wouldn’t it be possible to have:

{
	var cf, bw, cf2, rQ, output;
	cf = 800 ; // center frequency
	bw = 500 ; // desired bandwith

	cf = SinOsc.ar(1).range(cf-200, cf+200);
	
	rQ = (cf / bw).clip(0.01, 2); // recalculate value of rQ, given new value of cf

	rQ.poll;
	
	output = BPF.ar(WhiteNoise.ar*0.1, cf, rQ); /// pass data through BandPassFilter()
	Out.ar(0, output)
}.play

And yep, the range method implements the same type of scaling function as the Dodge formula you listed. It simplifies the code a lot!

I tried your example when you first posted it, and thought as a relative new comer to SC I was missing something, because it worked out of the box. And going and doing the math on paper also showed that the formula was functioning as you intended.

Is there something specific you were after that wasn’t achieved by your first implementation?