Sum of multiple BPFs

Noob trying to make a quick patch with a bunch of band pass filters using the same source as an input.
I thought something like this would yield a sum/mix of 5 BPFs but not really :slight_smile:

	{ Mix.new( BPF.ar(Saw.ar(333), [111, 222, 333, 444, 555] ))!2 }.play

Pointers?
Thanks!!!

You should check

  • the spectrum of the source and filter, and
  • the bandwidth of the filter.

1. Does Saw.ar(333) contain 111 Hz, 222 Hz, 444 Hz and 555 Hz?

Let’s evaluate the following code to see the spectrum of the output signal:

FreqScope.new(400, 200, 0, server: s);

Then evaluate the following code to listen to the sound and see its spectrum:

{ Saw.ar(333) * 0.01 }.play

Stop the sound by pressing ‘cmd + .’ or ‘ctrl + .’

Then evaluate the following code to hear the sound and see its spectrum:

{ Saw.ar(111) * 0.01 }.play

You can see the result in the following picture:

So you should change the frequency of Saw.ar into 111, otherwise the frequency array of the BPF into 333 * (1..5):
Evaluating 333 * (1..5) returns [333, 666, 999, 1332, 1665]

You will then get one of the following codes:

{ Mix.new(BPF.ar(Saw.ar(333), 333 * (1..5))) ! 2 * 0.01 }.play

or the following code:

{ Mix.new(BPF.ar(Saw.ar(111), 111 * (1..5))) ! 2 * 0.01 }.play

These codes can be reconstructed as follows:

x = { |freq = 111| Mix.new(BPF.ar(Saw.ar(freq), freq * (1..5))) ! 2 * 0.01 }

You could use .sum instead of Mix.new in this case:

x = { |freq = 111| BPF.ar(Saw.ar(freq), freq * (1..5)).sum ! 2 * 0.01 }

After evaluating the above code, you can hear the sound by evaluating the following code::

y = x.play(args: [freq: 440]);
y.free

y = x.play(args: [freq: 111]);
y.free

y = x.play(args: [freq: 333]);
y.free

2. The bandwidth

BPF uses the reciprocal of Q. The narrower the bandwidth, the lower the RQ!
However, the lower the RQ, the quieter the sound!

To test this, rewrite the above function as follows

x = { |freq = 111, rq = 1, mul=1| BPF.ar(Saw.ar(freq), freq * (1..5), rq, mul).sum ! 2 }
y = x.play(args: [freq: 333, rq: 1, mul: 0.01]);
y.free

y = x.play(args: [freq: 333, rq: 0.1, mul: 0.05]);
y.free

y = x.play(args: [freq: 333, rq: 0.01, mul: 0.1]);
y.free

y = x.play(args: [freq: 333, rq: 0.0001, mul: 0.1]);
// <- Extremely narrow bandwidth and a static (unchanging) signal will cause some feedback! The sound gets louder for a while!
y.free

To avoid the feedback of the last code, you should use the daisy chain BPF as follows:

(
x = { |freq = 111, rq = 1, mul=1|
	var bpf = { |source|
		{ BPF.ar(source, freq * (1..5), rq, mul).sum } ! 2 
	};
	bpf = bpf.(Saw.ar(freq));
	bpf = bpf.(bpf);
	bpf = bpf.(bpf);
	bpf = bpf.(bpf);
	bpf = bpf.(bpf)
}
)

y = x.play(args: [freq: 444, rq: 0.05, mul: 0.05]);
y.free

y = x.play(args: [freq: 333, rq: 0.05, mul: 0.05]);
y.free

y = x.play(args: [freq: 111, rq: 0.05, mul: 0.05]);
y.free

I think white noise or blip would be convenient to hear each filtered frequency:

{ BPF.ar(WhiteNoise.ar, 333 * [1, 3], 0.0001, 10 ).sum ! 2 }.play 
// <- left sound = right sound

{ { BPF.ar(WhiteNoise.ar, 333 * [1, 3], 0.0001, 10 ).sum } ! 2 }.play
// stereo!
{ Blip.ar(222) * 0.5 ! 2 }.play

{ { BPF.ar(Blip.ar(222), 222, 0.01) } ! 2 }.play

{ { BPF.ar(Blip.ar(222), 222 * (1..2), 0.01).sum } ! 2 }.play

{ { BPF.ar(Blip.ar(222), 222 * (1..3), 0.01).sum } ! 2 }.play
3 Likes

Thanks so much for the detailed reply. That Saw was purely a quick test, the intention was to use it to filter other things :slight_smile:
Incredibly helpful!!!

1 Like

I just wanted to show that the frequencies not contained in the source cannot be produced by using a filter.
Glad to read that I was helpful!